All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.ow2.petals.microkernel.container.lifecycle.ComponentLifeCycleImpl Maven / Gradle / Ivy

There is a newer version: 4.3.0
Show newest version
/**
 * Copyright (c) 2005-2012 EBM WebSourcing, 2012-2016 Linagora
 * 
 * This program/library is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 2.1 of the License, or (at your
 * option) any later version.
 * 
 * This program/library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
 * for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program/library; If not, see http://www.gnu.org/licenses/
 * for the GNU Lesser General Public License version 2.1.
 */
package org.ow2.petals.microkernel.container.lifecycle;

import java.util.concurrent.Callable;
import java.util.logging.Logger;

import javax.jbi.JBIException;
import javax.management.ObjectName;

import org.objectweb.fractal.fraclet.annotations.Component;
import org.objectweb.fractal.fraclet.annotations.Interface;
import org.objectweb.fractal.fraclet.annotations.Lifecycle;
import org.objectweb.fractal.fraclet.annotations.Requires;
import org.objectweb.fractal.fraclet.types.Step;
import org.ow2.petals.basisapi.exception.PetalsException;
import org.ow2.petals.jbi.messaging.PetalsDeliveryChannel;
import org.ow2.petals.microkernel.api.container.ComponentLifeCycle;
import org.ow2.petals.microkernel.api.container.ContainerService;
import org.ow2.petals.microkernel.api.container.Installer;
import org.ow2.petals.microkernel.api.container.IsolatingThread;
import org.ow2.petals.microkernel.api.jbi.component.PetalsComponentContext;
import org.ow2.petals.microkernel.api.system.SystemStateService;

import com.ebmwebsourcing.easycommons.log.LoggingUtil;

/**
 * Implementation of the ComponentLifeCycle mbean.
 * 
 * The synchonisation and ordering of lifecycle actions is managed using synchronization on this and all the actual
 * actions on the component implementation rely on the component {@link IsolatingThread}.
 * 
 * @author Adrien LOUIS - EBM WebSourcing
 * @author wjoseph - EBM WebSourcing
 * @author Nicolas Salatge - EBM WebSourcing
 * @author vnoel
 */
@Component(provides = @Interface(name = ComponentLifeCycle.FRACTAL_SRV_ITF_NAME, signature = ExtendedComponentLifeCycle.class))
public class ComponentLifeCycleImpl implements ExtendedComponentLifeCycle {

    private final LoggingUtil log = new LoggingUtil(Logger.getLogger(ComponentLifeCycle.COMPONENT_LOGGER_NAME));

    /**
     * Platform component :: SystemState Service
     */
    @Requires(name = "systemstate")
    private SystemStateService systemStateService;

    /**
     * Container Component :: Container Service
     */
    @Requires(name = "container")
    private ContainerService containerService;

    @Requires(name = "installer")
    private Installer componentInstaller;

    private PetalsComponentContext componentContext;

    private ClassLoader classLoader;

    private javax.jbi.component.ComponentLifeCycle lifecycle;

    private IsolatingThread separateThread;

    private String state;

    private String name;

    private boolean firstStart = true;

    /**
     * Force the set of a state, ignoring eventual errors when changing of states
     */
    private boolean forcedState = false;

    @Override
    public void setForcedState(final boolean forcedState) {
        this.forcedState = forcedState;
    }

    @Override
    public synchronized String getCurrentState() {
        if (!(SHUTDOWN.equals(this.state) || STARTED.equals(this.state) || STOPPED.equals(this.state)
                || UNKNOWN.equals(this.state))) {
            return UNKNOWN;
        } else {
            return this.state;
        }
    }

    private void setState(String state) throws JBIException {
        if (!(SHUTDOWN.equals(state) || STARTED.equals(state) || STOPPED.equals(state) || UNKNOWN.equals(state))) {
            throw new JBIException(
                    "State '" + state + "' isn't defined by the JBI specification. No state change done.");
        }

        this.state = state;

        try {
            this.systemStateService.updateComponentLifeCycleState(this.name, state);
        } catch (final Exception e) {
            String msg = "Component state can't be persisted";
            this.log.error(msg, e);
            throw new JBIException(msg, e);
        }
    }

    private boolean isShutdownState() {
        return SHUTDOWN.equals(this.getCurrentState());
    }

    private boolean isStartedState() {
        return STARTED.equals(this.getCurrentState());
    }

    private boolean isStoppedState() {
        return STOPPED.equals(this.getCurrentState());
    }

    @Override
    public synchronized void shutDown() throws JBIException {
        this.log.start(name);

        if (isShutdownState()) {
            log.warning("The component '" + name + "' is already shut down");
        } else if (forcedState || isStoppedState()) {

            // if a service unit (on any state) need this component, you can't shutdown the component
            if (!forcedState && !containerService.getServiceUnitsLifeCyclesByComponent(name).isEmpty()) {
                // TODO in the case it is forced, shouldn't we force undeploy them then?
                throw new JBIException("Cannot uninstall a component which holds deployed Service Unit(s)");
            }

            try {
                lifecycleShutDown();
                setState(SHUTDOWN);
            } catch (final Exception re) {
                log.error(re.getMessage(), re);
                // TODO first try to revert before?
                setState(UNKNOWN);
                throw new JBIException(
                        "An exception occured while shutting down the component  '" + name + "': " + re.getMessage());
            }
        } else {
            throw new JBIException("The component '" + name + "' cannot be shut down in this state: " + state);
        }

        this.log.end(name);
    }

    @Override
    public synchronized void start() throws JBIException {
        this.log.start(name);

        if (isStartedState()) {
            log.warning("The component '" + name + "' is already started");
        } else if (forcedState || isShutdownState() || isStoppedState()) {
            try {
                if (isShutdownState()) {
                    lifecycleInit();
                    setState(STOPPED);
                }
                lifecycleStart();
                setState(STARTED);
            } catch (final Exception re) {
                log.error(re.getMessage(), re);
                // TODO first try to revert before?
                setState(UNKNOWN);
                throw new JBIException(
                        "An exception occured while starting the component '" + name + "' : " + re.getMessage());
            }
        } else {
            throw new JBIException("The component '" + name + "' cannot be started in this state: " + state);
        }

        this.log.end(name);
    }

    @Override
    public synchronized void stop() throws JBIException {
        this.log.start(name);

        if (isStoppedState()) {
            log.warning("The component '" + name + "' is already stopped");
        } else if (forcedState || isStartedState()) {
            try {
                lifecycleStop();
                setState(STOPPED);
            } catch (final Exception re) {
                log.error(re.getMessage(), re);
                // TODO first try to revert before?
                setState(UNKNOWN);
                throw new JBIException(
                        "An exception occured while stopping the component '" + name + "' : " + re.getMessage());
            }
        } else {
            throw new JBIException("The component '" + name + "' cannot be stopped in this state: " + state);
        }

        this.log.end();
    }

    private void lifecycleInit() throws JBIException {
        this.separateThread.execute(new Callable() {
            @Override
            public Void call() throws Exception {
                ComponentLifeCycleImpl.this.lifecycle.init(ComponentLifeCycleImpl.this.componentContext);
                return null;
            }
        }, this.classLoader);
    }

    private void lifecycleShutDown() throws JBIException {
        try {
            this.separateThread.execute(new Callable() {
                @Override
                public Void call() throws Exception {
                    ComponentLifeCycleImpl.this.lifecycle.shutDown();
                    return null;
                }
            }, this.classLoader);
        } finally {
            // always close the Channel if needed
            final PetalsDeliveryChannel channel = this.componentContext.getDeliveryChannelInstance();
            if (channel != null && channel.isOpened()) {
                try {
                    channel.close();
                } catch (final Exception e) {
                    log.warning("Can't close the delivery channel on shutdown", e);
                }
            }
        }
    }

    private void lifecycleStart() throws JBIException {
        this.separateThread.execute(new Callable() {
            @Override
            public Void call() throws Exception {
                ComponentLifeCycleImpl.this.lifecycle.start();
                return null;
            }
        }, this.classLoader);
    }

    private void lifecycleStop() throws JBIException {
        this.separateThread.execute(new Callable() {
            @Override
            public Void call() throws Exception {
                ComponentLifeCycleImpl.this.lifecycle.stop();
                return null;
            }
        }, this.classLoader);
    }

    @Override
    public synchronized ObjectName getExtensionMBeanName() throws JBIException {
        // TODO does it make sense not to check the current state of the component? According to the spec, no.
        return this.separateThread.execute(new Callable() {
            @Override
            public ObjectName call() throws Exception {
                return ComponentLifeCycleImpl.this.lifecycle.getExtensionMBeanName();
            }
        }, this.classLoader);
    }

    /**
     * Initialization of the petals component
     * 
     * @throws PetalsException
     * @throws JBIException
     * 
     */
    @Lifecycle(step = Step.START)
    public void startFractalComponent() throws Exception {
        this.log.start();

        if (firstStart) {
            this.componentContext = componentInstaller.getComponentContext();
            this.classLoader = componentContext.getComponent().getClass().getClassLoader();
            this.lifecycle = componentContext.getComponent().getLifeCycle();
            this.name = componentInstaller.getComponentName();
            this.separateThread = componentInstaller.getComponentThread();

            // set the state to SHUTDOWN, as the JBI specifications specifies
            this.setState(SHUTDOWN);

            firstStart = false;
        } else {
            // Note: this method is never really called after stopFractalComponent has been called,
            // but the following is present for coherence: this is NOT related to restoration (for restoration, init and
            // start are called as needed by the restoration subsystem)
            if (STARTED.equals(this.getCurrentState())) {
                try {
                    this.lifecycleInit();
                    this.lifecycleStart();
                } catch (final JBIException e) {
                    this.log.warning("Failed to restore to start the component '" + this.name + "'", e);
                }
            }

            if (STOPPED.equals(this.getCurrentState())) {
                try {
                    this.lifecycleInit();
                } catch (final JBIException e) {
                    this.log.warning("Failed to restore to stop the component '" + this.name + "'", e);
                }
            }
        }

        this.log.end();

    }

    /**
     * Stop of the Fractal component, means shutdown the life cycle.
     * 
     */
    @Lifecycle(step = Step.STOP)
    public void stopFractalComponent() {
        this.log.start();

        this.setForcedState(true);
        try {
            if (STARTED.equals(this.getCurrentState())) {
                try {
                    this.lifecycleStop();
                    this.lifecycleShutDown();
                } catch (JBIException e) {
                    this.log.warning("Failed to stop the component '" + this.name + "'", e);
                }
            }

            if (STOPPED.equals(this.getCurrentState())) {
                try {
                    this.lifecycleShutDown();
                } catch (JBIException e) {
                    this.log.warning("Failed to shut down the component '" + this.name + "'", e);
                }
            }
        } finally {
            this.setForcedState(false);
        }

        this.log.end();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy