/* * 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.tests.integration.openwire.amq; import javax.jms.Connection; import javax.jms.DeliveryMode; import javax.jms.Destination; import javax.jms.JMSException; import javax.jms.Message; import javax.jms.MessageConsumer; import javax.jms.MessageListener; import javax.jms.MessageProducer; import javax.jms.Queue; import javax.jms.Session; import javax.jms.TextMessage; import java.util.ArrayList; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import org.apache.activemq.ActiveMQConnectionFactory; import org.apache.activemq.ActiveMQMessageConsumer; import org.apache.activemq.RedeliveryPolicy; import org.apache.activemq.artemis.tests.integration.openwire.BasicOpenWireTest; import org.apache.activemq.command.ActiveMQDestination; import org.apache.activemq.command.ActiveMQMessage; import org.apache.activemq.command.ActiveMQQueue; import org.junit.After; import org.junit.Before; import org.junit.Test; /** * adapted from: org.apache.activemq.MessageListenerRedeliveryTest */ public class MessageListenerRedeliveryTest extends BasicOpenWireTest { private Connection redeliverConnection; @Override @Before public void setUp() throws Exception { super.setUp(); redeliverConnection = createRetryConnection(); } /** * @see junit.framework.TestCase#tearDown() */ @Override @After public void tearDown() throws Exception { if (redeliverConnection != null) { redeliverConnection.close(); redeliverConnection = null; } super.tearDown(); } protected RedeliveryPolicy getRedeliveryPolicy() { RedeliveryPolicy redeliveryPolicy = new RedeliveryPolicy(); redeliveryPolicy.setInitialRedeliveryDelay(0); redeliveryPolicy.setRedeliveryDelay(1000); redeliveryPolicy.setMaximumRedeliveries(3); redeliveryPolicy.setBackOffMultiplier((short) 2); redeliveryPolicy.setUseExponentialBackOff(true); return redeliveryPolicy; } protected Connection createRetryConnection() throws Exception { ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(urlString); factory.setRedeliveryPolicy(getRedeliveryPolicy()); return factory.createConnection(); } private class TestMessageListener implements MessageListener { public int counter; private final Session session; private TestMessageListener(Session session) { this.session = session; } @Override public void onMessage(Message message) { try { System.out.println("Message Received: " + message); counter++; if (counter <= 4) { System.out.println("Message Rollback."); session.rollback(); } else { System.out.println("Message Commit."); message.acknowledge(); session.commit(); } } catch (JMSException e) { System.out.println("Error when rolling back transaction"); } } } @Test public void testQueueRollbackConsumerListener() throws Exception { redeliverConnection.start(); Session session = redeliverConnection.createSession(true, Session.CLIENT_ACKNOWLEDGE); String qname = "queue-testQueueRollbackConsumerListener"; Queue queue = session.createQueue(qname); this.makeSureCoreQueueExist(qname); MessageProducer producer = createProducer(session, queue); Message message = createTextMessage(session); producer.send(message); session.commit(); MessageConsumer consumer = session.createConsumer(queue); ActiveMQMessageConsumer mc = (ActiveMQMessageConsumer) consumer; mc.setRedeliveryPolicy(getRedeliveryPolicy()); TestMessageListener listener = new TestMessageListener(session); consumer.setMessageListener(listener); try { Thread.sleep(500); } catch (InterruptedException e) { } // first try.. should get 2 since there is no delay on the // first redeliver.. assertEquals(2, listener.counter); try { Thread.sleep(1000); } catch (InterruptedException e) { } // 2nd redeliver (redelivery after 1 sec) assertEquals(3, listener.counter); try { Thread.sleep(2000); } catch (InterruptedException e) { } // 3rd redeliver (redelivery after 2 seconds) - it should give up after // that assertEquals(4, listener.counter); // create new message producer.send(createTextMessage(session)); session.commit(); try { Thread.sleep(500); } catch (InterruptedException e) { } // it should be committed, so no redelivery assertEquals(5, listener.counter); try { Thread.sleep(1500); } catch (InterruptedException e) { } // no redelivery, counter should still be 4 assertEquals(5, listener.counter); session.close(); } @Test public void testQueueRollbackSessionListener() throws Exception { redeliverConnection.start(); Session session = redeliverConnection.createSession(true, Session.CLIENT_ACKNOWLEDGE); String qname = "queue-testQueueRollbackSessionListener"; Queue queue = session.createQueue(qname); this.makeSureCoreQueueExist(qname); MessageProducer producer = createProducer(session, queue); Message message = createTextMessage(session); producer.send(message); session.commit(); MessageConsumer consumer = session.createConsumer(queue); ActiveMQMessageConsumer mc = (ActiveMQMessageConsumer) consumer; mc.setRedeliveryPolicy(getRedeliveryPolicy()); TestMessageListener listener = new TestMessageListener(session); consumer.setMessageListener(listener); try { Thread.sleep(500); } catch (InterruptedException e) { } // first try assertEquals(2, listener.counter); try { Thread.sleep(1000); } catch (InterruptedException e) { } // second try (redelivery after 1 sec) assertEquals(3, listener.counter); try { Thread.sleep(2000); } catch (InterruptedException e) { } // third try (redelivery after 2 seconds) - it should give up after that assertEquals(4, listener.counter); // create new message producer.send(createTextMessage(session)); session.commit(); try { Thread.sleep(500); } catch (InterruptedException e) { // ignore } // it should be committed, so no redelivery assertEquals(5, listener.counter); try { Thread.sleep(1500); } catch (InterruptedException e) { // ignore } // no redelivery, counter should still be 4 assertEquals(5, listener.counter); session.close(); } @Test public void testQueueSessionListenerExceptionRetry() throws Exception { redeliverConnection.start(); Session session = redeliverConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); String qname = "queue-testQueueSessionListenerExceptionRetry"; Queue queue = session.createQueue(qname); this.makeSureCoreQueueExist(qname); MessageProducer producer = createProducer(session, queue); Message message = createTextMessage(session, "1"); producer.send(message); message = createTextMessage(session, "2"); producer.send(message); MessageConsumer consumer = session.createConsumer(queue); final CountDownLatch gotMessage = new CountDownLatch(2); final AtomicInteger count = new AtomicInteger(0); final int maxDeliveries = getRedeliveryPolicy().getMaximumRedeliveries(); final ArrayList<String> received = new ArrayList<>(); consumer.setMessageListener(new MessageListener() { @Override public void onMessage(Message message) { System.out.println("Message Received: " + message); try { received.add(((TextMessage) message).getText()); } catch (JMSException e) { e.printStackTrace(); fail(e.toString()); } if (count.incrementAndGet() < maxDeliveries) { throw new RuntimeException(getName() + " force a redelivery"); } // new blood count.set(0); gotMessage.countDown(); } }); assertTrue("got message before retry expiry", gotMessage.await(20, TimeUnit.SECONDS)); for (int i = 0; i < maxDeliveries; i++) { assertEquals("got first redelivered: " + i, "1", received.get(i)); } for (int i = maxDeliveries; i < maxDeliveries * 2; i++) { assertEquals("got first redelivered: " + i, "2", received.get(i)); } session.close(); } @Test public void testQueueSessionListenerExceptionDlq() throws Exception { redeliverConnection.start(); Session session = redeliverConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); String qname = "queue-testQueueSessionListenerExceptionDlq"; Queue queue = session.createQueue(qname); this.makeSureCoreQueueExist(qname); MessageProducer producer = createProducer(session, queue); Message message = createTextMessage(session); producer.send(message); final Message[] dlqMessage = new Message[1]; ActiveMQDestination dlqDestination = new ActiveMQQueue("ActiveMQ.DLQ"); this.makeSureCoreQueueExist("ActiveMQ.DLQ"); MessageConsumer dlqConsumer = session.createConsumer(dlqDestination); final CountDownLatch gotDlqMessage = new CountDownLatch(1); dlqConsumer.setMessageListener(new MessageListener() { @Override public void onMessage(Message message) { System.out.println("DLQ Message Received: " + message); dlqMessage[0] = message; gotDlqMessage.countDown(); } }); MessageConsumer consumer = session.createConsumer(queue); final int maxDeliveries = getRedeliveryPolicy().getMaximumRedeliveries(); System.out.println("max redlivery: " + maxDeliveries); final CountDownLatch gotMessage = new CountDownLatch(maxDeliveries); consumer.setMessageListener(new MessageListener() { @Override public void onMessage(Message message) { System.out.println("Message Received: " + message); gotMessage.countDown(); throw new RuntimeException(getName() + " force a redelivery"); } }); assertTrue("got message before retry expiry", gotMessage.await(20, TimeUnit.SECONDS)); // check DLQ assertTrue("got dlq message", gotDlqMessage.await(20, TimeUnit.SECONDS)); // check DLQ message cause is captured message = dlqMessage[0]; assertNotNull("dlq message captured", message); String cause = message.getStringProperty(ActiveMQMessage.DLQ_DELIVERY_FAILURE_CAUSE_PROPERTY); System.out.println("DLQ'd message cause reported as: " + cause); assertTrue("cause 'cause' exception is remembered", cause.contains("RuntimeException")); assertTrue("is correct exception", cause.contains(getName())); assertTrue("cause exception is remembered", cause.contains("Throwable")); assertTrue("cause policy is remembered", cause.contains("RedeliveryPolicy")); session.close(); } private TextMessage createTextMessage(Session session, String text) throws JMSException { return session.createTextMessage(text); } private TextMessage createTextMessage(Session session) throws JMSException { return session.createTextMessage("Hello"); } private MessageProducer createProducer(Session session, Destination queue) throws JMSException { MessageProducer producer = session.createProducer(queue); producer.setDeliveryMode(getDeliveryMode()); return producer; } protected int getDeliveryMode() { return DeliveryMode.PERSISTENT; } @Override protected String getName() { return "testQueueSessionListenerExceptionDlq"; } }