Package org.rioproject.impl.servicebean

Source Code of org.rioproject.impl.servicebean.ServiceBeanActivation

/*
* Copyright to the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.rioproject.impl.servicebean;

import com.sun.jini.admin.DestroyAdmin;
import com.sun.jini.start.LifeCycle;
import net.jini.admin.Administrable;
import net.jini.config.Configuration;
import net.jini.config.ConfigurationException;
import net.jini.config.ConfigurationProvider;
import net.jini.core.discovery.LookupLocator;
import net.jini.id.Uuid;
import net.jini.id.UuidFactory;
import net.jini.security.BasicProxyPreparer;
import net.jini.security.ProxyPreparer;
import org.rioproject.admin.ServiceBeanControlException;
import org.rioproject.util.MulticastStatus;
import org.rioproject.config.Constants;
import org.rioproject.impl.container.DiscardManager;
import org.rioproject.servicebean.ServiceBeanContext;
import org.rioproject.impl.container.ServiceAdvertiser;
import org.rioproject.deploy.SystemRequirements;
import org.rioproject.loader.CommonClassLoader;
import org.rioproject.loader.ServiceClassLoader;
import org.rioproject.log.LoggerConfig;
import org.rioproject.opstring.ClassBundle;
import org.rioproject.opstring.ServiceBeanConfig;
import org.rioproject.opstring.ServiceElement;
import org.rioproject.impl.client.DiscoveryManagementPool;
import org.rioproject.impl.client.LookupCachePool;
import org.rioproject.impl.service.Destroyer;
import org.rioproject.rmi.RegistryUtil;
import org.rioproject.sla.ServiceLevelAgreements;
import org.rioproject.impl.system.ComputeResource;
import org.rioproject.watch.ThresholdValues;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.security.auth.Subject;
import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

/**
* The ServiceBeanActivation class is a utility that provides bootstrap support
* for a ServiceBean
*
* @author Dennis Reedy
*/
@SuppressWarnings("PMD.AvoidThrowingRawExceptionTypes")
public class ServiceBeanActivation {
    static final String COMPONENT = ServiceBeanActivation.class.getPackage().getName();
    public static final String QOS_COMPONENT = Constants.BASE_COMPONENT+".system";
    public static final String BOOT_COMPONENT = Constants.BASE_COMPONENT+".boot";
    public static final String BOOT_CONFIG_COMPONENT = BOOT_COMPONENT+".configComponent";
    static LifeCycleManager sbLifeCycleManager;
    static final Logger logger = LoggerFactory.getLogger(COMPONENT);
    static final String BOOT_COOKIE = "boot-cookie";

    /**
     * Create a ServiceBeanContext from the Configuration element.
     *
     * @param configComponent The configuration component name of the
     * ServiceBean to use when obtaining configuration attributes. Must not be null.
     * @param defaultServiceName The default name of the service. Must not be null.
     * @param configArgs Configuration for the ServiceBean. Must not be null.
     * @param loader The ClassLoader which loaded the ServiceBean. Must not be null.
     *
     * @return A ServiceBeanContext. A new ServiceBeanContext is created each time
     *
     * @throws ConfigurationException If the Configuration cannot be created
     * @throws IOException If the hostname cannot be accessed
     * @throws IllegalArgumentException If any of the arguments are null.
     */
    public static ServiceBeanContext getServiceBeanContext(final String configComponent,
                                                           final String defaultServiceName,
                                                           final String[] configArgs,
                                                           final ClassLoader loader) throws ConfigurationException, IOException {
        if(configArgs == null)
            throw new IllegalArgumentException("configArgs is null");
        logger.debug("Creating configuration for {}", configComponent);
        Configuration config = ConfigurationProvider.getInstance(configArgs, loader);
        logger.debug("Created configuration for {}", configComponent);
        return getServiceBeanContext(configComponent, defaultServiceName, configArgs, config, loader);

    }

    /**
     * Create a ServiceBeanContext from the Configuration element. This method is used if the
     * {@code Configuration} object has already been created.
     *
     * @param configComponent The configuration component name of the
     * ServiceBean to use when obtaining configuration attributes. Must not be null.
     * @param defaultServiceName The default name of the service. Must not be null.
     * @param configArgs Configuration arguments for the ServiceBean. This is used to create a
     * {@code ServiceBeanConfig} object, and the {@code configArgs} are those used to create the
     * {@code Configuration} argument following. Must not be null.
     * @param config Configuration for the ServiceBean. Must not be null.
     * @param loader The ClassLoader which loaded the ServiceBean. Must not be null.
     *
     * @return A ServiceBeanContext. A new ServiceBeanContext is created each time
     *
     * @throws ConfigurationException If the Configuration cannot be created
     * @throws IOException If the hostname cannot be accessed
     * @throws IllegalArgumentException If any of the arguments are null.
     */
    public static ServiceBeanContext getServiceBeanContext(final String configComponent,
                                                           final String defaultServiceName,
                                                           final String[] configArgs,
                                                           final Configuration config,
                                                           final ClassLoader loader) throws ConfigurationException,
                                                                                      IOException {
        logger.debug("Entering getServiceBeanContext");
        if(configComponent == null)
            throw new IllegalArgumentException("configComponent is null");
        if(defaultServiceName == null)
            throw new IllegalArgumentException("defaultServiceName is null");
        if(configArgs == null)
            throw new IllegalArgumentException("configArgs is null");
        if(config == null)
            throw new IllegalArgumentException("config is null");
        if(loader == null)
            throw new IllegalArgumentException("loader is null");

        Map<String, Object> configParms = new HashMap<String, Object>();

        RegistryUtil.checkRegistry();
       
        configParms.putAll(readServiceBeanConfig(configComponent, defaultServiceName, config));

        String jmxName = (String)config.getEntry(configComponent, "jmxName", String.class, null);
        if(jmxName!=null)
            configParms.put(ServiceBeanConfig.JMX_NAME, jmxName);

        ServiceBeanConfig sbConfig = new ServiceBeanConfig(configParms, configArgs);
        sbConfig.addInitParameter(BOOT_CONFIG_COMPONENT, configComponent);

        ClassLoader cl = Thread.currentThread().getContextClassLoader();
        if(cl instanceof ServiceClassLoader) {
            Properties p = new Properties();
            p.setProperty("opStringName", sbConfig.getOperationalStringName());
            p.setProperty("serviceName", sbConfig.getName());
            ((ServiceClassLoader)cl).addMetaData(p);
        }

        /* Add a boot-cookie, indicating that the JSB was booted by this utility */
        sbConfig.addInitParameter("org.rioproject.boot", BOOT_COOKIE);
        ServiceLevelAgreements sla = new ServiceLevelAgreements();
        /* Get the export codebase from the ClassLoader which loaded us. The
         * export codebase will be returned by the getURLs() method since
         * getURLs() is overridden to return configured export codebase
         */
        URL[] urls = ((URLClassLoader)loader).getURLs();
        if(urls.length==0)
            throw new RuntimeException("Unknown Export Codebase");

        ClassBundle exportBundle;
        String exportCodebase = urls[0].toExternalForm();
        if(!exportCodebase.startsWith("artifact:")) {
            if(exportCodebase.contains(".jar")) {
                int index = exportCodebase.lastIndexOf('/');
                if(index != -1)
                    exportCodebase = exportCodebase.substring(0, index+1);
            } else {
                throw new RuntimeException("Cannot determine export codebase from "+exportCodebase);
            }
            exportBundle = new ClassBundle("");
            exportBundle.setCodebase(exportCodebase);
            for (URL url : urls) {
                String jar = url.getFile();
                int index = jar.lastIndexOf('/');
                if (index != -1)
                    jar = jar.substring(1);
                exportBundle.addJAR(jar);
            }
        } else {
            exportBundle = new ClassBundle("");
            exportBundle.setArtifact(exportCodebase);
        }

        /* Default system threshold is the number of available processors.
         * Since the system threshold is the summation of all depletion oriented
         * resources, total utilization is =
         * (num_available_processors * cpu_utilization *  mem_utilization * diskspace_utilization) */
        double defaultSystemThreshold = Runtime.getRuntime().availableProcessors();
        double systemThreshold = (Double)config.getEntry(QOS_COMPONENT,
                                                         "systemThreshold",
                                                         double.class,
                                                         defaultSystemThreshold);
        sla.getSystemRequirements().addSystemThreshold(SystemRequirements.SYSTEM,
                                                       new ThresholdValues(0.0, systemThreshold));

        ServiceElement sElem = new ServiceElement(ServiceElement.ProvisionType.EXTERNAL,
                                                  sbConfig,
                                                  sla,
                                                  new ClassBundle[]{exportBundle});
        if(sbLifeCycleManager == null)
            sbLifeCycleManager = new LifeCycleManager();

        checkUtilityConfiguration(config);
        ComputeResource computeResource = new ComputeResource(config);

        Uuid serviceID = UuidFactory.generate();
        DefaultServiceBeanManager serviceBeanManager = new DefaultServiceBeanManager(sElem,
                                               computeResource.getHostName(),
                                               computeResource.getAddress().getHostAddress(),
                                               serviceID);
        serviceBeanManager.setDiscardManager(sbLifeCycleManager);
        serviceBeanManager.setServiceID(serviceID);
        DefaultServiceBeanContext serviceBeanContext = new DefaultServiceBeanContext(sElem, serviceBeanManager, computeResource, null); /* Shared Configuration */
        serviceBeanContext.setConfiguration(config);
        serviceBeanContext.setConfigurationFiles(configArgs);
        logger.debug("Leaving getServiceBeanContext");
        return (serviceBeanContext);
    }

    /**
     * Get ServiceBean config params, using the package name of the ServiceBean
     * class as the component
     *
     * @param configComponent The component name used to access entries in
     * the configuration
     * @param defaultServiceName The service's default name
     * @param config The Configuration to use
     *
     * @return  A Map of name,value pairs specifying configuration
     * attributes
     *
     * @throws ConfigurationException if there are errors reading the configuration 1
     * @throws IllegalArgumentException If any of the arguments are null.
     */
    static Map<String, Object> readServiceBeanConfig(final String configComponent,
                                                     final String defaultServiceName,
                                                     final Configuration config)
    throws ConfigurationException {
        if(configComponent == null)
            throw new IllegalArgumentException("configComponent is null");
        if(defaultServiceName == null)
            throw new IllegalArgumentException("defaultServiceName is null");
        if(config == null)
            throw new IllegalArgumentException("config is null");

        Map<String, Object> configParms = new HashMap<String, Object>();

        /* Set the ClassLoader for the DiscoveryManagementPool to be the
         * CommonCLassLoader, not the current context ClassLoader */
        ClassLoader cCL = Thread.currentThread().getContextClassLoader();
        CommonClassLoader common = CommonClassLoader.getInstance();
        Thread.currentThread().setContextClassLoader(common);
        try {
            /* Set the Configuration for the DiscoveryManagementPool */
            DiscoveryManagementPool.getInstance().setConfiguration(config);
            LookupCachePool.getInstance().setConfiguration(config);
        } finally {
            Thread.currentThread().setContextClassLoader(cCL);
        }

        /* Set the config component */
        configParms.put(ServiceBeanConfig.COMPONENT, configComponent);
       
        /* Get the ServiceBean name */
        String serviceName = (String)config.getEntry(configComponent, "serviceName", String.class, defaultServiceName);
        configParms.put(ServiceBeanConfig.NAME, serviceName);
        /* Get the comment for the ServiceBean */
        String serviceComment = (String)config.getEntry(configComponent, "serviceComment", String.class, null);
        if(serviceComment != null)
            configParms.put(ServiceBeanConfig.COMMENT, serviceComment);
        /* Get the log OperationalString name */
        String opStringName = (String)config.getEntry(configComponent, "opStringName", String.class, Constants.CORE_OPSTRING);
        configParms.put(ServiceBeanConfig.OPSTRING, opStringName);       
        /* Get group values, default to all groups */
        String[] groups = (String[])config.getEntry(configComponent,
                                                    "initialLookupGroups",
                                                    String[].class,
                                                    new String[]{"all"});
        configParms.put(ServiceBeanConfig.GROUPS, groups);
        /* Get LookupLocator values */
        LookupLocator[] lookupLocators =
            (LookupLocator[])config.getEntry(configComponent, "initialLookupLocators", LookupLocator[].class, null);
        /* Get LoggerConfig values */
        LoggerConfig[] logConfigs =
            (LoggerConfig[])config.getEntry(configComponent, "loggerConfigs", LoggerConfig[].class, null);
        if(logConfigs != null) {
            for (LoggerConfig logConfig : logConfigs) {
                logConfig.getLogger();
            }
        }
        if(lookupLocators != null)
            configParms.put(ServiceBeanConfig.LOCATORS, lookupLocators);
        return (configParms);
    }

    /**
     * Check for multicast verification and setting up a shutdown hook
     *
     * @param config Configuration to use
     *
     * @throws IOException If the multicast check is performed and it fails
     * @throws ConfigurationException if there are problems reading the configuration
     * @throws IllegalArgumentException If the config argument is null.
     */
    static void checkUtilityConfiguration(final Configuration config) throws IOException, ConfigurationException {
        if(config == null)
            throw new IllegalArgumentException("configArgs are null");

        Boolean multiCheck = (Boolean)config.getEntry(BOOT_COMPONENT, "verifyMulticast", Boolean.class, false);
        if(logger.isDebugEnabled())
            logger.debug("Verify multicast [{}]", multiCheck);
        if(multiCheck) {
            if(logger.isInfoEnabled())
                logger.info("Verifying multicast, wait up to 10 seconds ... ");
            MulticastStatus.checkMulticast(1000 * 10);
            if(logger.isInfoEnabled())
                logger.info("Multicast responds okay");
        }
        /* Check for the creation of a ShutdownHook */
        Boolean createShutdownHook = (Boolean)config.getEntry(BOOT_COMPONENT, "createShutdownHook", Boolean.class, true);
        if(logger.isDebugEnabled())
            logger.debug("Create ShutdownHook [{}]", createShutdownHook);
        if(createShutdownHook) {
            boolean okay = false;
            if(sbLifeCycleManager != null) {
                if(!sbLifeCycleManager.isShutDownHookRegistered()) {
                    okay = true;
                }
            } else {
                okay = true;
            }
            if(okay) {
                ShutdownHook shutdownHook = new ShutdownHook();
                shutdownHook.setDaemon(true);
                Runtime.getRuntime().addShutdownHook(shutdownHook);
                if(sbLifeCycleManager != null) {
                    sbLifeCycleManager.setShutDownHookRegistered();
                }
            }
        }
    }

    /**
     * Class that provides basic functionality to enable bootstrapping
     */
    public static class LifeCycleManager implements DiscardManager, LifeCycle {
        boolean terminated = false;
        boolean shutdownHookRegistered = false;
        final Map<DestroyAdmin, Subject>registrationMap = new HashMap<DestroyAdmin, Subject>();

        /*
         * Register the ServiceBean to the LifeCycleManager and advertise it
         */
        public void register(final Object sbProxy, final ServiceBeanContext context) throws ServiceBeanControlException {
            try {
                if(sbProxy == null)
                    throw new IllegalArgumentException("sbProxy is null");
                if(context == null)
                    throw new IllegalArgumentException("context is null");
                ServiceAdvertiser.advertise(sbProxy, context, false);

                try {
                    ProxyPreparer prep = (ProxyPreparer)context.getConfiguration().getEntry(BOOT_COMPONENT,
                                                                                            "adminProxyPreparer",
                                                                                            BasicProxyPreparer.class,
                                                                                            new BasicProxyPreparer());
                    Object preparedPProxy = prep.prepareProxy(sbProxy);
                    if(preparedPProxy instanceof Administrable) {
                        Administrable admin = (Administrable)preparedPProxy;
                        Object adminObject = admin.getAdmin();
                        if(adminObject instanceof DestroyAdmin) {
                            Subject subject = null;
                            if(context instanceof DefaultServiceBeanContext)
                                subject = ((DefaultServiceBeanContext)context).getSubject();
                            registrationMap.put((DestroyAdmin)adminObject, subject);
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }

            } catch(Throwable t) {
                String name = (context == null ? "unknown name" : context.getServiceElement().getName());
                throw new ServiceBeanControlException("ServiceBean ["+ name+"] advertise failed", t);
            }
        }

        /**
         * A flag to indicate that a shutdown hook has already been registered
         * by this utility
         */
        void setShutDownHookRegistered() {
            shutdownHookRegistered = true;
        }

        /*
         * Return whether a shutdown hook has already been registered
         * by this utility
         */
        boolean isShutDownHookRegistered() {
            return(shutdownHookRegistered);
        }

        /**
         * Shutdown the utility and terminate the ServiceBean if needed
         */
        public void terminate() {
            if(!terminated) {
                for (Map.Entry<DestroyAdmin, Subject> mapEntry :
                    registrationMap.entrySet()) {
                    final DestroyAdmin dAdmin = mapEntry.getKey();
                    final Subject subject = mapEntry.getValue();
                    if (subject != null) {
                        try {
                            Subject.doAsPrivileged(subject,
                                                   new PrivilegedExceptionAction<Void>() {
                                                       public Void run() throws Exception {
                                                           try {
                                                               dAdmin.destroy();
                                                           } catch (Exception e) {
                                                               //e.printStackTrace();
                                                           }
                                                           return (null);
                                                       }
                                                   },
                                                   null);
                        } catch (PrivilegedActionException e) {
                            e.printStackTrace();
                        }
                    } else {
                        try {
                            dAdmin.destroy();
                        } catch (Exception e) {
                            //e.printStackTrace();
                        }
                    }

                }
            }
        }

        /**
         * @see org.rioproject.impl.container.DiscardManager#discard
         */
        public void discard() {
            if(terminated)
                return;
            terminated = true;
            new Destroyer(null, null);
        }

        /**
         * @see com.sun.jini.start.LifeCycle#unregister
         */
        public boolean unregister(final Object impl) {
            if(terminated)
                return (true);
            terminate();
            new Destroyer(null, null);
            return (true);
        }
    }

    /**
     * ShutdownHook for the ServiceBean
     */
    static class ShutdownHook extends Thread {
        ShutdownHook() {
            super("ShutdownHook");
        }

        public void run() {
            try {
                if(sbLifeCycleManager != null) {
                    sbLifeCycleManager.terminate();
                }
            } catch(Throwable t) {
                logger.error("Terminating ServiceBean", t);
            }
        }
    }
}
TOP

Related Classes of org.rioproject.impl.servicebean.ServiceBeanActivation

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.