com.arjuna.ats.internal.jts.orbspecific.ControlImple Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of narayana-jts-jacorb Show documentation
Show all versions of narayana-jts-jacorb Show documentation
JTS uber jar with jacorb stubs
/*
* 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) 2001, 2002,
*
* Hewlett-Packard Arjuna Labs,
* Newcastle upon Tyne,
* Tyne and Wear,
* UK.
*
* $Id: ControlImple.java 2342 2006-03-30 13:06:17Z $
*/
package com.arjuna.ats.internal.jts.orbspecific;
import java.util.Hashtable;
import org.omg.CORBA.BAD_OPERATION;
import org.omg.CORBA.SystemException;
import org.omg.CosTransactions.Control;
import org.omg.CosTransactions.Coordinator;
import org.omg.CosTransactions.Terminator;
import org.omg.CosTransactions.Unavailable;
import com.arjuna.ArjunaOTS.ActiveThreads;
import com.arjuna.ArjunaOTS.ActiveTransaction;
import com.arjuna.ArjunaOTS.ArjunaTransaction;
import com.arjuna.ArjunaOTS.BadControl;
import com.arjuna.ArjunaOTS.Destroyed;
import com.arjuna.ArjunaOTS.UidCoordinator;
import com.arjuna.ats.arjuna.common.Uid;
import com.arjuna.ats.arjuna.coordinator.ActionStatus;
import com.arjuna.ats.arjuna.coordinator.BasicAction;
import com.arjuna.ats.internal.jts.ORBManager;
import com.arjuna.ats.internal.jts.orbspecific.coordinator.ArjunaTransactionImple;
import com.arjuna.ats.internal.jts.utils.Helper;
import com.arjuna.ats.jts.logging.jtsLogger;
/*
* Although a transaction may have a timeout associated with it,
* this can only happen for a top-level transaction. This, combined
* with the fact that the default timeout is 0 means that many (most?)
* transactions will not have a timeout. So, rather than increase the
* size of all of the transaction objects, we keep the information
* separate in the TransactionReaper. (Since it already needs to have this
* information anyway this is no extra burden.) It also means that we can
* support non-JBoss transactions: if we were to add a new method to the
* control (get_timeout, say) then this would be Arjuna specific.
*/
/**
* An implementation of CosTransactions::Control
*
* @author Mark Little ([email protected])
* @version $Id: ControlImple.java 2342 2006-03-30 13:06:17Z $
* @since JTS 1.0.
*/
public class ControlImple extends com.arjuna.ArjunaOTS.ActionControlPOA
{
/**
* Create a new instance with the specified parent.
*/
public ControlImple (Control parentCon, ArjunaTransactionImple parentTran)
{
if (jtsLogger.logger.isTraceEnabled()) {
jtsLogger.logger.trace("ControlImple::ControlImple ( Control parentCon, "
+ ((parentTran != null) ? parentTran.get_uid()
: Uid.nullUid()) + " )");
}
_theTerminator = null;
_theCoordinator = null;
_parentControl = parentCon;
_transactionHandle = new ArjunaTransactionImple(_parentControl,
parentTran);
_theUid = _transactionHandle.get_uid();
_transactionImpl = null;
_myControl = null;
_destroyed = false;
/*
* Pass a pointer to the control to the transaction so it knows what the
* control is. We use this for transaction comparison and
* thread-to-context management.
*/
_transactionHandle.setControlHandle(this);
addControl();
}
public void finalize () throws Throwable
{
if (jtsLogger.logger.isTraceEnabled()) {
jtsLogger.logger.trace("ControlImple.finalize ()");
}
if (!_destroyed)
{
try
{
destroy();
}
catch (Exception e)
{
}
}
tidyup();
/*
* Do this here rather than in tidyup so anyone else with a reference to
* this control can continue to determine the status of the transaction
* until the control is garbage collected.
*/
_theTerminator = null;
_theCoordinator = null;
_theUid = null;
}
/**
* Used for garbage collection so we can keep a list of controls and delete
* local ones.
*/
public Uid get_uid ()
{
return _theUid;
}
/**
* @return the transaction implementation.
*/
public final ArjunaTransactionImple getImplHandle ()
{
return _transactionHandle;
}
/**
* @return the CORBA Control object.
*/
public final synchronized Control getControl ()
{
/*
* If we have been committed then the reference will be null. There is
* no point in recreating it and in some cases (e.g., JacORB) this will
* in fact cause an exception to be thrown.
*/
if ((_myControl == null) && (!_destroyed))
{
ORBManager.getPOA().objectIsReady(this);
_myControl = com.arjuna.ArjunaOTS.ActionControlHelper.narrow(ORBManager.getPOA().corbaReference(this));
}
/*
* In C++ we had to narrow to Control for some ORBs, despite the fact
* that an ArjunaControl is a Control. Does now seem to be necessary for
* Java.
*
* return ControlHelper.narrow(_myControl);
*/
return _myControl;
}
public Terminator get_terminator () throws SystemException,
org.omg.CosTransactions.Unavailable
{
if ((_transactionHandle != null) && (_theTerminator == null))
createTransactionHandle();
if (_theTerminator != null)
return _theTerminator;
else
throw new Unavailable();
}
public Coordinator get_coordinator () throws SystemException,
org.omg.CosTransactions.Unavailable
{
if ((_transactionHandle != null) && (_theCoordinator == null))
createTransactionHandle();
if (_theCoordinator != null)
return _theCoordinator;
else
throw new Unavailable();
}
public void set_terminator (Terminator terminator) throws SystemException,
org.omg.CosTransactions.Unavailable
{
throw new org.omg.CosTransactions.Unavailable();
}
public void set_coordinator (Coordinator coordinator)
throws SystemException, org.omg.CosTransactions.Unavailable
{
throw new org.omg.CosTransactions.Unavailable();
}
public Control getParentControl () throws Unavailable, SystemException
{
if (_parentControl != null)
return _parentControl;
else
return null;
}
/**
* destroy should only be called for remote Control objects. Destroy them
* locally by calling DESTROY_IMPL.
*
* Since we assume that a factory will either be remote or local, we can
* destroy this object and rely upon the ORB to return an exception to
* subsequent clients which indicates they no longer have a valid reference.
*/
public synchronized void destroy () throws ActiveTransaction,
ActiveThreads, BadControl, Destroyed, SystemException
{
if (jtsLogger.logger.isTraceEnabled()) {
jtsLogger.logger.trace("Control::destroy called for "
+ get_uid());
}
canDestroy();
try
{
_destroyed = true;
removeControl();
/*
* We do a lazy connect to the ORB, so we may never have to do a
* disconnect either.
*/
if (_myControl != null)
{
ORBManager.getPOA().shutdownObject(this);
_myControl = null;
}
/*
* If this is a proxy then there won't be a local transaction
* implementation.
*/
if (_transactionHandle != null)
{
_transactionHandle.setControlHandle(null); // for gc
_transactionHandle = null;
}
tidyup();
}
catch (Exception e)
{
throw new BAD_OPERATION(
"ControlImple "
+ jtsLogger.i18NLogger.get_orbspecific_destroyfailed()
+ e);
}
}
public ControlImple getParentImple ()
{
BasicAction parent = ((_transactionHandle != null) ? _transactionHandle.parent()
: null);
if (parent != null)
{
try
{
synchronized (ControlImple.allControls)
{
return (ControlImple) ControlImple.allControls.get(parent.get_uid());
}
}
catch (Exception ex)
{
return null;
}
}
else
return null;
}
public String toString ()
{
return "ControlImple < " + get_uid() + " >";
}
public boolean equals (java.lang.Object obj)
{
if (obj instanceof ControlImple)
{
if (((ControlImple) obj).get_uid().equals(get_uid()))
return true;
}
return false;
}
/**
* In the case that the transaction is terminated by the reaper then it will
* also be tidied up. This means that the internal handle to the real transaction
* instance will be nulled out. In that case we cache the status just before removing
* the handle and this method can be used to obtain it.
*
* @return the final termination status of the transaction.
* @throws IllegalStateException thrown if the transaction is still available.
*/
public org.omg.CosTransactions.Status getFinalStatus () throws IllegalStateException
{
if (getImplHandle() != null)
throw new IllegalStateException();
else
return _finalStatus;
}
protected synchronized void canDestroy () throws ActiveTransaction,
ActiveThreads, BadControl, Destroyed, SystemException
{
canDestroy(true);
}
/**
* Generally we do not want to destroy the transaction if it is doing some
* work, or other threads are still registered with it. However, for some
* situations (e.g., the transaction reaper) we must terminate the
* transaction regardless.
*/
protected synchronized void canDestroy (boolean force)
throws ActiveTransaction, ActiveThreads, BadControl, Destroyed,
SystemException
{
if (jtsLogger.logger.isTraceEnabled()) {
jtsLogger.logger.trace("Control::canDestroy ( "
+ force + " ) called for " + get_uid());
}
if (_destroyed)
throw new Destroyed();
if (_transactionHandle != null) // not a proxy control.
{
if ((_transactionHandle.activeThreads() != 0) && (!force))
{
if (jtsLogger.logger.isTraceEnabled()) {
jtsLogger.logger.trace("ControlImple::canDestroy for "
+ get_uid()
+ " - transaction has "
+ _transactionHandle.activeThreads()
+ " active threads.");
}
throw new ActiveThreads();
}
boolean active = false;
try
{
if ((force)
|| ((_transactionHandle.status() == ActionStatus.CREATED)
|| (_transactionHandle.status() == ActionStatus.ABORTED) || (_transactionHandle.status() == ActionStatus.COMMITTED)))
{
active = false;
}
else
active = true; // might be committing, aborting, etc.
}
catch (Exception e)
{
active = true;
}
if (active)
{
if (jtsLogger.logger.isTraceEnabled()) {
jtsLogger.logger.trace("Control::canDestroy for "
+ get_uid() + " - transaction active.");
}
throw new ActiveTransaction();
}
} // it is always safe to delete proxies.
/*
* Got here, so it is either ok to destroy or the caller wants to force
* the destruction regardless.
*/
}
/**
* This is used for implicit context propagation, and for Current.resume on
* remote transactions. In both cases we need to create a local control
* given a remove coordinator and terminator, but we can't create a
* transaction handle.
*/
protected ControlImple (Coordinator coordinator, Terminator terminator)
{
this(coordinator, terminator, null, null);
}
protected ControlImple (Coordinator coordinator, Terminator terminator, Uid uid)
{
this(coordinator, terminator, null, uid);
}
protected ControlImple (Coordinator coordinator, Terminator terminator, Control parentControl, Uid uid)
{
if (jtsLogger.logger.isTraceEnabled()) {
jtsLogger.logger.trace("ControlImple::ControlImple (Coordinator, Terminator, Control, "
+ uid + " )");
}
_theTerminator = terminator;
_theCoordinator = coordinator;
_parentControl = parentControl;
_transactionHandle = null;
_transactionImpl = null;
_myControl = null;
_destroyed = false;
if (uid == null)
{
UidCoordinator uidCoord = Helper.getUidCoordinator(coordinator);
if (uidCoord != null)
{
try
{
_theUid = Helper.getUid(uidCoord);
}
catch (Exception e)
{
/*
* Not an JBoss transaction, so allocate any Uid.
*/
_theUid = new Uid();
}
uidCoord = null;
}
else
_theUid = new Uid();
}
else
_theUid = uid;
duplicateTransactionHandle(coordinator, terminator);
addControl();
}
/**
* Protected constructor for inheritance. The derived classes are
* responsible for setting everything up, including adding the control to
* the list of controls and assigning the Uid variable.
*/
protected ControlImple ()
{
if (jtsLogger.logger.isTraceEnabled()) {
jtsLogger.logger.trace("ControlImple::ControlImple ()");
}
_theTerminator = null;
_theCoordinator = null;
_parentControl = null;
_transactionHandle = null;
_theUid = Uid.nullUid();
_transactionImpl = null;
_myControl = null;
_destroyed = false;
}
protected final void createTransactionHandle ()
{
if (jtsLogger.logger.isTraceEnabled()) {
jtsLogger.logger.trace("ControlImple::createTransactionHandle ()");
}
/* Create/bind the 2 IDL interfaces to the same implementation */
_transactionImpl = new com.arjuna.ArjunaOTS.ArjunaTransactionPOATie(
_transactionHandle);
ORBManager.getPOA().objectIsReady(_transactionImpl);
ArjunaTransaction transactionReference = com.arjuna.ArjunaOTS.ArjunaTransactionHelper.narrow(ORBManager.getPOA().corbaReference(_transactionImpl));
_theCoordinator = com.arjuna.ArjunaOTS.UidCoordinatorHelper.narrow(transactionReference);
_theTerminator = org.omg.CosTransactions.TerminatorHelper.narrow(transactionReference);
transactionReference = null;
}
protected final void duplicateTransactionHandle (Coordinator coord, Terminator term)
{
if (jtsLogger.logger.isTraceEnabled()) {
jtsLogger.logger.trace("ControlImple::duplicateTransactionHandle ()");
}
_theCoordinator = coord;
_theTerminator = term;
}
/**
* Transaction needs to call these methods to enable garbage collection to
* occur.
*
* Note, we assume that one ContorlImple per transaction is maintained per address
* space, so that overwriting a previously added ControlImple for the same tx is
* not possible.
*/
protected boolean addControl ()
{
if (jtsLogger.logger.isTraceEnabled()) {
jtsLogger.logger.trace("ControlImple::addControl ()");
}
try
{
synchronized (ControlImple.allControls)
{
ControlImple.allControls.put(get_uid(), this);
}
}
catch (Exception ex)
{
return false;
}
return true;
}
protected boolean removeControl ()
{
if (jtsLogger.logger.isTraceEnabled()) {
jtsLogger.logger.trace("ControlImple::removeControl ()");
}
try
{
synchronized (ControlImple.allControls)
{
ControlImple.allControls.remove(get_uid());
}
}
catch (Exception ex)
{
return false;
}
return true;
}
/**
* No need to protect with mutex since only called from destroy (and
* destructor), which is protected with a mutex. Do not call directly
* without synchronizing.
*/
protected final void tidyup ()
{
if (jtsLogger.logger.isTraceEnabled()) {
jtsLogger.logger.trace("ControlImple::tidyup ()");
}
_myControl = null;
_parentControl = null;
try
{
if (_transactionImpl != null)
{
_finalStatus = _transactionImpl.get_status();
ORBManager.getPOA().shutdownObject(_transactionImpl);
_transactionHandle = null;
_transactionImpl = null;
}
}
catch (Exception e)
{
jtsLogger.i18NLogger.warn_orbspecific_tidyfail("ControlImple.tidyup", e);
}
}
/*
* Make private, with public accessor.
*/
public static Hashtable allControls = new Hashtable();
protected Terminator _theTerminator;
protected Coordinator _theCoordinator;
protected Control _parentControl;
protected ArjunaTransactionImple _transactionHandle;
protected Uid _theUid;
protected com.arjuna.ArjunaOTS.ActionControl _myControl;
protected com.arjuna.ArjunaOTS.ArjunaTransactionPOATie _transactionImpl;
protected boolean _destroyed;
private org.omg.CosTransactions.Status _finalStatus = org.omg.CosTransactions.Status.StatusUnknown;
}