View Javadoc

1   /*
2    * $Id: TransactedPollingMessageReceiver.java 12181 2008-06-26 20:05:55Z 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  
11  package org.mule.transport;
12  
13  import org.mule.api.MuleException;
14  import org.mule.api.config.ThreadingProfile;
15  import org.mule.api.endpoint.InboundEndpoint;
16  import org.mule.api.lifecycle.CreateException;
17  import org.mule.api.service.Service;
18  import org.mule.api.transaction.TransactionCallback;
19  import org.mule.api.transport.Connector;
20  import org.mule.transaction.TransactionTemplate;
21  
22  import java.util.Iterator;
23  import java.util.List;
24  
25  import javax.resource.spi.work.Work;
26  
27  import edu.emory.mathcs.backport.java.util.concurrent.CountDownLatch;
28  import edu.emory.mathcs.backport.java.util.concurrent.TimeUnit;
29  
30  /**
31   * The TransactedPollingMessageReceiver is an abstract receiver that handles polling
32   * and transaction management. Derived implementations of these class must be thread
33   * safe as several threads can be started at once for an improveded throuput.
34   */
35  public abstract class TransactedPollingMessageReceiver extends AbstractPollingMessageReceiver
36  {
37      /** determines whether messages will be received in a transaction template */
38      private boolean receiveMessagesInTransaction = true;
39  
40      /** determines whether Multiple receivers are created to improve throughput */
41      private boolean useMultipleReceivers = true;
42  
43      public TransactedPollingMessageReceiver(Connector connector,
44                                              Service service,
45                                              final InboundEndpoint endpoint) throws CreateException
46      {
47          super(connector, service, endpoint);
48          this.setReceiveMessagesInTransaction(endpoint.getTransactionConfig().isTransacted());
49      }
50  
51      /**
52       * @deprecated please use
53       *             {@link #TransactedPollingMessageReceiver(Connector,Service,InboundEndpoint,long,TimeUnit)}
54       *             instead
55       */
56      public TransactedPollingMessageReceiver(Connector connector,
57                                              Service service,
58                                              final InboundEndpoint endpoint,
59                                              long frequency) throws CreateException
60      {
61          this(connector, service, endpoint);
62          this.setFrequency(frequency);
63      }
64  
65      public boolean isReceiveMessagesInTransaction()
66      {
67          return receiveMessagesInTransaction;
68      }
69  
70      public void setReceiveMessagesInTransaction(boolean useTx)
71      {
72          receiveMessagesInTransaction = useTx;
73      }
74  
75      public boolean isUseMultipleTransactedReceivers()
76      {
77          return useMultipleReceivers;
78      }
79  
80      public void setUseMultipleTransactedReceivers(boolean useMultiple)
81      {
82          useMultipleReceivers = useMultiple;
83      }
84  
85      // @Override
86      public void doStart() throws MuleException
87      {
88          // Connector property overrides any implied value
89          this.setUseMultipleTransactedReceivers(connector.isCreateMultipleTransactedReceivers());
90  
91          ThreadingProfile tp = connector.getReceiverThreadingProfile();
92          int numReceiversToStart = 1;
93  
94          if (this.isReceiveMessagesInTransaction() && this.isUseMultipleTransactedReceivers()
95                  && tp.isDoThreading())
96          {
97              numReceiversToStart = connector.getNumberOfConcurrentTransactedReceivers();
98          }
99  
100         for (int i = 0; i < numReceiversToStart; i++)
101         {
102             super.doStart();
103         }
104     }
105 
106     public void poll() throws Exception
107     {
108         TransactionTemplate tt = new TransactionTemplate(endpoint.getTransactionConfig(),
109                 connector.getExceptionListener(), connector.getMuleContext());
110 
111         if (this.isReceiveMessagesInTransaction())
112         {
113             // Receive messages and process them in a single transaction
114             // Do not enable threading here, but several workers
115             // may have been started
116             TransactionCallback cb = new TransactionCallback()
117             {
118                 public Object doInTransaction() throws Exception
119                 {
120                     List messages = getMessages();
121                     if (messages != null && messages.size() > 0)
122                     {
123                         for (Iterator it = messages.iterator(); it.hasNext();)
124                         {
125                             TransactedPollingMessageReceiver.this.processMessage(it.next());
126                         }
127                     }
128                     return null;
129                 }
130             };
131             tt.execute(cb);
132         }
133         else
134         {
135             // Receive messages and launch a worker for each message
136             List messages = getMessages();
137             if (messages != null && messages.size() > 0)
138             {
139                 final CountDownLatch countdown = new CountDownLatch(messages.size());
140                 for (Iterator it = messages.iterator(); it.hasNext();)
141                 {
142                     try
143                     {
144                         this.getWorkManager().scheduleWork(
145                                 new MessageProcessorWorker(tt, countdown, it.next()));
146                     }
147                     catch (Exception e)
148                     {
149                         countdown.countDown();
150                         throw e;
151                     }
152                 }
153                 countdown.await();
154             }
155         }
156     }
157 
158     protected class MessageProcessorWorker implements Work, TransactionCallback
159     {
160         private final TransactionTemplate tt;
161         private final Object message;
162         private final CountDownLatch latch;
163 
164         public MessageProcessorWorker(TransactionTemplate tt, CountDownLatch latch, Object message)
165         {
166             this.tt = tt;
167             this.message = message;
168             this.latch = latch;
169         }
170 
171         public void release()
172         {
173             // nothing to do
174         }
175 
176         public void run()
177         {
178             try
179             {
180                 tt.execute(this);
181             }
182             catch (Exception e)
183             {
184                 handleException(e);
185             }
186             finally
187             {
188                 latch.countDown();
189             }
190         }
191 
192         public Object doInTransaction() throws Exception
193         {
194             TransactedPollingMessageReceiver.this.processMessage(message);
195             return null;
196         }
197 
198     }
199 
200     protected abstract List getMessages() throws Exception;
201 
202     protected abstract void processMessage(Object message) throws Exception;
203 
204 }