View Javadoc

1   /*
2    * $Id: DefaultLifecycleAdapter.java 11517 2008-03-31 21:34:19Z dirk.olmes $
3    * --------------------------------------------------------------------------------------
4    * Copyright (c) MuleSource, Inc.  All rights reserved.  http://www.mulesource.com
5    *
6    * The software in this package is published under the terms of the CPAL v1.0
7    * license, a copy of which has been included with this distribution in the
8    * LICENSE.txt file.
9    */
10  
11  package org.mule.component;
12  
13  import org.mule.RequestContext;
14  import org.mule.VoidResult;
15  import org.mule.api.DefaultMuleException;
16  import org.mule.api.MuleEvent;
17  import org.mule.api.MuleException;
18  import org.mule.api.MuleMessage;
19  import org.mule.api.component.JavaComponent;
20  import org.mule.api.component.LifecycleAdapter;
21  import org.mule.api.interceptor.Invocation;
22  import org.mule.api.lifecycle.Disposable;
23  import org.mule.api.lifecycle.Initialisable;
24  import org.mule.api.lifecycle.InitialisationException;
25  import org.mule.api.lifecycle.Startable;
26  import org.mule.api.lifecycle.Stoppable;
27  import org.mule.api.model.EntryPointResolverSet;
28  import org.mule.api.routing.NestedRouter;
29  import org.mule.api.service.ServiceAware;
30  import org.mule.api.service.ServiceException;
31  import org.mule.config.i18n.CoreMessages;
32  import org.mule.model.resolvers.LegacyEntryPointResolverSet;
33  import org.mule.model.resolvers.NoSatisfiableMethodsException;
34  import org.mule.model.resolvers.TooManySatisfiableMethodsException;
35  import org.mule.routing.nested.NestedInvocationHandler;
36  import org.mule.transformer.TransformerTemplate;
37  import org.mule.util.ClassUtils;
38  
39  import java.lang.reflect.Method;
40  import java.lang.reflect.Proxy;
41  import java.util.Collections;
42  import java.util.HashMap;
43  import java.util.Iterator;
44  import java.util.List;
45  import java.util.Map;
46  
47  import org.apache.commons.logging.Log;
48  import org.apache.commons.logging.LogFactory;
49  
50  /**
51   * <code>DefaultLifecycleAdapter</code> provides lifecycle methods for all Mule
52   * managed components. It's possible to plugin custom lifecycle adapters, this can
53   * provide additional lifecycle methods triggered by an external source.
54   */
55  public class DefaultLifecycleAdapter implements LifecycleAdapter
56  {
57      /** logger used by this class */
58      protected static final Log logger = LogFactory.getLog(DefaultLifecycleAdapter.class);
59  
60      protected Object componentObject;
61      protected JavaComponent component;
62      private boolean isStoppable = false;
63      private boolean isStartable = false;
64      private boolean isDisposable = false;
65  
66      private boolean started = false;
67      private boolean disposed = false;
68  
69      private EntryPointResolverSet entryPointResolver;
70  
71      public DefaultLifecycleAdapter(Object componentObject, JavaComponent component) throws MuleException
72      {
73          this(componentObject, component, new LegacyEntryPointResolverSet());
74      }
75  
76      public DefaultLifecycleAdapter(Object componentObject,
77                                     JavaComponent component,
78                                     EntryPointResolverSet entryPointResolver) throws MuleException
79      {
80  
81          if (componentObject == null)
82          {
83              throw new IllegalArgumentException("POJO Service cannot be null");
84          }
85          if (entryPointResolver == null)
86          {
87              entryPointResolver = new LegacyEntryPointResolverSet();
88          }
89          this.componentObject = componentObject;
90          this.component = component;
91          this.entryPointResolver = entryPointResolver;
92  
93          isStartable = Startable.class.isInstance(componentObject);
94          isStoppable = Stoppable.class.isInstance(componentObject);
95          isDisposable = Disposable.class.isInstance(componentObject);
96  
97          if (componentObject instanceof ServiceAware)
98          {
99              ((ServiceAware) componentObject).setService(component.getService());
100         }
101         configureNestedRouter();
102     }
103 
104     /**
105      * Propagates start() life-cycle to component object implementations if they
106      * implement the mule {@link Startable} interface. NOT: It is up to component
107      * implementations to ensure their implementation of start() is thread-safe.
108      */
109     public void start() throws MuleException
110     {
111         if (isStartable)
112         {
113             try
114             {
115                 ((Startable) componentObject).start();                
116                 started = true;
117             }
118             catch (Exception e)
119             {
120                 throw new DefaultMuleException(CoreMessages.failedToStart("UMO Service: "
121                                                                           + component.getService().getName()), e);
122             }
123         }
124         else
125         {
126             started = true;
127         }
128     }
129 
130     /**
131      * Propagates stop() life-cycle to component object implementations if they
132      * implement the mule {@link Stoppable} interface. NOT: It is up to component
133      * implementations to ensure their implementation of stop() is thread-safe.
134      */
135     public void stop() throws MuleException
136     {
137         if (isStoppable)
138         {
139             try
140             {
141                 ((Stoppable) componentObject).stop();
142                 started = false;
143             }
144             catch (Exception e)
145             {
146                 throw new DefaultMuleException(CoreMessages.failedToStop("UMO Service: "
147                                                                          + component.getService().getName()), e);
148             }
149         }
150         else
151         {
152             started = false;
153         }
154     }
155 
156     /**
157      * Propagates dispose() life-cycle to component object implementations if they
158      * implement the mule {@link Disposable} interface. NOT: It is up to component
159      * implementations to ensure their implementation of dispose() is thread-safe.
160      */
161     public void dispose()
162     {
163         if (isDisposable)
164         {
165             try
166             {
167                 ((Disposable) componentObject).dispose();
168             }
169             catch (Exception e)
170             {
171                 // TODO MULE-863: Handle or fail
172                 logger.error("failed to dispose: " + 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     {
181         return started;
182     }
183 
184     /** @return whether the service managed by this lifecycle has been disposed */
185     public boolean isDisposed()
186     {
187         return disposed;
188     }
189 
190     // Note: Invocation argument is not even used!
191     public MuleMessage intercept(Invocation invocation) throws MuleException
192     {
193         // Invoke method
194         Object result;
195         MuleEvent event = RequestContext.getEvent();
196 
197         try
198         {
199             // Use the overriding entrypoint resolver if one is set
200             if (component.getEntryPointResolverSet() != null)
201             {
202                 result = component.getEntryPointResolverSet().invoke(componentObject, RequestContext.getEventContext());
203 
204             }
205             else
206             {
207                 result = entryPointResolver.invoke(componentObject, RequestContext.getEventContext());
208             }
209         }
210         catch (Exception e)
211         {
212             // should all Exceptions caught here be a ServiceException?!?
213             // TODO MULE-863: See above
214             throw new ServiceException(RequestContext.getEventContext().getMessage(), component.getService(), e);
215         }
216 
217         MuleMessage resultMessage = null;
218         if (result instanceof VoidResult)
219         {
220             // This will rewire the current message
221             event.transformMessage();
222             resultMessage = event.getMessage();
223         }
224         else if (result != null)
225         {
226             if (result instanceof MuleMessage)
227             {
228                 resultMessage = (MuleMessage) result;
229             }
230             else
231             {
232                 event.getMessage().applyTransformers(
233                     Collections.singletonList(new TransformerTemplate(new TransformerTemplate.OverwitePayloadCallback(
234                         result))));
235                 resultMessage = event.getMessage();
236             }
237         }
238         return resultMessage;
239     }
240 
241     /**
242      * Propagates initialise() life-cycle to component object implementations if they
243      * implement the mule {@link Initialisable} interface.
244      * <p/> 
245      * <b>NOTE:</b> It is up to component implementations to ensure their implementation of 
246      * <code>initialise()</code> is thread-safe.
247      */
248     public void initialise() throws InitialisationException
249     {
250         if (Initialisable.class.isInstance(componentObject))
251         {
252             ((Initialisable) componentObject).initialise();
253         }
254     }
255 
256     protected void configureNestedRouter() throws MuleException
257     {
258         // Initialise the nested router and bind the endpoints to the methods using a
259         // Proxy
260         if (component.getNestedRouter() != null)
261         {
262             Map bindings = new HashMap();
263             for (Iterator it = component.getNestedRouter().getRouters().iterator(); it.hasNext();)
264             {
265                 NestedRouter nestedRouter = (NestedRouter) it.next();
266                 Object proxy = bindings.get(nestedRouter.getInterface());
267 
268                 if (proxy == null)
269                 {
270                     // Create a proxy that implements this interface
271                     // and just routes away using a mule client
272                     // ( using the high level Mule client is probably
273                     // a bit agricultural but this is just POC stuff )
274                     proxy = nestedRouter.createProxy(componentObject);
275                     bindings.put(nestedRouter.getInterface(), proxy);
276 
277                     // Now lets set the proxy on the Service object
278                     Method setterMethod;
279 
280                     List methods = ClassUtils.getSatisfiableMethods(componentObject.getClass(),
281                         new Class[]{nestedRouter.getInterface()}, true, false, null);
282                     if (methods.size() == 1)
283                     {
284                         setterMethod = (Method) methods.get(0);
285                     }
286                     else if (methods.size() > 1)
287                     {
288                         throw new TooManySatisfiableMethodsException(componentObject.getClass(),
289                             new Class[]{nestedRouter.getInterface()});
290                     }
291                     else
292                     {
293                         throw new NoSatisfiableMethodsException(componentObject.getClass(),
294                             new Class[]{nestedRouter.getInterface()});
295                     }
296 
297                     try
298                     {
299                         setterMethod.invoke(componentObject, new Object[]{proxy});
300                     }
301                     catch (Exception e)
302                     {
303                         throw new InitialisationException(CoreMessages.failedToSetProxyOnService(nestedRouter,
304                             componentObject.getClass()), e, this);
305                     }
306                 }
307                 else
308                 {
309                     NestedInvocationHandler handler = (NestedInvocationHandler) Proxy.getInvocationHandler(proxy);
310                     handler.addRouterForInterface(nestedRouter);
311                 }
312             }
313         }
314     }
315 
316 }