com.arjuna.wst11.stub.SubordinateCoordinatorCompletionParticipantStub Maven / Gradle / Ivy
package com.arjuna.wst11.stub;
import com.arjuna.wst.*;
import com.arjuna.wst.WrongStateException;
import com.arjuna.wst.SystemException;
import com.arjuna.ats.arjuna.state.OutputObjectState;
import com.arjuna.ats.arjuna.state.InputObjectState;
import com.arjuna.ats.arjuna.coordinator.ActionStatus;
import com.arjuna.mwlabs.wscf.model.sagas.arjunacore.subordinate.SubordinateBACoordinator;
import com.arjuna.wst11.*;
import com.arjuna.wst11.BAParticipantManager;
import com.arjuna.webservices11.wsba.BusinessActivityConstants;
import org.jboss.jbossts.xts.recovery.participant.ba.PersistableBAParticipant;
import org.jboss.jbossts.xts.recovery.participant.ba.XTSBARecoveryManager;
import java.io.IOException;
/**
* A coordinator completion participant registered on behalf of an interposed WS-BA coordinator in order
* to ensure that durable participants in the interposed transaction are completed, closed or cancelled
* when requested from the parent transaction.
*/
public class SubordinateCoordinatorCompletionParticipantStub
implements BusinessAgreementWithCoordinatorCompletionParticipant, PersistableParticipant, PersistableBAParticipant
{
public SubordinateCoordinatorCompletionParticipantStub(SubordinateBACoordinator coordinator)
{
this.coordinator = coordinator;
this.coordinatorId = coordinator.get_uid().stringForm();
this.recovered = false;
this.manager = null;
}
public SubordinateCoordinatorCompletionParticipantStub()
{
this.coordinator = null;
this.coordinatorId = null;
this.recovered = true;
this.manager = null;
}
/**
* set the participant manager for this stub. this cannot be supplied to the constructor because it
* refers to the engine which drives this participant and the engine can only be created once the
* participant has been created. it is needed in order to be able to send a fail upward to the
* parent coordinator during complete processing. it is not needed during close or compensate
* processing which is ok because we cannot save and restore it anyway.
*
* @param manager the manager for this participant
*/
public void setManager(BAParticipantManager manager)
{
this.manager = manager;
}
public void complete() throws WrongStateException, SystemException {
if (!recovered) {
// the coordinator will send complete to all participants and then
// also run phase one commit. the former may throw an exception.
// if the latter succeeds the tx state will be COMMITTING whereas
// if it fails it will be ABORTED.
try {
coordinator.complete();
} catch (com.arjuna.mw.wsas.exceptions.WrongStateException wse) {
throw new WrongStateException(wse.getMessage());
} catch (com.arjuna.mw.wsas.exceptions.SystemException se) {
throw new SystemException(se.getMessage());
}
// if status is COMMITTING then we return allowing the participant to be logged
// if status is ABORTED then the participant must fail avoiding any logging
if (coordinator.status() == ActionStatus.ABORTED) {
manager.fail(BusinessActivityConstants.WSBA_ELEMENT_FAIL_QNAME);
} else {
// null out the manager so we don't attempt to save it to the log
manager = null;
}
} else {
// we should never get asked to complete a recovered activity
throw new WrongStateException();
}
}
public void close() throws WrongStateException, SystemException {
if (!recovered) {
int result;
try {
result = coordinator.close();
} catch (com.arjuna.mw.wsas.exceptions.SystemException se) {
throw new SystemException(se.getMessage());
}
if (result != ActionStatus.COMMITTED) {
throw new SystemException("failed to close subordinate transaction " + coordinatorId);
}
} else {
XTSBARecoveryManager recoveryManager = null;
boolean isRecoveryScanStarted = false;
if (coordinator == null) {
// try fetching coordinator from the recovery manager
recoveryManager = XTSBARecoveryManager.getRecoveryManager();
// check whether recovery has started before we check for the presence
// of the subordinate coordinator
isRecoveryScanStarted = recoveryManager.isSubordinateCoordinatorRecoveryStarted();
coordinator = SubordinateBACoordinator.getRecoveredCoordinator(coordinatorId);
}
if (coordinator == null) {
// hmm, still null -- see if we have finished recovery scanning
if (!isRecoveryScanStarted) {
// the subtransaction may still be waiting to be resolved
// throw an exception causing the commit to be retried later
throw new SystemException();
}
// ok we have no transaction to commit so assume we already committed it and
// return without error
} else if(!coordinator.isActivated()) {
// the transaction was logged but has not yet been recovered successfully
// throw an exception causing the commit to be retried later
throw new SystemException();
} else {
int status = coordinator.status();
if (status == ActionStatus.PREPARED || status == ActionStatus.COMMITTING) {
// ok, the commit process was not previously initiated so start it now
try {
coordinator.close();
SubordinateBACoordinator.removeActiveProxy(coordinatorId);
} catch (com.arjuna.mw.wsas.exceptions.SystemException e) {
// throw an exception causing the commit to be retried later
throw new SystemException();
}
status = coordinator.status();
}
// TODO -- check if this is really necessary given the catch above?
// check that we are not still committing because of a comms timeout
if (status == ActionStatus.COMMITTING) {
// throw an exception causing the commit to be retried later
throw new SystemException();
}
}
}
}
public void cancel() throws FaultedException, WrongStateException, SystemException {
if (!recovered) {
int result = coordinator.cancel();
if (result != ActionStatus.ABORTED) {
throw new FaultedException("failed to compensate subordinate transaction " + coordinatorId);
}
} else {
XTSBARecoveryManager recoveryManager = null;
boolean isRecoveryScanStarted = false;
if (coordinator == null) {
// try fetching coordinator from the recovery manager
recoveryManager = XTSBARecoveryManager.getRecoveryManager();
// check whether recovery has started before we check for the presence
// of the subordinate coordinator
isRecoveryScanStarted = recoveryManager.isSubordinateCoordinatorRecoveryStarted();
coordinator = SubordinateBACoordinator.getRecoveredCoordinator(coordinatorId);
}
if (coordinator == null) {
// hmm, still null -- see if we have finished recovery scanning
if (!isRecoveryScanStarted) {
// the subtransaction may still be waiting to be resolved
// throw an exception causing the commit to be retried later
throw new SystemException();
}
// ok we have no transaction to commit so assume we already committed it and
// return without error
} else if(!coordinator.isActivated()) {
// the transaction was logged but has not yet been recovered successfully
// throw an exception causing the commit to be retried later
throw new SystemException();
} else {
int status = coordinator.status();
if (status == ActionStatus.PREPARED || status == ActionStatus.COMMITTING) {
// ok, the commit process was not previously initiated so start it now
coordinator.cancel();
SubordinateBACoordinator.removeActiveProxy(coordinatorId);
}
// check that we are not still committing because of a comms timeout
if (status == ActionStatus.COMMITTING) {
// throw an exception causing the commit to be retried later
throw new SystemException();
} else if (status != ActionStatus.ABORTED) {
throw new FaultedException();
}
}
}
}
public void compensate() throws FaultedException, WrongStateException, SystemException {
if (!recovered) {
int result = coordinator.cancel();
// test result and throw a SystemException if the compensate was delayed
} else {
XTSBARecoveryManager recoveryManager = null;
boolean isRecoveryScanStarted = false;
if (coordinator == null) {
// try fetching coordinator from the recovery manager
recoveryManager = XTSBARecoveryManager.getRecoveryManager();
// check whether recovery has started before we check for the presence
// of the subordinate coordinator
isRecoveryScanStarted = recoveryManager.isSubordinateCoordinatorRecoveryStarted();
coordinator = SubordinateBACoordinator.getRecoveredCoordinator(coordinatorId);
}
if (coordinator == null) {
// hmm, still null -- see if we have finished recovery scanning
if (!isRecoveryScanStarted) {
// the subtransaction may still be waiting to be resolved
// throw an exception causing the commit to be retried later
throw new SystemException();
}
// ok we have no transaction to commit so assume we already committed it and
// return without error
} else if(!coordinator.isActivated()) {
// the transaction was logged but has not yet been recovered successfully
// throw an exception causing the commit to be retried later
throw new SystemException();
} else {
int status = coordinator.status();
if (status == ActionStatus.PREPARED || status == ActionStatus.COMMITTING) {
// ok, the commit process was not previously initiated so start it now
coordinator.cancel();
SubordinateBACoordinator.removeActiveProxy(coordinatorId);
status = coordinator.status();
}
// TODO -- check if this is really necessary given the catch above?
// check that we are not still committing because of a comms timeout
if (status == ActionStatus.COMMITTING) {
// throw an exception causing the commit to be retried later
throw new SystemException();
} else if (status != ActionStatus.ABORTED) {
throw new FaultedException();
}
}
}
}
/**
* this should never get called
* @throws com.arjuna.wst.SystemException
*/
public String status() throws SystemException
{
return null;
}
/**
* this should never get called
* @throws com.arjuna.wst.SystemException
*/
public void unknown() throws SystemException
{
}
/**
* this should never get called
* @throws com.arjuna.wst.SystemException
*/
public void error() throws SystemException
{
}
/**
* Save the state of the particpant to the specified input object stream.
* @param oos The output output stream.
* @return true if persisted, false otherwise.
*/
public boolean saveState(OutputObjectState oos) {
// we need to save the id of the subordinate coordinator so we can identify it again
// when we are recreated
try {
oos.packString(coordinatorId);
return true;
} catch (IOException e) {
return false;
}
}
/**
* Restore the state of the particpant from the specified input object stream.
* @param ios The Input object stream.
* @return true if restored, false otherwise.
*/
public boolean restoreState(InputObjectState ios) {
// restore the subordinate coordinator id so we can check to ensure it has been committed
try {
coordinatorId = ios.unpackString();
SubordinateBACoordinator.addActiveProxy(coordinatorId);
return true;
} catch (IOException e) {
return false;
}
}
/*
* this participant implements the PersistableBAParticipant interface so it can save its state.
* recovery is managed by an XTS recovery module
* @return
* @throws Exception
*/
public byte[] getRecoveryState() throws Exception {
OutputObjectState oos = new OutputObjectState();
oos.packString(this.getClass().getName());
this.saveState(oos);
return oos.buffer();
}
private SubordinateBACoordinator coordinator;
private String coordinatorId;
private boolean recovered;
private BAParticipantManager manager;
}