All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jboss.jbossts.txbridge.inbound.BridgeDurableParticipant Maven / Gradle / Ivy

The newest version!
/*
   Copyright The Narayana Authors
   SPDX-License-Identifier: Apache-2.0
 */

package org.jboss.jbossts.txbridge.inbound;

import com.arjuna.ats.jta.utils.XAHelper;
import com.arjuna.wst.*;
import com.arjuna.ats.arjuna.common.Uid;
import com.arjuna.ats.internal.arjuna.FormatConstants;
import com.arjuna.ats.internal.jta.transaction.arjunacore.jca.SubordinationManager;
import org.jboss.jbossts.txbridge.utils.txbridgeLogger;

import javax.transaction.xa.Xid;
import javax.transaction.xa.XAException;
import javax.transaction.xa.XAResource;

import jakarta.resource.spi.XATerminator;

import java.io.Serializable;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

/**
 * Provides method call mapping between WS-AT Durable Participant interface
 * and an underlying JTA subtransaction coordinator.
 *
 * @author [email protected], 2007-04-30
 */
public class BridgeDurableParticipant implements Durable2PCParticipant, Serializable
{
    /*
     * Uniq String used to prefix ids at participant registration,
     * so that the recovery module can identify relevant instances.
     */
    public static final String TYPE_IDENTIFIER = "BridgeDurableParticipant_";

    /*
     * Uniq (well, hopefully) formatId so we can distinguish our own Xids.
     */
    public static final int XARESOURCE_FORMAT_ID = FormatConstants.XTS_BRIDGE_FORMAT_ID;

    private transient volatile XATerminator xaTerminator;

    private transient volatile String externalTxId;

    private transient volatile boolean isAwaitingRecovery = false;

    static final long serialVersionUID = -5739871936627778072L;

    // Xid not guaranteed Serializable by spec, but our XidImple happens to be
    private volatile Xid xid;

    // Id needed for recovery of the subordinate tx. Uids are likewise Serializable.
    private volatile Uid subordinateTransactionId;

    /**
     * Create a new WS-AT Durable Participant which wraps the subordinate XA tx terminator.
     *
     * @param externalTxId the WS-AT Tx identifier
     * @param xid the Xid to use when driving the subordinate XA transaction.
     */
    BridgeDurableParticipant(String externalTxId, Xid xid)
    {
        txbridgeLogger.logger.trace("BridgeDurableParticipant.(TxId="+externalTxId+", Xid="+xid+")");

        this.xid = xid;
        this.externalTxId = externalTxId;
        xaTerminator = SubordinationManager.getXATerminator();
    }

    /**
     * Serialization hook. Gathers and writes information needed for transaction recovery.
     *
     * @param out the stream to which the object state is serialized.
     * @throws IOException if serialization fails.
     */
    private void writeObject(ObjectOutputStream out) throws IOException
    {
        txbridgeLogger.logger.trace("BridgeDurableParticipant.writeObject() for Xid="+xid);

        // we need to preserve the Uid of the underlying SubordinateTx, as it's required
        // to get a handle on it again during recovery, Using the xid wont work,
        // although we do need to serialize that too for use after recovery.
        try
        {
            subordinateTransactionId = SubordinationManager.getTransactionImporter().getImportedTransaction(xid).get_uid();
        }
        catch(XAException xaException)
        {
            txbridgeLogger.i18NLogger.error_ibdp_nosub(xaException);
            throw new IOException(xaException);
        }

        //out.defaultWriteObject();
        out.writeObject(xid);
        out.writeObject(subordinateTransactionId);
    }

    /**
     * Deserialization hook. Unpacks transaction recovery information and uses it to
     * recover the subordinate transaction.
     *
     * @param in the stream from which to unpack the object state.
     * @throws IOException if deserialzation and recovery fail.
     * @throws ClassNotFoundException if deserialzation fails.
     */
    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException
    {
        txbridgeLogger.logger.trace("BridgeDurableParticipant.readObject()");

        //in.defaultReadObject();
        xid = (Xid)in.readObject();
        subordinateTransactionId = (Uid)in.readObject();

        // this readObject method executes only when a log is being read at recovery time:
        isAwaitingRecovery = true;

        xaTerminator = SubordinationManager.getXATerminator();

        try
        {
            SubordinationManager.getTransactionImporter().recoverTransaction(subordinateTransactionId);
        }
        catch(XAException xaException)
        {
            txbridgeLogger.i18NLogger.error_ibdp_norecovery(subordinateTransactionId, xaException);
            throw new IOException(xaException);
        }
    }

    /**
     * Perform any work necessary to allow it to either commit or rollback
     * the work performed by the Web service under the scope of the
     * transaction. The implementation is free to do whatever it needs to in
     * order to fulfill the implicit contract between it and the coordinator.
     *
     * @return an indication of whether it can prepare or not.
     * @see com.arjuna.wst.Vote
     */
    public Vote prepare() throws WrongStateException, SystemException
    {
        txbridgeLogger.logger.trace("BridgeDurableParticipant.prepare(Xid="+xid+")");

        try
        {
            // XAResource.XA_OK, XAResource.XA_RDONLY or exception.  if RDONLY, don't call commit
            int result = xaTerminator.prepare(xid);
            if(result == XAResource.XA_OK)
            {
                txbridgeLogger.logger.trace("prepare on Xid="+xid+" returning Prepared");
                return new Prepared();
            }
            else
            {
                cleanupRefs();
                txbridgeLogger.logger.trace("prepare on Xid="+xid+" returning ReadOnly");
                return new ReadOnly();
            }

        }
        catch(XAException e)
        {
            // TODO: this is not necessarily an error. If the subordinate tx is setRollbackOnly
            // e.g. due to failure of VolatileParticipant.prepare, then it's expected the prepare will fail.
            // we really need to use XATerminatorExtensions to expose a isSetRollbackOnly...
            cleanupRefs();
            txbridgeLogger.i18NLogger.warn_ibdp_aborted(XAHelper.xidToString(xid), e);
            return new Aborted();
        }
    }

    /**
     * The participant should make permanent the work that it controls.
     *
     * @throws WrongStateException
     * @throws SystemException
     */
    public void commit() throws WrongStateException, SystemException
    {
        txbridgeLogger.logger.trace("BridgeDurableParticipant.commit(Xid="+xid+")");

        try
        {
            xaTerminator.commit(xid, false);
            txbridgeLogger.logger.trace("commit on Xid="+xid+" OK");
        }
        catch (XAException e)
        {
            txbridgeLogger.i18NLogger.error_ibdp_commitfailed(XAHelper.xidToString(xid), e);
        }
        finally
        {
            cleanupRefs();
        }
    }

    /**
     * The participant should undo the work that it controls. The participant
     * will then return an indication of whether or not it succeeded..
     *
     * @throws WrongStateException
     * @throws SystemException
     */
    public void rollback() throws WrongStateException, SystemException
    {
        txbridgeLogger.logger.trace("BridgeDurableParticipant.rollback(Xid="+xid+")");

        try
        {
            xaTerminator.rollback(xid);
            txbridgeLogger.logger.trace("rollback on Xid="+xid+" OK");
        }
        catch (XAException e)
        {
            txbridgeLogger.i18NLogger.error_ibdp_rollbackfailed(XAHelper.xidToString(xid), e);
        }
        finally
        {
            cleanupRefs();
        }
    }

    /**
     * During recovery the participant can enquire as to the status of the
     * transaction it was registered with. If that transaction is no longer
     * available (has rolled back) then this operation will be invoked by the
     * coordination service.
     */
    public void unknown() throws SystemException
    {
        txbridgeLogger.logger.trace("BridgeDurableParticipant.unknown(Xid="+xid+"): NOT IMPLEMENTED");
    }

    /**
     * During recovery the participant can enquire as to the status of the
     * transaction it was registered with. If an error occurs (e.g., the
     * transaction service is unavailable) then this operation will be invoked.
     */
    public void error() throws SystemException
    {
        txbridgeLogger.logger.trace("BridgeDurableParticipant.error(Xid="+xid+"): NOT IMPLEMENTED");
    }

    public boolean isAwaitingRecovery() {
        return isAwaitingRecovery;
    }

    public Xid getXid()
    {
        return xid;
    }

    private void cleanupRefs()
    {
        txbridgeLogger.logger.trace("BridgeDurableParticipant.cleanupRefs()");

        org.jboss.jbossts.txbridge.inbound.InboundBridgeManager.removeMapping(externalTxId);
        isAwaitingRecovery = false;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy