001: /*
002: * $Id: DefaultLifecycleAdapter.java 11379 2008-03-17 02:46:56Z dfeist $
003: * --------------------------------------------------------------------------------------
004: * Copyright (c) MuleSource, Inc. All rights reserved. http://www.mulesource.com
005: *
006: * The software in this package is published under the terms of the CPAL v1.0
007: * license, a copy of which has been included with this distribution in the
008: * LICENSE.txt file.
009: */
010:
011: package org.mule.component;
012:
013: import org.mule.RequestContext;
014: import org.mule.VoidResult;
015: import org.mule.api.DefaultMuleException;
016: import org.mule.api.MuleEvent;
017: import org.mule.api.MuleException;
018: import org.mule.api.MuleMessage;
019: import org.mule.api.component.JavaComponent;
020: import org.mule.api.component.LifecycleAdapter;
021: import org.mule.api.interceptor.Invocation;
022: import org.mule.api.lifecycle.Disposable;
023: import org.mule.api.lifecycle.Initialisable;
024: import org.mule.api.lifecycle.InitialisationException;
025: import org.mule.api.lifecycle.LifecycleTransitionResult;
026: import org.mule.api.lifecycle.Startable;
027: import org.mule.api.lifecycle.Stoppable;
028: import org.mule.api.model.EntryPointResolverSet;
029: import org.mule.api.routing.NestedRouter;
030: import org.mule.api.service.ServiceAware;
031: import org.mule.api.service.ServiceException;
032: import org.mule.config.i18n.CoreMessages;
033: import org.mule.model.resolvers.LegacyEntryPointResolverSet;
034: import org.mule.model.resolvers.NoSatisfiableMethodsException;
035: import org.mule.model.resolvers.TooManySatisfiableMethodsException;
036: import org.mule.routing.nested.NestedInvocationHandler;
037: import org.mule.transformer.TransformerTemplate;
038: import org.mule.util.ClassUtils;
039:
040: import java.lang.reflect.Method;
041: import java.lang.reflect.Proxy;
042: import java.util.Collections;
043: import java.util.HashMap;
044: import java.util.Iterator;
045: import java.util.List;
046: import java.util.Map;
047:
048: import org.apache.commons.logging.Log;
049: import org.apache.commons.logging.LogFactory;
050:
051: /**
052: * <code>DefaultLifecycleAdapter</code> provides lifecycle methods for all Mule
053: * managed components. It's possible to plugin custom lifecycle adapters, this can
054: * provide additional lifecycle methods triggered by an external source.
055: */
056: public class DefaultLifecycleAdapter implements LifecycleAdapter {
057: /** logger used by this class */
058: protected static final Log logger = LogFactory
059: .getLog(DefaultLifecycleAdapter.class);
060:
061: protected Object componentObject;
062: protected JavaComponent component;
063: private boolean isStoppable = false;
064: private boolean isStartable = false;
065: private boolean isDisposable = false;
066:
067: private boolean started = false;
068: private boolean disposed = false;
069:
070: private EntryPointResolverSet entryPointResolver;
071:
072: public DefaultLifecycleAdapter(Object componentObject,
073: JavaComponent component) throws MuleException {
074: this (componentObject, component,
075: new LegacyEntryPointResolverSet());
076: }
077:
078: public DefaultLifecycleAdapter(Object componentObject,
079: JavaComponent component,
080: EntryPointResolverSet entryPointResolver)
081: throws MuleException {
082:
083: if (componentObject == null) {
084: throw new IllegalArgumentException(
085: "POJO Service cannot be null");
086: }
087: if (entryPointResolver == null) {
088: entryPointResolver = new LegacyEntryPointResolverSet();
089: }
090: this .componentObject = componentObject;
091: this .component = component;
092: this .entryPointResolver = entryPointResolver;
093:
094: isStartable = Startable.class.isInstance(componentObject);
095: isStoppable = Stoppable.class.isInstance(componentObject);
096: isDisposable = Disposable.class.isInstance(componentObject);
097:
098: if (componentObject instanceof ServiceAware) {
099: ((ServiceAware) componentObject).setService(component
100: .getService());
101: }
102: configureNestedRouter();
103: }
104:
105: /**
106: * Propagates start() life-cycle to component object implementations if they
107: * implement the mule {@link Startable} interface. NOT: It is up to component
108: * implementations to ensure their implementation of start() is thread-safe.
109: */
110: public LifecycleTransitionResult start() throws MuleException {
111: if (isStartable) {
112: try {
113: return LifecycleTransitionResult.startOrStopAll(
114: ((Startable) componentObject).start(),
115: new LifecycleTransitionResult.Closure() {
116: public LifecycleTransitionResult doContinue() {
117: started = true;
118: return LifecycleTransitionResult.OK;
119: }
120: });
121: } catch (Exception e) {
122: throw new DefaultMuleException(CoreMessages
123: .failedToStart("UMO Service: "
124: + component.getService().getName()), e);
125: }
126:
127: } else {
128: started = true;
129: return LifecycleTransitionResult.OK;
130: }
131: }
132:
133: /**
134: * Propagates stop() life-cycle to component object implementations if they
135: * implement the mule {@link Stoppable} interface. NOT: It is up to component
136: * implementations to ensure their implementation of stop() is thread-safe.
137: */
138: public LifecycleTransitionResult stop() throws MuleException {
139: if (isStoppable) {
140: try {
141: return LifecycleTransitionResult.startOrStopAll(
142: ((Stoppable) componentObject).stop(),
143: new LifecycleTransitionResult.Closure() {
144: public LifecycleTransitionResult doContinue() {
145: started = false;
146: return LifecycleTransitionResult.OK;
147: }
148: });
149: } catch (Exception e) {
150: throw new DefaultMuleException(CoreMessages
151: .failedToStop("UMO Service: "
152: + component.getService().getName()), e);
153: }
154: } else {
155: started = false;
156: return LifecycleTransitionResult.OK;
157: }
158: }
159:
160: /**
161: * Propagates dispose() life-cycle to component object implementations if they
162: * implement the mule {@link Disposable} interface. NOT: It is up to component
163: * implementations to ensure their implementation of dispose() is thread-safe.
164: */
165: public void dispose() {
166: if (isDisposable) {
167: try {
168: ((Disposable) componentObject).dispose();
169: } catch (Exception e) {
170: // TODO MULE-863: Handle or fail
171: logger.error("failed to dispose: "
172: + component.getService().getName(), e);
173: }
174: }
175: disposed = true;
176: }
177:
178: /** @return true if the service has been started */
179: public boolean isStarted() {
180: return started;
181: }
182:
183: /** @return whether the service managed by this lifecycle has been disposed */
184: public boolean isDisposed() {
185: return disposed;
186: }
187:
188: // Note: Invocation argument is not even used!
189: public MuleMessage intercept(Invocation invocation)
190: throws MuleException {
191: // Invoke method
192: Object result;
193: MuleEvent event = RequestContext.getEvent();
194:
195: try {
196: // Use the overriding entrypoint resolver if one is set
197: if (component.getEntryPointResolverSet() != null) {
198: result = component.getEntryPointResolverSet().invoke(
199: componentObject,
200: RequestContext.getEventContext());
201:
202: } else {
203: result = entryPointResolver.invoke(componentObject,
204: RequestContext.getEventContext());
205: }
206: } catch (Exception e) {
207: // should all Exceptions caught here be a ServiceException?!?
208: // TODO MULE-863: See above
209: throw new ServiceException(RequestContext.getEventContext()
210: .getMessage(), component.getService(), e);
211: }
212:
213: MuleMessage resultMessage = null;
214: if (result instanceof VoidResult) {
215: // This will rewire the current message
216: event.transformMessage();
217: resultMessage = event.getMessage();
218: } else if (result != null) {
219: if (result instanceof MuleMessage) {
220: resultMessage = (MuleMessage) result;
221: } else {
222: event
223: .getMessage()
224: .applyTransformers(
225: Collections
226: .singletonList(new TransformerTemplate(
227: new TransformerTemplate.OverwitePayloadCallback(
228: result))));
229: resultMessage = event.getMessage();
230: }
231: }
232: return resultMessage;
233: }
234:
235: /**
236: * Propagates initialise() life-cycle to component object implementations if they
237: * implement the mule {@link Initialisable} interface. NOT: It is up to component
238: * implementations to ensure their implementation of initialise() is thread-safe.
239: */
240: public LifecycleTransitionResult initialise()
241: throws InitialisationException {
242: if (Initialisable.class.isInstance(componentObject)) {
243: ((Initialisable) componentObject).initialise();
244: }
245: return LifecycleTransitionResult.OK;
246: }
247:
248: protected void configureNestedRouter() throws MuleException {
249: // Initialise the nested router and bind the endpoints to the methods using a
250: // Proxy
251: if (component.getNestedRouter() != null) {
252: Map bindings = new HashMap();
253: for (Iterator it = component.getNestedRouter().getRouters()
254: .iterator(); it.hasNext();) {
255: NestedRouter nestedRouter = (NestedRouter) it.next();
256: Object proxy = bindings
257: .get(nestedRouter.getInterface());
258:
259: if (proxy == null) {
260: // Create a proxy that implements this interface
261: // and just routes away using a mule client
262: // ( using the high level Mule client is probably
263: // a bit agricultural but this is just POC stuff )
264: proxy = nestedRouter.createProxy(componentObject);
265: bindings.put(nestedRouter.getInterface(), proxy);
266:
267: // Now lets set the proxy on the Service object
268: Method setterMethod;
269:
270: List methods = ClassUtils
271: .getSatisfiableMethods(componentObject
272: .getClass(),
273: new Class[] { nestedRouter
274: .getInterface() }, true,
275: false, null);
276: if (methods.size() == 1) {
277: setterMethod = (Method) methods.get(0);
278: } else if (methods.size() > 1) {
279: throw new TooManySatisfiableMethodsException(
280: componentObject.getClass(),
281: new Class[] { nestedRouter
282: .getInterface() });
283: } else {
284: throw new NoSatisfiableMethodsException(
285: componentObject.getClass(),
286: new Class[] { nestedRouter
287: .getInterface() });
288: }
289:
290: try {
291: setterMethod.invoke(componentObject,
292: new Object[] { proxy });
293: } catch (Exception e) {
294: throw new InitialisationException(CoreMessages
295: .failedToSetProxyOnService(
296: nestedRouter, componentObject
297: .getClass()), e, this );
298: }
299: } else {
300: NestedInvocationHandler handler = (NestedInvocationHandler) Proxy
301: .getInvocationHandler(proxy);
302: handler.addRouterForInterface(nestedRouter);
303: }
304: }
305: }
306: }
307:
308: }
|