Package org.apache.servicemix.jbi.framework

Source Code of org.apache.servicemix.jbi.framework.ServiceUnitLifeCycle$TimedOutExecutor

/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements.  See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.apache.servicemix.jbi.framework;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.util.concurrent.Callable;

import javax.jbi.component.ServiceUnitManager;
import javax.jbi.management.DeploymentException;
import javax.management.JMException;
import javax.management.MBeanAttributeInfo;
import javax.management.MBeanOperationInfo;

import org.apache.servicemix.jbi.deployment.Descriptor;
import org.apache.servicemix.jbi.deployment.DescriptorFactory;
import org.apache.servicemix.jbi.deployment.ServiceUnit;
import org.apache.servicemix.jbi.deployment.Services;
import org.apache.servicemix.jbi.event.ServiceUnitEvent;
import org.apache.servicemix.jbi.event.ServiceUnitListener;
import org.apache.servicemix.jbi.management.AttributeInfoHelper;
import org.apache.servicemix.jbi.management.MBeanInfoProvider;
import org.apache.servicemix.jbi.management.OperationInfoHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class ServiceUnitLifeCycle implements ServiceUnitMBean, MBeanInfoProvider {

    /**
     * Default timeout for deployment operation.
     */
    private static final long DEFAULT_DEPLOYMENT_OPERATION_TIMEOUT = 2 * 60 * 1000;

    /**
     * Name of the system property that contains deployment operation timeout.
     */
    private static final String DEPLOYMENT_OPERATION_TIMEOUT_PROPERTY = "org.apache.servicemix.deployment.timeout";

    private static final transient Logger LOGGER = LoggerFactory.getLogger(ServiceUnitLifeCycle.class);

    private ServiceUnit serviceUnit;

    private String currentState = SHUTDOWN;
   
    private String serviceAssembly;
   
    private Registry registry;

    private PropertyChangeListener listener;
   
    private Services services;
   
    private File rootDir;
   
    public ServiceUnitLifeCycle(ServiceUnit serviceUnit,
                                String serviceAssembly,
                                Registry registry,
                                File rootDir) {
        this.serviceUnit = serviceUnit;
        this.serviceAssembly = serviceAssembly;
        this.registry = registry;
        this.rootDir = rootDir;
        Descriptor d = DescriptorFactory.buildDescriptor(rootDir);
        if (d != null) {
            services = d.getServices();
        }
    }

    /**
     * Deployment operation executor that supports timeout.
     */
    private class TimedOutExecutor {

        private final ClassLoader classLoader;
        private final String name;
        private final Callable<?> task;
        private Exception fault;

        /**
         * Constructor.
         *
         * @param classLoader the class loader to use for task execution.
         * @param name Name of this executor. Used for error reporting purposes.
         * @param task Task to execute. Return value of task is not used.
         */
        public TimedOutExecutor(ClassLoader classLoader, String name, Callable<?> task) {
            this.classLoader = classLoader;
            this.name = name;
            this.task = task;
        }

        private class Worker implements Runnable {

            public void run() {
                try {
                    task.call();
                } catch (Exception e) {
                    fault = e;
                }
            }
        }

        /**
         * Executes task respecting timeout.
         *
         * @param timeout Timeout for task execution in milliseconds.
         * @throws DeploymentException If task throws an exception, current thread is interrupted or timeout expires.
         */
        public void execute(long timeout) throws DeploymentException {
            Thread worker = new Thread(new Worker(), "AsyncDeployer for " + name);
            worker.setContextClassLoader(classLoader);
            worker.start();
            try {
                worker.join(timeout);
                if (worker.isAlive()) {
                    worker.interrupt();
                    throw new DeploymentException("Timeout expired while waiting for async operation " + name);
                } else {
                    if (fault != null) {
                        throw new DeploymentException("Error while executing async operation " + name, fault);
                    }
                }
            } catch (InterruptedException interruptedException) {
                Thread.currentThread().interrupt();
                throw new DeploymentException("Interrupted while waiting for async operation " + name, interruptedException);
            }
        }
    }

    /**
     * Returns effective deployment operation timeout.
     *
     * @return Timeout in milliseconds.
     */
    private long getDeploymentTimeout() {
        String propertyValue = System.getProperty(DEPLOYMENT_OPERATION_TIMEOUT_PROPERTY);
        if (propertyValue == null) {
            return DEFAULT_DEPLOYMENT_OPERATION_TIMEOUT;
        }
        try {
            return Long.parseLong(propertyValue);
        } catch (NumberFormatException numberFormatException) {
            LOGGER.warn("Wrong value for system property {}", DEPLOYMENT_OPERATION_TIMEOUT_PROPERTY, numberFormatException);
            return DEFAULT_DEPLOYMENT_OPERATION_TIMEOUT;
        }
    }

    /**
     * Initialize the service unit.
     *
     * @throws DeploymentException
     */
    public void init() throws DeploymentException {
        LOGGER.info("Initializing service unit: {}", getName());
        checkComponentStarted("init");
        final ServiceUnitManager sum = getServiceUnitManager();
        final File path = getServiceUnitRootPath();
        new TimedOutExecutor(getComponentClassLoader(), "init " + getName(),
                new Callable<Object>() {
                    public Object call() throws Exception {
                        sum.init(getName(), path.getAbsolutePath());
                        return null;
                    }
                }).execute(getDeploymentTimeout());
        currentState = STOPPED;
    }
   
    /**
     * Start the service unit.
     *
     * @throws DeploymentException
     */
    public void start() throws DeploymentException {
        LOGGER.info("Starting service unit: {}", getName());
        checkComponentStarted("start");
        final ServiceUnitManager sum = getServiceUnitManager();
        new TimedOutExecutor(getComponentClassLoader(), "start " + getName(),
                new Callable<Object>() {
                    public Object call() throws Exception {
                        sum.start(getName());
                        return null;
                    }
                }).execute(getDeploymentTimeout());
        currentState = STARTED;
    }

    /**
     * Stop the service unit. This suspends current messaging activities.
     *
     * @throws DeploymentException
     */
    public void stop() throws DeploymentException {
        LOGGER.info("Stopping service unit: {}", getName());
        checkComponentStarted("stop");
        final ServiceUnitManager sum = getServiceUnitManager();
        new TimedOutExecutor(getComponentClassLoader(), "stop " + getName(),
                new Callable<Object>() {
                    public Object call() throws Exception {
                        sum.stop(getName());
                        return null;
                    }
                }).execute(getDeploymentTimeout());
        currentState = STOPPED;
    }

    /**
     * Shut down the service unit.
     * This releases resources, preparatory to uninstallation.
     *
     * @throws DeploymentException
     */
    public void shutDown() throws DeploymentException {
        LOGGER.info("Shutting down service unit: {}", getName());
        checkComponentStartedOrStopped("shutDown");
        final ServiceUnitManager sum = getServiceUnitManager();
        new TimedOutExecutor(getComponentClassLoader(), "shutdown " + getName(),
                new Callable<Object>() {
                    public Object call() throws Exception {
                        sum.shutDown(getName());
                        return null;
                    }
                }).execute(getDeploymentTimeout());
        currentState = SHUTDOWN;
    }

    /**
     * @return the currentState as a String
     */
    public String getCurrentState() {
        return currentState;
    }

    public boolean isShutDown() {
        return currentState.equals(SHUTDOWN);
    }

    public boolean isStopped() {
        return currentState.equals(STOPPED);
    }

    public boolean isStarted() {
        return currentState.equals(STARTED);
    }
   
    /**
     * @return the name of the ServiceAssembly
     */
    public String getName() {
        return serviceUnit.getIdentification().getName();
    }

    /**
     * @return the description of the ServiceAssembly
     */
    public String getDescription() {
        return serviceUnit.getIdentification().getDescription();
    }
   
    public String getComponentName() {
        return serviceUnit.getTarget().getComponentName();
    }

    public String getServiceAssembly() {
        return serviceAssembly;
    }

    public String getDescriptor() {
        File suDir = getServiceUnitRootPath();
        return DescriptorFactory.getDescriptorAsText(suDir);
    }
   
    public Services getServices() {
        return services;
    }

    protected void checkComponentStarted(String task) throws DeploymentException {
        String componentName = getComponentName();
        String suName = getName();
        ComponentMBeanImpl lcc = registry.getComponent(componentName);
        if (lcc == null) {
            throw ManagementSupport.componentFailure("deploy", componentName, "Target component "
                            + componentName + " for service unit " + suName + " is not installed");
        }
        if (!lcc.isStarted()) {
            throw ManagementSupport.componentFailure("deploy", componentName, "Target component "
                            + componentName + " for service unit " + suName + " is not started");
        }
        if (lcc.getServiceUnitManager() == null) {
            throw ManagementSupport.componentFailure("deploy", componentName, "Target component "
                            + componentName + " for service unit " + suName + " does not accept deployments");
        }
    }
   
    protected void checkComponentStartedOrStopped(String task) throws DeploymentException {
        String componentName = getComponentName();
        String suName = getName();
        ComponentMBeanImpl lcc = registry.getComponent(componentName);
        if (lcc == null) {
            throw ManagementSupport.componentFailure("deploy", componentName, "Target component "
                            + componentName + " for service unit " + suName + " is not installed");
        }
        if (!lcc.isStarted() && !lcc.isStopped()) {
            throw ManagementSupport.componentFailure("deploy", componentName, "Target component "
                            + componentName + " for service unit " + suName + " is not started");
        }
        if (lcc.getServiceUnitManager() == null) {
            throw ManagementSupport.componentFailure("deploy", componentName, "Target component "
                            + componentName + " for service unit " + suName + " does not accept deployments");
        }
    }
   
    protected File getServiceUnitRootPath() {
        return rootDir;
    }
   
    protected ServiceUnitManager getServiceUnitManager() {
        ComponentMBeanImpl lcc = registry.getComponent(getComponentName());
        return lcc.getServiceUnitManager();
    }

    protected ClassLoader getComponentClassLoader() {
        ComponentMBeanImpl lcc = registry.getComponent(getComponentName());
        // TODO: should retrieve the real component class loader
        return lcc.getComponent().getClass().getClassLoader();
    }

    public MBeanAttributeInfo[] getAttributeInfos() throws JMException {
        AttributeInfoHelper helper = new AttributeInfoHelper();
        helper.addAttribute(getObjectToManage(), "currentState", "current state of the service unit");
        helper.addAttribute(getObjectToManage(), "name", "name of the service unit");
        helper.addAttribute(getObjectToManage(), "componentName", "component name of the service unit");
        helper.addAttribute(getObjectToManage(), "serviceAssembly", "service assembly name of the service unit");
        helper.addAttribute(getObjectToManage(), "description", "description of the service unit");
        return helper.getAttributeInfos();
    }

    public MBeanOperationInfo[] getOperationInfos() throws JMException {
        OperationInfoHelper helper = new OperationInfoHelper();
        helper.addOperation(getObjectToManage(), "getDescriptor", "retrieve the jbi descriptor for this unit");
        return helper.getOperationInfos();
    }

    public Object getObjectToManage() {
        return this;
    }

    public String getType() {
        return "ServiceUnit";
    }

    public String getSubType() {
        return getComponentName();
    }

    public void setPropertyChangeListener(PropertyChangeListener l) {
        this.listener = l;
    }

    protected void firePropertyChanged(String name, Object oldValue, Object newValue) {
        PropertyChangeListener l = listener;
        if (l != null) {
            PropertyChangeEvent event = new PropertyChangeEvent(this, name, oldValue, newValue);
            l.propertyChange(event);
        }
    }

    public String getKey() {
        return getComponentName() + "/" + getName();
    }

    protected void fireEvent(int type) {
        ServiceUnitEvent event = new ServiceUnitEvent(this, type);
        ServiceUnitListener[] listeners = (ServiceUnitListener[]) registry.getContainer().getListeners(ServiceUnitListener.class);
        for (int i = 0; i < listeners.length; i++) {
            switch (type) {
            case ServiceUnitEvent.UNIT_STARTED:
                listeners[i].unitStarted(event);
                break;
            case ServiceUnitEvent.UNIT_STOPPED:
                listeners[i].unitStopped(event);
                break;
            case ServiceUnitEvent.UNIT_SHUTDOWN:
                listeners[i].unitShutDown(event);
                break;
            default:
                break;
            }
        }
    }

}
TOP

Related Classes of org.apache.servicemix.jbi.framework.ServiceUnitLifeCycle$TimedOutExecutor

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.
om/analytics.js','ga'); ga('create', 'UA-20639858-1', 'auto'); ga('send', 'pageview');