/** * 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.usecases; import javax.jms.Connection; import javax.jms.JMSException; import javax.jms.Message; import javax.jms.MessageConsumer; import javax.jms.MessageProducer; import javax.jms.Session; import java.util.HashSet; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import org.apache.activemq.ActiveMQConnectionFactory; import org.apache.activemq.command.ActiveMQTopic; import org.apache.activemq.command.MessageId; import org.apache.activemq.store.kahadb.KahaDBPersistenceAdapter; import org.apache.activemq.store.kahadb.disk.page.PageFile; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; public class DurableSubscriptionOfflineTest extends DurableSubscriptionOfflineTestBase { private static final Logger LOG = LoggerFactory.getLogger(DurableSubscriptionOfflineTest.class); @Override protected ActiveMQConnectionFactory createConnectionFactory() throws Exception { ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory("vm://" + getName(true)); connectionFactory.setWatchTopicAdvisories(false); return connectionFactory; } @Test(timeout = 60 * 1000) public void testConsumeAllMatchedMessages() throws Exception { // create durable subscription Connection con = createConnection(); Session session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); session.createDurableSubscriber(topic, "SubsId", "filter = 'true'", true); session.close(); con.close(); // send messages con = createConnection(); session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); MessageProducer producer = session.createProducer(null); int sent = 0; for (int i = 0; i < 10; i++) { sent++; Message message = session.createMessage(); message.setStringProperty("filter", "true"); producer.send(topic, message); } Thread.sleep(1 * 1000); session.close(); con.close(); // consume messages con = createConnection(); session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); MessageConsumer consumer = session.createDurableSubscriber(topic, "SubsId", "filter = 'true'", true); DurableSubscriptionOfflineTestListener listener = new DurableSubscriptionOfflineTestListener(); consumer.setMessageListener(listener); Thread.sleep(3 * 1000); session.close(); con.close(); assertEquals(sent, listener.count); } @Test(timeout = 60 * 1000) public void testTwoOfflineSubscriptionCanConsume() throws Exception { // create durable subscription 1 Connection con = createConnection("cliId1"); Session session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); session.createDurableSubscriber(topic, "SubsId", "filter = 'true'", true); session.close(); con.close(); // create durable subscription 2 Connection con2 = createConnection("cliId2"); Session session2 = con2.createSession(false, Session.AUTO_ACKNOWLEDGE); MessageConsumer consumer2 = session2.createDurableSubscriber(topic, "SubsId", "filter = 'true'", true); DurableSubscriptionOfflineTestListener listener2 = new DurableSubscriptionOfflineTestListener(); consumer2.setMessageListener(listener2); // send messages con = createConnection(); session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); MessageProducer producer = session.createProducer(null); int sent = 0; for (int i = 0; i < 10; i++) { sent++; Message message = session.createMessage(); message.setStringProperty("filter", "true"); producer.send(topic, message); } Thread.sleep(1 * 1000); session.close(); con.close(); // test online subs Thread.sleep(3 * 1000); session2.close(); con2.close(); assertEquals(sent, listener2.count); // consume messages con = createConnection("cliId1"); session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); MessageConsumer consumer = session.createDurableSubscriber(topic, "SubsId", "filter = 'true'", true); DurableSubscriptionOfflineTestListener listener = new DurableSubscriptionOfflineTestListener(); consumer.setMessageListener(listener); Thread.sleep(3 * 1000); session.close(); con.close(); assertEquals("offline consumer got all", sent, listener.count); } @Test(timeout = 60 * 1000) public void testRemovedDurableSubDeletes() throws Exception { String filter = "$a='A1' AND (($b=true AND $c=true) OR ($d='D1' OR $d='D2'))"; // create durable subscription 1 Connection con = createConnection("cliId1"); Session session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); session.createDurableSubscriber(topic, "SubsId", "filter = 'true'", true); session.close(); con.close(); // send messages con = createConnection(); session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); MessageProducer producer = session.createProducer(null); for (int i = 0; i < 10; i++) { Message message = session.createMessage(); message.setStringProperty("filter", "true"); producer.send(topic, message); } Thread.sleep(1 * 1000); Connection con2 = createConnection("cliId1"); Session session2 = con2.createSession(false, Session.AUTO_ACKNOWLEDGE); session2.unsubscribe("SubsId"); session2.close(); con2.close(); // see if retroactive can consumer any topic = new ActiveMQTopic(topic.getPhysicalName() + "?consumer.retroactive=true"); con = createConnection("offCli2"); session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); MessageConsumer consumer = session.createDurableSubscriber(topic, "SubsId", filter, true); DurableSubscriptionOfflineTestListener listener = new DurableSubscriptionOfflineTestListener(); consumer.setMessageListener(listener); session.close(); con.close(); assertEquals(0, listener.count); } @Test(timeout = 60 * 1000) public void testRemovedDurableSubDeletesFromIndex() throws Exception { if (!(broker.getPersistenceAdapter() instanceof KahaDBPersistenceAdapter)) { return; } final int numMessages = 2750; KahaDBPersistenceAdapter kahaDBPersistenceAdapter = (KahaDBPersistenceAdapter) broker.getPersistenceAdapter(); PageFile pageFile = kahaDBPersistenceAdapter.getStore().getPageFile(); LOG.info("PageCount " + pageFile.getPageCount() + " f:" + pageFile.getFreePageCount() + ", fileSize:" + pageFile.getFile().length()); long lastDiff = 0; for (int repeats = 0; repeats < 2; repeats++) { LOG.info("Iteration: " + repeats + " Count:" + pageFile.getPageCount() + " f:" + pageFile.getFreePageCount()); Connection con = createConnection("cliId1" + "-" + repeats); Session session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); session.createDurableSubscriber(topic, "SubsId", "filter = 'true'", true); session.close(); con.close(); // send messages con = createConnection(); session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); MessageProducer producer = session.createProducer(null); for (int i = 0; i < numMessages; i++) { Message message = session.createMessage(); message.setStringProperty("filter", "true"); producer.send(topic, message); } con.close(); Connection con2 = createConnection("cliId1" + "-" + repeats); Session session2 = con2.createSession(false, Session.AUTO_ACKNOWLEDGE); session2.unsubscribe("SubsId"); session2.close(); con2.close(); LOG.info("PageCount " + pageFile.getPageCount() + " f:" + pageFile.getFreePageCount() + " diff: " + (pageFile.getPageCount() - pageFile.getFreePageCount()) + " fileSize:" + pageFile.getFile().length()); if (lastDiff != 0) { assertEquals("Only use X pages per iteration: " + repeats, lastDiff, pageFile.getPageCount() - pageFile.getFreePageCount()); } lastDiff = pageFile.getPageCount() - pageFile.getFreePageCount(); } } @Test(timeout = 60 * 1000) public void testInterleavedOfflineSubscriptionCanConsumeAfterUnsub() throws Exception { // create offline subs 1 Connection con = createConnection("offCli1"); Session session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); session.createDurableSubscriber(topic, "SubsId", "filter = 'true'", true); session.close(); con.close(); // create offline subs 2 con = createConnection("offCli2"); session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); session.createDurableSubscriber(topic, "SubsId", null, true); session.close(); con.close(); // send messages con = createConnection(); session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); MessageProducer producer = session.createProducer(null); int sent = 0; for (int i = 0; i < 10; i++) { boolean filter = (int) (Math.random() * 2) >= 1; sent++; Message message = session.createMessage(); message.setStringProperty("filter", filter ? "true" : "false"); producer.send(topic, message); } Thread.sleep(1 * 1000); Connection con2 = createConnection("offCli1"); Session session2 = con2.createSession(false, Session.AUTO_ACKNOWLEDGE); session2.unsubscribe("SubsId"); session2.close(); con2.close(); // consume all messages con = createConnection("offCli2"); session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); MessageConsumer consumer = session.createDurableSubscriber(topic, "SubsId", null, true); DurableSubscriptionOfflineTestListener listener = new DurableSubscriptionOfflineTestListener("SubsId"); consumer.setMessageListener(listener); Thread.sleep(3 * 1000); session.close(); con.close(); assertEquals("offline consumer got all", sent, listener.count); } @Test(timeout = 60 * 1000) public void testNoDuplicateOnConcurrentSendTranCommitAndActivate() throws Exception { final int messageCount = 1000; Connection con = null; Session session = null; final int numConsumers = 10; for (int i = 0; i <= numConsumers; i++) { con = createConnection("cli" + i); session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); session.createDurableSubscriber(topic, "SubsId", null, true); session.close(); con.close(); } class CheckForDupsClient implements Runnable { HashSet<Long> ids = new HashSet<>(); final int id; public CheckForDupsClient(int id) { this.id = id; } @Override public void run() { try { Connection con = createConnection("cli" + id); Session session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); for (int j = 0; j < 2; j++) { MessageConsumer consumer = session.createDurableSubscriber(topic, "SubsId", null, true); for (int i = 0; i < messageCount / 2; i++) { Message message = consumer.receive(4000); assertNotNull(message); long producerSequenceId = new MessageId(message.getJMSMessageID()).getProducerSequenceId(); assertTrue("ID=" + id + " not a duplicate: " + producerSequenceId, ids.add(producerSequenceId)); } consumer.close(); } // verify no duplicates left MessageConsumer consumer = session.createDurableSubscriber(topic, "SubsId", null, true); Message message = consumer.receive(4000); if (message != null) { long producerSequenceId = new MessageId(message.getJMSMessageID()).getProducerSequenceId(); assertTrue("ID=" + id + " not a duplicate: " + producerSequenceId, ids.add(producerSequenceId)); } assertNull(message); session.close(); con.close(); } catch (Throwable e) { e.printStackTrace(); exceptions.add(e); } } } final String payLoad = new String(new byte[1000]); con = createConnection(); final Session sendSession = con.createSession(true, Session.SESSION_TRANSACTED); MessageProducer producer = sendSession.createProducer(topic); for (int i = 0; i < messageCount; i++) { producer.send(sendSession.createTextMessage(payLoad)); } ExecutorService executorService = Executors.newCachedThreadPool(); // concurrent commit and activate executorService.execute(new Runnable() { @Override public void run() { try { sendSession.commit(); } catch (JMSException e) { e.printStackTrace(); exceptions.add(e); } } }); for (int i = 0; i < numConsumers; i++) { executorService.execute(new CheckForDupsClient(i)); } executorService.shutdown(); executorService.awaitTermination(5, TimeUnit.MINUTES); con.close(); assertTrue("no exceptions: " + exceptions, exceptions.isEmpty()); } @Test(timeout = 2 * 60 * 1000) public void testOrderOnActivateDeactivate() throws Exception { for (int i = 0; i < 10; i++) { LOG.info("Iteration: " + i); doTestOrderOnActivateDeactivate(); broker.stop(); broker.waitUntilStopped(); createBroker(true /*deleteAllMessages*/); } } public void doTestOrderOnActivateDeactivate() throws Exception { final int messageCount = 1000; Connection con = null; Session session = null; final int numConsumers = 4; for (int i = 0; i <= numConsumers; i++) { con = createConnection("cli" + i); session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); session.createDurableSubscriber(topic, "SubsId", null, true); session.close(); con.close(); } final String url = "failover:(tcp://localhost:" + (broker.getTransportConnectors().get(1).getConnectUri()).getPort() + "?wireFormat.maxInactivityDuration=0)?" + "jms.watchTopicAdvisories=false&" + "jms.alwaysSyncSend=true&jms.dispatchAsync=true&" + "jms.sendAcksAsync=true&" + "initialReconnectDelay=100&maxReconnectDelay=30000&" + "useExponentialBackOff=true"; final ActiveMQConnectionFactory clientFactory = new ActiveMQConnectionFactory(url); class CheckOrderClient implements Runnable { final int id; int runCount = 0; public CheckOrderClient(int id) { this.id = id; } @Override public void run() { try { synchronized (this) { Connection con = clientFactory.createConnection(); con.setClientID("cli" + id); con.start(); Session session = con.createSession(false, Session.CLIENT_ACKNOWLEDGE); MessageConsumer consumer = session.createDurableSubscriber(topic, "SubsId", null, true); int nextId = 0; ++runCount; int i = 0; for (; i < messageCount / 2; i++) { Message message = consumer.receiveNoWait(); if (message == null) { break; } long producerSequenceId = new MessageId(message.getJMSMessageID()).getProducerSequenceId(); assertEquals(id + " expected order: runCount: " + runCount + " id: " + message.getJMSMessageID(), ++nextId, producerSequenceId); } LOG.info(con.getClientID() + " peeked " + i); session.close(); con.close(); } } catch (Throwable e) { e.printStackTrace(); exceptions.add(e); } } } Runnable producer = new Runnable() { final String payLoad = new String(new byte[600]); @Override public void run() { try { Connection con = createConnection(); final Session sendSession = con.createSession(true, Session.SESSION_TRANSACTED); MessageProducer producer = sendSession.createProducer(topic); for (int i = 0; i < messageCount; i++) { producer.send(sendSession.createTextMessage(payLoad)); } LOG.info("About to commit: " + messageCount); sendSession.commit(); LOG.info("committed: " + messageCount); con.close(); } catch (Exception e) { e.printStackTrace(); exceptions.add(e); } } }; ExecutorService executorService = Executors.newCachedThreadPool(); // concurrent commit and activate for (int i = 0; i < numConsumers; i++) { final CheckOrderClient client = new CheckOrderClient(i); for (int j = 0; j < 100; j++) { executorService.execute(client); } } executorService.execute(producer); executorService.shutdown(); executorService.awaitTermination(5, TimeUnit.MINUTES); con.close(); assertTrue("no exceptions: " + exceptions, exceptions.isEmpty()); } @Test(timeout = 60 * 1000) public void testUnmatchedSubUnsubscribeDeletesAll() throws Exception { // create offline subs 1 Connection con = createConnection("offCli1"); Session session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); session.createDurableSubscriber(topic, "SubsId", "filter = 'true'", true); session.close(); con.close(); // send messages con = createConnection(); session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); MessageProducer producer = session.createProducer(null); int filtered = 0; for (int i = 0; i < 10; i++) { boolean filter = (i % 2 == 0); //(int) (Math.random() * 2) >= 1; if (filter) filtered++; Message message = session.createMessage(); message.setStringProperty("filter", filter ? "true" : "false"); producer.send(topic, message); } LOG.info("sent: " + filtered); Thread.sleep(1 * 1000); session.close(); con.close(); // test offline subs con = createConnection("offCli1"); session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); session.unsubscribe("SubsId"); session.close(); con.close(); con = createConnection("offCli1"); session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); MessageConsumer consumer = session.createDurableSubscriber(topic, "SubsId", "filter = 'true'", true); DurableSubscriptionOfflineTestListener listener = new DurableSubscriptionOfflineTestListener(); consumer.setMessageListener(listener); Thread.sleep(3 * 1000); session.close(); con.close(); assertEquals(0, listener.count); } @Test(timeout = 60 * 1000) public void testAllConsumed() throws Exception { final String filter = "filter = 'true'"; Connection con = createConnection("cli1"); Session session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); session.createDurableSubscriber(topic, "SubsId", filter, true); session.close(); con.close(); con = createConnection("cli2"); session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); session.createDurableSubscriber(topic, "SubsId", filter, true); session.close(); con.close(); // send messages con = createConnection(); session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); MessageProducer producer = session.createProducer(null); int sent = 0; for (int i = 0; i < 10; i++) { Message message = session.createMessage(); message.setStringProperty("filter", "true"); producer.send(topic, message); sent++; } LOG.info("sent: " + sent); Thread.sleep(1 * 1000); session.close(); con.close(); con = createConnection("cli1"); session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); MessageConsumer consumer = session.createDurableSubscriber(topic, "SubsId", filter, true); DurableSubscriptionOfflineTestListener listener = new DurableSubscriptionOfflineTestListener(); consumer.setMessageListener(listener); Thread.sleep(3 * 1000); session.close(); con.close(); assertEquals(sent, listener.count); LOG.info("cli2 pull 2"); con = createConnection("cli2"); session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); consumer = session.createDurableSubscriber(topic, "SubsId", filter, true); assertNotNull("got message", consumer.receive(2000)); assertNotNull("got message", consumer.receive(2000)); session.close(); con.close(); // send messages con = createConnection(); session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); producer = session.createProducer(null); sent = 0; for (int i = 0; i < 2; i++) { Message message = session.createMessage(); message.setStringProperty("filter", i == 1 ? "true" : "false"); producer.send(topic, message); sent++; } LOG.info("sent: " + sent); Thread.sleep(1 * 1000); session.close(); con.close(); LOG.info("cli1 again, should get 1 new ones"); con = createConnection("cli1"); session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); consumer = session.createDurableSubscriber(topic, "SubsId", filter, true); listener = new DurableSubscriptionOfflineTestListener(); consumer.setMessageListener(listener); Thread.sleep(3 * 1000); session.close(); con.close(); assertEquals(1, listener.count); } // https://issues.apache.org/jira/browse/AMQ-3190 @Test(timeout = 60 * 1000) public void testNoMissOnMatchingSubAfterRestart() throws Exception { final String filter = "filter = 'true'"; Connection con = createConnection("cli1"); Session session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); session.createDurableSubscriber(topic, "SubsId", filter, true); session.close(); con.close(); // send unmatched messages con = createConnection(); session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); MessageProducer producer = session.createProducer(null); int sent = 0; // message for cli1 to keep it interested Message message = session.createMessage(); message.setStringProperty("filter", "true"); message.setIntProperty("ID", 0); producer.send(topic, message); sent++; for (int i = sent; i < 10; i++) { message = session.createMessage(); message.setStringProperty("filter", "false"); message.setIntProperty("ID", i); producer.send(topic, message); sent++; } con.close(); LOG.info("sent: " + sent); // new sub at id 10 con = createConnection("cli2"); session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); session.createDurableSubscriber(topic, "SubsId", filter, true); session.close(); con.close(); destroyBroker(); createBroker(false); con = createConnection(); session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); producer = session.createProducer(null); for (int i = sent; i < 30; i++) { message = session.createMessage(); message.setStringProperty("filter", "true"); message.setIntProperty("ID", i); producer.send(topic, message); sent++; } con.close(); LOG.info("sent: " + sent); // pick up the first of the next twenty messages con = createConnection("cli2"); session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); MessageConsumer consumer = session.createDurableSubscriber(topic, "SubsId", filter, true); Message m = consumer.receive(3000); assertEquals("is message 10", 10, m.getIntProperty("ID")); session.close(); con.close(); // pick up the first few messages for client1 con = createConnection("cli1"); session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); consumer = session.createDurableSubscriber(topic, "SubsId", filter, true); m = consumer.receive(3000); assertEquals("is message 0", 0, m.getIntProperty("ID")); m = consumer.receive(3000); assertEquals("is message 10", 10, m.getIntProperty("ID")); session.close(); con.close(); } // // https://issues.apache.org/jira/browse/AMQ-3768 // public void testPageReuse() throws Exception { // Connection con = null; // Session session = null; // // final int numConsumers = 115; // for (int i=0; i<=numConsumers;i++) { // con = createConnection("cli" + i); // session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); // session.createDurableSubscriber(topic, "SubsId", null, true); // session.close(); // con.close(); // } // // // populate ack locations // con = createConnection(); // session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); // MessageProducer producer = session.createProducer(null); // Message message = session.createTextMessage(new byte[10].toString()); // producer.send(topic, message); // con.close(); // // // we have a split, remove all but the last so that // // the head pageid changes in the acklocations listindex // for (int i=0; i<=numConsumers -1; i++) { // con = createConnection("cli" + i); // session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); // session.unsubscribe("SubsId"); // session.close(); // con.close(); // } // // destroyBroker(); // createBroker(false); // // // create a bunch more subs to reuse the freed page and get us in a knot // for (int i=1; i<=numConsumers;i++) { // con = createConnection("cli" + i); // session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); // session.createDurableSubscriber(topic, "SubsId", filter, true); // session.close(); // con.close(); // } // } // // public void testRedeliveryFlag() throws Exception { // // Connection con; // Session session; // final int numClients = 2; // for (int i=0; i<numClients; i++) { // con = createConnection("cliId" + i); // session = con.createSession(false, Session.CLIENT_ACKNOWLEDGE); // session.createDurableSubscriber(topic, "SubsId", "filter = 'true'", true); // session.close(); // con.close(); // } // // final Random random = new Random(); // // // send messages // con = createConnection(); // session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); // MessageProducer producer = session.createProducer(null); // // final int count = 1000; // for (int i = 0; i < count; i++) { // Message message = session.createMessage(); // message.setStringProperty("filter", "true"); // producer.send(topic, message); // } // session.close(); // con.close(); // // class Client implements Runnable { // Connection con; // Session session; // String clientId; // Client(String id) { // this.clientId = id; // } // // @Override // public void run() { // MessageConsumer consumer = null; // Message message = null; // // try { // for (int i = -1; i < random.nextInt(10); i++) { // // go online and take none // con = createConnection(clientId); // session = con.createSession(false, Session.CLIENT_ACKNOWLEDGE); // consumer = session.createDurableSubscriber(topic, "SubsId", "filter = 'true'", true); // session.close(); // con.close(); // } // // // consume 1 // con = createConnection(clientId); // session = con.createSession(false, Session.CLIENT_ACKNOWLEDGE); // consumer = session.createDurableSubscriber(topic, "SubsId", "filter = 'true'", true); // message = consumer.receive(4000); // assertNotNull("got message", message); // // it is not reliable as it depends on broker dispatch rather than client receipt // // and delivered ack // // assertFalse("not redelivered", message.getJMSRedelivered()); // message.acknowledge(); // session.close(); // con.close(); // // // peek all // for (int j = -1; j < random.nextInt(10); j++) { // con = createConnection(clientId); // session = con.createSession(false, Session.CLIENT_ACKNOWLEDGE); // consumer = session.createDurableSubscriber(topic, "SubsId", "filter = 'true'", true); // // for (int i = 0; i < count - 1; i++) { // assertNotNull("got message", consumer.receive(4000)); // } // // no ack // session.close(); // con.close(); // } // // // consume remaining // con = createConnection(clientId); // session = con.createSession(false, Session.CLIENT_ACKNOWLEDGE); // consumer = session.createDurableSubscriber(topic, "SubsId", "filter = 'true'", true); // // for (int i = 0; i < count - 1; i++) { // message = consumer.receive(4000); // assertNotNull("got message", message); // assertTrue("is redelivered", message.getJMSRedelivered()); // } // message.acknowledge(); // session.close(); // con.close(); // // con = createConnection(clientId); // session = con.createSession(false, Session.CLIENT_ACKNOWLEDGE); // consumer = session.createDurableSubscriber(topic, "SubsId", "filter = 'true'", true); // assertNull("no message left", consumer.receive(2000)); // } catch (Throwable throwable) { // throwable.printStackTrace(); // exceptions.add(throwable); // } // } // } // ExecutorService executorService = Executors.newCachedThreadPool(); // for (int i=0; i<numClients; i++) { // executorService.execute(new Client("cliId" + i)); // } // executorService.shutdown(); // executorService.awaitTermination(10, TimeUnit.MINUTES); // assertTrue("No exceptions expected, but was: " + exceptions, exceptions.isEmpty()); // } }