/* * 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.timing.jms.bridge.impl; import javax.jms.Connection; import javax.jms.ConnectionFactory; 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.Session; import javax.jms.TextMessage; import javax.management.MBeanServerInvocationHandler; import javax.transaction.HeuristicMixedException; import javax.transaction.HeuristicRollbackException; import javax.transaction.InvalidTransactionException; import javax.transaction.NotSupportedException; import javax.transaction.RollbackException; import javax.transaction.SystemException; import javax.transaction.Transaction; import javax.transaction.TransactionManager; import java.lang.management.ManagementFactory; import java.lang.reflect.Field; import java.util.LinkedList; import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; import org.apache.activemq.artemis.api.core.SimpleString; import org.apache.activemq.artemis.api.core.TransportConfiguration; import org.apache.activemq.artemis.api.core.management.ObjectNameBuilder; import org.apache.activemq.artemis.api.core.management.QueueControl; import org.apache.activemq.artemis.api.jms.ActiveMQJMSClient; import org.apache.activemq.artemis.api.jms.JMSFactoryType; import org.apache.activemq.artemis.core.config.Configuration; import org.apache.activemq.artemis.core.registry.JndiBindingRegistry; import org.apache.activemq.artemis.core.remoting.impl.invm.InVMAcceptorFactory; import org.apache.activemq.artemis.core.remoting.impl.invm.InVMConnectorFactory; import org.apache.activemq.artemis.core.server.ActiveMQServers; import org.apache.activemq.artemis.api.core.RoutingType; import org.apache.activemq.artemis.jms.bridge.ConnectionFactoryFactory; import org.apache.activemq.artemis.jms.bridge.DestinationFactory; import org.apache.activemq.artemis.jms.bridge.QualityOfServiceMode; import org.apache.activemq.artemis.jms.bridge.impl.JMSBridgeImpl; import org.apache.activemq.artemis.jms.client.ActiveMQJMSConnectionFactory; import org.apache.activemq.artemis.jms.server.JMSServerManager; import org.apache.activemq.artemis.jms.server.impl.JMSServerManagerImpl; import org.apache.activemq.artemis.tests.unit.UnitTestLogger; import org.apache.activemq.artemis.tests.unit.util.InVMNamingContext; import org.apache.activemq.artemis.tests.util.ActiveMQTestBase; import org.apache.activemq.artemis.utils.RandomUtil; import org.junit.Assert; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; public class JMSBridgeImplTest extends ActiveMQTestBase { // Constants ----------------------------------------------------- private static final UnitTestLogger log = UnitTestLogger.LOGGER; // Attributes ---------------------------------------------------- private static final String SOURCE = RandomUtil.randomString(); private static final String TARGET = RandomUtil.randomString(); private JMSServerManager jmsServer; private static final AtomicBoolean tcclClassFound = new AtomicBoolean(false); @Rule public ExpectedException thrown = ExpectedException.none(); // Static -------------------------------------------------------- protected static TransactionManager newTransactionManager() { return new TransactionManager() { @Override public Transaction suspend() throws SystemException { return null; } @Override public void setTransactionTimeout(final int arg0) throws SystemException { } @Override public void setRollbackOnly() throws IllegalStateException, SystemException { } @Override public void rollback() throws IllegalStateException, SecurityException, SystemException { } @Override public void resume(final Transaction arg0) throws InvalidTransactionException, IllegalStateException, SystemException { } @Override public Transaction getTransaction() throws SystemException { return null; } @Override public int getStatus() throws SystemException { return 0; } @Override public void commit() throws RollbackException, HeuristicMixedException, HeuristicRollbackException, SecurityException, IllegalStateException, SystemException { } @Override public void begin() throws NotSupportedException, SystemException { } }; } private static DestinationFactory newDestinationFactory(final Destination dest) { return new DestinationFactory() { @Override public Destination createDestination() throws Exception { return dest; } }; } private static ConnectionFactoryFactory newConnectionFactoryFactory(final ConnectionFactory cf) { return new ConnectionFactoryFactory() { @Override public ConnectionFactory createConnectionFactory() throws Exception { return cf; } }; } private static ConnectionFactory createConnectionFactory() { ActiveMQJMSConnectionFactory cf = (ActiveMQJMSConnectionFactory) ActiveMQJMSClient.createConnectionFactoryWithoutHA(JMSFactoryType.CF, new TransportConfiguration(InVMConnectorFactory.class.getName())); // Note! We disable automatic reconnection on the session factory. The bridge needs to do the reconnection cf.setReconnectAttempts(0); cf.setBlockOnNonDurableSend(true); cf.setBlockOnDurableSend(true); return cf; } private static ConnectionFactoryFactory newTCCLAwareConnectionFactoryFactory(final ConnectionFactory cf) { return new ConnectionFactoryFactory() { @Override public ConnectionFactory createConnectionFactory() throws Exception { loadATCCLClass(); return cf; } private void loadATCCLClass() { ClassLoader tcclClassLoader = Thread.currentThread().getContextClassLoader(); try { tcclClassLoader.loadClass("com.class.only.visible.to.tccl.SomeClass"); tcclClassFound.set(true); } catch (ClassNotFoundException e) { e.printStackTrace(); } } }; } // Constructors -------------------------------------------------- // Public -------------------------------------------------------- @Test public void testStartWithRepeatedFailure() throws Exception { ActiveMQJMSConnectionFactory failingSourceCF = new ActiveMQJMSConnectionFactory(false, new TransportConfiguration(InVMConnectorFactory.class.getName())) { private static final long serialVersionUID = 2834937512213001068L; @Override public Connection createConnection() throws JMSException { throw new JMSException("unable to create a conn"); } }; ConnectionFactoryFactory sourceCFF = JMSBridgeImplTest.newConnectionFactoryFactory(failingSourceCF); ConnectionFactoryFactory targetCFF = JMSBridgeImplTest.newConnectionFactoryFactory(JMSBridgeImplTest.createConnectionFactory()); DestinationFactory sourceDF = JMSBridgeImplTest.newDestinationFactory(ActiveMQJMSClient.createQueue(JMSBridgeImplTest.SOURCE)); DestinationFactory targetDF = JMSBridgeImplTest.newDestinationFactory(ActiveMQJMSClient.createQueue(JMSBridgeImplTest.TARGET)); TransactionManager tm = JMSBridgeImplTest.newTransactionManager(); JMSBridgeImpl bridge = new JMSBridgeImpl(); bridge.setSourceConnectionFactoryFactory(sourceCFF); bridge.setSourceDestinationFactory(sourceDF); bridge.setTargetConnectionFactoryFactory(targetCFF); bridge.setTargetDestinationFactory(targetDF); // retry after 10 ms bridge.setFailureRetryInterval(10); // retry only once bridge.setMaxRetries(1); bridge.setMaxBatchSize(1); bridge.setMaxBatchTime(-1); bridge.setTransactionManager(tm); bridge.setQualityOfServiceMode(QualityOfServiceMode.AT_MOST_ONCE); Assert.assertFalse(bridge.isStarted()); bridge.start(); Thread.sleep(50); Assert.assertFalse(bridge.isStarted()); Assert.assertTrue(bridge.isFailed()); bridge.stop(); } @Test public void testStartWithFailureThenSuccess() throws Exception { ActiveMQJMSConnectionFactory failingSourceCF = new ActiveMQJMSConnectionFactory(false, new TransportConfiguration(InVMConnectorFactory.class.getName())) { private static final long serialVersionUID = 4657153922210359725L; boolean firstTime = true; @Override public Connection createConnection() throws JMSException { if (firstTime) { firstTime = false; throw new JMSException("unable to create a conn"); } else { return super.createConnection(); } } }; // Note! We disable automatic reconnection on the session factory. The bridge needs to do the reconnection failingSourceCF.setReconnectAttempts(0); failingSourceCF.setBlockOnNonDurableSend(true); failingSourceCF.setBlockOnDurableSend(true); ConnectionFactoryFactory sourceCFF = JMSBridgeImplTest.newConnectionFactoryFactory(failingSourceCF); ConnectionFactoryFactory targetCFF = JMSBridgeImplTest.newConnectionFactoryFactory(JMSBridgeImplTest.createConnectionFactory()); DestinationFactory sourceDF = JMSBridgeImplTest.newDestinationFactory(ActiveMQJMSClient.createQueue(JMSBridgeImplTest.SOURCE)); DestinationFactory targetDF = JMSBridgeImplTest.newDestinationFactory(ActiveMQJMSClient.createQueue(JMSBridgeImplTest.TARGET)); TransactionManager tm = JMSBridgeImplTest.newTransactionManager(); JMSBridgeImpl bridge = new JMSBridgeImpl(); bridge.setSourceConnectionFactoryFactory(sourceCFF); bridge.setSourceDestinationFactory(sourceDF); bridge.setTargetConnectionFactoryFactory(targetCFF); bridge.setTargetDestinationFactory(targetDF); // retry after 10 ms bridge.setFailureRetryInterval(10); // retry only once bridge.setMaxRetries(1); bridge.setMaxBatchSize(1); bridge.setMaxBatchTime(-1); bridge.setTransactionManager(tm); bridge.setQualityOfServiceMode(QualityOfServiceMode.AT_MOST_ONCE); Assert.assertFalse(bridge.isStarted()); bridge.start(); Thread.sleep(500); Assert.assertTrue(bridge.isStarted()); Assert.assertFalse(bridge.isFailed()); bridge.stop(); } /* * we receive only 1 message. The message is sent when the maxBatchTime * expires even if the maxBatchSize is not reached */ @Test public void testSendMessagesWhenMaxBatchTimeExpires() throws Exception { int maxBatchSize = 2; long maxBatchTime = 500; ConnectionFactoryFactory sourceCFF = JMSBridgeImplTest.newConnectionFactoryFactory(JMSBridgeImplTest.createConnectionFactory()); ConnectionFactoryFactory targetCFF = JMSBridgeImplTest.newConnectionFactoryFactory(JMSBridgeImplTest.createConnectionFactory()); DestinationFactory sourceDF = JMSBridgeImplTest.newDestinationFactory(ActiveMQJMSClient.createQueue(JMSBridgeImplTest.SOURCE)); DestinationFactory targetDF = JMSBridgeImplTest.newDestinationFactory(ActiveMQJMSClient.createQueue(JMSBridgeImplTest.TARGET)); TransactionManager tm = JMSBridgeImplTest.newTransactionManager(); JMSBridgeImpl bridge = new JMSBridgeImpl(); Assert.assertNotNull(bridge); bridge.setSourceConnectionFactoryFactory(sourceCFF); bridge.setSourceDestinationFactory(sourceDF); bridge.setTargetConnectionFactoryFactory(targetCFF); bridge.setTargetDestinationFactory(targetDF); bridge.setFailureRetryInterval(10); bridge.setMaxRetries(-1); bridge.setMaxBatchSize(maxBatchSize); bridge.setMaxBatchTime(maxBatchTime); bridge.setTransactionManager(tm); bridge.setQualityOfServiceMode(QualityOfServiceMode.AT_MOST_ONCE); Assert.assertFalse(bridge.isStarted()); bridge.start(); Assert.assertTrue(bridge.isStarted()); Connection targetConn = JMSBridgeImplTest.createConnectionFactory().createConnection(); Session targetSess = targetConn.createSession(false, Session.AUTO_ACKNOWLEDGE); MessageConsumer consumer = targetSess.createConsumer(targetDF.createDestination()); final List<Message> messages = new LinkedList<>(); MessageListener listener = new MessageListener() { @Override public void onMessage(final Message message) { messages.add(message); } }; consumer.setMessageListener(listener); targetConn.start(); Connection sourceConn = JMSBridgeImplTest.createConnectionFactory().createConnection(); Session sourceSess = sourceConn.createSession(false, Session.AUTO_ACKNOWLEDGE); MessageProducer producer = sourceSess.createProducer(sourceDF.createDestination()); producer.send(sourceSess.createTextMessage()); sourceConn.close(); Assert.assertEquals(0, messages.size()); Thread.sleep(3 * maxBatchTime); Assert.assertEquals(1, messages.size()); bridge.stop(); Assert.assertFalse(bridge.isStarted()); targetConn.close(); } @Test public void testSendMessagesWithMaxBatchSize() throws Exception { final int numMessages = 10; ConnectionFactoryFactory sourceCFF = JMSBridgeImplTest.newConnectionFactoryFactory(JMSBridgeImplTest.createConnectionFactory()); ConnectionFactoryFactory targetCFF = JMSBridgeImplTest.newConnectionFactoryFactory(JMSBridgeImplTest.createConnectionFactory()); DestinationFactory sourceDF = JMSBridgeImplTest.newDestinationFactory(ActiveMQJMSClient.createQueue(JMSBridgeImplTest.SOURCE)); DestinationFactory targetDF = JMSBridgeImplTest.newDestinationFactory(ActiveMQJMSClient.createQueue(JMSBridgeImplTest.TARGET)); TransactionManager tm = JMSBridgeImplTest.newTransactionManager(); JMSBridgeImpl bridge = new JMSBridgeImpl(); Assert.assertNotNull(bridge); bridge.setSourceConnectionFactoryFactory(sourceCFF); bridge.setSourceDestinationFactory(sourceDF); bridge.setTargetConnectionFactoryFactory(targetCFF); bridge.setTargetDestinationFactory(targetDF); bridge.setFailureRetryInterval(10); bridge.setMaxRetries(-1); bridge.setMaxBatchSize(numMessages); bridge.setMaxBatchTime(-1); bridge.setTransactionManager(tm); bridge.setQualityOfServiceMode(QualityOfServiceMode.AT_MOST_ONCE); Assert.assertFalse(bridge.isStarted()); bridge.start(); Assert.assertTrue(bridge.isStarted()); Connection targetConn = JMSBridgeImplTest.createConnectionFactory().createConnection(); Session targetSess = targetConn.createSession(false, Session.AUTO_ACKNOWLEDGE); MessageConsumer consumer = targetSess.createConsumer(targetDF.createDestination()); final List<Message> messages = new LinkedList<>(); final CountDownLatch latch = new CountDownLatch(numMessages); MessageListener listener = new MessageListener() { @Override public void onMessage(final Message message) { messages.add(message); latch.countDown(); } }; consumer.setMessageListener(listener); targetConn.start(); Connection sourceConn = JMSBridgeImplTest.createConnectionFactory().createConnection(); Session sourceSess = sourceConn.createSession(false, Session.AUTO_ACKNOWLEDGE); MessageProducer producer = sourceSess.createProducer(sourceDF.createDestination()); for (int i = 0; i < numMessages - 1; i++) { TextMessage msg = sourceSess.createTextMessage(); producer.send(msg); JMSBridgeImplTest.log.info("sent message " + i); } Thread.sleep(1000); Assert.assertEquals(0, messages.size()); TextMessage msg = sourceSess.createTextMessage(); producer.send(msg); Assert.assertTrue(latch.await(10000, TimeUnit.MILLISECONDS)); sourceConn.close(); Assert.assertEquals(numMessages, messages.size()); bridge.stop(); Assert.assertFalse(bridge.isStarted()); targetConn.close(); } @Test public void testAutoAckOnSourceBatchOfOne() throws Exception { doTestAutoAckOnSource(1); } @Test public void testAutoAckOnSourceBatchOfTen() throws Exception { doTestAutoAckOnSource(10); } public void doTestAutoAckOnSource(int maxBatchSize) throws Exception { final int numMessages = maxBatchSize; ConnectionFactoryFactory sourceCFF = JMSBridgeImplTest.newConnectionFactoryFactory(JMSBridgeImplTest.createConnectionFactory()); ConnectionFactoryFactory targetCFF = JMSBridgeImplTest.newConnectionFactoryFactory(JMSBridgeImplTest.createConnectionFactory()); DestinationFactory sourceDF = JMSBridgeImplTest.newDestinationFactory(ActiveMQJMSClient.createQueue(JMSBridgeImplTest.SOURCE)); DestinationFactory targetDF = JMSBridgeImplTest.newDestinationFactory(ActiveMQJMSClient.createQueue(JMSBridgeImplTest.TARGET)); TransactionManager tm = JMSBridgeImplTest.newTransactionManager(); JMSBridgeImpl bridge = new JMSBridgeImpl(); Assert.assertNotNull(bridge); bridge.setSourceConnectionFactoryFactory(sourceCFF); bridge.setSourceDestinationFactory(sourceDF); bridge.setTargetConnectionFactoryFactory(targetCFF); bridge.setTargetDestinationFactory(targetDF); bridge.setFailureRetryInterval(10); bridge.setMaxRetries(1); bridge.setMaxBatchSize(maxBatchSize); bridge.setMaxBatchTime(-1); bridge.setTransactionManager(tm); bridge.setQualityOfServiceMode(QualityOfServiceMode.AT_MOST_ONCE); Assert.assertFalse(bridge.isStarted()); bridge.start(); Assert.assertTrue(bridge.isStarted()); Connection sourceConn = JMSBridgeImplTest.createConnectionFactory().createConnection(); Session sourceSess = sourceConn.createSession(false, Session.AUTO_ACKNOWLEDGE); MessageProducer producer = sourceSess.createProducer(sourceDF.createDestination()); for (int i = 0; i < numMessages; i++) { TextMessage msg = sourceSess.createTextMessage(); producer.send(msg); JMSBridgeImplTest.log.info("sent message " + i); } sourceConn.close(); SimpleString add = new SimpleString(JMSBridgeImplTest.SOURCE); QueueControl jmsQueueControl = MBeanServerInvocationHandler.newProxyInstance(ManagementFactory.getPlatformMBeanServer(), ObjectNameBuilder.DEFAULT.getQueueObjectName(add, add, RoutingType.ANYCAST), QueueControl.class, false); assertNotEquals(jmsQueueControl.getDeliveringCount(), numMessages); bridge.stop(); Assert.assertFalse(bridge.isStarted()); } @Test public void testExceptionOnSourceAndRetrySucceeds() throws Exception { final AtomicReference<Connection> sourceConn = new AtomicReference<>(); ActiveMQJMSConnectionFactory failingSourceCF = new ActiveMQJMSConnectionFactory(false, new TransportConfiguration(InVMConnectorFactory.class.getName())) { private static final long serialVersionUID = -8866390811966688830L; @Override public Connection createConnection() throws JMSException { sourceConn.set(super.createConnection()); return sourceConn.get(); } }; // Note! We disable automatic reconnection on the session factory. The bridge needs to do the reconnection failingSourceCF.setReconnectAttempts(0); failingSourceCF.setBlockOnNonDurableSend(true); failingSourceCF.setBlockOnDurableSend(true); ConnectionFactoryFactory sourceCFF = JMSBridgeImplTest.newConnectionFactoryFactory(failingSourceCF); ConnectionFactoryFactory targetCFF = JMSBridgeImplTest.newConnectionFactoryFactory(JMSBridgeImplTest.createConnectionFactory()); DestinationFactory sourceDF = JMSBridgeImplTest.newDestinationFactory(ActiveMQJMSClient.createQueue(JMSBridgeImplTest.SOURCE)); DestinationFactory targetDF = JMSBridgeImplTest.newDestinationFactory(ActiveMQJMSClient.createQueue(JMSBridgeImplTest.TARGET)); TransactionManager tm = JMSBridgeImplTest.newTransactionManager(); JMSBridgeImpl bridge = new JMSBridgeImpl(); Assert.assertNotNull(bridge); bridge.setSourceConnectionFactoryFactory(sourceCFF); bridge.setSourceDestinationFactory(sourceDF); bridge.setTargetConnectionFactoryFactory(targetCFF); bridge.setTargetDestinationFactory(targetDF); bridge.setFailureRetryInterval(10); bridge.setMaxRetries(2); bridge.setMaxBatchSize(1); bridge.setMaxBatchTime(-1); bridge.setTransactionManager(tm); bridge.setQualityOfServiceMode(QualityOfServiceMode.AT_MOST_ONCE); Assert.assertFalse(bridge.isStarted()); bridge.start(); Assert.assertTrue(bridge.isStarted()); sourceConn.get().getExceptionListener().onException(new JMSException("exception on the source")); Thread.sleep(4 * bridge.getFailureRetryInterval()); // reconnection must have succeeded Assert.assertTrue(bridge.isStarted()); bridge.stop(); Assert.assertFalse(bridge.isStarted()); } @Test public void testExceptionOnSourceAndRetryFails() throws Exception { final AtomicReference<Connection> sourceConn = new AtomicReference<>(); ActiveMQJMSConnectionFactory failingSourceCF = new ActiveMQJMSConnectionFactory(false, new TransportConfiguration(INVM_CONNECTOR_FACTORY)) { private static final long serialVersionUID = 8216804886099984645L; boolean firstTime = true; @Override public Connection createConnection() throws JMSException { if (firstTime) { firstTime = false; sourceConn.set(super.createConnection()); return sourceConn.get(); } else { throw new JMSException("exception while retrying to connect"); } } }; // Note! We disable automatic reconnection on the session factory. The bridge needs to do the reconnection failingSourceCF.setReconnectAttempts(0); failingSourceCF.setBlockOnNonDurableSend(true); failingSourceCF.setBlockOnDurableSend(true); ConnectionFactoryFactory sourceCFF = JMSBridgeImplTest.newConnectionFactoryFactory(failingSourceCF); ConnectionFactoryFactory targetCFF = JMSBridgeImplTest.newConnectionFactoryFactory(JMSBridgeImplTest.createConnectionFactory()); DestinationFactory sourceDF = JMSBridgeImplTest.newDestinationFactory(ActiveMQJMSClient.createQueue(JMSBridgeImplTest.SOURCE)); DestinationFactory targetDF = JMSBridgeImplTest.newDestinationFactory(ActiveMQJMSClient.createQueue(JMSBridgeImplTest.TARGET)); TransactionManager tm = JMSBridgeImplTest.newTransactionManager(); JMSBridgeImpl bridge = new JMSBridgeImpl(); Assert.assertNotNull(bridge); bridge.setSourceConnectionFactoryFactory(sourceCFF); bridge.setSourceDestinationFactory(sourceDF); bridge.setTargetConnectionFactoryFactory(targetCFF); bridge.setTargetDestinationFactory(targetDF); bridge.setFailureRetryInterval(100); bridge.setMaxRetries(1); bridge.setMaxBatchSize(1); bridge.setMaxBatchTime(-1); bridge.setTransactionManager(tm); bridge.setQualityOfServiceMode(QualityOfServiceMode.AT_MOST_ONCE); Assert.assertFalse(bridge.isStarted()); bridge.start(); Assert.assertTrue(bridge.isStarted()); sourceConn.get().getExceptionListener().onException(new JMSException("exception on the source")); Thread.sleep(4 * bridge.getFailureRetryInterval()); // reconnection must have failed Assert.assertFalse(bridge.isStarted()); } @Test public void testStartWithSpecificTCCL() throws Exception { MockContextClassLoader mockTccl = setMockTCCL(); try { final AtomicReference<Connection> sourceConn = new AtomicReference<>(); ActiveMQJMSConnectionFactory failingSourceCF = new ActiveMQJMSConnectionFactory(false, new TransportConfiguration(InVMConnectorFactory.class.getName())) { private static final long serialVersionUID = -8866390811966688830L; @Override public Connection createConnection() throws JMSException { sourceConn.set(super.createConnection()); return sourceConn.get(); } }; // Note! We disable automatic reconnection on the session factory. The bridge needs to do the reconnection failingSourceCF.setReconnectAttempts(0); failingSourceCF.setBlockOnNonDurableSend(true); failingSourceCF.setBlockOnDurableSend(true); ConnectionFactoryFactory sourceCFF = JMSBridgeImplTest.newTCCLAwareConnectionFactoryFactory(failingSourceCF); ConnectionFactoryFactory targetCFF = JMSBridgeImplTest.newConnectionFactoryFactory(JMSBridgeImplTest.createConnectionFactory()); DestinationFactory sourceDF = JMSBridgeImplTest.newDestinationFactory(ActiveMQJMSClient.createQueue(JMSBridgeImplTest.SOURCE)); DestinationFactory targetDF = JMSBridgeImplTest.newDestinationFactory(ActiveMQJMSClient.createQueue(JMSBridgeImplTest.TARGET)); TransactionManager tm = JMSBridgeImplTest.newTransactionManager(); JMSBridgeImpl bridge = new JMSBridgeImpl(); Assert.assertNotNull(bridge); bridge.setSourceConnectionFactoryFactory(sourceCFF); bridge.setSourceDestinationFactory(sourceDF); bridge.setTargetConnectionFactoryFactory(targetCFF); bridge.setTargetDestinationFactory(targetDF); bridge.setFailureRetryInterval(10); bridge.setMaxRetries(2); bridge.setMaxBatchSize(1); bridge.setMaxBatchTime(-1); bridge.setTransactionManager(tm); bridge.setQualityOfServiceMode(QualityOfServiceMode.AT_MOST_ONCE); Assert.assertFalse(bridge.isStarted()); bridge.start(); Assert.assertTrue(bridge.isStarted()); unsetMockTCCL(mockTccl); tcclClassFound.set(false); sourceConn.get().getExceptionListener().onException(new JMSException("exception on the source")); Thread.sleep(4 * bridge.getFailureRetryInterval()); // reconnection must have succeeded Assert.assertTrue(bridge.isStarted()); bridge.stop(); Assert.assertFalse(bridge.isStarted()); assertTrue(tcclClassFound.get()); } finally { if (mockTccl != null) unsetMockTCCL(mockTccl); } } // Package protected --------------------------------------------- // Protected ----------------------------------------------------- private static MockContextClassLoader setMockTCCL() { ClassLoader parent = JMSBridgeImpl.class.getClassLoader(); MockContextClassLoader tccl = new MockContextClassLoader(parent); Thread.currentThread().setContextClassLoader(tccl); return tccl; } private static void unsetMockTCCL(MockContextClassLoader mockTccl) { Thread.currentThread().setContextClassLoader(mockTccl.getOriginal()); } @Override @Before public void setUp() throws Exception { super.setUp(); Configuration config = createBasicConfig().addAcceptorConfiguration(new TransportConfiguration(InVMAcceptorFactory.class.getName())); InVMNamingContext context = new InVMNamingContext(); jmsServer = new JMSServerManagerImpl(addServer(ActiveMQServers.newActiveMQServer(config, false))); jmsServer.setRegistry(new JndiBindingRegistry(context)); jmsServer.start(); jmsServer.createQueue(false, JMSBridgeImplTest.SOURCE, null, true, "/queue/" + JMSBridgeImplTest.SOURCE); jmsServer.createQueue(false, JMSBridgeImplTest.TARGET, null, true, "/queue/" + JMSBridgeImplTest.TARGET); } @Test public void testTransactionManagerNotSetForDuplicatesOK() throws Exception { ConnectionFactoryFactory sourceCFF = JMSBridgeImplTest.newConnectionFactoryFactory(JMSBridgeImplTest.createConnectionFactory()); ConnectionFactoryFactory targetCFF = JMSBridgeImplTest.newConnectionFactoryFactory(JMSBridgeImplTest.createConnectionFactory()); DestinationFactory sourceDF = JMSBridgeImplTest.newDestinationFactory(ActiveMQJMSClient.createQueue(JMSBridgeImplTest.SOURCE)); DestinationFactory targetDF = JMSBridgeImplTest.newDestinationFactory(ActiveMQJMSClient.createQueue(JMSBridgeImplTest.TARGET)); JMSBridgeImpl bridge = new JMSBridgeImpl(); Assert.assertNotNull(bridge); bridge.setSourceConnectionFactoryFactory(sourceCFF); bridge.setSourceDestinationFactory(sourceDF); bridge.setTargetConnectionFactoryFactory(targetCFF); bridge.setTargetDestinationFactory(targetDF); bridge.setFailureRetryInterval(10); bridge.setMaxRetries(1); bridge.setMaxBatchTime(-1); bridge.setMaxBatchSize(10); bridge.setQualityOfServiceMode(QualityOfServiceMode.DUPLICATES_OK); Assert.assertFalse(bridge.isStarted()); bridge.start(); Field field = JMSBridgeImpl.class.getDeclaredField("tm"); field.setAccessible(true); assertNull(field.get(bridge)); bridge.stop(); Assert.assertFalse(bridge.isStarted()); } @Test public void testThrowErrorWhenTMNotSetForOnceOnly() throws Exception { thrown.expect(RuntimeException.class); ConnectionFactoryFactory sourceCFF = JMSBridgeImplTest.newConnectionFactoryFactory(JMSBridgeImplTest.createConnectionFactory()); ConnectionFactoryFactory targetCFF = JMSBridgeImplTest.newConnectionFactoryFactory(JMSBridgeImplTest.createConnectionFactory()); DestinationFactory sourceDF = JMSBridgeImplTest.newDestinationFactory(ActiveMQJMSClient.createQueue(JMSBridgeImplTest.SOURCE)); DestinationFactory targetDF = JMSBridgeImplTest.newDestinationFactory(ActiveMQJMSClient.createQueue(JMSBridgeImplTest.TARGET)); JMSBridgeImpl bridge = new JMSBridgeImpl(); Assert.assertNotNull(bridge); bridge.setSourceConnectionFactoryFactory(sourceCFF); bridge.setSourceDestinationFactory(sourceDF); bridge.setTargetConnectionFactoryFactory(targetCFF); bridge.setTargetDestinationFactory(targetDF); bridge.setFailureRetryInterval(10); bridge.setMaxRetries(1); bridge.setMaxBatchTime(-1); bridge.setMaxBatchSize(10); bridge.setQualityOfServiceMode(QualityOfServiceMode.ONCE_AND_ONLY_ONCE); Assert.assertFalse(bridge.isStarted()); bridge.start(); Field field = JMSBridgeImpl.class.getDeclaredField("tm"); field.setAccessible(true); assertNotNull(field.get(bridge)); bridge.stop(); Assert.assertFalse(bridge.isStarted()); } // Private ------------------------------------------------------- // Inner classes ------------------------------------------------- private static class MockContextClassLoader extends ClassLoader { private final ClassLoader original; private final String knownClass = "com.class.only.visible.to.tccl.SomeClass"; private MockContextClassLoader(ClassLoader parent) { super(parent); original = Thread.currentThread().getContextClassLoader(); } public ClassLoader getOriginal() { return original; } @Override protected Class<?> findClass(String name) throws ClassNotFoundException { if (knownClass.equals(name)) { return null; } return super.findClass(name); } } }