package org.jboss.jbossts.xts.recovery.participant.at; import com.arjuna.wst.PersistableParticipant; import com.arjuna.wst.Durable2PCParticipant; import com.arjuna.ats.arjuna.state.OutputObjectState; import com.arjuna.ats.arjuna.state.InputObjectState; import com.arjuna.webservices.logging.WSTLogger; import javax.xml.stream.XMLStreamException; import java.io.*; /** * asbstract class used to implement save, recover and reactivate API for durable * XTS participants. this is subclassed by both a 1.0 and a 1.1 specific class because * the activate operation needs to create a participant engine appropriate to the * protocol in use when the participant was saved. */ public abstract class ATParticipantRecoveryRecord implements PersistableParticipant { /** * construct the protocol-independent part of a WS-AT participant recovery record * @param id * @param participant */ protected ATParticipantRecoveryRecord(String id, Durable2PCParticipant participant) { this.id = id; this.participant = participant; recoveryState = null; recoveryStateValid = false; } /** * Retrieve and 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 final boolean saveState(OutputObjectState oos) { if (participant == null) { return false; } try { useSerialization = ATParticipantHelper.isSerializable(participant); recoveryState = ATParticipantHelper.getRecoveryState(useSerialization, participant); recoveryStateValid = true; } catch (Exception exception) { WSTLogger.i18NLogger.warn_recovery_participant_at_ATParticipantRecoveryRecord_saveState_1(id); // if we continue here then we cannot recover this transaction if we crash during // commit processing. we should strictly fail here to play safe but . . . recoveryStateValid = false; } try { oos.packString(id); saveEndpointReference(oos); oos.packBoolean(recoveryStateValid); if (recoveryStateValid) { oos.packBoolean(useSerialization); if (recoveryState != null) { oos.packBoolean(true); oos.packBytes(recoveryState); } else { oos.packBoolean(false); } } } catch (XMLStreamException xmle) { WSTLogger.i18NLogger.warn_recovery_participant_at_ATParticipantRecoveryRecord_saveState_2(id, xmle); return false; } catch (IOException ioe) { WSTLogger.i18NLogger.warn_recovery_participant_at_ATParticipantRecoveryRecord_saveState_3(id, ioe); return false; } return true; } /** * 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) { try { id = ios.unpackString(); restoreEndpointReference(ios); recoveryStateValid = ios.unpackBoolean(); if (recoveryStateValid) { useSerialization = ios.unpackBoolean(); if (ios.unpackBoolean()) { recoveryState = ios.unpackBytes(); } else { recoveryState = null; } } } catch (XMLStreamException xmle) { WSTLogger.i18NLogger.warn_recovery_participant_at_ATParticipantRecoveryRecord_restoreState_1(id, xmle); return false; } catch (IOException ioe) { WSTLogger.i18NLogger.warn_recovery_participant_at_ATParticipantRecoveryRecord_restoreState_2(id, ioe); return false; } return true; } /** * called during recovery processing to attempt to convert the restored application- * specific recovery state back into a participant * @param module the XTS recovery module to be used to attempt the conversion * @return whether the record could be restored using the XTSATRecoveryModule */ public boolean restoreParticipant(XTSATRecoveryModule module) throws Exception { if (participant != null) { // don't think this should ever happen return false; } if (recoveryStateValid) { if (useSerialization) { final ByteArrayInputStream bais = new ByteArrayInputStream(recoveryState) ; final ObjectInputStream ois = new ObjectInputStream(bais) ; participant = module.deserialize(getId(), ois); } else { participant = module.recreate(getId(), recoveryState); } if (participant != null) { return true; } } else { // the original participant did not provide a way to save its state so // throw an exception to notify this String mesg = WSTLogger.i18NLogger.get_recovery_participant_at_ATParticipantRecoveryRecord_restoreParticipant_1(id); throw new Exception(mesg); } return false; } public String getId() { return id; } /** * @return the path string under which AT participant records are to be located in the TX * object store */ public static String type () { return type; } /** * save the endpoint reference to the coordinator for this participant */ protected abstract void saveEndpointReference(OutputObjectState oos) throws IOException, XMLStreamException; /** * restore the endpoint reference to the coordinator for this participant */ protected abstract void restoreEndpointReference(InputObjectState ios) throws IOException, XMLStreamException; /** * create a participant engine to manage commit or rollback processing for the * participant and install it in the active participants table */ public abstract void activate(); /** * test whether a participant is currently activated with the id of this recovery record. * * @return true if a participant is currently activated with the id of this recovery record */ public abstract boolean isActive(); protected Durable2PCParticipant participant; protected String id; private boolean useSerialization; private byte[] recoveryState; private boolean recoveryStateValid; final private static String type = "/XTS/WSAT/ParticipantRecoveryRecord"; }