/* * 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) 1999-2001 by HP Bluestone Software, Inc. All rights Reserved. * * HP Arjuna Labs, * Newcastle upon Tyne, * Tyne and Wear, * UK. * * $Id: ActionStatusService.java 2342 2006-03-30 13:06:17Z $ */ package com.arjuna.ats.arjuna.recovery; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.nio.charset.StandardCharsets; import java.util.Vector; import com.arjuna.ats.arjuna.common.Uid; import com.arjuna.ats.arjuna.coordinator.ActionManager; import com.arjuna.ats.arjuna.coordinator.ActionStatus; import com.arjuna.ats.arjuna.coordinator.BasicAction; import com.arjuna.ats.arjuna.logging.tsLogger; import com.arjuna.ats.arjuna.objectstore.RecoveryStore; import com.arjuna.ats.arjuna.objectstore.StateStatus; import com.arjuna.ats.arjuna.objectstore.StoreManager; import com.arjuna.ats.arjuna.state.InputObjectState; import com.arjuna.ats.arjuna.utils.Utility; import com.arjuna.ats.internal.arjuna.common.UidHelper; public class ActionStatusService implements Service { /** * Get a reference to the Transaction Store. */ public ActionStatusService() { if ( _recoveryStore == null ) { _recoveryStore = StoreManager.getRecoveryStore(); } } /** * Retrieve the transaction status for the specified Uid and * if available transaction type. */ public int getTransactionStatus( String transactionType, String strUid ) { int action_status = ActionStatus.INVALID; if (strUid != null) { Uid tranUid = new Uid( strUid ); if ( transactionType == null || transactionType.equals("") ) { action_status = getTranStatus( tranUid ); } else { action_status = getActionStatus( tranUid, transactionType ); } } return action_status; } /** * Does the main work of reading in a uid and transaction type * from the recovery manager, retrieving the status of the * transaction and sending it back to the Recovery Manager. */ public void doWork( InputStream is, OutputStream os ) throws IOException { BufferedReader in = new BufferedReader ( new InputStreamReader(is, StandardCharsets.UTF_8) ); PrintWriter out = new PrintWriter ( new OutputStreamWriter(os, StandardCharsets.UTF_8) ); try { // Send the process id to the recovery module so that it // can verify that it is talking to the right process. out.println ( Utility.intToHexString( Utility.getpid() )); out.flush(); // recovery module returns either "OK" or "DEAD" String rmStatus = in.readLine(); if ( rmStatus.equals( "OK" ) ) { for (;;) { // read in a transaction type and its Uid sent by the // recovery module. String transactionType = null; String strUid = null; try { transactionType = in.readLine(); strUid = in.readLine(); } catch (IOException ex) { // recovery manager has torn down connection, so end loop } /* * check for null - in theory we get this from readLine when EOF has been reached, although in practice * since we are reading from a socket we will probably get an IOException in which case we will still * see null */ if ((transactionType == null) && (strUid == null)) return; int status = getTransactionStatus( transactionType, strUid ); String strStatus = Integer.toString( status ); out.println( strStatus ); out.flush(); tsLogger.i18NLogger.info_recovery_ActionStatusService_1(transactionType, strUid, strStatus); } } } catch ( IOException ex ) { tsLogger.i18NLogger.warn_recovery_ActionStatusService_7(); } catch ( Exception ex ) { tsLogger.i18NLogger.warn_recovery_ActionStatusService_2(ex); } } /** * Check for transaction status in the local hash table, * if does not exist, then retrieve the status from the * Object Store. */ private int getActionStatus( Uid tranUid, String transactionType ) { int action_status = ActionStatus.INVALID; try { // check in local hash table BasicAction basic_action = null; synchronized ( ActionManager.manager() ) { basic_action = (BasicAction)ActionManager.manager().get( tranUid ); } if ( basic_action != null) { action_status = basic_action.status(); } else { /* * If there is a persistent representation for this * transaction, then return that status. */ action_status = getObjectStoreStatus( tranUid, transactionType ); } } catch ( Exception ex ) { tsLogger.i18NLogger.warn_recovery_ActionStatusService_3(ex); } return action_status; } /** * Get transaction status for a transaction when the transactionType * is unknown. */ private int getTranStatus( Uid tranUid ) { int action_status = ActionStatus.INVALID; try { BasicAction basic_action = null; synchronized ( ActionManager.manager() ) { basic_action = (BasicAction)ActionManager.manager().get( tranUid ); } if ( basic_action != null) { action_status = basic_action.status(); } else { /** * Run through the object store and try and find the matching id. */ action_status = getOsStatus( tranUid ); } } catch ( Exception ex ) { tsLogger.i18NLogger.warn_recovery_ActionStatusService_3(ex); } return action_status; } /** * Obtains the status for the specified transaction Uid when * the transaction type is unknown. */ private int getOsStatus( Uid tranUid ) { int action_status = ActionStatus.INVALID; Vector matchingUidVector = new Vector(); Vector matchingUidTypeVector = new Vector(); try { InputObjectState types = new InputObjectState(); // find all types if ( _recoveryStore.allTypes(types) ) { String theTypeName = null; boolean endOfList = false; while ( !endOfList ) { // extract a type theTypeName = types.unpackString(); if ( theTypeName.compareTo("") == 0 ) { endOfList = true; } else { InputObjectState uids = new InputObjectState(); boolean endOfUids = false; if ( _recoveryStore.allObjUids( theTypeName, uids ) ) { Uid theUid = null; while ( !endOfUids ) { // extract a uid theUid = UidHelper.unpackFrom(uids); if (theUid.equals( Uid.nullUid() )) { endOfUids = true; } else if ( theUid.equals( tranUid ) ) { // add to vector matchingUidVector.addElement( tranUid ); matchingUidTypeVector.addElement( theTypeName ); tsLogger.i18NLogger.info_recovery_ActionStatusService_4(tranUid); } } } else { return action_status; // Errors contacting recovery store for the list of uids it has for a type so return INVALID state } } } } else { return action_status; // Errors contacting recovery store for the list of types it holds so return INVALID state } } catch ( Exception ex ) { tsLogger.i18NLogger.warn_recovery_ActionStatusService_5(tranUid, ex); return action_status; // Read invalid data from the objectstore so return INVALID state } int uidVectorSize = matchingUidVector.size(); int first_index = 0; if ( uidVectorSize == 0 ) { // no state means aborted because of presumed abort rules action_status = ActionStatus.ABORTED; } else if ( uidVectorSize == 1 ) { Uid uid = (Uid)matchingUidVector.get( first_index ); String typeName = (String)matchingUidTypeVector.get( first_index ); action_status = getObjectStoreStatus( uid, typeName ); } else if ( uidVectorSize > 1 ) { // find root of hierarchy Uid rootUid = (Uid)matchingUidVector.get( first_index ); String rootTypeName = (String)matchingUidTypeVector.get( first_index ); for ( int index = first_index+1; index < uidVectorSize; index++ ) { String typeName = (String)matchingUidTypeVector.get( index ); if ( typeName.length() < rootTypeName.length() ) { rootTypeName = typeName; rootUid = (Uid)matchingUidVector.get( index ); } } action_status = getObjectStoreStatus( rootUid, rootTypeName ); } return action_status; } /** * Retrieve the status of the transaction from the object store. */ private int getObjectStoreStatus( Uid tranUid, String transactionType ) { int action_status = ActionStatus.INVALID; try { int osState = _recoveryStore.currentState( tranUid, transactionType ); switch ( osState ) { case StateStatus.OS_COMMITTED : action_status = ActionStatus.COMMITTED; break; case StateStatus.OS_UNKNOWN: action_status = ActionStatus.ABORTED; // no state means aborted because of presumed abort rules break; case StateStatus.OS_UNCOMMITTED : case StateStatus.OS_HIDDEN : case StateStatus.OS_COMMITTED_HIDDEN : case StateStatus.OS_UNCOMMITTED_HIDDEN : action_status = ActionStatus.PREPARED; break; } } catch ( Exception ex ) { tsLogger.i18NLogger.warn_recovery_ActionStatusService_6(ex); } return action_status; } /** * Reference to transaction object store. */ private static RecoveryStore _recoveryStore = null; }