com.arjuna.ats.internal.jts.context.ContextManager Maven / Gradle / Ivy
The 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) 2000, 2001, 2002,
*
* Hewlett-Packard Arjuna Labs,
* Newcastle upon Tyne,
* Tyne and Wear,
* UK.
*
* $Id: ContextManager.java 2342 2006-03-30 13:06:17Z $
*/
package com.arjuna.ats.internal.jts.context;
import java.util.EmptyStackException;
import java.util.Hashtable;
import java.util.Stack;
import org.omg.CORBA.BAD_OPERATION;
import org.omg.CORBA.BAD_PARAM;
import org.omg.CORBA.SystemException;
import org.omg.CORBA.TCKind;
import org.omg.CORBA.TRANSACTION_UNAVAILABLE;
import org.omg.CORBA.UNKNOWN;
import org.omg.CORBA.ORBPackage.InvalidName;
import org.omg.CosTransactions.Control;
import org.omg.CosTransactions.Coordinator;
import org.omg.CosTransactions.PropagationContext;
import org.omg.CosTransactions.Terminator;
import org.omg.CosTransactions.TransactionFactory;
import org.omg.PortableInterceptor.InvalidSlot;
import com.arjuna.ArjunaOTS.ActionControl;
import com.arjuna.ats.arjuna.exceptions.FatalError;
import com.arjuna.ats.arjuna.utils.ThreadUtil;
import com.arjuna.ats.internal.arjuna.thread.ThreadActionData;
import com.arjuna.ats.internal.jts.ControlWrapper;
import com.arjuna.ats.internal.jts.ORBManager;
import com.arjuna.ats.internal.jts.OTSImpleManager;
import com.arjuna.ats.internal.jts.orbspecific.ControlImple;
import com.arjuna.ats.internal.jts.orbspecific.TransactionFactoryImple;
import com.arjuna.ats.jts.OTSManager;
import com.arjuna.ats.jts.logging.jtsLogger;
/**
* This class is responsible for managing the thread-to-transaction
* context mappings.
*
* @author Mark Little ([email protected])
* @version $Id: ContextManager.java 2342 2006-03-30 13:06:17Z $
* @since JTS 1.0.
*/
public class ContextManager
{
public ContextManager ()
{
if (jtsLogger.logger.isTraceEnabled()) {
jtsLogger.logger.trace("ContextManager::ContextManager ()");
}
try
{
_piCurrent = org.omg.PortableInterceptor.CurrentHelper.narrow(ORBManager.getORB().orb().resolve_initial_references("PICurrent"));
}
catch (InvalidName ex)
{
throw new FatalError("ContextManager "+jtsLogger.i18NLogger.get_context_picreffail()+" "+ex, ex);
}
catch (Exception ex)
{
throw new FatalError("ContextManager "+jtsLogger.i18NLogger.get_context_picreffail()+" "+ex, ex);
}
}
/**
* Get the current transaction associated with the invoking thread. Do
* not look in the PI thread data.
*
* Does not need to be synchronized since it is implicitly single-threaded.
*
* @return the context.
*/
public ControlWrapper current (String threadId) throws SystemException
{
Object arg = otsCurrent.get(threadId);
ControlWrapper wrapper = null;
if (arg != null)
{
try
{
Stack hier = (Stack) arg;
return (ControlWrapper) hier.peek();
}
catch (EmptyStackException e)
{
}
}
return null;
}
/**
* Get the transaction for the invoking thread. If there isn't one in
* the normal thread associated data then look in the PI implementation.
*
* @return the current transaction for the invoking thread.
*/
public ControlWrapper current () throws SystemException
{
if (jtsLogger.logger.isTraceEnabled()) {
jtsLogger.logger.trace("ContextManager::current ()");
}
Object arg = otsCurrent.get(ThreadUtil.getThreadId());
ControlWrapper wrapper = null;
if (arg != null)
{
try
{
Stack hier = (Stack) arg;
wrapper = (ControlWrapper) hier.peek();
}
catch (EmptyStackException e)
{
e.printStackTrace();
}
}
/*
* If we do not have a context currently, then check to see if
* we have just been spawned to handle a transactional invocation.
* If so, there may be a context handle associated with this
* thread in piCurrent.
*
* We only do this for the current thread, hence the difference
* between the two versions of ContextManager.current.
*/
if (wrapper == null)
{
wrapper = currentPIContext();
try
{
if (wrapper != null)
{
pushAction(wrapper);
}
}
catch (Throwable ex)
{
jtsLogger.i18NLogger.warn_context_genfail("ContextManager.current", ex);
throw new BAD_OPERATION();
}
}
return wrapper;
}
public final ControlWrapper popAction (String threadId)
{
if (jtsLogger.logger.isTraceEnabled()) {
jtsLogger.logger.trace("ContextManager::popAction ()");
}
ControlWrapper action = null;
Object arg = otsCurrent.get(threadId);
if (arg != null)
{
Stack sl = (Stack) arg;
try
{
/*
* When we pushed the action we did the check for whether
* it was local to save time now.
*/
action = (ControlWrapper) sl.pop();
}
catch (EmptyStackException e)
{
}
/*
* If size now zero we can delete from thread
* specific data.
*/
if (sl.size() == 0)
{
sl = null;
otsCurrent.remove(threadId);
disassociateContext();
}
}
/*
* Now update action in thread's notion of current if
* this action is local.
*/
// Check that action is local and not a proxy.
if (action != null)
{
/*
* Now update action in thread's notion of current if
* this action is local.
*/
// Check that action is local and not a proxy.
if (action.isLocal())
{
/*
* If transaction is terminated by another thread
* then our thread-action information may have already
* been removed from the action.
*/
try
{
ThreadActionData.popAction(threadId);
}
catch (EmptyStackException e)
{
}
}
}
return action;
}
public final ControlWrapper popAction ()
{
return popAction(ThreadUtil.getThreadId());
}
public final void purgeActions (String threadId)
{
if (jtsLogger.logger.isTraceEnabled()) {
jtsLogger.logger.trace("ContextManager::purgeActions ()");
}
/*
* Don't do anything with these actions, i.e., do
* not commit/abort them. Just because this thread is
* finished with them does not mean other threads
* are!
*/
ControlWrapper ptr = popAction(threadId);
while (ptr != null)
{
ptr = null;
ptr = popAction(threadId);
} while (ptr != null);
}
public final void purgeActions ()
{
purgeActions(ThreadUtil.getThreadId());
}
/**
* Force the thread-to-transaction association. Applications should not use
* this method.
*
* @since JTS 2.1.1.
*/
public void associate () throws SystemException
{
current();
}
/**
* We could maintain a list of suspended action hierarchies and resume
* the right one (and the right place!) given the control. However, this
* can lead to memory leaks, since we never know when to remove this
* hierarchy information. So, for now we simply rely on the propagation
* context.
*/
public final boolean addRemoteHierarchy (Control cont)
{
if (jtsLogger.logger.isTraceEnabled()) {
jtsLogger.logger.trace("ContextManager::addRemoteHierarchy ()");
}
/*
* Here until we can make this work with recreate.
*/
if (false)
{
pushAction(new ControlWrapper(cont));
return true;
}
else
{
boolean isError = false;
try
{
Coordinator coord = cont.get_coordinator();
PropagationContext ctx = coord.get_txcontext();
if (ctx != null)
{
/*
* Depth must be non-zero or we wouldn't be here!
*/
int depth = ctx.parents.length;
for (int i = depth -1; i >= 0; i--)
{
/*
* No memory leak as we delete either when suspend
* is called, or the transaction is terminated.
*/
Coordinator tmpCoord = ctx.parents[i].coord;
Terminator tmpTerm = ctx.parents[i].term;
Control theControl = TransactionFactoryImple.createProxy(tmpCoord, tmpTerm);
pushAction(new ControlWrapper(theControl)); // takes care of thread/BasicAction for us.
}
ctx = null;
}
else
{
/*
* If we can't get a propagation context then we cannot
* create the hierarchy!
*/
isError = true;
}
coord = null;
}
catch (Exception e)
{
isError = true;
}
return isError;
}
}
/*
* All OTSArjuna controls have a method for getting their parent.
*/
public final boolean addActionControlHierarchy (ActionControl cont)
{
if (jtsLogger.logger.isTraceEnabled()) {
jtsLogger.logger.trace("ContextManager::addActionControlHierarchy ()");
}
boolean isError = false;
try
{
ActionControl actControl = cont;
Control parentControl = actControl.getParentControl();
Stack hier = new Stack();
while (parentControl != null)
{
hier.push(new ControlWrapper(parentControl));
actControl = com.arjuna.ArjunaOTS.ActionControlHelper.narrow(parentControl);
/*
* Currently assume that entire hierarchy will contain only one
* type of action, i.e., Arjuna actions or someone elses!
*/
if (actControl != null)
parentControl = actControl.getParentControl();
else
parentControl = null;
}
actControl = null;
try
{
ControlWrapper wrapper = (ControlWrapper) hier.pop();
while (wrapper != null)
{
pushAction(wrapper);
wrapper = null;
wrapper = (ControlWrapper) hier.pop();
}
}
catch (EmptyStackException e)
{
}
}
catch (Exception e)
{
jtsLogger.i18NLogger.warn_context_genfail("ContextManager.addActionControlHierarchy", e);
isError = true;
}
return isError;
}
/*
* Given a ControlWrapper we can create the hierarchy quickly, since
* we have the implementation information to hand.
*/
public final boolean addControlImpleHierarchy (ControlImple which)
{
if (jtsLogger.logger.isTraceEnabled()) {
jtsLogger.logger.trace("ContextManager::addControlImpleHierarchy ()");
}
boolean isError = false;
try
{
ControlImple curr = which.getParentImple();
Stack hier = new Stack();
while (curr != null)
{
hier.push(new ControlWrapper(curr));
curr = curr.getParentImple();
}
try
{
ControlWrapper wrapper = (ControlWrapper) hier.pop();
while (wrapper != null)
{
pushAction(wrapper);
wrapper = null;
wrapper = (ControlWrapper) hier.pop();
}
}
catch (EmptyStackException e)
{
}
}
catch (Exception e)
{
jtsLogger.i18NLogger.warn_context_genfail("ContextManager.addActionControlImple", e);
isError = true;
}
return isError;
}
/**
* If we have a hierarchy of remote actions (controls) then they will not
* be registered with BasicAction.
* Also, they will either all be remote references to controls, or all but
* the current action will be proxy/wrapper controls, i.e., controls which
* contain references to the remote coordinator/terminator.
*/
public final void pushAction (ControlWrapper action)
{
if (jtsLogger.logger.isTraceEnabled()) {
jtsLogger.logger.trace("ContextManager::pushAction ()");
}
final String threadId = ThreadUtil.getThreadId() ;
Stack sl = (Stack) otsCurrent.get(threadId);
boolean isNew = false;
if (sl == null)
{
isNew = true;
sl = new Stack();
}
// Check here that action is local and not a proxy.
/*
* If it's a local transaction then save the transaction
* pointer. We'll need it when we pop the transaction
* later.
*/
if (action != null)
action.determineLocality();
/*
* Doesn't need to be synchronized since only this thread
* can play with its own stack!
*/
sl.push(action);
if (isNew)
otsCurrent.put(threadId, sl);
associateContext();
if (action.isLocal())
{
/*
* Add thread to action list!
*/
/*
* Given a Control we can maintain a mapping to the
* actual action.
*
* Do we want this to work for remote actions? Yes, because
* we want all actions to know about active threads, even
* those that are remote. (But we don't do it yet!)
*
* Call action to increment number of threads. This is all we
* need to do for remote actions. If local, we need to make this
* action the current action.
*/
ThreadActionData.pushAction(action.getImple().getImplHandle());
}
}
public ControlWrapper currentPIContext () throws SystemException
{
if (_piCurrent != null)
{
try
{
int slotId = OTSManager.getReceivedSlotId();
if (slotId == -1)
return null;
org.omg.CORBA.Any ctx = _piCurrent.get_slot(slotId);
/*
* If we have something then we must be a server thread.
* In which case we save the thread id so that the server
* interceptor can do the suspend when the call returns.
*/
if (ctx.type().kind().value() != TCKind._tk_null)
{
ControlWrapper control = null;
// Is this just a Coordinator, or a full blown context?
if (ctx.type().kind().value() == TCKind._tk_string)
{
control = createProxy(ctx);
}
else
{
control = createHierarchy(ctx);
}
org.omg.CORBA.Any threadData = ORBManager.getORB().orb().create_any();
threadData.insert_string(ThreadUtil.getThreadId());
_piCurrent.set_slot(slotId, threadData);
return control;
}
else
return null;
}
catch (NullPointerException e)
{
// slot not set.
return null;
}
catch (InvalidSlot is)
{
// Something very wrong
throw new org.omg.CORBA.INTERNAL();
}
}
else
return null;
}
public final ControlWrapper createProxy (org.omg.CORBA.Any ctx) throws SystemException
{
String stringRef = null;
try
{
stringRef = ctx.extract_string();
/*
* Is this a thread id or an IOR? If the latter then use it,
* otherwise ignore it as:
*
* (i) this thread has been re-used before our filter has had a
* chance to remove the threading information from the slot. This
* will happen later.
*
* or
*
* (ii) the thread is calling back into itself to setup the
* BasicAction structure.
*
* Either way we can safely ignore.
*/
if (stringRef.startsWith(IORTag))
{
org.omg.CORBA.Object obj = ORBManager.getORB().orb().string_to_object(stringRef);
Coordinator theCoordinator = org.omg.CosTransactions.CoordinatorHelper.narrow(obj);
if (theCoordinator == null)
throw new BAD_PARAM();
return new ControlWrapper(TransactionFactoryImple.createProxy(theCoordinator, null));
}
else
return null;
}
catch (BAD_PARAM e1)
{
jtsLogger.i18NLogger.warn_context_genfail("ContextManager "+stringRef, e1);
}
catch (Exception e2) {
jtsLogger.i18NLogger.warn_context_genfail("ContextManager", e2);
throw new UNKNOWN(e2.toString());
}
return null;
}
public final ControlWrapper createHierarchy (org.omg.CORBA.Any ctx) throws SystemException
{
if (ctx != null)
{
try
{
PropagationContext theContext = org.omg.CosTransactions.PropagationContextHelper.extract(ctx);
if (OTSImpleManager.localFactory())
{
TransactionFactoryImple theFactory = OTSImpleManager.factory();
return new ControlWrapper(theFactory.recreateLocal(theContext));
}
else
{
TransactionFactory theFactory = OTSImpleManager.get_factory();
return new ControlWrapper(theFactory.recreate(theContext));
}
}
catch (TRANSACTION_UNAVAILABLE ex)
{
// Already logged this
throw ex;
}
catch (SystemException ex)
{
jtsLogger.i18NLogger.warn_context_genfail("ContextManager.createHierarchy", ex);
throw ex;
}
catch (Exception e) {
jtsLogger.i18NLogger.warn_context_genfail("ContextManager.createHierarchy", e);
throw new UNKNOWN();
}
}
else
return null;
}
private final void associateContext () throws SystemException
{
if (_piCurrent != null)
{
try
{
int slotId = OTSManager.getLocalSlotId();
if (slotId != -1)
{
org.omg.CORBA.Any localDataAny = ORBManager.getORB().orb().create_any();
localDataAny.insert_string(ThreadUtil.getThreadId());
_piCurrent.set_slot(slotId, localDataAny);
}
}
catch (InvalidSlot is)
{
// Something very wrong
throw new org.omg.CORBA.INTERNAL();
}
}
}
private final void disassociateContext () throws SystemException
{
if (_piCurrent != null)
{
try
{
int slotId = OTSManager.getLocalSlotId();
if (slotId != -1)
{
_piCurrent.set_slot(slotId, null);
}
}
catch (InvalidSlot is)
{
// Something very wrong
throw new org.omg.CORBA.INTERNAL();
}
}
}
private Hashtable otsCurrent = new Hashtable();
private org.omg.PortableInterceptor.Current _piCurrent = null;
private static final String IORTag = "IOR";
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy