/*
* 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.jms;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import javax.jms.ExceptionListener;
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.naming.Context;
import java.util.ArrayList;
import java.util.Date;
import java.util.concurrent.CountDownLatch;
import org.apache.activemq.artemis.api.core.TransportConfiguration;
import org.apache.activemq.artemis.core.registry.JndiBindingRegistry;
import org.apache.activemq.artemis.core.server.ActiveMQServer;
import org.apache.activemq.artemis.jms.server.JMSServerManager;
import org.apache.activemq.artemis.jms.server.config.ConnectionFactoryConfiguration;
import org.apache.activemq.artemis.jms.server.config.JMSConfiguration;
import org.apache.activemq.artemis.jms.server.config.impl.ConnectionFactoryConfigurationImpl;
import org.apache.activemq.artemis.jms.server.config.impl.JMSConfigurationImpl;
import org.apache.activemq.artemis.jms.server.config.impl.JMSQueueConfigurationImpl;
import org.apache.activemq.artemis.jms.server.impl.JMSServerManagerImpl;
import org.apache.activemq.artemis.tests.integration.IntegrationTestLogger;
import org.apache.activemq.artemis.tests.unit.util.InVMNamingContext;
import org.apache.activemq.artemis.tests.util.ActiveMQTestBase;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import static java.util.concurrent.TimeUnit.SECONDS;
public class ManualReconnectionToSingleServerTest extends ActiveMQTestBase {
// Constants -----------------------------------------------------
private static final IntegrationTestLogger log = IntegrationTestLogger.LOGGER;
private Connection connection;
private MessageConsumer consumer;
private CountDownLatch exceptionLatch;
private CountDownLatch reconnectionLatch;
private CountDownLatch allMessagesReceived;
private JMSServerManager serverManager;
private InVMNamingContext context;
private static final String QUEUE_NAME = ManualReconnectionToSingleServerTest.class.getSimpleName() + ".queue";
private static final int NUM = 20;
private final ExceptionListener exceptionListener = new ExceptionListener() {
@Override
public void onException(final JMSException e) {
exceptionLatch.countDown();
disconnect();
connect();
reconnectionLatch.countDown();
}
};
private Listener listener;
private ActiveMQServer server;
@Test
public void testExceptionListener() throws Exception {
connect();
ConnectionFactory cf = (ConnectionFactory) context.lookup("/cf");
Destination dest = (Destination) context.lookup(QUEUE_NAME);
Connection conn = cf.createConnection();
Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
MessageProducer prod = sess.createProducer(dest);
for (int i = 0; i < NUM; i++) {
Message message = sess.createTextMessage(new Date().toString());
message.setIntProperty("counter", i + 1);
prod.send(message);
if (i == NUM / 2) {
conn.close();
serverManager.stop();
Thread.sleep(5000);
serverManager.start();
cf = (ConnectionFactory) context.lookup("/cf");
dest = (Destination) context.lookup(QUEUE_NAME);
conn = cf.createConnection();
sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
prod = sess.createProducer(dest);
}
}
conn.close();
boolean gotException = exceptionLatch.await(10, SECONDS);
Assert.assertTrue(gotException);
boolean clientReconnected = reconnectionLatch.await(10, SECONDS);
Assert.assertTrue("client did not reconnect after server was restarted", clientReconnected);
boolean gotAllMessages = allMessagesReceived.await(10, SECONDS);
Assert.assertTrue(gotAllMessages);
connection.close();
}
// Package protected ---------------------------------------------
// Protected -----------------------------------------------------
@Override
@Before
public void setUp() throws Exception {
super.setUp();
context = new InVMNamingContext();
server = createServer(false, createDefaultNettyConfig());
JMSConfiguration configuration = new JMSConfigurationImpl();
serverManager = new JMSServerManagerImpl(server, configuration);
serverManager.setRegistry(new JndiBindingRegistry(context));
configuration.getQueueConfigurations().add(new JMSQueueConfigurationImpl().setName(QUEUE_NAME).setBindings(QUEUE_NAME));
ArrayList<TransportConfiguration> configs = new ArrayList<>();
configs.add(new TransportConfiguration(NETTY_CONNECTOR_FACTORY));
ConnectionFactoryConfiguration cfConfig = new ConnectionFactoryConfigurationImpl().setName("cf").setConnectorNames(registerConnectors(server, configs)).setBindings("/cf").setRetryInterval(1000).setReconnectAttempts(-1);
configuration.getConnectionFactoryConfigurations().add(cfConfig);
serverManager.start();
listener = new Listener();
exceptionLatch = new CountDownLatch(1);
reconnectionLatch = new CountDownLatch(1);
allMessagesReceived = new CountDownLatch(1);
}
// Private -------------------------------------------------------
// Inner classes -------------------------------------------------
protected void disconnect() {
ManualReconnectionToSingleServerTest.log.info("calling disconnect");
if (connection == null) {
ManualReconnectionToSingleServerTest.log.info("connection is null");
return;
}
try {
connection.setExceptionListener(null);
ManualReconnectionToSingleServerTest.log.info("closing the connection");
connection.close();
connection = null;
ManualReconnectionToSingleServerTest.log.info("connection closed");
} catch (Exception e) {
ManualReconnectionToSingleServerTest.log.info("** got exception");
e.printStackTrace();
}
}
protected void connect() {
int retries = 0;
final int retryLimit = 1000;
try {
if (context == null) {
return;
}
Context initialContext = context;
Queue queue;
ConnectionFactory cf;
while (true) {
try {
queue = (Queue) initialContext.lookup(QUEUE_NAME);
cf = (ConnectionFactory) initialContext.lookup("/cf");
break;
} catch (Exception e) {
if (retries++ > retryLimit)
throw e;
// retry until server is up
Thread.sleep(100);
}
}
connection = cf.createConnection();
connection.setExceptionListener(exceptionListener);
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
consumer = session.createConsumer(queue);
consumer.setMessageListener(listener);
connection.start();
} catch (Exception e) {
if (connection != null) {
try {
connection.close();
} catch (JMSException e1) {
e1.printStackTrace();
}
}
}
}
private class Listener implements MessageListener {
private int count = 0;
@Override
public void onMessage(final Message msg) {
count++;
try {
msg.getIntProperty("counter");
} catch (JMSException e) {
e.printStackTrace();
}
if (count == NUM) {
allMessagesReceived.countDown();
}
}
}
}