Package org.rioproject.cybernode.service

Source Code of org.rioproject.cybernode.service.ServiceBeanExecutorImpl$CreateFDH

/*
* Copyright 2008 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.cybernode.service;

import com.sun.jini.start.LifeCycle;
import net.jini.config.Configuration;
import net.jini.config.ConfigurationProvider;
import net.jini.core.lookup.ServiceID;
import net.jini.export.Exporter;
import net.jini.id.Uuid;
import org.rioproject.config.Constants;
import org.rioproject.deploy.ServiceBeanInstance;
import org.rioproject.deploy.ServiceBeanInstantiationException;
import org.rioproject.deploy.ServiceRecord;
import org.rioproject.event.EventHandler;
import org.rioproject.exec.ServiceBeanExecListener;
import org.rioproject.exec.ServiceBeanExecutor;
import org.rioproject.impl.config.ExporterConfig;
import org.rioproject.impl.container.ServiceBeanContainerListener;
import org.rioproject.impl.container.ServiceBeanLoaderResult;
import org.rioproject.impl.container.ServiceLogUtil;
import org.rioproject.impl.exec.JVMProcessMonitor;
import org.rioproject.impl.exec.VirtualMachineHelper;
import org.rioproject.impl.fdh.FaultDetectionListener;
import org.rioproject.impl.fdh.JMXFaultDetectionHandler;
import org.rioproject.impl.opstring.OpStringManagerProxy;
import org.rioproject.impl.servicebean.ServiceBeanActivation;
import org.rioproject.impl.servicebean.ServiceBeanAdapter;
import org.rioproject.impl.servicebean.ServiceElementUtil;
import org.rioproject.impl.system.ComputeResource;
import org.rioproject.impl.system.measurable.MeasurableCapability;
import org.rioproject.impl.system.measurable.cpu.CPU;
import org.rioproject.impl.system.measurable.memory.Memory;
import org.rioproject.opstring.OperationalStringManager;
import org.rioproject.opstring.ServiceElement;
import org.rioproject.rmi.RegistryUtil;
import org.rioproject.servicebean.ServiceBeanContext;
import org.rioproject.system.ComputeResourceUtilization;
import org.rioproject.system.SystemWatchID;
import org.rioproject.system.capability.PlatformCapability;
import org.rioproject.watch.WatchDataSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.rmi.Remote;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;

/**
* Provides support to create a ServiceBean in it's own JVM.
*
* @author Dennis Reedy
*/
@SuppressWarnings({"unused", "PMD.AvoidThrowingRawExceptionTypes"})
public class ServiceBeanExecutorImpl implements ServiceBeanExecutor,
                                                ServiceBeanContainerListener,
                                                FaultDetectionListener<String> {
    private ServiceBeanContainerImpl container;
    private Exporter exporter;
    private String execBindName;
    private ServiceBeanContext context;
    private int cybernodeRegistryPort;
    private Registry registry;
    private ServiceBeanExecListener listener;
    private JMXFaultDetectionHandler fdh;
    private ComputeResource computeResource;
    private ComputeResourcePolicyHandler computeResourcePolicyHandler;
    private ServiceBeanInstance instance;
    private final String myID;
    private final AtomicBoolean initializing = new AtomicBoolean(true);
    static final String CONFIG_COMPONENT = "org.rioproject.cybernode";
    private Logger logger = LoggerFactory.getLogger(ServiceBeanExecutorImpl.class);

    /**
     * Create a ServiceBeanExecutor launched from the ServiceStarter
     * framework
     *
     * @param configArgs Configuration arguments
     * @param lifeCycle The LifeCycle object that started the
     * ServiceBeanExecutor
     *
     * @throws Exception if bootstrapping fails
     */
    public ServiceBeanExecutorImpl(final String[] configArgs, final LifeCycle lifeCycle)
        throws Exception {
        myID = VirtualMachineHelper.getID();
        String sPort = System.getProperty(Constants.REGISTRY_PORT, "0");
        if (Integer.parseInt(sPort) == 0)
            logger.warn("The RMI Registry port provided (or obtained by default) is 0. " +
                        "Because it is 0, the port will default to {}. This port may be " +
                        "taken by another RMI Registry instance. If there is an MBeanServer " +
                        "bound to that RMI Registry instance, the ServiceBeanExecutorImpl will monitor the " +
                        "ability to connect to that MBeanServer. If that MBeanServer is terminated, " +
                        "the ServiceBeanExecutorImpl will also terminate. Care should be taken to not " +
                        "use the default RMI Registry port.", Registry.REGISTRY_PORT);
        cybernodeRegistryPort = Integer.parseInt(sPort);
        execBindName = System.getProperty(Constants.SERVICE_BEAN_EXEC_NAME, "ServiceBeanExecutorImpl");
        bootstrap(configArgs);
        logger.info("Started ServiceBeanExecutor for {}", execBindName);
    }

    private void bootstrap(final String[] configArgs) throws Exception {
        ClassLoader cCL = Thread.currentThread().getContextClassLoader();
        Configuration config = ConfigurationProvider.getInstance(configArgs, cCL);
        container = new ServiceBeanContainerImpl(config);
        computeResource = new ComputeResource(config);

        /* Setup persistent provisioning attributes */
        boolean provisionEnabled = (Boolean) config.getEntry("org.rioproject.cybernode",
                                                             "provisionEnabled",
                                                             Boolean.class,
                                                             true);
        computeResource.setPersistentProvisioning(provisionEnabled);       
        String provisionRoot = Environment.setupProvisionRoot(provisionEnabled, config);
        computeResource.setPersistentProvisioningRoot(provisionRoot);

        MeasurableCapability[] mCaps = loadMeasurables(config);
        for(MeasurableCapability mCap : mCaps) {
            computeResource.addMeasurableCapability(mCap);
            mCap.start();
        }

        container.setComputeResource(computeResource);
        container.addListener(this);

        context = ServiceBeanActivation.getServiceBeanContext(CONFIG_COMPONENT,
                                                              "Cybernode",
                                                              configArgs,
                                                              config,
                                                              getClass().getClassLoader());
        registry = LocateRegistry.getRegistry(cybernodeRegistryPort);

        exporter = ExporterConfig.getExporter(config, "org.rioproject.cybernode", "exporter");

        int createdRegistryPort = RegistryUtil.getRegistry();
        if(createdRegistryPort>0) {
            System.setProperty(Constants.REGISTRY_PORT, Integer.toString(createdRegistryPort));
        } else {
            throw new RuntimeException("Unable to create RMI Registry");
        }

        Remote proxy = exporter.export(this);
        registry.bind(execBindName, proxy);
        initializing.set(false);

        new Thread(new CreateFDH(config, this)).start();
    }

    public String getID() {
        return myID;
    }

    public void setUuid(final Uuid uuid) {
        if(uuid==null)
            throw new IllegalArgumentException("uuid cannot be null");
        container.setUuid(uuid);
    }

    public void setServiceBeanExecListener(final ServiceBeanExecListener listener) {
        this.listener = listener;
    }

    public void applyPlatformCapabilities(final PlatformCapability[] pCaps) {
        if(pCaps==null)
            return;
        for(PlatformCapability pCap : pCaps) {
            logger.info("Adding [{}] capability", pCap.getName());
            computeResource.addPlatformCapability(pCap);
        }
    }

    @Override
    public ServiceBeanInstance getServiceBeanInstance()  {
        return instance;
    }

    public ServiceBeanInstance instantiate(final ServiceElement sElem,
                                           final OperationalStringManager opStringMgr)
        throws ServiceBeanInstantiationException {
        logger.info("Instantiating {}, service counter={}", sElem.getName(), container.getServiceCounter());
        if (container.getServiceCounter() > 0)
            throw new ServiceBeanInstantiationException("ServiceBeanExecutor has already instantiated a service");

        OperationalStringManager opMgr = opStringMgr;
        try {
            opMgr = OpStringManagerProxy.getProxy(sElem.getOperationalStringName(),
                                                  opStringMgr,
                                                  context.getDiscoveryManagement());
        } catch (Exception e) {
            logger.warn("Unable to create proxy for OperationalStringManager, using provided OperationalStringManager", e);

        }

        /* Set up thread deadlock detection */
        ServiceElementUtil.setThreadDeadlockDetector(sElem, null);

        /* Get the SLA ThresholdEvent wired up */
        EventHandler slaThresholdEventHandler = null;
        instance = container.activate(sElem, opMgr, null);
        ServiceBeanDelegateImpl delegate = (ServiceBeanDelegateImpl) container.getServiceBeanDelegate(instance.getServiceBeanID());
        ServiceBeanLoaderResult result = delegate.getLoadedServiceResult();
        if(result.getImpl() instanceof ServiceBeanAdapter) {
            slaThresholdEventHandler = ((ServiceBeanAdapter)result.getImpl()).getSLAEventHandler();
        } else {
            if(result.getBeanAdapter()!=null) {
                slaThresholdEventHandler = result.getBeanAdapter().getSLAEventHandler();
            } else {
                String className = result.getImpl()==null?"<NO IMPLEMENTATION>":result.getImpl().getClass().getName();
                logger.warn("SLAThresholdEvent notifications from this forked service are not enabled, service class does not provide support for Rio event registration {}.",
                            className);
            }
        }
        if(slaThresholdEventHandler!=null) {
            computeResourcePolicyHandler = new ComputeResourcePolicyHandler(sElem,
                                                                            slaThresholdEventHandler,
                                                                            null,
                                                                            instance);
            computeResource.addThresholdListener(computeResourcePolicyHandler);
        }
        return instance;
    }

    public void update(final ServiceElement element, final OperationalStringManager opStringMgr)  {
        container.update(new ServiceElement[]{element}, opStringMgr);
    }

    public ComputeResourceUtilization getComputeResourceUtilization() {
        return computeResource.getComputeResourceUtilization();
    }

    public void serviceInstantiated(final ServiceRecord record) {
        ServiceElement service = record.getServiceElement();
        logger.info("Instantiated {}, {}", ServiceLogUtil.logName(service), ServiceLogUtil.discoveryInfo(service));
        try {
            listener.serviceInstantiated(record);
        } catch (RemoteException e) {
            logger.warn("Notifying Cybernode that the service is active", e);
        }
    }

    public void serviceDiscarded(final ServiceRecord record) {
        logger.info("Destroying ServiceBeanExecutor for {}", execBindName);
        if(fdh!=null)
            fdh.terminate();

        if(computeResourcePolicyHandler!=null) {
            computeResourcePolicyHandler.terminate();
        }

        exporter.unexport(true);
        try {
            registry.unbind(execBindName);
        } catch (Exception e) {
            logger.warn("{}: {}, Unbinding from RMI Registry", e.getClass().getName(), e.getMessage());
        }
        if(record!=null) {
            try {
                listener.serviceDiscarded(record);
            } catch (RemoteException e) {
                logger.warn("{}: {}, Notifying Cybernode that we are exiting", e.getClass().getName(), e.getMessage());
            }
        }
       
        /* Perform the system exit in a thread, allowing the method to return */
        new Thread(new Runnable() {
            public void run() {
                System.exit(0);
            }
        }).start();
    }

    public void serviceFailure(final Object service, final String pid) {
        logger.warn("Parent Cybernode has orphaned us, exiting");
        container.terminate();
        serviceDiscarded(null);
    }

    public WatchDataSource[] fetch() {
        List<WatchDataSource> watchDataSources = new ArrayList<WatchDataSource>();
        for(MeasurableCapability mCap : computeResource.getMeasurableCapabilities()) {
            watchDataSources.add(mCap.getWatchDataSource());
        }
        return watchDataSources.toArray(new WatchDataSource[watchDataSources.size()]);
    }

    public WatchDataSource fetch(final String id) {
        WatchDataSource watchDataSource = null;
        for(MeasurableCapability mCap : computeResource.getMeasurableCapabilities()) {
            if(mCap.getId().equals(id)) {
                watchDataSource = mCap.getWatchDataSource();
                break;
            }
        }
        return watchDataSource;
    }

    private MeasurableCapability[] loadMeasurables(final Configuration config) {
        List<MeasurableCapability> measurables = new ArrayList<MeasurableCapability>();
        /* Create the Memory MeasurableCapability */
        MeasurableCapability memory = new Memory(config);
        if(memory.isEnabled())
            measurables.add(memory);

        try{
            MeasurableCapability cpu = new CPU(config, SystemWatchID.PROC_CPU, true);
            if(cpu.isEnabled())
                measurables.add(cpu);
        } catch (RuntimeException e) {
            logger.warn("JVM CPU monitoring not supported");
        }
        return measurables.toArray(new MeasurableCapability[measurables.size()]);
    }

    private class CreateFDH implements Runnable {
        private final Configuration config;
        private final FaultDetectionListener<String> faultDetectionListener;

        private CreateFDH(final Configuration config, final FaultDetectionListener<String> faultDetectionListener) {
            this.config = config;
            this.faultDetectionListener = faultDetectionListener;
        }

        public void run() {
            final String parentPID = System.getProperty(Constants.PROCESS_ID);
            if(parentPID!=null) {
                JVMProcessMonitor.getInstance().monitor(parentPID, faultDetectionListener);
            } else {
                logger.error("Cybernode PID is null, unable to setup FDH to make sure Cybernode doesn't orphan us");
            }
        }
    }

    class WrappedFaultDetectionListener implements FaultDetectionListener<ServiceID> {
        private final FaultDetectionListener<String> wrapped;

        WrappedFaultDetectionListener(FaultDetectionListener<String> wrapped) {
            this.wrapped = wrapped;
        }

        @Override
        public void serviceFailure(Object service, ServiceID serviceID) {
            wrapped.serviceFailure(service, serviceID==null?null:serviceID.toString());
        }
    }
}
TOP

Related Classes of org.rioproject.cybernode.service.ServiceBeanExecutorImpl$CreateFDH

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.