View Javadoc

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