/*
* 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) 2002,
*
* Arjuna Technologies Limited,
* Newcastle upon Tyne,
* Tyne and Wear,
* UK.
*
* $Id: ParticipantRecord.java,v 1.6 2005/05/19 12:13:37 nmcl Exp $
*/
package com.arjuna.mwlabs.wscf.model.sagas.arjunacore;
import com.arjuna.mw.wscf.logging.wscfLogger;
import com.arjuna.ats.arjuna.ObjectType;
import com.arjuna.ats.arjuna.coordinator.*;
import com.arjuna.ats.arjuna.common.*;
import com.arjuna.ats.arjuna.state.*;
import com.arjuna.mw.wscf.model.sagas.participants.Participant;
import com.arjuna.mw.wscf.model.sagas.participants.ParticipantWithComplete;
import com.arjuna.mw.wscf.model.sagas.exceptions.CompensateFailedException;
import com.arjuna.mw.wscf.model.sagas.exceptions.CancelFailedException;
import com.arjuna.mw.wsas.exceptions.*;
import com.arjuna.mw.wscf.exceptions.*;
import com.arjuna.webservices.util.ClassLoaderHelper;
import java.io.PrintWriter;
/**
* Arjuna abstract record to handle two-phase participants.
*
* @author Mark Little (mark.little@arjuna.com)
* @version $Id: ParticipantRecord.java,v 1.6 2005/05/19 12:13:37 nmcl Exp $
*/
public class ParticipantRecord extends
com.arjuna.ats.arjuna.coordinator.AbstractRecord
{
/**
* Constructor.
*
* @param theResource
* is the proxy that allows us to call out to the object.
*
*/
public ParticipantRecord (Participant theResource, Uid id)
{
super(id, null, ObjectType.ANDPERSISTENT);
_resourceHandle = theResource;
_timeout = 0;
_coordId = new CoordinatorIdImple(id);
if (theResource == null)
wscfLogger.i18NLogger.warn_model_sagas_coordinator_arjunacore_ParticipantRecord_1(order());
}
/**
* Override AbstractRecord.propagateOnCommit
*/
public boolean propagateOnCommit ()
{
return true;
}
/**
* The type of this abstract record.
*/
public int typeIs ()
{
// TODO add to record list
return RecordType.XTS_WSBA_RECORD;
}
/**
* The internal value.
*/
public Object value ()
{
return _resourceHandle;
}
/**
* Set the internal value. Not allowed for this class.
*
*/
public void setValue (Object o)
{
wscfLogger.i18NLogger.warn_model_sagas_coordinator_arjunacore_ParticipantRecord_2();
}
/**
* The record is being driven through nested rollback.
*
*/
// TODO
public int nestedAbort ()
{
try
{
if (_resourceHandle != null)
{
return TwoPhaseOutcome.FINISH_ERROR;
}
else
return TwoPhaseOutcome.FINISH_ERROR;
}
catch (Exception ex6) {
wscfLogger.i18NLogger.warn_model_sagas_coordinator_arjunacore_ParticipantRecord_3(order(), ex6);
ex6.printStackTrace();
return TwoPhaseOutcome.FINISH_ERROR;
}
}
/**
* The record is being driven through nested commit.
*
*/
public int nestedCommit ()
{
try
{
if (_resourceHandle != null)
{
return TwoPhaseOutcome.FINISH_ERROR;
}
else
return TwoPhaseOutcome.FINISH_ERROR;
}
catch (Exception ex6) {
wscfLogger.i18NLogger.warn_model_sagas_coordinator_arjunacore_ParticipantRecord_4(order(), ex6);
ex6.printStackTrace();
return TwoPhaseOutcome.FINISH_ERROR;
}
}
/**
* The record is being driven through nested prepare.
*
*/
public int nestedPrepare ()
{
try
{
if (_resourceHandle != null)
{
return TwoPhaseOutcome.FINISH_ERROR;
}
else
return TwoPhaseOutcome.PREPARE_NOTOK;
}
catch (Exception e6) {
wscfLogger.i18NLogger.warn_model_sagas_coordinator_arjunacore_ParticipantRecord_5(order(), e6);
e6.printStackTrace();
return TwoPhaseOutcome.HEURISTIC_HAZARD;
}
}
/**
* The record is being driven through top-level rollback.
*
*/
public int topLevelAbort ()
{
try
{
if (_resourceHandle != null)
{
try
{
if (!_exited)
{
if (_completed) _resourceHandle.compensate();
else
_resourceHandle.cancel();
}
}
catch (InvalidParticipantException ex)
{
return TwoPhaseOutcome.FINISH_ERROR;
}
catch (WrongStateException ex)
{
// this indicates a fail occured and was detected during cancel (or compensation?) so we return a
// HEURISTIC_HAZARD which will place the participant in the heuristic list
return TwoPhaseOutcome.HEURISTIC_HAZARD;
}
catch (CancelFailedException ex)
{
// this indicates a fail occured and was detected during cancel so we return a HEURISTIC_HAZARD
// which will place the participant in the heuristic list
return TwoPhaseOutcome.HEURISTIC_HAZARD;
}
catch (CompensateFailedException ex)
{
// this indicates a fail occured during compensation so we return a HEURISTIC_HAZARD
// which will place the participant in the heuristic list
return TwoPhaseOutcome.HEURISTIC_HAZARD;
}
catch (SystemException ex)
{
// this indicates a comms failure so we return FINISH_ERROR which will place
// the participant in the failed list and cause a retry of the close
return TwoPhaseOutcome.FINISH_ERROR;
}
// we are not guaranteed to detect all state transitions so we still have to
// make sure we did not fail and then end while we were trying to cancel or
// compensate
if (_failed) {
return TwoPhaseOutcome.HEURISTIC_HAZARD;
}
return TwoPhaseOutcome.FINISH_OK;
}
else
return TwoPhaseOutcome.FINISH_ERROR;
}
catch (Exception ex6) {
wscfLogger.i18NLogger.warn_model_sagas_coordinator_arjunacore_ParticipantRecord_6(order(), ex6);
ex6.printStackTrace();
return TwoPhaseOutcome.FINISH_ERROR;
}
}
/**
* The record is being driven through top-level commit.
*
*/
public int topLevelCommit ()
{
try
{
if (_resourceHandle != null)
{
try
{
if (!_exited) _resourceHandle.close();
}
catch (InvalidParticipantException ex)
{
return TwoPhaseOutcome.FINISH_ERROR;
}
catch (WrongStateException ex)
{
// this indicates a failure to close so we notify a heuristic hazard
return TwoPhaseOutcome.HEURISTIC_HAZARD;
}
catch (SystemException ex)
{
// this indicates a comms failure so we return FINISH_ERROR which will place
// the participant in the failed list and cause a retry of the close
return TwoPhaseOutcome.FINISH_ERROR;
}
// if we have failed we notify a heuristic hazard to ensure that the
// participant is placed in the heuristic list and the transaction is logged
if (_failed) {
return TwoPhaseOutcome.HEURISTIC_HAZARD;
}
return TwoPhaseOutcome.FINISH_OK;
}
else
return TwoPhaseOutcome.FINISH_ERROR;
}
catch (Exception ex6) {
wscfLogger.i18NLogger.warn_model_sagas_coordinator_arjunacore_ParticipantRecord_7(order(), ex6);
ex6.printStackTrace();
return TwoPhaseOutcome.FINISH_ERROR;
}
}
/**
* The record is being driven through top-level prepare.
*
*/
public int topLevelPrepare ()
{
try
{
boolean result;
if (_failed) {
// if we have failed we return heuristic hazard so the participant is added to
// the heuristic list and the transaction is logged
return TwoPhaseOutcome.HEURISTIC_HAZARD;
} else if (_exited) {
// otherwise if we have exited then this means the resource is read only
return TwoPhaseOutcome.PREPARE_READONLY;
} else {
// otherwise we only need to have completed for the prepare to be ok -- if we have
// not completed then the prepare is not ok
return (_completed ? TwoPhaseOutcome.PREPARE_OK: TwoPhaseOutcome.PREPARE_NOTOK);
}
}
catch (Exception e6) {
wscfLogger.i18NLogger.warn_model_sagas_coordinator_arjunacore_ParticipantRecord_8(order(), e6);
e6.printStackTrace();
return TwoPhaseOutcome.PREPARE_OK;
}
}
/**
* The record is being driven through nested commit and is the only
* resource.
*
*/
public int nestedOnePhaseCommit ()
{
try
{
if (_resourceHandle != null)
{
return TwoPhaseOutcome.FINISH_ERROR;
}
else
return TwoPhaseOutcome.FINISH_ERROR;
}
catch (Exception ex6) {
wscfLogger.i18NLogger.warn_model_sagas_coordinator_arjunacore_ParticipantRecord_9(order(), ex6);
ex6.printStackTrace();
return TwoPhaseOutcome.FINISH_ERROR;
}
}
/**
* The record is being driven through top-level commit and is the only
* resource.
*
*/
public int topLevelOnePhaseCommit ()
{
try
{
if (_resourceHandle != null)
{
// we cannot proceed if the participant has neither completed not exited
if (isActive()) return TwoPhaseOutcome.ONE_PHASE_ERROR;
try
{
if (!_exited) _resourceHandle.close();
}
catch (InvalidParticipantException ex)
{
return TwoPhaseOutcome.ONE_PHASE_ERROR;
}
catch (WrongStateException ex)
{
// this indicates a failure to close so we notify a heuristic hazard
return TwoPhaseOutcome.HEURISTIC_HAZARD;
}
catch (SystemException ex)
{
// this indicates a comms failure so we return FINISH_ERROR which will place
// the participant in the failed list and cause a retry of the close
return TwoPhaseOutcome.FINISH_ERROR;
}
// if we have failed we notify a heuristic hazard to ensure that the
// participant is placed in the heuristic list and the transaction is logged
if (_failed) {
return TwoPhaseOutcome.HEURISTIC_HAZARD;
}
// if we closed or we exited then all is ok
return TwoPhaseOutcome.FINISH_OK;
}
else
return TwoPhaseOutcome.ONE_PHASE_ERROR;
}
catch (Exception ex6) {
wscfLogger.i18NLogger.warn_model_sagas_coordinator_arjunacore_ParticipantRecord_10(order(), ex6);
ex6.printStackTrace();
return TwoPhaseOutcome.FINISH_ERROR;
}
}
/**
* The record generated a heuristic and can now forget about it.
*
*/
public boolean forgetHeuristic ()
{
try
{
if (_resourceHandle != null)
{
try
{
if (!_exited) _resourceHandle.forget();
}
catch (InvalidParticipantException ex)
{
return false;
}
catch (WrongStateException ex)
{
return false;
}
catch (SystemException ex)
{
return false;
}
return true;
}
else {
wscfLogger.i18NLogger.warn_model_sagas_coordinator_arjunacore_ParticipantRecord_11(order());
}
}
catch (Exception e) {
wscfLogger.i18NLogger.warn_model_sagas_coordinator_arjunacore_ParticipantRecord_12(order(), e);
e.printStackTrace();
}
return false;
}
public boolean complete ()
{
boolean result = false;
try
{
if (_resourceHandle != null)
{
try
{
if (isActive())
{
if (_resourceHandle instanceof ParticipantWithComplete)
{
((ParticipantWithComplete) _resourceHandle)
.complete();
completed();
}
result = true;
}
else
{
// already completed, so this is a null op. just rtn
// true.
result = true;
}
}
catch (InvalidParticipantException ex)
{
}
catch (WrongStateException ex)
{
}
catch (SystemException ex)
{
}
}
}
catch (Exception ex6) {
wscfLogger.i18NLogger.warn_model_sagas_coordinator_arjunacore_ParticipantRecord_13(order(), ex6);
ex6.printStackTrace();
}
return result;
}
public static AbstractRecord create ()
{
return new ParticipantRecord();
}
public void print (PrintWriter strm)
{
super.print(strm);
strm.print("ParticipantRecord");
strm.print(_resourceHandle);
}
public boolean restore_state (InputObjectState os, int t)
{
boolean result = super.restore_state(os, t);
if (result)
{
try
{
String resourcehandleImplClassName = os.unpackString();
Class clazz = ClassLoaderHelper.forName(ParticipantRecord.class, resourcehandleImplClassName);
_resourceHandle = (Participant)clazz.newInstance();
result = _resourceHandle.restore_state(os);
if (result) {
_timeout = os.unpackLong();
_completed = os.unpackBoolean();
_exited = os.unpackBoolean();
if (_exited) {
_failed = os.unpackBoolean();
}
}
}
catch (Exception ex) {
wscfLogger.i18NLogger.warn_model_sagas_coordinator_arjunacore_ParticipantRecord_14(ex);
result = false;
}
}
return result;
}
public boolean save_state (OutputObjectState os, int t)
{
boolean result = super.save_state(os, t);
if (result)
{
try
{
os.packString(_resourceHandle.getClass().getName()); // TODO: a shorter value whould be more efficient.
result = _resourceHandle.save_state(os);
if (result) {
os.packLong(_timeout);
os.packBoolean(_completed);
os.packBoolean(_exited);
if (_exited) {
os.packBoolean(_failed);
}
}
/*
* TODO: pack qualifiers and coord id.
*/
}
catch (Exception ex) {
wscfLogger.i18NLogger.warn_model_sagas_coordinator_arjunacore_ParticipantRecord_15(ex);
result = false;
}
}
return result;
}
public String type ()
{
return "/StateManager/AbstractRecord/WSCF/ArjunaCore/ParticipantRecord";
}
public boolean doSave ()
{
/*
* If the participant has exited without failure, then we don't need to save anything
* about it in the transaction log. If it has not exited or it has exited with failure
* we do need to log it
*/
return (!_exited || _failed);
}
public void merge (AbstractRecord a)
{
}
public void alter (AbstractRecord a)
{
}
public boolean shouldAdd (AbstractRecord a)
{
return false;
}
public boolean shouldAlter (AbstractRecord a)
{
return false;
}
public boolean shouldMerge (AbstractRecord a)
{
return false;
}
public boolean shouldReplace (AbstractRecord rec)
{
return false;
}
/**
* record the fact that this participant has exited
*
* @param failed true if the exit was because of a failure i.e. the participant may be in an unclean state
*/
public final void delist (boolean failed)
{
_exited = true;
_failed = failed;
}
/**
* record the fact that this participant has completed
*/
public final synchronized void completed ()
{
_completed = true;
}
/**
* is the participant is still able to be sent a complete request
*
* @caveat it is only appropriate to call this if this is a CoordinatorCompletion participant
* @return true if the participant is still able to be sent a complete request otherwise false
*/
public final synchronized boolean isActive ()
{
return !_completed && !_exited;
}
/**
* is this a ParticipantCompletion participant
* @return true if this is a ParticipantCompletion participant otherwise false
*/
public final boolean isParticipantCompletion ()
{
// n.b. this is ok if _resourceHandle is null
return !(_resourceHandle instanceof ParticipantWithComplete);
}
/*
* Protected constructor used by crash recovery.
*/
public ParticipantRecord ()
{
super();
_resourceHandle = null;
_timeout = 0;
_coordId = null;
}
private Participant _resourceHandle;
private long _timeout;
private CoordinatorIdImple _coordId;
private boolean _exited = false;
private boolean _failed = false;
private boolean _completed = false;
}