package org.jacorb.transaction;
/*
* JacORB transaction service - a free TS for JacORB
*
* Copyright (C) 1999-2004 LogicLand group Alex Sinishin.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
import java.util.Vector;
import org.omg.CosTransactions.Control;
import org.omg.CosTransactions.ControlHelper;
import org.omg.CosTransactions.ControlOperations;
import org.omg.CosTransactions.ControlPOATie;
import org.omg.CosTransactions.Coordinator;
import org.omg.CosTransactions.CoordinatorHelper;
import org.omg.CosTransactions.CoordinatorOperations;
import org.omg.CosTransactions.CoordinatorPOATie;
import org.omg.CosTransactions.HeuristicCommit;
import org.omg.CosTransactions.HeuristicHazard;
import org.omg.CosTransactions.HeuristicMixed;
import org.omg.CosTransactions.HeuristicRollback;
import org.omg.CosTransactions.Inactive;
import org.omg.CosTransactions.NotPrepared;
import org.omg.CosTransactions.NotSubtransaction;
import org.omg.CosTransactions.PropagationContext;
import org.omg.CosTransactions.RecoveryCoordinator;
import org.omg.CosTransactions.Resource;
import org.omg.CosTransactions.Status;
import org.omg.CosTransactions.SubtransactionAwareResource;
import org.omg.CosTransactions.SubtransactionsUnavailable;
import org.omg.CosTransactions.Synchronization;
import org.omg.CosTransactions.SynchronizationUnavailable;
import org.omg.CosTransactions.Terminator;
import org.omg.CosTransactions.TerminatorHelper;
import org.omg.CosTransactions.TerminatorOperations;
import org.omg.CosTransactions.TerminatorPOATie;
import org.omg.CosTransactions.Unavailable;
import org.omg.CosTransactions.Vote;
/**
* Instances of this class represent transactions. A single instance
* is used for implementing the Coordinator, Terminator and Control
* CORBA objects.
*
* @author Nicolas Noffke
* @author Vladimir Mencl
* @version $Id: CoordinatorImpl.java,v 1.10 2008-11-14 08:55:36 nick.cross Exp $
*/
public class CoordinatorImpl
implements Sleeper, CoordinatorOperations,
ControlOperations, TerminatorOperations
{
private Terminator term_ref;
private TerminatorPOATie term_skel;
private Coordinator coord_ref;
private CoordinatorPOATie coord_skel;
private Control contr_ref;
private ControlPOATie contr_skel;
private int transaction_id;
private int hash_code;
private int status;
private String stat_semaphore;
private Vector resources;
private Vector votes;
private Vector syncs;
private org.omg.PortableServer.POA poa;
CoordinatorImpl(org.omg.PortableServer.POA _poa, int _trans_id,
int _hash_code, int time)
{
transaction_id = _trans_id;
hash_code = _hash_code;
poa = _poa;
stat_semaphore = new String("sss");
resources = new Vector();
syncs = new Vector();
votes = new Vector();
try {
coord_skel = new CoordinatorPOATie(this);
coord_ref = CoordinatorHelper.narrow(poa.servant_to_reference(coord_skel));
term_skel = new TerminatorPOATie(this);
term_ref = TerminatorHelper.narrow(poa.servant_to_reference(term_skel));
contr_skel = new ControlPOATie(this);
contr_ref = ControlHelper.narrow(poa.servant_to_reference(contr_skel));
} catch (org.omg.PortableServer.POAPackage.ServantNotActive esn){
throw new org.omg.CORBA.INTERNAL();
} catch (org.omg.PortableServer.POAPackage.WrongPolicy ew){
throw new org.omg.CORBA.INTERNAL();
}
status = Status._StatusActive;
if (time != 0){
TransactionService.get_timer().add_channel(this, time);
}
}
private void destroy(){
try {
byte[] oid = poa.reference_to_id(term_ref);
poa.deactivate_object(oid);
term_ref._release();
oid = poa.reference_to_id(coord_ref);
poa.deactivate_object(oid);
coord_ref._release();
oid = poa.reference_to_id(contr_ref);
poa.deactivate_object(oid);
contr_ref._release();
} catch (org.omg.PortableServer.POAPackage.ObjectNotActive esn){
throw new org.omg.CORBA.INTERNAL();
} catch (org.omg.PortableServer.POAPackage.WrongPolicy ew){
throw new org.omg.CORBA.INTERNAL();
} catch (org.omg.PortableServer.POAPackage.WrongAdapter ew){
throw new org.omg.CORBA.INTERNAL();
}
TransactionService.release_coordinator(hash_code);
}
private boolean move_to_state(int new_status){
synchronized(stat_semaphore){
switch(status){
case Status._StatusActive:
switch(new_status){
case Status._StatusMarkedRollback:
case Status._StatusPreparing:
case Status._StatusRollingBack:
status = new_status;
return true;
default:
return false;
}
case Status._StatusMarkedRollback:
switch(new_status){
case Status._StatusRollingBack:
status = new_status;
return true;
default:
return false;
}
case Status._StatusPrepared:
switch(new_status){
case Status._StatusCommitting:
status = new_status;
return true;
default:
return false;
}
case Status._StatusCommitted:
switch(new_status){
case Status._StatusNoTransaction:
status = new_status;
return true;
default:
return false;
}
case Status._StatusRolledBack:
switch(new_status){
case Status._StatusNoTransaction:
status = new_status;
return true;
default:
return false;
}
case Status._StatusUnknown:
throw new org.omg.CORBA.INTERNAL();
case Status._StatusNoTransaction:
throw new org.omg.CORBA.INTERNAL();
case Status._StatusPreparing:
switch(new_status){
case Status._StatusRollingBack:
case Status._StatusPrepared:
status = new_status;
return true;
default:
return false;
}
case Status._StatusCommitting:
switch(new_status){
case Status._StatusCommitted:
status = new_status;
return true;
default:
return false;
}
case Status._StatusRollingBack:
switch(new_status){
case Status._StatusRolledBack:
status = new_status;
return true;
default:
return false;
}
default:
throw new org.omg.CORBA.INTERNAL();
}
}
}
public void wakeup(){
TransactionService.get_timer().kill_channel(this);
if (move_to_state(Status._StatusRollingBack)){
rolling_to_back();
}
}
int _get_transaction_id(){
return transaction_id;
}
Control _get_control(){
return contr_ref;
}
public Status get_status(){
return Status.from_int(status);
}
public Status get_parent_status(){
throw new org.omg.CORBA.NO_IMPLEMENT();
}
public Status get_top_level_status(){
return Status.from_int(status);
}
public boolean is_same_transaction(Coordinator tc){
return (hash_code == tc.hash_transaction());
}
public boolean is_related_transaction(Coordinator tc){
throw new org.omg.CORBA.NO_IMPLEMENT();
}
public boolean is_ancestor_transaction(Coordinator tc){
throw new org.omg.CORBA.NO_IMPLEMENT();
}
public boolean is_descendant_transaction(Coordinator tc){
throw new org.omg.CORBA.NO_IMPLEMENT();
}
public boolean is_top_level_transaction(){
return true;
}
public int hash_transaction(){
return hash_code;
}
public int hash_top_level_tran(){
throw new org.omg.CORBA.NO_IMPLEMENT();
}
public RecoveryCoordinator register_resource(Resource r) throws Inactive{
synchronized(stat_semaphore){
if (status == Status._StatusMarkedRollback){
throw new org.omg.CORBA.TRANSACTION_ROLLEDBACK();
}
if (status != Status._StatusActive){
throw new Inactive();
}
resources.addElement(r);
votes.addElement(null);
}
return null;
}
public void register_synchronization(Synchronization sync)
throws Inactive, SynchronizationUnavailable{
synchronized(stat_semaphore){
if (status == Status._StatusMarkedRollback){
throw new org.omg.CORBA.TRANSACTION_ROLLEDBACK();
}
if (status != Status._StatusActive){
throw new Inactive();
}
syncs.addElement(sync);
}
}
public void register_subtran_aware(SubtransactionAwareResource r)
throws Inactive, NotSubtransaction{
throw new org.omg.CORBA.NO_IMPLEMENT();
}
public void rollback_only() throws Inactive{
if (!move_to_state(Status._StatusMarkedRollback)){
throw new Inactive();
}
}
public String get_transaction_name(){
return "Transaction_" + transaction_id;
}
public Control create_subtransaction()
throws SubtransactionsUnavailable, Inactive{
throw new org.omg.CORBA.NO_IMPLEMENT();
}
public PropagationContext get_txcontext() throws Unavailable{
throw new org.omg.CORBA.NO_IMPLEMENT();
}
public Terminator get_terminator() throws Unavailable{
if (status == Status._StatusNoTransaction){
throw new Unavailable();
}
return term_ref;
}
public Coordinator get_coordinator() throws Unavailable{
if (status == Status._StatusNoTransaction){
throw new Unavailable();
}
return coord_ref;
}
private void forget(){
resources.removeAllElements();
votes.removeAllElements();
syncs.removeAllElements();
}
public void commit(boolean report_heuristics) throws HeuristicMixed,
HeuristicHazard{
if (!move_to_state(Status._StatusPreparing)){
if (move_to_state(Status._StatusRollingBack)){
TransactionService.get_timer().kill_channel(this);
rolling_to_back();
throw new org.omg.CORBA.TRANSACTION_ROLLEDBACK();
}
throw new org.omg.CORBA.INTERNAL();
}
TransactionService.get_timer().kill_channel(this);
for (int i = 0;i < syncs.size();i++){
Synchronization sync = (Synchronization)syncs.elementAt(i);
sync.before_completion();
}
if (resources.size() == 1){
Resource r = (Resource)resources.elementAt(0);
try {
r.commit_one_phase();
} catch(org.omg.CORBA.TRANSACTION_ROLLEDBACK tr) {
// the only one resource requested a rollback
votes.setElementAt(Vote.VoteRollback,0);
rollback();
throw new org.omg.CORBA.TRANSACTION_ROLLEDBACK();
} catch(HeuristicHazard hh) {
throw new org.omg.CORBA.NO_IMPLEMENT();
}
votes.setElementAt(Vote.VoteCommit,0);
if (!move_to_state(Status._StatusPrepared)){
throw new org.omg.CORBA.INTERNAL();
}
if (!move_to_state(Status._StatusCommitting)){
throw new org.omg.CORBA.INTERNAL();
}
} else {
for (int i = 0;i < resources.size();i++){
Resource r = (Resource)resources.elementAt(i);
try {
Vote v = r.prepare();
votes.setElementAt(v, i);
if (v.value() == Vote._VoteRollback){
rollback();
throw new org.omg.CORBA.TRANSACTION_ROLLEDBACK();
}
} catch(HeuristicHazard hh) {
throw new org.omg.CORBA.NO_IMPLEMENT();
} catch(HeuristicMixed hm) {
throw new org.omg.CORBA.NO_IMPLEMENT();
}
}
if (!move_to_state(Status._StatusPrepared)){
throw new org.omg.CORBA.INTERNAL();
}
if (!move_to_state(Status._StatusCommitting)){
throw new org.omg.CORBA.INTERNAL();
}
for (int i = 0;i < resources.size();i++){
Resource r = (Resource)resources.elementAt(i);
Vote v = (Vote)votes.elementAt(i);
try {
if (v == null){
throw new org.omg.CORBA.INTERNAL();
} else {
if (v.value() == Vote._VoteCommit){
r.commit();
}
}
} catch(NotPrepared np) {
throw new org.omg.CORBA.NO_IMPLEMENT();
} catch(HeuristicRollback hr) {
throw new org.omg.CORBA.NO_IMPLEMENT();
} catch(HeuristicHazard hh) {
throw new org.omg.CORBA.NO_IMPLEMENT();
} catch(HeuristicMixed hm) {
throw new org.omg.CORBA.NO_IMPLEMENT();
}
}
}
if (!move_to_state(Status._StatusCommitted)){
throw new org.omg.CORBA.INTERNAL();
}
forget();
if (!move_to_state(Status._StatusNoTransaction)){
throw new org.omg.CORBA.INTERNAL();
}
destroy();
}
private void rolling_to_back(){
for (int i = 0;i < resources.size();i++){
Resource r = (Resource)resources.elementAt(i);
Vote v = (Vote)votes.elementAt(i);
try {
if (v == null){
r.rollback();
} else {
if (v.value() == Vote._VoteCommit){
r.rollback();
}
}
} catch(HeuristicCommit hc) {
throw new org.omg.CORBA.NO_IMPLEMENT();
} catch(HeuristicMixed hm) {
throw new org.omg.CORBA.NO_IMPLEMENT();
} catch(HeuristicHazard hh) {
throw new org.omg.CORBA.NO_IMPLEMENT();
}
}
if (!move_to_state(Status._StatusRolledBack)){
throw new org.omg.CORBA.INTERNAL();
}
forget();
if (!move_to_state(Status._StatusNoTransaction)){
throw new org.omg.CORBA.INTERNAL();
}
destroy();
}
public void rollback(){
if (!move_to_state(Status._StatusRollingBack)){
throw new org.omg.CORBA.TRANSACTION_REQUIRED();
}
TransactionService.get_timer().kill_channel(this);
rolling_to_back();
}
}