/*
* 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.Message;
import javax.jms.MessageConsumer;
import javax.jms.MessageListener;
import javax.jms.Session;
import java.lang.Thread.UncaughtExceptionHandler;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.activemq.ActiveMQMessageConsumer;
import org.apache.activemq.artemis.tests.integration.openwire.BasicOpenWireTest;
import org.apache.activemq.artemis.utils.ActiveMQThreadFactory;
import org.apache.activemq.command.ActiveMQDestination;
import org.junit.Test;
/**
* adapted from: org.apache.activemq.JMSConsumerTest
*/
public class JMSConsumer2Test extends BasicOpenWireTest {
@Test
public void testMessageListenerWithConsumerCanBeStoppedConcurently() throws Exception {
final AtomicInteger counter = new AtomicInteger(0);
final CountDownLatch closeDone = new CountDownLatch(1);
connection.start();
Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE);
ActiveMQDestination destination = createDestination(session, ActiveMQDestination.QUEUE_TYPE);
// preload the queue
sendMessages(session, destination, 2000);
final ActiveMQMessageConsumer consumer = (ActiveMQMessageConsumer) session.createConsumer(destination);
final Map<Thread, Throwable> exceptions = Collections.synchronizedMap(new HashMap<Thread, Throwable>());
Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread t, Throwable e) {
exceptions.put(t, e);
}
});
final class AckAndClose implements Runnable {
private final Message message;
AckAndClose(Message m) {
this.message = m;
}
@Override
public void run() {
try {
int count = counter.incrementAndGet();
if (count == 590) {
// close in a separate thread is ok by jms
consumer.close();
closeDone.countDown();
}
if (count % 200 == 0) {
// ensure there are some outstanding messages
// ack every 200
message.acknowledge();
}
} catch (Exception e) {
exceptions.put(Thread.currentThread(), e);
}
}
}
final ExecutorService executor = Executors.newCachedThreadPool(ActiveMQThreadFactory.defaultThreadFactory());
consumer.setMessageListener(new MessageListener() {
@Override
public void onMessage(Message m) {
// ack and close eventually in separate thread
executor.execute(new AckAndClose(m));
}
});
assertTrue(closeDone.await(20, TimeUnit.SECONDS));
// await possible exceptions
Thread.sleep(1000);
assertTrue("no exceptions: " + exceptions, exceptions.isEmpty());
}
@Test
public void testDupsOkConsumer() throws Exception {
// Receive a message with the JMS API
connection.start();
Session session = connection.createSession(false, Session.DUPS_OK_ACKNOWLEDGE);
ActiveMQDestination destination = createDestination(session, ActiveMQDestination.QUEUE_TYPE);
MessageConsumer consumer = session.createConsumer(destination);
// Send the messages
sendMessages(session, destination, 4);
// Make sure only 4 message are delivered.
for (int i = 0; i < 4; i++) {
Message m = consumer.receive(1000);
assertNotNull(m);
}
assertNull(consumer.receive(1000));
// Close out the consumer.. no other messages should be left on the queue.
consumer.close();
consumer = session.createConsumer(destination);
assertNull(consumer.receive(1000));
}
@Test
public void testRedispatchOfUncommittedTx() throws Exception {
connection.start();
Session session = connection.createSession(true, Session.SESSION_TRANSACTED);
ActiveMQDestination destination = createDestination(session, ActiveMQDestination.QUEUE_TYPE);
sendMessages(connection, destination, 2);
MessageConsumer consumer = session.createConsumer(destination);
Message m = consumer.receive(1000);
System.out.println("m1 received: " + m);
assertNotNull(m);
m = consumer.receive(5000);
System.out.println("m2 received: " + m);
assertNotNull(m);
// install another consumer while message dispatch is unacked/uncommitted
Session redispatchSession = connection.createSession(true, Session.SESSION_TRANSACTED);
MessageConsumer redispatchConsumer = redispatchSession.createConsumer(destination);
System.out.println("redispatch consumer: " + redispatchConsumer);
// no commit so will auto rollback and get re-dispatched to
// redisptachConsumer
System.out.println("closing session: " + session);
session.close();
Message msg = redispatchConsumer.receive(3000);
assertNotNull(msg);
assertTrue("redelivered flag set", msg.getJMSRedelivered());
assertEquals(2, msg.getLongProperty("JMSXDeliveryCount"));
msg = redispatchConsumer.receive(1000);
assertNotNull(msg);
assertTrue(msg.getJMSRedelivered());
assertEquals(2, msg.getLongProperty("JMSXDeliveryCount"));
redispatchSession.commit();
assertNull(redispatchConsumer.receive(500));
System.out.println("closing dispatch session: " + redispatchSession);
redispatchSession.close();
}
@Test
public void testRedispatchOfRolledbackTx() throws Exception {
connection.start();
Session session = connection.createSession(true, Session.SESSION_TRANSACTED);
ActiveMQDestination destination = createDestination(session, ActiveMQDestination.QUEUE_TYPE);
sendMessages(connection, destination, 2);
MessageConsumer consumer = session.createConsumer(destination);
assertNotNull(consumer.receive(1000));
assertNotNull(consumer.receive(1000));
// install another consumer while message dispatch is unacked/uncommitted
Session redispatchSession = connection.createSession(true, Session.SESSION_TRANSACTED);
MessageConsumer redispatchConsumer = redispatchSession.createConsumer(destination);
session.rollback();
session.close();
Message msg = redispatchConsumer.receive(1000);
assertNotNull(msg);
assertTrue(msg.getJMSRedelivered());
assertEquals(2, msg.getLongProperty("JMSXDeliveryCount"));
msg = redispatchConsumer.receive(1000);
assertNotNull(msg);
assertTrue(msg.getJMSRedelivered());
assertEquals(2, msg.getLongProperty("JMSXDeliveryCount"));
redispatchSession.commit();
assertNull(redispatchConsumer.receive(500));
redispatchSession.close();
}
}