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