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