/* * JBoss, Home of Professional Open Source. * Copyright 2008, Red Hat Middleware LLC, and individual contributors * as indicated by the @author tags. See the copyright.txt file in the * distribution for a full listing of individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.jboss.test.jbossmessaging.test; import javax.jms.BytesMessage; import javax.jms.DeliveryMode; import javax.jms.JMSException; import javax.jms.Message; import javax.jms.MessageListener; import javax.jms.QueueConnection; import javax.jms.QueueConnectionFactory; import javax.jms.QueueReceiver; import javax.jms.QueueSender; import javax.jms.QueueSession; import javax.jms.Session; import javax.jms.Topic; import javax.jms.TopicConnection; import javax.jms.TopicConnectionFactory; import javax.jms.TopicPublisher; import javax.jms.TopicSession; import javax.jms.TopicSubscriber; import javax.jms.Queue; import javax.naming.Context; import junit.framework.Test; import org.jboss.logging.Logger; import org.jboss.test.JBossJMSTestCase; import org.jboss.test.util.jms.JMSDestinationsUtil; /** * Rollback tests * * @author <a href="mailto:richard.achmatowicz@jboss.com">Richard Achmatowicz</a> * @author * @version */ public class RollBackUnitTestCase extends JBossJMSTestCase { // Provider specific static String TOPIC_FACTORY = "ConnectionFactory"; static String QUEUE_FACTORY = "ConnectionFactory"; static String TEST_QUEUE = "queue/testQueue"; static String TEST_TOPIC = "topic/testTopic"; static String TEST_DURABLE_TOPIC = "topic/testDurableTopic"; static byte[] PAYLOAD = new byte[10]; static Context context; static QueueConnection queueConnection; static TopicConnection topicConnection; static TopicConnection topicDurableConnection; /** * Constructor the test * * @param name Description of Parameter * @exception Exception Description of Exception */ public RollBackUnitTestCase(String name) throws Exception { super(name); } /** * #Description of the Method * * @param persistence Description of Parameter * @exception Exception Description of Exception */ public void runQueueSendRollBack(final int persistence, final boolean explicit) throws Exception { drainQueue(); final int iterationCount = getIterationCount(); final Logger log = getLog(); Thread sendThread = new Thread() { public void run() { try { QueueSession session = queueConnection.createQueueSession(true, Session.AUTO_ACKNOWLEDGE); Queue queue = (Queue) context.lookup(TEST_QUEUE); QueueSender sender = session.createSender(queue); BytesMessage message = session.createBytesMessage(); message.writeBytes(PAYLOAD); message.setStringProperty("TEST_NAME", "runQueueSendRollback"); message.setIntProperty("TEST_PERSISTENCE", persistence); message.setBooleanProperty("TEST_EXPLICIT", explicit); for (int i = 0; i < iterationCount; i++) { sender.send(message, persistence, 4, 0); } if (explicit) session.rollback(); session.close(); } catch (Exception e) { log.error("error", e); } } }; sendThread.start(); sendThread.join(); assertTrue("Queue should be empty", drainQueue() == 0); } /** * #Description of the Method * * @param persistence Description of Parameter * @exception Exception Description of Exception */ public void runTopicSendRollBack(final int persistence, final boolean explicit) throws Exception { drainQueue(); drainTopic(); final int iterationCount = getIterationCount(); final Logger log = getLog(); Thread sendThread = new Thread() { public void run() { try { TopicSession session = topicConnection.createTopicSession(true, Session.AUTO_ACKNOWLEDGE); Topic topic = (Topic) context.lookup(TEST_TOPIC); TopicPublisher publisher = session.createPublisher(topic); BytesMessage message = session.createBytesMessage(); message.writeBytes(PAYLOAD); message.setStringProperty("TEST_NAME", "runTopicSendRollback"); message.setIntProperty("TEST_PERSISTENCE", persistence); message.setBooleanProperty("TEST_EXPLICIT", explicit); for (int i = 0; i < iterationCount; i++) { publisher.publish(message, persistence, 4, 0); } session.close(); } catch (Exception e) { log.error("error", e); } } }; sendThread.start(); sendThread.join(); assertTrue("Topic should be empty", drainTopic() == 0); } /** * #Description of the Method * * @param persistence Description of Parameter * @exception Exception Description of Exception */ public void runAsynchQueueReceiveRollBack(final int persistence, final boolean explicit) throws Exception { drainQueue(); final int iterationCount = getIterationCount(); final Logger log = getLog(); Thread sendThread = new Thread() { public void run() { try { QueueSession session = queueConnection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE); Queue queue = (Queue) context.lookup(TEST_QUEUE); QueueSender sender = session.createSender(queue); BytesMessage message = session.createBytesMessage(); message.writeBytes(PAYLOAD); message.setStringProperty("TEST_NAME", "runAsynchQueueReceiveRollback"); message.setIntProperty("TEST_PERSISTENCE", persistence); message.setBooleanProperty("TEST_EXPLICIT", explicit); for (int i = 0; i < iterationCount; i++) { sender.send(message, persistence, 4, 0); } session.close(); } catch (Exception e) { log.error("error", e); } } }; QueueSession session = queueConnection.createQueueSession(true, Session.AUTO_ACKNOWLEDGE); Queue queue = (Queue) context.lookup(TEST_QUEUE); QueueReceiver receiver = session.createReceiver(queue); MyMessageListener listener = new MyMessageListener(iterationCount, log); sendThread.start(); receiver.setMessageListener(listener); queueConnection.start(); synchronized (listener) { if (listener.i < iterationCount) listener.wait(); } receiver.setMessageListener(null); if (explicit) session.rollback(); session.close(); queueConnection.stop(); sendThread.join(); assertTrue("Queue should be full", drainQueue() == iterationCount); } /** * #Description of the Method * * @param persistence Description of Parameter * @exception Exception Description of Exception */ public void runAsynchTopicReceiveRollBack(final int persistence, final boolean explicit) throws Exception { drainQueue(); drainTopic(); final int iterationCount = getIterationCount(); final Logger log = getLog(); Thread sendThread = new Thread() { public void run() { try { TopicSession session = topicConnection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); Topic topic = (Topic) context.lookup(TEST_TOPIC); TopicPublisher publisher = session.createPublisher(topic); waitForSynchMessage(); BytesMessage message = session.createBytesMessage(); message.writeBytes(PAYLOAD); message.setStringProperty("TEST_NAME", "runAsynchTopicReceiveRollback"); message.setIntProperty("TEST_PERSISTENCE", persistence); message.setBooleanProperty("TEST_EXPLICIT", explicit); for (int i = 0; i < iterationCount; i++) { publisher.publish(message, persistence, 4, 0); log.debug("Published message " + i); } session.close(); } catch (Exception e) { log.error("error", e); } } }; TopicSession session = topicConnection.createTopicSession(true, Session.AUTO_ACKNOWLEDGE); Topic topic = (Topic) context.lookup(TEST_TOPIC); TopicSubscriber subscriber = session.createSubscriber(topic); MyMessageListener listener = new MyMessageListener(iterationCount, log); queueConnection.start(); sendThread.start(); subscriber.setMessageListener(listener); topicConnection.start(); sendSynchMessage(); getLog().debug("Waiting for all messages"); synchronized (listener) { if (listener.i < iterationCount) listener.wait(); } getLog().debug("Got all messages"); subscriber.setMessageListener(null); if (explicit) session.rollback(); session.close(); sendThread.join(); topicConnection.stop(); queueConnection.stop(); assertTrue("Topic should be empty", drainTopic() == 0); } /** * #Description of the Method * * @param persistence Description of Parameter * @exception Exception Description of Exception */ public void runAsynchDurableTopicReceiveRollBack(final int persistence, final boolean explicit) throws Exception { getLog().debug("====> runAsynchDurableTopicReceiveRollBack persistence=" + persistence + " explicit=" + explicit); drainQueue(); drainDurableTopic(); final int iterationCount = getIterationCount(); final Logger log = getLog(); Thread sendThread = new Thread() { public void run() { try { TopicSession session = topicConnection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); Topic topic = (Topic) context.lookup(TEST_DURABLE_TOPIC); TopicPublisher publisher = session.createPublisher(topic); waitForSynchMessage(); BytesMessage message = session.createBytesMessage(); message.writeBytes(PAYLOAD); message.setStringProperty("TEST_NAME", "runAsynchDurableTopicReceiveRollback"); message.setIntProperty("TEST_PERSISTENCE", persistence); message.setBooleanProperty("TEST_EXPLICIT", explicit); for (int i = 0; i < iterationCount; i++) { publisher.publish(message, persistence, 4, 0); log.debug("Published message " + i); } session.close(); } catch (Exception e) { log.error("error", e); } } }; TopicSession session = topicDurableConnection.createTopicSession(true, Session.AUTO_ACKNOWLEDGE); Topic topic = (Topic) context.lookup(TEST_DURABLE_TOPIC); TopicSubscriber subscriber = session.createDurableSubscriber(topic, "test"); try { MyMessageListener listener = new MyMessageListener(iterationCount, log); queueConnection.start(); sendThread.start(); subscriber.setMessageListener(listener); topicDurableConnection.start(); sendSynchMessage(); getLog().debug("Waiting for all messages"); synchronized (listener) { if (listener.i < iterationCount) listener.wait(); } getLog().debug("Got all messages"); subscriber.setMessageListener(null); subscriber.close(); if (explicit) session.rollback(); session.close(); sendThread.join(); topicDurableConnection.stop(); queueConnection.stop(); assertTrue("Topic should be full", drainDurableTopic() == iterationCount); } finally { removeDurableSubscription(); } } /** * A unit test for JUnit * * @exception Exception Description of Exception */ public void testQueueSendRollBack() throws Exception { getLog().debug("Starting AsynchQueueSendRollBack test"); runQueueSendRollBack(DeliveryMode.NON_PERSISTENT, false); runQueueSendRollBack(DeliveryMode.PERSISTENT, false); runQueueSendRollBack(DeliveryMode.NON_PERSISTENT, true); runQueueSendRollBack(DeliveryMode.PERSISTENT, true); getLog().debug("AsynchQueueSendRollBack passed"); } /** * A unit test for JUnit * * @exception Exception Description of Exception */ public void testAsynchQueueReceiveBack() throws Exception { getLog().debug("Starting AsynchQueueReceiveRollBack test"); runAsynchQueueReceiveRollBack(DeliveryMode.NON_PERSISTENT, false); runAsynchQueueReceiveRollBack(DeliveryMode.PERSISTENT, false); runQueueSendRollBack(DeliveryMode.NON_PERSISTENT, true); runQueueSendRollBack(DeliveryMode.PERSISTENT, true); getLog().debug("AsynchQueueReceiveRollBack passed"); } /** * A unit test for JUnit * * @exception Exception Description of Exception */ public void testTopicSendRollBack() throws Exception { getLog().debug("Starting AsynchTopicSendRollBack test"); runTopicSendRollBack(DeliveryMode.NON_PERSISTENT, false); runTopicSendRollBack(DeliveryMode.PERSISTENT, false); runTopicSendRollBack(DeliveryMode.NON_PERSISTENT, true); runTopicSendRollBack(DeliveryMode.PERSISTENT, true); getLog().debug("AsynchTopicSendRollBack passed"); } /** * A unit test for JUnit * * @exception Exception Description of Exception */ public void testAsynchTopicReceiveRollBack() throws Exception { getLog().debug("Starting AsynchTopicReceiveRollBack test"); runAsynchTopicReceiveRollBack(DeliveryMode.NON_PERSISTENT, false); runAsynchTopicReceiveRollBack(DeliveryMode.PERSISTENT, false); runAsynchTopicReceiveRollBack(DeliveryMode.NON_PERSISTENT, true); runAsynchTopicReceiveRollBack(DeliveryMode.PERSISTENT, true); getLog().debug("AsynchTopicReceiveRollBack passed"); } /** * A unit test for JUnit * * @exception Exception Description of Exception */ public void testAsynchDurableTopicReceiveRollBack() throws Exception { getLog().debug("Starting AsynchDurableTopicReceiveRollBack test"); runAsynchDurableTopicReceiveRollBack(DeliveryMode.NON_PERSISTENT, false); runAsynchDurableTopicReceiveRollBack(DeliveryMode.PERSISTENT, false); runAsynchDurableTopicReceiveRollBack(DeliveryMode.NON_PERSISTENT, true); runAsynchDurableTopicReceiveRollBack(DeliveryMode.PERSISTENT, true); getLog().debug("AsynchDurableTopicReceiveRollBack passed"); } /** * A unit test for JUnit * * @exception Exception Description of Exception */ public void removeDurableSubscription() throws Exception { TopicSession session = topicDurableConnection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); session.unsubscribe("test"); } /** * The JUnit setup method * * @exception Exception Description of Exception */ protected void setUp() throws Exception { super.setUp(); JMSDestinationsUtil.setupBasicDestinations(); getLog().debug("START TEST " + getName()); context = getInitialContext(); QueueConnectionFactory queueFactory = (QueueConnectionFactory) context.lookup(QUEUE_FACTORY); queueConnection = queueFactory.createQueueConnection(); TopicConnectionFactory topicFactory = (TopicConnectionFactory) context.lookup(TOPIC_FACTORY); topicConnection = topicFactory.createTopicConnection(); topicDurableConnection = topicFactory.createTopicConnection("john", "needle"); if (JMSDestinationsUtil.isHornetQ()) { // HornetQ doesn't support clientID associated with the user/password, // hence we need to set it manually topicDurableConnection.setClientID("someClient"); } getLog().debug("Connection to JBossMQ established."); } protected void tearDown() throws Exception { try { if (topicDurableConnection != null) { topicDurableConnection.close(); topicDurableConnection = null; } } catch (JMSException ignored) { } try { if (topicConnection != null) { topicConnection.close(); topicConnection = null; } } catch (JMSException ignored) { } try { if (queueConnection != null) { queueConnection.close(); queueConnection = null; } } catch (JMSException ignored) { } JMSDestinationsUtil.destroyDestinations(); super.tearDown(); } // Emptys out all the messages in a queue private int drainQueue() throws Exception { getLog().debug("Draining Queue"); queueConnection.start(); QueueSession session = queueConnection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE); Queue queue = (Queue) context.lookup(TEST_QUEUE); QueueReceiver receiver = session.createReceiver(queue); Message message = receiver.receive(50); int c = 0; while (message != null) { c++; message = receiver.receive(50); } getLog().debug(" Drained " + c + " messages from the queue"); session.close(); queueConnection.stop(); return c; } // Emptys out all the messages in a topic private int drainTopic() throws Exception { getLog().debug("Draining Topic"); topicConnection.start(); final TopicSession session = topicConnection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); Topic topic = (Topic) context.lookup(TEST_TOPIC); TopicSubscriber subscriber = session.createSubscriber(topic); Message message = subscriber.receive(50); int c = 0; while (message != null) { c++; message = subscriber.receive(50); } getLog().debug(" Drained " + c + " messages from the topic"); session.close(); topicConnection.stop(); return c; } // Emptys out all the messages in a durable topic private int drainDurableTopic() throws Exception { getLog().debug("Draining Durable Topic"); topicDurableConnection.start(); final TopicSession session = topicDurableConnection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); Topic topic = (Topic) context.lookup(TEST_DURABLE_TOPIC); TopicSubscriber subscriber = session.createDurableSubscriber(topic, "test"); Message message = subscriber.receive(50); int c = 0; while (message != null) { c++; message = subscriber.receive(50); } getLog().debug(" Drained " + c + " messages from the durable topic"); session.close(); topicDurableConnection.stop(); return c; } private void waitForSynchMessage() throws Exception { getLog().debug("Waiting for Synch Message"); QueueSession session = queueConnection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE); Queue queue = (Queue) context.lookup(TEST_QUEUE); QueueReceiver receiver = session.createReceiver(queue); receiver.receive(); session.close(); getLog().debug("Got Synch Message"); } private void sendSynchMessage() throws Exception { getLog().debug("Sending Synch Message"); QueueSession session = queueConnection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE); Queue queue = (Queue) context.lookup(TEST_QUEUE); QueueSender sender = session.createSender(queue); Message message = session.createMessage(); sender.send(message); session.close(); getLog().debug("Sent Synch Message"); } public class MyMessageListener implements MessageListener { public int i = 0; public int iterationCount; public Logger log; public MyMessageListener(int iterationCount, Logger log) { this.iterationCount = iterationCount; this.log = log; } public void onMessage(Message message) { synchronized (this) { i++; log.debug("Got message " + i); if (i >= iterationCount) this.notify(); } } } public int getIterationCount() { return 5; } }