View Javadoc

1   /*
2    * $Id: AbstractReceiverWorker.java 20498 2010-12-08 00:27:08Z tcarlson $
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  package org.mule.transport;
11  
12  import org.mule.api.MessagingException;
13  import org.mule.api.MuleContext;
14  import org.mule.api.MuleEvent;
15  import org.mule.api.MuleMessage;
16  import org.mule.api.MuleSession;
17  import org.mule.api.endpoint.InboundEndpoint;
18  import org.mule.api.transaction.Transaction;
19  import org.mule.api.transaction.TransactionCallback;
20  import org.mule.api.transaction.TransactionException;
21  import org.mule.api.transport.SessionHandler;
22  import org.mule.session.LegacySessionHandler;
23  import org.mule.session.MuleSessionHandler;
24  import org.mule.transaction.TransactionCoordination;
25  import org.mule.transaction.TransactionTemplate;
26  
27  import java.io.OutputStream;
28  import java.util.ArrayList;
29  import java.util.List;
30  
31  import javax.resource.spi.work.Work;
32  
33  import org.apache.commons.lang.SerializationException;
34  
35  /**
36   * A base Worker used by Transport {@link org.mule.api.transport.MessageReceiver} implementations.
37   */
38  public abstract class AbstractReceiverWorker implements Work
39  {
40      protected List<Object> messages;
41      protected InboundEndpoint endpoint;
42      protected AbstractMessageReceiver receiver;
43      protected OutputStream out;
44  
45      public AbstractReceiverWorker(List<Object> messages, AbstractMessageReceiver receiver)
46      {
47          this(messages, receiver, null);
48      }
49  
50      public AbstractReceiverWorker(List<Object> messages, AbstractMessageReceiver receiver, OutputStream out)
51      {
52          this.messages = messages;
53          this.receiver = receiver;
54          this.endpoint = receiver.getEndpoint();
55          this.out = out;
56      }
57  
58      /**
59       * This will run the receiver logic and call {@link #release()} once {@link #doRun()} completes.
60      *
61      */
62      public final void run()
63      {
64          doRun();
65          release();
66      }
67  
68      /**
69       * The actual logic used to receive messages from the underlying transport.  The default implementation
70       * will execute the processing of messages within a TransactionTemplate.  This template will manage the
71       * transaction lifecycle for the list of messages associated with this receiver worker.
72       */
73      protected void doRun()
74      {
75          //  MuleContext is used down the line for
76          // getTransactionManager() (XaTransactionFactory) and getQueueManager() (VMTransaction)
77          final MuleContext muleContext = receiver.getConnector().getMuleContext();
78          TransactionTemplate tt = new TransactionTemplate(endpoint.getTransactionConfig(), muleContext);
79  
80          // Receive messages and process them in a single transaction
81          // Do not enable threading here, but serveral workers
82          // may have been started
83          TransactionCallback<?> cb = new TransactionCallback()
84          {
85              public Object doInTransaction() throws Exception
86              {
87                  Transaction tx = TransactionCoordination.getInstance().getTransaction();
88                  if (tx != null)
89                  {
90                      bindTransaction(tx);
91                  }
92                  List<Object> results = new ArrayList<Object>(messages.size());
93  
94                  for (Object payload : messages)
95                  {
96                      payload = preProcessMessage(payload);
97                      if (payload != null)
98                      {
99                          MuleMessage muleMessage = receiver.createMuleMessage(payload, endpoint.getEncoding());
100                         preRouteMuleMessage(muleMessage);
101 
102                         // TODO Move getSessionHandler() to the Connector interface
103                         SessionHandler handler;
104                         if (endpoint.getConnector() instanceof AbstractConnector)
105                         {
106                             handler = ((AbstractConnector) endpoint.getConnector()).getSessionHandler();
107                         }
108                         else
109                         {
110                             handler = new MuleSessionHandler();
111                         }
112                         MuleSession session;
113                         try
114                         {
115                             session = handler.retrieveSessionInfoFromMessage(muleMessage);
116                         }
117                         catch (SerializationException e)
118                         {
119                             // EE-1820 Support message headers generated by previous Mule versions
120                             session = new LegacySessionHandler().retrieveSessionInfoFromMessage(muleMessage);
121                         }
122                         
123                         MuleEvent resultEvent;
124                         if (session != null)
125                         {
126                             resultEvent = receiver.routeMessage(muleMessage, session, tx, out);
127                         }
128                         else
129                         {
130                             resultEvent = receiver.routeMessage(muleMessage, tx, out);
131                         }
132                         MuleMessage result = resultEvent == null ?  null : resultEvent.getMessage();
133                         if (result != null)
134                         {
135                             payload = postProcessMessage(result);
136                             if (payload != null)
137                             {
138                                 results.add(payload);
139                             }
140                         }
141                     }
142                 }
143                 return results;
144             }
145         };
146 
147         try
148         {
149             List results = (List) tt.execute(cb);
150             handleResults(results);
151         }
152         catch (MessagingException e)
153         {
154             receiver.getFlowConstruct().getExceptionListener().handleException(e, e.getEvent());
155         }
156         catch (Exception e)
157         {
158             muleContext.getExceptionListener().handleException(e);
159         }
160         finally
161         {
162             messages.clear();
163         }
164     }
165 
166     /**
167      * This callback is called before a message is routed into Mule and can be used by the worker to set connection
168      * specific properties to message before it gets routed
169      *
170      * @param message the next message to be processed
171      * @throws Exception
172      */
173     protected void preRouteMuleMessage(MuleMessage message) throws Exception
174     {
175         //no op
176     }
177 
178     /**
179      * Template method used to bind the resources of this receiver to the transaction.  Only transactional
180      * transports need implment this method
181      * @param tx the current transaction or null if there is no transaction
182      * @throws TransactionException
183      */
184     protected abstract void bindTransaction(Transaction tx) throws TransactionException;
185 
186     /**
187      * When Mule has finished processing the current messages, there may be zero or more messages to process
188      * by the receiver if request/response messaging is being used. The result(s) should be passed back to the callee.
189      * @param messages a list of messages.  This argument will not be null
190      * @throws Exception
191      */
192     protected void handleResults(List messages) throws Exception
193     {
194         //no op
195     }
196 
197     /**
198      * Before a message is passed into Mule this callback is called and can be used by the worker to inspect the
199      * message before it gets sent to Mule
200      * @param message the next message to be processed
201      * @return the message to be processed. If Null is returned the message will not get processed.
202      * @throws Exception
203      */
204     protected Object preProcessMessage(Object message) throws Exception
205     {
206         //no op
207         return message;
208     }
209 
210     /**
211      * If a result is returned back this method will get called before the message is added to te list of
212      * results (these are later passed to {@link #handleResults(java.util.List)})
213      * @param message the result message, this will never be null
214      * @return the message to add to the list of results. If null is returned nothing is added to the
215      * list of results
216      * @throws Exception
217      */
218     protected MuleMessage postProcessMessage(MuleMessage message) throws Exception
219     {
220         //no op
221         return message;
222     }
223 
224 
225     /**
226      * This method is called once this worker is no longer required.  Any resources *only* associated with
227      * this worker should be cleaned up here.
228      */
229     public void release()
230     {
231         // no op
232     }
233 }