/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 * 
 * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
 * 
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License. You can obtain
 * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
 * or glassfish/bootstrap/legal/LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 * 
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
 * Sun designates this particular file as subject to the "Classpath" exception
 * as provided by Sun in the GPL Version 2 section of the License file that
 * accompanied this code.  If applicable, add the following below the License
 * Header, with the fields enclosed by brackets [] replaced by your own
 * identifying information: "Portions Copyrighted [year]
 * [name of copyright owner]"
 * 
 * Contributor(s):
 * 
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 */

/*
 * Copyright 2004-2005 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */
//----------------------------------------------------------------------------
//
// Module:      CoordinatorResourceImpl.java
//
// Description: Subordinate Coordinator participation interface.
//
// Product:     com.sun.jts.CosTransactions
//
// Author:      Simon Holdsworth
//
// Date:        March, 1997
//
// Copyright (c):   1995-1997 IBM Corp.
//
//   The source code for this program is not published or otherwise divested
//   of its trade secrets, irrespective of what has been deposited with the
//   U.S. Copyright Office.
//
//   This software contains confidential and proprietary information of
//   IBM Corp.
//----------------------------------------------------------------------------

package com.sun.jts.CosTransactions;

// Import required classes.

import org.omg.CORBA.*;
import org.omg.PortableServer.*;
import org.omg.PortableServer.POAPackage.ServantAlreadyActive;
import org.omg.PortableServer.POAPackage.ServantNotActive;
import org.omg.CosTransactions.*;

import com.sun.jts.otsidl.*;

import com.sun.jts.trace.*;
import java.util.logging.Logger;
import java.util.logging.Level;
import com.sun.logging.LogDomains;
import com.sun.jts.utils.LogFormatter;

/**The CoordinatorResourceImpl interface provides operations that allow a
 * Coordinator to be represented among the registered Resources of a
 * superior Coordinator, without requiring that the Coordinator support the
 * Resource interface.
 *
 * @version 0.02
 *
 * @author Simon Holdsworth, IBM Corporation
 *
 * @see
*/
//----------------------------------------------------------------------------
// CHANGE HISTORY
//
// Version By     Change Description
//   0.01  SAJH   Initial implementation.
//   0.02  GDH    Gordon Hutchison April 1998
//                Improved behaviour post recovery occurring
//-----------------------------------------------------------------------------

class CoordinatorResourceImpl extends CoordinatorResourcePOA
        implements CompletionHandler {
    private static POA poa = null;
    private static boolean recoverable = false;
    private CoordinatorResource thisRef = null;

    /**This flag may be set to indicate that the transaction is being forced.
     */
    boolean beingForced = false;

    private GlobalTID globalTID = null;
    private boolean   subtransaction = false;
    private boolean   aborted = false;
    private boolean   heuristicDamage = false;
    private boolean   completed = false;
    private boolean   setAsTerminator = false;

	/*
		Logger to log transaction messages
	*/
	
	static Logger _logger = LogDomains.getLogger(LogDomains.TRANSACTION_LOGGER);
    /**Normal constructor.
     * <p>
     * Sets up the CoordinatorResourceImpl with the Coordinator reference and the
     * local transaction identifier so that the Resource can always find the
     * Coordinator to pass on the two-phase commit messages.
     * <p>
     * A flag is passed to indicate whether the CoordinatorResourceImpl represents
     * a subtransaction.
     *
     * @param globalTID  The global transaction identifier.
     * @param coord      The Coordinator for the transaction.
     * @param subtran    Subtransaction indicator.
     *
     * @return
     *
     * @see
     */
    CoordinatorResourceImpl( GlobalTID       globalTID,
                             CoordinatorImpl coord,
                             boolean         subtran ) {


        // Set up the instance variables to those values passed in.

        subtransaction = subtran;
        this.globalTID = globalTID;

        // Inform the Coordinator that this is the object that normally terminates
        // the transaction.

        if( coord != null )
            coord.setTerminator(this);

    }

    /**Cleans up the state of the object.
     *
     * @param
     *
     * @return
     *
     * @see
     */
    /*
    public void finalize() {

        globalTID = null;

    }
    */

    /**Informs the CoordinatorResourceImpl object that the transaction it
     * represents has completed.
     * <p>
     * Flags indicate whether the transaction aborted, and whether there was
     * heuristic damage.
     *
     * @param aborted          Indicates the transaction aborted.
     * @param heuristicDamage  Indicates heuristic damage occurred.
     *
     * @return
     *
     * @see CompletionHandler
     */
    public void setCompleted( boolean aborted,
                              boolean heuristicDamage ) {

        // Record the information.

        completed = true;
        this.aborted = aborted;
        this.heuristicDamage = heuristicDamage;

    }

    /**Requests the prepare phase vote from the object.
     * <p>
     * This uses a private interface to pass the superior Coordinator's prepare request.
     * on to the Coordinator that registered the CoordinatorResourceImpl.
     * <p>
     * The result from the Coordinator is returned to the caller.
     *
     * @param
     *
     * @return  The Coordinators vote.
     *
     * @exception SystemException  The operation failed.
     * @exception HeuristicMixed  Indicates that a participant voted to roll the
     *   transaction back, but one or more others have already heuristically committed.
     * @exception HeuristicHazard  Indicates that a participant voted to roll the
     *   transaction back, but one or more others may have already heuristically
     *   committed.
     *
     * @see Resource
     */
    public Vote prepare()
        throws SystemException, HeuristicMixed, HeuristicHazard {


        Vote result = Vote.VoteRollback;

        // If no global identifier has been set up, we can do nothing but vote for
        // the transaction to be rolled back.

        if( globalTID == null ) {
            INTERNAL exc = new INTERNAL(MinorCode.NoGlobalTID,
                                        CompletionStatus.COMPLETED_NO);
            throw exc;
        }

        // Prepare operations should only come in for top-level transactions.

        if( subtransaction ) {

            INTERNAL exc = new INTERNAL(MinorCode.TopForSub,
                                        CompletionStatus.COMPLETED_NO);
            throw exc;
        }

        // If the transaction that this object represents has already been rolled
        // back, return a rollback vote.

        if (completed) {
            if (aborted) {
                result = Vote.VoteRollback;
            } else {
                result = Vote.VoteCommit;
            }
        } else {

            // Look up the Coordinator for the transaction.

            TopCoordinator coord = (TopCoordinator)RecoveryManager.getCoordinator(globalTID);

            // If there is a Coordinator, lock it for the duration of this operation.
            // If there is no Coordinator, return a rollback vote.

            if( coord != null )
                synchronized( coord ) {

                    // Get the Coordinator's vote.
                    // If the Coordinator throws HeuristicMixed or HeuristicHazard,
                    // allow them to percolate to the caller.

                    result = coord.prepare();

                    // If the Coordinator has voted to roll the transaction back, then this
                    // CoordinatorResourceImpl will not be called again.  Ensure that the
                    // Coordinator has rolled back.
                    // If the Coordinator throws HeuristicMixed or HeuristicHazard,
                    // allow them to percolate to the caller.

                    if( result == Vote.VoteRollback )
                        coord.rollback(false);
                }
        }

        // If the Coordinator has voted to roll the transaction back, then this
        // CoordinatorResourceImpl will not be called again.
        // If a heuristic exception was thrown, this will be done in forget.

        if (result == Vote.VoteRollback) {
            destroy();
        }

        return result;
    }

    /**Informs the object that the transaction is to be committed.
     * <p>
     * Passes the superior Coordinator's commit request on to the Coordinator that
     * registered the CoordinatorResourceImpl, using a private interface.
     * <p>
     * If the Coordinator does not raise any heuristic exception, the
     * CoordinatorResourceImpl destroys itself.
     *
     * @param
     *
     * @return
     *
     * @exception HeuristicRollback  The transaction has already been rolled back.
     * @exception HeuristicMixed  At least one participant in the transaction has
     *                            rolled back its changes.
     * @exception HeuristicHazard  At least one participant in the transaction may
     *                             have rolled back its changes.
     * @exception NotPrepared  The transaction has not yet been prepared.
     * @exception SystemException  An error occurred.  The minor code indicates
     *                             the reason for the exception.
     *
     * @see Resource
     */
    public void commit()
        throws HeuristicRollback, HeuristicMixed, HeuristicHazard, NotPrepared,
        SystemException {

        // If no global identifier has been set up, we can do nothing.

        if( globalTID == null ) {
            INTERNAL exc = new INTERNAL(MinorCode.NoGlobalTID,
                                        CompletionStatus.COMPLETED_NO);
            throw exc;
        }

        // Commit operations should only come in for top-level transactions.

        if( subtransaction ) {
            INTERNAL exc = new INTERNAL(MinorCode.TopForSub,
                                        CompletionStatus.COMPLETED_NO);
            throw exc;
        }

        // If the transaction that this object represents has already been completed,
        // raise a heuristic exception if necessary.  This object must wait for a
        // forget before destroying itself if it returns a heuristic exception.

        if( completed ) {
            if( aborted ) {
                heuristicDamage = true;
                HeuristicRollback exc = new HeuristicRollback();
                throw exc;
            } else if( heuristicDamage ) {
                HeuristicMixed exc = new HeuristicMixed();
                throw exc;
            }
        } else {

            // Look up the Coordinator for the transaction.

            // GDH: First of all make sure it has been recovered if necessary
	    if(_logger.isLoggable(Level.FINE))
	    {
			_logger.logp(Level.FINE,"CoordinatorResourceImpl","commit()",
					"Before invoking RecoveryManager.waitForRecovery():"+
					"GTID is: "+ globalTID.toString());

	    }
            RecoveryManager.waitForRecovery();

            TopCoordinator coord = (TopCoordinator)RecoveryManager.getCoordinator(globalTID);

            // If there is a Coordinator, lock it for the duration of this operation.
            // Tell the Coordinator to commit.
            // If the Coordinator throws HeuristicMixed or HeuristicHazard,
            // allow them to percolate to the caller.

            if( coord != null )
                synchronized( coord ) {
                    // GDH:
                    // Make sure the coordinator knows we are it's terminator
                    // (this is done here in case we are in a recovery situation)
                    // (the operation has been moved from the constructor of the
                    // this object to here as the constructor is now called
                    // to early to ensure the coordinator is present in all
                    // cases

                    // GDH:
                    // If the transaction has completed at this point the
                    // makeSureSetAsTerminator method will be unable to
                    // set the coordinators terminator and will throw
                    // an object not exist exception: This is what we want in this case.

                    makeSureSetAsTerminator();
                    coord.commit();
                }
        }

        // If and we are not being forced, we can destroy ourselves before returning.
        // Otherwise, the TopCoordinator will have called setCompleted to set up
        // the information we need should a subsequent commit or rollback request
        // arrive.

        if( !beingForced )
            destroy();

    }

    /**Informs the object that the transaction is to be committed in one phase.
     * <p>
     * Passes the superior Coordinator's single-phase commit request on to the
     * Coordinator that registered the CoordinatorResourceImpl, using a private
     * interface.
     * <p>
     * The result from the Coordinator is returned to the caller. If the
     * Coordinator did not raise any heuristic exception, the CoordinatorResourceImpl
     * destroys itself.
     *
     * @param
     *
     * @return
     *
     * @exception TRANSACTION_ROLLEDBACK  The transaction could not be committed and
     *                                   has been rolled back.
     * @exception HeuristicHazard  One or more resources in the transaction may have
     *                             rolled back.
     * @exception SystemException  An error occurred.  The minor code indicates
     *                             the reason for the exception.
     *
     * @see Resource
     */
    public void commit_one_phase()
        throws TRANSACTION_ROLLEDBACK, HeuristicHazard, SystemException {

        boolean rolledBack;


        // If no global_identifier has been set up, we can do nothing.

        if( globalTID == null ) {
            INTERNAL exc = new INTERNAL(MinorCode.NoGlobalTID,
                                        CompletionStatus.COMPLETED_NO);
            throw exc;
        }

        // Commit operations should only come in for top-level transactions.

        if( subtransaction ) {
            INTERNAL exc = new INTERNAL(MinorCode.TopForSub,
                                        CompletionStatus.COMPLETED_NO);
            throw exc;
        }

        // If the transaction that this object represents has already been completed,
        // raise an exception if necessary.

        if( completed ) {
            if( aborted ) {
                TRANSACTION_ROLLEDBACK exc = new TRANSACTION_ROLLEDBACK(0,CompletionStatus.COMPLETED_NO);
                throw exc;
            }
        } else {

            // Look up the Coordinator for the transaction.

            // GDH: First of all make sure it has been recovered if necessary
	    if(_logger.isLoggable(Level.FINE))
	    {
			_logger.logp(Level.FINE,"CoordinatorResourceImpl","commit_one_phase()",
					"Before invoking RecoveryManager.waitForRecovery(): "+
					"GTID is: " + globalTID.toString());
	    }
            RecoveryManager.waitForRecovery();

            TopCoordinator coord = (TopCoordinator)RecoveryManager.getCoordinator(globalTID);

            // If there is a Coordinator, lock it for the duration of this operation.
            // Tell the Coordinator to commit, by first doing a prepare.
            // If the Coordinator throws HeuristicMixed or HeuristicHazard,
            // allow them to percolate to the caller.

            if( coord != null ) {
                rolledBack = false;

                synchronized( coord ) {

                    // GDH:
                    // Make sure the coordinator knows we are it's terminator
                    // (this is done here in case we are in a recovery situation)
                    // (the operation has been moved from the constructor of the
                    // this object to here as the constructor is now called
                    // to early to ensure the coordinator is present in all
                    // cases
                    makeSureSetAsTerminator();

                    // The prepare operation may throw the HeuristicHazard exception.  In this case
                    // allow it to go back to the caller.

                    Vote vote = Vote.VoteRollback;
                    try {
                        vote = coord.prepare();
                    } catch( HeuristicMixed exc ) {
                        throw new HeuristicHazard();
                    }
                    try {
                        if( vote == Vote.VoteCommit )
                            coord.commit();
                        else if (vote == Vote.VoteRollback) {
                            // COMMENT (Ram J) 12/11/2000 The above if check
                            // for rollback was added to avoid throwing a
                            // rollback exception for readonly votes.
                            coord.rollback(true);
                            rolledBack = true;
                        }
                    } catch (Throwable exc) {
                        // ADDED(Ram J) percolate any system exception
                        // back to the caller.
                        if (exc instanceof INTERNAL) {
                            destroy();
                            throw (INTERNAL) exc;
                        }
                    }
                }

            } else {
                // coord is null
                // We could still find no coord that matched even after recovery
                // If there is still no coord then the process failed between
                // deleting the subordinate coordinator and the result being received
                // in the superior.   As all of the recoverable work occurred in this
                // server or in its subordinate servers (we are in cop), from a data integrity point of
                // view, it does not matter what result the CoordinatorResource returns
                // to the superior.  However, the superior may still have a client attached
                // and it would look strange if the transaction actually rolled back and
                // the TRANSACTION_ROLLEDBACK exception was not reported to the client.
                // Therefore we jump through hoops to give the best answer as possible.
                // By delaying the call to forget_superior until CoordinatorResource's
                // destructor we ensure the Coordinator and the CoordinatorResource are
                // deleted together (as much as is possible in the JAVA/CORBA environment) and
                // this occurs after the response has been sent to the superior (because
                // the ORB is holding a reference count to the CoordinatorResource).
                // Therefore, the most likely reason for this to occur is that the
                // Coordinator was timed out (and removed) just before the server
                // terminated.  In this case, the transaction rolled back, which is the
                // response that will be returned.

                rolledBack = true;

            }

            if( rolledBack ) {
                destroy();
                TRANSACTION_ROLLEDBACK exc = new TRANSACTION_ROLLEDBACK(0,CompletionStatus.COMPLETED_YES);
                throw exc;
            }
        }

        // Self-destruct before returning.

        destroy();

    }

    /**Informs the object that the transaction is to be rolled back.
     * <p>
     * Passes the superior Coordinator's rollback request on to the Coordinator
     * that registered the CoordinatorResourceImpl, using a private interface.
     * <p>
     * If the Coordinator does not raise any heuristic exception, the
     * CoordinatorResourceImpl destroys itself.
     *
     * @param
     *
     * @return
     *
     * @exception HeuristicCommit  The transaction has already been committed.
     * @exception HeuristicMixed  At least one participant in the transaction has
     *                            committed its changes.
     * @exception HeuristicHazard  At least one participant in the transaction may
     *                             have rolled back its changes.
     * @exception SystemException  An error occurred.  The minor code indicates
     *                             the reason for the exception.
     *
     * @see Resource
     *///----------------------------------------------------------------------------
         public void rollback()
             throws HeuristicCommit, HeuristicMixed,
             HeuristicHazard, SystemException {

             // If no global identifier has been set up, we can do nothing.

             if( globalTID == null ) {
                 INTERNAL exc = new INTERNAL(MinorCode.NoGlobalTID,
                                             CompletionStatus.COMPLETED_NO);
                 throw exc;
             }

             // Rollback operations should only come in for top-level transactions.

             if( subtransaction ) {
                 INTERNAL exc = new INTERNAL(MinorCode.TopForSub,
                                             CompletionStatus.COMPLETED_NO);
                 throw exc;
             }

             // If the transaction that this object represents has already been completed,
             // raise a heuristic exception if necessary.  This object must wait for a
             // forget before destroying itself if it returns a heuristic exception.

             if( completed ) {
                 if( !aborted ) {
                     heuristicDamage = true;
                     HeuristicCommit exc = new HeuristicCommit();
                     throw exc;
                 }
                 else if( heuristicDamage ) {
                     HeuristicMixed exc = new HeuristicMixed();
                     throw exc;
                 }
             } else {

                 // Look up the Coordinator for the transaction.

                 // GDH: First of all make sure it has been recovered if necessary
	    	if(_logger.isLoggable(Level.FINE))
	    	{
				_logger.logp(Level.FINE,"CoordinatorResourceImpl","rollback()",
						"Before invoking RecoveryManager.waitForRecovery(): "+
						"GTID is : "+ globalTID.toString()); 
			
	    	}
                 RecoveryManager.waitForRecovery();

                 TopCoordinator coord = (TopCoordinator)RecoveryManager.getCoordinator(globalTID);

                 // If there is a Coordinator, lock it for the duration of this operation.
                 // Tell the Coordinator to rollback.
                 // If the Coordinator throws HeuristicMixed or HeuristicHazard,
                 // allow them to percolate to the caller.

                 if( coord != null )
                     synchronized( coord ) {

                         // GDH:
                         // Make sure the coordinator knows we are it's terminator
                         // (this is done here in case we are in a recovery situation)
                         // (the operation has been moved from the constructor of the
                         // this object to here as the constructor is now called
                         // to early to ensure the coordinator is present in all
                         // cases
                         makeSureSetAsTerminator();
                         coord.rollback(true);
                     }
             }

             // If we are not being forced, we can destroy ourselves before returning.
             // Otherwise, the TopCoordinator will have called set_completed to set up
             // the information we need should a subsequent commit or rollback request
             // arrive.

             if( !beingForced )
                 destroy();

         }

    /**Informs the object that the transaction is to be forgotten.
     * <p>
     * Informs the CoordinatorResourceImpl that it does not need to retain heuristic
     * information any longer.
     *
     * @param
     *
     * @return
     *
     * @exception  SystemException  An error occurred.  The minor code indicates
     *                              the reason for the exception.
     *
     * @see
     */
    public void forget() throws SystemException {

        // Forget operations should only come in for top-level transactions.

        if( subtransaction ) {
            INTERNAL exc = new INTERNAL(MinorCode.TopForSub,
                                        CompletionStatus.COMPLETED_NO);
            throw exc;
        }

        // If no exception is raised, we can destroy ourselves before returning.

        destroy();
    }

    /**Informs the object that the subtransaction is to be committed.
     * <p>
     * Passes the superior Coordinator's commit request on to the SubCoordinator
     * that registered the CoordinatorResourceImpl, using a private interface.
     * <p>
     * The result from the SubCoordinator is returned to the caller. The
     * CoordinatorResourceImpl destroys itself.
     *
     * @param parent  The parent Coordinator reference.
     *
     * @return
     *
     * @exception TRANSACTION_ROLLEDBACK  The transaction could not be committed
     *                                   and some parts may have rolled back.
     * @exception SystemException  An error occurred.  The minor code indicates
     *                             the reason for the exception.
     *
     * @see
     */
    public void commit_subtransaction( Coordinator parent )
        throws TRANSACTION_ROLLEDBACK, SystemException {

        // If no global identifier has been set up, we can do nothing.

        if( globalTID == null ) {
            INTERNAL exc = new INTERNAL(MinorCode.NoGlobalTID,
                                        CompletionStatus.COMPLETED_NO);
            throw exc;
        }

        // Commit_subtransaction operations should only come in for subtransactions.

        if( !subtransaction ) {
            INTERNAL exc = new INTERNAL(MinorCode.SubForTop,
                                        CompletionStatus.COMPLETED_NO);
            throw exc;
        }

        // If the transaction that this object represents has already been rolled
        // back, raise the TRANSACTION_ROLLEDBACK exception.

        if( completed ) {
            if( aborted ) {
                destroy();
                TRANSACTION_ROLLEDBACK exc = new TRANSACTION_ROLLEDBACK(0,CompletionStatus.COMPLETED_YES);
                throw exc;
            }
        } else {

            // Look up the Coordinator for the subtransaction.

            SubCoordinator coord = (SubCoordinator)RecoveryManager.getCoordinator(globalTID);

            // If there is a Coordinator, lock it for the duration of this operation.
            // Tell the Coordinator to prepare then commit.
            // Record then ignore any exceptions - we do not expect heuristics during
            // subtransaction completion.

            if( coord != null ) {
                boolean rolledBack = false;

                synchronized( coord ) {
                    try {
                        if( coord.prepare() == Vote.VoteCommit )
                            coord.commit();
                        else {
                            coord.rollback(true);
                            rolledBack = true;
                        }
                    }
                    catch( Throwable ex ) {
                    }
                }

                if( rolledBack ) {
                    destroy();
                    TRANSACTION_ROLLEDBACK exc = new TRANSACTION_ROLLEDBACK(0,CompletionStatus.COMPLETED_YES);
                    throw exc;
                }
            }
        }

        // Destroy ourselves before returning (there is no heuristic information for
        // subtransactions).

        destroy();

    }

    /**Informs the object that the subtransaction is to be rolled back.
     * <p>
     * Passes the superior Coordinator's rollback request on to the SubCoordinator
     * that registered the CoordinatorResourceImpl, using a private interface.
     * <p>
     * The result from the SubCoordinator is returned to the caller. The
     * CoordinatorResourceImpl destroys itself.
     *
     * @param
     *
     * @return
     *
     * @exception SystemException  An error occurred.  The minor code indicates
     *                             the reason for the exception.
     *
     * @see
     */

    public void rollback_subtransaction() throws SystemException {

        // If no global identifier has been set up, we can do nothing.

        if( globalTID == null ) {
            INTERNAL exc = new INTERNAL(MinorCode.NoGlobalTID,
                                        CompletionStatus.COMPLETED_NO);
            throw exc;
        }

        // Commit_subtransaction operations should only come in for subtransactions.

        if( !subtransaction ) {
            INTERNAL exc = new INTERNAL(MinorCode.SubForTop,
                                        CompletionStatus.COMPLETED_NO);
            throw exc;
        }

        // If the transaction that this object represents has already been completed,
        // do nothing.

        if( !completed ) {

            // Look up the Coordinator for the transaction.

            SubCoordinator coord = (SubCoordinator)RecoveryManager.getCoordinator(globalTID);

            // If there is a Coordinator, lock it for the duration of this operation.
            // Tell the Coordinator to rollback.

            if( coord != null )
                synchronized( coord ) {
                    coord.rollback(true);
                }
        }

        // Destroy ourselves before returning (there is no heuristic information for
        // subtransactions).

        destroy();

    }

    /**Creates the CoordinatorResourceImpl with the given key.  This is done when
     * the CoordinatorResource object is recreated after the server has been
     * restarted.
     *
     * @param key  The key for the object.
     *
     * @return
     *
     * @see
     */
    CoordinatorResourceImpl( byte[] key ) {

        // Get the global transaction identifier from the key.

        globalTID = new GlobalTID(key);

        // GDH
        // Ensure that recovery has completed so that we can get the Coordinator.
        // This is now delayed until the 2PC methods for normal resync and is
        // done as part of the superinfo.reconst

        //    RecoveryManager.waitForRecovery();

        // Check that the global transaction identifier represents a known transaction.
        // If it does not, then throw the OBJECT_NOT_EXIST exception.

        //    CoordinatorImpl coord = RecoveryManager.getCoordinator(globalTID);
        //    if( coord == null )
        //      {
        //      OBJECT_NOT_EXIST exc = new OBJECT_NOT_EXIST();
        //      if( trc != null ) trc.event(EVT_THROW).data(exc).write();
        //      throw exc;
        //      }

        // If the transaction is known, then inform the Coordinator that this is the
        // terminator for it.

        //    else
        //      coord.setTerminator(this);

        // Leave other members at the default values.

    }

    /**Returns the CORBA Object which represents this object.
     *
     * @param
     *
     * @return  The CORBA object.
     *
     * @see
     */
    CoordinatorResource object() {
        if( thisRef == null ) {
            if( poa == null ) {
                poa = Configuration.getPOA("CoordinatorResource"/*#Frozen*/);
                recoverable = Configuration.isRecoverable();
            }

            try {
                byte[] id = null;
                if (recoverable && globalTID != null) {
                    id = globalTID.toBytes();
                    poa.activate_object_with_id(id, this);
                    org.omg.CORBA.Object obj = poa.create_reference_with_id(id, CoordinatorResourceHelper.id());
                    thisRef = CoordinatorResourceHelper.narrow(obj);
                    //thisRef = (CoordinatorResource) this;
                } else {
                    poa.activate_object(this);
                    org.omg.CORBA.Object obj = poa.servant_to_reference(this);
                    thisRef = CoordinatorResourceHelper.narrow(obj);
                    //thisRef = (CoordinatorResource) this;
                }
            } catch( ServantAlreadyActive saexc ) {
				_logger.log(Level.SEVERE,
						"jts.create_CoordinatorResource_object_error",saexc);
				String msg = LogFormatter.getLocalizedMessage(_logger,
										 "jts.create_CoordinatorResource_object_error");
				throw  new org.omg.CORBA.INTERNAL(msg);
						
            } catch( ServantNotActive snexc ) {
				_logger.log(Level.SEVERE,
						"jts.create_CoordinatorResource_object_error",snexc);
				String msg = LogFormatter.getLocalizedMessage(_logger,
										 "jts.create_CoordinatorResource_object_error");
				throw  new org.omg.CORBA.INTERNAL(msg);
						
            } catch( Exception exc ) {
				_logger.log(Level.SEVERE,
						"jts.create_CoordinatorResource_object_error",exc);
				String msg = LogFormatter.getLocalizedMessage(_logger,
										 "jts.create_CoordinatorResource_object_error");
				throw  new org.omg.CORBA.INTERNAL(msg);
						
            }
        }

        return thisRef;
    }

    /**Destroys the CoordinatorResourceImpl object.
     *
     * @param
     *
     * @return
     *
     * @see
     */
    void destroy() {

        try {
            if (poa != null && thisRef != null) {
                poa.deactivate_object(poa.reference_to_id(thisRef));
                thisRef = null;
            } else {
                // BUGFIX(Ram J) It is possible that the
                // CoordinatorResource object was activated via the activation
                // daemon. In that case, there is no guarantee
                // that poa and thisRef are set to a meaningful value.
                // So, try to deactivate the CoordinatorResource object anyway.

                POA crPoa = null;
                if (poa == null) {
                    crPoa = Configuration.getPOA("CoordinatorResource"/*#Frozen*/);
                } else {
                    crPoa = poa;
                }
                if (thisRef == null) {
                    crPoa.deactivate_object(crPoa.servant_to_id(this));
                } else {
                    crPoa.deactivate_object(crPoa.reference_to_id(thisRef));
                    thisRef = null;
                }
            }
        } catch( Exception exc ) {
			 _logger.log(Level.WARNING,"jts.object_destroy_error","CoordinatorResource");
				
        }

        // finalize();
        globalTID = null;
    }

    /**Dumps the state of the object.
     *
     * @param
     *
     * @return
     *
     * @see
     */
    void dump() {
    }

    /**Makes sure this object is set as the Coordinator Terminator
     *
     * @param
     *
     * @return
     *
     * @see
     */
    void makeSureSetAsTerminator() {

        if( !setAsTerminator ) {

            CoordinatorImpl coord = RecoveryManager.getCoordinator(globalTID);

            // If the transaction is not known then throw an exception,
            // otherwise inform the Coordinator that this is the
            // terminator for it.

            if( coord == null ) {
                OBJECT_NOT_EXIST exc = new OBJECT_NOT_EXIST();
                throw exc;
            } else {
                coord.setTerminator(this);
                setAsTerminator = true;
            }
        }

    }  // MakeSureSetAsTerminator method

    } // class

