/*
* JBoss, Home of Professional Open Source
* Copyright 2007, 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) 2007,
* @author Red Hat Middleware LLC.
*/
package org.jboss.jbossts.xts.recovery.coordinator.at;
import org.jboss.jbossts.xts.logging.XTSLogger;
import org.jboss.jbossts.xts.recovery.participant.at.XTSATRecoveryManager;
import com.arjuna.ats.arjuna.recovery.RecoveryModule;
import com.arjuna.ats.arjuna.recovery.TransactionStatusConnectionManager;
import com.arjuna.ats.arjuna.logging.FacilityCode;
import com.arjuna.ats.arjuna.coordinator.TxControl;
import com.arjuna.ats.arjuna.coordinator.ActionStatus;
import com.arjuna.ats.arjuna.state.InputObjectState;
import com.arjuna.ats.arjuna.exceptions.ObjectStoreException;
import com.arjuna.ats.arjuna.common.Uid;
import com.arjuna.ats.arjuna.objectstore.ObjectStore;
import com.arjuna.common.util.logging.DebugLevel;
import com.arjuna.common.util.logging.VisibilityLevel;
import com.arjuna.mwlabs.wscf.model.twophase.arjunacore.ACCoordinator;
import java.util.Vector;
import java.util.Enumeration;
/**
* This class is a plug-in module for the recovery manager.
* It is responsible for recovering failed XTS AT (ACCoordinator) transactions.
* (instances of com.arjuna.mwlabs.wscf.model.twophase.arjunacore.ACCoordinator)
*
* $Id$
*
* @message org.jboss.transactions.xts.recovery.coordinator.at.ACCoordinatorRecoveryModule_1 [org.jboss.transactions.xts.recovery.coordinator.at.ACCoordinatorRecoveryModule_1] - RecoveryManagerStatusModule: Object store exception: {0}
* @message org.jboss.transactions.xts.recovery.coordinator.at.ACCoordinatorRecoveryModule_2 [org.jboss.transactions.xts.recovery.coordinator.at.ACCoordinatorRecoveryModule_2] - failed to recover Transaction {0} {1}
* @message org.jboss.transactions.xts.recovery.coordinator.at.ACCoordinatorRecoveryModule_3 [org.jboss.transactions.xts.recovery.coordinator.at.ACCoordinatorRecoveryModule_3] - failed to access transaction store {0} {1}
*/
public class ACCoordinatorRecoveryModule implements RecoveryModule
{
public ACCoordinatorRecoveryModule()
{
if (XTSLogger.arjLogger.isDebugEnabled())
{
XTSLogger.arjLogger.debug
( DebugLevel.CONSTRUCTORS,
VisibilityLevel.VIS_PUBLIC,
FacilityCode.FAC_CRASH_RECOVERY,
"ACCoordinatorRecoveryModule created - default" );
}
if (_transactionStore == null)
{
_transactionStore = TxControl.getStore() ;
}
_transactionStatusConnectionMgr = new TransactionStatusConnectionManager() ;
}
/**
* called by the service startup code before the recovery module is added to the recovery managers
* module list
*/
public void install()
{
Implementations.install();
}
/**
* module list in order to allow the implementations list to be purged of this module's implementations
*/
public void uninstall()
{
Implementations.uninstall();
}
/**
* This is called periodically by the RecoveryManager
*/
public void periodicWorkFirstPass()
{
// Transaction type
boolean ACCoordinators = false ;
// uids per transaction type
InputObjectState acc_uids = new InputObjectState() ;
try
{
if (XTSLogger.arjLogger.isDebugEnabled())
{
XTSLogger.arjLogger.debug( "StatusModule: first pass " );
}
ACCoordinators = _transactionStore.allObjUids( _transactionType, acc_uids );
}
catch ( ObjectStoreException ex )
{
if (XTSLogger.arjLoggerI18N.isWarnEnabled())
{
XTSLogger.arjLoggerI18N.warn("org.jboss.transactions.xts.recovery.coordinator.at.ACCoordinatorRecoveryModule_1",
new Object[]{ex});
}
}
if ( ACCoordinators )
{
_transactionUidVector = processTransactions( acc_uids ) ;
}
}
public void periodicWorkSecondPass()
{
if (XTSLogger.arjLogger.isDebugEnabled())
{
XTSLogger.arjLogger.debug( "ACCoordinatorRecoveryModule: Second pass " );
}
if (_transactionUidVector != null) {
processTransactionsStatus() ;
}
// ok notify the coordinator processor that recovery processing has completed
}
protected ACCoordinatorRecoveryModule (String type)
{
if (XTSLogger.arjLogger.isDebugEnabled())
{
XTSLogger.arjLogger.debug
( DebugLevel.CONSTRUCTORS,
VisibilityLevel.VIS_PUBLIC,
FacilityCode.FAC_CRASH_RECOVERY,
"ACCoordinatorRecoveryModule created " + type );
}
if (_transactionStore == null)
{
_transactionStore = TxControl.getStore() ;
}
_transactionStatusConnectionMgr = new TransactionStatusConnectionManager() ;
_transactionType = type;
}
private void doRecoverTransaction( Uid recoverUid )
{
boolean commitThisTransaction = true ;
// Retrieve the transaction status from its original process.
// n.b. for a non-active XTS TX this status wil l always be committed even
// if it aborted or had a heuristic outcome. in that case we need to use
// the logged action status which can only be retrieved after activation
int theStatus = _transactionStatusConnectionMgr.getTransactionStatus( _transactionType, recoverUid ) ;
boolean inFlight = isTransactionInMidFlight( theStatus ) ;
String Status = ActionStatus.stringForm( theStatus ) ;
if (XTSLogger.arjLogger.isDebugEnabled())
{
XTSLogger.arjLogger.debug
( DebugLevel.FUNCTIONS,
VisibilityLevel.VIS_PUBLIC,
FacilityCode.FAC_CRASH_RECOVERY,
"transaction type is "+ _transactionType + " uid is " +
recoverUid.toString() + "\n ActionStatus is " + Status +
" in flight is " + inFlight ) ;
}
if ( ! inFlight )
{
try
{
XTSLogger.arjLogger.debug( DebugLevel.FUNCTIONS, VisibilityLevel.VIS_PUBLIC,
FacilityCode.FAC_CRASH_RECOVERY, "jjh doing revovery here for "+recoverUid);
// TODO jjh
RecoverACCoordinator rcvACCoordinator =
new RecoverACCoordinator(recoverUid);
// RecoverAtomicAction rcvAtomicAction =
// new RecoverAtomicAction( recoverUid, theStatus ) ;
// rcvAtomicAction.replayPhase2() ;
rcvACCoordinator.replayPhase2();
}
catch ( Exception ex )
{
if (XTSLogger.arjLoggerI18N.isWarnEnabled())
{
XTSLogger.arjLoggerI18N.warn("org.jboss.transactions.xts.recovery.coordinator.at.ACCoordinatorRecoveryModule_2",
new Object[]{recoverUid.toString(), ex});
}
}
}
}
private boolean isTransactionInMidFlight( int status )
{
boolean inFlight = false ;
switch ( status )
{
// these states can only come from a process that is still alive
case ActionStatus.RUNNING :
case ActionStatus.ABORT_ONLY :
case ActionStatus.PREPARING :
case ActionStatus.COMMITTING :
case ActionStatus.ABORTING :
case ActionStatus.PREPARED :
inFlight = true ;
break ;
// the transaction is apparently still there, but has completed its
// phase2. should be safe to redo it.
case ActionStatus.COMMITTED :
case ActionStatus.H_COMMIT :
case ActionStatus.H_MIXED :
case ActionStatus.H_HAZARD :
case ActionStatus.ABORTED :
case ActionStatus.H_ROLLBACK :
inFlight = false ;
break ;
// this shouldn't happen
case ActionStatus.INVALID :
default:
inFlight = false ;
}
return inFlight ;
}
private Vector processTransactions( InputObjectState uids )
{
Vector uidVector = new Vector() ;
if (XTSLogger.arjLogger.isDebugEnabled())
{
XTSLogger.arjLogger.debug( DebugLevel.FUNCTIONS,
VisibilityLevel.VIS_PUBLIC,
FacilityCode.FAC_CRASH_RECOVERY,
"processing " + _transactionType
+ " transactions" ) ;
}
Uid theUid = new Uid( Uid.nullUid() );
boolean moreUids = true ;
while (moreUids)
{
try
{
theUid.unpack( uids ) ;
if (theUid.equals( Uid.nullUid() ))
{
moreUids = false;
}
else
{
Uid newUid = new Uid( theUid ) ;
if (XTSLogger.arjLogger.isDebugEnabled())
{
XTSLogger.arjLogger.debug
( DebugLevel.FUNCTIONS,
VisibilityLevel.VIS_PUBLIC,
FacilityCode.FAC_CRASH_RECOVERY,
"found transaction "+ newUid ) ;
}
uidVector.addElement( newUid ) ;
}
}
catch ( Exception ex )
{
moreUids = false;
}
}
return uidVector ;
}
private void processTransactionsStatus()
{
// Process the Vector of transaction Uids
Enumeration transactionUidEnum = _transactionUidVector.elements() ;
while ( transactionUidEnum.hasMoreElements() )
{
Uid currentUid = (Uid) transactionUidEnum.nextElement();
try
{
if ( _transactionStore.currentState( currentUid, _transactionType ) != ObjectStore.OS_UNKNOWN )
{
doRecoverTransaction( currentUid ) ;
}
}
catch ( ObjectStoreException ex )
{
if (XTSLogger.arjLogger.isWarnEnabled())
{
XTSLogger.arjLoggerI18N.warn("org.jboss.transactions.xts.recovery.coordinator.at.ACCoordinatorRecoveryModule_3",
new Object[]{currentUid.toString(), ex});
}
}
}
XTSATRecoveryManager.getRecoveryManager().setCoordinatorRecoveryStarted();
}
// 'type' within the Object Store for ACCoordinator.
private String _transactionType = new ACCoordinator().type() ;
// Array of transactions found in the object store of the
// ACCoordinator type.
private Vector _transactionUidVector = null ;
// Reference to the Object Store.
private static ObjectStore _transactionStore = null ;
// This object manages the interface to all TransactionStatusManagers
// processes(JVMs) on this system/node.
private TransactionStatusConnectionManager _transactionStatusConnectionMgr ;
}