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.ConnectException;
15 import org.mule.providers.SingleAttemptConnectionStrategy;
16 import org.mule.providers.TransactedPollingMessageReceiver;
17 import org.mule.providers.jms.filters.JmsSelectorFilter;
18 import org.mule.transaction.TransactionCoordination;
19 import org.mule.umo.UMOComponent;
20 import org.mule.umo.UMOTransaction;
21 import org.mule.umo.endpoint.UMOEndpoint;
22 import org.mule.umo.lifecycle.InitialisationException;
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.MapUtils;
27
28 import java.util.List;
29
30 import javax.jms.Destination;
31 import javax.jms.JMSException;
32 import javax.jms.Message;
33 import javax.jms.MessageConsumer;
34 import javax.jms.Session;
35
36 import edu.emory.mathcs.backport.java.util.concurrent.TimeUnit;
37
38 public class XaTransactedJmsMessageReceiver extends TransactedPollingMessageReceiver
39 {
40 public static final long DEFAULT_JMS_POLL_FREQUENCY = 100;
41 public static final TimeUnit DEFAULT_JMS_POLL_TIMEUNIT = TimeUnit.MILLISECONDS;
42
43 protected final JmsConnector connector;
44 protected boolean reuseConsumer;
45 protected boolean reuseSession;
46 protected final ThreadContextLocal context = new ThreadContextLocal();
47 protected final long timeout;
48 protected final RedeliveryHandler redeliveryHandler;
49
50
51
52
53 protected static class JmsThreadContext
54 {
55 public Session session;
56 public MessageConsumer consumer;
57 }
58
59
60
61
62 protected static class ThreadContextLocal extends ThreadLocal
63 {
64 public JmsThreadContext getContext()
65 {
66 return (JmsThreadContext)get();
67 }
68
69 protected Object initialValue()
70 {
71 return new JmsThreadContext();
72 }
73 }
74
75 public XaTransactedJmsMessageReceiver(UMOConnector umoConnector, UMOComponent component, UMOEndpoint endpoint)
76 throws InitialisationException
77 {
78 super(umoConnector, component, endpoint);
79
80
81 this.setFrequency(DEFAULT_JMS_POLL_FREQUENCY);
82 this.setTimeUnit(DEFAULT_JMS_POLL_TIMEUNIT);
83 this.connector = (JmsConnector) umoConnector;
84 this.timeout = endpoint.getTransactionConfig().getTimeout();
85
86
87
88
89 if (this.connectionStrategy instanceof SingleAttemptConnectionStrategy)
90 {
91 this.reuseConsumer = true;
92 this.reuseSession = true;
93 }
94
95
96 this.reuseConsumer = MapUtils.getBooleanValue(endpoint.getProperties(), "reuseConsumer",
97 this.reuseConsumer);
98 this.reuseSession = MapUtils.getBooleanValue(endpoint.getProperties(), "reuseSession",
99 this.reuseSession);
100
101
102
103
104
105 final boolean topic = connector.getTopicResolver().isTopic(endpoint);
106
107
108
109 this.setUseMultipleTransactedReceivers(!topic);
110
111 try
112 {
113 redeliveryHandler = this.connector.createRedeliveryHandler();
114 redeliveryHandler.setConnector(this.connector);
115 }
116 catch (Exception e)
117 {
118 throw new InitialisationException(e, this);
119 }
120
121 }
122
123 protected void doDispose()
124 {
125
126 }
127
128 protected void doConnect() throws Exception
129 {
130 if (connector.isConnected() && connector.isEagerConsumer())
131 {
132 createConsumer();
133
134
135
136
137
138
139
140
141
142
143
144
145
146 }
147 }
148
149 protected void doDisconnect() throws Exception
150 {
151 if (connector.isConnected())
152 {
153 closeConsumer(true);
154 }
155 }
156
157
158
159
160 public void poll() throws Exception
161 {
162 try
163 {
164 JmsThreadContext ctx = context.getContext();
165
166 if (ctx.consumer == null)
167 {
168 createConsumer();
169 }
170
171 super.poll();
172 }
173 catch (Exception e)
174 {
175
176 closeConsumer(true);
177 throw e;
178 }
179 finally
180 {
181
182 closeConsumer(false);
183 }
184 }
185
186
187
188
189
190
191 protected List getMessages() throws Exception
192 {
193
194
195 JmsThreadContext ctx = context.getContext();
196
197 UMOTransaction tx = TransactionCoordination.getInstance().getTransaction();
198 if (tx != null)
199 {
200 tx.bindResource(connector.getConnection(), ctx.session);
201 }
202
203
204 Message message = null;
205 try
206 {
207 message = ctx.consumer.receive(timeout);
208 }
209 catch (JMSException e)
210 {
211
212 if (!this.isConnected())
213 {
214
215 }
216 else
217 {
218 throw e;
219 }
220 }
221 if (message == null)
222 {
223 if (tx != null)
224 {
225 tx.setRollbackOnly();
226 }
227 return null;
228 }
229 message = connector.preProcessMessage(message, ctx.session);
230
231
232 if (logger.isDebugEnabled())
233 {
234 logger.debug("Message received it is of type: " +
235 ClassUtils.getSimpleName(message.getClass()));
236 if (message.getJMSDestination() != null)
237 {
238 logger.debug("Message received on " + message.getJMSDestination() + " ("
239 + message.getJMSDestination().getClass().getName() + ")");
240 }
241 else
242 {
243 logger.debug("Message received on unknown destination");
244 }
245 logger.debug("Message CorrelationId is: " + message.getJMSCorrelationID());
246 logger.debug("Jms Message Id is: " + message.getJMSMessageID());
247 }
248
249 if (message.getJMSRedelivered())
250 {
251 if (logger.isDebugEnabled())
252 {
253 logger.debug("Message with correlationId: " + message.getJMSCorrelationID()
254 + " is redelivered. handing off to Exception Handler");
255 }
256 redeliveryHandler.handleRedelivery(message);
257 }
258
259 if (tx instanceof JmsClientAcknowledgeTransaction)
260 {
261 tx.bindResource(message, null);
262 }
263
264 UMOMessageAdapter adapter = connector.getMessageAdapter(message);
265 routeMessage(new MuleMessage(adapter));
266 return null;
267 }
268
269
270
271
272
273
274 protected void processMessage(Object msg) throws Exception
275 {
276
277
278 }
279
280 protected void closeConsumer(boolean force)
281 {
282 JmsThreadContext ctx = context.getContext();
283 if (ctx == null)
284 {
285 return;
286 }
287
288 if (force || !reuseSession || !reuseConsumer)
289 {
290 connector.closeQuietly(ctx.consumer);
291 ctx.consumer = null;
292 }
293
294
295 if (force || !reuseSession)
296 {
297 connector.closeQuietly(ctx.session);
298 ctx.session = null;
299 }
300 }
301
302
303
304
305
306
307 protected void createConsumer() throws Exception
308 {
309 try
310 {
311 JmsSupport jmsSupport = this.connector.getJmsSupport();
312 JmsThreadContext ctx = context.getContext();
313
314 if (ctx.session == null)
315 {
316 ctx.session = this.connector.getSession(endpoint);
317 }
318
319
320 final boolean topic = connector.getTopicResolver().isTopic(endpoint);
321 Destination dest = jmsSupport.createDestination(ctx.session, endpoint.getEndpointURI()
322 .getAddress(), topic);
323
324
325 String selector = null;
326 if (endpoint.getFilter() != null && endpoint.getFilter() instanceof JmsSelectorFilter)
327 {
328 selector = ((JmsSelectorFilter)endpoint.getFilter()).getExpression();
329 }
330 else if (endpoint.getProperties() != null)
331 {
332
333
334 selector = (String)endpoint.getProperties().get(JmsConstants.JMS_SELECTOR_PROPERTY);
335 }
336 String tempDurable = (String)endpoint.getProperties().get("durable");
337 boolean durable = connector.isDurable();
338 if (tempDurable != null)
339 {
340 durable = Boolean.valueOf(tempDurable).booleanValue();
341 }
342
343
344 String durableName = (String)endpoint.getProperties().get("durableName");
345 if (durableName == null && durable && topic)
346 {
347 durableName = "mule." + connector.getName() + "." + endpoint.getEndpointURI().getAddress();
348 logger.debug("Jms Connector for this receiver is durable but no durable name has been specified. Defaulting to: "
349 + durableName);
350 }
351
352
353 ctx.consumer = jmsSupport.createConsumer(ctx.session, dest, selector, connector.isNoLocal(),
354 durableName, topic);
355 }
356 catch (JMSException e)
357 {
358 throw new ConnectException(e, this);
359 }
360 }
361 }