/**
 * Copyright (C) 2000-2010 Atomikos <info@atomikos.com>
 *
 * This code ("Atomikos TransactionsEssentials"), by itself,
 * is being distributed under the
 * Apache License, Version 2.0 ("License"), a copy of which may be found at
 * http://www.atomikos.com/licenses/apache-license-2.0.txt .
 * You may not use this file except in compliance with the License.
 *
 * While the License grants certain patent license rights,
 * those patent license rights only extend to the use of
 * Atomikos TransactionsEssentials by itself.
 *
 * This code (Atomikos TransactionsEssentials) contains certain interfaces
 * in package (namespace) com.atomikos.icatch
 * (including com.atomikos.icatch.Participant) which, if implemented, may
 * infringe one or more patents held by Atomikos.
 * It should be appreciated that you may NOT implement such interfaces;
 * licensing to implement these interfaces must be obtained separately from Atomikos.
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 */

package com.atomikos.icatch.system;

import com.atomikos.icatch.CompositeTransaction;
import com.atomikos.icatch.HeuristicMessage;
import com.atomikos.icatch.Propagation;
import com.atomikos.icatch.RollbackException;
import com.atomikos.icatch.SubTxCode;
import com.atomikos.icatch.SysException;

/**
 * 
 * 
 * A thread class for subtransaction threads. A SubTxThread is a thread whose
 * code is automatically executed in a subtransaction of the calling thread's
 * transaction. Creation, start and end of the subtransaction is done by the
 * system so the programmer does not have to worry about that. To create a new
 * instance, you need a <a href="Waiter.html">Waiter</a> and a <a
 * href="SubTxCode.html">SubTxCode</a> instance.
 */

public class SubTxThread extends Thread
{
    private SubTxCode myCode;
    private Waiter myWaiter;
    private Exception myException;
    private CompositeTransaction parent;
    private Propagation propagation;
    private HeuristicMessage msg;

    /**
     * Creates a new instance for a given waiter, with a given subtx code.
     * 
     * @param w
     *            The waiter for synchronization. The creating thread should
     *            wait for all subtx threads to finish.
     * @param code
     *            The SubTxCode to execute.
     * @param tag
     *            A heuristic message for this thread's execution. Useful in
     *            case of heuristic problems.
     * @exception SysException
     *                On failure; for instance, if the calling thread has no
     *                transaction associated to it, or no transaction manager is
     *                running.
     */

    public SubTxThread ( Waiter w , SubTxCode code , HeuristicMessage tag )
            throws SysException
    {
        parent = Configuration.getCompositeTransactionManager ()
                .getCompositeTransaction ();
        // if (ct.getSerial()) throw new SystemException("Tx in serial mode;
        // multiple threads not allowed");

        msg = tag;
        try {
            propagation = Configuration.getExportingTransactionManager ()
                    .getPropagation ();
        } catch ( RollbackException e ) {
            throw new SysException ( "Transaction already rolled back" );
        }
        myWaiter = w;
        myWaiter.incActives ();
        myCode = code;
        myException = null;

    }

    public Exception getException ()
    {
        return myException;
    }

    public void run ()
    {
        CompositeTransaction ct = null;
        try {
            ct = Configuration.getImportingTransactionManager ()
                    .importTransaction ( propagation, true, false );
            ct.getTransactionControl ().setTag ( msg );
            if ( propagation.isSerial () )
                myWaiter.getToken ();
            myCode.exec ();
            // delegates call to implementation

            ct.getTransactionControl ().getTerminator ().commit ();
        } catch ( Exception e ) {
            myWaiter.incAbortCount ();
            myException = e;
            ct.getTransactionControl ().getTerminator ().rollback ();
        } finally {
            if ( propagation.isSerial () )
                myWaiter.giveToken ();
            myWaiter.decActives ();
        }

    }

}
