org.mule.component.DefaultComponentLifecycleAdapter.java Source code

Java tutorial

Introduction

Here is the source code for org.mule.component.DefaultComponentLifecycleAdapter.java

Source

/*
 * $Id$
 * --------------------------------------------------------------------------------------
 * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
 *
 * The software in this package is published under the terms of the CPAL v1.0
 * license, a copy of which has been included with this distribution in the
 * LICENSE.txt file.
 */

package org.mule.component;

import org.mule.DefaultMuleEventContext;
import org.mule.RequestContext;
import org.mule.api.DefaultMuleException;
import org.mule.api.MuleContext;
import org.mule.api.MuleEvent;
import org.mule.api.MuleEventContext;
import org.mule.api.MuleException;
import org.mule.api.component.JavaComponent;
import org.mule.api.component.LifecycleAdapter;
import org.mule.api.construct.FlowConstruct;
import org.mule.api.lifecycle.Disposable;
import org.mule.api.lifecycle.Initialisable;
import org.mule.api.lifecycle.InitialisationException;
import org.mule.api.lifecycle.Startable;
import org.mule.api.lifecycle.Stoppable;
import org.mule.api.model.EntryPointResolverSet;
import org.mule.config.i18n.CoreMessages;
import org.mule.config.i18n.MessageFactory;
import org.mule.model.resolvers.LegacyEntryPointResolverSet;
import org.mule.registry.JSR250ValidatorProcessor;
import org.mule.util.annotation.AnnotationMetaData;
import org.mule.util.annotation.AnnotationUtils;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * <code>DefaultComponentLifecycleAdapter</code> is a default implementation of
 * {@link LifecycleAdapter} for use with {@link JavaComponent} that expects component
 * instances to implement Mule lifecycle interfaces in order to receive lifecycle. Lifecycle interfaces supported are -
 * <ul>
 * <li>{@link org.mule.api.lifecycle.Initialisable}</li>
 * <li>{@link org.mule.api.lifecycle.Startable}</li>
 * <li>{@link org.mule.api.lifecycle.Stoppable}</li>
 * <li>{@link org.mule.api.lifecycle.Disposable}</li>
 * </ul>
 *  This implementation also supports JSR-250 lifecycle annotations
 *  {@link javax.annotation.PostConstruct} (for initialisation) and/or {@link javax.annotation.PreDestroy}
 * (for disposal of the object). Only one of each annotation can be used per component object.
 *
 * @see org.mule.registry.JSR250ValidatorProcessor for details about the rules for using JSR-250 lifecycle annotations
 */
public class DefaultComponentLifecycleAdapter implements LifecycleAdapter {
    /**
     * logger used by this class
     */
    protected static final Log logger = LogFactory.getLog(DefaultComponentLifecycleAdapter.class);

    protected Object componentObject;

    protected JavaComponent component;
    protected EntryPointResolverSet entryPointResolver;
    protected FlowConstruct flowConstruct;

    protected boolean isInitialisable = false;
    protected boolean isStartable = false;
    protected boolean isStoppable = false;
    protected boolean isDisposable = false;

    protected Method initMethod;
    protected Method disposeMethod;

    private boolean started = false;
    private boolean disposed = false;

    protected MuleContext muleContext;

    public DefaultComponentLifecycleAdapter(Object componentObject, JavaComponent component,
            FlowConstruct flowConstruct, MuleContext muleContext) throws MuleException {
        if (muleContext == null) {
            throw new IllegalStateException("No muleContext provided");
        }
        if (componentObject == null) {
            throw new IllegalArgumentException("POJO Service cannot be null");
        }

        if (entryPointResolver == null) {
            entryPointResolver = new LegacyEntryPointResolverSet();
        }
        this.componentObject = componentObject;
        this.component = component;
        this.flowConstruct = flowConstruct;

        // save a ref for later disposal call
        this.muleContext = muleContext;
        setLifecycleFlags();
        BindingUtils.configureBinding(component, componentObject);
    }

    public DefaultComponentLifecycleAdapter(Object componentObject, JavaComponent component,
            FlowConstruct flowConstruct, EntryPointResolverSet entryPointResolver, MuleContext muleContext)
            throws MuleException {

        this(componentObject, component, flowConstruct, muleContext);
        this.entryPointResolver = entryPointResolver;
    }

    protected void setLifecycleFlags() {
        Object object = componentObject;
        initMethod = findInitMethod(object);
        disposeMethod = findDisposeMethod(object);
        isInitialisable = initMethod != null;
        isDisposable = disposeMethod != null;
        isStartable = Startable.class.isInstance(object);
        isStoppable = Stoppable.class.isInstance(object);
    }

    protected Method findInitMethod(Object object) {
        if (object instanceof Initialisable) {
            try {
                return object.getClass().getMethod(Initialisable.PHASE_NAME);
            } catch (NoSuchMethodException e) {
                //ignore
            }
        }

        List<AnnotationMetaData> metaData = AnnotationUtils.getMethodAnnotations(object.getClass(),
                PostConstruct.class);
        if (metaData.size() == 0) {
            return null;
        } else if (metaData.size() > 1) {
            throw new IllegalArgumentException(
                    CoreMessages.objectHasMoreThanOnePostConstructAnnotation(object.getClass()).getMessage());
        } else {
            Method m = (Method) metaData.get(0).getMember();
            new JSR250ValidatorProcessor().validateLifecycleMethod(m);
            return m;
        }
    }

    protected Method findDisposeMethod(Object object) {
        if (object instanceof Disposable) {
            try {
                return object.getClass().getMethod(Disposable.PHASE_NAME);
            } catch (NoSuchMethodException e) {
                //ignore
            }
        }

        List<AnnotationMetaData> metaData = AnnotationUtils.getMethodAnnotations(object.getClass(),
                PreDestroy.class);
        if (metaData.size() == 0) {
            return null;
        } else if (metaData.size() > 1) {
            throw new IllegalArgumentException(
                    CoreMessages.objectHasMoreThanOnePreDestroyAnnotation(object.getClass()).getMessage());
        } else {
            Method m = (Method) metaData.get(0).getMember();
            new JSR250ValidatorProcessor().validateLifecycleMethod(m);
            return m;
        }
    }

    /**
     * Propagates initialise() life-cycle to component object implementations if they
     * implement the mule {@link Initialisable} interface.
     * <p/>
     * <b>NOTE:</b> It is up to component implementations to ensure their implementation of
     * <code>initialise()</code> is thread-safe.
     */
    public void initialise() throws InitialisationException {
        if (isInitialisable) {
            try {
                initMethod.invoke(componentObject);
            } catch (IllegalAccessException e) {
                throw new InitialisationException(e, this);
            } catch (InvocationTargetException e) {
                throw new InitialisationException(e.getTargetException(), this);
            }
        }
    }

    /**
     * Propagates start() life-cycle to component object implementations if they
     * implement the mule {@link Startable} interface. NOT: It is up to component
     * implementations to ensure their implementation of start() is thread-safe.
     */
    public void start() throws MuleException {
        if (isStartable) {
            try {
                ((Startable) componentObject).start();
                started = true;
            } catch (Exception e) {
                throw new DefaultMuleException(CoreMessages.failedToStart("Service: " + flowConstruct.getName()),
                        e);
            }
        } else {
            started = true;
        }
    }

    /**
     * Propagates stop() life-cycle to component object implementations if they
     * implement the mule {@link Stoppable} interface. NOT: It is up to component
     * implementations to ensure their implementation of stop() is thread-safe.
     */
    public void stop() throws MuleException {
        if (isStoppable) {
            try {
                ((Stoppable) componentObject).stop();
                started = false;
            } catch (Exception e) {
                throw new DefaultMuleException(CoreMessages.failedToStop("Service: " + flowConstruct.getName()), e);
            }
        } else {
            started = false;
        }
    }

    /**
     * Propagates dispose() life-cycle to component object implementations if they
     * implement the mule {@link Disposable} interface. NOT: It is up to component
     * implementations to ensure their implementation of dispose() is thread-safe.
     */
    public void dispose() {
        try {
            if (isDisposable) {
                // make sure we haven't lost the reference to the object
                Object o = componentObject;
                if (o != null) {
                    try {
                        disposeMethod.invoke(o);
                    } catch (InvocationTargetException e) {
                        //unwrap
                        throw e.getTargetException();
                    }
                }
            }
            componentObject = null;

        } catch (Throwable e) {
            logger.error("failed to dispose: " + flowConstruct.getName(), e);
        }
        disposed = true;
    }

    /**
     * @return true if the service has been started
     */
    public boolean isStarted() {
        return started;
    }

    /**
     * @return whether the service managed by this lifecycle has been disposed
     */
    public boolean isDisposed() {
        return disposed;
    }

    public Object invoke(MuleEvent event) throws MuleException {
        // Invoke method
        MuleEventContext eventContext = new DefaultMuleEventContext(event);
        Object result;
        try {
            if (componentObject == null) {
                throw new ComponentException(MessageFactory.createStaticMessage("componentObject is null"),
                        RequestContext.getEvent(), component);
            }
            // Use the overriding entrypoint resolver if one is set
            if (component.getEntryPointResolverSet() != null) {
                result = component.getEntryPointResolverSet().invoke(componentObject, eventContext);
            } else {
                result = entryPointResolver.invoke(componentObject, eventContext);
            }
        } catch (Exception e) {
            throw new ComponentException(RequestContext.getEvent(), component, e);
        }

        return result;
    }
}