org.jboss.jbossts.fileio.xalib.txdirs.dir.XAFileResourceManager.java Source code

Java tutorial

Introduction

Here is the source code for org.jboss.jbossts.fileio.xalib.txdirs.dir.XAFileResourceManager.java

Source

/*     JBoss, Home of Professional Open Source Copyright 2008, Red Hat
 *  Middleware LLC, and individual contributors as indicated by the
 *  @author tags.
 *     See the copyright.txt in the distribution for a full listing of
 *  individual contributors. This copyrighted material is made available
 *  to anyone wishing to use, modify, copy, or redistribute it subject to
 *  the terms and conditions of the GNU Lesser General Public License, v. 2.1.
 *  This program is distributed in the hope that it will be useful, but
 *  WITHOUT A WARRANTY; without even the implied warranty of MERCHANTABILITY
 *  or FITNESS FOR A PARTICULAR PURPOSE.
 *     See the GNU Lesser General Public License for more details. You should
 *  have received a copy of the GNU Lesser General Public License, v.2.1
 *  along with this distribution; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor,
 *  Boston, MA  02110-1301, USA.
 *
 *  (C) 2008,
 *  @author Red Hat Middleware LLC.
 */
package org.jboss.jbossts.fileio.xalib.txdirs.dir;

import javax.transaction.xa.XAResource;
import javax.transaction.xa.Xid;
import javax.transaction.xa.XAException;
import java.io.Serializable;
import java.io.ObjectInputStream;
import java.io.IOException;
import java.io.File;

import org.apache.commons.transaction.file.*;
import org.apache.commons.transaction.util.CommonsLoggingLogger;
import org.apache.commons.logging.LogFactory;
import org.jboss.jbossts.fileio.xalib.Globals;

/**
 * This class implements methods of the standard {@link javax.transaction.xa.XAResource} interface
 * which acts like a contract between a Resource Manager and a Transaction
 * Manager.
 * <p>
 * Each instance of an <code>XAFileResourceManager</code> has its own {@link javax.transaction.xa.Xid}
 * which distinguishes by the other objects of this class and is associated
 * with a Transaction. It also has a unique transaction id which is represented by
 * a <code>String</code> and is used by {@link org.apache.commons.transaction.file.FileResourceManager}
 * to know which transaction to start, commit/rollback etc.
 * <p>
 * Any changes made within a transaction specified by the <code>Xid</code> mentioned above
 * will be applied to the transactional directory only after this <code>XAFileResourceManager</code>
 * has commited. If the decision is to rollback then all the modifications made within the transaction
 * are removed.
 *
 * @author Ioannis Ganotis
 * @version Aug 6, 2008
 */
public class XAFileResourceManager implements XAResource, Serializable {
    private Xid currentXid;
    private String curTxId;
    transient private FileResourceManager freMngr; // todo must be setializable
    private boolean recovers;
    private String storeDir;

    /**
     * Constructor to create Resource Manager objects. Each of these
     * objects, at transaction time, are informed by the Transaction
     * Manager to prepare, commit or rollback (depending on the outcome
     * of the 2PC protocol).
     *
     * @param freMngr the Resource Manager on which methods like start, commit
     *                or rollback a transaction will be applied
     * @param curTxId the unique transaction id used by <code>freMngr</code> to
     *                know on which transaction to work
     */
    public XAFileResourceManager(FileResourceManager freMngr, String curTxId) {
        this.freMngr = freMngr;
        this.curTxId = curTxId;
        storeDir = freMngr.getStoreDir();
        recovers = false;
    }

    /**
     * Acts like the {@link org.apache.commons.transaction.file.FileResourceManager#prepareTransaction(Object)}
     * method does.
     *
     * @param xid the global transaction id
     * @throws XAException
     *         if a <code>ResourceManagerException</code> is thrown
     */
    public int prepare(Xid xid) throws XAException {
        // flush data on disk here
        System.out.println("XAFileResourceManager.prepare(Xid=" + xid + ")");
        try {
            return freMngr.prepareTransaction(curTxId);
        } catch (ResourceManagerException rme) {
            throw new XAException(rme.getMessage());
        }
    }

    /**
     * Method to commit the global transaction with the given <code>xid</code>.
     * <p/>
     * It also acts like the {@link org.apache.commons.transaction.file.FileResourceManager#commitTransaction(Object)}
     * does.
     *
     * @param xid      a global Transaction id
     * @param onePhase If true, the resource manager should use a one-phase
     *                 commit protocol to commit the work done on behalf of xid
     * @throws XAException
     *         if a <code>ResourceManagerException</code> is thrown
     */
    public void commit(Xid xid, boolean onePhase) throws XAException {
        System.out.println("XAFileResourceManager.commit(Xid=" + xid + ", onePhase=" + onePhase + ")");
        if (!xid.equals(currentXid)) {
            System.out.println("XAFileResourceManager.commit - wrong Xid!");
        }
        try {
            if (!recovers) {
                freMngr.commitTransaction(curTxId);
            } else {
                // the initFREM() method will take care of incomplete txs
            }
        } catch (ResourceManagerException rme) {
            throw new XAException(rme.getMessage());
        }
        currentXid = null;
    }

    /**
     * Ends the work performed on behalf of a transaction branch.
     *
     * @param xid   a global transaction identifier that is the same as what was used
     *              previously in the start method
     * @param flags (can be anything)
     */
    public void end(Xid xid, int flags) {
        System.out.println("XAFileResourceManager.end(Xid=" + xid + ", flags=" + flags + ")");
    }

    /**
     * Forget about a heuristically completed transaction branch.
     * The <code>currentXid</code> is set to null
     *
     * @param xid a global Transaction id
     */
    public void forget(Xid xid) {
        System.out.println("XAFileResourceManager.forget(Xid=" + xid + ")");
        if (!xid.equals(currentXid)) {
            System.out.println("XAFileResourceManager.forget - wrong Xid!");
        }
        currentXid = null;
    }

    /**
     * Obtain the current transaction timeout value set for this
     * <code>XAFileResourceManager</code> instance. If
     * <code>XAFileResourceManager.setTransactionTimeout</code> was not used prior to
     * invoking this method, the return value is the default timeout set for
     * the resource manager; otherwise, the value used in the previous
     * <code>setTransactionTimeout</code> call is returned.
     *
     * @return the transaction timeout value in seconds
     */
    public int getTransactionTimeout() throws XAException {
        try {
            int timeout = (int) freMngr.getTransactionTimeout(curTxId) / 1000; // ms -> secs
            System.out.println("XAFileResourceManager.getTransactionTimeout() [returning " + timeout + "]");
            return timeout;
        } catch (ResourceManagerException rme) {
            throw new XAException(rme.getMessage());
        }
    }

    /*
    * No implementation.
    * @param xares an XAResource object whose resource manager instance is to
    *              be compared with the resource manager instance of the target
    *              object
    * @return always false
    */
    public boolean isSameRM(XAResource xares) throws XAException {
        System.out.println("XAFileResourceManager.isSameRM(xaresMngr=" + xares + ")");
        return false;
    }

    /*
    * No implementation.
    * @param flag
    * @return always zero xids
    */
    public Xid[] recover(int flag) throws XAException {
        System.out.println("XAFileResourceManager.recover(flag=" + flag + ")");
        return new Xid[0];
    }

    /**
     * Rollback any updates attempted to be written to the directory.
     * <p/>
     * The method acts like the
     * {@link org.apache.commons.transaction.file.FileResourceManager#rollbackTransaction(Object)}
     * does.
     * @param xid a global Transaction id
     * @throws XAException
     *         if a <code>ResourceManagerException</code> is thrown
     */
    public void rollback(Xid xid) throws XAException {
        System.out.println("XAFileResourceManager.rollback(Xid=" + xid + ")");
        try {
            freMngr.rollbackTransaction(curTxId);
        } catch (ResourceManagerException rme) {
            throw new XAException(rme.getMessage());
        }
        currentXid = null;
    }

    /**
     * Set the current transaction <code>timeout</code> value for this
     * <code>XAFileResourceManager</code> instance. Once set, this timeout value is
     * effective until <code>setTransactionTimeout</code> is invoked again with
     * a different value.
     * The method acts like the
     * {@link org.apache.commons.transaction.file.FileResourceManager#setTransactionTimeout(Object, long)}
     * does.
     *
     * @param seconds transaction timeout value in seconds
     * @return true if transaction timeout value is set successfully;
     *         otherwise false
     */
    public boolean setTransactionTimeout(int seconds) throws XAException {
        System.out.println("XAFileResourceManager.setTransactionTimeout(timeout=" + seconds + ")");
        try {
            freMngr.setTransactionTimeout(curTxId, seconds * 1000);
        } catch (ResourceManagerException rme) {
            throw new XAException(rme.getMessage());
        }
        return false;
    }

    /**
     * Start work on behalf of a transaction branch specified in <code>xid</code>.
     * The method act like the
     * {@link org.apache.commons.transaction.file.FileResourceManager#startTransaction(Object)}
     * does.
     * @param xid   a global Transaction id to be associated with this
     *              Resource Manager instance
     * @param flags (can be anything)
     * @throws XAException if there is already a Transaction
     */
    public void start(Xid xid, int flags) throws XAException {
        System.out.println("XAFileResourceManager.start(Xid=" + xid + ", flags=" + flags + ")");
        if (currentXid != null) {
            System.out.println("XAFileResourceManager.start - wrong Xid!");
            throw new XAException(
                    "Current Transaction is: <" + currentXid + ">\nCannot start the new Transaction.");
        }
        try {
            freMngr.startTransaction(curTxId);
        } catch (ResourceManagerException rme) {
            throw new XAException(rme.getMessage());
        }
        currentXid = xid;
    }

    /**
     * Returns the global Transaction id associated with this
     * <code>XAFileResourceManager</code>
     * @return the global Transaction id associated with this
     *         <code>XAFileResourceManager</code>
     */
    public Xid getCurrentXid() {
        return currentXid;
    }

    /**
     * After a system crash and upon recovery phase the <code>FileResourceManager</code>
     * object needs to be re-initialised.
     */
    private void initFREM() {
        String workDir = storeDir + "/" + Globals.WORK_DIR_NAME;
        freMngr = new FileResourceManager(storeDir, workDir, false,
                new CommonsLoggingLogger(LogFactory.getLog(XADir.class.getName())));
        try {
            freMngr.start(); // will automatically recover incomplete txs
        } catch (ResourceManagerSystemException e) {
            e.printStackTrace();
        }
    }

    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
        in.defaultReadObject();
        recovers = true; // indicate that the XAFileResourceManager recovers now
        initFREM();
    }
}