ack.setFirstMessageId(md.getMessage().getMessageId()); doStartTransaction(); ack.setTransactionId(getTransactionContext().getTransactionId()); if (ack.getTransactionId() != null) { getTransactionContext().addSynchronization(new Synchronization() { if (getTransactionContext() != null && getTransactionContext().isInXATransaction()) { LOG.debug("Marking transaction: {} rollbackOnly", getTransactionContext()); getTransactionContext().setRollbackOnly(true);
/** * Send TransactionInfo to indicate transaction has started * * @throws JMSException if some internal error occurs */ protected void doStartTransaction() throws JMSException { if (getTransacted() && !transactionContext.isInXATransaction()) { transactionContext.begin(); } }
/** * Commits all messages done in this transaction and releases any locks * currently held. * * @throws JMSException if the JMS provider fails to commit the transaction * due to some internal error. * @throws TransactionRolledBackException if the transaction is rolled back * due to some internal error during commit. * @throws javax.jms.IllegalStateException if the method is not called by a * transacted session. */ @Override public void commit() throws JMSException { checkClosed(); if (!getTransacted()) { throw new javax.jms.IllegalStateException("Not a transacted session"); } if (LOG.isDebugEnabled()) { LOG.debug(getSessionId() + " Transaction Commit :" + transactionContext.getTransactionId()); } transactionContext.commit(); }
private void invokeBeforeEnd() throws XAException { boolean throwingException = false; try { beforeEnd(); } catch (JMSException e) { throwingException = true; throw toXAException(e); } finally { try { setXid(null); } catch (XAException ignoreIfWillMask){ if (!throwingException) { throw ignoreIfWillMask; } } } }
@Override public void end(Xid xid, int flags) throws XAException { LOG.debug("End: {}, flags: {}", xid, XASupport.toString(flags)); if (isInLocalTransaction()) { throw new XAException(XAException.XAER_PROTO); } if ((flags & (TMSUSPEND | TMFAIL)) != 0) { // You can only suspend the associated xid. if (!equals(associatedXid, xid)) { throw new XAException(XAException.XAER_PROTO); } invokeBeforeEnd(); } else if ((flags & TMSUCCESS) == TMSUCCESS) { // set to null if this is the current xid. // otherwise this could be an asynchronous success call if (equals(associatedXid, xid)) { invokeBeforeEnd(); } } else { throw new XAException(XAException.XAER_INVAL); } }
throw new XAException(XAException.XAER_PROTO); if (equals(associatedXid, xid)) { TransactionInfo info = new TransactionInfo(getConnectionId(), x, TransactionInfo.ROLLBACK); this.connection.syncSendPacket(info); ctx.afterRollback(); throw toXAException(e);
if (isInXATransaction()) { throw new TransactionInProgressException("Cannot commit() if an XA transaction is already in progress "); beforeEnd(); } catch (JMSException e) { rollback(); throw e; final String message = "Commit of " + transactionId + " failed due to rollback only request; typically due to failover with pending acks"; try { rollback(); } finally { LOG.warn(message); transactionId, (synchronizations != null ? synchronizations.size() : 0)); TransactionInfo info = new TransactionInfo(getConnectionId(), transactionId, TransactionInfo.COMMIT_ONE_PHASE); this.transactionId = null; localTransactionEventListener.commitEvent(); afterCommit(); } catch (JMSException cause) { LOG.info("commit failed for transaction {}", info.getTransactionId(), cause); afterRollback(); throw cause;
if (isInXATransaction()) { throw new TransactionInProgressException("Cannot rollback() if an XA transaction is already in progress "); beforeEnd(); } catch (TransactionRolledBackException canOcurrOnFailover) { LOG.warn("rollback processing error", canOcurrOnFailover); transactionId, (synchronizations != null ? synchronizations.size() : 0)); TransactionInfo info = new TransactionInfo(getConnectionId(), transactionId, TransactionInfo.ROLLBACK); this.transactionId = null; afterRollback();
if (isInLocalTransaction()) { throw new XAException(XAException.XAER_PROTO); if (!equals(associatedXid, xid)) { throw new XAException(XAException.XAER_PROTO); beforeEnd(); } catch (JMSException e) { throw toXAException(e); setXid(null); } else if ((flags & TMSUCCESS) == TMSUCCESS) { if (equals(associatedXid, xid)) { try { beforeEnd(); } catch (JMSException e) { throw toXAException(e); setXid(null);
@Override public void forget(Xid xid) throws XAException { LOG.debug("Forget: {}", xid); // We allow interleaving multiple transactions, so // we don't limit forget to the associated xid. XATransactionId x; if (xid == null) { throw new XAException(XAException.XAER_PROTO); } if (equals(associatedXid, xid)) { // TODO determine if this can happen... I think not. x = (XATransactionId)transactionId; } else { x = new XATransactionId(xid); } TransactionInfo info = new TransactionInfo(getConnectionId(), x, TransactionInfo.FORGET); try { // Tell the server to forget the transaction. this.connection.syncSendPacket(info); } catch (JMSException e) { throw toXAException(e); } synchronized(ENDED_XA_TRANSACTION_CONTEXTS) { ENDED_XA_TRANSACTION_CONTEXTS.remove(x); } }
/** * Start a local transaction. * @throws javax.jms.JMSException on internal error */ public void begin() throws JMSException { if (isInXATransaction()) { throw new TransactionInProgressException("Cannot start local transaction. XA transaction is already in progress."); } if (transactionId == null) { synchronizations = null; beforeEndIndex = 0; setRollbackOnly(false); this.transactionId = new LocalTransactionId(getConnectionId(), localTransactionIdGenerator.getNextSequenceId()); TransactionInfo info = new TransactionInfo(getConnectionId(), transactionId, TransactionInfo.BEGIN); this.connection.ensureConnectionInfoSent(); this.connection.asyncSendPacket(info); // Notify the listener that the tx was started. if (localTransactionEventListener != null) { localTransactionEventListener.beginEvent(); } LOG.debug("Begin:{}", transactionId); } }
this.connection.ensureConnectionInfoSent(); } catch (JMSException e) { disassociate(); throw toXAException(e); transactionId = new XATransactionId(xid); TransactionInfo info = new TransactionInfo(getConnectionId(), transactionId, TransactionInfo.BEGIN); try { this.connection.asyncSendPacket(info); LOG.debug("{} started XA transaction {}", this, transactionId); } catch (JMSException e) { disassociate(); throw toXAException(e); TransactionInfo info = new TransactionInfo(getConnectionId(), transactionId, TransactionInfo.END); try { this.connection.syncSendPacket(info); LOG.debug("{} ended XA transaction {}", this, transactionId); } catch (JMSException e) { disassociate(); throw toXAException(e); disassociate();
public void close() throws JMSException { if (!unconsumedMessages.isClosed()) { if (!deliveredMessages.isEmpty() && session.getTransactionContext().isInTransaction()) { session.getTransactionContext().addSynchronization(new Synchronization() { @Override public void afterCommit() throws Exception {
public void close() throws JMSException { if (!closed) { if (getTransactionContext().isInXATransaction()) { if (!synchronizationRegistered) { synchronizationRegistered = true; getTransactionContext().addSynchronization(new Synchronization() {
/** * Rolls back any messages done in this transaction and releases any locks * currently held. * * @throws JMSException if the JMS provider fails to roll back the * transaction due to some internal error. * @throws javax.jms.IllegalStateException if the method is not called by a * transacted session. */ @Override public void rollback() throws JMSException { checkClosed(); if (!getTransacted()) { throw new javax.jms.IllegalStateException("Not a transacted session"); } if (LOG.isDebugEnabled()) { LOG.debug(getSessionId() + " Transaction Rollback, txid:" + transactionContext.getTransactionId()); } transactionContext.rollback(); }
@Override public Xid[] recover(int flag) throws XAException { LOG.debug("recover({})", flag); XATransactionId[] answer; if (XAResource.TMNOFLAGS == flag) { // signal next in cursor scan, which for us is always the end b/c we don't maintain any cursor state // allows looping scan to complete answer = new XATransactionId[0]; } else { TransactionInfo info = new TransactionInfo(getConnectionId(), null, TransactionInfo.RECOVER); try { this.connection.checkClosedOrFailed(); this.connection.ensureConnectionInfoSent(); DataArrayResponse receipt = (DataArrayResponse) this.connection.syncSendPacket(info); DataStructure[] data = receipt.getData(); if (data instanceof XATransactionId[]) { answer = (XATransactionId[]) data; } else { answer = new XATransactionId[data.length]; System.arraycopy(data, 0, answer, 0, data.length); } } catch (JMSException e) { throw toXAException(e); } } LOG.debug("recover({})={}", flag, answer); return answer; }
@Test public void testSyncIndexCleared() throws Exception { final AtomicInteger beforeEndCountA = new AtomicInteger(0); final AtomicInteger rollbackCountA = new AtomicInteger(0); Synchronization sync = new Synchronization() { @Override public void beforeEnd() throws Exception { beforeEndCountA.getAndIncrement(); } @Override public void afterCommit() throws Exception { fail("expected rollback exception"); } @Override public void afterRollback() throws Exception { rollbackCountA.incrementAndGet(); } }; underTest.begin(); underTest.addSynchronization(sync); underTest.rollback(); assertEquals("beforeEnd", 1, beforeEndCountA.get()); assertEquals("rollback", 1, rollbackCountA.get()); // do it again underTest.begin(); underTest.addSynchronization(sync); underTest.rollback(); assertEquals("beforeEnd", 2, beforeEndCountA.get()); assertEquals("rollback", 2, rollbackCountA.get()); }
if (!synchronizationRegistered) { synchronizationRegistered = true; session.getTransactionContext().addSynchronization(new Synchronization() { @Override public void beforeEnd() throws Exception { pendingAck.setTransactionId(session.getTransactionContext().getTransactionId()); if( oldPendingAck==null ) { pendingAck.setFirstMessageId(pendingAck.getLastMessageId());
/** * Construct the Session * * @param connection * @param sessionId * @param acknowledgeMode n.b if transacted - the acknowledgeMode == * Session.SESSION_TRANSACTED * @param asyncDispatch * @param sessionAsyncDispatch * @throws JMSException on internal error */ protected ActiveMQSession(ActiveMQConnection connection, SessionId sessionId, int acknowledgeMode, boolean asyncDispatch, boolean sessionAsyncDispatch) throws JMSException { this.debug = LOG.isDebugEnabled(); this.connection = connection; this.acknowledgementMode = acknowledgeMode; this.asyncDispatch = asyncDispatch; this.sessionAsyncDispatch = sessionAsyncDispatch; this.info = new SessionInfo(connection.getConnectionInfo(), sessionId.getValue()); setTransactionContext(new TransactionContext(connection)); stats = new JMSSessionStatsImpl(producers, consumers); this.connection.asyncSendPacket(info); setTransformer(connection.getTransformer()); setBlobTransferPolicy(connection.getBlobTransferPolicy()); this.connectionExecutor=connection.getExecutor(); this.executor = new ActiveMQSessionExecutor(this); connection.addSession(this); if (connection.isStarted()) { start(); } }
final AtomicInteger rollbackCountA = new AtomicInteger(0); final AtomicInteger rollbackCountB = new AtomicInteger(0); underTest.addSynchronization(new Synchronization() { @Override public void beforeEnd() throws Exception { underTest.addSynchronization(new Synchronization() { @Override public void beforeEnd() throws Exception { underTest.commit(); fail("expected rollback exception"); } catch (TransactionRolledBackException expected) {