All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.arjuna.ats.internal.jts.interposition.resources.arjuna.Interposition Maven / Gradle / Ivy

There is a newer version: 5.12.7.Final
Show newest version
/*
 * JBoss, Home of Professional Open Source
 * Copyright 2006, Red Hat Middleware LLC, and individual contributors
 * as indicated by the @author tags.
 * See the copyright.txt in the distribution for a full listing
 * of individual contributors.
 * This copyrighted material is made available to anyone wishing to use,
 * modify, copy, or redistribute it subject to the terms and conditions
 * of the GNU Lesser General Public License, v. 2.1.
 * This program is distributed in the hope that it will be useful, but WITHOUT A
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
 * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 * You should have received a copy of the GNU Lesser General Public License,
 * v.2.1 along with this distribution; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA  02110-1301, USA.
 *
 * (C) 2005-2006,
 * @author JBoss Inc.
 */
/*
 * Copyright (C) 1998, 1999, 2000,
 *
 * Arjuna Solutions Limited,
 * Newcastle upon Tyne,
 * Tyne and Wear,
 * UK.
 *
 * $Id: Interposition.java 2342 2006-03-30 13:06:17Z  $
 */

package com.arjuna.ats.internal.jts.interposition.resources.arjuna;

import java.util.LinkedList;
import java.util.List;

import org.omg.CORBA.CompletionStatus;
import org.omg.CORBA.SystemException;
import org.omg.CORBA.TRANSACTION_ROLLEDBACK;
import org.omg.CORBA.TRANSACTION_UNAVAILABLE;
import org.omg.CosTransactions.Coordinator;
import org.omg.CosTransactions.PropagationContext;
import org.omg.CosTransactions.Terminator;
import org.omg.CosTransactions.TransIdentity;

import com.arjuna.ats.arjuna.common.Uid;
import com.arjuna.ats.internal.jts.interposition.ServerFactory;
import com.arjuna.ats.internal.jts.orbspecific.ControlImple;
import com.arjuna.ats.internal.jts.orbspecific.interposition.ServerControl;
import com.arjuna.ats.internal.jts.orbspecific.interposition.resources.arjuna.ServerNestedAction;
import com.arjuna.ats.internal.jts.orbspecific.interposition.resources.arjuna.ServerTopLevelAction;
import com.arjuna.ats.jts.logging.jtsLogger;
import com.arjuna.ats.jts.utils.Utility;

public class Interposition
{

    public Interposition ()
    {
        _head = new LinkedList(); // not synchronized as the methods that access it all are synchronized.
    }

public static ControlImple create (PropagationContext context) throws SystemException
    {
	if (__list != null)
	    return __list.setupHierarchy(context);
	else
	    return null;
    }

public static boolean destroy (Uid act)
    {
	if (__list != null)
	    return __list.removeHierarchy(act);
	else
	    return false;
    }

    /*
     * Assume that all actions in the imported hierarchy are of the same
     * type, i.e., all JBoss transactions.
     *
     * Because of the way garbage collection works in the ORB we have to
     * run an explicit garbage collection phase for finished hierarchies.
     */

public synchronized ControlImple setupHierarchy (PropagationContext context) throws SystemException
    {
	ControlImple controlPtr = null;
	Uid theUid = null;
	ServerTopLevelAction proxyAction = null;

	if (context.parents.length == 0)
	    theUid = Utility.otidToUid(context.current.otid);
	else
	    theUid = Utility.otidToUid(context.parents[context.parents.length-1].otid);

	proxyAction = present(theUid);

	if (proxyAction == null)
	{
	    /*
	     * Create a new proxyAction element and return the
	     * "current" transaction.
	     */

	    controlPtr = createHierarchy(context, theUid);
	}
	else
	{
	    /*
	     * Check hierarchy of existing element.
	     */

	    controlPtr = checkHierarchy(proxyAction, context);
	    proxyAction = null;
	}

	return controlPtr;
    }

    protected final synchronized ServerTopLevelAction present (Uid actUid)
    {
        if(_head == null) {
            return null;
        }

        for(ServerTopLevelAction action : _head) {
            if(actUid.equals(action.get_uid())) {
                return action;
            }
        }

        return null;
    }

protected synchronized ControlImple createHierarchy (PropagationContext ctx, Uid tlUid) throws SystemException
    {
	/*
	 * Start at the parent and work our way down to "current". The current
	 * transaction is not in the IDL sequence, but sent as separate field
	 * of the propagation context. This tends to make the code more
	 * complex than it would be if the entire hierarchy was represented in
	 * one place.
	 */

	int depth = ctx.parents.length;
	ServerResource action = null;
	Coordinator tmpCoord = null;
	Terminator tmpTerm = null;

	/*
	 * First deal with top-level transaction, which may be
	 * the current transaction.
	 */

	if (depth == 0)
	{
	    tmpCoord = ctx.current.coord;
	    tmpTerm = ctx.current.term;
	}
	else
	{
	    tmpCoord = ctx.parents[depth-1].coord;
	    tmpTerm = ctx.parents[depth-1].term;
	}

	if (tmpCoord == null)  // terminator may correctly be null
	{
	    return null;
	}

	ServerControl control = ServerFactory.create_transaction(tlUid, null, null,
								 tmpCoord, tmpTerm, ctx.timeout);

	action = new ServerTopLevelAction(control);

	if (!action.valid())
	{
	    try
	    {
		((ServerTopLevelAction) action).rollback();  // does dispose as well!
	    }
	    catch (Exception e)
	    {
	    }

        if (((ServerTopLevelAction)action).isTransactionInactive()) {
            throw new TRANSACTION_UNAVAILABLE(jtsLogger.i18NLogger.get_transaction_was_inactive(), 1, CompletionStatus.COMPLETED_NO);
        } else {
            throw new TRANSACTION_ROLLEDBACK();
        }
	}

	ServerTopLevelAction newElement = (ServerTopLevelAction)action;

	_head.add(newElement);

	if (depth > 0) // current is a nested transaction
	{
	    /*
	     * Now deal with any nested transactions.
	     * As we create, register with the original transactions.
	     */

	    ServerResource nestedAction = null;

	    for (int i = depth -2; i >= 0; i--)
	    {
		tmpCoord = ctx.parents[i].coord;
		tmpTerm = ctx.parents[i].term;

		control = ServerFactory.create_subtransaction(Utility.otidToUid(ctx.parents[i].otid),
								  tmpCoord, tmpTerm, control);

		nestedAction = new ServerNestedAction(control);

		if (!nestedAction.valid())
		{
		    /*
		     * Just deal with current transaction. Others must have been
		     * registered successfully, and will be deal with automatically
		     * when the parent transaction terminates.
		     */

		    try
		    {
			((ServerNestedAction) nestedAction).rollback_subtransaction();  // does dispose as well!
			nestedAction = null;
		    }
		    catch (Exception e)
		    {
		    }

		    throw new TRANSACTION_ROLLEDBACK();
		}

		/*
		 * Add transaction resource to list.
		 */

		action.addChild((ServerNestedAction) nestedAction);
		action = nestedAction;
	    }

	    /*
	     * Now deal with current transaction. If there is
	     * only one transaction we do nothing.
	     */

	    tmpCoord = ctx.current.coord;
	    tmpTerm = ctx.current.term;

	    control = ServerFactory.create_subtransaction(Utility.otidToUid(ctx.current.otid),
							      tmpCoord, tmpTerm, control);

	    nestedAction = new ServerNestedAction(control);

	    if (!nestedAction.valid())
	    {
		/*
		 * Just deal with current transaction. Others must have been
		 * registered successfully, and will be deal with automatically
		 * when the parent transaction terminates.
		 */

		try
		{
		    ((ServerNestedAction) nestedAction).rollback_subtransaction();  // does dispose as well!
		    nestedAction = null;
		}
		catch (Exception e)
		{
		}

		throw new TRANSACTION_ROLLEDBACK();
	    }

	    action.addChild((ServerNestedAction) nestedAction);
	}

	if (jtsLogger.logger.isTraceEnabled())
	    compareHierarchies(ctx, newElement);

	return control;
    }

    /*
     * In a single threaded environment we could walk down the hierarchy,
     * aborting any actions which are no longer valid, and creating any new
     * ones. However, in a multi-threaded environment, a thread can make a
     * call from any point in the client's hierarchy, and multiple client
     * threads can invoke the same server object. So, in general we cannot do
     * this optimisation. We must maintain the entire tree until portions of
     * it have explicitly been termined.
     *
     * Once we find the point in the new hierarchy which deviates from our
     * current representation, we begin to assemble a new subtree in much the
     * same way as we did for creating a completely new hierarchy.
     */

protected synchronized ControlImple checkHierarchy (ServerTopLevelAction hier,
						   PropagationContext context) throws SystemException
    {
	ServerControl control = null;
	ServerResource currentAction = hier;  // top-level transaction
	int depth = context.parents.length;
	int differenceIndex = -1;  // index of the new transactions in the hierarchy

	/*
	 * Find the point at which our notion of the hierarchy deviates from
	 * the one we have just received.
	 *
	 * To get here we have already checked the id of the parent
	 * transaction, i.e., depth -1.
	 *
	 * Remember: the context hierarchy sequence *does not* include the
	 * current transaction!
	 */

	if (depth == 0)
	{
	    /*
	     * There are no transactions in the context other than the current
	     * transaction, which must therefore be top-level. We already have
	     * the control to return.
	     */

	    control = hier.control();  // top-level transaction's control
	}
	else
	{
	    ServerResource nestedAction = null;

	    /*
	     * Start at -2 and work our way down the hierarchy. We
	     * use -2 since the length gives us the *number* of elements,
	     * which is 0 to n-1, and the n-1th element is the top-level
	     * transaction, which we must deal with first!
	     */

	    for (int i = depth -2; i >= 0; i--)  // don't check depth-1 as it is current action!
	    {
		nestedAction = currentAction.getChild(Utility.otidToUid(context.parents[i].otid));

		if (nestedAction == null)  // point of difference, so stop trawling hierarchy
		{
		    differenceIndex = i;   // remember for later so that we can add new actions.
		    break;
		}
		else
		{
		    /*
		     * currentAction *always* points to the last known
		     * good transaction in our hierarchy.
		     */

		    currentAction = nestedAction;
		}
	    }

	    /*
	     * Do we have anything left in the sent hierarchy (other than
	     * current)? If so, add it now.
	     */

	    if (differenceIndex != -1)
	    {
		control = currentAction.control();

		Coordinator tmpCoord;
		Terminator tmpTerm;

		for (int j = differenceIndex; j >= 0; j--)
		{
		    tmpCoord = context.parents[j].coord;
		    tmpTerm = context.parents[j].term;

		    control = ServerFactory.create_subtransaction(Utility.otidToUid(context.parents[j].otid),
								      tmpCoord, tmpTerm, control);
		    nestedAction = new ServerNestedAction(control);

		    if (!nestedAction.valid())
		    {
			/*
			 * Just deal with current transaction. Others must have been
			 * registered successfully, and will be deal with automatically
			 * when the parent transaction terminates.
			 */

			try
			{
			    ((ServerNestedAction) nestedAction).rollback();  // does dispose as well!
			    nestedAction = null;
			}
			catch (Exception e)
			{
			}

			throw new TRANSACTION_ROLLEDBACK();
		    }

		    currentAction.addChild((ServerNestedAction) nestedAction);
		    currentAction = nestedAction;
		}
	    }
	    else
	    {
		/*
		 * Hierarchies may be identical.
		 * Remember to check!
		 */
	    }

	    Uid currentUid = Utility.otidToUid(context.current.otid);

	    /*
	     * currentAction points to the parent of the 'current'
	     * transaction, i.e., the last element in the TransIdentity
	     * structure. So, ask it if the sent hierarchy's child is
	     * one of its children.
	     */

	    nestedAction = currentAction.getChild(currentUid);

	    if (nestedAction == null)
	    {
		/*
		 * Different notion of current in sent hierarchy.
		 * So, add it to the hierarchy here.
		 */

		control = currentAction.control();

		/*
		 * Now deal with the current transaction.
		 */

		TransIdentity currentID = context.current;

		control = ServerFactory.create_subtransaction(currentUid,
								  currentID.coord, currentID.term, control);
		nestedAction = new ServerNestedAction(control);

		if (!nestedAction.valid())
		{
		    /*
		     * Just deal with current transaction. Others must have
		     * been registered successfully, and will be deal with
		     * automatically when the parent transaction terminates.
		     */

		    try
		    {
			((ServerNestedAction) nestedAction).rollback();  // does dispose as well!
			nestedAction = null;
		    }
		    catch (Exception e)
		    {
		    }

		    throw new TRANSACTION_ROLLEDBACK();
		}

		currentAction.addChild((ServerNestedAction) nestedAction);
	    }
	    else
	    {
		/*
		 * Same current, so get its control and return it.
		 */

		control = nestedAction.control();
	    }
	}

	if (jtsLogger.logger.isTraceEnabled())
	    compareHierarchies(context, hier);

	return control;
    }

    protected final synchronized boolean removeHierarchy (Uid theUid)
    {
        ServerTopLevelAction action = present(theUid);

        if (action != null)
        {
            _head.remove(action);
            return true;
        }
        else
        {
            if (jtsLogger.logger.isTraceEnabled()) {
                jtsLogger.i18NLogger.warn_interposition_resources_arjuna_ipfail("Interposition.removeHeirarchy", theUid);
            }
        }

        return false;
    }

protected final void compareHierarchies (PropagationContext ctx, ServerTopLevelAction action)
    {
	int depth = ctx.parents.length;
	Uid[] ctxHierarchy = new Uid [depth+1];
	boolean printHierarchies = false;

	for (int i = depth -1; i >= 0; i--)
	{
	    ctxHierarchy[i+1] = new Uid(Utility.otidToUid(ctx.parents[i].otid));
	}

	ctxHierarchy[0] = new Uid(Utility.otidToUid(ctx.current.otid));

	boolean problem = false;

	if (action != null)
	{
	    if (action.get_uid().notEquals(ctxHierarchy[depth])) {
            jtsLogger.i18NLogger.warn_interposition_resources_arjuna_iptl(action.get_uid(), ctxHierarchy[depth - 1]);

            printHierarchies = true;
        }
	    else
	    {
		if (depth > 0)
		{
		    ServerNestedAction child = action.getChild(ctxHierarchy[depth-1]);

		    if (child != null)
		    {
			int i = 0;

			for (i = depth -2; (i >= 0) && (child != null); i--)
			{
			    child = child.getChild(ctxHierarchy[i]);

			    if (child == null)
			    {
				problem = true;
				break;
			    }
			}

			if (i != -1)
			    problem = true;
		    }
		    else
			problem = true;
		}

		if (problem) {
            jtsLogger.i18NLogger.warn_interposition_resources_arjuna_ipnt();

            printHierarchies = true;
        }
	    }
	}
	else {
        jtsLogger.i18NLogger.warn_interposition_resources_arjuna_ipnull();

        printHierarchies = true;
    }

	if (!printHierarchies)
	    printHierarchies = jtsLogger.logger.isTraceEnabled();

	if (printHierarchies)
	{
        synchronized (jtsLogger.logger)
        {
            if (!problem)
            {
                if (jtsLogger.logger.isTraceEnabled()) {
                    jtsLogger.logger.trace(Utility.getHierarchy(ctx));
                    jtsLogger.logger.trace(hierarchytoString(action));
                }
            }
            else
            {
                jtsLogger.i18NLogger.warn_interposition_resources_arjuna_problemhierarchy(Utility.getHierarchy(ctx));
                jtsLogger.i18NLogger.warn_interposition_resources_arjuna_problemhierarchy(hierarchytoString(action));
            }
        }
	}

	if (ctxHierarchy != null)
	{
	    for (int i = 0; i < (int) depth; i++)
	    {
		if (ctxHierarchy[i] != null)
		    ctxHierarchy[i] = null;
	    }

	    ctxHierarchy = null;
	}
    }

    private final String hierarchytoString(ServerTopLevelAction action)
    {
        String hier = "InterposedHierarchy:";

        if (action != null)
        {
            hier += action.get_uid();

            List children = action.getChildren();

            synchronized (children) {
                for(ServerNestedAction child : children) {
                    hier += "\n"+child.get_uid();
                    hier += child.getChildren(2);
                }
            }
        }
        else
            hier += "EMPTY";

        return hier;
    }

protected List _head;

private static Interposition __list = new Interposition();

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy