/* * 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.cluster.bridge; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import org.apache.activemq.artemis.api.core.ActiveMQBuffer; import org.apache.activemq.artemis.api.core.ActiveMQException; import org.apache.activemq.artemis.api.core.Interceptor; import org.apache.activemq.artemis.api.core.Message; import org.apache.activemq.artemis.api.core.RoutingType; import org.apache.activemq.artemis.api.core.SimpleString; 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.ServerLocator; import org.apache.activemq.artemis.core.config.BridgeConfiguration; import org.apache.activemq.artemis.core.config.Configuration; import org.apache.activemq.artemis.core.config.CoreQueueConfiguration; import org.apache.activemq.artemis.core.io.SequentialFileFactory; import org.apache.activemq.artemis.core.io.nio.NIOSequentialFileFactory; import org.apache.activemq.artemis.core.journal.PreparedTransactionInfo; import org.apache.activemq.artemis.core.journal.RecordInfo; import org.apache.activemq.artemis.core.journal.impl.JournalImpl; import org.apache.activemq.artemis.core.persistence.impl.journal.DescribeJournal; import org.apache.activemq.artemis.core.persistence.impl.journal.JournalRecordIds; import org.apache.activemq.artemis.core.postoffice.DuplicateIDCache; import org.apache.activemq.artemis.core.postoffice.impl.PostOfficeImpl; import org.apache.activemq.artemis.core.protocol.core.Packet; import org.apache.activemq.artemis.core.protocol.core.impl.wireformat.SessionSendContinuationMessage; import org.apache.activemq.artemis.core.protocol.core.impl.wireformat.SessionSendLargeMessage; import org.apache.activemq.artemis.core.protocol.core.impl.wireformat.SessionSendMessage; 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.MessageReference; import org.apache.activemq.artemis.core.server.Queue; import org.apache.activemq.artemis.core.server.cluster.Bridge; import org.apache.activemq.artemis.core.server.cluster.Transformer; import org.apache.activemq.artemis.core.server.cluster.impl.BridgeImpl; import org.apache.activemq.artemis.core.server.impl.ActiveMQServerImpl; import org.apache.activemq.artemis.core.server.impl.ServiceRegistryImpl; import org.apache.activemq.artemis.core.transaction.impl.TransactionImpl; import org.apache.activemq.artemis.spi.core.protocol.RemotingConnection; import org.apache.activemq.artemis.tests.integration.IntegrationTestLogger; import org.apache.activemq.artemis.tests.util.ActiveMQTestBase; import org.apache.activemq.artemis.utils.RandomUtil; import org.apache.activemq.artemis.utils.ReusableLatch; import org.apache.activemq.artemis.utils.collections.LinkedListIterator; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @RunWith(value = Parameterized.class) public class BridgeTest extends ActiveMQTestBase { private ActiveMQServer server0; private ActiveMQServer server1; private ServerLocator locator; private final boolean netty; @Parameterized.Parameters(name = "isNetty={0}") public static Collection getParameters() { return Arrays.asList(new Object[][]{{true}, {false}}); } public BridgeTest(boolean isNetty) { this.netty = isNetty; } protected boolean isNetty() { return netty; } @Override @Before public void setUp() throws Exception { StopInterceptor.reset(); super.setUp(); } private String getConnector() { if (isNetty()) { return NETTY_CONNECTOR_FACTORY; } else { return INVM_CONNECTOR_FACTORY; } } @Test public void testSimpleBridge() throws Exception { internaltestSimpleBridge(false, false); } @Test public void testSimpleBridgeFiles() throws Exception { internaltestSimpleBridge(false, true); } @Test public void testSimpleBridgeLargeMessageNullPersistence() throws Exception { internaltestSimpleBridge(true, false); } @Test public void testSimpleBridgeLargeMessageFiles() throws Exception { internaltestSimpleBridge(true, true); } @Test public void testLargeMessageBridge() throws Exception { long time = System.currentTimeMillis(); Map<String, Object> server0Params = new HashMap<>(); server0 = createClusteredServerWithParams(isNetty(), 0, true, server0Params); Map<String, Object> server1Params = new HashMap<>(); addTargetParameters(server1Params); server1 = createClusteredServerWithParams(isNetty(), 1, true, server1Params); final String testAddress = "testAddress"; final String queueName0 = "queue0"; final String forwardAddress = "forwardAddress"; final String queueName1 = "queue1"; TransportConfiguration server0tc = new TransportConfiguration(getConnector(), server0Params); TransportConfiguration server1tc = new TransportConfiguration(getConnector(), server1Params); HashMap<String, TransportConfiguration> connectors = new HashMap<>(); connectors.put(server1tc.getName(), server1tc); server0.getConfiguration().setConnectorConfigurations(connectors); final int messageSize = 1024 * 200; final int numMessages = 10; ArrayList<String> connectorConfig = new ArrayList<>(); connectorConfig.add(server1tc.getName()); BridgeConfiguration bridgeConfiguration = new BridgeConfiguration().setName("bridge1").setQueueName(queueName0).setForwardingAddress(forwardAddress).setRetryInterval(1000).setReconnectAttemptsOnSameNode(-1).setUseDuplicateDetection(false).setConfirmationWindowSize(numMessages * messageSize / 2).setStaticConnectors(connectorConfig); List<BridgeConfiguration> bridgeConfigs = new ArrayList<>(); bridgeConfigs.add(bridgeConfiguration); server0.getConfiguration().setBridgeConfigurations(bridgeConfigs); CoreQueueConfiguration queueConfig0 = new CoreQueueConfiguration().setAddress(testAddress).setName(queueName0); List<CoreQueueConfiguration> queueConfigs0 = new ArrayList<>(); queueConfigs0.add(queueConfig0); server0.getConfiguration().setQueueConfigurations(queueConfigs0); CoreQueueConfiguration queueConfig1 = new CoreQueueConfiguration().setAddress(forwardAddress).setName(queueName1); List<CoreQueueConfiguration> queueConfigs1 = new ArrayList<>(); queueConfigs1.add(queueConfig1); server1.getConfiguration().setQueueConfigurations(queueConfigs1); server1.start(); server0.start(); locator = addServerLocator(ActiveMQClient.createServerLocatorWithoutHA(server0tc, server1tc)); ClientSessionFactory sf0 = addSessionFactory(locator.createSessionFactory(server0tc)); ClientSessionFactory sf1 = addSessionFactory(locator.createSessionFactory(server1tc)); ClientSession session0 = sf0.createSession(false, true, true); ClientSession session1 = sf1.createSession(false, true, true); ClientProducer producer0 = session0.createProducer(new SimpleString(testAddress)); ClientConsumer consumer1 = session1.createConsumer(queueName1); session1.start(); final byte[] bytes = new byte[messageSize]; final SimpleString propKey = new SimpleString("testkey"); for (int i = 0; i < numMessages; i++) { ClientMessage message = session0.createMessage(true); message.putIntProperty(propKey, i); message.getBodyBuffer().writeBytes(bytes); producer0.send(message); } for (int i = 0; i < numMessages; i++) { ClientMessage message = consumer1.receive(5000); Assert.assertNotNull(message); Assert.assertEquals(i, message.getObjectProperty(propKey)); readLargeMessages(message, 10); message.acknowledge(); } Assert.assertNull(consumer1.receiveImmediate()); session0.close(); session1.close(); sf0.close(); sf1.close(); closeFields(); if (server0.getConfiguration().isPersistenceEnabled()) { assertEquals(0, loadQueues(server0).size()); } long timeTaken = System.currentTimeMillis() - time; System.out.println(timeTaken + "ms"); } public void internaltestSimpleBridge(final boolean largeMessage, final boolean useFiles) throws Exception { Map<String, Object> server0Params = new HashMap<>(); server0 = createClusteredServerWithParams(isNetty(), 0, useFiles, server0Params); Map<String, Object> server1Params = new HashMap<>(); addTargetParameters(server1Params); server1 = createClusteredServerWithParams(isNetty(), 1, useFiles, server1Params); final String testAddress = "testAddress"; final String queueName0 = "queue0"; final String forwardAddress = "forwardAddress"; final String queueName1 = "queue1"; // Map<String, TransportConfiguration> connectors = new HashMap<String, TransportConfiguration>(); TransportConfiguration server0tc = new TransportConfiguration(getConnector(), server0Params); TransportConfiguration server1tc = new TransportConfiguration(getConnector(), server1Params); HashMap<String, TransportConfiguration> connectors = new HashMap<>(); connectors.put(server1tc.getName(), server1tc); server0.getConfiguration().setConnectorConfigurations(connectors); final int messageSize = 1024; final int numMessages = 10; ArrayList<String> connectorConfig = new ArrayList<>(); connectorConfig.add(server1tc.getName()); BridgeConfiguration bridgeConfiguration = new BridgeConfiguration().setName("bridge1").setQueueName(queueName0).setForwardingAddress(forwardAddress).setRetryInterval(1000).setReconnectAttemptsOnSameNode(-1).setUseDuplicateDetection(false).setConfirmationWindowSize(numMessages * messageSize / 2).setStaticConnectors(connectorConfig); List<BridgeConfiguration> bridgeConfigs = new ArrayList<>(); bridgeConfigs.add(bridgeConfiguration); server0.getConfiguration().setBridgeConfigurations(bridgeConfigs); CoreQueueConfiguration queueConfig0 = new CoreQueueConfiguration().setAddress(testAddress).setName(queueName0); List<CoreQueueConfiguration> queueConfigs0 = new ArrayList<>(); queueConfigs0.add(queueConfig0); server0.getConfiguration().setQueueConfigurations(queueConfigs0); CoreQueueConfiguration queueConfig1 = new CoreQueueConfiguration().setAddress(forwardAddress).setName(queueName1); List<CoreQueueConfiguration> queueConfigs1 = new ArrayList<>(); queueConfigs1.add(queueConfig1); server1.getConfiguration().setQueueConfigurations(queueConfigs1); server1.start(); server0.start(); locator = addServerLocator(ActiveMQClient.createServerLocatorWithoutHA(server0tc, server1tc)); ClientSessionFactory sf0 = addSessionFactory(locator.createSessionFactory(server0tc)); ClientSessionFactory sf1 = addSessionFactory(locator.createSessionFactory(server1tc)); ClientSession session0 = sf0.createSession(false, true, true); ClientSession session1 = sf1.createSession(false, true, true); ClientProducer producer0 = session0.createProducer(new SimpleString(testAddress)); ClientConsumer consumer1 = session1.createConsumer(queueName1); session1.start(); final byte[] bytes = new byte[messageSize]; final SimpleString propKey = new SimpleString("testkey"); for (int i = 0; i < numMessages; i++) { ClientMessage message = session0.createMessage(true); if (largeMessage) { message.setBodyInputStream(ActiveMQTestBase.createFakeLargeStream(10 * 1024)); } message.putIntProperty(propKey, i); message.getBodyBuffer().writeBytes(bytes); producer0.send(message); } for (int i = 0; i < numMessages; i++) { ClientMessage message = consumer1.receive(5000); Assert.assertNotNull(message); Assert.assertEquals(i, message.getObjectProperty(propKey)); if (largeMessage) { readLargeMessages(message, 10); } message.acknowledge(); } Assert.assertNull(consumer1.receiveImmediate()); session0.close(); session1.close(); sf0.close(); sf1.close(); closeFields(); if (server0.getConfiguration().isPersistenceEnabled()) { assertEquals(0, loadQueues(server0).size()); } } @Test public void testLostMessageSimpleMessage() throws Exception { internalTestMessageLoss(false); } @Test public void testLostMessageLargeMessage() throws Exception { internalTestMessageLoss(true); } /** * This test will ignore messages * What will cause the bridge to fail with a timeout * The bridge should still recover the failure and reconnect on that case */ public void internalTestMessageLoss(final boolean largeMessage) throws Exception { class MyInterceptor implements Interceptor { public boolean ignoreSends = true; public CountDownLatch latch; MyInterceptor(int numberOfIgnores) { latch = new CountDownLatch(numberOfIgnores); } @Override public boolean intercept(Packet packet, RemotingConnection connection) throws ActiveMQException { if (ignoreSends && packet instanceof SessionSendMessage || ignoreSends && packet instanceof SessionSendLargeMessage || ignoreSends && packet instanceof SessionSendContinuationMessage && !((SessionSendContinuationMessage) packet).isContinues()) { IntegrationTestLogger.LOGGER.info("IGNORED: " + packet); latch.countDown(); return false; } else { IntegrationTestLogger.LOGGER.info(packet); return true; } } } MyInterceptor myInterceptor = new MyInterceptor(3); Map<String, Object> server0Params = new HashMap<>(); server0 = createClusteredServerWithParams(isNetty(), 0, true, server0Params); Map<String, Object> server1Params = new HashMap<>(); addTargetParameters(server1Params); server1 = createClusteredServerWithParams(isNetty(), 1, true, server1Params); final String testAddress = "testAddress"; final String queueName0 = "queue0"; final String forwardAddress = "forwardAddress"; final String queueName1 = "queue1"; TransportConfiguration server0tc = new TransportConfiguration(getConnector(), server0Params); TransportConfiguration server1tc = new TransportConfiguration(getConnector(), server1Params); HashMap<String, TransportConfiguration> connectors = new HashMap<>(); connectors.put(server1tc.getName(), server1tc); server0.getConfiguration().setConnectorConfigurations(connectors); final int messageSize = 1024; final int numMessages = 1; ArrayList<String> connectorConfig = new ArrayList<>(); connectorConfig.add(server1tc.getName()); BridgeConfiguration bridgeConfiguration = new BridgeConfiguration().setName("bridge1").setQueueName(queueName0).setForwardingAddress(forwardAddress).setRetryInterval(100).setReconnectAttempts(-1).setReconnectAttemptsOnSameNode(-1).setUseDuplicateDetection(false).setConfirmationWindowSize(numMessages * messageSize / 2).setStaticConnectors(connectorConfig).setCallTimeout(500); List<BridgeConfiguration> bridgeConfigs = new ArrayList<>(); bridgeConfigs.add(bridgeConfiguration); server0.getConfiguration().setBridgeConfigurations(bridgeConfigs); CoreQueueConfiguration queueConfig0 = new CoreQueueConfiguration().setAddress(testAddress).setName(queueName0); List<CoreQueueConfiguration> queueConfigs0 = new ArrayList<>(); queueConfigs0.add(queueConfig0); server0.getConfiguration().setQueueConfigurations(queueConfigs0); CoreQueueConfiguration queueConfig1 = new CoreQueueConfiguration().setAddress(forwardAddress).setName(queueName1); List<CoreQueueConfiguration> queueConfigs1 = new ArrayList<>(); queueConfigs1.add(queueConfig1); server1.getConfiguration().setQueueConfigurations(queueConfigs1); server1.start(); server1.getRemotingService().addIncomingInterceptor(myInterceptor); server0.start(); locator = addServerLocator(ActiveMQClient.createServerLocatorWithoutHA(server0tc, server1tc)); ClientSessionFactory sf0 = addSessionFactory(locator.createSessionFactory(server0tc)); ClientSessionFactory sf1 = addSessionFactory(locator.createSessionFactory(server1tc)); ClientSession session0 = sf0.createSession(false, true, true); ClientSession session1 = sf1.createSession(false, true, true); ClientProducer producer0 = session0.createProducer(new SimpleString(testAddress)); ClientConsumer consumer1 = session1.createConsumer(queueName1); session1.start(); final byte[] bytes = new byte[messageSize]; final SimpleString propKey = new SimpleString("testkey"); for (int i = 0; i < numMessages; i++) { ClientMessage message = session0.createMessage(true); if (largeMessage) { message.setBodyInputStream(ActiveMQTestBase.createFakeLargeStream(10 * 1024)); } message.putIntProperty(propKey, i); message.getBodyBuffer().writeBytes(bytes); producer0.send(message); } assertTrue("where is the countDown?", myInterceptor.latch.await(30, TimeUnit.SECONDS)); myInterceptor.ignoreSends = false; server1.getRemotingService().removeIncomingInterceptor(myInterceptor); IntegrationTestLogger.LOGGER.info("No longer ignoring packets."); for (int i = 0; i < numMessages; i++) { ClientMessage message = consumer1.receive(30000); Assert.assertNotNull(message); Assert.assertEquals(i, message.getObjectProperty(propKey)); if (largeMessage) { readLargeMessages(message, 10); } message.acknowledge(); } Assert.assertNull(consumer1.receiveImmediate()); session0.close(); session1.close(); sf0.close(); sf1.close(); closeFields(); assertEquals("there should be no queues", 0, loadQueues(server0).size()); } /** * @param server1Params */ private void addTargetParameters(final Map<String, Object> server1Params) { if (isNetty()) { server1Params.put("port", org.apache.activemq.artemis.core.remoting.impl.netty.TransportConstants.DEFAULT_PORT + 1); } else { server1Params.put(TransportConstants.SERVER_ID_PROP_NAME, 1); } } /** * @param message */ private void readLargeMessages(final ClientMessage message, int kiloBlocks) { byte[] byteRead = new byte[1024]; for (int j = 0; j < kiloBlocks; j++) { message.getBodyBuffer().readBytes(byteRead); } } @Test public void testWithFilter() throws Exception { internalTestWithFilter(false, false); } @Test public void testWithFilterFiles() throws Exception { internalTestWithFilter(false, true); } @Test public void testWithFilterLargeMessages() throws Exception { internalTestWithFilter(true, false); } @Test public void testWithFilterLargeMessagesFiles() throws Exception { internalTestWithFilter(true, true); } public void internalTestWithFilter(final boolean largeMessage, final boolean useFiles) throws Exception { final int numMessages = 10; Map<String, Object> server0Params = new HashMap<>(); server0 = createClusteredServerWithParams(isNetty(), 0, useFiles, server0Params); Map<String, Object> server1Params = new HashMap<>(); addTargetParameters(server1Params); server1 = createClusteredServerWithParams(isNetty(), 1, useFiles, server1Params); final String testAddress = "testAddress"; final String queueName0 = "queue0"; final String forwardAddress = "forwardAddress"; final String queueName1 = "queue1"; Map<String, TransportConfiguration> connectors = new HashMap<>(); TransportConfiguration server0tc = new TransportConfiguration(getConnector(), server0Params); TransportConfiguration server1tc = new TransportConfiguration(getConnector(), server1Params); connectors.put(server1tc.getName(), server1tc); server0.getConfiguration().setConnectorConfigurations(connectors); final String filterString = "animal='goat'"; ArrayList<String> staticConnectors = new ArrayList<>(); staticConnectors.add(server1tc.getName()); BridgeConfiguration bridgeConfiguration = new BridgeConfiguration().setName("bridge1").setQueueName(queueName0).setForwardingAddress(forwardAddress).setFilterString(filterString).setRetryInterval(1000).setReconnectAttemptsOnSameNode(-1).setUseDuplicateDetection(false).setConfirmationWindowSize(0).setStaticConnectors(staticConnectors); List<BridgeConfiguration> bridgeConfigs = new ArrayList<>(); bridgeConfigs.add(bridgeConfiguration); server0.getConfiguration().setBridgeConfigurations(bridgeConfigs); CoreQueueConfiguration queueConfig0 = new CoreQueueConfiguration().setAddress(testAddress).setName(queueName0); List<CoreQueueConfiguration> queueConfigs0 = new ArrayList<>(); queueConfigs0.add(queueConfig0); server0.getConfiguration().setQueueConfigurations(queueConfigs0); CoreQueueConfiguration queueConfig1 = new CoreQueueConfiguration().setAddress(forwardAddress).setName(queueName1); List<CoreQueueConfiguration> queueConfigs1 = new ArrayList<>(); queueConfigs1.add(queueConfig1); server1.getConfiguration().setQueueConfigurations(queueConfigs1); server1.start(); server0.start(); locator = addServerLocator(ActiveMQClient.createServerLocatorWithoutHA(server0tc, server1tc)); ClientSessionFactory sf0 = locator.createSessionFactory(server0tc); ClientSessionFactory sf1 = locator.createSessionFactory(server1tc); ClientSession session0 = sf0.createSession(false, true, true); ClientSession session1 = sf1.createSession(false, true, true); ClientProducer producer0 = session0.createProducer(new SimpleString(testAddress)); ClientConsumer consumer1 = session1.createConsumer(queueName1); session1.start(); final SimpleString propKey = new SimpleString("testkey"); final SimpleString selectorKey = new SimpleString("animal"); for (int i = 0; i < numMessages; i++) { ClientMessage message = session0.createMessage(true); message.putIntProperty(propKey, i); message.putStringProperty(selectorKey, new SimpleString("monkey")); if (largeMessage) { message.setBodyInputStream(ActiveMQTestBase.createFakeLargeStream(10 * 1024)); } producer0.send(message); } Assert.assertNull(consumer1.receiveImmediate()); for (int i = 0; i < numMessages; i++) { ClientMessage message = session0.createMessage(true); message.putIntProperty(propKey, i); message.putStringProperty(selectorKey, new SimpleString("goat")); if (largeMessage) { message.setBodyInputStream(ActiveMQTestBase.createFakeLargeStream(10 * 1024)); } producer0.send(message); } for (int i = 0; i < numMessages; i++) { ClientMessage message = consumer1.receive(4000); Assert.assertNotNull(message); Assert.assertEquals("goat", message.getStringProperty(selectorKey)); Assert.assertEquals(i, message.getObjectProperty(propKey)); message.acknowledge(); if (largeMessage) { readLargeMessages(message, 10); } } session0.commit(); session1.commit(); Assert.assertNull(consumer1.receiveImmediate()); session0.close(); session1.close(); sf0.close(); sf1.close(); closeFields(); if (useFiles) { Map<Long, AtomicInteger> counters = loadQueues(server0); assertEquals(1, counters.size()); Long key = counters.keySet().iterator().next(); AtomicInteger value = counters.get(key); assertNotNull(value); assertEquals(numMessages, counters.get(key).intValue()); } } // Created to verify JBPAPP-6057 @Test public void testStartLater() throws Exception { Map<String, Object> server0Params = new HashMap<>(); server0 = createClusteredServerWithParams(isNetty(), 0, true, server0Params); Map<String, Object> server1Params = new HashMap<>(); addTargetParameters(server1Params); server1 = createClusteredServerWithParams(isNetty(), 1, true, server1Params); final String testAddress = "testAddress"; final String queueName0 = "queue0"; final String forwardAddress = "forwardAddress"; final String queueName1 = "forwardAddress"; Map<String, TransportConfiguration> connectors = new HashMap<>(); TransportConfiguration server0tc = new TransportConfiguration(getConnector(), server0Params); TransportConfiguration server1tc = new TransportConfiguration(getConnector(), server1Params); connectors.put(server1tc.getName(), server1tc); server0.getConfiguration().setConnectorConfigurations(connectors); ArrayList<String> staticConnectors = new ArrayList<>(); staticConnectors.add(server1tc.getName()); BridgeConfiguration bridgeConfiguration = new BridgeConfiguration().setName("bridge1").setQueueName(queueName0).setForwardingAddress(forwardAddress).setRetryInterval(100).setReconnectAttemptsOnSameNode(-1).setUseDuplicateDetection(false).setConfirmationWindowSize(1024).setStaticConnectors(staticConnectors); List<BridgeConfiguration> bridgeConfigs = new ArrayList<>(); bridgeConfigs.add(bridgeConfiguration); server0.getConfiguration().setBridgeConfigurations(bridgeConfigs); CoreQueueConfiguration queueConfig0 = new CoreQueueConfiguration().setAddress(testAddress).setName(queueName0); List<CoreQueueConfiguration> queueConfigs0 = new ArrayList<>(); queueConfigs0.add(queueConfig0); server0.getConfiguration().setQueueConfigurations(queueConfigs0); server0.start(); locator = addServerLocator(ActiveMQClient.createServerLocatorWithoutHA(server0tc, server1tc)); ClientSessionFactory sf0 = locator.createSessionFactory(server0tc); ClientSession session0 = sf0.createSession(false, true, true); ClientProducer producer0 = session0.createProducer(new SimpleString(testAddress)); final int numMessages = 100; final SimpleString propKey = new SimpleString("testkey"); final SimpleString selectorKey = new SimpleString("animal"); for (int i = 0; i < numMessages; i++) { ClientMessage message = session0.createMessage(true); message.getBodyBuffer().writeBytes(new byte[1024]); message.putIntProperty(propKey, i); message.putStringProperty(selectorKey, new SimpleString("monkey" + i)); producer0.send(message); } server1.start(); Thread.sleep(1000); ClientSessionFactory sf1 = locator.createSessionFactory(server1tc); ClientSession session1 = sf1.createSession(false, true, true); try { session1.createQueue(forwardAddress, RoutingType.ANYCAST, queueName1); } catch (Throwable ignored) { ignored.printStackTrace(); } ClientConsumer consumer1 = session1.createConsumer(queueName1); session1.start(); for (int i = 0; i < numMessages; i++) { ClientMessage message = consumer1.receive(5000); assertNotNull(message); message.acknowledge(); } session1.commit(); Assert.assertNull(consumer1.receiveImmediate()); consumer1.close(); session1.deleteQueue(queueName1); session1.close(); sf1.close(); server1.stop(); session0.close(); sf0.close(); closeFields(); assertEquals(0, loadQueues(server0).size()); } @Test public void testWithDuplicates() throws Exception { Map<String, Object> server0Params = new HashMap<>(); server0 = createClusteredServerWithParams(isNetty(), 0, true, server0Params); Map<String, Object> server1Params = new HashMap<>(); addTargetParameters(server1Params); server1 = createClusteredServerWithParams(isNetty(), 1, true, server1Params); final String testAddress = "testAddress"; final String queueName0 = "queue0"; final String forwardAddress = "forwardAddress"; final String queueName1 = "forwardQueue"; Map<String, TransportConfiguration> connectors = new HashMap<>(); TransportConfiguration server0tc = new TransportConfiguration(getConnector(), server0Params); TransportConfiguration server1tc = new TransportConfiguration(getConnector(), server1Params); connectors.put(server1tc.getName(), server1tc); server0.getConfiguration().setConnectorConfigurations(connectors); ArrayList<String> staticConnectors = new ArrayList<>(); staticConnectors.add(server1tc.getName()); BridgeConfiguration bridgeConfiguration = new BridgeConfiguration().setName("bridge1").setQueueName(queueName0).setForwardingAddress(forwardAddress).setRetryInterval(100).setReconnectAttemptsOnSameNode(-1).setConfirmationWindowSize(0).setStaticConnectors(staticConnectors); List<BridgeConfiguration> bridgeConfigs = new ArrayList<>(); bridgeConfigs.add(bridgeConfiguration); server0.getConfiguration().setBridgeConfigurations(bridgeConfigs); CoreQueueConfiguration queueConfig0 = new CoreQueueConfiguration().setAddress(testAddress).setName(queueName0); List<CoreQueueConfiguration> queueConfigs0 = new ArrayList<>(); queueConfigs0.add(queueConfig0); server0.getConfiguration().setQueueConfigurations(queueConfigs0); server0.start(); locator = addServerLocator(ActiveMQClient.createServerLocatorWithoutHA(server0tc, server1tc)); ClientSessionFactory sf0 = locator.createSessionFactory(server0tc); ClientSession session0 = sf0.createSession(false, true, true); ClientProducer producer0 = session0.createProducer(new SimpleString(testAddress)); final int numMessages = 1000; final SimpleString propKey = new SimpleString("testkey"); final SimpleString selectorKey = new SimpleString("animal"); for (int i = 0; i < numMessages; i++) { ClientMessage message = session0.createMessage(true); message.getBodyBuffer().writeBytes(new byte[1024]); message.putIntProperty(propKey, i); message.putStringProperty(selectorKey, new SimpleString("monkey" + i)); producer0.send(message); } server1.start(); // Inserting the duplicateIDs so the bridge will fail in a few { long[] ids = new long[100]; Queue queue = server0.locateQueue(new SimpleString(queueName0)); LinkedListIterator<MessageReference> iterator = queue.iterator(); for (int i = 0; i < 100; i++) { iterator.hasNext(); ids[i] = iterator.next().getMessage().getMessageID(); } iterator.close(); DuplicateIDCache duplicateTargetCache = server1.getPostOffice().getDuplicateIDCache(PostOfficeImpl.BRIDGE_CACHE_STR.concat(forwardAddress)); TransactionImpl tx = new TransactionImpl(server1.getStorageManager()); for (long id : ids) { byte[] duplicateArray = BridgeImpl.getDuplicateBytes(server0.getNodeManager().getUUID(), id); duplicateTargetCache.addToCache(duplicateArray, tx); } tx.commit(); } Thread.sleep(1000); ClientSessionFactory sf1 = locator.createSessionFactory(server1tc); ClientSession session1 = sf1.createSession(false, true, true); try { session1.createQueue(forwardAddress, RoutingType.ANYCAST, queueName1); } catch (Throwable ignored) { ignored.printStackTrace(); } ClientConsumer consumer1 = session1.createConsumer(queueName1); session1.start(); for (int i = 100; i < numMessages; i++) { ClientMessage message = consumer1.receive(5000); assertNotNull(message); assertEquals(i, message.getIntProperty(propKey).intValue()); message.acknowledge(); } session1.commit(); Assert.assertNull(consumer1.receiveImmediate()); consumer1.close(); session1.deleteQueue(queueName1); session1.close(); sf1.close(); server1.stop(); session0.close(); sf0.close(); closeFields(); assertEquals(0, loadQueues(server0).size()); } private void closeFields() throws Exception { locator.close(); server0.stop(); server1.stop(); } @Test public void testWithTransformer() throws Exception { internaltestWithTransformer(false); } @Test public void testWithTransformerFiles() throws Exception { internaltestWithTransformer(true); } public void internaltestWithTransformer(final boolean useFiles) throws Exception { Map<String, Object> server0Params = new HashMap<>(); server0 = createClusteredServerWithParams(isNetty(), 0, false, server0Params); Map<String, Object> server1Params = new HashMap<>(); addTargetParameters(server1Params); server1 = createClusteredServerWithParams(isNetty(), 1, false, server1Params); final String testAddress = "testAddress"; final String queueName0 = "queue0"; final String forwardAddress = "forwardAddress"; final String queueName1 = "queue1"; Map<String, TransportConfiguration> connectors = new HashMap<>(); TransportConfiguration server0tc = new TransportConfiguration(getConnector(), server0Params); TransportConfiguration server1tc = new TransportConfiguration(getConnector(), server1Params); connectors.put(server1tc.getName(), server1tc); server0.getConfiguration().setConnectorConfigurations(connectors); ArrayList<String> staticConnectors = new ArrayList<>(); staticConnectors.add(server1tc.getName()); BridgeConfiguration bridgeConfiguration = new BridgeConfiguration().setName("bridge1").setQueueName(queueName0).setForwardingAddress(forwardAddress).setTransformerClassName(SimpleTransformer.class.getName()).setRetryInterval(1000).setReconnectAttemptsOnSameNode(-1).setUseDuplicateDetection(false).setConfirmationWindowSize(1024).setStaticConnectors(staticConnectors); List<BridgeConfiguration> bridgeConfigs = new ArrayList<>(); bridgeConfigs.add(bridgeConfiguration); server0.getConfiguration().setBridgeConfigurations(bridgeConfigs); CoreQueueConfiguration queueConfig0 = new CoreQueueConfiguration().setAddress(testAddress).setName(queueName0); List<CoreQueueConfiguration> queueConfigs0 = new ArrayList<>(); queueConfigs0.add(queueConfig0); server0.getConfiguration().setQueueConfigurations(queueConfigs0); CoreQueueConfiguration queueConfig1 = new CoreQueueConfiguration().setAddress(forwardAddress).setName(queueName1); List<CoreQueueConfiguration> queueConfigs1 = new ArrayList<>(); queueConfigs1.add(queueConfig1); server1.getConfiguration().setQueueConfigurations(queueConfigs1); server1.start(); server0.start(); locator = addServerLocator(ActiveMQClient.createServerLocatorWithoutHA(server0tc, server1tc)); ClientSessionFactory sf0 = locator.createSessionFactory(server0tc); ClientSessionFactory sf1 = locator.createSessionFactory(server1tc); ClientSession session0 = sf0.createSession(false, true, true); ClientSession session1 = sf1.createSession(false, true, true); ClientProducer producer0 = session0.createProducer(new SimpleString(testAddress)); ClientConsumer consumer1 = session1.createConsumer(queueName1); session1.start(); final int numMessages = 10; final SimpleString propKey = new SimpleString("wibble"); for (int i = 0; i < numMessages; i++) { ClientMessage message = session0.createMessage(true); message.putStringProperty(propKey, new SimpleString("bing")); message.getBodyBuffer().writeString("doo be doo be doo be doo"); producer0.send(message); } for (int i = 0; i < numMessages; i++) { ClientMessage message = consumer1.receive(200); Assert.assertNotNull(message); SimpleString val = (SimpleString) message.getObjectProperty(propKey); Assert.assertEquals(new SimpleString("bong"), val); String sval = message.getBodyBuffer().readString(); Assert.assertEquals("dee be dee be dee be dee", sval); message.acknowledge(); } Assert.assertNull(consumer1.receiveImmediate()); session0.close(); session1.close(); sf0.close(); sf1.close(); if (server0.getConfiguration().isPersistenceEnabled()) { assertEquals(0, loadQueues(server0).size()); } } @Test public void testSawtoothLoad() throws Exception { Map<String, Object> server0Params = new HashMap<>(); ActiveMQServer server0 = createClusteredServerWithParams(isNetty(), 0, true, server0Params); server0.getConfiguration().setThreadPoolMaxSize(10); Map<String, Object> server1Params = new HashMap<>(); addTargetParameters(server1Params); ActiveMQServer server1 = createClusteredServerWithParams(isNetty(), 1, true, server1Params); server1.getConfiguration().setThreadPoolMaxSize(10); final String testAddress = "testAddress"; final String queueName0 = "queue0"; final String forwardAddress = "forwardAddress"; final String queueName1 = "queue1"; Map<String, TransportConfiguration> connectors = new HashMap<>(); final TransportConfiguration server0tc = new TransportConfiguration(getConnector(), server0Params); final TransportConfiguration server1tc = new TransportConfiguration(getConnector(), server1Params); connectors.put(server1tc.getName(), server1tc); server0.getConfiguration().setConnectorConfigurations(connectors); ArrayList<String> staticConnectors = new ArrayList<>(); staticConnectors.add(server1tc.getName()); BridgeConfiguration bridgeConfiguration = new BridgeConfiguration().setName("bridge1").setQueueName(queueName0).setForwardingAddress(forwardAddress).setRetryInterval(1000).setReconnectAttemptsOnSameNode(-1).setUseDuplicateDetection(false).setConfirmationWindowSize(0).setStaticConnectors(staticConnectors); List<BridgeConfiguration> bridgeConfigs = new ArrayList<>(); bridgeConfigs.add(bridgeConfiguration); server0.getConfiguration().setBridgeConfigurations(bridgeConfigs); CoreQueueConfiguration queueConfig0 = new CoreQueueConfiguration().setAddress(testAddress).setName(queueName0); List<CoreQueueConfiguration> queueConfigs0 = new ArrayList<>(); queueConfigs0.add(queueConfig0); server0.getConfiguration().setQueueConfigurations(queueConfigs0); CoreQueueConfiguration queueConfig1 = new CoreQueueConfiguration().setAddress(forwardAddress).setName(queueName1); List<CoreQueueConfiguration> queueConfigs1 = new ArrayList<>(); queueConfigs1.add(queueConfig1); server1.getConfiguration().setQueueConfigurations(queueConfigs1); try { server1.start(); server0.start(); final int numMessages = 300; final int totalrepeats = 3; final AtomicInteger errors = new AtomicInteger(0); // We shouldn't have more than 10K messages pending final Semaphore semop = new Semaphore(10000); class ConsumerThread extends Thread { @Override public void run() { try { ServerLocator locator = addServerLocator(ActiveMQClient.createServerLocatorWithoutHA(server1tc)); ClientSessionFactory sf = createSessionFactory(locator); ClientSession session = sf.createSession(false, false); session.start(); ClientConsumer consumer = session.createConsumer(queueName1); for (int i = 0; i < numMessages; i++) { ClientMessage message = consumer.receive(5000); Assert.assertNotNull(message); message.acknowledge(); semop.release(); if (i % 1000 == 0) { session.commit(); } } session.commit(); session.close(); sf.close(); locator.close(); } catch (Throwable e) { e.printStackTrace(); errors.incrementAndGet(); } } } class ProducerThread extends Thread { final int nmsg; ProducerThread(int nmsg) { this.nmsg = nmsg; } @Override public void run() { ServerLocator locator = addServerLocator(ActiveMQClient.createServerLocatorWithoutHA(server0tc)); locator.setBlockOnDurableSend(false).setBlockOnNonDurableSend(false); ClientSessionFactory sf = null; ClientSession session = null; ClientProducer producer = null; try { sf = createSessionFactory(locator); session = sf.createSession(false, true, true); producer = session.createProducer(new SimpleString(testAddress)); for (int i = 0; i < nmsg; i++) { assertEquals(0, errors.get()); ClientMessage message = session.createMessage(true); message.putIntProperty("seq", i); if (i % 100 == 0) { message.setPriority((byte) (RandomUtil.randomPositiveInt() % 9)); } else { message.setPriority((byte) 5); } message.getBodyBuffer().writeBytes(new byte[50]); producer.send(message); assertTrue(semop.tryAcquire(1, 10, TimeUnit.SECONDS)); } } catch (Throwable e) { e.printStackTrace(System.out); errors.incrementAndGet(); } finally { try { session.close(); sf.close(); locator.close(); } catch (Exception ignored) { errors.incrementAndGet(); } } } } for (int repeat = 0; repeat < totalrepeats; repeat++) { ArrayList<Thread> threads = new ArrayList<>(); threads.add(new ConsumerThread()); threads.add(new ProducerThread(numMessages / 2)); threads.add(new ProducerThread(numMessages / 2)); for (Thread t : threads) { t.start(); } for (Thread t : threads) { t.join(); } assertEquals(0, errors.get()); } } finally { try { server0.stop(); } catch (Exception ignored) { } try { server1.stop(); } catch (Exception ignored) { } } assertEquals(0, loadQueues(server0).size()); } @Test public void testBridgeWithPaging() throws Exception { ActiveMQServer server0 = null; ActiveMQServer server1 = null; final int PAGE_MAX = 10 * 1024; final int PAGE_SIZE = 1 * 1024; try { Map<String, Object> server0Params = new HashMap<>(); server0 = createClusteredServerWithParams(isNetty(), 0, true, PAGE_SIZE, PAGE_MAX, server0Params); Map<String, Object> server1Params = new HashMap<>(); addTargetParameters(server1Params); server1 = createClusteredServerWithParams(isNetty(), 1, true, PAGE_SIZE, PAGE_MAX, server1Params); server1.getConfiguration().setJournalBufferTimeout_AIO(10).setJournalBufferTimeout_NIO(10); final String testAddress = "testAddress"; final String queueName0 = "queue0"; final String forwardAddress = "forwardAddress"; final String queueName1 = "queue1"; Map<String, TransportConfiguration> connectors = new HashMap<>(); TransportConfiguration server0tc = new TransportConfiguration(getConnector(), server0Params); TransportConfiguration server1tc = new TransportConfiguration(getConnector(), server1Params); connectors.put(server1tc.getName(), server1tc); server0.getConfiguration().setConnectorConfigurations(connectors); server0.getConfiguration().setIDCacheSize(20000).setJournalBufferTimeout_NIO(10).setJournalBufferTimeout_AIO(10); ArrayList<String> staticConnectors = new ArrayList<>(); staticConnectors.add(server1tc.getName()); BridgeConfiguration bridgeConfiguration = new BridgeConfiguration().setName("bridge1").setQueueName(queueName0).setForwardingAddress(forwardAddress).setRetryInterval(1).setReconnectAttemptsOnSameNode(-1).setUseDuplicateDetection(false).setConfirmationWindowSize(1).setStaticConnectors(staticConnectors); bridgeConfiguration.setCallTimeout(1000); bridgeConfiguration.setUseDuplicateDetection(true); List<BridgeConfiguration> bridgeConfigs = new ArrayList<>(); bridgeConfigs.add(bridgeConfiguration); server0.getConfiguration().setBridgeConfigurations(bridgeConfigs); CoreQueueConfiguration queueConfig0 = new CoreQueueConfiguration().setAddress(testAddress).setName(queueName0); List<CoreQueueConfiguration> queueConfigs0 = new ArrayList<>(); queueConfigs0.add(queueConfig0); server0.getConfiguration().setQueueConfigurations(queueConfigs0); CoreQueueConfiguration queueConfig1 = new CoreQueueConfiguration().setAddress(forwardAddress).setName(queueName1); List<CoreQueueConfiguration> queueConfigs1 = new ArrayList<>(); queueConfigs1.add(queueConfig1); server1.getConfiguration().setQueueConfigurations(queueConfigs1); List<String> interceptorToStop = new ArrayList<>(); interceptorToStop.add(StopInterceptor.class.getName()); server1.getConfiguration().setIncomingInterceptorClassNames(interceptorToStop); StopInterceptor.serverToStop = server0; server1.start(); server0.start(); locator = addServerLocator(ActiveMQClient.createServerLocatorWithoutHA(server0tc, server1tc)); ClientSessionFactory sf0 = locator.createSessionFactory(server0tc); ClientSessionFactory sf1 = locator.createSessionFactory(server1tc); ClientSession session0 = sf0.createSession(false, false, true); ClientSession session1 = sf1.createSession(false, true, true); ClientProducer producer0 = session0.createProducer(new SimpleString(testAddress)); ClientConsumer consumer1 = session1.createConsumer(queueName1); session1.start(); final int numMessages = 200; final SimpleString propKey = new SimpleString("testkey"); for (int i = 0; i < numMessages; i++) { ClientMessage message = session0.createMessage(true); message.getBodyBuffer().writeBytes(new byte[512]); message.putIntProperty(propKey, i); producer0.send(message); } session0.commit(); assertTrue(StopInterceptor.latch.await(1, TimeUnit.HOURS)); StopInterceptor.thread.join(15000); if (StopInterceptor.thread.isAlive()) { System.out.println(threadDump("Still alive, stop didn't work!!!")); fail("Thread that should restart the server still alive"); } // Restarting the server server0.start(); HashMap<Integer, AtomicInteger> receivedMsg = new HashMap<>(); for (int i = 0; i < numMessages; i++) { ClientMessage message = consumer1.receive(5000); if (message == null) { break; } Integer msgKey = message.getIntProperty(propKey); AtomicInteger msgCount = receivedMsg.get(msgKey); if (msgKey.intValue() != i) { System.err.println("Message " + msgCount + " received out of order, expected to be " + i + " it's acceptable but not the ideal!"); } if (msgCount == null) { msgCount = new AtomicInteger(); receivedMsg.put(msgKey, msgCount); } msgCount.incrementAndGet(); if (i % 500 == 0) System.out.println("received " + i); } boolean failed = false; if (consumer1.receiveImmediate() != null) { System.err.println("Unexpected message received"); failed = true; } for (int i = 0; i < numMessages; i++) { AtomicInteger msgCount = receivedMsg.get(Integer.valueOf(i)); if (msgCount == null) { System.err.println("Msg " + i + " wasn't received"); failed = true; } else if (msgCount.get() > 1) { System.err.println("msg " + i + " was received " + msgCount.get() + " times"); failed = true; } } assertFalse("Test failed", failed); session0.close(); session1.close(); sf0.close(); sf1.close(); } finally { if (locator != null) { locator.close(); } try { server0.stop(); } catch (Throwable ignored) { } try { server1.stop(); } catch (Throwable ignored) { } } assertEquals(0, loadQueues(server0).size()); } // Stops a server after 100 messages received public static class StopInterceptor implements Interceptor { static ActiveMQServer serverToStop; static Thread thread; static final ReusableLatch latch = new ReusableLatch(0); public static void reset() { latch.setCount(1); serverToStop = null; count = 0; thread = null; } static int count = 0; @Override public synchronized boolean intercept(Packet packet, RemotingConnection connection) throws ActiveMQException { if (packet instanceof SessionSendMessage && ++count == 100) { try { System.out.println("Stopping server after " + count + " messages"); thread = new Thread("***Server Restarter***") { @Override public void run() { try { System.out.println("Stopping server"); latch.countDown(); serverToStop.stop(false); } catch (Exception e) { e.printStackTrace(); } } }; thread.start(); latch.await(); return true; } catch (Exception e) { e.printStackTrace(); } } return true; } } @Test public void testBridgeWithLargeMessage() throws Exception { ActiveMQServer server0 = null; ActiveMQServer server1 = null; final int PAGE_MAX = 1024 * 1024; final int PAGE_SIZE = 10 * 1024; ServerLocator locator = null; try { Map<String, Object> server0Params = new HashMap<>(); server0 = createClusteredServerWithParams(isNetty(), 0, true, PAGE_SIZE, PAGE_MAX, server0Params); Map<String, Object> server1Params = new HashMap<>(); addTargetParameters(server1Params); server1 = createClusteredServerWithParams(isNetty(), 1, true, server1Params); final String testAddress = "testAddress"; final String queueName0 = "queue0"; final String forwardAddress = "forwardAddress"; final String queueName1 = "queue1"; Map<String, TransportConfiguration> connectors = new HashMap<>(); TransportConfiguration server0tc = new TransportConfiguration(getConnector(), server0Params); TransportConfiguration server1tc = new TransportConfiguration(getConnector(), server1Params); connectors.put(server1tc.getName(), server1tc); server0.getConfiguration().setConnectorConfigurations(connectors); ArrayList<String> staticConnectors = new ArrayList<>(); staticConnectors.add(server1tc.getName()); BridgeConfiguration bridgeConfiguration = new BridgeConfiguration().setName("bridge1").setQueueName(queueName0).setForwardingAddress(forwardAddress).setRetryInterval(1000).setReconnectAttemptsOnSameNode(-1).setUseDuplicateDetection(false).setConfirmationWindowSize(1024).setStaticConnectors(staticConnectors); List<BridgeConfiguration> bridgeConfigs = new ArrayList<>(); bridgeConfigs.add(bridgeConfiguration); server0.getConfiguration().setBridgeConfigurations(bridgeConfigs); CoreQueueConfiguration queueConfig0 = new CoreQueueConfiguration().setAddress(testAddress).setName(queueName0); List<CoreQueueConfiguration> queueConfigs0 = new ArrayList<>(); queueConfigs0.add(queueConfig0); server0.getConfiguration().setQueueConfigurations(queueConfigs0); CoreQueueConfiguration queueConfig1 = new CoreQueueConfiguration().setAddress(forwardAddress).setName(queueName1); List<CoreQueueConfiguration> queueConfigs1 = new ArrayList<>(); queueConfigs1.add(queueConfig1); server1.getConfiguration().setQueueConfigurations(queueConfigs1); server1.start(); server0.start(); locator = addServerLocator(ActiveMQClient.createServerLocatorWithoutHA(server0tc, server1tc)); ClientSessionFactory sf0 = locator.createSessionFactory(server0tc); ClientSessionFactory sf1 = locator.createSessionFactory(server1tc); ClientSession session0 = sf0.createSession(false, true, true); ClientSession session1 = sf1.createSession(false, true, true); ClientProducer producer0 = session0.createProducer(new SimpleString(testAddress)); ClientConsumer consumer1 = session1.createConsumer(queueName1); session1.start(); final int numMessages = 50; final SimpleString propKey = new SimpleString("testkey"); final int LARGE_MESSAGE_SIZE = 1024; for (int i = 0; i < numMessages; i++) { ClientMessage message = session0.createMessage(true); message.setBodyInputStream(createFakeLargeStream(LARGE_MESSAGE_SIZE)); message.putIntProperty(propKey, i); producer0.send(message); } session0.commit(); for (int i = 0; i < numMessages; i++) { ClientMessage message = consumer1.receive(5000); Assert.assertNotNull(message); Assert.assertEquals(i, message.getObjectProperty(propKey)); ActiveMQBuffer buff = message.getBodyBuffer(); for (int posMsg = 0; posMsg < LARGE_MESSAGE_SIZE; posMsg++) { assertEquals(getSamplebyte(posMsg), buff.readByte()); } message.acknowledge(); } session1.commit(); Assert.assertNull(consumer1.receiveImmediate()); session0.close(); session1.close(); sf0.close(); sf1.close(); } finally { if (locator != null) { locator.close(); } try { server0.stop(); } catch (Throwable ignored) { } try { server1.stop(); } catch (Throwable ignored) { } } assertEquals(0, loadQueues(server0).size()); } @Test public void testBridgeWithVeryLargeMessage() throws Exception { ActiveMQServer server0 = null; ActiveMQServer server1 = null; final int PAGE_MAX = 1024 * 1024; final int PAGE_SIZE = 10 * 1024; ServerLocator locator = null; try { Map<String, Object> server0Params = new HashMap<>(); server0 = createClusteredServerWithParams(isNetty(), 0, true, PAGE_SIZE, PAGE_MAX, server0Params); Map<String, Object> server1Params = new HashMap<>(); addTargetParameters(server1Params); server1 = createClusteredServerWithParams(isNetty(), 1, true, server1Params); final String testAddress = "testAddress"; final String queueName0 = "queue0"; final String forwardAddress = "forwardAddress"; final String queueName1 = "queue1"; Map<String, TransportConfiguration> connectors = new HashMap<>(); TransportConfiguration server0tc = new TransportConfiguration(getConnector(), server0Params); TransportConfiguration server1tc = new TransportConfiguration(getConnector(), server1Params); connectors.put(server1tc.getName(), server1tc); server0.getConfiguration().setConnectorConfigurations(connectors); ArrayList<String> staticConnectors = new ArrayList<>(); staticConnectors.add(server1tc.getName()); int minLargeMessageSize = 1024 * 1024; BridgeConfiguration bridgeConfiguration = new BridgeConfiguration().setName("bridge1").setQueueName(queueName0).setForwardingAddress(forwardAddress).setRetryInterval(1000).setReconnectAttemptsOnSameNode(-1).setUseDuplicateDetection(false).setConfirmationWindowSize(1024).setStaticConnectors(staticConnectors).setMinLargeMessageSize(minLargeMessageSize).setProducerWindowSize(minLargeMessageSize / 2); List<BridgeConfiguration> bridgeConfigs = new ArrayList<>(); bridgeConfigs.add(bridgeConfiguration); server0.getConfiguration().setBridgeConfigurations(bridgeConfigs); CoreQueueConfiguration queueConfig0 = new CoreQueueConfiguration().setAddress(testAddress).setName(queueName0); List<CoreQueueConfiguration> queueConfigs0 = new ArrayList<>(); queueConfigs0.add(queueConfig0); server0.getConfiguration().setQueueConfigurations(queueConfigs0); CoreQueueConfiguration queueConfig1 = new CoreQueueConfiguration().setAddress(forwardAddress).setName(queueName1); List<CoreQueueConfiguration> queueConfigs1 = new ArrayList<>(); queueConfigs1.add(queueConfig1); server1.getConfiguration().setQueueConfigurations(queueConfigs1); server1.start(); server0.start(); locator = addServerLocator(ActiveMQClient.createServerLocatorWithoutHA(server0tc, server1tc)); ClientSessionFactory sf0 = locator.createSessionFactory(server0tc); ClientSessionFactory sf1 = locator.createSessionFactory(server1tc); ClientSession session0 = sf0.createSession(false, true, true); ClientSession session1 = sf1.createSession(false, true, true); ClientProducer producer0 = session0.createProducer(new SimpleString(testAddress)); ClientConsumer consumer1 = session1.createConsumer(queueName1); session1.start(); //create a large message bigger than Integer.MAX_VALUE final long largeMessageSize = Integer.MAX_VALUE + 1000L; ClientMessage largeMessage = createLargeMessage(session0, largeMessageSize); producer0.send(largeMessage); session0.commit(); //check target queue for large message arriving ClientSession.QueueQuery query = session1.queueQuery(new SimpleString(queueName1)); long messageCount = query.getMessageCount(); int count = 0; //wait for 300 sec max while (messageCount == 0 && count < 300) { count++; Thread.sleep(1000); query = session1.queueQuery(new SimpleString(queueName1)); messageCount = query.getMessageCount(); } if (messageCount == 0) { fail("large message didn't arrived after 5 min!"); } //receive the message ClientMessage message = consumer1.receive(5000); message.acknowledge(); File outputFile = new File(getTemporaryDir(), "huge_message_received.dat"); System.out.println("-----message save to: " + outputFile.getAbsolutePath()); FileOutputStream fileOutputStream = new FileOutputStream(outputFile); BufferedOutputStream bufferedOutput = new BufferedOutputStream(fileOutputStream); message.setOutputStream(bufferedOutput); if (!message.waitOutputStreamCompletion(5 * 60 * 1000)) { fail("message didn't get received to disk in 5 min. Is the machine slow?"); } session1.commit(); Assert.assertNull(consumer1.receiveImmediate()); session0.close(); session1.close(); sf0.close(); sf1.close(); } finally { if (locator != null) { locator.close(); } try { server0.stop(); } catch (Throwable ignored) { } try { server1.stop(); } catch (Throwable ignored) { } } assertEquals(0, loadQueues(server0).size()); } private ClientMessage createLargeMessage(ClientSession session, long largeMessageSize) throws Exception { File fileInput = new File(getTemporaryDir(), "huge_message_to_send.dat"); createFile(fileInput, largeMessageSize); System.out.println("File created at: " + fileInput.getAbsolutePath()); ClientMessage message = session.createMessage(Message.BYTES_TYPE, true); FileInputStream fileInputStream = new FileInputStream(fileInput); BufferedInputStream bufferedInput = new BufferedInputStream(fileInputStream); message.setBodyInputStream(bufferedInput); return message; } private static void createFile(final File file, final long fileSize) throws IOException { if (file.exists()) { System.out.println("---file already there " + file.length()); return; } FileOutputStream fileOut = new FileOutputStream(file); BufferedOutputStream buffOut = new BufferedOutputStream(fileOut); byte[] outBuffer = new byte[1024 * 1024]; System.out.println(" --- creating file, size: " + fileSize); for (long i = 0; i < fileSize; i += outBuffer.length) { buffOut.write(outBuffer); } buffOut.close(); } @Test public void testNullForwardingAddress() throws Exception { Map<String, Object> server0Params = new HashMap<>(); server0 = createClusteredServerWithParams(isNetty(), 0, false, server0Params); Map<String, Object> server1Params = new HashMap<>(); addTargetParameters(server1Params); server1 = createClusteredServerWithParams(isNetty(), 1, false, server1Params); final String testAddress = "testAddress"; final String queueName0 = "queue0"; final String queueName1 = "queue1"; Map<String, TransportConfiguration> connectors = new HashMap<>(); TransportConfiguration server0tc = new TransportConfiguration(getConnector(), server0Params); TransportConfiguration server1tc = new TransportConfiguration(getConnector(), server1Params); connectors.put(server1tc.getName(), server1tc); server0.getConfiguration().setConnectorConfigurations(connectors); final int messageSize = 1024; final int numMessages = 10; ArrayList<String> staticConnectors = new ArrayList<>(); staticConnectors.add(server1tc.getName()); // do not set forwarding address (defaults to null) to use messages' original address BridgeConfiguration bridgeConfiguration = new BridgeConfiguration().setName("bridge1").setQueueName(queueName0).setRetryInterval(1000).setReconnectAttemptsOnSameNode(-1).setUseDuplicateDetection(false).setConfirmationWindowSize(numMessages * messageSize / 2).setStaticConnectors(staticConnectors); List<BridgeConfiguration> bridgeConfigs = new ArrayList<>(); bridgeConfigs.add(bridgeConfiguration); server0.getConfiguration().setBridgeConfigurations(bridgeConfigs); CoreQueueConfiguration queueConfig0 = new CoreQueueConfiguration().setAddress(testAddress).setName(queueName0); List<CoreQueueConfiguration> queueConfigs0 = new ArrayList<>(); queueConfigs0.add(queueConfig0); server0.getConfiguration().setQueueConfigurations(queueConfigs0); // on server #1, we bind queueName1 to same address testAddress CoreQueueConfiguration queueConfig1 = new CoreQueueConfiguration().setAddress(testAddress).setName(queueName1); List<CoreQueueConfiguration> queueConfigs1 = new ArrayList<>(); queueConfigs1.add(queueConfig1); server1.getConfiguration().setQueueConfigurations(queueConfigs1); server1.start(); server0.start(); locator = addServerLocator(ActiveMQClient.createServerLocatorWithoutHA(server0tc, server1tc)); ClientSessionFactory sf0 = locator.createSessionFactory(server0tc); ClientSessionFactory sf1 = locator.createSessionFactory(server1tc); ClientSession session0 = sf0.createSession(false, true, true); ClientSession session1 = sf1.createSession(false, true, true); ClientProducer producer0 = session0.createProducer(new SimpleString(testAddress)); ClientConsumer consumer1 = session1.createConsumer(queueName1); session1.start(); final byte[] bytes = new byte[messageSize]; final SimpleString propKey = new SimpleString("testkey"); for (int i = 0; i < numMessages; i++) { ClientMessage message = session0.createMessage(true); message.putIntProperty(propKey, i); message.getBodyBuffer().writeBytes(bytes); producer0.send(message); } for (int i = 0; i < numMessages; i++) { ClientMessage message = consumer1.receive(200); Assert.assertNotNull(message); Assert.assertEquals(i, message.getObjectProperty(propKey)); message.acknowledge(); } Assert.assertNull(consumer1.receiveImmediate()); session0.close(); session1.close(); sf0.close(); sf1.close(); closeFields(); } @Test public void testInjectedTransformer() throws Exception { final SimpleString ADDRESS = new SimpleString("myAddress"); final SimpleString QUEUE = new SimpleString("myQueue"); final String BRIDGE = "myBridge"; ServiceRegistryImpl serviceRegistry = new ServiceRegistryImpl(); Transformer transformer = (Message encode) -> null; serviceRegistry.addBridgeTransformer(BRIDGE, transformer); Configuration config = createDefaultInVMConfig().addConnectorConfiguration("in-vm", new TransportConfiguration(INVM_CONNECTOR_FACTORY)); ActiveMQServer server = addServer(new ActiveMQServerImpl(config, null, null, null, serviceRegistry)); server.start(); server.waitForActivation(100, TimeUnit.MILLISECONDS); server.createQueue(ADDRESS, RoutingType.ANYCAST, QUEUE, null, false, false); List<String> connectors = new ArrayList<>(); connectors.add("in-vm"); server.deployBridge(new BridgeConfiguration().setName(BRIDGE).setQueueName(QUEUE.toString()).setForwardingAddress(ADDRESS.toString()).setStaticConnectors(connectors)); Bridge bridge = server.getClusterManager().getBridges().get(BRIDGE); assertNotNull(bridge); assertEquals(transformer, ((BridgeImpl) bridge).getTransformer()); } /** * It will inspect the journal directly and determine if there are queues on this journal, * * @param serverToInvestigate * @return a Map containing the reference counts per queue * @throws Exception */ protected Map<Long, AtomicInteger> loadQueues(ActiveMQServer serverToInvestigate) throws Exception { SequentialFileFactory messagesFF = new NIOSequentialFileFactory(serverToInvestigate.getConfiguration().getJournalLocation(), 1); JournalImpl messagesJournal = new JournalImpl(serverToInvestigate.getConfiguration().getJournalFileSize(), serverToInvestigate.getConfiguration().getJournalMinFiles(), serverToInvestigate.getConfiguration().getJournalPoolFiles(), 0, 0, messagesFF, "activemq-data", "amq", 1); List<RecordInfo> records = new LinkedList<>(); List<PreparedTransactionInfo> preparedTransactions = new LinkedList<>(); messagesJournal.start(); messagesJournal.load(records, preparedTransactions, null); // These are more immutable integers Map<Long, AtomicInteger> messageRefCounts = new HashMap<>(); for (RecordInfo info : records) { Object o = DescribeJournal.newObjectEncoding(info); if (info.getUserRecordType() == JournalRecordIds.ADD_REF) { DescribeJournal.ReferenceDescribe ref = (DescribeJournal.ReferenceDescribe) o; AtomicInteger count = messageRefCounts.get(ref.refEncoding.queueID); if (count == null) { count = new AtomicInteger(1); messageRefCounts.put(ref.refEncoding.queueID, count); } else { count.incrementAndGet(); } } } messagesJournal.stop(); return messageRefCounts; } }