/* * 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, 2001, 2002, * * Hewlett-Packard Arjuna Labs, * Newcastle upon Tyne, * Tyne and Wear, * UK. * * $Id: ExtendedResourceRecord.java 2342 2006-03-30 13:06:17Z $ */ package com.arjuna.ats.internal.jts.resources; /* * * OTS Abstract Record Class Implementation. * * (Extended resource functionality.) * */ import java.io.IOException; import java.io.PrintWriter; import org.omg.CORBA.BAD_PARAM; import org.omg.CORBA.INVALID_TRANSACTION; import org.omg.CORBA.OBJECT_NOT_EXIST; import org.omg.CORBA.SystemException; import org.omg.CORBA.TRANSACTION_ROLLEDBACK; import org.omg.CORBA.UNKNOWN; import org.omg.CosTransactions.Coordinator; import org.omg.CosTransactions.HeuristicCommit; import org.omg.CosTransactions.HeuristicHazard; import org.omg.CosTransactions.HeuristicMixed; import org.omg.CosTransactions.HeuristicRollback; import org.omg.CosTransactions.NotPrepared; import org.omg.CosTransactions.Vote; import com.arjuna.ArjunaOTS.ArjunaSubtranAwareResource; import com.arjuna.ArjunaOTS.OTSAbstractRecord; import com.arjuna.ats.arjuna.ObjectType; import com.arjuna.ats.arjuna.common.Uid; import com.arjuna.ats.arjuna.coordinator.AbstractRecord; import com.arjuna.ats.arjuna.coordinator.RecordType; import com.arjuna.ats.arjuna.coordinator.TwoPhaseOutcome; import com.arjuna.ats.arjuna.state.InputObjectState; import com.arjuna.ats.arjuna.state.OutputObjectState; import com.arjuna.ats.internal.arjuna.common.UidHelper; import com.arjuna.ats.internal.jts.ORBManager; import com.arjuna.ats.internal.jts.orbspecific.ControlImple; import com.arjuna.ats.internal.jts.orbspecific.coordinator.ArjunaTransactionImple; import com.arjuna.ats.jts.logging.jtsLogger; /** * This abstract record is used whenever resources are derived from the * ArjunaOTS module's AbstractRecord interface. This gives users the flexibility * of the original Arjuna system's AbstractRecord, and makes resources behave * correctly! * * We know that instances of this record will only be called for instances of * AbstractRecord objects. * * @author Mark Little (mark@arjuna.com) * @version $Id: ExtendedResourceRecord.java 2342 2006-03-30 13:06:17Z $ * @since JTS 1.0. */ public class ExtendedResourceRecord extends com.arjuna.ats.arjuna.coordinator.AbstractRecord { private boolean lastRecord; /** * @param propagate * tells us whether to propagate the resource at nested commit or * not. * @param theResource * is the proxy that allows us to call out to the object. * @param myParent * is the proxy for the parent coordinator needed in * commit_subtransaction. */ public ExtendedResourceRecord (boolean propagate, Uid objUid, ArjunaSubtranAwareResource theResource, Coordinator myParent, Uid recCoordUid, ArjunaTransactionImple current) { super(objUid, null, ObjectType.ANDPERSISTENT); _resourceHandle = theResource; _stringifiedResourceHandle = null; _parentCoordHandle = myParent; _recCoordUid = (recCoordUid != null) ? recCoordUid : new Uid( Uid.nullUid()); _currentTransaction = current; _propagateRecord = propagate; _rolledback = false; _endpointFailed = false; _restored = false; } /** * Specific OTS method for getting at the value. */ public final ArjunaSubtranAwareResource resourceHandle () { /* * After recovery we may have not been able to recreate the * _resourceHandle due to the fact that the Resource itself may not be * alive resulting in a failure to narrow the reference returned from * string_to_object. In such cases we cache the stringified reference * and retry the narrow when we need to use the _resourceHandle as at * this point the Resource may have recovered. */ if ((_resourceHandle == null) && (_stringifiedResourceHandle != null)) { try { org.omg.CORBA.ORB theOrb = ORBManager.getORB().orb(); if (theOrb == null) throw new UNKNOWN(); if (jtsLogger.logger.isTraceEnabled()) { jtsLogger.logger.trace( "ExtendedResourceRecord: About to string_to_object on " + _stringifiedResourceHandle); } org.omg.CORBA.Object optr = theOrb.string_to_object(_stringifiedResourceHandle); if (jtsLogger.logger.isTraceEnabled()) { jtsLogger.logger.trace("ExtendedResourceRecord: Successfully stringed to object, next try to narrow"); } theOrb = null; _resourceHandle = com.arjuna.ArjunaOTS.ArjunaSubtranAwareResourceHelper.narrow(optr); // This is needed because for JDK ORB it could narrow and won't allow shutdown of OA if (jtsLogger.logger.isTraceEnabled()) { jtsLogger.logger.trace("ExtendedResourceRecord: Successfully narrowed"); } if (_resourceHandle == null) throw new BAD_PARAM(); else { optr = null; } } catch (SystemException e) { // Failed to narrow to a ArjunaSubtranAwareResource if (jtsLogger.logger.isTraceEnabled()) { jtsLogger.logger.trace("ExtendedResourceRecord: Failed to narrow to ArjunaSubtranAwareResource"); } } } return _resourceHandle; } public boolean propagateOnCommit () { if (_propagateRecord) return true; OTSAbstractRecord resHandle = otsRecord(); try { if ((resHandle != null) && !_endpointFailed) return resHandle.propagateOnCommit(); } catch (Exception e) { _endpointFailed = true; } return true; } public boolean propagateOnAbort () { OTSAbstractRecord resHandle = otsRecord(); try { if ((resHandle != null) && !_endpointFailed) return resHandle.propagateOnAbort(); } catch (Exception e) { _endpointFailed = true; } return false; } public Uid order () { Uid toReturn = super.order(); if (_cachedUid == null) { OTSAbstractRecord resHandle = otsRecord(); try { if ((resHandle != null) && !_endpointFailed) { toReturn = _cachedUid = new Uid(resHandle.uid()); } } catch (Exception e) { _endpointFailed = true; } } else toReturn = _cachedUid; return toReturn; } public int typeIs () { OTSAbstractRecord resHandle = otsRecord(); int r = RecordType.OTS_ABSTRACTRECORD; if (_cachedType == -1) { try { if ((resHandle != null) && !_endpointFailed) _cachedType = r = resHandle.type_id(); } catch (Exception e) { r = RecordType.OTS_ABSTRACTRECORD; _endpointFailed = true; jtsLogger.i18NLogger.warn_resources_errtypefail("ExtendedResourceRecord.typeIs", Integer.toString(r)); } } else r = _cachedType; resHandle = null; return r; } public Object value () { return _resourceHandle; } public void setValue (Object o) { jtsLogger.i18NLogger.warn_resources_errsetvalue("ExtendedResourceRecord.set_value"); } /** * General nesting rules: * * Only SubtransactionAware resources get registered with nested actions. * The ExtendedResourceRecord creator is assumed to ensure that plain * Resources are only registered with the appropriate top level action. * * That said the _propagateRecord flag ensures that resources registered via * register_subtran only take part in the action they where registered in * after which they are dropped. */ public int nestedAbort () { if (jtsLogger.logger.isTraceEnabled()) { jtsLogger.logger.trace("ExtendedResourceRecord::nestedAbort() for " + order()); } /* * Must be an staResource to get here. */ try { resourceHandle().rollback_subtransaction(); } catch (OBJECT_NOT_EXIST one) { if (_rolledback) { _rolledback = false; // in case we get propagated to the parent return TwoPhaseOutcome.FINISH_OK; } else return TwoPhaseOutcome.FINISH_ERROR; } catch (SystemException ex) { jtsLogger.i18NLogger.warn_resources_errgenerr("ExtendedResourceRecord.nestedAbort", ex); return TwoPhaseOutcome.FINISH_ERROR; } return TwoPhaseOutcome.FINISH_OK; } public int nestedCommit () { if (jtsLogger.logger.isTraceEnabled()) { jtsLogger.logger.trace("ExtendedResourceRecord::nestedCommit() for " + order()); } int o = TwoPhaseOutcome.FINISH_ERROR; try { resourceHandle().commit_subtransaction(_parentCoordHandle); /* * Now release the parent as it is about to be destroyed anyway. */ _parentCoordHandle = null; if (_currentTransaction != null) { /* * Now change our notion of our parent for subsequent nested * transaction commits. We were passed a reference to the * current transaction, so we can just ask it for it's parent. * If it doesn't have one, then generate an error. */ _currentTransaction = (ArjunaTransactionImple) _currentTransaction.parent(); ControlImple control = ((_currentTransaction == null) ? null : _currentTransaction.getControlHandle()); if (control != null) { _parentCoordHandle = control.get_coordinator(); control = null; o = TwoPhaseOutcome.FINISH_OK; } else { jtsLogger.i18NLogger.warn_resources_errnoparent("ExtendedResourceRecord.nestedCommit"); o = TwoPhaseOutcome.FINISH_ERROR; } } else { jtsLogger.i18NLogger.warn_resources_noparent(get_uid()); o = TwoPhaseOutcome.FINISH_ERROR; } } catch (Exception e) { jtsLogger.i18NLogger.warn_resources_errgenerr("ExtendedResourceRecord.nestedCommit", e); o = TwoPhaseOutcome.FINISH_ERROR; } return o; } /** * Because resource is an Arjuna AbstractRecord we can do proper nesting! */ public int nestedPrepare () { if (jtsLogger.logger.isTraceEnabled()) { jtsLogger.logger.trace("ExtendedResourceRecord::nestedPrepare() for " + order()); } int o = TwoPhaseOutcome.PREPARE_NOTOK; try { switch (resourceHandle().prepare_subtransaction().value()) { case Vote._VoteCommit: o = TwoPhaseOutcome.PREPARE_OK; break; case Vote._VoteRollback: _rolledback = true; o = TwoPhaseOutcome.PREPARE_NOTOK; break; case Vote._VoteReadOnly: o = TwoPhaseOutcome.PREPARE_READONLY; break; } } catch (Exception e) { jtsLogger.i18NLogger.warn_resources_errgenerr("ExtendedResourceRecord.nestedPrepare", e); o = TwoPhaseOutcome.PREPARE_NOTOK; } return o; } public int topLevelAbort () { if (jtsLogger.logger.isTraceEnabled()) { jtsLogger.logger.trace("ExtendedResourceRecord::topLevelAbort() for " + order()); } try { if (resourceHandle() != null) { _resourceHandle.rollback(); } else return TwoPhaseOutcome.FINISH_ERROR; } catch (HeuristicCommit e1) { if (_rolledback) return TwoPhaseOutcome.HEURISTIC_HAZARD; // participant lied in // prepare! else return TwoPhaseOutcome.HEURISTIC_COMMIT; } catch (HeuristicMixed e2) { return TwoPhaseOutcome.HEURISTIC_MIXED; } catch (HeuristicHazard e3) { return TwoPhaseOutcome.HEURISTIC_HAZARD; } catch (OBJECT_NOT_EXIST one) { /* * If the resource voted to roll back in prepare then it can legally * be garbage collected at that point. Hence, it may be that we get * a failure during rollback if we try to call it. If it didn't vote * to roll back then some other error has happened. */ if (_rolledback) return TwoPhaseOutcome.FINISH_OK; else return TwoPhaseOutcome.HEURISTIC_HAZARD; } catch (SystemException e4) { jtsLogger.i18NLogger.warn_resources_errgenerr("ExtendedResourceRecord.topLevelAbort", e4); return TwoPhaseOutcome.FINISH_ERROR; } return TwoPhaseOutcome.FINISH_OK; } public int topLevelCommit () { if (jtsLogger.logger.isTraceEnabled()) { jtsLogger.logger.trace("ExtendedResourceRecord::topLevelCommit() for " + order()); } if (!lastRecord) { try { if (resourceHandle() != null) { _resourceHandle.commit(); } else return TwoPhaseOutcome.FINISH_ERROR; } catch (NotPrepared e1) { return TwoPhaseOutcome.NOT_PREPARED; } catch (HeuristicRollback e2) { return TwoPhaseOutcome.HEURISTIC_ROLLBACK; } catch (HeuristicMixed e3) { return TwoPhaseOutcome.HEURISTIC_MIXED; } catch (HeuristicHazard e4) { return TwoPhaseOutcome.HEURISTIC_HAZARD; } catch (SystemException e6) { jtsLogger.i18NLogger.warn_resources_errgenerr("ExtendedResourceRecord.topLevelCommit", e6); return TwoPhaseOutcome.FINISH_ERROR; } catch (Exception e2) { e2.printStackTrace(); return TwoPhaseOutcome.FINISH_ERROR; } } return TwoPhaseOutcome.FINISH_OK; } public int topLevelPrepare () { if (jtsLogger.logger.isTraceEnabled()) { jtsLogger.logger.trace("ExtendedResourceRecord::topLevelPrepare() for " + order()); } try { if (resourceHandle() != null) { switch (_resourceHandle.prepare().value()) { case Vote._VoteCommit: return TwoPhaseOutcome.PREPARE_OK; case Vote._VoteRollback: _rolledback = true; return TwoPhaseOutcome.PREPARE_NOTOK; case Vote._VoteReadOnly: return TwoPhaseOutcome.PREPARE_READONLY; } } else return TwoPhaseOutcome.PREPARE_NOTOK; } catch (HeuristicMixed e1) { return TwoPhaseOutcome.HEURISTIC_MIXED; } catch (HeuristicHazard e2) { return TwoPhaseOutcome.HEURISTIC_HAZARD; } catch (Exception e) { jtsLogger.i18NLogger.warn_resources_errgenerr("ExtendedResourceRecord.topLevelPrepare", e); return TwoPhaseOutcome.PREPARE_NOTOK; } return TwoPhaseOutcome.PREPARE_NOTOK; } public int nestedOnePhaseCommit () { switch (nestedPrepare()) { case TwoPhaseOutcome.PREPARE_OK: return nestedCommit(); case TwoPhaseOutcome.PREPARE_READONLY: return TwoPhaseOutcome.FINISH_OK; default: return TwoPhaseOutcome.FINISH_ERROR; } } public int topLevelOnePhaseCommit () { try { if (resourceHandle() != null) _resourceHandle.commit_one_phase(); } catch (HeuristicHazard e1) { return TwoPhaseOutcome.HEURISTIC_HAZARD; } catch (TRANSACTION_ROLLEDBACK e4) { /* * It rolled back. That's ok, but we need to be able * to communicate that back to the caller. */ return TwoPhaseOutcome.ONE_PHASE_ERROR; // TODO TPO extension required. } catch (INVALID_TRANSACTION e5) { return TwoPhaseOutcome.ONE_PHASE_ERROR; } catch (final UNKNOWN ex) { /* * Means we can retry. */ return TwoPhaseOutcome.FINISH_ERROR; } catch (Exception e5) { jtsLogger.i18NLogger.warn_resources_errgenerr("ExtendedResourceRecord.topLevelOnePhaseCommit", e5); e5.printStackTrace(); /* * Unknown error - better assume heuristic! */ return TwoPhaseOutcome.HEURISTIC_HAZARD; } return TwoPhaseOutcome.FINISH_OK; } public boolean forgetHeuristic () { try { if (resourceHandle() != null) { _resourceHandle.forget(); return true; } else { jtsLogger.i18NLogger.warn_resources_errnores("ExtendedResourceRecord.forgetHeuristic"); } } catch (Exception e) { jtsLogger.i18NLogger.warn_resources_errgenerr("ExtendedResourceRecord.forgetHeuristic", e); } return false; } /* public static AbstractRecord create () { return new ExtendedResourceRecord(); } public void remove (AbstractRecord toDelete) { toDelete = null; } */ public void print (PrintWriter strm) { super.print(strm); strm.println("ExtendedResourceRecord"); strm.println(_resourceHandle + "\t" + _parentCoordHandle + "\t" + _propagateRecord); } /** * restore_state and save_state for ExtendedResourceRecords doesn't * generally apply due to object pointers. However, we need to save * something so we can recover failed transactions. So, rather than insist * that all Resources derive from a class which we can guarantee will give * us some unique id, we simply rely on string_to_object and * object_to_string to be meaningful. */ public boolean restore_state (InputObjectState os, int t) { int isString = 0; boolean result = super.restore_state(os, t); if (!result) return false; try { _propagateRecord = os.unpackBoolean(); /* * Do we need to restore the parent coordinator handle? */ _parentCoordHandle = null; _cachedUid = UidHelper.unpackFrom(os); _cachedType = os.unpackInt(); isString = os.unpackInt(); if (isString == 1) { _stringifiedResourceHandle = os.unpackString(); /* * Could call resourceHandle() here to restore the * _resourceHandle reference but no loss in doing it lazily. */ // Unpack recovery coordinator Uid _recCoordUid = UidHelper.unpackFrom(os); if (jtsLogger.logger.isTraceEnabled()) { jtsLogger.logger.trace("ExtendedResourceRecord.restore_state: unpacked record with uid=" + _recCoordUid); } } else _stringifiedResourceHandle = null; lastRecord = os.unpackBoolean(); } catch (IOException e) { e.printStackTrace(); result = false; } _restored = result; return result; } /** * restore_state and save_state for ExtendedResourceRecords doesn't * generally apply due to object pointers. However, we need to save * something so we can recover failed transactions. So, rather than insist * that all Resources derive from a class which we can guarantee will give * us some unique id, we simply rely on string_to_object and * object_to_string to be meaningful. */ public boolean save_state (OutputObjectState os, int t) { boolean result = super.save_state(os, t); if (!result) return false; try { /* * Do we need to save the parent coordinator handle? */ /* * If we have a _resourceHandle then we stringify it and pack the * string. Failing that if we have a cached stringified version (in * _stringifiedResourceHandle) then we pack that. If we have neither * then we're doomed. */ os.packBoolean(_propagateRecord); if (_cachedUid == null) _cachedUid = order(); UidHelper.packInto(_cachedUid, os); if (_cachedType == -1) _cachedType = typeIs(); os.packInt(_cachedType); if ((_resourceHandle == null) && (_stringifiedResourceHandle == null)) { os.packInt(-1); } else { os.packInt(1); String stringRef = null; if (_resourceHandle != null) { org.omg.CORBA.ORB theOrb = ORBManager.getORB().orb(); if (theOrb == null) throw new UNKNOWN(); stringRef = theOrb.object_to_string(_resourceHandle); theOrb = null; } else { stringRef = _stringifiedResourceHandle; } if (stringRef != null) { os.packString(stringRef); if (jtsLogger.logger.isTraceEnabled()) { jtsLogger.logger.trace("ExtendedResourceRecord: packed obj ref " + stringRef); } } else { result = false; } stringRef = null; if (result) { // Pack recovery coordinator Uid UidHelper.packInto(_recCoordUid, os); if (jtsLogger.logger.isTraceEnabled()) { jtsLogger.logger.trace("Packed rec co uid of " + _recCoordUid); } } os.packBoolean(lastRecord); } } catch (IOException e) { result = false; } catch (SystemException e) { result = false; } return result; } public String type () { return "/StateManager/AbstractRecord/ExtendedResourceRecord"; } public boolean doSave () { if (_restored) return true; switch (_doSave) // check cached value first { case -1: break; // not cached yet case 0: return false; case 1: return true; default: break; } OTSAbstractRecord resHandle = otsRecord(); boolean save = true; try { if ((resHandle != null) && !_endpointFailed) save = resHandle.saveRecord(); } catch (Exception e) { save = true; // just to be on the safe side! _endpointFailed = true; jtsLogger.i18NLogger.warn_resources_errsavefail("ExtendedResourceRecord.doSave", Boolean.toString(save)); } resHandle = null; _doSave = (save ? 1 : 0); return save; } public final Uid getRCUid () { return _recCoordUid; } public void merge (AbstractRecord absRec) { OTSAbstractRecord resHandle = otsRecord(); if (resHandle != null) { OTSAbstractRecord rec = otsRecord(absRec); if (rec != null) { try { resHandle.merge(rec); } catch (OBJECT_NOT_EXIST ex) { } catch (Exception e) { jtsLogger.i18NLogger.warn_resources_errgenerr("ExtendedResourceRecord.merge", e); } rec = null; } } resHandle = null; } public void alter (AbstractRecord absRec) { OTSAbstractRecord resHandle = otsRecord(); if (resHandle != null) { OTSAbstractRecord rec = otsRecord(absRec); if (rec != null) { try { resHandle.alter(rec); } catch (OBJECT_NOT_EXIST ex) { } catch (Exception e) { jtsLogger.i18NLogger.warn_resources_errgenerr("ExtendedResourceRecord.alter", e); } rec = null; } } resHandle = null; } public boolean shouldAdd (AbstractRecord absRec) { boolean result = false; OTSAbstractRecord resHandle = otsRecord(); if ((resHandle != null) && !_endpointFailed) { OTSAbstractRecord rec = otsRecord(absRec); if (rec != null) { try { result = resHandle.shouldAdd(rec); } catch (OBJECT_NOT_EXIST ex) { // This is expected to happen whenever a resource has gone away, for example during a crash or if it has exited the 2PC process early by returning XA_RDONLY out of prepare } catch (Exception e) { _endpointFailed = true; jtsLogger.i18NLogger.warn_resources_errgenerr("ExtendedResourceRecord.shouldAdd", e); } rec = null; } } resHandle = null; return result; } public boolean shouldAlter (AbstractRecord absRec) { boolean result = false; OTSAbstractRecord resHandle = otsRecord(); if ((resHandle != null) && !_endpointFailed) { OTSAbstractRecord rec = otsRecord(absRec); if (rec != null) { try { result = resHandle.shouldAlter(rec); } catch (OBJECT_NOT_EXIST ex) { // This is expected to happen whenever a resource has gone away, for example during a crash or if it has exited the 2PC process early by returning XA_RDONLY out of prepare } catch (Exception e) { _endpointFailed = true; jtsLogger.i18NLogger.warn_resources_errgenerr("ExtendedResourceRecord.shouldAlter", e); } rec = null; } } resHandle = null; return result; } public boolean shouldMerge (AbstractRecord absRec) { boolean result = false; OTSAbstractRecord resHandle = otsRecord(); if ((resHandle != null) && !_endpointFailed) { OTSAbstractRecord rec = otsRecord(absRec); if (rec != null) { try { result = resHandle.shouldMerge(rec); } catch (OBJECT_NOT_EXIST ex) { // This is expected to happen whenever a resource has gone away, for example during a crash or if it has exited the 2PC process early by returning XA_RDONLY out of prepare } catch (Exception e) { _endpointFailed = true; jtsLogger.i18NLogger.warn_resources_errgenerr("ExtendedResourceRecord.shouldMerge", e); } rec = null; } } resHandle = null; return result; } public boolean shouldReplace (AbstractRecord absRec) { boolean result = recoveryReplace(absRec); OTSAbstractRecord resHandle = otsRecord(); if ((resHandle != null) && !result && !_endpointFailed) { OTSAbstractRecord rec = otsRecord(absRec); if (rec != null) { try { result = resHandle.shouldReplace(rec); } catch (OBJECT_NOT_EXIST ex) { // This is expected to happen whenever a resource has gone away, for example during a crash or if it has exited the 2PC process early by returning XA_RDONLY out of prepare } catch (Exception e) { _endpointFailed = true; jtsLogger.i18NLogger.warn_resources_errgenerr("ExtendedResourceRecord.shouldReplace", e); } rec = null; } } resHandle = null; return result; } /** * Protected constructor used by crash recovery. */ public ExtendedResourceRecord () { super(); _resourceHandle = null; _stringifiedResourceHandle = null; _recCoordUid = new Uid(Uid.nullUid()); _parentCoordHandle = null; _currentTransaction = null; _propagateRecord = false; _endpointFailed = false; _restored = false; } private boolean recoveryReplace (AbstractRecord rec) { boolean replace = false; if ((rec != null) && (rec instanceof ExtendedResourceRecord)) { /* * It is no good checking type equality because at recovery time the * failed resource won't respond and the implementations of this * interface can override typeIs. */ ExtendedResourceRecord newRec = (ExtendedResourceRecord) rec; /* * Check whether the new record corresponds to the same * RecoveryCoordinator as this one. If so replace. Don't replace if * the uids are NIL_UID */ if ((_recCoordUid.notEquals(Uid.nullUid())) && (_recCoordUid.equals(newRec.getRCUid()))) { replace = true; } } return replace; } private final OTSAbstractRecord otsRecord (AbstractRecord absRec) { /* * Is the abstract record an ExtendedResourceRecord ? */ OTSAbstractRecord resHandle = null; if ((absRec != null) && (absRec instanceof ExtendedResourceRecord)) { try { ExtendedResourceRecord theRecord = (ExtendedResourceRecord) absRec; ArjunaSubtranAwareResource theResource = theRecord.resourceHandle(); resHandle = com.arjuna.ArjunaOTS.OTSAbstractRecordHelper.unchecked_narrow(theResource); theResource = null; } catch (Exception e) { jtsLogger.i18NLogger.warn_resources_errgenerr("ExtendedResourceRecord.otsRecord", e); } } return resHandle; } private final OTSAbstractRecord otsRecord () { try { if (_otsARHandle == null && _resourceHandle != null) { _otsARHandle = com.arjuna.ArjunaOTS.OTSAbstractRecordHelper.unchecked_narrow(_resourceHandle); lastRecord = RecordType.LASTRESOURCE == _otsARHandle.type_id(); } if (_otsARHandle == null) throw new BAD_PARAM(); else return _otsARHandle; } catch (Exception e) { // we are not an OTSAbstractRecord return null; } } private Coordinator _parentCoordHandle; private ArjunaSubtranAwareResource _resourceHandle; private String _stringifiedResourceHandle; private Uid _recCoordUid; private ArjunaTransactionImple _currentTransaction; private boolean _propagateRecord; private OTSAbstractRecord _otsARHandle; // cached variables private Uid _cachedUid = null; private int _cachedType = -1; private int _doSave = -1; // not saved private boolean _rolledback; private boolean _endpointFailed; private boolean _restored; }