View Javadoc

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