Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*
   * JBoss, Home of Professional Open Source
   * Copyright 2006, Red Hat Middleware LLC, and individual contributors
   * as indicated by the @author tags. 
   * See the copyritypeght.txt in the distribution for a full listing
   * of individual contributors.
   * This copyrighted material is made available to anyone wishing to use,
   * modify, copy, or redistribute it subject to the terms and conditions
   * of the GNU Lesser General Public License, v. 2.1.
  * This program is distributed in the hope that it will be useful, but WITHOUT A
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
  * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
  * You should have received a copy of the GNU Lesser General Public License,
  * v.2.1 along with this distribution; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
  * MA  02110-1301, USA.
  * 
  * (C) 2005-2006,
  * @author JBoss Inc.
  */
 /*
  * Copyright (C) 2002,
  *
  * Arjuna Technologies Limited,
  * Newcastle upon Tyne,
  * Tyne and Wear,
  * UK.
  *
  * $Id: SubordinateCoordinator.java,v 1.1 2005/05/19 12:13:39 nmcl Exp $
  */
 
 package com.arjuna.mwlabs.wscf.model.sagas.arjunacore.subordinate;
 
 
 
 
 
 
This class represents a specific coordination instance. It inherits from ArjunaCore TwoPhaseCoordinator via the BACoordinator. This is the subordinate coordinator implementation which we use when doing interposition. This implementation registers itself as a coordinator completion participant in its parent activity. It has to use the coordinator completion protocol because it relies upon dispatch of a complete request from the parent to drive logging of i) the subordinate transaction state then ii) the state of its registered proxy participant. These operations must both happen in that order and only when the parent transaction is preparing to close. Note that this does not imply that the transaction is closed, merely that it goes through phase 1 of the transaction termination protocol (PREPARE) leaving a transaction log record on the disk (albeit in state COMMITTING). It must still be possible to leave phase 2 open for either close (COMMIT) or compensate (ROLLBACK). Why? Well, if the participant logs its state first either at parent complete or, if participant completion is in use, before parent complete, then a crash risks losing details of the subordinate transaction -- including potentialy completed participants which may require closing or compensating. Note that this danger bypasses any question of whether or when subsequently the subordinate transaction state might be logged -- the participant cannot log its state and guarantee to close or compensate correctly without having first ensured that it can guarantee to close or compensate subordinate participants. Contrariwise, if the subordinate transaction logs its state first and a crash occurs before the proxy participant state can be saved then it is still possible during recovery to correlate the presence of the logged subordinate transaction with the absence of its proxy participant and automatically compensate the subordinate transaction's completed participants. This will match the action of the parent since absence of the proxy participant requires it also to compensate. It is not possible to commit any earlier than parent complete because it is still legitimate for participants to register before that event. So, the implication of this is that when the proxy notifies complete to this coordinator it must perform the usual complete processing and also drive phase 1 of the commit process. Later, when a close request is dispatched, it can drive phase 2 of the commit process. If there is a failure during phase 1 of the commit process then the subordinate transaction will not be logged. In this case the proxy participant must notify a fail to the parent transaction and avoid logging its own state. This is safe because a crash will automatically cause a subsequent resend of the complete request to return fail because the proxy participant is unknown. If phase 1 completes successfully then the proxy participant must log its state and notify completed to the parent trasaction. If a crash occurs between logging the subordinate transaction state and logging the proxy state then the absence of the proxy participant can be reconciled during recovery and the subordinate transaction can be automatically compensated. If a crash occurs between logging the proxy participant and notifying completed to the parent transaction then the participant will be recreated during recovery and a subsequent resend of complete can be answered with completed. Note that this means complete requests for unknown participants must only be answered after the first pass of the BA participant recovery module has completed.

Author(s):
Mark Little (mark.little@arjuna.com)
Version:
$Id: SubordinateCoordinator.java,v 1.1 2005/05/19 12:13:39 nmcl Exp $
Since:
2.0.
    // TODO - modify to use above protocol!

    
normal constructor
	{
		super();
         = true;
	}

    
constructor for recovered coordinator

Parameters:
recovery
	public SubordinateBACoordinator(Uid recovery)
	{
		super(recovery);
         = false;
	}

    
If the application requires and if the coordination protocol supports it, then this method can be used to execute a coordination protocol on the currently enlisted participants at any time prior to the termination of the coordination scope. This implementation only supports coordination at the end of the activity.

Parameters:
cs The completion status to use when determining how to execute the protocol.
Returns:
The result of executing the protocol, or null.
Throws:
com.arjuna.mw.wsas.exceptions.WrongStateException Thrown if the coordinator is in a state the does not allow coordination to occur.
com.arjuna.mw.wsas.exceptions.ProtocolViolationException Thrown if the protocol is violated in some manner during execution.
com.arjuna.mw.wsas.exceptions.SystemException Thrown if any other error occurs.
	{
	}
	public int end (boolean reportHeuristics)
	{
	}

    
this is driven by a coordinator-completion participant registered on behalf of the coordinator and is required to propagate the complete to all registered coordinator-completion participants.

Returns:
the result of preparing the transaction
	public void complete ()  throws WrongStateExceptionSystemException
	{
        // if this goes wrong here then we will throw an exception
        super.complete();
        // now we need to run phase one of commit
        // TODO -- need to do completion processing here?
        int outcome = super.prepare(true);
        // if we have prepared ok (or are read only) then status will be COMMITTING
        if (outcome == .) {
            // phase 1 failed so we need to run phase 2 abort
            // this will set status to ABORTED
            phase2Abort(true);
        }
        // no need to return anything as the caller can just check the status
	}

    
this is driven by a coordinator-completion participant registered on behalf of the coordinator and is required to propagate the close to all registered participants.
	public int close () throws SystemException
	{
        int status = status();
        int result;
        if (status == .) {
            // TODO -- need to do completion processing here?
            // we already completed and ran phase 1 so do a phase 2 commit
            phase2Commit(true);
            result = status();
        } else {
            // we have not yet completed so we can rely upon the parent implementation to do
            // everything we need
            result = super.close();
        }
        // if we have completed then remove the coordinator from the recovered coordinators table
        if (status() != .) {
            SubordinateBACoordinator.removeRecoveredCoordinator(this);
        }
        // run any callback associated with this transaction
        runCallback(get_uid().stringForm());
        return result;
	}

    
this is driven by a coordinator-completion participant registered on behalf of the coordinator and is required to propagate the cancel to all registered participants.
	public int cancel ()
	{
        int status = status();
        int result;
        // TODO -- check if there is a window here where status could change to COMMITTING
        if (status == .) {
            phase2Abort(true);
            result = status();
        } else {
            result = super.cancel();
        }
        SubordinateBACoordinator.removeRecoveredCoordinator(this);
        // run any callback associated with this transaction
        runCallback(get_uid().stringForm());
        return result;
	}

    
called by the durable participant during recovery processing TODO clarify when and why this gets called and what to do about it
    public void unknown()
    {
    }

    
called by the durable participant during recovery processing TODO clarify when and why this gets called and what to do about it
    public void error()
    {
    }
    public String type ()
    {
        return "/StateManager/BasicAction/AtomicAction/Sagas/SubordinateCoordinator";
    }

    
unique string used as prefix for participant ids to ensure they can be identified at recovery
    public static String PARTICIPANT_PREFIX = "org.jboss.jbossts.xts.ba.subordinate.participant.";

    
return a uid for the corodinator completion participant registered on behalf of this coordinator
    {
        return  + get_uid().stringForm() + "_CCP";
    }
    protected static synchronized void addRecoveredCoordinator(SubordinateBACoordinator coordinator)
    {
        .put(coordinator.get_uid().stringForm(), coordinator);
    }
    protected static synchronized void removeRecoveredCoordinator(SubordinateBACoordinator coordinator)
    {
        .remove(coordinator.get_uid().stringForm());
    }
    public static synchronized void addActiveProxy(String id)
    {
        .put(id.);
    }
    public static synchronized void removeActiveProxy(String id)
    {
        .remove(id);
    }
    protected void setActivated()
    {
         = true;
    }
    public boolean isActivated()
    {
        return ;
    }

    
test whether a transaction has been restored without its proxy participant. this indicates that we crashed between preparing the suborindate TX and logging the proxy participant.

Returns:
    public boolean isOrphaned()
    {
        String id = get_uid().stringForm();
        if (isActiveProxy(id)) {
            return false;
        }
        // the proxy may have been removed because this tx has been resolved while we were checking
        if (getRecoveredCoordinator(id) == null) {
            return false;
        }
        // ok we have a tx but no proxy so this is really an orphan
        
        return true;
    }
    private static synchronized boolean isActiveProxy(String proxyId)
    {
        return .get(proxyId) == .;
    }
    public static synchronized SubordinateBACoordinator getRecoveredCoordinator(String coordinatorId)
    {
        return .get(coordinatorId);
    }
    public static synchronized SubordinateBACoordinator[] listRecoveredCoordinators()
    {
        int length = values.size();
        return values.toArray(new SubordinateBACoordinator[length]);
    }

    
flag identifying whether this coordinator is active, set true for normal transactions and false for recovered transactions until they are activated
    private boolean activated;
    private static final HashMap<StringBooleanactiveProxies = new HashMap<StringBoolean>();

    
we need to remove the association between parent and subordinate context at completion of commit or rollback -- we use a callback mechanism keyed by transaction id to achieve this
    private static final HashMap<StringSubordinateCallbackcallbacks = new HashMap<StringSubordinateCallback>();

    
class implemented by any code which wishes to register a callabck
    public static abstract class SubordinateCallback
    {
        private SubordinateCallback next// in case multiple callbacks are registered
        public abstract void run();
    }

    
register a callback to be called when a subordinate transaction with a specific key executes a commit or rollback. the callback will not be called in the case of a crash

Parameters:
key
callback
    public static void addCallback(String keySubordinateCallback callback)
    {
        SubordinateCallback old = .put(keycallback);
        // chian any existign callback so we ensure to call them all
        callback.next = old;
    }
    private void runCallback(String key)
    {
        SubordinateCallback callback = .get(key);
        while (callback != null) {
            callback.run();
            callback = callback.next;
        }
    }
New to GrepCode? Check out our FAQ X