View Javadoc

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