/** * 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.network; import javax.jms.Connection; import javax.jms.DeliveryMode; 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.jms.TopicRequestor; import javax.jms.TopicSession; import java.net.URI; import java.util.Arrays; import java.util.concurrent.ConcurrentMap; import org.apache.activemq.ActiveMQConnection; import org.apache.activemq.ActiveMQConnectionFactory; import org.apache.activemq.broker.BrokerService; import org.apache.activemq.command.ActiveMQDestination; import org.apache.activemq.command.ActiveMQMessage; import org.apache.activemq.command.ActiveMQTopic; import org.apache.activemq.command.ConsumerId; import org.apache.activemq.util.Wait; import org.apache.activemq.xbean.BrokerFactoryBean; import org.junit.After; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.support.AbstractApplicationContext; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; public class SimpleNetworkTest { protected static final int MESSAGE_COUNT = 10; private static final Logger LOG = LoggerFactory.getLogger(SimpleNetworkTest.class); protected AbstractApplicationContext context; protected Connection localConnection; protected Connection remoteConnection; protected BrokerService localBroker; protected BrokerService remoteBroker; protected Session localSession; protected Session remoteSession; protected ActiveMQTopic included; protected ActiveMQTopic excluded; protected String consumerName = "durableSubs"; // works b/c of non marshaling vm transport, the connection // ref from the client is used during the forward @Test(timeout = 60 * 1000) public void testMessageCompression() throws Exception { ActiveMQConnection localAmqConnection = (ActiveMQConnection) localConnection; localAmqConnection.setUseCompression(true); MessageConsumer consumer1 = remoteSession.createConsumer(included); MessageProducer producer = localSession.createProducer(included); producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); waitForConsumerRegistration(localBroker, 1, included); for (int i = 0; i < MESSAGE_COUNT; i++) { Message test = localSession.createTextMessage("test-" + i); producer.send(test); Message msg = consumer1.receive(3000); assertNotNull(msg); ActiveMQMessage amqMessage = (ActiveMQMessage) msg; assertTrue(amqMessage.isCompressed()); } // ensure no more messages received assertNull(consumer1.receive(1000)); } @Test(timeout = 60 * 1000) public void testRequestReply() throws Exception { final MessageProducer remoteProducer = remoteSession.createProducer(null); MessageConsumer remoteConsumer = remoteSession.createConsumer(included); remoteConsumer.setMessageListener(new MessageListener() { @Override public void onMessage(Message msg) { try { TextMessage textMsg = (TextMessage) msg; String payload = "REPLY: " + textMsg.getText(); Destination replyTo; replyTo = msg.getJMSReplyTo(); textMsg.clearBody(); textMsg.setText(payload); remoteProducer.send(replyTo, textMsg); } catch (JMSException e) { e.printStackTrace(); } } }); TopicRequestor requestor = new TopicRequestor((TopicSession) localSession, included); // allow for consumer infos to perculate around Thread.sleep(5000); for (int i = 0; i < MESSAGE_COUNT; i++) { TextMessage msg = localSession.createTextMessage("test msg: " + i); TextMessage result = (TextMessage) requestor.request(msg); assertNotNull(result); LOG.info(result.getText()); } } @Test(timeout = 60 * 1000) public void testFiltering() throws Exception { MessageConsumer includedConsumer = remoteSession.createConsumer(included); MessageConsumer excludedConsumer = remoteSession.createConsumer(excluded); MessageProducer includedProducer = localSession.createProducer(included); MessageProducer excludedProducer = localSession.createProducer(excluded); // allow for consumer infos to perculate around Thread.sleep(2000); Message test = localSession.createTextMessage("test"); includedProducer.send(test); excludedProducer.send(test); assertNull(excludedConsumer.receive(1000)); assertNotNull(includedConsumer.receive(1000)); } @Test(timeout = 60 * 1000) public void testConduitBridge() throws Exception { MessageConsumer consumer1 = remoteSession.createConsumer(included); MessageConsumer consumer2 = remoteSession.createConsumer(included); MessageProducer producer = localSession.createProducer(included); producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); waitForConsumerRegistration(localBroker, 2, included); for (int i = 0; i < MESSAGE_COUNT; i++) { Message test = localSession.createTextMessage("test-" + i); producer.send(test); assertNotNull(consumer1.receive(1000)); assertNotNull(consumer2.receive(1000)); } // ensure no more messages received assertNull(consumer1.receive(1000)); assertNull(consumer2.receive(1000)); } private void waitForConsumerRegistration(final BrokerService brokerService, final int min, final ActiveMQDestination destination) throws Exception { assertTrue("Internal bridge consumers registered in time", Wait.waitFor(new Wait.Condition() { @Override public boolean isSatisified() throws Exception { Object[] bridges = brokerService.getNetworkConnectors().get(0).bridges.values().toArray(); if (bridges.length > 0) { LOG.info(brokerService + " bridges " + Arrays.toString(bridges)); DemandForwardingBridgeSupport demandForwardingBridgeSupport = (DemandForwardingBridgeSupport) bridges[0]; ConcurrentMap<ConsumerId, DemandSubscription> forwardingBridges = demandForwardingBridgeSupport.getLocalSubscriptionMap(); LOG.info(brokerService + " bridge " + demandForwardingBridgeSupport + ", localSubs: " + forwardingBridges); if (!forwardingBridges.isEmpty()) { for (DemandSubscription demandSubscription : forwardingBridges.values()) { if (demandSubscription.getLocalInfo().getDestination().equals(destination)) { LOG.info(brokerService + " DemandSubscription " + demandSubscription + ", size: " + demandSubscription.size()); return demandSubscription.size() >= min; } } } } return false; } })); } @Test(timeout = 60 * 1000) public void testDurableStoreAndForward() throws Exception { // create a remote durable consumer MessageConsumer remoteConsumer = remoteSession.createDurableSubscriber(included, consumerName); Thread.sleep(1000); // now close everything down and restart doTearDown(); doSetUp(false); MessageProducer producer = localSession.createProducer(included); for (int i = 0; i < MESSAGE_COUNT; i++) { Message test = localSession.createTextMessage("test-" + i); producer.send(test); } Thread.sleep(1000); // close everything down and restart doTearDown(); doSetUp(false); remoteConsumer = remoteSession.createDurableSubscriber(included, consumerName); for (int i = 0; i < MESSAGE_COUNT; i++) { assertNotNull("message count: " + i, remoteConsumer.receive(2500)); } } @Ignore("This seems like a simple use case, but it is problematic to consume an existing topic store, " + "it requires a connection per durable to match that connectionId") public void testDurableStoreAndForwardReconnect() throws Exception { // create a local durable consumer MessageConsumer localConsumer = localSession.createDurableSubscriber(included, consumerName); Thread.sleep(5000); // now close everything down and restart doTearDown(); doSetUp(false); // send messages MessageProducer producer = localSession.createProducer(included); for (int i = 0; i < MESSAGE_COUNT; i++) { Message test = localSession.createTextMessage("test-" + i); producer.send(test); } Thread.sleep(5000); // consume some messages locally localConsumer = localSession.createDurableSubscriber(included, consumerName); LOG.info("Consume from local consumer: " + localConsumer); for (int i = 0; i < MESSAGE_COUNT / 2; i++) { assertNotNull("message count: " + i, localConsumer.receive(2500)); } Thread.sleep(5000); // close everything down and restart doTearDown(); doSetUp(false); Thread.sleep(5000); LOG.info("Consume from remote"); // consume the rest remotely MessageConsumer remoteConsumer = remoteSession.createDurableSubscriber(included, consumerName); LOG.info("Remote consumer: " + remoteConsumer); Thread.sleep(5000); for (int i = 0; i < MESSAGE_COUNT / 2; i++) { assertNotNull("message count: " + i, remoteConsumer.receive(10000)); } } @Before public void setUp() throws Exception { doSetUp(true); } @After public void tearDown() throws Exception { doTearDown(); } protected void doTearDown() throws Exception { localConnection.close(); remoteConnection.close(); localBroker.stop(); remoteBroker.stop(); } protected void doSetUp(boolean deleteAllMessages) throws Exception { remoteBroker = createRemoteBroker(); remoteBroker.setDeleteAllMessagesOnStartup(deleteAllMessages); remoteBroker.start(); remoteBroker.waitUntilStarted(); localBroker = createLocalBroker(); localBroker.setDeleteAllMessagesOnStartup(deleteAllMessages); localBroker.start(); localBroker.waitUntilStarted(); URI localURI = localBroker.getVmConnectorURI(); ActiveMQConnectionFactory fac = new ActiveMQConnectionFactory(localURI); fac.setAlwaysSyncSend(true); fac.setDispatchAsync(false); localConnection = fac.createConnection(); localConnection.setClientID("clientId"); localConnection.start(); URI remoteURI = remoteBroker.getVmConnectorURI(); fac = new ActiveMQConnectionFactory(remoteURI); remoteConnection = fac.createConnection(); remoteConnection.setClientID("clientId"); remoteConnection.start(); included = new ActiveMQTopic("include.test.bar"); excluded = new ActiveMQTopic("exclude.test.bar"); localSession = localConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); remoteSession = remoteConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); } protected String getRemoteBrokerURI() { return "org/apache/activemq/network/remoteBroker.xml"; } protected String getLocalBrokerURI() { return "org/apache/activemq/network/localBroker.xml"; } protected BrokerService createBroker(String uri) throws Exception { Resource resource = new ClassPathResource(uri); BrokerFactoryBean factory = new BrokerFactoryBean(resource); resource = new ClassPathResource(uri); factory = new BrokerFactoryBean(resource); factory.afterPropertiesSet(); BrokerService result = factory.getBroker(); return result; } protected BrokerService createLocalBroker() throws Exception { return createBroker(getLocalBrokerURI()); } protected BrokerService createRemoteBroker() throws Exception { return createBroker(getRemoteBrokerURI()); } }