1
2
3
4
5
6
7
8
9
10
11 package org.mule.providers.jms;
12
13 import org.mule.MuleRuntimeException;
14 import org.mule.config.i18n.MessageFactory;
15 import org.mule.providers.AbstractMessageReceiver;
16 import org.mule.providers.AbstractReceiverWorker;
17 import org.mule.providers.ConnectException;
18 import org.mule.providers.jms.filters.JmsSelectorFilter;
19 import org.mule.umo.TransactionException;
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.util.ClassUtils;
28
29 import java.util.ArrayList;
30
31 import javax.jms.Destination;
32 import javax.jms.JMSException;
33 import javax.jms.Message;
34 import javax.jms.MessageConsumer;
35 import javax.jms.MessageListener;
36 import javax.jms.Session;
37 import javax.jms.Topic;
38 import javax.resource.spi.work.WorkException;
39
40 import edu.emory.mathcs.backport.java.util.concurrent.BlockingDeque;
41 import edu.emory.mathcs.backport.java.util.concurrent.LinkedBlockingDeque;
42 import org.apache.commons.logging.Log;
43 import org.apache.commons.logging.LogFactory;
44
45
46
47
48
49
50
51
52
53
54 public class MultiConsumerJmsMessageReceiver extends AbstractMessageReceiver
55 {
56 protected final BlockingDeque consumers;
57
58 protected volatile int receiversCount;
59
60 private final JmsConnector jmsConnector;
61
62 public MultiConsumerJmsMessageReceiver(UMOConnector connector, UMOComponent component, UMOEndpoint endpoint)
63 throws InitialisationException
64 {
65 super(connector, component, endpoint);
66
67 jmsConnector = (JmsConnector) connector;
68
69 final boolean isTopic = jmsConnector.getTopicResolver().isTopic(endpoint, true);
70 receiversCount = jmsConnector.getNumberOfConcurrentTransactedReceivers();
71 if (isTopic && receiversCount != 1)
72 {
73 if (logger.isInfoEnabled())
74 {
75 logger.info("Destination " + getEndpoint().getEndpointURI() + " is a topic, but " + receiversCount +
76 " receivers have been configured. Will configure only 1.");
77 }
78 receiversCount = 1;
79 }
80 if (logger.isDebugEnabled())
81 {
82 logger.debug("Creating " + receiversCount + " sub-receivers for " + endpoint.getEndpointURI());
83 }
84 consumers = new LinkedBlockingDeque(receiversCount);
85 for (int i = 0; i < receiversCount; i++)
86 {
87 consumers.addLast(new SubReceiver());
88 }
89 }
90
91 protected void doStart() throws UMOException
92 {
93 logger.debug("doStart()");
94 for (int i = 0; i < receiversCount; i++)
95 {
96 SubReceiver sub = (SubReceiver) consumers.removeFirst();
97 sub.doStart();
98 consumers.addLast(sub);
99 }
100 }
101
102 protected void doStop() throws UMOException
103 {
104 logger.debug("doStop()");
105 for (int i = 0; i < receiversCount; i++)
106 {
107 SubReceiver sub = (SubReceiver) consumers.removeFirst();
108 sub.doStop();
109 consumers.addLast(sub);
110 }
111 }
112
113 protected void doConnect() throws Exception
114 {
115 logger.debug("doConnect()");
116 for (int i = 0; i < receiversCount; i++)
117 {
118 SubReceiver sub = (SubReceiver) consumers.removeFirst();
119 sub.doConnect();
120 consumers.addLast(sub);
121 }
122 }
123
124 protected void doDisconnect() throws Exception
125 {
126 logger.debug("doDisconnect()");
127 for (int i = 0; i < receiversCount; i++)
128 {
129 SubReceiver sub = (SubReceiver) consumers.removeFirst();
130 sub.doDisconnect();
131 consumers.addLast(sub);
132 }
133
134 }
135
136 protected void doDispose()
137 {
138 logger.debug("doDispose()");
139 }
140
141 private class SubReceiver implements MessageListener
142 {
143 private final Log subLogger = LogFactory.getLog(getClass());
144
145 private volatile Session session;
146 private volatile MessageConsumer consumer;
147
148 protected void doConnect() throws Exception
149 {
150 subLogger.debug("SUB doConnect()");
151 createConsumer();
152 }
153
154 protected void doDisconnect() throws Exception
155 {
156 closeConsumer();
157 }
158
159 protected void closeConsumer()
160 {
161 jmsConnector.closeQuietly(consumer);
162 consumer = null;
163 jmsConnector.closeQuietly(session);
164 session = null;
165 }
166
167 protected void doStart() throws UMOException
168 {
169 try
170 {
171 consumer.setMessageListener(this);
172 }
173 catch (JMSException e)
174 {
175 throw new LifecycleException(e, this);
176 }
177 }
178
179 protected void doStop() throws UMOException
180 {
181 try
182 {
183 if (consumer != null)
184 {
185 consumer.setMessageListener(null);
186 }
187 }
188 catch (JMSException e)
189 {
190 throw new LifecycleException(e, this);
191 }
192 }
193
194
195
196
197
198 protected void createConsumer() throws Exception
199 {
200 try
201 {
202 JmsSupport jmsSupport = jmsConnector.getJmsSupport();
203
204 if (session == null)
205 {
206 session = jmsConnector.getSession(endpoint);
207 }
208
209 boolean topic = jmsConnector.getTopicResolver().isTopic(endpoint, true);
210
211
212 Destination dest = jmsSupport.createDestination(session, endpoint.getEndpointURI().getAddress(),
213 topic);
214
215
216 String selector = null;
217 if (endpoint.getFilter() != null && endpoint.getFilter() instanceof JmsSelectorFilter)
218 {
219 selector = ((JmsSelectorFilter) endpoint.getFilter()).getExpression();
220 }
221 else
222 {
223 if (endpoint.getProperties() != null)
224 {
225
226
227 selector = (String) endpoint.getProperties().get(JmsConstants.JMS_SELECTOR_PROPERTY);
228 }
229 }
230 String tempDurable = (String) endpoint.getProperties().get(JmsConstants.DURABLE_PROPERTY);
231 boolean durable = jmsConnector.isDurable();
232 if (tempDurable != null)
233 {
234 durable = Boolean.valueOf(tempDurable).booleanValue();
235 }
236
237
238 String durableName = (String) endpoint.getProperties().get(JmsConstants.DURABLE_NAME_PROPERTY);
239 if (durableName == null && durable && dest instanceof Topic)
240 {
241 durableName = "mule." + jmsConnector.getName() + "." + endpoint.getEndpointURI().getAddress();
242 logger.debug("Jms Connector for this receiver is durable but no durable name has been specified. Defaulting to: "
243 + durableName);
244 }
245
246
247 consumer = jmsSupport.createConsumer(session, dest, selector, jmsConnector.isNoLocal(), durableName,
248 topic);
249 }
250 catch (JMSException e)
251 {
252 throw new ConnectException(e, this);
253 }
254 }
255
256 public void onMessage(final Message message)
257 {
258 try
259 {
260
261
262
263
264 getWorkManager().doWork(new JmsWorker(message, MultiConsumerJmsMessageReceiver.this, this));
265 }
266 catch (WorkException e)
267 {
268 throw new MuleRuntimeException(MessageFactory.createStaticMessage(
269 "Couldn't submit a work item to the WorkManager"), e);
270 }
271 }
272 }
273
274 protected class JmsWorker extends AbstractReceiverWorker
275 {
276 private final SubReceiver subReceiver;
277
278 public JmsWorker(Message message, AbstractMessageReceiver receiver, SubReceiver subReceiver)
279 {
280 super(new ArrayList(1), receiver);
281 this.subReceiver = subReceiver;
282 messages.add(message);
283 }
284
285
286 protected Object preProcessMessage(Object message) throws Exception
287 {
288 Message m = (Message) message;
289
290 if (logger.isDebugEnabled())
291 {
292 logger.debug("Message received it is of type: " +
293 ClassUtils.getSimpleName(message.getClass()));
294 if (m.getJMSDestination() != null)
295 {
296 logger.debug("Message received on " + m.getJMSDestination() + " ("
297 + m.getJMSDestination().getClass().getName() + ")");
298 }
299 else
300 {
301 logger.debug("Message received on unknown destination");
302 }
303 logger.debug("Message CorrelationId is: " + m.getJMSCorrelationID());
304 logger.debug("Jms Message Id is: " + m.getJMSMessageID());
305 }
306
307 if (m.getJMSRedelivered())
308 {
309
310 RedeliveryHandler redeliveryHandler = jmsConnector.createRedeliveryHandler();
311 redeliveryHandler.setConnector(jmsConnector);
312 if (logger.isDebugEnabled())
313 {
314 logger.debug("Message with correlationId: " + m.getJMSCorrelationID()
315 + " has redelivered flag set, handing off to Exception Handler");
316 }
317 redeliveryHandler.handleRedelivery(m);
318 }
319 return m;
320
321 }
322
323 protected void bindTransaction(UMOTransaction tx) throws TransactionException
324 {
325 if (tx instanceof JmsTransaction)
326 {
327 if (logger.isDebugEnabled())
328 {
329 logger.debug(">>> !! Binding " + subReceiver.session + " to " + jmsConnector.getConnection());
330 }
331 tx.bindResource(jmsConnector.getConnection(), subReceiver.session);
332 }
333 else
334 {
335 if (tx instanceof JmsClientAcknowledgeTransaction)
336 {
337
338
339
340 ((JmsClientAcknowledgeTransaction) tx).setMessage((Message) messages.get(0));
341 }
342 }
343 }
344
345 }
346
347 }