View Javadoc

1   /*
2    * $Id: DefaultLifecycleAdapter.java 7976 2007-08-21 14:26:13Z 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                 // TODO MULE-863: Handle or fail
154                 logger.error("failed to dispose: " + descriptor.getName(), e);
155             }
156         }
157         disposed = true;
158     }
159 
160     /**
161      * @return true if the component has been started
162      */
163     public boolean isStarted()
164     {
165         return started;
166     }
167 
168     /**
169      * @return whether the component managed by this lifecycle has been disposed
170      */
171     public boolean isDisposed()
172     {
173         return disposed;
174     }
175 
176     public UMODescriptor getDescriptor()
177     {
178         return descriptor;
179     }
180 
181     public void handleException(Object message, Exception e)
182     {
183         descriptor.getExceptionListener().exceptionThrown(e);
184     }
185 
186     public UMOMessage intercept(Invocation invocation) throws UMOException
187     {
188         // Invoke method
189         Object result;
190         UMOEvent event = RequestContext.getEvent();   // new copy here?
191 
192         try
193         {
194             result = entryPoint.invoke(component, RequestContext.getEventContext());
195         }
196         catch (Exception e)
197         {
198             // should all Exceptions caught here be a ComponentException?!?
199             // TODO MULE-863: See above
200             throw new ComponentException(
201                 CoreMessages.failedToInvoke(component.getClass().getName()),
202                 invocation.getMessage(), event.getComponent(), e);
203         }
204 
205         UMOMessage resultMessage = null;
206         if (result instanceof VoidResult)
207         {
208             resultMessage = new MuleMessage(event.getTransformedMessage(), 
209                 RequestContext.getEventContext().getMessage());
210         }
211         else if (result != null)
212         {
213             if (result instanceof UMOMessage)
214             {
215                 resultMessage = (UMOMessage) result;
216             }
217             else
218             {
219                 resultMessage = new MuleMessage(result, event.getMessage());
220             }
221         }
222         return resultMessage;
223     }
224 
225     public void initialise() throws InitialisationException
226     {
227         if (Initialisable.class.isInstance(component))
228         {
229             ((Initialisable) component).initialise();
230         }
231     }
232 
233     protected void configureNestedRouter() throws UMOException
234     {
235         // Initialise the nested router and bind the endpoints to the methods using a Proxy
236         if (descriptor.getNestedRouter() != null)
237         {
238             Map bindings = new HashMap();
239             for (Iterator it = descriptor.getNestedRouter().getRouters().iterator(); it.hasNext();)
240             {
241                 UMONestedRouter nestedRouter = (UMONestedRouter) it.next();
242                 Object proxy = bindings.get(nestedRouter.getInterface());
243 
244                 if (proxy == null)
245                 {
246                     // Create a proxy that implements this interface
247                     // and just routes away using a mule client
248                     // ( using the high level Mule client is probably
249                     // a bit agricultural but this is just POC stuff )
250                     proxy = nestedRouter.createProxy(component);
251                     bindings.put(nestedRouter.getInterface(), proxy);
252 
253                     //Now lets set the proxy on the Service object
254                     Method setterMethod;
255 
256 
257                     List methods = 
258                         ClassUtils.getSatisfiableMethods(component.getClass(), 
259                             new Class[]{nestedRouter.getInterface()}, true, false, null);
260                     if (methods.size() == 1)
261                     {
262                         setterMethod = (Method) methods.get(0);
263                     }
264                     else if (methods.size() > 1)
265                     {
266                         throw new TooManySatisfiableMethodsException(
267                                 component.getClass(), new Class[]{nestedRouter.getInterface()});
268                     }
269                     else
270                     {
271                         throw new NoSatisfiableMethodsException(
272                                 component.getClass(), nestedRouter.getInterface());
273                     }
274 
275                     try
276                     {
277                         setterMethod.invoke(component, new Object[]{proxy});
278                     }
279                     catch (Exception e)
280                     {
281                         throw new InitialisationException(
282                             CoreMessages.failedToSetProxyOnService(nestedRouter, 
283                                 component.getClass()), e, this);
284                     }
285                 }
286                 else
287                 {
288                     NestedInvocationHandler handler = (NestedInvocationHandler) Proxy.getInvocationHandler(proxy);
289                     handler.addRouterForInterface(nestedRouter);
290                 }
291             }
292         }
293     }
294 }