View Javadoc

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