/*
* JBoss, Home of Professional Open Source
* Copyright 2006, 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) 2015,
* @author JBoss Inc.
*/
package org.jboss.stm.async;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import org.jboss.stm.internal.async.TransactionExecutorAbort;
import org.jboss.stm.internal.async.TransactionExecutorBegin;
import org.jboss.stm.internal.async.TransactionExecutorCommit;
import com.arjuna.ats.arjuna.AtomicAction;
import com.arjuna.ats.arjuna.common.Uid;
/**
* This is a user-level transaction class. Unlike AtomicAction which it uses, this
* provides an asynchronous begin, commit and rollback capability. There
* are a number of ways in which we currently support asynchronous interactions with
* the transaction system, such as async prepare or async commit. The developer could
* also register a two-phase aware participant or a Synchronisation and use callbacks
* themselves to determine the outcome of the transaction. These continue to be
* available to the developer but this API is intended to provide a simplified interface
* to allow clients to make use of asynchronous transactions.
*
* Note, we deliberately don't derive from AtomicAction so that developers must make
* a conscious choice between a synchronous or asynchronous transaction.
*
* @author Mark Little (mark@arjuna.com)
* @version $Id$
*/
public class Transaction
{
/**
* Create a new transaction. If there is already a transaction associated
* with the thread then this new transaction will be automatically nested.
* The transaction is *not* running at this point.
*
* No timeout is associated with this transaction, i.e., it will not be
* automatically rolled back by the system.
*/
public Transaction ()
{
_theTransaction = new AtomicAction();
}
/**
* AtomicAction constructor with a Uid. This constructor is for recreating
* an AtomicAction, typically during crash recovery.
*/
public Transaction (Uid objUid)
{
_theTransaction = new AtomicAction(objUid);
}
/**
* Start the transaction running.
*
* If the transaction is already running or has terminated, then an error
* code will be returned. No timeout is associated with the transaction.
*
* @return <code>ActionStatus</code> indicating outcome.
*/
public Future<Integer> begin ()
{
return begin(AtomicAction.NO_TIMEOUT);
}
/**
* Start the transaction running.
*
* If the transaction is already running or has terminated, then an error
* code will be returned.
*
* @param timeout the timeout associated with the transaction. If the
* transaction is still active when this timeout elapses, the
* system will automatically roll it back.
*
* @return <code>ActionStatus</code> indicating outcome.
*/
public Future<Integer> begin (int timeout)
{
return _threadPool.submit(new TransactionExecutorBegin(timeout, _theTransaction));
}
/**
* Commit the transaction, and have heuristic reporting. Heuristic reporting
* via the return code is enabled.
*
* @return <code>ActionStatus</code> indicating outcome.
*/
public Future<Integer> commit ()
{
return commit(true);
}
/**
* Commit the transaction. The report_heuristics parameter can be used to
* determine whether or not heuristic outcomes are reported.
*
* If the transaction has already terminated, or has not begun, then an
* appropriate error code will be returned.
*
* @return <code>ActionStatus</code> indicating outcome.
*/
public Future<Integer> commit (boolean report_heuristics)
{
return _threadPool.submit(new TransactionExecutorCommit(report_heuristics, _theTransaction));
}
/**
* Abort (rollback) the transaction.
*
* If the transaction has already terminated, or has not been begun, then an
* appropriate error code will be returned.
*
* @return <code>ActionStatus</code> indicating outcome.
*/
public Future<Integer> abort ()
{
return _threadPool.submit(new TransactionExecutorAbort(_theTransaction));
}
/*
* @return the timeout associated with this instance.
*/
public final int getTimeout ()
{
return _theTransaction.getTimeout();
}
/**
* The type of the class is used to locate the state of the transaction log
* in the object store.
*
* Overloads BasicAction.type()
*
* @return a string representation of the hierarchy of the class for storing
* logs in the transaction object store.
*/
public String type ()
{
return _theTransaction.type();
}
/**
* Suspend all transaction association from the invoking thread. When this
* operation returns, the thread will be associated with no transactions.
*
* If the current transaction is not an AtomicAction then this method will
* not suspend.
*
* Note, we do not provide an async version of suspend because it would be
* wrong for an application thread to proceed under the assumption it had
* succeeded/happened yet. Ordering of events makes a difference here.
*
* @return a handle on the current AtomicAction (if any) so that the thread
* can later resume association if required.
*
*/
public static final Transaction suspend ()
{
return new Transaction(AtomicAction.suspend());
}
/**
* Resume transaction association on the current thread. If the specified
* transaction is null, then this is the same as doing a suspend. If the
* current thread is associated with transactions then those associations
* will be lost.
*
* Note, we do not provide an async version of resume because it would be
* wrong for an application thread to proceed under the assumption it had
* succeeded/happened yet. Ordering of events makes a difference here.
*
* @param act the transaction to associate. If this is a nested
* transaction, then the thread will be associated with all of
* the transactions in the hierarchy.
*
* @return <code>true</code> if association is successful,
* <code>false</code> otherwise.
*/
public static final boolean resume (Transaction act)
{
return AtomicAction.resume(act._theTransaction);
}
private Transaction (AtomicAction act)
{
_theTransaction = act;
}
private AtomicAction _theTransaction;
private final ExecutorService _threadPool = Executors.newFixedThreadPool(1);
}