View Javadoc

1   /*
2    * $Id: AsyncInterceptingMessageProcessor.java 20343 2010-11-24 21:02:10Z mike.schilling $
3    * --------------------------------------------------------------------------------------
4    * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.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.processor;
12  
13  import org.mule.DefaultMuleEvent;
14  import org.mule.api.MessagingException;
15  import org.mule.api.MuleEvent;
16  import org.mule.api.MuleException;
17  import org.mule.api.MuleRuntimeException;
18  import org.mule.api.config.ThreadingProfile;
19  import org.mule.api.context.WorkManager;
20  import org.mule.api.context.WorkManagerSource;
21  import org.mule.api.endpoint.OutboundEndpoint;
22  import org.mule.api.lifecycle.Startable;
23  import org.mule.api.lifecycle.Stoppable;
24  import org.mule.api.processor.MessageProcessor;
25  import org.mule.config.i18n.CoreMessages;
26  import org.mule.interceptor.ProcessingTimeInterceptor;
27  import org.mule.work.AbstractMuleEventWork;
28  import org.mule.work.MuleWorkManager;
29  
30  import javax.resource.spi.work.WorkEvent;
31  import javax.resource.spi.work.WorkListener;
32  
33  /**
34   * Processes {@link MuleEvent}'s asynchronously using a {@link MuleWorkManager} to
35   * schedule asynchronous processing of the next {@link MessageProcessor}. The next
36   * {@link MessageProcessor} is therefore be executed in a different thread regardless
37   * of the exchange-pattern configured on the inbound endpoint. If a transaction is
38   * present then an exception is thrown.
39   */
40  public class AsyncInterceptingMessageProcessor extends AbstractInterceptingMessageProcessor
41      implements WorkListener, Startable, Stoppable
42  {
43      protected WorkManagerSource workManagerSource;
44      protected boolean doThreading = true;
45      protected WorkManager workManager;
46  
47      public AsyncInterceptingMessageProcessor(WorkManagerSource workManagerSource)
48      {
49          this.workManagerSource = workManagerSource;
50      }
51  
52      @Deprecated
53      public AsyncInterceptingMessageProcessor(WorkManagerSource workManagerSource, boolean doThreading)
54      {
55          this.workManagerSource = workManagerSource;
56          this.doThreading = doThreading;
57      }
58  
59      public AsyncInterceptingMessageProcessor(ThreadingProfile threadingProfile,
60                                               String name,
61                                               int shutdownTimeout)
62      {
63          this.doThreading = threadingProfile.isDoThreading();
64          workManager = threadingProfile.createWorkManager(name, shutdownTimeout);
65          workManagerSource = new WorkManagerSource()
66          {
67              public WorkManager getWorkManager() throws MuleException
68              {
69                  return workManager;
70              }
71          };
72      }
73  
74      public void start() throws MuleException
75      {
76          if (workManager != null)
77          {
78              workManager.start();
79          }
80      }
81  
82      public void stop() throws MuleException
83      {
84          if (workManager != null)
85          {
86              workManager.dispose();
87          }
88      }
89  
90      public MuleEvent process(MuleEvent event) throws MuleException
91      {
92          if (next == null)
93          {
94              return event;
95          }
96          else if (isProcessAsync(event))
97          {
98              processNextAsync(event);
99              return null;
100         }
101         else
102         {
103             MuleEvent response = processNext(event);
104             return response;
105         }
106     }
107 
108     protected MuleEvent processNextTimed(MuleEvent event) throws MuleException
109     {
110         if (next == null)
111         {
112             return event;
113         }
114         else
115         {
116             if (logger.isTraceEnabled())
117             {
118                 logger.trace("Invoking next MessageProcessor: '" + next.getClass().getName() + "' ");
119             }
120             // If the next message processor is an outbound router then create outbound event
121             if (next instanceof OutboundEndpoint)
122             {
123                 event = new DefaultMuleEvent(event.getMessage(), (OutboundEndpoint) next, event.getSession());
124             }
125 
126             MuleEvent response;
127             if (event.getFlowConstruct() != null)
128             {
129                 response = new ProcessingTimeInterceptor(next, event.getFlowConstruct()).process(event);
130             }
131             else
132             {
133                 response = next.process(event);
134             }
135             return response;
136         }
137     }
138 
139     protected boolean isProcessAsync(MuleEvent event) throws MessagingException
140     {
141         // We do not support transactions and async
142         if (event.getEndpoint().getTransactionConfig().isTransacted())
143         {
144             throw new MessagingException(CoreMessages.asyncDoesNotSupportTransactions(), event);
145         }
146         return doThreading;
147     }
148 
149     protected void processNextAsync(MuleEvent event) throws MuleException
150     {
151         try
152         {
153             workManagerSource.getWorkManager().scheduleWork(new AsyncMessageProcessorWorker(event),
154                 WorkManager.INDEFINITE, null, this);
155         }
156         catch (Exception e)
157         {
158             new MessagingException(CoreMessages.errorSchedulingMessageProcessorForAsyncInvocation(next),
159                 event, e);
160         }
161     }
162 
163     public void workAccepted(WorkEvent event)
164     {
165         this.handleWorkException(event, "workAccepted");
166     }
167 
168     public void workRejected(WorkEvent event)
169     {
170         this.handleWorkException(event, "workRejected");
171     }
172 
173     public void workStarted(WorkEvent event)
174     {
175         this.handleWorkException(event, "workStarted");
176     }
177 
178     public void workCompleted(WorkEvent event)
179     {
180         this.handleWorkException(event, "workCompleted");
181     }
182 
183     protected void handleWorkException(WorkEvent event, String type)
184     {
185         if (event == null)
186         {
187             return;
188         }
189 
190         Throwable e = event.getException();
191 
192         if (e == null)
193         {
194             return;
195         }
196 
197         if (e.getCause() != null)
198         {
199             e = e.getCause();
200         }
201 
202         logger.error("Work caused exception on '" + type + "'. Work being executed was: "
203                      + event.getWork().toString());
204         throw new MuleRuntimeException(CoreMessages.errorInvokingMessageProcessorAsynchronously(next), e);
205     }
206 
207     class AsyncMessageProcessorWorker extends AbstractMuleEventWork
208     {
209         public AsyncMessageProcessorWorker(MuleEvent event)
210         {
211             super(event);
212         }
213 
214         @Override
215         protected void doRun()
216         {
217             try
218             {
219                 processNextTimed(event);
220             }
221             catch (MuleException e)
222             {
223                 event.getFlowConstruct().getExceptionListener().handleException(e, event);
224             }
225         }
226     }
227 
228 }