/* * 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.extras.jms.bridge; import javax.jms.ConnectionFactory; import javax.jms.Destination; import javax.naming.Context; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import com.arjuna.ats.arjuna.coordinator.TransactionReaper; import com.arjuna.ats.arjuna.coordinator.TxControl; import org.apache.activemq.artemis.api.core.ActiveMQException; import org.apache.activemq.artemis.api.core.TransportConfiguration; import org.apache.activemq.artemis.api.core.client.ActiveMQClient; import org.apache.activemq.artemis.api.core.client.ClientConsumer; import org.apache.activemq.artemis.api.core.client.ClientMessage; import org.apache.activemq.artemis.api.core.client.ClientProducer; import org.apache.activemq.artemis.api.core.client.ClientSession; import org.apache.activemq.artemis.api.core.client.ClientSessionFactory; import org.apache.activemq.artemis.api.core.client.FailoverEventListener; import org.apache.activemq.artemis.api.core.client.FailoverEventType; import org.apache.activemq.artemis.api.core.client.ServerLocator; 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.config.ha.ReplicaPolicyConfiguration; import org.apache.activemq.artemis.core.config.ha.ReplicatedPolicyConfiguration; import org.apache.activemq.artemis.core.registry.JndiBindingRegistry; import org.apache.activemq.artemis.core.remoting.impl.invm.TransportConstants; import org.apache.activemq.artemis.core.server.ActiveMQServer; import org.apache.activemq.artemis.core.server.ActiveMQServers; import org.apache.activemq.artemis.jms.bridge.ConnectionFactoryFactory; import org.apache.activemq.artemis.jms.bridge.DestinationFactory; import org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory; import org.apache.activemq.artemis.jms.server.JMSServerManager; import org.apache.activemq.artemis.jms.server.impl.JMSServerManagerImpl; import org.apache.activemq.artemis.tests.unit.util.InVMContext; import org.apache.activemq.artemis.tests.util.ActiveMQTestBase; import org.junit.After; import org.junit.Before; /** * A ClusteredBridgeTestBase * This class serves as a base class for jms bridge tests in * clustered scenarios. */ public abstract class ClusteredBridgeTestBase extends ActiveMQTestBase { private static int index = 0; protected Map<String, ServerGroup> groups = new HashMap<>(); @Override @Before public void setUp() throws Exception { super.setUp(); Iterator<ServerGroup> iter = groups.values().iterator(); while (iter.hasNext()) { iter.next().start(); } TxControl.enable(); } @Override @After public void tearDown() throws Exception { Iterator<ServerGroup> iter = groups.values().iterator(); while (iter.hasNext()) { iter.next().stop(); } TxControl.disable(true); TransactionReaper.terminate(false); super.tearDown(); } //create a live/backup pair. protected ServerGroup createServerGroup(String name) throws Exception { ServerGroup server = groups.get(name); if (server == null) { server = new ServerGroup(name, groups.size()); server.create(); groups.put(name, server); } return server; } //each ServerGroup represents a live/backup pair protected class ServerGroup { private static final int ID_OFFSET = 100; private String name; private int id; private JMSServerManager liveNode; private JMSServerManager backupNode; private TransportConfiguration liveConnector; private TransportConfiguration backupConnector; private Context liveContext; private ServerLocator locator; private ClientSessionFactory sessionFactory; /** * @param name - name of the group * @param id - id of the live (should be < 100) */ public ServerGroup(String name, int id) { this.name = name; this.id = id; } public String getName() { return name; } public void create() throws Exception { Map<String, Object> params0 = new HashMap<>(); params0.put(TransportConstants.SERVER_ID_PROP_NAME, id); liveConnector = new TransportConfiguration(INVM_CONNECTOR_FACTORY, params0, "in-vm-live"); Map<String, Object> params = new HashMap<>(); params.put(TransportConstants.SERVER_ID_PROP_NAME, id + ID_OFFSET); backupConnector = new TransportConfiguration(INVM_CONNECTOR_FACTORY, params, "in-vm-backup"); //live Configuration conf0 = createBasicConfig().setJournalDirectory(getJournalDir(id, false)).setBindingsDirectory(getBindingsDir(id, false)).addAcceptorConfiguration(new TransportConfiguration(INVM_ACCEPTOR_FACTORY, params0)).addConnectorConfiguration(liveConnector.getName(), liveConnector).setHAPolicyConfiguration(new ReplicatedPolicyConfiguration()).addClusterConfiguration(basicClusterConnectionConfig(liveConnector.getName())); ActiveMQServer server0 = addServer(ActiveMQServers.newActiveMQServer(conf0, true)); liveContext = new InVMContext(); liveNode = new JMSServerManagerImpl(server0); liveNode.setRegistry(new JndiBindingRegistry(liveContext)); //backup Configuration config = createBasicConfig().setJournalDirectory(getJournalDir(id, true)).setBindingsDirectory(getBindingsDir(id, true)).addAcceptorConfiguration(new TransportConfiguration(INVM_ACCEPTOR_FACTORY, params)).addConnectorConfiguration(backupConnector.getName(), backupConnector).addConnectorConfiguration(liveConnector.getName(), liveConnector).setHAPolicyConfiguration(new ReplicaPolicyConfiguration()).addClusterConfiguration(basicClusterConnectionConfig(backupConnector.getName(), liveConnector.getName())); ActiveMQServer backup = addServer(ActiveMQServers.newActiveMQServer(config, true)); Context context = new InVMContext(); backupNode = new JMSServerManagerImpl(backup); backupNode.setRegistry(new JndiBindingRegistry(context)); } public void start() throws Exception { liveNode.start(); waitForServerToStart(liveNode.getActiveMQServer()); backupNode.start(); waitForRemoteBackupSynchronization(backupNode.getActiveMQServer()); locator = ActiveMQClient.createServerLocatorWithHA(liveConnector).setReconnectAttempts(-1); sessionFactory = locator.createSessionFactory(); } public void stop() throws Exception { sessionFactory.close(); locator.close(); liveNode.stop(); backupNode.stop(); } public void createQueue(String queueName) throws Exception { liveNode.createQueue(true, queueName, null, true, "/queue/" + queueName); } public ConnectionFactoryFactory getConnectionFactoryFactory() { ConnectionFactoryFactory cff = new ConnectionFactoryFactory() { @Override public ConnectionFactory createConnectionFactory() throws Exception { ActiveMQConnectionFactory cf = ActiveMQJMSClient.createConnectionFactoryWithHA(JMSFactoryType.XA_CF, liveConnector); cf.getServerLocator().setReconnectAttempts(-1); return cf; } }; return cff; } public DestinationFactory getDestinationFactory(final String queueName) { DestinationFactory destFactory = new DestinationFactory() { @Override public Destination createDestination() throws Exception { return (Destination) liveContext.lookup("/queue/" + queueName); } }; return destFactory; } public void sendMessages(String queueName, int num) throws ActiveMQException { ClientSession session = sessionFactory.createSession(); ClientProducer producer = session.createProducer(queueName); for (int i = 0; i < num; i++) { ClientMessage m = session.createMessage(true); m.putStringProperty("bridge-message", "hello " + index); index++; producer.send(m); } session.close(); } public void receiveMessages(String queueName, int num, boolean checkDup) throws ActiveMQException { ClientSession session = sessionFactory.createSession(); session.start(); ClientConsumer consumer = session.createConsumer(queueName); for (int i = 0; i < num; i++) { ClientMessage m = consumer.receive(30000); assertNotNull("i=" + i, m); assertNotNull(m.getStringProperty("bridge-message")); m.acknowledge(); } ClientMessage m = consumer.receive(500); if (checkDup) { assertNull(m); } else { //drain messages while (m != null) { m = consumer.receive(200); } } session.close(); } public void crashLive() throws Exception { final CountDownLatch latch = new CountDownLatch(1); sessionFactory.addFailoverListener(new FailoverEventListener() { @Override public void failoverEvent(FailoverEventType eventType) { if (eventType == FailoverEventType.FAILOVER_COMPLETED) { latch.countDown(); } } }); liveNode.getActiveMQServer().stop(); boolean ok = latch.await(10000, TimeUnit.MILLISECONDS); assertTrue(ok); } } }