/* * Source and target on same server * -------------------------------- * If the source and target destinations are on the same server (same resource manager) then, * in order to get ONCE_AND_ONLY_ONCE, we simply need to consuming and send in a single * local JMS transaction. * * We actually use a single local transacted session for the other QoS modes too since this * is more performant than using DUPS_OK_ACKNOWLEDGE or AUTO_ACKNOWLEDGE session ack modes, so effectively * the QoS is upgraded. * * Source and target on different server * ------------------------------------- * If the source and target destinations are on a different servers (different resource managers) then: * * If desired QoS is ONCE_AND_ONLY_ONCE, then we start a JTA transaction and enlist the consuming and sending * XAResources in that. * * If desired QoS is DUPLICATES_OK then, we use CLIENT_ACKNOWLEDGE for the consuming session and * AUTO_ACKNOWLEDGE (this is ignored) for the sending session if the maxBatchSize == 1, otherwise we * use a local transacted session for the sending session where maxBatchSize > 1, since this is more performant * When bridging a batch, we make sure to manually acknowledge the consuming session, if it is CLIENT_ACKNOWLEDGE * *after* the batch has been sent * * If desired QoS is AT_MOST_ONCE then, if maxBatchSize == 1, we use AUTO_ACKNOWLEDGE for the consuming session, * and AUTO_ACKNOWLEDGE for the sending session. * If maxBatchSize > 1, we use CLIENT_ACKNOWLEDGE for the consuming session and a local transacted session for the * sending session. * * When bridging a batch, we make sure to manually acknowledge the consuming session, if it is CLIENT_ACKNOWLEDGE * *before* the batch has been sent * */ private boolean setupJMSObjects() { try { if (sourceCff == targetCff) { // Source and target destinations are on the server - we can get once and only once // just using a local transacted session // everything becomes once and only once forwardMode = JMSBridgeImpl.FORWARD_MODE_LOCALTX; } else { // Different servers if (qualityOfServiceMode == QualityOfServiceMode.ONCE_AND_ONLY_ONCE) { // Use XA forwardMode = JMSBridgeImpl.FORWARD_MODE_XA; } else { forwardMode = JMSBridgeImpl.FORWARD_MODE_NONTX; } } // Lookup the destinations sourceDestination = sourceDestinationFactory.createDestination(); targetDestination = targetDestinationFactory.createDestination(); if (forwardMode == JMSBridgeImpl.FORWARD_MODE_LOCALTX) { // We simply use a single local transacted session for consuming and sending sourceConn = createConnection(sourceUsername, sourcePassword, sourceCff, clientID, false); sourceSession = sourceConn.createSession(true, Session.SESSION_TRANSACTED); } else { if (forwardMode == JMSBridgeImpl.FORWARD_MODE_XA) { // Create an XASession for consuming from the source if (JMSBridgeImpl.trace) { HornetQJMSServerLogger.LOGGER.trace("Creating XA source session"); } sourceConn = createConnection(sourceUsername, sourcePassword, sourceCff, clientID, true); sourceSession = ((XAConnection) sourceConn).createXASession(); } else { if (JMSBridgeImpl.trace) { HornetQJMSServerLogger.LOGGER.trace("Creating non XA source session"); } // Create a standard session for consuming from the source // We use ack mode client ack sourceConn = createConnection(sourceUsername, sourcePassword, sourceCff, clientID, false); sourceSession = sourceConn.createSession(false, Session.CLIENT_ACKNOWLEDGE); } } if (subName == null) { if (selector == null) { sourceConsumer = sourceSession.createConsumer(sourceDestination); } else { sourceConsumer = sourceSession.createConsumer(sourceDestination, selector, false); } } else { // Durable subscription if (selector == null) { sourceConsumer = sourceSession.createDurableSubscriber((Topic) sourceDestination, subName); } else { sourceConsumer = sourceSession.createDurableSubscriber( (Topic) sourceDestination, subName, selector, false); } } // Now the sending session if (forwardMode == JMSBridgeImpl.FORWARD_MODE_LOCALTX) { targetConn = sourceConn; targetSession = sourceSession; } else { if (forwardMode == JMSBridgeImpl.FORWARD_MODE_XA) { if (JMSBridgeImpl.trace) { HornetQJMSServerLogger.LOGGER.trace("Creating XA dest session"); } // Create an XA sesion for sending to the destination targetConn = createConnection(targetUsername, targetPassword, targetCff, null, true); targetSession = ((XAConnection) targetConn).createXASession(); } else { if (JMSBridgeImpl.trace) { HornetQJMSServerLogger.LOGGER.trace("Creating non XA dest session"); } // Create a standard session for sending to the target // If batch size > 1 we use a transacted session since is more efficient boolean transacted = maxBatchSize > 1; targetConn = createConnection(targetUsername, targetPassword, targetCff, null, false); targetSession = targetConn.createSession( transacted, transacted ? Session.SESSION_TRANSACTED : Session.AUTO_ACKNOWLEDGE); } } if (forwardMode == JMSBridgeImpl.FORWARD_MODE_XA) { if (JMSBridgeImpl.trace) { HornetQJMSServerLogger.LOGGER.trace("Starting JTA transaction"); } tx = startTx(); enlistResources(tx); } targetProducer = targetSession.createProducer(null); return true; } catch (Exception e) { // We shouldn't log this, as it's expected when trying to connect when target/source is not // available // If this fails we should attempt to cleanup or we might end up in some weird state // Adding a log.warn, so the use may see the cause of the failure and take actions HornetQJMSServerLogger.LOGGER.bridgeConnectError(e); cleanup(); return false; } }
@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( HornetQJMSClient.createQueue(JMSBridgeImplTest.SOURCE)); DestinationFactory targetDF = JMSBridgeImplTest.newDestinationFactory( HornetQJMSClient.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<Message>(); final CountDownLatch latch = new CountDownLatch(numMessages); MessageListener listener = new MessageListener() { 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(); }
protected void setUpAdministeredObjects() throws Exception { cff0LowProducerWindow = new ConnectionFactoryFactory() { public ConnectionFactory createConnectionFactory() throws Exception { HornetQConnectionFactory cf = HornetQJMSClient.createConnectionFactoryWithoutHA( JMSFactoryType.CF, new TransportConfiguration(INVM_CONNECTOR_FACTORY)); // 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); cf.setCacheLargeMessagesClient(true); cf.setProducerWindowSize(100); return cf; } }; cff0 = new ConnectionFactoryFactory() { public ConnectionFactory createConnectionFactory() throws Exception { HornetQConnectionFactory cf = HornetQJMSClient.createConnectionFactoryWithoutHA( JMSFactoryType.CF, new TransportConfiguration(INVM_CONNECTOR_FACTORY)); // 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); cf.setCacheLargeMessagesClient(true); return cf; } }; cff0xa = new ConnectionFactoryFactory() { public Object createConnectionFactory() throws Exception { HornetQXAConnectionFactory cf = (HornetQXAConnectionFactory) HornetQJMSClient.createConnectionFactoryWithoutHA( JMSFactoryType.XA_CF, new TransportConfiguration(INVM_CONNECTOR_FACTORY)); // 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); cf.setCacheLargeMessagesClient(true); return cf; } }; cf0 = (ConnectionFactory) cff0.createConnectionFactory(); cf0xa = (XAConnectionFactory) cff0xa.createConnectionFactory(); cff1 = new ConnectionFactoryFactory() { public ConnectionFactory createConnectionFactory() throws Exception { HornetQJMSConnectionFactory cf = (HornetQJMSConnectionFactory) HornetQJMSClient.createConnectionFactoryWithoutHA( JMSFactoryType.CF, new TransportConfiguration(INVM_CONNECTOR_FACTORY, params1)); // 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); cf.setCacheLargeMessagesClient(true); return cf; } }; cff1xa = new ConnectionFactoryFactory() { public XAConnectionFactory createConnectionFactory() throws Exception { HornetQXAConnectionFactory cf = (HornetQXAConnectionFactory) HornetQJMSClient.createConnectionFactoryWithoutHA( JMSFactoryType.XA_CF, new TransportConfiguration(INVM_CONNECTOR_FACTORY, params1)); // 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); cf.setCacheLargeMessagesClient(true); return cf; } }; cf1 = (ConnectionFactory) cff1.createConnectionFactory(); cf1xa = (XAConnectionFactory) cff1xa.createConnectionFactory(); sourceQueueFactory = new DestinationFactory() { public Destination createDestination() throws Exception { return (Destination) context0.lookup("/queue/sourceQueue"); } }; sourceQueue = (Queue) sourceQueueFactory.createDestination(); targetQueueFactory = new DestinationFactory() { public Destination createDestination() throws Exception { return (Destination) context1.lookup("/queue/targetQueue"); } }; targetQueue = (Queue) targetQueueFactory.createDestination(); sourceTopicFactory = new DestinationFactory() { public Destination createDestination() throws Exception { return (Destination) context0.lookup("/topic/sourceTopic"); } }; sourceTopic = (Topic) sourceTopicFactory.createDestination(); localTargetQueueFactory = new DestinationFactory() { public Destination createDestination() throws Exception { return (Destination) context0.lookup("/queue/localTargetQueue"); } }; localTargetQueue = (Queue) localTargetQueueFactory.createDestination(); }
/* * 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( HornetQJMSClient.createQueue(JMSBridgeImplTest.SOURCE)); DestinationFactory targetDF = JMSBridgeImplTest.newDestinationFactory( HornetQJMSClient.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<Message>(); MessageListener listener = new MessageListener() { 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(); }