1
2
3
4
5
6
7
8
9
10
11 package org.mule.providers.jms;
12
13 import org.mule.impl.MuleMessage;
14 import org.mule.providers.AbstractMessageDispatcher;
15 import org.mule.providers.jms.filters.JmsSelectorFilter;
16 import org.mule.providers.jms.i18n.JmsMessages;
17 import org.mule.transaction.IllegalTransactionStateException;
18 import org.mule.umo.UMOEvent;
19 import org.mule.umo.UMOMessage;
20 import org.mule.umo.endpoint.UMOEndpointURI;
21 import org.mule.umo.endpoint.UMOImmutableEndpoint;
22 import org.mule.umo.provider.DispatchException;
23 import org.mule.umo.provider.UMOConnector;
24 import org.mule.umo.provider.UMOMessageAdapter;
25 import org.mule.util.ClassUtils;
26 import org.mule.util.NumberUtils;
27 import org.mule.util.StringUtils;
28 import org.mule.util.concurrent.Latch;
29 import org.mule.util.concurrent.WaitableBoolean;
30
31 import javax.jms.DeliveryMode;
32 import javax.jms.Destination;
33 import javax.jms.Message;
34 import javax.jms.MessageConsumer;
35 import javax.jms.MessageListener;
36 import javax.jms.MessageProducer;
37 import javax.jms.Session;
38 import javax.jms.TemporaryQueue;
39 import javax.jms.TemporaryTopic;
40
41 import edu.emory.mathcs.backport.java.util.concurrent.TimeUnit;
42
43 import org.apache.commons.lang.BooleanUtils;
44
45
46
47
48
49
50
51 public class JmsMessageDispatcher extends AbstractMessageDispatcher
52 {
53
54 private JmsConnector connector;
55 private Session cachedSession;
56
57 public JmsMessageDispatcher(UMOImmutableEndpoint endpoint)
58 {
59 super(endpoint);
60 this.connector = (JmsConnector) endpoint.getConnector();
61 }
62
63 protected void doDispatch(UMOEvent event) throws Exception
64 {
65 dispatchMessage(event);
66 }
67
68 protected void doConnect() throws Exception
69 {
70
71 }
72
73 protected void doDisconnect() throws Exception
74 {
75
76 }
77
78 private UMOMessage dispatchMessage(UMOEvent event) throws Exception
79 {
80 Session session = null;
81 MessageProducer producer = null;
82 MessageConsumer consumer = null;
83 Destination replyTo = null;
84 boolean transacted = false;
85 boolean cached = false;
86 boolean remoteSync = useRemoteSync(event);
87
88 if (logger.isDebugEnabled())
89 {
90 logger.debug("dispatching on endpoint: " + event.getEndpoint().getEndpointURI()
91 + ". Event id is: " + event.getId());
92 }
93
94 try
95 {
96 session = connector.getSessionFromTransaction();
97 if (session != null)
98 {
99 transacted = true;
100
101
102
103 if (remoteSync)
104 {
105 throw new IllegalTransactionStateException(
106 JmsMessages.connectorDoesNotSupportSyncReceiveWhenTransacted());
107 }
108 }
109
110
111 else if (event.getMessage().getBooleanProperty(JmsConstants.CACHE_JMS_SESSIONS_PROPERTY,
112 connector.isCacheJmsSessions()))
113 {
114 cached = true;
115 if (cachedSession != null)
116 {
117 session = cachedSession;
118 }
119 else
120 {
121 session = connector.getSession(event.getEndpoint());
122 cachedSession = session;
123 }
124 }
125 else
126 {
127 session = connector.getSession(event.getEndpoint());
128 if (event.getEndpoint().getTransactionConfig().isTransacted())
129 {
130 transacted = true;
131 }
132 }
133
134 UMOEndpointURI endpointUri = event.getEndpoint().getEndpointURI();
135
136 boolean topic = connector.getTopicResolver().isTopic(event.getEndpoint(), true);
137
138 Destination dest = connector.getJmsSupport().createDestination(session, endpointUri.getAddress(),
139 topic);
140 producer = connector.getJmsSupport().createProducer(session, dest, topic);
141
142 Object message = event.getTransformedMessage();
143 if (!(message instanceof Message))
144 {
145 throw new DispatchException(
146 JmsMessages.checkTransformer("JMS message", message.getClass(), connector.getName()),
147 event.getMessage(), event.getEndpoint());
148 }
149
150 Message msg = (Message) message;
151 if (event.getMessage().getCorrelationId() != null)
152 {
153 msg.setJMSCorrelationID(event.getMessage().getCorrelationId());
154 }
155
156 UMOMessage eventMsg = event.getMessage();
157
158
159 if (connector.supportsProperty(JmsConstants.JMS_REPLY_TO))
160 {
161 Object tempReplyTo = eventMsg.removeProperty(JmsConstants.JMS_REPLY_TO);
162 if (tempReplyTo != null)
163 {
164 if (tempReplyTo instanceof Destination)
165 {
166 replyTo = (Destination) tempReplyTo;
167 }
168 else
169 {
170
171 boolean replyToTopic = false;
172 String reply = tempReplyTo.toString();
173 int i = reply.indexOf(":");
174 if (i > -1)
175 {
176
177
178
179
180 String qtype = reply.substring(0, i);
181 replyToTopic = JmsConstants.TOPIC_PROPERTY.equalsIgnoreCase(qtype);
182 reply = reply.substring(i + 1);
183 }
184 replyTo = connector.getJmsSupport().createDestination(session, reply, replyToTopic);
185 }
186 }
187
188 if (remoteSync && replyTo == null)
189 {
190 replyTo = connector.getJmsSupport().createTemporaryDestination(session, topic);
191 }
192
193 if (replyTo != null)
194 {
195 msg.setJMSReplyTo(replyTo);
196 }
197
198
199 if (remoteSync)
200 {
201 consumer = connector.getJmsSupport().createConsumer(session, replyTo, topic);
202 }
203 }
204
205
206 String ttlString = (String) eventMsg.removeProperty(JmsConstants.TIME_TO_LIVE_PROPERTY);
207 String priorityString = (String) eventMsg.removeProperty(JmsConstants.PRIORITY_PROPERTY);
208 String persistentDeliveryString = (String) eventMsg.removeProperty(JmsConstants.PERSISTENT_DELIVERY_PROPERTY);
209
210 long ttl = StringUtils.isNotBlank(ttlString)
211 ? NumberUtils.toLong(ttlString)
212 : Message.DEFAULT_TIME_TO_LIVE;
213 int priority = StringUtils.isNotBlank(priorityString)
214 ? NumberUtils.toInt(priorityString)
215 : Message.DEFAULT_PRIORITY;
216 boolean persistent = StringUtils.isNotBlank(persistentDeliveryString)
217 ? BooleanUtils.toBoolean(persistentDeliveryString)
218 : connector.isPersistentDelivery();
219
220 if (connector.isHonorQosHeaders())
221 {
222 int priorityProp = eventMsg.getIntProperty(JmsConstants.JMS_PRIORITY, UMOConnector.INT_VALUE_NOT_SET);
223 int deliveryModeProp = eventMsg.getIntProperty(JmsConstants.JMS_DELIVERY_MODE, UMOConnector.INT_VALUE_NOT_SET);
224
225 if (priorityProp != UMOConnector.INT_VALUE_NOT_SET)
226 {
227 priority = priorityProp;
228 }
229 if (deliveryModeProp != UMOConnector.INT_VALUE_NOT_SET)
230 {
231 persistent = deliveryModeProp == DeliveryMode.PERSISTENT;
232 }
233 }
234
235 if (logger.isDebugEnabled())
236 {
237 logger.debug("Sending message of type " + ClassUtils.getSimpleName(msg.getClass()));
238 }
239
240 if (consumer != null && topic)
241 {
242
243 Latch l = new Latch();
244 ReplyToListener listener = new ReplyToListener(l);
245 consumer.setMessageListener(listener);
246
247 connector.getJmsSupport().send(producer, msg, persistent, priority, ttl, topic);
248
249 int timeout = event.getTimeout();
250
251 if (logger.isDebugEnabled())
252 {
253 logger.debug("Waiting for return event for: " + timeout + " ms on " + replyTo);
254 }
255
256 l.await(timeout, TimeUnit.MILLISECONDS);
257 consumer.setMessageListener(null);
258 listener.release();
259 Message result = listener.getMessage();
260 if (result == null)
261 {
262 logger.debug("No message was returned via replyTo destination");
263 return null;
264 }
265 else
266 {
267 UMOMessageAdapter adapter = connector.getMessageAdapter(result);
268 return new MuleMessage(JmsMessageUtils.toObject(result, connector.getSpecification()),
269 adapter);
270 }
271 }
272 else
273 {
274 connector.getJmsSupport().send(producer, msg, persistent, priority, ttl, topic);
275 if (consumer != null)
276 {
277 int timeout = event.getTimeout();
278
279 if (logger.isDebugEnabled())
280 {
281 logger.debug("Waiting for return event for: " + timeout + " ms on " + replyTo);
282 }
283
284 Message result = consumer.receive(timeout);
285 if (result == null)
286 {
287 logger.debug("No message was returned via replyTo destination");
288 return null;
289 }
290 else
291 {
292 UMOMessageAdapter adapter = connector.getMessageAdapter(result);
293 return new MuleMessage(
294 JmsMessageUtils.toObject(result, connector.getSpecification()), adapter);
295 }
296 }
297 }
298 return null;
299 }
300 finally
301 {
302 connector.closeQuietly(producer);
303 connector.closeQuietly(consumer);
304
305
306 if (replyTo != null && (replyTo instanceof TemporaryQueue || replyTo instanceof TemporaryTopic))
307 {
308 if (replyTo instanceof TemporaryQueue)
309 {
310 connector.closeQuietly((TemporaryQueue) replyTo);
311 }
312 else
313 {
314
315
316 connector.closeQuietly((TemporaryTopic) replyTo);
317 }
318 }
319
320
321
322 if (session != null && !cached && !transacted)
323 {
324 connector.closeQuietly(session);
325 }
326 }
327 }
328
329 protected UMOMessage doSend(UMOEvent event) throws Exception
330 {
331 UMOMessage message = dispatchMessage(event);
332 return message;
333 }
334
335
336
337
338
339
340
341
342
343
344
345
346 protected UMOMessage doReceive(long timeout) throws Exception
347 {
348 Session session = null;
349 MessageConsumer consumer = null;
350
351 try
352 {
353 final boolean topic = connector.getTopicResolver().isTopic(endpoint);
354
355 JmsSupport support = connector.getJmsSupport();
356 session = connector.getSession(false, topic);
357 Destination dest = support.createDestination(session, endpoint.getEndpointURI().getAddress(),
358 topic);
359
360
361 String selector = null;
362 if (endpoint.getFilter() != null && endpoint.getFilter() instanceof JmsSelectorFilter)
363 {
364 selector = ((JmsSelectorFilter) endpoint.getFilter()).getExpression();
365 }
366 else if (endpoint.getProperties() != null)
367 {
368
369
370 selector = (String) endpoint.getProperties().get(JmsConstants.JMS_SELECTOR_PROPERTY);
371 }
372 String tempDurable = (String) endpoint.getProperties().get(JmsConstants.DURABLE_PROPERTY);
373 boolean durable = connector.isDurable();
374 if (tempDurable != null)
375 {
376 durable = Boolean.valueOf(tempDurable).booleanValue();
377 }
378
379
380 String durableName = (String) endpoint.getProperties().get(JmsConstants.DURABLE_NAME_PROPERTY);
381 if (durableName == null && durable && topic)
382 {
383 durableName = "mule." + connector.getName() + "." + endpoint.getEndpointURI().getAddress();
384 if (logger.isDebugEnabled())
385 {
386 logger.debug("Jms Connector for this receiver is durable but no durable name has been specified. Defaulting to: "
387 + durableName);
388 }
389 }
390
391
392 consumer = support.createConsumer(session, dest, selector, connector.isNoLocal(), durableName,
393 topic);
394
395 try
396 {
397 Message message;
398
399 if (timeout == RECEIVE_NO_WAIT)
400 {
401 message = consumer.receiveNoWait();
402 }
403 else if (timeout == RECEIVE_WAIT_INDEFINITELY)
404 {
405 message = consumer.receive();
406 }
407 else
408 {
409 message = consumer.receive(timeout);
410 }
411
412 if (message == null)
413 {
414 return null;
415 }
416
417 message = connector.preProcessMessage(message, session);
418
419 return new MuleMessage(connector.getMessageAdapter(message));
420 }
421 catch (Exception e)
422 {
423 connector.handleException(e);
424 return null;
425 }
426 }
427 finally
428 {
429 connector.closeQuietly(consumer);
430 connector.closeQuietly(session);
431 }
432 }
433
434 protected void doDispose()
435 {
436
437 }
438
439 private class ReplyToListener implements MessageListener
440 {
441 private final Latch latch;
442 private volatile Message message;
443 private final WaitableBoolean released = new WaitableBoolean(false);
444
445 public ReplyToListener(Latch latch)
446 {
447 this.latch = latch;
448 }
449
450 public Message getMessage()
451 {
452 return message;
453 }
454
455 public void release()
456 {
457 released.set(true);
458 }
459
460 public void onMessage(Message message)
461 {
462 this.message = message;
463 latch.countDown();
464 try
465 {
466 released.whenTrue(null);
467 }
468 catch (InterruptedException e)
469 {
470
471 }
472 }
473 }
474
475 }