/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.activemq.artemis.jms.tests; import javax.jms.Connection; import javax.jms.DeliveryMode; import javax.jms.IllegalStateException; import javax.jms.InvalidDestinationException; import javax.jms.InvalidSelectorException; import javax.jms.Message; import javax.jms.MessageConsumer; import javax.jms.MessageProducer; import javax.jms.Session; import javax.jms.TextMessage; import javax.jms.Topic; import javax.jms.TopicSubscriber; import javax.naming.InitialContext; import java.util.List; import org.apache.activemq.artemis.jms.tests.util.ProxyAssertSupport; import org.junit.Test; /** * Tests focused on durable subscription behavior. More durable subscription tests can be found in * MessageConsumerTest. */ public class DurableSubscriptionTest extends JMSTestCase { // Constants ----------------------------------------------------- // Static -------------------------------------------------------- // Attributes ---------------------------------------------------- // Constructors -------------------------------------------------- // Public -------------------------------------------------------- @Test public void testSimplestDurableSubscription() throws Exception { Connection conn = null; try { conn = createConnection(); conn.setClientID("brookeburke"); Session s = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); MessageProducer prod = s.createProducer(ActiveMQServerTestCase.topic1); prod.setDeliveryMode(DeliveryMode.PERSISTENT); s.createDurableSubscriber(ActiveMQServerTestCase.topic1, "monicabelucci"); List<String> subs = listAllSubscribersForTopic("Topic1"); ProxyAssertSupport.assertNotNull(subs); ProxyAssertSupport.assertEquals(1, subs.size()); ProxyAssertSupport.assertEquals("monicabelucci", subs.get(0)); prod.send(s.createTextMessage("k")); conn.close(); subs = listAllSubscribersForTopic("Topic1"); ProxyAssertSupport.assertEquals(1, subs.size()); ProxyAssertSupport.assertEquals("monicabelucci", subs.get(0)); conn = createConnection(); conn.setClientID("brookeburke"); s = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); MessageConsumer durable = s.createDurableSubscriber(ActiveMQServerTestCase.topic1, "monicabelucci"); conn.start(); TextMessage tm = (TextMessage) durable.receive(1000); ProxyAssertSupport.assertEquals("k", tm.getText()); Message m = durable.receive(1000); ProxyAssertSupport.assertNull(m); durable.close(); s.unsubscribe("monicabelucci"); } finally { if (conn != null) { conn.close(); } } } // https://issues.apache.org/jira/browse/ARTEMIS-177 @Test public void testDurableSubscriptionRemovalRaceCondition() throws Exception { final String topicName = "myTopic"; final String clientID = "myClientID"; final String subscriptionName = "mySub"; createTopic(topicName); InitialContext ic = getInitialContext(); Topic myTopic = (Topic) ic.lookup("/topic/" + topicName); Connection conn = null; for (int i = 0; i < 1000; i++) { try { conn = createConnection(); conn.setClientID(clientID); Session s = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); MessageProducer prod = s.createProducer(myTopic); prod.setDeliveryMode(DeliveryMode.PERSISTENT); s.createDurableSubscriber(myTopic, subscriptionName); prod.send(s.createTextMessage("k")); conn.close(); destroyTopic(topicName); createTopic(topicName); conn = createConnection(); conn.setClientID(clientID); s = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); MessageConsumer durable = s.createDurableSubscriber(myTopic, subscriptionName); conn.start(); TextMessage tm = (TextMessage) durable.receiveNoWait(); ProxyAssertSupport.assertNull(tm); durable.close(); s.unsubscribe(subscriptionName); } finally { if (conn != null) { conn.close(); } } } } /** * JMS 1.1 6.11.1: A client can change an existing durable subscription by creating a durable * TopicSubscriber with the same name and a new topic and/or message selector, or NoLocal * attribute. Changing a durable subscription is equivalent to deleting and recreating it. * <br> * Test with a different topic (a redeployed topic is a different topic). */ @Test public void testDurableSubscriptionOnNewTopic() throws Exception { Connection conn = null; try { conn = createConnection(); conn.setClientID("brookeburke"); Session s = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); MessageProducer prod = s.createProducer(ActiveMQServerTestCase.topic1); prod.setDeliveryMode(DeliveryMode.PERSISTENT); s.createDurableSubscriber(ActiveMQServerTestCase.topic1, "monicabelucci"); prod.send(s.createTextMessage("one")); conn.close(); conn = createConnection(); conn.setClientID("brookeburke"); s = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); MessageConsumer durable = s.createDurableSubscriber(ActiveMQServerTestCase.topic2, "monicabelucci"); conn.start(); Message m = durable.receive(1000); ProxyAssertSupport.assertNull(m); durable.close(); s.unsubscribe("monicabelucci"); } finally { if (conn != null) { conn.close(); } } } /** * JMS 1.1 6.11.1: A client can change an existing durable subscription by creating a durable * TopicSubscriber with the same name and a new topic and/or message selector, or NoLocal * attribute. Changing a durable subscription is equivalent to deleting and recreating it. * <br> * Test with a different selector. */ @Test public void testDurableSubscriptionDifferentSelector() throws Exception { Connection conn = null; try { conn = createConnection(); conn.setClientID("brookeburke"); Session s = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); MessageProducer prod = s.createProducer(ActiveMQServerTestCase.topic1); prod.setDeliveryMode(DeliveryMode.PERSISTENT); MessageConsumer durable = s.createDurableSubscriber(ActiveMQServerTestCase.topic1, "monicabelucci", "color = 'red' AND shape = 'square'", false); TextMessage tm = s.createTextMessage("A red square message"); tm.setStringProperty("color", "red"); tm.setStringProperty("shape", "square"); prod.send(tm); conn.start(); TextMessage rm = (TextMessage) durable.receive(5000); ProxyAssertSupport.assertEquals("A red square message", rm.getText()); tm = s.createTextMessage("Another red square message"); tm.setStringProperty("color", "red"); tm.setStringProperty("shape", "square"); prod.send(tm); // TODO: when subscriptions/durable subscription will be registered as MBean, use the JMX // interface to make sure the 'another red square message' is maintained by the // durable subascription // http://jira.jboss.org/jira/browse/JBMESSAGING-217 conn.close(); conn = createConnection(); conn.setClientID("brookeburke"); s = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); // modify the selector durable = s.createDurableSubscriber(ActiveMQServerTestCase.topic1, "monicabelucci", "color = 'red'", false); conn.start(); Message m = durable.receive(1000); // the durable subscription is destroyed and re-created. The red square message stored by // the previous durable subscription is lost and (hopefully) garbage collected. ProxyAssertSupport.assertNull(m); durable.close(); s.unsubscribe("monicabelucci"); } finally { if (conn != null) { conn.close(); } } } @Test public void testDurableSubscriptionOnTemporaryTopic() throws Exception { Connection conn = null; conn = createConnection(); try { conn.setClientID("doesn't actually matter"); Session s = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); Topic temporaryTopic = s.createTemporaryTopic(); try { s.createDurableSubscriber(temporaryTopic, "mySubscription"); ProxyAssertSupport.fail("this should throw exception"); } catch (InvalidDestinationException e) { // OK } } finally { if (conn != null) { conn.close(); } } } @Test public void testUnsubscribeDurableSubscription() throws Exception { Connection conn = null; try { conn = createConnection(); conn.setClientID("ak47"); Session s = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); MessageConsumer cons = s.createDurableSubscriber(ActiveMQServerTestCase.topic1, "uzzi"); MessageProducer prod = s.createProducer(ActiveMQServerTestCase.topic1); prod.setDeliveryMode(DeliveryMode.PERSISTENT); prod.send(s.createTextMessage("one")); cons.close(); s.unsubscribe("uzzi"); MessageConsumer ds = s.createDurableSubscriber(ActiveMQServerTestCase.topic1, "uzzi"); conn.start(); ProxyAssertSupport.assertNull(ds.receive(1000)); ds.close(); s.unsubscribe("uzzi"); } finally { if (conn != null) { conn.close(); } } } @Test public void testInvalidSelectorException() throws Exception { Connection c = createConnection(); c.setClientID("sofiavergara"); Session s = c.createSession(false, Session.AUTO_ACKNOWLEDGE); try { s.createDurableSubscriber(ActiveMQServerTestCase.topic1, "mysubscribption", "=TEST 'test'", true); ProxyAssertSupport.fail("this should fail"); } catch (InvalidSelectorException e) { // OK } } // See JMS 1.1. spec sec 6.11 @Test public void testUnsubscribeWithActiveConsumer() throws Exception { Connection conn = createConnection(); conn.setClientID("zeke"); Session s = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); TopicSubscriber dursub = s.createDurableSubscriber(ActiveMQServerTestCase.topic1, "dursub0"); try { s.unsubscribe("dursub0"); ProxyAssertSupport.fail(); } catch (IllegalStateException e) { // Ok - it is illegal to ubscribe a subscription if it has active consumers } dursub.close(); s.unsubscribe("dursub0"); } @Test public void testSubscribeWithActiveSubscription() throws Exception { Connection conn = createConnection(); conn.setClientID("zeke"); Session s = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); TopicSubscriber dursub1 = s.createDurableSubscriber(ActiveMQServerTestCase.topic1, "dursub1"); try { s.createDurableSubscriber(ActiveMQServerTestCase.topic1, "dursub1"); ProxyAssertSupport.fail(); } catch (IllegalStateException e) { // Ok - it is illegal to have more than one active subscriber on a subscrtiption at any one time } dursub1.close(); s.unsubscribe("dursub1"); } @Test public void testDurableSubscriptionWithPeriodsInName() throws Exception { Connection conn = createConnection(); conn.setClientID(".client.id.with.periods."); Session s = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); TopicSubscriber subscriber = s.createDurableSubscriber(ActiveMQServerTestCase.topic1, ".subscription.name.with.periods."); s.createProducer(ActiveMQServerTestCase.topic1).send(s.createTextMessage("Subscription test")); conn.start(); Message m = subscriber.receive(1000L); ProxyAssertSupport.assertNotNull(m); ProxyAssertSupport.assertTrue(m instanceof TextMessage); subscriber.close(); s.unsubscribe(".subscription.name.with.periods."); } @Test public void testNoLocal() throws Exception { internalTestNoLocal(true); internalTestNoLocal(false); } private void internalTestNoLocal(final boolean noLocal) throws Exception { Connection conn1 = createConnection(); conn1.setClientID(".client.id.with.periods."); Connection conn2 = createConnection(); conn2.setClientID(".client.id.with.periods2."); Session s1 = conn1.createSession(false, Session.AUTO_ACKNOWLEDGE); Session s2 = conn2.createSession(false, Session.AUTO_ACKNOWLEDGE); TopicSubscriber subscriber1 = s1.createDurableSubscriber(ActiveMQServerTestCase.topic1, ".subscription.name.with.periods.", null, noLocal); TopicSubscriber subscriber2 = s2.createDurableSubscriber(ActiveMQServerTestCase.topic1, ".subscription.name.with.periods.", null, false); s1.createProducer(ActiveMQServerTestCase.topic1).send(s1.createTextMessage("Subscription test")); conn1.start(); Message m = subscriber1.receive(100L); if (noLocal) { ProxyAssertSupport.assertNull(m); } else { ProxyAssertSupport.assertNotNull(m); } conn2.start(); m = subscriber2.receive(1000L); ProxyAssertSupport.assertNotNull(m); ProxyAssertSupport.assertTrue(m instanceof TextMessage); subscriber1.close(); subscriber2.close(); s1.unsubscribe(".subscription.name.with.periods."); s2.unsubscribe(".subscription.name.with.periods."); conn1.close(); conn2.close(); } }