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