1
2
3
4
5
6
7
8
9
10
11 package org.mule.transport.jms.integration;
12
13 import org.mule.api.MuleMessage;
14 import org.mule.api.config.ConfigurationBuilder;
15 import org.mule.api.transaction.Transaction;
16 import org.mule.config.spring.SpringXmlConfigurationBuilder;
17 import org.mule.module.client.MuleClient;
18 import org.mule.tck.FunctionalTestCase;
19 import org.mule.transaction.TransactionCoordination;
20 import org.mule.util.ClassUtils;
21 import org.mule.util.CollectionUtils;
22 import org.mule.util.IOUtils;
23 import org.mule.util.StringUtils;
24
25 import java.net.URL;
26 import java.util.Arrays;
27 import java.util.Collection;
28 import java.util.Iterator;
29 import java.util.List;
30 import java.util.Map;
31 import java.util.Properties;
32
33 import javax.jms.Connection;
34 import javax.jms.DeliveryMode;
35 import javax.jms.Destination;
36 import javax.jms.JMSException;
37 import javax.jms.Message;
38 import javax.jms.MessageConsumer;
39 import javax.jms.MessageProducer;
40 import javax.jms.Session;
41 import javax.jms.TextMessage;
42 import javax.jms.Topic;
43 import javax.jms.TopicConnection;
44 import javax.jms.TopicPublisher;
45 import javax.transaction.HeuristicMixedException;
46 import javax.transaction.HeuristicRollbackException;
47 import javax.transaction.RollbackException;
48 import javax.transaction.SystemException;
49
50 import org.apache.commons.logging.Log;
51 import org.apache.commons.logging.LogFactory;
52 import org.junit.After;
53 import org.junit.Before;
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98 public abstract class AbstractJmsFunctionalTestCase extends FunctionalTestCase
99 {
100
101 public static final String DEFAULT_INPUT_MESSAGE = "INPUT MESSAGE";
102 public static final String DEFAULT_OUTPUT_MESSAGE = "OUTPUT MESSAGE";
103
104 public static final String INBOUND_ENDPOINT_KEY = "inbound.destination";
105 public static final String OUTBOUND_ENDPOINT_KEY = "outbound.destination";
106
107 public static final String MIDDLE_ENDPOINT_KEY = "middle.destination";
108 public static final String MIDDLE2_ENDPOINT_KEY = "middle2.destination";
109 public static final String MIDDLE3_ENDPOINT_KEY = "middle3.destination";
110 public static final String BROADCAST_TOPIC_ENDPOINT_KEY = "broadcast.topic.destination";
111
112 protected static final Log logger = LogFactory.getLog("MULE_TESTS");
113
114 protected JmsVendorConfiguration jmsConfig = null;
115 protected Scenario scenarioNoTx;
116
117 protected Scenario scenarioCommit;
118 protected Scenario scenarioRollback;
119 protected Scenario scenarioNotReceive;
120 protected Scenario scenarioReceive;
121
122 private MuleClient client = null;
123
124
125
126
127 private boolean multipleProviders = true;
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143 public static Collection jmsProviderConfigs()
144 {
145 JmsVendorConfiguration[][] configs;
146 URL url = ClassUtils.getResource("jms-vendor-configs.txt", AbstractJmsFunctionalTestCase.class);
147
148 if (url == null)
149 {
150 fail("Please specify the org.mule.transport.jms.integration.JmsVendorConfiguration " +
151 "implementation to use in jms-vendor-configs.txt on classpaath.");
152 return CollectionUtils.EMPTY_COLLECTION;
153 }
154
155 if (logger.isInfoEnabled())
156 {
157 logger.info("Parameterized test using: " + url);
158 }
159
160 try
161 {
162 List classes = IOUtils.readLines(url.openStream());
163 configs = new JmsVendorConfiguration[1][classes.size()];
164 int i = 0;
165 for (Iterator iterator = classes.iterator(); iterator.hasNext(); i++)
166 {
167 String cls = (String) iterator.next();
168 configs[0][i] = (JmsVendorConfiguration) ClassUtils.instanciateClass(cls, ClassUtils.NO_ARGS);
169 }
170 return Arrays.asList(configs);
171 }
172 catch (Exception e)
173 {
174 fail("Please specify the org.mule.transport.jms.integration.JmsVendorConfiguration " +
175 "implementation to use in jms-vendor-configs.txt on classpath: " + e.getMessage());
176 return CollectionUtils.EMPTY_COLLECTION;
177 }
178 }
179
180
181
182
183
184
185
186 @Before
187 public void before() throws Exception
188 {
189 super.setUp();
190 }
191
192
193
194
195
196
197
198 @After
199 public void after() throws Exception
200 {
201 super.tearDown();
202 }
203
204 public AbstractJmsFunctionalTestCase()
205 {
206
207 this(((JmsVendorConfiguration[]) jmsProviderConfigs().iterator().next())[0]);
208 }
209
210 public AbstractJmsFunctionalTestCase(JmsVendorConfiguration config)
211 {
212 setJmsConfig(config);
213 scenarioNoTx = new NonTransactedScenario();
214 scenarioCommit = new ScenarioCommit();
215 scenarioRollback = new ScenarioRollback();
216 scenarioNotReceive = new ScenarioNotReceive();
217 scenarioReceive = new ScenarioReceive();
218 }
219
220 @Override
221 protected void suitePreSetUp() throws Exception
222 {
223 super.suitePreSetUp();
224
225 purge(getInboundQueueName());
226 purge(getOutboundQueueName());
227
228 }
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245 @Override
246 protected Properties getStartUpProperties()
247 {
248 Properties props = new Properties();
249
250 props.put(INBOUND_ENDPOINT_KEY, getJmsConfig().getInboundEndpoint());
251 props.put(OUTBOUND_ENDPOINT_KEY, getJmsConfig().getOutboundEndpoint());
252 props.put(MIDDLE_ENDPOINT_KEY, getJmsConfig().getMiddleEndpoint());
253 props.put(MIDDLE2_ENDPOINT_KEY, getJmsConfig().getMiddleEndpoint() + "2");
254 props.put(MIDDLE3_ENDPOINT_KEY, getJmsConfig().getMiddleEndpoint() + "3");
255
256 props.put(BROADCAST_TOPIC_ENDPOINT_KEY, getJmsConfig().getTopicBroadcastEndpoint());
257 props.put("protocol", getJmsConfig().getProtocol());
258
259 Map p = getJmsConfig().getProperties();
260 if (p != null)
261 {
262 props.putAll(p);
263 }
264 return props;
265 }
266
267
268
269
270
271
272
273
274
275 @Override
276 protected ConfigurationBuilder getBuilder() throws Exception
277 {
278 if (multipleProviders)
279 {
280 final String configResource = getConfigResources();
281
282 if (StringUtils.splitAndTrim(configResource, ",; ").length > 1)
283 {
284 throw new IllegalArgumentException("Parameterized tests don't support multiple " +
285 "config files as input: " + configResource);
286 }
287 String resources = configResource.substring(configResource.lastIndexOf("/") + 1);
288 resources = String.format("integration/%s/connector-%s,%s", getJmsConfig().getName(),
289 resources, getConfigResources());
290 SpringXmlConfigurationBuilder builder = new SpringXmlConfigurationBuilder(resources);
291 return builder;
292 }
293 else
294 {
295 return super.getBuilder();
296 }
297 }
298
299
300
301
302
303
304
305 public final JmsVendorConfiguration getJmsConfig()
306 {
307 if (jmsConfig == null)
308 {
309 jmsConfig = createJmsConfig();
310 }
311 return jmsConfig;
312 }
313
314
315
316
317
318
319
320 public final void setJmsConfig(JmsVendorConfiguration jmsConfig)
321 {
322 this.jmsConfig = jmsConfig;
323 }
324
325
326
327
328
329
330
331 protected JmsVendorConfiguration createJmsConfig()
332 {
333
334 return null;
335 }
336
337
338
339
340
341
342
343
344
345
346 protected final Connection getConnection(boolean topic, boolean xa) throws Exception
347 {
348 checkConfig();
349 return getJmsConfig().getConnection(topic, xa);
350 }
351
352
353
354
355
356
357
358
359
360 protected final String getInboundEndpoint()
361 {
362 checkConfig();
363 return getJmsConfig().getInboundEndpoint();
364 }
365
366
367
368
369
370
371
372
373
374 protected final String getOutboundEndpoint()
375 {
376 checkConfig();
377 return getJmsConfig().getOutboundEndpoint();
378 }
379
380
381
382
383
384
385
386
387
388 protected final String getInboundQueueName()
389 {
390 checkConfig();
391 return getJmsConfig().getInboundDestinationName();
392 }
393
394
395
396
397
398
399
400
401
402 protected final String getDeadLetterQueueName()
403 {
404 checkConfig();
405 return getJmsConfig().getDeadLetterDestinationName();
406 }
407
408
409
410
411
412
413
414
415
416 protected final String getOutboundQueueName()
417 {
418 checkConfig();
419 return getJmsConfig().getOutboundDestinationName();
420 }
421
422
423
424
425
426
427
428
429
430 protected final long getSmallTimeout()
431 {
432 checkConfig();
433 return getJmsConfig().getSmallTimeout();
434
435 }
436
437
438
439
440
441
442
443
444
445 protected final long getTimeout()
446 {
447 checkConfig();
448 return getJmsConfig().getTimeout();
449 }
450
451
452
453
454
455 protected void checkConfig()
456 {
457 if (getJmsConfig() == null)
458 {
459 throw new IllegalStateException("There must be a Jms Vendor config set on this test");
460 }
461 }
462
463 protected void dispatchMessage() throws Exception
464 {
465 dispatchMessage(DEFAULT_INPUT_MESSAGE);
466 }
467
468 protected void dispatchMessage(Object payload) throws Exception
469 {
470 dispatchMessage(payload, null);
471 }
472
473 protected void dispatchMessage(Object payload, Properties props) throws Exception
474 {
475 client.dispatch(getInboundEndpoint(), payload, props);
476 }
477
478 protected MuleMessage receiveMessage() throws Exception
479 {
480 return receiveMessage(DEFAULT_OUTPUT_MESSAGE);
481 }
482
483 protected MuleMessage receiveMessage(Object expected) throws Exception
484 {
485 MuleMessage result = client.request(getOutboundEndpoint(), getTimeout());
486 assertNotNull(result);
487 assertNotNull(result.getPayload());
488 assertNull(result.getExceptionPayload());
489 assertEquals(expected, result.getPayload());
490 return result;
491 }
492
493 protected MuleMessage receiveMessage(byte[] expected) throws Exception
494 {
495 MuleMessage result = client.request(getOutboundEndpoint(), getTimeout());
496 assertNotNull(result);
497 assertNotNull(result.getPayload());
498 assertNull(result.getExceptionPayload());
499 byte[] bytes = result.getPayloadAsBytes();
500 assertEquals("Wrong number of bytes", expected.length, bytes.length);
501 for (int i=0; i < expected.length; ++i)
502 {
503 assertEquals("Byte #" + i + " does not match", expected[i], bytes[i]);
504 }
505 return result;
506 }
507
508 public void runAsynchronousDispatching() throws Exception
509 {
510 dispatchMessage();
511 receiveMessage();
512 MuleMessage result = client.request(getOutboundEndpoint(), getSmallTimeout());
513 assertNull(result);
514 }
515
516 protected void doSetUp() throws Exception
517 {
518 super.doSetUp();
519 client = new MuleClient(muleContext);
520 Transaction tx = TransactionCoordination.getInstance().getTransaction();
521 if (tx != null)
522 {
523 TransactionCoordination.getInstance().unbindTransaction(tx);
524 logger.warn("Transaction was active when this test began");
525 }
526 }
527
528 protected void doTearDown() throws Exception
529 {
530 purge(getInboundQueueName());
531 purge(getOutboundQueueName());
532 purgeTopics();
533
534 super.doTearDown();
535 if (client != null)
536 {
537 client.dispose();
538 }
539 Transaction tx = TransactionCoordination.getInstance().getTransaction();
540 if (tx != null)
541 {
542 TransactionCoordination.getInstance().unbindTransaction(tx);
543 logger.warn("Transaction was active when this test ended");
544 }
545 }
546
547 protected MuleClient getClient()
548 {
549 return client;
550 }
551
552 public void send(Scenario scenario) throws Exception
553 {
554 Connection connection = null;
555 try
556 {
557 connection = getConnection(false, false);
558 connection.start();
559 Session session = null;
560 try
561 {
562 session = connection.createSession(scenario.isTransacted(), scenario.getAcknowledge());
563 Destination destination = createInputDestination(session, scenario);
564 MessageProducer producer = null;
565 try
566 {
567 producer = session.createProducer(destination);
568 if (scenario.isPersistent())
569 {
570 producer.setDeliveryMode(DeliveryMode.PERSISTENT);
571 }
572 scenario.send(session, producer);
573 }
574 finally
575 {
576 if (producer != null)
577 {
578 producer.close();
579 }
580 }
581 }
582 finally
583 {
584 if (session != null)
585 {
586 session.close();
587 }
588 }
589 }
590 finally
591 {
592 if (connection != null)
593 {
594 connection.close();
595 }
596 }
597 }
598
599
600
601
602
603
604
605
606
607 protected Destination createInputDestination(Session session, Scenario scenario) throws JMSException
608 {
609 return session.createQueue(scenario.getInputDestinationName());
610 }
611
612
613
614
615
616
617
618
619
620 protected Destination createOutputDestination(Session session, Scenario scenario) throws JMSException
621 {
622 return session.createQueue(scenario.getOutputDestinationName());
623 }
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680 protected void purge(final String destination) throws JMSException
681 {
682 Connection c = null;
683 Session s = null;
684 try
685 {
686 logger.debug("purging queue : " + destination);
687 c = getConnection(false, false);
688 assertNotNull(c);
689 c.start();
690
691 s = c.createSession(false, Session.AUTO_ACKNOWLEDGE);
692 Destination d = s.createQueue(destination);
693 MessageConsumer consumer = s.createConsumer(d);
694
695 while (consumer.receiveNoWait() != null)
696 {
697 logger.debug("Destination " + destination + " isn't empty, draining it");
698 }
699 }
700 catch (Exception e)
701 {
702 logger.error("unable to purge : " + destination);
703 }
704 finally
705 {
706 if (c != null)
707 {
708 c.stop();
709 if (s != null)
710 {
711 s.close();
712 }
713 c.close();
714 }
715 }
716 }
717
718
719
720
721
722
723 protected void purgeTopics() throws Exception
724 {
725 String destination = "broadcast";
726 purgeTopic(destination, "Client1");
727 purgeTopic(destination, "Client2");
728 purgeTopic(destination, "mule.JmsConnectorC1.broadcast");
729 purgeTopic(destination, "mule.JmsConnectorC2.broadcast");
730 }
731
732
733
734
735
736
737
738
739 protected void purgeTopic(String destination, String topic) throws Exception
740 {
741 Connection c = null;
742 Session s = null;
743
744 try
745 {
746 logger.debug("purging topic : " + topic);
747 c = (TopicConnection) getConnection(true, false);
748 if (c == null)
749 {
750 logger.debug("could not create a connection to topic : " + destination);
751 }
752
753 c.start();
754 s = ((TopicConnection) c).createTopicSession(true, Session.SESSION_TRANSACTED);
755
756 logger.debug("created topic session");
757 Topic dest = s.createTopic(destination);
758 logger.debug("created topic destination");
759
760 TopicPublisher t;
761
762 if (client != null)
763 {
764 client.dispose();
765 }
766
767 MessageConsumer consumer = null;
768
769 try
770 {
771 consumer = s.createDurableSubscriber((Topic) dest, topic);
772 logger.debug("created consumer");
773 while (consumer.receiveNoWait() != null)
774 {
775 logger.debug("Topic " + topic + " isn't empty, draining it");
776 }
777 logger.debug("topic should be empty");
778 consumer.close();
779 s.unsubscribe(topic);
780 }
781 catch (JMSException e)
782 {
783 logger.debug("could not unsubscribe : " + topic);
784 }
785 }
786
787 finally
788 {
789 if (c != null)
790 {
791 c.stop();
792 if (s != null)
793 {
794 s.close();
795 }
796 c.close();
797 }
798 }
799 logger.debug("completed draining topic :" + topic);
800 }
801
802 public boolean isMultipleProviders()
803 {
804 return multipleProviders;
805 }
806
807 public void setMultipleProviders(boolean multipleProviders)
808 {
809 this.multipleProviders = multipleProviders;
810 }
811
812
813
814
815
816 protected interface Scenario
817 {
818
819 boolean isPersistent();
820
821 void setPersistent(boolean persistent);
822
823 String getInputDestinationName();
824
825 void setInputDestinationName(String inputQueue);
826
827 String getOutputDestinationName();
828
829 void setOutputDestinationName(String outputQueue);
830
831 int getAcknowledge();
832
833 void send(Session session, MessageProducer producer)
834 throws JMSException, SystemException, HeuristicMixedException, HeuristicRollbackException,
835 RollbackException;
836
837 Message receive(Session session, MessageConsumer consumer)
838 throws JMSException, SystemException, HeuristicMixedException, HeuristicRollbackException,
839 RollbackException;
840
841 boolean isTransacted();
842 }
843
844 protected abstract class AbstractScenario implements Scenario
845 {
846
847 private String inputQueue = getInboundQueueName();
848 private String outputQueue = getOutboundQueueName();
849 private boolean persistent = false;
850
851 public boolean isPersistent()
852 {
853 return persistent;
854 }
855
856 public void setPersistent(boolean persistent)
857 {
858 this.persistent = persistent;
859 }
860
861 public String getInputDestinationName()
862 {
863 return inputQueue;
864 }
865
866 public String getOutputDestinationName()
867 {
868 return outputQueue;
869 }
870
871 public void setInputDestinationName(String inputQueue)
872 {
873 this.inputQueue = inputQueue;
874 }
875
876 public void setOutputDestinationName(String outputQueue)
877 {
878 this.outputQueue = outputQueue;
879 }
880
881 public int getAcknowledge()
882 {
883 return Session.AUTO_ACKNOWLEDGE;
884 }
885
886 public void send(Session session, MessageProducer producer) throws JMSException
887 {
888 producer.send(session.createTextMessage(DEFAULT_INPUT_MESSAGE));
889 applyTransaction(session);
890 }
891
892 public Message receive(Session session, MessageConsumer consumer) throws JMSException
893 {
894 Message message = consumer.receive(getTimeout());
895 assertNotNull(message);
896 assertTrue(TextMessage.class.isAssignableFrom(message.getClass()));
897 assertEquals(DEFAULT_OUTPUT_MESSAGE, ((TextMessage) message).getText());
898 applyTransaction(session);
899 return message;
900 }
901
902 abstract protected void applyTransaction(Session session) throws JMSException;
903 }
904
905 protected class NonTransactedScenario extends AbstractScenario
906 {
907
908 public boolean isTransacted()
909 {
910 return false;
911 }
912
913 protected void applyTransaction(Session session) throws JMSException
914 {
915
916 }
917 }
918
919 protected class ScenarioCommit extends AbstractScenario
920 {
921
922 public boolean isTransacted()
923 {
924 return true;
925 }
926
927 protected void applyTransaction(Session session) throws JMSException
928 {
929 session.commit();
930 }
931 }
932
933 protected class ScenarioRollback extends AbstractScenario
934 {
935
936 public boolean isTransacted()
937 {
938 return true;
939 }
940
941 protected void applyTransaction(Session session) throws JMSException
942 {
943 session.rollback();
944 }
945 }
946
947 protected class ScenarioNotReceive extends NonTransactedScenario
948 {
949
950 @Override
951 public Message receive(Session session, MessageConsumer consumer) throws JMSException
952 {
953 Message message = consumer.receive(getSmallTimeout());
954 assertNull(message);
955 return message;
956 }
957 }
958
959 protected class ScenarioReceive extends NonTransactedScenario
960 {
961
962 @Override
963 public Message receive(Session session, MessageConsumer consumer) throws JMSException
964 {
965 Message message = consumer.receive(getTimeout());
966 assertNotNull(message);
967 return message;
968 }
969 }
970 }