View Javadoc

1   /*
2    * $Id: TransactedSingleResourceJmsMessageReceiver.java 7963 2007-08-21 08:53:15Z 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.providers.jms;
12  
13  import org.mule.impl.MuleMessage;
14  import org.mule.providers.AbstractMessageReceiver;
15  import org.mule.providers.ConnectException;
16  import org.mule.providers.jms.filters.JmsSelectorFilter;
17  import org.mule.transaction.TransactionCallback;
18  import org.mule.transaction.TransactionCoordination;
19  import org.mule.transaction.TransactionTemplate;
20  import org.mule.umo.UMOComponent;
21  import org.mule.umo.UMOException;
22  import org.mule.umo.UMOTransaction;
23  import org.mule.umo.endpoint.UMOEndpoint;
24  import org.mule.umo.lifecycle.InitialisationException;
25  import org.mule.umo.lifecycle.LifecycleException;
26  import org.mule.umo.provider.UMOConnector;
27  import org.mule.umo.provider.UMOMessageAdapter;
28  import org.mule.util.ClassUtils;
29  
30  import javax.jms.Destination;
31  import javax.jms.JMSException;
32  import javax.jms.Message;
33  import javax.jms.MessageConsumer;
34  import javax.jms.MessageListener;
35  import javax.jms.Session;
36  import javax.jms.Topic;
37  import javax.resource.spi.work.Work;
38  
39  public class TransactedSingleResourceJmsMessageReceiver extends AbstractMessageReceiver
40      implements MessageListener
41  {
42      protected JmsConnector connector;
43      protected RedeliveryHandler redeliveryHandler;
44      protected MessageConsumer consumer;
45      protected Session session;
46      protected boolean startOnConnect = false;
47  
48      /** determines whether messages will be received in a transaction template */
49      protected boolean receiveMessagesInTransaction = true;
50  
51      /** determines whether Multiple receivers are created to improve throughput */
52      protected boolean useMultipleReceivers = true;
53  
54      /**
55       * @param connector
56       * @param component
57       * @param endpoint
58       * @throws InitialisationException
59       */
60      public TransactedSingleResourceJmsMessageReceiver(UMOConnector connector,
61                                                        UMOComponent component,
62                                                        UMOEndpoint endpoint) throws InitialisationException
63      {
64          super(connector, component, endpoint);
65          this.connector = (JmsConnector)connector;
66  
67          // TODO check which properties being set in the TransecteJmsMessage receiver
68          // are needed...
69  
70          try
71          {
72              redeliveryHandler = this.connector.createRedeliveryHandler();
73              redeliveryHandler.setConnector(this.connector);
74          }
75          catch (Exception e)
76          {
77              throw new InitialisationException(e, this);
78          }
79      }
80  
81      protected void doDispose()
82      {
83          // template method
84      }
85  
86      protected void doConnect() throws Exception
87      {
88          try
89          {
90              JmsSupport jmsSupport = this.connector.getJmsSupport();
91              // Create session if none exists
92              if (session == null)
93              {
94                  session = this.connector.getSession(endpoint);
95              }
96  
97              // Create destination
98              boolean topic = connector.getTopicResolver().isTopic(endpoint, true);
99  
100             Destination dest = jmsSupport.createDestination(session, endpoint.getEndpointURI().getAddress(),
101                 topic);
102 
103             // Extract jms selector
104             String selector = null;
105             if (endpoint.getFilter() != null && endpoint.getFilter() instanceof JmsSelectorFilter)
106             {
107                 selector = ((JmsSelectorFilter)endpoint.getFilter()).getExpression();
108             }
109             else if (endpoint.getProperties() != null)
110             {
111                 // still allow the selector to be set as a property on the endpoint
112                 // to be backward compatable
113                 selector = (String)endpoint.getProperties().get(JmsConstants.JMS_SELECTOR_PROPERTY);
114             }
115             String tempDurable = (String)endpoint.getProperties().get(JmsConstants.DURABLE_PROPERTY);
116             boolean durable = connector.isDurable();
117             if (tempDurable != null)
118             {
119                 durable = Boolean.valueOf(tempDurable).booleanValue();
120             }
121 
122             // Get the durable subscriber name if there is one
123             String durableName = (String)endpoint.getProperties().get(JmsConstants.DURABLE_NAME_PROPERTY);
124             if (durableName == null && durable && dest instanceof Topic)
125             {
126                 durableName = "mule." + connector.getName() + "." + endpoint.getEndpointURI().getAddress();
127                 logger.debug("Jms Connector for this receiver is durable but no durable name has been specified. Defaulting to: "
128                              + durableName);
129             }
130 
131             // Create consumer
132             consumer = jmsSupport.createConsumer(session, dest, selector, connector.isNoLocal(), durableName,
133                 topic);
134         }
135         catch (JMSException e)
136         {
137             throw new ConnectException(e, this);
138         }
139     }
140 
141     protected void doStart() throws UMOException
142     {
143         try
144         {
145             // We ned to register the listener when start is called in order to only
146             // start receiving messages after start.
147             // If the consumer is null it means that the connection strategy is being
148             // run in a separate thread and hasn't managed to connect yet.
149             if (consumer == null)
150             {
151                 startOnConnect = true;
152             }
153             else
154             {
155                 startOnConnect = false;
156                 this.consumer.setMessageListener(this);
157             }
158         }
159         catch (JMSException e)
160         {
161             throw new LifecycleException(e, this);
162         }
163     }
164 
165     protected void doStop() throws UMOException
166     {
167         try
168         {
169             if (consumer != null)
170             {
171                 consumer.setMessageListener(null);
172             }
173         }
174         catch (JMSException e)
175         {
176             throw new LifecycleException(e, this);
177         }
178     }
179 
180     public void doDisconnect() throws Exception
181     {
182         closeConsumer();
183     }
184 
185     protected void closeConsumer()
186     {
187         connector.closeQuietly(consumer);
188         consumer = null;
189         connector.closeQuietly(session);
190         session = null;
191     }
192 
193     public void onMessage(Message message)
194     {
195         try
196         {
197             getWorkManager().scheduleWork(new MessageReceiverWorker(message));
198         }
199         catch (Exception e)
200         {
201             handleException(e);
202         }
203     }
204 
205     protected class MessageReceiverWorker implements Work
206     {
207         Message message;
208 
209         public MessageReceiverWorker(Message message)
210         {
211             this.message = message;
212         }
213 
214         public void run()
215         {
216             try
217             {
218                 TransactionTemplate tt = new TransactionTemplate(endpoint.getTransactionConfig(),
219                     connector.getExceptionListener());
220 
221                 if (receiveMessagesInTransaction)
222                 {
223                     TransactionCallback cb = new MessageTransactionCallback(message)
224                     {
225 
226                         public Object doInTransaction() throws Exception
227                         {
228                             // Get Transaction & Bind Session
229                             UMOTransaction tx = TransactionCoordination.getInstance().getTransaction();
230                             if (tx != null)
231                             {
232                                 tx.bindResource(connector.getConnection(), session);
233                             }
234                             if (tx instanceof JmsClientAcknowledgeTransaction)
235                             {
236                                 tx.bindResource(message, message);
237                             }
238 
239                             if (logger.isDebugEnabled())
240                             {
241                                 logger.debug("Message received it is of type: " +
242                                         ClassUtils.getSimpleName(message.getClass()));
243                                 if (message.getJMSDestination() != null)
244                                 {
245                                     logger.debug("Message received on " + message.getJMSDestination() + " ("
246                                                  + message.getJMSDestination().getClass().getName() + ")");
247                                 }
248                                 else
249                                 {
250                                     logger.debug("Message received on unknown destination");
251                                 }
252                                 logger.debug("Message CorrelationId is: " + message.getJMSCorrelationID());
253                                 logger.debug("Jms Message Id is: " + message.getJMSMessageID());
254                             }
255 
256                             if (message.getJMSRedelivered())
257                             {
258                                 if (logger.isDebugEnabled())
259                                 {
260                                     logger.debug("Message with correlationId: "
261                                                  + message.getJMSCorrelationID()
262                                                  + " is redelivered. handing off to Exception Handler");
263                                 }
264                                 redeliveryHandler.handleRedelivery(message);
265                             }
266 
267                             UMOMessageAdapter adapter = connector.getMessageAdapter(message);
268                             routeMessage(new MuleMessage(adapter));
269                             return null;
270                         }
271                     };
272                     tt.execute(cb);
273                 }
274                 else
275                 {
276                     UMOMessageAdapter adapter = connector.getMessageAdapter(message);
277                     routeMessage(new MuleMessage(adapter));
278                 }
279 
280             }
281             catch (Exception e)
282             {
283                 getConnector().handleException(e);
284             }
285 
286         }
287 
288         public void release()
289         {
290             // Nothing to release.
291         }
292 
293     }
294 
295 }