private void sendBatchXA() { try { sendMessages(); // Commit the JTA transaction and start another delistResources(tx); if (JMSBridgeImpl.trace) { HornetQJMSServerLogger.LOGGER.trace("Committing JTA transaction"); } tx.commit(); if (JMSBridgeImpl.trace) { HornetQJMSServerLogger.LOGGER.trace("Committed JTA transaction"); } tx = startTx(); enlistResources(tx); // Clear the messages messages.clear(); } catch (Exception e) { HornetQJMSServerLogger.LOGGER.bridgeAckError(e); handleFailureOnSend(); } }
/* * 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; } }