/*
* JBoss, Home of Professional Open Source
* Copyright 2008, 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) 2008,
* @author JBoss Inc.
*/
package com.arjuna.ats.internal.jts;
import org.omg.CosTransactions.Control;
import org.omg.CosTransactions.Coordinator;
import com.arjuna.ArjunaOTS.UidCoordinator;
import com.arjuna.ats.arjuna.common.Uid;
import com.arjuna.ats.internal.jts.orbspecific.ControlImple;
import com.arjuna.ats.internal.jts.utils.Helper;
/**
* a wrapper used to wrap a ControlImple or a Control when attempting to remove it from the TransactionReaper
* transactions list. this wrapper ensures that hashcode and equals calls compare correctly while performing
* as few remote invocations as possible to do the comparison.
*/
public class PseudoControlWrapper
{
// public API
/**
* wrap a Control in a wrapper which can be used to test for equality against ControlWrapper instances
* n.b. the Control must have been determined to be a non-local control by the caller
*
* @param control
*/
public PseudoControlWrapper(Control control)
{
_coordinator = null; // for non-local control -- only compute when needed
_control = control;
_uid = null; // for non-local control -- only compute when needed
_local = null;
_hashCode = computeHashCode();
}
/**
* wrap a ControlImple in a wrapper which can be used to test for equality against ControlWrapper instances
*
* @param controlImple
*/
public PseudoControlWrapper(ControlImple controlImple)
{
_coordinator = null; // for non-local control -- only compute when needed
_control = null;
_uid = null; // for non-local control -- only compute when needed
_local = controlImple;
_hashCode = computeHashCode();
}
/**
* this returns the same hashcode as ControlWrapper for a given Control or ControlImple
*
* @return the hashcode of the object
*/
public int hashCode()
{
return _hashCode;
}
/**
* Test whether this PseudoControlWrapper wraps the same Control as a ControlWrapper
*
* The equality rules differ depending upon whether this wraps a local or remote Control
*
* if the wrapped control is local then the local uid can be compared against the uid cached in the ControlWrapper
*
* if the wrapped control is non-local then the test depends upon whether the ControlWrapper wraps a local
* or remote control. in the former case a uid comparison can be used. in the latter case the coordinators of
* the two controls must be obtained and a call to coord.is_same_transaction(othercoord) must be used.
*
* @caveats this comparison is only defined against instances of ControlWrapper because this class should only be
* used to wrap a control for comparison against an entry in the TransactionReaper's list of controls and should
* only compare equal to an entry which is a ControlWrapper for the same Control. as such it breaks all the
* rules for an equals implementation and should not be expected to work anywhere else.
*
*
*/
public boolean equals(Object o)
{
if (o instanceof ControlWrapper) {
ControlWrapper wrapper = (ControlWrapper)o;
if (_local != null) {
// the other guys uid will already have been computed so just do a uid -- uid comparison
return _local.get_uid().equals(wrapper.get_uid());
} else if (_control == null) {
return false;
} else if (wrapper.isLocal()) {
// the other control is local so a UID comparison must be ok
try
{
// make sure we have our uid
if (_uid == null) {
_uid = computeUid();
}
return _uid.equals(wrapper.get_uid());
} catch (Exception e) {
return false;
}
} else {
/*
* Trying to compare two non-local controls -- assuming the previous implementation was correct we
* need to do a full comparison of this control's coordinator against the wrapper control's coordinator
* TODO why can't we just get the two UIDs and compare them?
*/
try {
// make sure we have our coordinator
if (_coordinator == null) {
_coordinator = computeCoordinator();
}
return _coordinator.is_same_transaction(wrapper.get_coordinator());
} catch (Exception e) {
return false;
}
}
}
return false;
}
/**
* fetch the coordinator for the wrapped non-local control
* @return the remote coordinator
* @throws Exception if the coordinator cannot be obtained e.g. because the control is no longer valid
*/
private Coordinator computeCoordinator()
throws Exception
{
return _control.get_coordinator();
}
/**
* fetc the uid for the wrapped non-local control
* @return the uid
* @throws Exception if the coordinator cannot be obtained e.g. because the control is no longer valid
*/
private Uid computeUid()
throws Exception
{
if (_coordinator == null) {
_coordinator = computeCoordinator();
}
UidCoordinator uidCoord = Helper.getUidCoordinator(_coordinator);
return Helper.getUid(uidCoord);
}
/**
* compute the hashcode for the wrapped local or remote control using the same algorithm as ControlWrapper
* @return the hashcode
*/
private int computeHashCode()
{
try {
if (_local != null) {
return _local.getImplHandle().hash_transaction();
} else if (_control != null) {
Coordinator coord = _control.get_coordinator();
return coord.hash_transaction();
}
} catch (Exception e) {
}
return -1;
}
/**
* the wrapped local control or null if the control is non-local
*/
private ControlImple _local;
/**
* the wrapped non-local control or null if the control is local
*/
private Control _control;
/**
* coordinator for the wrapped non-local control computed lazily as needed
*/
private Coordinator _coordinator;
/**
* uid for the wrapped non-local control computed lazily as needed
*/
private Uid _uid;
/**
* hashcode for the wrapped control
*/
private int _hashCode;
}