1
2
3
4
5
6
7
8
9
10
11 package org.mule.test.integration.providers.jms;
12
13 import org.mule.MuleManager;
14 import org.mule.config.MuleProperties;
15 import org.mule.impl.DefaultExceptionStrategy;
16 import org.mule.impl.MuleDescriptor;
17 import org.mule.impl.MuleTransactionConfig;
18 import org.mule.impl.endpoint.MuleEndpoint;
19 import org.mule.impl.endpoint.MuleEndpointURI;
20 import org.mule.providers.jms.JmsConnector;
21 import org.mule.providers.jms.MessageRedeliveredException;
22 import org.mule.providers.jms.transformers.JMSMessageToObject;
23 import org.mule.providers.jms.transformers.ObjectToJMSMessage;
24 import org.mule.tck.functional.EventCallback;
25 import org.mule.tck.functional.FunctionalTestComponent;
26 import org.mule.test.integration.providers.jms.tools.JmsTestUtils;
27 import org.mule.transaction.TransactionCoordination;
28 import org.mule.umo.UMOComponent;
29 import org.mule.umo.UMODescriptor;
30 import org.mule.umo.UMOEventContext;
31 import org.mule.umo.UMOException;
32 import org.mule.umo.UMOMessage;
33 import org.mule.umo.UMOTransaction;
34 import org.mule.umo.UMOTransactionConfig;
35 import org.mule.umo.UMOTransactionFactory;
36 import org.mule.umo.endpoint.MalformedEndpointException;
37 import org.mule.umo.endpoint.UMOEndpoint;
38 import org.mule.umo.endpoint.UMOEndpointURI;
39 import org.mule.umo.manager.UMOManager;
40 import org.mule.umo.provider.UMOConnector;
41 import org.mule.util.ExceptionUtils;
42
43 import java.util.HashMap;
44
45 import javax.jms.JMSException;
46 import javax.jms.Message;
47 import javax.jms.MessageConsumer;
48 import javax.jms.MessageListener;
49 import javax.jms.QueueConnection;
50 import javax.jms.Session;
51 import javax.jms.TextMessage;
52 import javax.jms.TopicConnection;
53
54 import edu.emory.mathcs.backport.java.util.concurrent.CountDownLatch;
55 import edu.emory.mathcs.backport.java.util.concurrent.TimeUnit;
56
57
58
59
60
61
62 public abstract class AbstractJmsTransactionFunctionalTest extends AbstractJmsFunctionalTestCase
63 {
64
65 public static final int SEND_NOT_TRANSACTED = 0x01;
66 public static final int SEND_TRANSACTED_ALWAYS = 0x02;
67 public static final int SEND_TRANSACTED_IF_POSSIBLE_WITH_TRANSACTION = 0x04;
68 public static final int SEND_TRANSACTED_IF_POSSIBLE_WITHOUT_TRANSACTION = 0x08;
69 public static final int SEND_TRANSACTED_ROLLBACK = 0x10;
70 public static final int CLEANUP = 0x20;
71 public static final int TRANSACTED_REDELIVERY_TO_DL_DESTINATION = 0x40;
72 public static final int ALL = 0xffff;
73
74 protected volatile UMOTransaction currentTx;
75 protected int exclusionFlag = 0;
76
77 protected void exclude(int flag)
78 {
79 exclusionFlag = flag;
80 }
81
82 protected boolean notExcluded(int flag)
83 {
84 boolean excluded = (flag & exclusionFlag) != 0;
85 if (excluded)
86 {
87 logger.warn("Excluding this test");
88 }
89 return ! excluded;
90 }
91
92 protected void doSetUp() throws Exception
93 {
94 super.doSetUp();
95 currentTx = null;
96 }
97
98 protected void doTearDown() throws Exception
99 {
100 TransactionCoordination.getInstance().unbindTransaction(
101 TransactionCoordination.getInstance().getTransaction());
102 super.doTearDown();
103 }
104
105 public void testSendNotTransacted() throws Exception
106 {
107 if (notExcluded(SEND_NOT_TRANSACTED))
108 {
109 UMODescriptor descriptor = getDescriptor("testComponent", FunctionalTestComponent.class.getName());
110
111 final int countDownInitialCount = 2;
112 final CountDownLatch countDown = new CountDownLatch(countDownInitialCount);
113
114 EventCallback callback = new EventCallback()
115 {
116 public synchronized void eventReceived(UMOEventContext context, Object component)
117 {
118 callbackCalled = true;
119 assertNull(context.getCurrentTransaction());
120 countDown.countDown();
121 }
122 };
123
124 initialiseComponent(descriptor, UMOTransactionConfig.ACTION_NONE, callback);
125 addResultListener(getOutDest().getAddress(), countDown);
126 MuleManager.getInstance().start();
127 afterInitialise();
128 send(DEFAULT_MESSAGE, false, Session.AUTO_ACKNOWLEDGE);
129
130 countDown.await(LOCK_WAIT, TimeUnit.MILLISECONDS);
131 assertTrue("Only " + (countDownInitialCount - countDown.getCount()) + " of " + countDownInitialCount
132 + " checkpoints hit", countDown.getCount() == 0);
133
134 assertNotNull(currentMsg);
135 assertTrue(currentMsg instanceof TextMessage);
136 assertEquals(DEFAULT_MESSAGE + " Received", ((TextMessage)currentMsg).getText());
137 assertTrue(callbackCalled);
138 assertNull(currentTx);
139 }
140 }
141
142 public void testSendTransactedAlways() throws Exception
143 {
144 if (notExcluded(SEND_TRANSACTED_ALWAYS))
145 {
146 final int countDownInitialCount = 2;
147 final CountDownLatch countDown = new CountDownLatch(countDownInitialCount);
148
149
150 UMODescriptor descriptor = getDescriptor("testComponent", FunctionalTestComponent.class.getName());
151
152 EventCallback callback = new EventCallback()
153 {
154 public synchronized void eventReceived(UMOEventContext context, Object component) throws Exception
155 {
156 callbackCalled = true;
157 currentTx = context.getCurrentTransaction();
158 assertNotNull(currentTx);
159 assertTrue(currentTx.isBegun());
160 countDown.countDown();
161 }
162 };
163
164 initialiseComponent(descriptor, UMOTransactionConfig.ACTION_ALWAYS_BEGIN, callback);
165
166
167 MuleManager.getInstance().start();
168 addResultListener(getOutDest().getAddress(), countDown);
169
170
171
172 send(DEFAULT_MESSAGE, false, getAcknowledgementMode());
173
174 countDown.await(LOCK_WAIT, TimeUnit.MILLISECONDS);
175 assertTrue("Only " + (countDownInitialCount - countDown.getCount()) + " of " + countDownInitialCount
176 + " checkpoints hit", countDown.getCount() == 0);
177
178 assertNotNull(currentMsg);
179 assertTrue(currentMsg instanceof TextMessage);
180 assertEquals(DEFAULT_MESSAGE + " Received", ((TextMessage)currentMsg).getText());
181 assertTrue(callbackCalled);
182 assertTrue(currentTx.isBegun());
183
184
185 Thread.sleep(1000);
186 assertTrue(currentTx.isCommitted());
187 }
188 }
189
190 public void testSendTransactedIfPossibleWithTransaction() throws Exception
191 {
192 if (notExcluded(SEND_TRANSACTED_IF_POSSIBLE_WITH_TRANSACTION))
193 {
194 doSendTransactedIfPossible(true);
195 }
196 }
197
198 public void testSendTransactedIfPossibleWithoutTransaction() throws Exception
199 {
200 if (notExcluded(SEND_TRANSACTED_IF_POSSIBLE_WITHOUT_TRANSACTION))
201 {
202 doSendTransactedIfPossible(false);
203 }
204 }
205
206 private void doSendTransactedIfPossible(final boolean transactionAvailable) throws Exception
207 {
208 final int countDownInitialCount = 2;
209 final CountDownLatch countDown = new CountDownLatch(countDownInitialCount);
210
211
212 UMODescriptor descriptor = getDescriptor("testComponent", FunctionalTestComponent.class.getName());
213
214 EventCallback callback = new EventCallback()
215 {
216 public synchronized void eventReceived(UMOEventContext context, Object component) throws Exception
217 {
218 callbackCalled = true;
219 currentTx = context.getCurrentTransaction();
220 if (transactionAvailable)
221 {
222 assertNotNull(currentTx);
223 assertTrue(currentTx.isBegun());
224 }
225 else
226 {
227 assertNull(currentTx);
228 }
229 countDown.countDown();
230 }
231 };
232
233 initialiseComponent(descriptor, (transactionAvailable
234 ? UMOTransactionConfig.ACTION_ALWAYS_BEGIN : UMOTransactionConfig.ACTION_NONE),
235 callback);
236
237
238 MuleManager.getInstance().start();
239 addResultListener(getOutDest().getAddress(), countDown);
240
241
242
243 send(DEFAULT_MESSAGE, false, Session.AUTO_ACKNOWLEDGE);
244
245 countDown.await(LOCK_WAIT, TimeUnit.MILLISECONDS);
246 assertTrue("Only " + (countDownInitialCount - countDown.getCount()) + " of " + countDownInitialCount
247 + " checkpoints hit", countDown.await(LOCK_WAIT, TimeUnit.MILLISECONDS));
248
249 assertNotNull(currentMsg);
250 assertTrue(currentMsg instanceof TextMessage);
251 assertEquals(DEFAULT_MESSAGE + " Received", ((TextMessage)currentMsg).getText());
252 assertTrue(callbackCalled);
253
254 if (transactionAvailable)
255 {
256 assertNotNull(currentTx);
257 assertTrue(currentTx.isBegun());
258
259
260 Thread.sleep(300);
261 assertTrue(currentTx.isCommitted());
262 }
263 else
264 {
265 assertNull(currentTx);
266 }
267 }
268
269 public void testSendTransactedRollback() throws Exception
270 {
271 if (notExcluded(SEND_TRANSACTED_ROLLBACK))
272 {
273 final int countDownInitialCount = 2;
274 final CountDownLatch countDown = new CountDownLatch(countDownInitialCount);
275
276
277
278
279
280 UMODescriptor descriptor = getDescriptor("testComponent", FunctionalTestComponent.class.getName());
281
282 EventCallback callback = new EventCallback()
283 {
284 public synchronized void eventReceived(UMOEventContext context, Object component) throws Exception
285 {
286 callbackCalled = true;
287 currentTx = context.getCurrentTransaction();
288 assertNotNull(currentTx);
289 assertTrue(currentTx.isBegun());
290 logger.debug("@@@@ Rolling back transaction @@@@");
291 currentTx.setRollbackOnly();
292 countDown.countDown();
293 }
294 };
295
296 initialiseComponent(descriptor, UMOTransactionConfig.ACTION_ALWAYS_BEGIN, callback);
297 UMOManager manager = MuleManager.getInstance();
298 addResultListener(getOutDest().getAddress(), countDown);
299
300 UMOConnector umoCnn = manager.lookupConnector(CONNECTOR_NAME);
301
302 umoCnn.setExceptionListener(new RollbackExceptionListener(countDown));
303
304
305 manager.start();
306
307
308
309 send(DEFAULT_MESSAGE, false, Session.AUTO_ACKNOWLEDGE);
310
311 afterInitialise();
312 countDown.await(LOCK_WAIT, TimeUnit.MILLISECONDS);
313 assertTrue("Only " + (countDownInitialCount - countDown.getCount()) + " of " + countDownInitialCount
314 + " checkpoints hit", countDown.getCount() == 0);
315
316
317 afterInitialise();
318
319 assertNull(currentMsg);
320 assertTrue(callbackCalled);
321 assertTrue(currentTx.isRolledBack());
322
323
324 assertNull(receive(getInDest().getAddress(), 2000));
325 }
326 }
327
328 public void testCleanup() throws Exception
329 {
330 if (notExcluded(CLEANUP))
331 {
332 assertNull("There should be no transaction associated with this thread",
333 TransactionCoordination.getInstance().getTransaction());
334 }
335 }
336
337 public UMOComponent initialiseComponent(UMODescriptor descriptor,
338 byte txBeginAction,
339 EventCallback callback) throws Exception
340 {
341 JMSMessageToObject inTrans = new JMSMessageToObject();
342 ObjectToJMSMessage outTrans = new ObjectToJMSMessage();
343
344 UMOEndpoint endpoint = new MuleEndpoint("testIn", getInDest(), connector, inTrans,
345 UMOEndpoint.ENDPOINT_TYPE_RECEIVER, 0, null, null);
346
347 UMOTransactionConfig txConfig = new MuleTransactionConfig();
348 txConfig.setFactory(getTransactionFactory());
349 txConfig.setAction(txBeginAction);
350
351 UMOEndpoint outProvider = new MuleEndpoint("testOut", getOutDest(), connector, outTrans,
352 UMOEndpoint.ENDPOINT_TYPE_SENDER, 0, null, null);
353
354 endpoint.setTransactionConfig(txConfig);
355
356 descriptor.setOutboundEndpoint(outProvider);
357 descriptor.setInboundEndpoint(endpoint);
358 HashMap props = new HashMap();
359 props.put("eventCallback", callback);
360 descriptor.setProperties(props);
361 UMOComponent component = model.registerComponent(descriptor);
362
363 return component;
364 }
365
366 public static UMODescriptor getDescriptor(String name, String implementation)
367 {
368 UMODescriptor descriptor = new MuleDescriptor();
369 descriptor.setExceptionListener(new DefaultExceptionStrategy());
370 descriptor.setName(name);
371 descriptor.setImplementation(implementation);
372 return descriptor;
373 }
374
375 public void afterInitialise() throws Exception
376 {
377 Thread.sleep(1000);
378 }
379
380 protected UMOEndpointURI getInDest()
381 {
382 try
383 {
384 if (cnn instanceof QueueConnection)
385 {
386 return new MuleEndpointURI(DEFAULT_IN_QUEUE);
387 }
388 else
389 {
390 return new MuleEndpointURI(DEFAULT_IN_TOPIC);
391 }
392 }
393 catch (MalformedEndpointException e)
394 {
395 fail(e.getMessage());
396 return null;
397 }
398 }
399
400 protected UMOEndpointURI getOutDest()
401 {
402 try
403 {
404 if (cnn instanceof QueueConnection)
405 {
406 return new MuleEndpointURI(DEFAULT_OUT_QUEUE);
407 }
408 else
409 {
410 return new MuleEndpointURI(DEFAULT_OUT_TOPIC);
411 }
412 }
413 catch (MalformedEndpointException e)
414 {
415 fail(e.getMessage());
416 return null;
417 }
418 }
419
420 protected UMOEndpointURI getDLDest()
421 {
422 try
423 {
424 if (cnn instanceof QueueConnection)
425 {
426 return new MuleEndpointURI(DEFAULT_DL_QUEUE);
427 }
428 else
429 {
430 return new MuleEndpointURI(DEFAULT_DL_TOPIC);
431 }
432 }
433 catch (MalformedEndpointException e)
434 {
435 fail(e.getMessage());
436 return null;
437 }
438 }
439
440 protected void send(String payload, boolean transacted, int ack) throws JMSException
441 {
442 if (cnn instanceof QueueConnection)
443 {
444 JmsTestUtils.queueSend((QueueConnection)cnn, getInDest().getAddress(), payload, transacted, ack,
445 null);
446 }
447 else
448 {
449 JmsTestUtils.topicPublish((TopicConnection)cnn, getInDest().getAddress(), payload, transacted,
450 ack);
451 }
452 }
453
454 protected int getAcknowledgementMode()
455 {
456 return Session.AUTO_ACKNOWLEDGE;
457 }
458
459 protected void addResultListener(String dest, final CountDownLatch countDown) throws JMSException
460 {
461 MessageConsumer mc;
462
463 if (useTopics())
464 {
465 mc = JmsTestUtils.getTopicSubscriber((TopicConnection)cnn, dest);
466 }
467 else
468 {
469 mc = JmsTestUtils.getQueueReceiver((QueueConnection)cnn, dest);
470 }
471 mc.setMessageListener(new MessageListener()
472 {
473 public void onMessage(Message message)
474 {
475 currentMsg = message;
476 if (countDown != null)
477 {
478 countDown.countDown();
479 }
480 }
481 });
482 }
483
484 public abstract UMOTransactionFactory getTransactionFactory();
485
486 public class RollbackExceptionListener extends DefaultExceptionStrategy
487 {
488 private CountDownLatch countDown;
489
490 public RollbackExceptionListener(CountDownLatch countDown)
491 {
492 this.countDown = countDown;
493 }
494
495 public RollbackExceptionListener(CountDownLatch countDown, UMOEndpointURI deadLetter)
496 throws UMOException
497 {
498 this.countDown = countDown;
499 UMOEndpoint ep = MuleEndpoint.createEndpointFromUri(deadLetter, UMOEndpoint.ENDPOINT_TYPE_SENDER);
500
501 ep.setTransactionConfig(new MuleTransactionConfig());
502 ep.getTransactionConfig().setAction(UMOTransactionConfig.ACTION_JOIN_IF_POSSIBLE);
503 super.addEndpoint(ep);
504 }
505
506 public void handleMessagingException(UMOMessage message, Throwable t)
507 {
508 logger.debug("@@@@ ExceptionHandler Called @@@@");
509 if (t instanceof MessageRedeliveredException)
510 {
511 countDown.countDown();
512 try
513 {
514
515
516 Message msg = (Message)message.getPayload();
517
518 assertNotNull(msg);
519 assertTrue(msg.getJMSRedelivered());
520 assertTrue(msg instanceof TextMessage);
521
522
523 super.handleMessagingException(message, t);
524 }
525 catch (Exception e)
526 {
527 fail(e.getMessage());
528 }
529 }
530 else
531 {
532 logger.error(ExceptionUtils.getFullStackTrace(t));
533 fail(t.getMessage());
534 }
535 super.handleMessagingException(message, t);
536 }
537
538 public void handleException(Throwable t)
539 {
540
541 }
542 }
543
544 public void testTransactedRedeliveryToDLDestination() throws Exception
545 {
546 if (notExcluded(TRANSACTED_REDELIVERY_TO_DL_DESTINATION))
547 {
548
549
550 final int countDownInitialCount = 4;
551 final CountDownLatch countDown = new CountDownLatch(countDownInitialCount);
552
553
554 UMODescriptor descriptor = getDescriptor("testComponent", FunctionalTestComponent.class.getName());
555
556 EventCallback callback = new EventCallback()
557 {
558 public synchronized void eventReceived(UMOEventContext context, Object component) throws Exception
559 {
560 callbackCalled = true;
561 currentTx = context.getCurrentTransaction();
562 assertNotNull(currentTx);
563 assertTrue(currentTx.isBegun());
564 logger.debug("@@@@ Rolling back transaction @@@@");
565 currentTx.setRollbackOnly();
566 countDown.countDown();
567 }
568 };
569
570 initialiseComponent(descriptor, UMOTransactionConfig.ACTION_ALWAYS_BEGIN, callback);
571 UMOManager manager = MuleManager.getInstance();
572 addResultListener(getDLDest().getAddress(), countDown);
573
574 JmsConnector umoCnn = (JmsConnector)manager.lookupConnector(CONNECTOR_NAME);
575
576
577 umoCnn.setMaxRedelivery(1);
578
579
580 umoCnn.setExceptionListener(new RollbackExceptionListener(countDown, getDLDest()));
581
582
583 manager.start();
584
585
586
587 send(DEFAULT_MESSAGE, false, Session.AUTO_ACKNOWLEDGE);
588
589 afterInitialise();
590 countDown.await(LOCK_WAIT, TimeUnit.MILLISECONDS);
591 assertTrue("Only " + (countDownInitialCount - countDown.getCount()) + " of " + countDownInitialCount
592 + " checkpoints hit", countDown.getCount() == 0);
593
594 assertNotNull(currentMsg);
595 logger.debug(currentMsg);
596 String dest = currentMsg.getStringProperty(MuleProperties.MULE_ENDPOINT_PROPERTY);
597 assertNotNull(dest);
598 assertEquals(getDLDest().getUri().toString(), dest);
599 assertTrue(callbackCalled);
600
601
602 assertNull(receive(getInDest().getAddress(), 2000));
603 }
604 }
605 }