org.mule.component.DefaultComponentLifecycleAdapter Maven / Gradle / Ivy
/*
* $Id: DefaultComponentLifecycleAdapter.java 20486 2010-12-07 11:12:25Z dirk.olmes $
* --------------------------------------------------------------------------------------
* 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.InterfaceBinding;
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.model.resolvers.NoSatisfiableMethodsException;
import org.mule.model.resolvers.TooManySatisfiableMethodsException;
import org.mule.registry.JSR250ValidatorProcessor;
import org.mule.util.ClassUtils;
import org.mule.util.annotation.AnnotationMetaData;
import org.mule.util.annotation.AnnotationUtils;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* DefaultComponentLifecycleAdapter
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 -
*
* - {@link org.mule.api.lifecycle.Initialisable}
* - {@link org.mule.api.lifecycle.Startable}
* - {@link org.mule.api.lifecycle.Stoppable}
* - {@link org.mule.api.lifecycle.Disposable}
*
* 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();
configureBinding();
}
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 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 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.
*
* NOTE: It is up to component implementations to ensure their implementation of
* initialise()
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;
}
protected void configureBinding() throws MuleException
{
// Initialise the nested router and bind the endpoints to the methods using a
// Proxy
if (component.getInterfaceBindings() != null)
{
Map, Object> bindings = new HashMap, Object>();
for (InterfaceBinding interfaceBinding : component.getInterfaceBindings())
{
Object proxy = bindings.get(interfaceBinding.getInterface());
if (proxy == null)
{
// Create a proxy that implements this interface
// and just routes away using a mule client
// ( using the high level Mule client is probably
// a bit agricultural but this is just POC stuff )
proxy = interfaceBinding.createProxy(componentObject);
bindings.put(interfaceBinding.getInterface(), proxy);
// Now lets set the proxy on the Service object
Method setterMethod;
List methods = ClassUtils.getSatisfiableMethods(componentObject.getClass(),
new Class[]{interfaceBinding.getInterface()}, true, false, null);
if (methods.size() == 1)
{
setterMethod = (Method) methods.get(0);
}
else if (methods.size() > 1)
{
throw new TooManySatisfiableMethodsException(componentObject.getClass(),
new Class[]{interfaceBinding.getInterface()});
}
else
{
throw new NoSatisfiableMethodsException(componentObject.getClass(),
new Class[]{interfaceBinding.getInterface()});
}
try
{
setterMethod.invoke(componentObject, proxy);
}
catch (Exception e)
{
throw new InitialisationException(CoreMessages.failedToSetProxyOnService(interfaceBinding,
componentObject.getClass()), e, this);
}
}
else
{
BindingInvocationHandler handler = (BindingInvocationHandler) Proxy.getInvocationHandler(proxy);
handler.addRouterForInterface(interfaceBinding);
}
}
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy