View Javadoc
1   /*
2    * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
3    * The software in this package is published under the terms of the CPAL v1.0
4    * license, a copy of which has been included with this distribution in the
5    * LICENSE.txt file.
6    */
7   package org.mule.processor;
8   
9   import org.mule.api.MessagingException;
10  import org.mule.api.MuleEvent;
11  import org.mule.api.MuleException;
12  import org.mule.api.config.ThreadingProfile;
13  import org.mule.api.context.WorkManager;
14  import org.mule.api.context.WorkManagerSource;
15  import org.mule.api.lifecycle.Startable;
16  import org.mule.api.lifecycle.Stoppable;
17  import org.mule.api.processor.MessageProcessor;
18  import org.mule.config.i18n.CoreMessages;
19  import org.mule.interceptor.ProcessingTimeInterceptor;
20  import org.mule.work.AbstractMuleEventWork;
21  import org.mule.work.MuleWorkManager;
22  
23  /**
24   * Processes {@link MuleEvent}'s asynchronously using a {@link MuleWorkManager} to
25   * schedule asynchronous processing of the next {@link MessageProcessor}. The next
26   * {@link MessageProcessor} is therefore be executed in a different thread regardless
27   * of the exchange-pattern configured on the inbound endpoint. If a transaction is
28   * present then an exception is thrown.
29   */
30  public class AsyncInterceptingMessageProcessor extends AbstractInterceptingMessageProcessor
31      implements Startable, Stoppable
32  {
33      protected WorkManagerSource workManagerSource;
34      protected boolean doThreading = true;
35      protected WorkManager workManager;
36  
37      public AsyncInterceptingMessageProcessor(WorkManagerSource workManagerSource)
38      {
39          this.workManagerSource = workManagerSource;
40      }
41  
42      @Deprecated
43      public AsyncInterceptingMessageProcessor(WorkManagerSource workManagerSource, boolean doThreading)
44      {
45          this.workManagerSource = workManagerSource;
46          this.doThreading = doThreading;
47      }
48  
49      public AsyncInterceptingMessageProcessor(ThreadingProfile threadingProfile,
50                                               String name,
51                                               int shutdownTimeout)
52      {
53          this.doThreading = threadingProfile.isDoThreading();
54          workManager = threadingProfile.createWorkManager(name, shutdownTimeout);
55          workManagerSource = new WorkManagerSource()
56          {
57              public WorkManager getWorkManager() throws MuleException
58              {
59                  return workManager;
60              }
61          };
62      }
63  
64      public void start() throws MuleException
65      {
66          if (workManager != null)
67          {
68              workManager.start();
69          }
70      }
71  
72      public void stop() throws MuleException
73      {
74          if (workManager != null)
75          {
76              workManager.dispose();
77          }
78      }
79  
80      public MuleEvent process(MuleEvent event) throws MuleException
81      {
82          if (next == null)
83          {
84              return event;
85          }
86          else if (isProcessAsync(event))
87          {
88              processNextAsync(event);
89              return null;
90          }
91          else
92          {
93              MuleEvent response = processNext(event);
94              return response;
95          }
96      }
97  
98      protected MuleEvent processNextTimed(MuleEvent event) throws MuleException
99      {
100         if (next == null)
101         {
102             return event;
103         }
104         else
105         {
106             if (logger.isTraceEnabled())
107             {
108                 logger.trace("Invoking next MessageProcessor: '" + next.getClass().getName() + "' ");
109             }
110 
111             MuleEvent response;
112             if (event.getFlowConstruct() != null)
113             {
114                 response = new ProcessingTimeInterceptor(next, event.getFlowConstruct()).process(event);
115             }
116             else
117             {
118                 response = processNext(event);
119             }
120             return response;
121         }
122     }
123 
124     protected boolean isProcessAsync(MuleEvent event) throws MessagingException
125     {
126         // We do not support transactions and async
127         if (event.getEndpoint().getTransactionConfig().isTransacted())
128         {
129             throw new MessagingException(CoreMessages.asyncDoesNotSupportTransactions(), event);
130         }
131         return doThreading;
132     }
133 
134     protected void processNextAsync(MuleEvent event) throws MuleException
135     {
136         try
137         {
138             workManagerSource.getWorkManager().scheduleWork(new AsyncMessageProcessorWorker(event),
139                 WorkManager.INDEFINITE, null, new AsyncWorkListener(next));
140         }
141         catch (Exception e)
142         {
143             new MessagingException(CoreMessages.errorSchedulingMessageProcessorForAsyncInvocation(next),
144                 event, e);
145         }
146     }
147 
148     class AsyncMessageProcessorWorker extends AbstractMuleEventWork
149     {
150         public AsyncMessageProcessorWorker(MuleEvent event)
151         {
152             super(event);
153         }
154 
155         @Override
156         protected void doRun()
157         {
158             try
159             {
160                 processNextTimed(event);
161             }
162             catch (Exception e)
163             {
164                 event.getFlowConstruct().getExceptionListener().handleException(e, event);
165             }
166         }
167     }
168 
169 }