FileDocCategorySizeDatePackage
SubCoordinator.javaAPI DocGlassfish v2 API66156Wed Jun 13 23:03:48 BST 2007com.sun.jts.CosTransactions

SubCoordinator

public class SubCoordinator extends CoordinatorImpl
The SubCoordinator interface is our implementation of the standard Coordinator interface that is used for subtransactions. It allows SubtransactionAwareResources to be registered for participation in a subtransaction. As an instance of this class may be accessed from multiple threads within a process, serialisation for thread-safety is necessary in the implementation. The information managed does not need to be reconstructible in the case of a failure as subtransactions are not durable.
version
0.01
author
Simon Holdsworth, IBM Corporation
see

Fields Summary
String
name
RegisteredResources
participants
SuperiorInfo
superInfo
NestingInfo
nestingInfo
TransactionState
tranState
CompletionHandler
terminator
boolean
registered
boolean
root
boolean
rollbackOnly
boolean
dying
boolean
temporary
int
hash
static Logger
_logger
static String[]
resultName
Directs the SubCoordinator to prepare to commit. The SubCoordinator checks that the subtransaction can be committed. It does not distribute prepare operations to the participants.
private static Any
emptyData
Constructors Summary
SubCoordinator(GlobalTID parentGlobalTID, Long parentLocalTID, CoordinatorImpl[] ancestors)
Creates and initialises a SubCoordinator, given the parent's local and global identifiers and the sequence of ancestors.

param
parentGlobalTID The parent's global transaction identifier.
param
parentLocalTID The parent's local transaction identifier.
param
ancestors This transactions's ancestors (includes parent).
return
exception
LogicErrorException An internal logic error occurred.
see



                                                                   
       
                

        // Allocate a new global identifier for the subtransaction.
        // If one cannot be allocated, raise an exception as the
        // subtransaction cannot be started.

        tranState = new TransactionState(parentLocalTID, parentGlobalTID);

        // Store information about the superior, ancestors and participants
        // of the new subtransaction.

        superInfo = new SuperiorInfo(tranState.localTID,
                                     tranState.globalTID, null, null);

        // Cache the name  - create a buffer and print the global XID into it.

        name = superInfo.globalTID.toString();

        // Cache the hash code.

        hash = superInfo.globalTID.hashCode();

        // Create the nesting info object to record the ancestors.

        nestingInfo = new NestingInfo(ancestors);

        // Zero out the RegisteredResources reference as it will be
        // created when needed.

        participants = null;

        // Set other instance variables.

        root = true;
        registered = true;
        rollbackOnly = false;
        dying = false;
        temporary = false;
        terminator = null;

        // Set the state of the subtransaction to active before making it
        // visible to the RecoveryManager.

        if (!tranState.setState(TransactionState.STATE_ACTIVE)) {
            LogicErrorException exc =
                new LogicErrorException(
					 LogFormatter.getLocalizedMessage(_logger,
					 "jts.invalid_state_change"));
            throw exc;
        } else {
            // Inform the RecoveryManager of the existence of this transaction.
            RecoveryManager.addCoordinator(tranState.globalTID,
                                           tranState.localTID, this, 0);
        }
    
SubCoordinator(GlobalTID globalTID, Coordinator superior, boolean temporary, CoordinatorImpl[] ancestors)
Creates and initialises a subordinate SubCoordinator, given the global identifier, a reference to the superior SubCoordinator, and the ancestors of the transaction. The temporary subordinate indicator is used for the case where a parent Coordinator is created when a subtransaction enters a process for the first time. If the request returns and the subtransaction has no participants, it is destroyed, along with any temporary ancestors.

param
globalTID The global identifier for the transaction.
param
superior The superior Coordinator.
param
temporary The temporary flag.
param
ancestors The ancestors of the transaction.
return
exception
LogicErrorException An internal logic error occurred.
see


        // Allocate a new local identifier for the transaction.  If one cannot
        // be allocated, raise an exception as the transaction
        // cannot be started.

        tranState = new TransactionState(globalTID,null);

        // Store information about the superior, ancestors and participants of
        // the new subordinate transaction.

        superInfo = new SuperiorInfo(tranState.localTID,
                                     globalTID, superior, null);

        // Cache the name  - create a buffer and print the global XID into it.

        name = superInfo.globalTID.toString();

        // Cache the hash code.

        hash = superInfo.globalTID.hashCode();

        // Create the nesting info object to record the ancestors.

        nestingInfo = new NestingInfo(ancestors);

        // Zero out the RegisteredResources reference,
        // as it will be created when needed.

        participants = null;

        // Set other instance variables.

        root = false;
        registered = false;
        rollbackOnly = false;
        dying = false;
        this.temporary = temporary;
        terminator = null;

        // Set the state of the transaction to active before making it visible
        // to the TransactionManager.

        if (!tranState.setState(TransactionState.STATE_ACTIVE)) {
            LogicErrorException exc = 
				new LogicErrorException(
					LogFormatter.getLocalizedMessage(_logger,
					"jts.invalid_state_change"));
            throw exc;
        } else if (!RecoveryManager.addCoordinator(globalTID,
                                                   tranState.localTID,
                                                   this, 0)) {
            LogicErrorException exc =
                new LogicErrorException(
					LogFormatter.getLocalizedMessage(_logger,
					"jts.transaction_id_already_in_use"));
            throw exc;
        }
    
Methods Summary
synchronized booleanaddChild(CoordinatorImpl child)
Adds the given Coordinator reference to the set of children of the target SubCoordinator.

param
child The child Coordinator.
return
Indicates success of the operation.
see


        boolean result = nestingInfo.addChild(child);
        return result;
    
voidcleanUpEmpty(CoordinatorImpl parent)
Cleans up an empty Coordinator.

param
parent The parent Coordinator, if any.
return
see


        // Roll the transaction back, ignoring any exceptions.

        try {
            rollback(true);
        } catch (Throwable exc) {}

        // If the transaction is a subtransaction, remove the
        // child from the parent's  set of children.
        // If the parent is temporary, this will cause the parent
        // to call cleanup_empty_coordinator, and so-on until all
        // empty ancestors are cleaned up.

        if (parent != null) {
            parent.removeChild(this);
        }
    
voidcommit()
Directs the SubCoordinator to commit the transaction. The SubCoordinator directs all registered Resources to commit.

param
return
see


        Coordinator parent = null;

        // Record that the Coordinator is about to commit.
        // Until we actually distribute commit flows, synchronize the method.

        synchronized (this) {

            // If the SubCoordinator is in the wrong state, return immediately.

            if (!tranState.setState(TransactionState.STATE_COMMITTING)) {
					_logger.log(Level.SEVERE,"jts.transaction_wrong_state",
							"commit");
					 String msg = LogFormatter.getLocalizedMessage(_logger,
				 							"jts.transaction_wrong_state",
											new java.lang.Object[] {
											"commit"});
					 throw  new org.omg.CORBA.INTERNAL(msg);
            }

            // Get the reference of the parent Coordinator.

            parent = nestingInfo.getParent(false).object();

            // Release the lock before proceeding with commit.

        }

        // Commit all participants.  If a fatal error occurs during this
        // method, then the process must be ended with a fatal error.

        if (participants != null) {
            try {
                participants.distributeSubcommit(parent);
            } catch (Throwable exc) {
				_logger.log(Level.SEVERE,"jts.exception_on_resource_operation",
                        new java.lang.Object[] { exc.toString(),
						"commit"});
				 String msg = LogFormatter.getLocalizedMessage(_logger,
				 							"jts.exception_on_resource_operation",
											new java.lang.Object[]
											{exc.toString(),
											"commit"});
				 throw  new org.omg.CORBA.INTERNAL(msg);
            }
        }

        // The remainder of the method needs to be synchronized.

        synchronized (this) {

            // Record that objects have been told to commit.
            // Set the state

            if (!tranState.setState(TransactionState.STATE_COMMITTED)) {
					_logger.log(Level.SEVERE,"jts.transaction_wrong_state",
							"commit");
					 String msg = LogFormatter.getLocalizedMessage(_logger,
				 							"jts.transaction_wrong_state",
											new java.lang.Object[] {
											"commit"});
					 throw  new org.omg.CORBA.INTERNAL(msg);
            }

            // Remove our reference from the parents set of children

            nestingInfo.removeFromParent(this);

            // Clean up the SubCoordinator after a commit.
            // In the case where the SubCoordinator is a root,
            // the CoordinatorTerm object must be informed that the
            // transaction has completed so that if another
            // caller has committed the transaction the object
            // normally responsible for terminating the transaction
            // can take the appropriate action. NOTE: This may DESTROY
            // the SubCoordinator object so NO INSTANCE VARIABLES
            // should be referenced after the call.
            // In the case where the SubCoordinator is a subordinate, the
            // CoordinatorResource object must be informed that the transaction
            // has been completed so that it can handle any subsequent requests
            // for the transaction.

            if (terminator != null) {
                terminator.setCompleted(false, false);
            }

            // As subtransactions do not have synchronization,
            // there is nothing left to  do, so get the
            //RecoveryManager to forget about us, then self-destruct.

            RecoveryManager.removeCoordinator(superInfo.globalTID,
                                              superInfo.localTID, false);
            destroy();

            /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
            /* NO INSTANCE VARIABLES MAY BE ACCESSED FROM THIS POINT ON.     */
            /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/

        }
    
booleancommitOnePhase()
Directs the SubCoordinator to commit the transaction in one phase The SubCoordinator directs all registered Resources to commit.

param
return
see


        // The commit of a subtransaction is always a one phase commit.
        // The implementation of the prepare/commit methods simply
        // split this up into two parts: the prepare checks the state and
        // the commit calls the resources.  Therefore commit_one_phase can
        // simply call these methods directly.
        // Also we let any exception pass up through.

        Vote v = this.prepare();

        if (v == Vote.VoteCommit) {
           this.commit();
        } else if (v == Vote.VoteReadOnly) {
            // Nothing to do
        } else {
            this.rollback(true);
        }

        return true;
    
public synchronized Controlcreate_subtransaction()
Creates a subtransaction and returns a Control object that represents the child transaction.

param
return
The Control object for the new child transaction.
exception
Inactive The Coordinator is completing the subtransaction and cannot create a new child.
see


        Control result = null;

        // First check the state of the transaction. If it is not active,
        // do not allow the subtransaction to be created.

        if (tranState == null ||
                tranState.state != TransactionState.STATE_ACTIVE) {
            Inactive exc = new Inactive();
            throw exc;
        }

        // Set up the sequence of ancestors to hold the single reference
        // and global identifier of the top-level SubCoordinator
        // as there are no ancestors. We do not need to make a copy of the
        // global TID as this is done by the factory when it creates the child.

        CoordinatorImpl[] thisAncestors = nestingInfo.getAncestors();
        CoordinatorImpl[] ancestors =
            new CoordinatorImpl[thisAncestors.length + 1];
        System.arraycopy(thisAncestors, 0, ancestors, 1, thisAncestors.length);
        ancestors[0] = this;

        // Create a new SubCoordinator, and initialise it with the given
        // identifiers and ancestry.  If the operation fails, return a
        // NULL Control object, and the SubtransactionsUnavailable exception.
        // Note that the ancestor sequence is not copied by the creation
        // operation.

        SubCoordinator child = null;
        TerminatorImpl terminator = null;
        try {
            child = new SubCoordinator(superInfo.globalTID,
                                       superInfo.localTID, ancestors);

            // Create a Terminator object, and initialise it with
            // the SubCoordinator reference and a flag to indicate that
            // it represents a subtransaction.

            terminator = new TerminatorImpl(child, true);

            // Create a Control object, and initialise it with the Terminator,
            // SubCoordinator and global OMGtid.

            result = new ControlImpl(terminator, child,
                                     new GlobalTID(child.getGlobalTID()),
                                     new Long(child.getLocalTID())).object();
        } catch (Throwable exc) {
            Inactive ex2 = new Inactive();
            throw ex2;
        }

        // If the operation succeeded, add the new child
        // to the set of children.

        nestingInfo.addChild(child);

        return result;
    
public voiddoFinalize()
Cleans up the state of the object.

param
return
see


        // Set the flag to indicate that the coordinator is being destroyed.

        dying = true;

        // What we do when destroyed depends on the transaction's state.
        // We assume that temporary Coordinators have rolled bak at this point.

        int state = TransactionState.STATE_ROLLED_BACK;
        if (tranState != null && !temporary) {
            state = tranState.state;
        }

        switch (state) {

        // If the transaction is active it should be rolled back.  This
        // will result in the TopCoordinator self-destructing at the
        // end of two-phase commit.

        case TransactionState.STATE_ACTIVE :
            rollback(true);
            break;

        // For committed or rolled-back, we really need to destroy the object

        case TransactionState.STATE_COMMITTED :
        case TransactionState.STATE_ROLLED_BACK :
            // if( tranState != null ) tranState.finalize();
            if( superInfo != null ) superInfo.doFinalize();
            // if( nestingInfo != null ) nestingInfo.finalize();
            // if( participants != null ) participants.finalize();

            tranState = null;
            superInfo = null;
            nestingInfo = null;
            participants = null;
            terminator = null;
            name = null;
            break;

        // For any other state, the transaction is completing, so the
        // TopCoordinator will eventually self-destruct.  We do nothing here.

        default :
            break;
        }
    
public booleanequals(java.lang.Object other)
Determines equality of the object with the parameter.

This relies on the availability of the propagation context from the target Coordinator.

If the other Coordinator is remote, and not a JCoordinator, and is in the process of ending the transaction, then this operation will fail; in this case we throw the INVALID_TRANSACTION exception with a minor code that indicates the cause of the failure.

Unfortunately this is the best we can do with the OMG interfaces when interoperating with a different OTS implementation.

param
other The other object.
return
Indicates equality.
see


        // Do a quick check on the object references.

        if (this == other) {
            return true;
        }

        // Obtain the global identifier for the other Coordinator.

        otid_t otherTID = null;

        if (other instanceof CoordinatorImpl) {
            // For local Coordinator objects which are really instances of the
            // CoordinatorImpl class, get the global TID via a private
            // method call.
            if (other instanceof SubCoordinator) {
                otherTID = ((SubCoordinator)other).superInfo.globalTID.realTID;
            }
        } else if (other instanceof org.omg.CORBA.Object) {

            // For remote Coordinator objects which are instances of the
            // JCoordinator class, use the getGlobalTID method remotely.

            try {
                JCoordinator jcoord =
                    JCoordinatorHelper.narrow((org.omg.CORBA.Object) other);
                otherTID = jcoord.getGlobalTID();
            } catch (BAD_PARAM exc) {

                // For remote Coordinator objects which are not instances of
                // the JCoordinator class, use the
                // propagation context to compare the Coordinators.
                // This relies on the availability of the propagation context
                // from the target Coordinator.

                try {
                    Coordinator coord =
                        CoordinatorHelper.narrow((org.omg.CORBA.Object)other);
                    PropagationContext pc = coord.get_txcontext();
                    otherTID = pc.current.otid;
                } catch (BAD_PARAM ex2) {
                    // If the other object is not actually a Coordinator,
                    // then the objects are not the same.
                } catch (Unavailable ex2) {
                    // If the other Coordinator is inactive, then there is
                    // nothing we can do to get the global identifier for the
                    // transaction, so we cannot compare the Coordinator
                    // objects.

                    INVALID_TRANSACTION ex3 =
                        new INVALID_TRANSACTION(MinorCode.CompareFailed,
                                                CompletionStatus.COMPLETED_NO);
                    throw ex3;
                }
            }
        }

        // Compare the global identifiers.

        if (otherTID != null) {
            return superInfo.globalTID.equals(otherTID);
        }

        return false;
    
public synchronized TransIdentity[]getAncestors()
Returns the sequence of ancestors of the transaction.

param
return
The sequence of ancestors.
see


        CoordinatorImpl[] coords = nestingInfo.getAncestors();

        TransIdentity[] result = new TransIdentity[coords.length];
        for (int i = 0; i < coords.length; i++) {
            try {
                result[i] = new TransIdentity(coords[i].object(), null,
                                              coords[i].getGlobalTID());
            } catch (Throwable exc) {}
        }

        return result;
    
public otid_tgetGlobalTID()
Returns a global identifier that represents the SubCoordinator's transaction.

This operation references only the global identifier, and so can be implemented locally in a proxy class.

This method is currently not synchronized because that causes a deadlock in resync. I don't think this is a problem as the global identifier is allocated in the constructor and then never changes.

param
return
The global identifier for the transaction.
see


        otid_t result = null;
        result = superInfo.globalTID.realTID;

        return result;
    
public longgetLocalTID()
Returns the internal identifier for the transaction. This method is currently not synchronized because that causes a deadlock in resync.

param
return
The local transaction identifier.
see


        long result = superInfo.localTID.longValue();
        return result;
    
CoordinatorgetParent()
Gets the parent coordinator of the transaction.

param
return
The parent Coordinator
see


        Coordinator result = nestingInfo.getParent(false).object();
        return result;
    
CoordinatorgetSuperior()
Gets the superior Coordinator for this transaction.

param
return
The superior Coordinator
see


        Coordinator result = superInfo.superior;
        return result;
    
CompletionHandlergetTerminator()
Gets the object normally responsible for terminating this Coordinator.

param
return
The object normally responsible for terminating the Coordinator.
see


        CompletionHandler result = terminator;
        return result;
    
public synchronized Statusget_parent_status()
Gets the local state of the parent transaction. This operation references no instance variables and so can be implemented locally in the proxy class.

param
return
The parent transaction's status.
exception
SystemException The parent could not be reached.
see


        Status result = Status.StatusNoTransaction;

        // Return the parents status.  If there is none, this is an error;
        // return no transaction status (may want to raise a LogicError here).

		if (tranState != null) {
			CoordinatorImpl parent = nestingInfo.getParent(false); 
			if (parent != null) { 
				result = parent.get_status();
			}
		} else {
			INVALID_TRANSACTION exc = new INVALID_TRANSACTION(
				MinorCode.Completed, CompletionStatus.COMPLETED_NO); 
			throw exc; 
		}

        return result;
    
public synchronized Statusget_status()
Returns the local status of the target transaction.

param
return
The status of the transaction.
see


        Status result = Status.StatusUnknown;

        if (tranState != null) {

            switch (tranState.state) {

            // If active, return active or marked rollback-only
            // if the flag is set.

            case TransactionState.STATE_ACTIVE :
                if (rollbackOnly) {
                    result = Status.StatusMarkedRollback;
                } else {
                    result = Status.StatusActive;
                }
                break;

            // If prepared, (successfully or otherwise), return prepared.
            // If committing return prepared (may want to block in this case).

            case TransactionState.STATE_PREPARED_SUCCESS :
            case TransactionState.STATE_PREPARED_FAIL :
            case TransactionState.STATE_PREPARED_READONLY :
                result = Status.StatusPrepared;
                break;

            // If we have no internal state, return that fact.
            // All of these states map directly to the OMG values.

            case TransactionState.STATE_NONE :
                result = Status.StatusNoTransaction;
                break;
            case TransactionState.STATE_PREPARING :
                result = Status.StatusPreparing;
                break;
            case TransactionState.STATE_COMMITTING :
                result = Status.StatusCommitting;
                break;
            case TransactionState.STATE_COMMITTED :
                result = Status.StatusCommitted;
                break;
            case TransactionState.STATE_ROLLING_BACK :
                result = Status.StatusRollingBack;
                break;
            case TransactionState.STATE_ROLLED_BACK :
                result = Status.StatusRolledBack;
                break;

            // Any other state, return unknown.

            default :
                result = Status.StatusUnknown;
                break;
            }
        } else {
            INVALID_TRANSACTION exc = new INVALID_TRANSACTION(
                MinorCode.Completed, CompletionStatus.COMPLETED_NO);
            throw exc;
        }

        return result;
    
public synchronized Statusget_top_level_status()
Gets the local state of the top-level transaction. This operation references no instance variables and so can be implemented locally in a proxy class.

param
return
The top-level transaction status.
exception
SystemException The top-level ancestor could not be reached.
see


        // Return the top-level status.  If there is none, this is an error;
        // return no transaction status (may want to raise a LogicError here).

        Status result = Status.StatusNoTransaction;

        if (tranState != null) {
            CoordinatorImpl topLevel = nestingInfo.getTopLevel();
            if (topLevel != null) {
                result = topLevel.get_status();
            }
        } else {
            INVALID_TRANSACTION exc = new INVALID_TRANSACTION(
                MinorCode.Completed, CompletionStatus.COMPLETED_NO);
            throw exc;
        }

        return result;
    
public synchronized java.lang.Stringget_transaction_name()
Returns a printable string that represents the SubCoordinator. This operation references only the global TID, and so can be implemented locally in a proxy class.

param
return
The transaction name.
see


        String result = null;
        if (tranState != null) {
            result = new String(name);
        } else {
            INVALID_TRANSACTION exc = new INVALID_TRANSACTION(
                                        MinorCode.Completed,
                                        CompletionStatus.COMPLETED_NO);

            throw exc;
        }

        return result;
    
public synchronized PropagationContextget_txcontext()
Creates a PropagationContext which contains the information which would normally be passed implicitly via the CosTSPropagation interfaces.

param
return
The transaction context.
exception
Inactive The Coordinator is in the process of completing the transaction and cannot return the information.
see


                                                     
          

        // First check the state of the transaction. If it is not active,
        // do not allow the operation.

        if (tranState == null ||
                tranState.state != TransactionState.STATE_ACTIVE ||
                rollbackOnly) {
            Unavailable exc = new Unavailable();
            throw exc;
        }

        // Work out the timeout value to pass, if any.
        // Note that only top-level transactions have timeouts.
        // We do not check for timeouts if the Coordinator is remote.
        // If the Coordinator does not have a timeout defined, the
        // TimeoutManager will return a negative value.
        // If the transaction has timed out, the value will be
        // zero.

        long timeLeft = TimeoutManager.timeLeft(superInfo.localTID);
        int timeout = 0;
        if (timeLeft > 0) {
          timeout = (int) timeLeft / 1000;
        } else if (timeLeft == 0) {
            // If the timeout has expired, then do not return a context,
            // but roll the transaction back and throw
            // the TRANSACTION_ROLLEDBACK exception.

            TimeoutManager.timeoutCoordinator(superInfo.localTID,
                                              TimeoutManager.ACTIVE_TIMEOUT);
            TRANSACTION_ROLLEDBACK exc =
                new TRANSACTION_ROLLEDBACK(0,CompletionStatus.COMPLETED_NO);
            throw exc;
        }

        // Fill in the context with the current transaction information,
        // and the ancestor information.

        TransIdentity current = new TransIdentity(this.object(),
                                                  null,
                                                  superInfo.globalTID.realTID);
        TransIdentity[] parents = getAncestors();

        // Ensure that the implementation specific data is filled with a value.

        if (emptyData == null) {
            emptyData = Configuration.getORB().create_any();
            emptyData.insert_boolean(false);
        }

        PropagationContext result = new PropagationContext(timeout, current,
                                                           parents, emptyData);

        return result;
    
synchronized booleanhasRegistered()
Checks whether the SubCoordinator has registered with its superior.

param
return
Indicates the registration status.
see


        boolean result = registered;
        return result;
    
public inthashCode()
Returns a hash code for the object. This very basic method is used by the trace facility and should not call any method which is traced.

param
return
The hash code for the object.
see

        return hash;
    
public synchronized inthash_top_level_tran()
Returns a hash value based on the top-level ancestor of the transaction associated with the target object.

param
return
The hash value for the top-level ancestor.
exception
SystemException The other Coordinator could not be reached.
see


        int result = 0;
        if (tranState != null) {
            CoordinatorImpl topLevel = nestingInfo.getTopLevel();
            if (topLevel != null) {
                result = topLevel.hash_transaction();
            }
        } else {
            INVALID_TRANSACTION exc = new INVALID_TRANSACTION(
                MinorCode.Completed, CompletionStatus.COMPLETED_NO);
            throw exc;
        }

        return result;
    
public synchronized inthash_transaction()
Returns a hash value based on the transaction associated with the target object.

param
return
The hash value for the transaction.
see


        int result =  hash;

        if (tranState == null) {
            INVALID_TRANSACTION exc = new INVALID_TRANSACTION(
                MinorCode.Completed, CompletionStatus.COMPLETED_NO);
            throw exc;
        }

        return result;
    
synchronized booleanisActive()
Checks whether the SubCoordinator is active.

param
return
Indicates the transaction is active.
see


        boolean result = (tranState.state == TransactionState.STATE_ACTIVE);
        return result;
    
public synchronized booleanisRollbackOnly()
Checks whether the SubCoordinator is marked rollback-only.

param
return
Indicates whether the transaction is rollback-only.
see


        boolean result = rollbackOnly;
        return result;
    
public booleanis_ancestor_transaction(Coordinator other)
Determines whether the target SubCoordinator is an ancestor of the given Coordinator. This operation references no instance variables and so can be implemented locally in a proxy class.

param
other The other Coordinator.
return
Indicates the relationship.
exception
SystemException The other Coordinator could not be reached.
see


        boolean result = false;
        if (tranState != null) {
            result = other.is_descendant_transaction(this.object());
        } else {
            INVALID_TRANSACTION exc = new INVALID_TRANSACTION(
                MinorCode.Completed, CompletionStatus.COMPLETED_NO);
            throw exc;
        }

        return result;
    
public synchronized booleanis_descendant_transaction(Coordinator other)
Determines whether the target SubCoordinator is a descendant of the given Coordinator. This operation references no instance variables and so can be implemented locally in a proxy class.

param
other The other Coordinator.
return
Indicates the relationship.
exception
SystemException The other Coordinator could not be reached.
see


        // A transaction is considered to be a descendant of itself, so if the
        // two transactions are the same, return TRUE.

        boolean result = false;
        if (tranState != null) {
            if (is_same_transaction(other)) {
                result = true;
            } else {
            // Otherwise, go through our ancestors, comparing
            // them with the given transaction.
            result = nestingInfo.isDescendant(other);
            }
        } else {
            INVALID_TRANSACTION exc = new INVALID_TRANSACTION(
                MinorCode.Completed, CompletionStatus.COMPLETED_NO);
            throw exc;
        }

        return result;
    
public synchronized booleanis_related_transaction(Coordinator other)
Determines whether the target SubCoordinator is related to the given Coordinator (i.e. is a member of the same transaction family). For a subtransaction this is equivalent to saying that the transaction associated with the parameter object is a descendant of the top-level ancestor of the transaction associated with the target object. This operation references no instance variables and so can be implemented locally in a proxy class.

param
other The other Coordinator.
return
Indicates the relationship.
exception
SystemException The other Coordinator could not be reached.
see


        // Check whether the given transaction is a descendant of our top-level
        // transaction.

        boolean result = false;
        if (tranState != null) {
            CoordinatorImpl topLevel = nestingInfo.getTopLevel();
            if (topLevel != null) {
                result = other.is_descendant_transaction(topLevel.object());
            }
        } else {
            INVALID_TRANSACTION exc = new INVALID_TRANSACTION(
                MinorCode.Completed, CompletionStatus.COMPLETED_NO);
            throw exc;
        }

        return result;
    
public synchronized booleanis_same_transaction(Coordinator other)
Compares the given Coordinator object with the target, and returns TRUE if they represent the same transaction. This operation needs to be implemented in an efficient manner, without any cross-process calls. This could be achieved by including the global identifier in the Coordinator references and comparing them. This operation references no instance variables and so can be implemented locally in a proxy class.

param
other The other Coordinator to be compared.
return
Indicates equality of the transactions the objects represent.
exception
SystemException The other Coordinator could not be reached.
see


        boolean result = false;

        // Get the names of the two transactions and compare them.

        if (name != null) {
          result = name.equals(other.get_transaction_name());
        } else {
            INVALID_TRANSACTION exc = new INVALID_TRANSACTION(
                MinorCode.Completed, CompletionStatus.COMPLETED_NO);
            throw exc;
        }

        return result;
    
public booleanis_top_level_transaction()
Determines whether the target SubCoordinator represents a top-level (non-nested) transaction.

For a subtransaction returns FALSE.

This operation references no instance variables and so can be implemented locally in a proxy class.

param
return
Indicates the transaction is top-level.
see


        boolean result = false;
        if (tranState == null) {
            INVALID_TRANSACTION exc = new INVALID_TRANSACTION(
                MinorCode.Completed, CompletionStatus.COMPLETED_NO);
            throw exc;
        }

        return result;
    
synchronized Voteprepare()


         

        Vote result = Vote.VoteRollback;
        int newState = TransactionState.STATE_PREPARED_FAIL;

        // Record that the Coordinator is about to prepare.

        // First check for active children, before getting too far
        // into the prepare. This is only done for the root Coordinator
        // as for any others it is too late.

        if (root && nestingInfo.numChildren() != 0) {
            INVALID_TRANSACTION exc =
                new INVALID_TRANSACTION(MinorCode.UnfinishedSubtransactions,
                                        CompletionStatus.COMPLETED_NO);
                throw exc;
        }

        // If the SubCoordinator is in the wrong state, return immediately.

        if (!tranState.setState(TransactionState.STATE_PREPARING)) {
            return Vote.VoteRollback;
        }

        // Check for marked rollback-only.

        if (rollbackOnly) {

            // Record that the Coordinator is deciding to rollback.
            // Try to set the state to prepared fail.

            if (!tranState.setState(TransactionState.STATE_PREPARED_FAIL)) {
                return Vote.VoteRollback;
            }
        } else {
            newState = TransactionState.STATE_PREPARED_SUCCESS;
            result = Vote.VoteCommit;
        }

        // Record that prepare is complete.
        // Set the state.

        if (!tranState.setState(newState)) {
            result = Vote.VoteRollback;
        }

        return result;
    
public synchronized RecoveryCoordinatorregister_resource(Resource res)
Enables a Resource to be registered as a participant in the completion of the subtransaction represented by the SubCoordinator. If the Resource is a SubtransactionAwareResource, it is registered with the SubCoordinator; if the SubCoordinator has not registered with is superior, it creates a CoordinatorResource and registers it with the superior. The registration is passed on to the top-level Coordinator in any case.

param
res The Resource to be registered.
return
The RecoveryCoordinator object from the registration with the top-level ancestor.
exception
Inactive The Coordinator is completing the transaction and cannot accept this registration.
exception
TRANSACTION_ROLLEDBACK The transaction which the Coordinator represents has already been rolled back, or been marked rollback-only.
exception
SystemException The operation failed.
see


        RecoveryCoordinator result = null;

        // First check the state of the transaction. If it is not active,
        // do not allow the registration.

        if (tranState == null ||
                tranState.state != TransactionState.STATE_ACTIVE) {
            Inactive exc = new Inactive();
            throw exc;
        }

        // Check whether the transaction has been marked rollback-only.

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

        // Register the given Resource with the top-level
        // Coordinator first, and remember the RecoveryCoordinator object
        // that is returned by the top-level Coordinator.

        CoordinatorImpl topLevel = nestingInfo.getTopLevel();

        // If the top-level Coordinator raises an exception, then do not
        // proceed with the registration, and return the exception.

        try {
            result = topLevel.register_resource(res);
        } catch (SystemException exc) {
            throw (SystemException) exc.fillInStackTrace();
        } catch (Inactive exc) {
            throw (Inactive) exc.fillInStackTrace();
        }

        // Find out whether the Resource is actually a
        // SubtransactionAwareResource.

        boolean subAwareRes =
            res._is_a(SubtransactionAwareResourceHelper.id());

        // If the Resource is actually a SubtransactionAwareResource,
        // then it needs to be registered for participation in completion
        // of the subtransaction as well as the top level transaction.

        if (subAwareRes) {

            // If not previously registered, a CoordinatorResource object
            // must be registered with our superior.  Note that root
            // SubCoordinators are created with the registration flag set,
            // so we do not need to check
            // whether we are the root SubCoordinator here.

            if (!registered) {

                // Initialise the CoordinatorResource with the local id,
                // our reference, and a flag to indicate that it does
                //  not represent a subtransaction.

                CoordinatorResourceImpl cImpl =
                    new CoordinatorResourceImpl(superInfo.globalTID,
                                                this, true);

                // Register the CoordinatorResource with superior Coordinator,
                // and store the resulting RecoveryCoordinator reference.

                try {
                    CoordinatorResource cRes = cImpl.object();
                    superInfo.superior.register_subtran_aware(cRes);
                    superInfo.setResource(cRes);
                    registered = true;
                } catch (Throwable exc) {
                    // If an exception was raised, do not set the
                    // registration flag, and destroy the object.
                    cImpl.destroy();

                    // If the exception is a system exception,
                    // then allow it to percolate to the caller.

                    if (exc instanceof OBJECT_NOT_EXIST) {
                        TRANSACTION_ROLLEDBACK ex2 =
                            new TRANSACTION_ROLLEDBACK(
                                0, CompletionStatus.COMPLETED_NO);
                        throw ex2;
                    }

                    if (exc instanceof Inactive) {
                        throw (Inactive) exc;
                    }

                    if (exc instanceof SystemException) {
                        throw (SystemException) exc;
                    }

                    // Otherwise throw an internal exception.

                    INTERNAL ex2 = new INTERNAL(MinorCode.NotRegistered,
                                                CompletionStatus.COMPLETED_NO);
                    throw ex2;
                }
            }

            // Add the SubtransactionAwareResource to the set of participants.
            // Make sure the RegisteredResources instance variable has been
            // set up.

            if (participants == null) {
                participants = new RegisteredResources(null, this);
            }

            // Add a duplicate of the reference to the set.  This is done
            // because if the registration is for a remote object, the proxy
            // will be freed when the registration request returns.

            participants.addRes((Resource)res._duplicate());
            temporary = false;
        }

        return result;
    
public synchronized voidregister_subtran_aware(SubtransactionAwareResource sares)
Enables a SubtransactionAwareResource to be registered as a participant in the completion of a subtransaction.

If the SubCoordinator has not registered with is superior, it creates a CoordinatorResource and registers it with the superior.

param
sares The SubtransactionAwareResource to be registered.
return
exception
Inactive The Coordinator is completing the transaction and cannot accept this registration.
exception
TRANSACTION_ROLLEDBACK The transaction which the Coordinator represents has already been rolled back, or has been marked rollback-only.
exception
SystemException The operation failed.
see


        // First check the state of the transaction. If it is not active,
        // do not allow the registration.

        if (tranState == null ||
                tranState.state != TransactionState.STATE_ACTIVE) {
            Inactive exc = new Inactive();
            throw exc;
        }

        // Check whether the transaction has been marked rollback-only.

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

        // If not previously registered, a CoordinatorResource object must be
        // registered with our superior.  Note that root SubCoordinators
        // are created with the registration flag set, so we do not need
        // to check whether we are the root SubCoordinator here.

        if (!registered) {

            // Initialise the CoordinatorResource with the local id,
            // our reference, and a
            // flag to indicate that it does not represent a subtransaction.

            CoordinatorResourceImpl cImpl =
                new CoordinatorResourceImpl(superInfo.globalTID, this, true);

            // Register the CoordinatorResource with the superior Coordinator,
            // and store the resulting RecoveryCoordinator reference.

            try {
                CoordinatorResource cRes = cImpl.object();
                superInfo.superior.register_subtran_aware(cRes);
                superInfo.setResource(cRes);
                registered = true;
            } catch(Throwable exc) {
                // If an exception was raised, do not set the registration flag.
                cImpl.destroy();

                // If the exception is a system exception, then allow
                // it to percolate to the caller.

                if (exc instanceof OBJECT_NOT_EXIST) {
                    TRANSACTION_ROLLEDBACK ex2 =
                        new TRANSACTION_ROLLEDBACK(
                            0, CompletionStatus.COMPLETED_NO);
                    throw ex2;
                }

                if (exc instanceof Inactive) {
                    throw (Inactive) exc;
                }

                if (exc instanceof SystemException) {
                    throw (SystemException) exc;
                }

                // Otherwise throw an internal exception.

                INTERNAL ex2 = new INTERNAL(MinorCode.NotRegistered,
                                            CompletionStatus.COMPLETED_NO);
                throw ex2;
            }
        }

        // Add the SubtransactionAwareResource to the set of participants.
        // Make sure the RegisteredResources instance variable has been set up.

        if (participants == null) {
            participants = new RegisteredResources(null, this);
        }

        // Add a duplicate of the reference to the set.
        // This is done because if the  registration is for a remote
        // object, the proxy will be freed when the
        // registration request returns.

        participants.addRes((Resource)sares._duplicate());
        temporary = false;
    
public synchronized voidregister_synchronization(Synchronization sync)
Informs the SubCoordinator that the given object requires synchronization before and after completion of the top-level ancestor transaction. The registration is passed directly to the top-level ancestor.

param
sync The Synchronization object to be registered.
return
exception
Inactive The Coordinator is in the process of completing the transaction and cannot accept this registration.
exception
SynchronizationUnavailable The transaction service cannot support synchronization.
see


        // First check the state of the transaction. If it is not active,
        // do not allow the registration.

        if (tranState == null ||
                tranState.state != TransactionState.STATE_ACTIVE) {
              Inactive exc = new Inactive();
              throw exc;
          }

        // Register the Synchronization object with the top-level Coordinator.
        // Allow any exception to percolate to the caller.

        CoordinatorImpl topLevel = nestingInfo.getTopLevel();
        topLevel.register_synchronization(sync);
    
synchronized booleanremoveChild(CoordinatorImpl child)
Removes the given Coordinator from the set of children of the target SubCoordinator. If the SubCoordinator is a temporary ancestor, and has no recoverable state after the child is removed, it destroys itself.

param
child The child Coordinator.
return
Indicates success of the operation.
see


        boolean result = false;

        // Remove the child from the set of children.  If the NestingInfo
        // instance variable has not been set up, then the child
        // cannot be removed.

        result = nestingInfo.removeChild(child);

        // If the removal results in an empty, temporary Coordinator, then this
        // Coordinator must be cleaned up.  The RecoveryManager is called to
        // clean up the transaction.

        if (temporary && !registered &&
                !(participants != null && participants.involved()) &&
                !(nestingInfo != null && nestingInfo.numChildren() > 0)) {

            // We pass the parent Coordinator to the RecoveryManager
            // so that it can remove the child from the parent's set of
            // children after the child is rolled back.

            CoordinatorImpl parent = nestingInfo.getParent(true);
            cleanUpEmpty(parent);
        }

        return result;
    
synchronized CoordinatorImplreplyAction(int[] action)
Indicates that a method reply is being sent and requests the SubCoordinator's action. If the Coordinator has active children, which are not registered with their superior (includes root Coordinators) then this method returns activeChildren. If it has already been registered, the method returns doNothing. Otherwise the SubCoordinator returns forgetMe.

param
action A 1-element array to hold the reply action.
return
The parent coordinator if any.
exception
SystemException An error occurred. The minor code indicates the reason for the exception.
see


        CoordinatorImpl result = null;
        action[0] = CoordinatorImpl.doNothing;

        // If this Coordinator is not a root, and there are active children,
        // report that fact to the caller. If the NestingInfo instance
        // variable has not been set up, there are no children.

        if (!root && nestingInfo.replyCheck()) {
          action[0] = CoordinatorImpl.activeChildren;

        // If there are no active children, then check whether this
        // transaction needs to be destroyed, or registered on reply.

        } else {

            // If there are participants, and we have not registered,
            // raise an exception.

            if (!registered) {
                if (participants != null && participants.involved()) {
                    INTERNAL ex2 = new INTERNAL(MinorCode.NotRegistered,
                                                CompletionStatus.COMPLETED_NO);
                    throw ex2;
                } else {
                    action[0] = forgetMe;
                }
            }

            // If we are not registered, and have no participants,
            // we have no reason to exist, so tell the caller to
            // forget about us. The TransactionManager will take care of
            // cleaning everything else up whenit receives the forgetMe
            // response.

            if (action[0] == doNothing && !registered)
                action[0] = forgetMe;
        }

        // Default action is do nothing when we are registered.

        result = null;

        return result;
    
voidrollback(boolean force)
Directs the SubCoordinator to roll back the transaction. The SubCoordinator directs all registered Resources to rollback.

param
force
return
see


        // Until we actually distribute rollback flows, synchronize the method.

        synchronized (this) {

            // If the transaction has already been rolled back, just return.

            if (tranState == null) {
                return;
            }

            // If this is not a forced rollback and the
            // coordinator has prepared or is in an
            // inappropriate state, do not continue and return FALSE.

            if (!force &&
                    ((tranState.state ==
                        TransactionState.STATE_PREPARED_SUCCESS) ||
                     (!tranState.setState(TransactionState.STATE_ROLLING_BACK))
                    )) {
                return;
            }

            // We do not care about invalid state changes as we are
            // rolling back anyway. If the SubCoordinator is temporary,
            // we do not change state as this would
            // cause a log force in a subordinate, which is not required.

            if (!temporary &&
                    !tranState.setState(TransactionState.STATE_ROLLING_BACK)) {
                // empty
            }

            // Rollback outstanding children.  If the NestingInfo instance
            // variable has not been created, there are no children
            // to roll back.

            if (nestingInfo != null) {
                nestingInfo.rollbackFamily();
            }

            // Release the lock before proceeding with rollback.

        }

        // Roll back all participants.  If a fatal error occurs during
        // this method, then the process must be ended with a fatal error.

        if (participants != null) {
            participants.distributeSubrollback();
        }

        // The remainder of the method needs to be synchronized.

        synchronized(this) {

            // Set the state to rolled back.

            // Remove our reference from the parents set of children
            if (!temporary &&
                    !tranState.setState(TransactionState.STATE_ROLLED_BACK)) {
                // empty
            }

            nestingInfo.removeFromParent(this);

            // Clean up the SubCoordinator after a rollback.
            // In the case where the SubCoordinator is a root,
            // the CoordinatorTerm object must be informed that
            // the transaction has completed so that if another caller has
            // rolled back the transaction (time-out for example) the object
            // normally responsible for terminating the transaction can
            // take the appropriate action.
            // NOTE: This may DESTROY the SubCoordinator object
            // so NO INSTANCE VARIABLES should be referenced after the call.
            // In the case where the SubCoordinator is a subordinate, the
            // CoordinatorResource object must be informed that the transaction
            // has been completed so that it can handle any subsequent
            // requests for the transaction.

            if (terminator != null) {
                terminator.setCompleted(true, false);
            }

            // As subtransactions do not have synchronization,
            // there is nothing left to do, so get the RecoveryManager
            // to forget about us, then self-destruct.

            RecoveryManager.removeCoordinator(superInfo.globalTID,
                                              superInfo.localTID, false);

            if (!dying) {
                destroy();
            }

            /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
            /* NO INSTANCE VARIABLES MAY BE ACCESSED FROM THIS POINT ON.     */
            /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
        }
    
public synchronized voidrollback_only()
Ensures that the transaction represented by the target SubCoordinator cannot be committed.

param
return
exception
Inactive The Coordinator is already completing the transaction.
see


        if (tranState.state != TransactionState.STATE_ACTIVE) {
            Inactive exc = new Inactive();
            throw exc;
        } else {
            // Set the rollback-only flag.
            rollbackOnly = true;
        }
    
synchronized java.lang.LongsetPermanent()
Marks the SubCoordinator as permanent.

param
return
The local transaction identifier.
see


        Long result = superInfo.localTID;
        temporary = false;

        return result;
    
synchronized voidsetTerminator(CompletionHandler term)
Informs the SubCoordinator of the identity of the object that is normally responsible for directing it through termination. The CoordinatorTerm/ CoordinatorResource object is informed by the Coordinator when the transaction aborts so that they can cope with asynchronous aborts.

param
term The object normally responsible for terminating the Coordinator.
return
see

        terminator = term;