View Javadoc

1   /*
2    * $Id: AbstractReceiverWorker.java 8440 2007-09-16 18:59:29Z aguenther $
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.umo.TransactionException;
13  import org.mule.umo.UMOMessage;
14  import org.mule.umo.UMOTransaction;
15  import org.mule.umo.provider.UMOMessageAdapter;
16  import org.mule.umo.endpoint.UMOImmutableEndpoint;
17  import org.mule.transaction.TransactionTemplate;
18  import org.mule.transaction.TransactionCallback;
19  import org.mule.transaction.TransactionCoordination;
20  import org.mule.impl.MuleMessage;
21  
22  import java.io.OutputStream;
23  import java.util.List;
24  import java.util.ArrayList;
25  import java.util.Iterator;
26  
27  import javax.resource.spi.work.Work;
28  
29  /**
30   * A base Worker used by Transport {@link UMOMessageReciever} 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 (Exception e)
128         {
129             handleException(e);
130         }
131         finally
132         {
133             messages.clear();
134         }
135     }
136 
137     /**
138      * This callback is called before a message is routed into Mule and can be used by the worker to set connection
139      * specific properties to message before it gets routed
140      *
141      * @param message the next message to be processed
142      * @throws Exception
143      */
144     protected void preRouteMuleMessage(MuleMessage message) throws Exception
145     {
146         //no op
147     }
148 
149     /**
150      * Template method used to bind the resources of this receiver to the transaction.  Only transactional
151      * transports need implment this method
152      * @param tx the current transaction or null if there is no transaction
153      * @throws TransactionException
154      */
155     protected abstract void bindTransaction(UMOTransaction tx) throws TransactionException;
156 
157     /**
158      * A conveniece method that passes the exception to the connector's ExceptionListener
159      * @param e
160      */
161     protected void handleException(Exception e)
162     {
163         endpoint.getConnector().handleException(e);
164     }
165 
166     /**
167      * When Mule has finished processing the current messages, there may be zero or more messages to process
168      * by the receiver if request/response messaging is being used. The result(s) should be passed back to the callee.
169      * @param messages a list of messages.  This argument will not be null
170      * @throws Exception
171      */
172     protected void handleResults(List messages) throws Exception
173     {
174         //no op
175     }
176 
177     /**
178      * Before a message is passed into Mule this callback is called and can be used by the worker to inspect the
179      * message before it gets sent to Mule
180      * @param message the next message to be processed
181      * @return the message to be processed. If Null is returned the message will not get processed.
182      * @throws Exception
183      */
184     protected Object preProcessMessage(Object message) throws Exception
185     {
186         //no op
187         return message;
188     }
189 
190     /**
191      * If a result is returned back this method will get called before the message is added to te list of
192      * results (these are later passed to {@link #handleResults(java.util.List)})
193      * @param message the result message, this will never be null
194      * @return the message to add to the list of results. If null is returned nothing is added to the
195      * list of results
196      * @throws Exception
197      */
198     protected UMOMessage postProcessMessage(UMOMessage message) throws Exception
199     {
200         //no op
201         return message;
202     }
203 
204 
205     /**
206      * This method is called once this worker is no longer required.  Any resources *only* associated with
207      * this worker should be cleaned up here.
208      */
209     public void release()
210     {
211         // no op
212     }
213 }