View Javadoc

1   /*
2    * $Id: DefaultMuleProxy.java 11728 2008-05-13 07:31:11Z 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.model;
12  
13  import org.mule.config.MuleProperties;
14  import org.mule.config.i18n.CoreMessages;
15  import org.mule.impl.ImmutableMuleDescriptor;
16  import org.mule.impl.InterceptorsInvoker;
17  import org.mule.impl.MuleDescriptor;
18  import org.mule.impl.MuleEvent;
19  import org.mule.impl.MuleMessage;
20  import org.mule.impl.OptimizedRequestContext;
21  import org.mule.impl.RequestContext;
22  import org.mule.impl.endpoint.MuleEndpoint;
23  import org.mule.impl.endpoint.MuleEndpointURI;
24  import org.mule.impl.message.ExceptionPayload;
25  import org.mule.management.stats.ComponentStatistics;
26  import org.mule.providers.AbstractConnector;
27  import org.mule.providers.NullPayload;
28  import org.mule.providers.ReplyToHandler;
29  import org.mule.umo.MessagingException;
30  import org.mule.umo.UMOEvent;
31  import org.mule.umo.UMOException;
32  import org.mule.umo.UMOExceptionPayload;
33  import org.mule.umo.UMOImmutableDescriptor;
34  import org.mule.umo.UMOInterceptor;
35  import org.mule.umo.UMOMessage;
36  import org.mule.umo.endpoint.UMOEndpoint;
37  import org.mule.umo.endpoint.UMOEndpointURI;
38  import org.mule.umo.endpoint.UMOImmutableEndpoint;
39  import org.mule.umo.lifecycle.Disposable;
40  import org.mule.umo.lifecycle.Initialisable;
41  import org.mule.umo.lifecycle.UMOLifecycleAdapter;
42  import org.mule.umo.model.ModelException;
43  import org.mule.umo.model.UMOEntryPointResolver;
44  import org.mule.umo.model.UMOModel;
45  import org.mule.util.queue.QueueSession;
46  
47  import java.util.ArrayList;
48  import java.util.Iterator;
49  import java.util.List;
50  import java.util.Map;
51  
52  import org.apache.commons.logging.Log;
53  import org.apache.commons.logging.LogFactory;
54  
55  /**
56   * <code>MuleProxy</code> is a proxy to a UMO. It is a poolable object that that
57   * can be executed in it's own thread.
58   */
59  
60  public class DefaultMuleProxy implements MuleProxy
61  {
62      /**
63       * logger used by this class
64       */
65      private static Log logger = LogFactory.getLog(DefaultMuleProxy.class);
66  
67      /**
68       * Holds the current event being processed
69       */
70      private UMOEvent event;
71  
72      /**
73       * Holds the actual UMO
74       */
75      private UMOLifecycleAdapter umo;
76  
77      /**
78       * holds the UMO descriptor
79       */
80      private ImmutableMuleDescriptor descriptor;
81  
82      /**
83       * Determines if the proxy is suspended
84       */
85      private boolean suspended = true;
86  
87      private List interceptorList;
88  
89      private ComponentStatistics stat = null;
90  
91      private QueueSession queueSession = null;
92  
93      /**
94       * Constructs a Proxy using the UMO's AbstractMessageDispatcher and the UMO
95       * itself
96       * 
97       * @param component the underlying object that with receive events
98       * @param descriptor the UMOComponent descriptor associated with the component
99       */
100     public DefaultMuleProxy(Object component, MuleDescriptor descriptor, UMOModel model) throws UMOException
101     {
102         this.descriptor = new ImmutableMuleDescriptor(descriptor);
103 
104         UMOEntryPointResolver resolver = model.getEntryPointResolver();
105         umo = model.getLifecycleAdapterFactory().create(component, descriptor, resolver);
106 
107         interceptorList = new ArrayList(descriptor.getInterceptors().size() + 1);
108         interceptorList.addAll(descriptor.getInterceptors());
109         interceptorList.add(umo);
110 
111         for (Iterator iter = interceptorList.iterator(); iter.hasNext();)
112         {
113             UMOInterceptor interceptor = (UMOInterceptor) iter.next();
114             if (interceptor instanceof Initialisable)
115             {
116                 try
117                 {
118                     ((Initialisable) interceptor).initialise();
119                 }
120                 catch (Exception e)
121                 {
122                     throw new ModelException(
123                         CoreMessages.objectFailedToInitialise(
124                             "Component '" + descriptor.getName() + "'"), e);
125                 }
126             }
127         }
128     }
129 
130     public void start() throws UMOException
131     {
132         checkDisposed();
133         if (!umo.isStarted())
134         {
135             try
136             {
137                 umo.start();
138             }
139             catch (Exception e)
140             {
141                 throw new ModelException(
142                     CoreMessages.failedToStart("Component '" + descriptor.getName() + "'"), e);
143             }
144         }
145 
146     }
147 
148     public boolean isStarted()
149     {
150         return umo.isStarted();
151     }
152 
153     public void stop() throws UMOException
154     {
155         checkDisposed();
156         if (umo.isStarted())
157         {
158             try
159             {
160                 umo.stop();
161             }
162             catch (Exception e)
163             {
164                 throw new ModelException(
165                     CoreMessages.failedToStop("Component '" + descriptor.getName() + "'"), e);
166             }
167         }
168     }
169 
170     public void dispose()
171     {
172         checkDisposed();
173         for (Iterator iter = interceptorList.iterator(); iter.hasNext();)
174         {
175             UMOInterceptor interceptor = (UMOInterceptor) iter.next();
176             if (interceptor instanceof Disposable)
177             {
178                 try
179                 {
180                     ((Disposable) interceptor).dispose();
181                 }
182                 catch (Exception e)
183                 {
184                     // We're being disposed. If there was an error while disposing the interceptor
185                     // there's not much we can do here.
186                     logger.error(
187                         CoreMessages.failedToDispose("Component '" + descriptor.getName() + "'"), e);
188                 }
189             }
190         }
191     }
192 
193     private void checkDisposed()
194     {
195         if (umo.isDisposed())
196         {
197             throw new IllegalStateException("Component has already been disposed of");
198         }
199     }
200 
201     /**
202      * Sets the current event being processed
203      * 
204      * @param event the event being processed
205      */
206     public void onEvent(QueueSession session, UMOEvent event)
207     {
208         this.queueSession = session;
209         this.event = event;
210     }
211 
212     public ComponentStatistics getStatistics()
213     {
214         return stat;
215     }
216 
217     public void setStatistics(ComponentStatistics stat)
218     {
219         this.stat = stat;
220     }
221 
222     /**
223      * Makes a synchronous call on the UMO
224      * 
225      * @param event the event to pass to the UMO
226      * @return the return event from the UMO
227      * @throws UMOException if the call fails
228      */
229     public Object onCall(UMOEvent event) throws UMOException
230     {
231         if (logger.isTraceEnabled())
232         {
233             logger.trace("MuleProxy: sync call for Mule UMO " + descriptor.getName());
234         }
235 
236         UMOMessage returnMessage = null;
237         try
238         {
239             if (event.getEndpoint().canReceive())
240             {
241                 event = OptimizedRequestContext.unsafeSetEvent(event);
242                 Object replyTo = event.getMessage().getReplyTo();
243                 ReplyToHandler replyToHandler = getReplyToHandler(event.getMessage(), event.getEndpoint());
244                 InterceptorsInvoker invoker = new InterceptorsInvoker(interceptorList, descriptor,
245                     event.getMessage());
246 
247                 // stats
248                 long startTime = 0;
249                 if (stat.isEnabled())
250                 {
251                     startTime = System.currentTimeMillis();
252                 }
253                 returnMessage = invoker.execute();
254 
255                 // stats
256                 if (stat.isEnabled())
257                 {
258                     stat.addExecutionTime(System.currentTimeMillis() - startTime);
259                 }
260                 // this is the request event
261                 event = RequestContext.getEvent();
262                 if (event.isStopFurtherProcessing())
263                 {
264                     logger.debug("Event stop further processing has been set, no outbound routing will be performed.");
265                 }
266                 if (returnMessage != null && !event.isStopFurtherProcessing())
267                 {
268                     if (descriptor.getOutboundRouter().hasEndpoints())
269                     {
270                         UMOMessage outboundReturnMessage = descriptor.getOutboundRouter().route(
271                             returnMessage, event.getSession(), event.isSynchronous());
272                         if (outboundReturnMessage != null)
273                         {
274                             returnMessage = outboundReturnMessage;
275                         }
276                     }
277                     else
278                     {
279                         logger.debug("Outbound router on component '" + descriptor.getName()
280                                      + "' doesn't have any endpoints configured.");
281                     }
282                 }
283 
284                 // Process Response Router
285                 if (returnMessage != null && descriptor.getResponseRouter() != null)
286                 {
287                     logger.debug("Waiting for response router message");
288                     returnMessage = descriptor.getResponseRouter().getResponse(returnMessage);
289                 }
290 
291                 // process replyTo if there is one
292                 if (returnMessage != null && replyToHandler != null)
293                 {
294                     String requestor = (String) returnMessage.getProperty(MuleProperties.MULE_REPLY_TO_REQUESTOR_PROPERTY);
295                     if ((requestor != null && !requestor.equals(descriptor.getName())) || requestor == null)
296                     {
297                         replyToHandler.processReplyTo(event, returnMessage, replyTo);
298                     }
299                 }
300 
301             }
302             else
303             {
304                 returnMessage = event.getSession().sendEvent(event);
305                 processReplyTo(returnMessage);
306             }
307 
308             // stats
309             if (stat.isEnabled())
310             {
311                 stat.incSentEventSync();
312             }
313         }
314         catch (Exception e)
315         {
316             event.getSession().setValid(false);
317             if (e instanceof MessagingException)
318             {
319                 handleException(e);
320             }
321             else
322             {
323                 handleException(
324                     new MessagingException(
325                         CoreMessages.eventProcessingFailedFor(descriptor.getName()), 
326                         event.getMessage(), e));
327             }
328 
329             if (returnMessage == null)
330             {
331                 returnMessage = new MuleMessage(NullPayload.getInstance(), (Map) null);
332             }
333             UMOExceptionPayload exceptionPayload = RequestContext.getExceptionPayload();
334             if (exceptionPayload == null)
335             {
336                 exceptionPayload = new ExceptionPayload(e);
337             }
338             returnMessage.setExceptionPayload(exceptionPayload);
339         }
340         return returnMessage;
341     }
342 
343     /**
344      * When an exception occurs this method can be called to invoke the configured
345      * UMOExceptionStrategy on the UMO
346      * 
347      * @param exception If the UMOExceptionStrategy implementation fails
348      */
349     public void handleException(Exception exception)
350     {
351         descriptor.getExceptionListener().exceptionThrown(exception);
352     }
353 
354     public String toString()
355     {
356         return "proxy for: " + descriptor.toString();
357     }
358 
359     /**
360      * Determines if the proxy is suspended
361      * 
362      * @return true if the proxy (and the UMO) are suspended
363      */
364     public boolean isSuspended()
365     {
366         return suspended;
367     }
368 
369     /**
370      * Controls the suspension of the UMO event processing
371      */
372     public void suspend()
373     {
374         suspended = true;
375     }
376 
377     /**
378      * Triggers the UMO to resume processing of events if it is suspended
379      */
380     public void resume()
381     {
382         suspended = false;
383     }
384 
385     protected ReplyToHandler getReplyToHandler(UMOMessage message, UMOImmutableEndpoint endpoint)
386     {
387         Object replyTo = message.getReplyTo();
388         ReplyToHandler replyToHandler = null;
389         if (replyTo != null)
390         {
391             replyToHandler = ((AbstractConnector) endpoint.getConnector()).getReplyToHandler();
392             // Use the response transformer for the event if one is set
393             if (endpoint.getResponseTransformer() != null)
394             {
395                 replyToHandler.setTransformer(endpoint.getResponseTransformer());
396             }
397         }
398         return replyToHandler;
399     }
400 
401     private void processReplyTo(UMOMessage returnMessage) throws UMOException
402     {
403         if (returnMessage != null && returnMessage.getReplyTo() != null)
404         {
405             if (logger.isDebugEnabled())
406             {
407                 logger.debug("sending reply to: " + returnMessage.getReplyTo());
408             }
409 
410             UMOEndpointURI endpointUri = new MuleEndpointURI(returnMessage.getReplyTo().toString());
411 
412             // get the endpointUri for this uri
413             UMOEndpoint endpoint = MuleEndpoint.getOrCreateEndpointForUri(endpointUri,
414                 UMOEndpoint.ENDPOINT_TYPE_SENDER);
415 
416             // make sure remove the replyTo property as not cause a a forever
417             // replyto loop
418             returnMessage.removeProperty(MuleProperties.MULE_REPLY_TO_PROPERTY);
419 
420             // Create the replyTo event asynchronous
421             UMOEvent replyToEvent = new MuleEvent(returnMessage, endpoint, event.getSession(), false);
422 
423             // queue the event
424             onEvent(queueSession, replyToEvent);
425 
426             if (logger.isDebugEnabled())
427             {
428                 logger.debug("reply to sent: " + returnMessage.getReplyTo());
429             }
430 
431             if (stat.isEnabled())
432             {
433                 stat.incSentReplyToEvent();
434             }
435         }
436     }
437 
438     /**
439      * This is the entry point for the thread that runs an asynchronous
440      * component request. This method executes the request and
441      * <p>
442      * <b>NOTE:</b> It is the responsibility of the creator of this proxy to
443      * release it (e.g., return it to the object pool), once this method has
444      * completed.
445      */
446     public void run()
447     {
448         if (logger.isTraceEnabled())
449         {
450             logger.trace("MuleProxy: async onEvent for Mule UMO " + descriptor.getName());
451         }
452 
453         try
454         {
455             if (event.getEndpoint().canReceive())
456             {
457                 // dispatch the next receiver
458                 event = OptimizedRequestContext.criticalSetEvent(event);
459                 Object replyTo = event.getMessage().getReplyTo();
460                 ReplyToHandler replyToHandler = getReplyToHandler(event.getMessage(), event.getEndpoint());
461                 InterceptorsInvoker invoker =
462                         new InterceptorsInvoker(interceptorList, descriptor,  event.getMessage());
463 
464                 // do stats
465                 long startTime = 0;
466                 if (stat.isEnabled())
467                 {
468                     startTime = System.currentTimeMillis();
469                 }
470                 UMOMessage result = invoker.execute();
471                 if (stat.isEnabled())
472                 {
473                     stat.addExecutionTime(System.currentTimeMillis() - startTime);
474                 }
475                 // processResponse(result, replyTo, replyToHandler);
476                 event = RequestContext.getEvent();
477                 if (result != null && !event.isStopFurtherProcessing())
478                 {
479                     descriptor.getOutboundRouter().route(result, event.getSession(), event.isSynchronous());
480                 }
481 
482                 // process replyTo if there is one
483                 if (result != null && replyToHandler != null)
484                 {
485                     String requestor = (String) result.getProperty(MuleProperties.MULE_REPLY_TO_REQUESTOR_PROPERTY);
486                     if ((requestor != null && !requestor.equals(descriptor.getName())) || requestor == null)
487                     {
488                         replyToHandler.processReplyTo(event, result, replyTo);
489                     }
490                 }
491             }
492             else
493             {
494                 event.getEndpoint().dispatch(event);
495             }
496 
497             if (stat.isEnabled())
498             {
499                 stat.incSentEventASync();
500             }
501         }
502         catch (Exception e)
503         {
504             event.getSession().setValid(false);
505             if (e instanceof MessagingException)
506             {
507                 handleException(e);
508             }
509             else
510             {
511                 handleException(
512                     new MessagingException(
513                         CoreMessages.eventProcessingFailedFor(descriptor.getName()), 
514                         event.getMessage(), e));
515             }
516         }
517     }
518     
519     public void release()
520     {
521         // nothing to do
522     }
523 
524     public UMOImmutableDescriptor getDescriptor()
525     {
526         return descriptor;
527     }
528 }