View Javadoc

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