/**
* Copyright (C) 2000-2010 Atomikos <info@atomikos.com>
*
* This code ("Atomikos TransactionsEssentials"), by itself,
* is being distributed under the
* Apache License, Version 2.0 ("License"), a copy of which may be found at
* http://www.atomikos.com/licenses/apache-license-2.0.txt .
* You may not use this file except in compliance with the License.
*
* While the License grants certain patent license rights,
* those patent license rights only extend to the use of
* Atomikos TransactionsEssentials by itself.
*
* This code (Atomikos TransactionsEssentials) contains certain interfaces
* in package (namespace) com.atomikos.icatch
* (including com.atomikos.icatch.Participant) which, if implemented, may
* infringe one or more patents held by Atomikos.
* It should be appreciated that you may NOT implement such interfaces;
* licensing to implement these interfaces must be obtained separately from Atomikos.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*/
package com.atomikos.icatch.imp;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Stack;
import com.atomikos.icatch.HeurCommitException;
import com.atomikos.icatch.HeurMixedException;
import com.atomikos.icatch.HeurRollbackException;
import com.atomikos.icatch.HeuristicMessage;
import com.atomikos.icatch.RollbackException;
import com.atomikos.icatch.StringHeuristicMessage;
import com.atomikos.icatch.TxState;
/**
*
*
* A result object for termination messages.
*/
class TerminationResult extends Result
{
protected boolean analyzed_;
// true if all answers processed
protected Hashtable heuristicparticipants_;
// where to put heuristic problems
protected Hashtable possiblyIndoubts_;
// for hazard exceptions
/**
* Constructor.
*
* @param count
* The number of messages to process.
*/
public TerminationResult ( int count )
{
super ( count );
analyzed_ = false;
heuristicparticipants_ = new Hashtable ();
possiblyIndoubts_ = new Hashtable ();
}
/**
* Get the heuristic participants for this termination round.
*
* @return Hashtable The heuristic participants, each mapped to its
* heuristic state object representation.
* @exception IllegalStateException
* If not done yet.
*/
public Hashtable getHeuristicParticipants () throws IllegalStateException,
InterruptedException
{
analyze ();
return heuristicparticipants_;
}
/**
* To get a set of possibly indoubt participants: those with a hazard case.
*
* @return Hashtable The list of possibly indoubts.
* @exception IllegalStateException
* If comm. not done yet.
*/
public Hashtable getPossiblyIndoubts () throws IllegalStateException,
InterruptedException
{
analyze ();
return possiblyIndoubts_;
}
protected synchronized void analyze () throws IllegalStateException,
InterruptedException
{
if ( analyzed_ )
return;
boolean heurmixed = false;
// true asap heurmixed exceptions
boolean heuraborts = false;
// true asap heuraborts
boolean heurcommits = false;
// true asap heurcommits
boolean heurhazards = false;
// true asap heur hazards
boolean allOK = true;
// if still true at end -> no problems
boolean rolledback = false;
// if true at end -> 1PC and rolledback already
Stack replies = getReplies ();
Enumeration enumm = replies.elements ();
while ( enumm.hasMoreElements () ) {
Reply reply = (Reply) enumm.nextElement ();
if ( reply.hasFailed () ) {
allOK = false;
Exception err = reply.getException ();
if ( err instanceof RollbackException ) {
// happens during 1pc if tx was rolled back already
rolledback = true;
} else if ( err instanceof HeurMixedException ) {
heurmixed = true;
HeurMixedException hm = (HeurMixedException) err;
addErrorMessages ( hm.getHeuristicMessages () );
heuristicparticipants_.put ( reply.getParticipant (),
TxState.HEUR_MIXED );
} else if ( err instanceof HeurCommitException ) {
heurcommits = true;
HeurCommitException hc = (HeurCommitException) err;
addErrorMessages ( hc.getHeuristicMessages () );
heurmixed = (heurmixed || heuraborts || heurhazards);
heuristicparticipants_.put ( reply.getParticipant (),
TxState.HEUR_COMMITTED );
// System.err.println ( "TerminationResult: processing heur
// commit" );
} else if ( err instanceof HeurRollbackException ) {
// System.err.println ( "TerminationResult: heuristic rb" );
heuraborts = true;
heurmixed = (heurmixed || heurcommits || heurhazards);
HeurRollbackException hr = (HeurRollbackException) err;
addErrorMessages ( hr.getHeuristicMessages () );
heuristicparticipants_.put ( reply.getParticipant (),
TxState.HEUR_ABORTED );
} else {
// heur hazard or not; the conclusion is the same
// System.err.println ( "TerminationResult: heuristic hh" );
heurhazards = true;
heurmixed = (heurmixed || heuraborts || heurcommits);
HeuristicMessage heurmsg = new StringHeuristicMessage (
"No commit ACK from " + "participant "
+ reply.getParticipant () );
errmsgvector_.addElement ( heurmsg );
heuristicparticipants_.put ( reply.getParticipant (),
TxState.HEUR_HAZARD );
possiblyIndoubts_.put ( reply.getParticipant (),
TxState.HEUR_HAZARD );
}
} // if failed reply
else {
// if reply OK -> add messages anyway, for complete overview
// this is in case coordinator makes heur commit
// So that it can present an overview of what has been
// heuristically committed.
HeuristicMessage[] msgs = (HeuristicMessage[]) reply
.getResponse ();
if ( msgs != null )
addMessages ( msgs );
}
} // while
// System.err.println ( heuristicparticipants_.size() + " heuristic
// participants in result of size " + replies.size() );
if ( rolledback )
result_ = ROLLBACK;
else if ( heurmixed || heuraborts
&& heuristicparticipants_.size () != replies.size ()
|| heurcommits
&& heuristicparticipants_.size () != replies.size () )
result_ = HEUR_MIXED;
else if ( heurhazards ) {
// heur hazard BEFORE heur abort or commit!
// see OTS definitions: hazard ASA some unknown, but ALL KNOWN ARE
// COMMIT
// OR ALL ARE ABORT
result_ = HEUR_HAZARD;
} else if ( heuraborts ) {
result_ = HEUR_ROLLBACK;
// here, there can be no heur commits as well, since otherwise mixed
// would have fitted. Same for hazards.
} else if ( heurcommits ) {
// here, there can be no heur aborts as well, since mixed would have
// fitted.
// no hazards either, since hazards would have fitted.
result_ = HEUR_COMMIT;
// System.err.println ( "TerminationResult.analyze: result is heur
// commit" );
} else if ( allOK )
result_ = ALL_OK;
analyzed_ = true;
}
}