View Javadoc

1   /*
2    * $Id: DefaultLifecycleAdapter.java 10415 2008-01-21 10:46:37Z 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.impl;
12  
13  import org.mule.MuleException;
14  import org.mule.config.i18n.CoreMessages;
15  import org.mule.impl.model.resolvers.DynamicEntryPoint;
16  import org.mule.impl.model.resolvers.DynamicEntryPointResolver;
17  import org.mule.routing.nested.NestedInvocationHandler;
18  import org.mule.umo.ComponentException;
19  import org.mule.umo.Invocation;
20  import org.mule.umo.UMODescriptor;
21  import org.mule.umo.UMOEvent;
22  import org.mule.umo.UMOException;
23  import org.mule.umo.UMOMessage;
24  import org.mule.umo.lifecycle.Disposable;
25  import org.mule.umo.lifecycle.Initialisable;
26  import org.mule.umo.lifecycle.InitialisationException;
27  import org.mule.umo.lifecycle.Startable;
28  import org.mule.umo.lifecycle.Stoppable;
29  import org.mule.umo.lifecycle.UMOLifecycleAdapter;
30  import org.mule.umo.model.UMOEntryPointResolver;
31  import org.mule.umo.routing.UMONestedRouter;
32  import org.mule.util.ClassUtils;
33  
34  import java.lang.reflect.Method;
35  import java.lang.reflect.Proxy;
36  import java.util.HashMap;
37  import java.util.Iterator;
38  import java.util.List;
39  import java.util.Map;
40  
41  import org.apache.commons.logging.Log;
42  import org.apache.commons.logging.LogFactory;
43  
44  /**
45   * <code>DefaultLifecycleAdapter</code> provides lifecycle methods for all Mule
46   * managed components. It's possible to plugin custom lifecycle adapters, this can
47   * provide additional lifecycle methods triggered by an external source.
48   */
49  public class DefaultLifecycleAdapter implements UMOLifecycleAdapter
50  {
51      /**
52       * logger used by this class
53       */
54      protected static final Log logger = LogFactory.getLog(DefaultLifecycleAdapter.class);
55  
56      private Object component;
57      private UMODescriptor descriptor;
58      private boolean isStoppable = false;
59      private boolean isStartable = false;
60      private boolean isDisposable = false;
61  
62      private boolean started = false;
63      private boolean disposed = false;
64  
65      private DynamicEntryPoint entryPoint;
66  
67      public DefaultLifecycleAdapter(Object component, UMODescriptor descriptor) throws UMOException
68      {
69          this(component, descriptor, new DynamicEntryPointResolver());
70      }
71  
72      public DefaultLifecycleAdapter(Object component,
73                                     UMODescriptor descriptor,
74                                     UMOEntryPointResolver epResolver) throws UMOException
75      {
76          initialise(component, descriptor, epResolver);
77      }
78  
79      protected void initialise(Object component, UMODescriptor descriptor, UMOEntryPointResolver epDiscovery)
80              throws UMOException
81      {
82          if (component == null)
83          {
84              throw new IllegalArgumentException("Component cannot be null");
85          }
86          if (descriptor == null)
87          {
88              throw new IllegalArgumentException("Descriptor cannot be null");
89          }
90          if (epDiscovery == null)
91          {
92              epDiscovery = new DynamicEntryPointResolver();
93          }
94          this.component = component;
95          this.entryPoint = (DynamicEntryPoint) epDiscovery.resolveEntryPoint(descriptor);
96          this.descriptor = descriptor;
97  
98          isStartable = Startable.class.isInstance(component);
99          isStoppable = Stoppable.class.isInstance(component);
100         isDisposable = Disposable.class.isInstance(component);
101 
102         if (component instanceof UMODescriptorAware)
103         {
104             ((UMODescriptorAware) component).setDescriptor(descriptor);
105         }
106         configureNestedRouter();
107     }
108 
109     public void start() throws UMOException
110     {
111         if (isStartable)
112         {
113             try
114             {
115                 ((Startable) component).start();
116             }
117             catch (Exception e)
118             {
119                 throw new MuleException(
120                     CoreMessages.failedToStart("UMO Component: " + descriptor.getName()), e);
121             }
122         }
123         started = true;
124     }
125 
126     public void stop() throws UMOException
127     {
128         if (isStoppable)
129         {
130             try
131             {
132                 ((Stoppable) component).stop();
133             }
134             catch (Exception e)
135             {
136                 throw new MuleException(
137                     CoreMessages.failedToStop("UMO Component: " + descriptor.getName()), e);
138             }
139         }
140         started = false;
141     }
142 
143     public void dispose()
144     {
145         if (isDisposable)
146         {
147             try
148             {
149                 ((Disposable) component).dispose();
150             }
151             catch (Exception e)
152             {
153                 logger.error("failed to dispose: " + descriptor.getName(), e);
154             }
155         }
156         disposed = true;
157     }
158 
159     /**
160      * @return true if the component has been started
161      */
162     public boolean isStarted()
163     {
164         return started;
165     }
166 
167     /**
168      * @return whether the component managed by this lifecycle has been disposed
169      */
170     public boolean isDisposed()
171     {
172         return disposed;
173     }
174 
175     public UMODescriptor getDescriptor()
176     {
177         return descriptor;
178     }
179 
180     public void handleException(Object message, Exception e)
181     {
182         descriptor.getExceptionListener().exceptionThrown(e);
183     }
184 
185     public UMOMessage intercept(Invocation invocation) throws UMOException
186     {
187         // Invoke method
188         Object result;
189         UMOEvent event = RequestContext.getEvent();   // new copy here?
190 
191         try
192         {
193             result = entryPoint.invoke(component, RequestContext.getEventContext());
194         }
195         catch (Exception e)
196         {
197             // should all Exceptions caught here be a ComponentException?!?
198             // TODO MULE-863: See above
199             throw new ComponentException(
200                 CoreMessages.failedToInvoke(component.getClass().getName()),
201                 invocation.getMessage(), event.getComponent(), e);
202         }
203 
204         UMOMessage resultMessage = null;
205         if (result instanceof VoidResult)
206         {
207             resultMessage = new MuleMessage(event.getTransformedMessage(), 
208                 RequestContext.getEventContext().getMessage());
209         }
210         else if (result != null)
211         {
212             if (result instanceof UMOMessage)
213             {
214                 resultMessage = (UMOMessage) result;
215             }
216             else
217             {
218                 resultMessage = new MuleMessage(result, event.getMessage());
219             }
220         }
221         return resultMessage;
222     }
223 
224     public void initialise() throws InitialisationException
225     {
226         if (Initialisable.class.isInstance(component))
227         {
228             ((Initialisable) component).initialise();
229         }
230     }
231 
232     protected void configureNestedRouter() throws UMOException
233     {
234         // Initialise the nested router and bind the endpoints to the methods using a Proxy
235         if (descriptor.getNestedRouter() != null)
236         {
237             Map bindings = new HashMap();
238             for (Iterator it = descriptor.getNestedRouter().getRouters().iterator(); it.hasNext();)
239             {
240                 UMONestedRouter nestedRouter = (UMONestedRouter) it.next();
241                 Object proxy = bindings.get(nestedRouter.getInterface());
242 
243                 if (proxy == null)
244                 {
245                     // Create a proxy that implements this interface
246                     // and just routes away using a mule client
247                     // ( using the high level Mule client is probably
248                     // a bit agricultural but this is just POC stuff )
249                     proxy = nestedRouter.createProxy(component);
250                     bindings.put(nestedRouter.getInterface(), proxy);
251 
252                     //Now lets set the proxy on the Service object
253                     Method setterMethod;
254 
255 
256                     List methods = 
257                         ClassUtils.getSatisfiableMethods(component.getClass(), 
258                             new Class[]{nestedRouter.getInterface()}, true, false, null);
259                     if (methods.size() == 1)
260                     {
261                         setterMethod = (Method) methods.get(0);
262                     }
263                     else if (methods.size() > 1)
264                     {
265                         throw new TooManySatisfiableMethodsException(
266                                 component.getClass(), new Class[]{nestedRouter.getInterface()});
267                     }
268                     else
269                     {
270                         throw new NoSatisfiableMethodsException(
271                                 component.getClass(), nestedRouter.getInterface());
272                     }
273 
274                     try
275                     {
276                         setterMethod.invoke(component, new Object[]{proxy});
277                     }
278                     catch (Exception e)
279                     {
280                         throw new InitialisationException(
281                             CoreMessages.failedToSetProxyOnService(nestedRouter, 
282                                 component.getClass()), e, this);
283                     }
284                 }
285                 else
286                 {
287                     NestedInvocationHandler handler = (NestedInvocationHandler) Proxy.getInvocationHandler(proxy);
288                     handler.addRouterForInterface(nestedRouter);
289                 }
290             }
291         }
292     }
293 }