View Javadoc

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