Package com.arjuna.ats.internal.jts.orbspecific.interposition.coordinator

Source Code of com.arjuna.ats.internal.jts.orbspecific.interposition.coordinator.ServerTransaction

/*
* 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) 2001, 2002,
*
* Hewlett-Packard Arjuna Labs,
* Newcastle upon Tyne,
* Tyne and Wear,
* UK. 
*
* $Id: ServerTransaction.java 2342 2006-03-30 13:06:17Z  $
*/

package com.arjuna.ats.internal.jts.orbspecific.interposition.coordinator;

import com.arjuna.ats.internal.jts.orbspecific.interposition.ServerControl;
import com.arjuna.ats.internal.jts.orbspecific.coordinator.ArjunaTransactionImple;
import com.arjuna.ats.internal.jts.orbspecific.interposition.resources.ServerSynchronization;
import com.arjuna.ats.internal.jts.ORBManager;

import com.arjuna.ats.jts.exceptions.ExceptionCodes;
import com.arjuna.ats.jts.common.jtsPropertyManager;
import com.arjuna.ats.jts.utils.Utility;
import com.arjuna.ats.jts.logging.*;

import com.arjuna.common.util.logging.*;

import com.arjuna.ats.arjuna.common.*;
import com.arjuna.ats.arjuna.coordinator.*;
import com.arjuna.ats.arjuna.state.*;

import org.omg.CosTransactions.*;
import org.omg.CORBA.CompletionStatus;

import org.omg.CORBA.SystemException;
import org.omg.CORBA.BAD_OPERATION;
import org.omg.CORBA.INVALID_TRANSACTION;
import org.omg.CORBA.TRANSACTION_ROLLEDBACK;
import java.io.IOException;

/**
* This looks like an Transaction, but is only created for interposition
* purposes. The classes ServerTopLevelAction and ServerNestedAction use
* instances of this class to drive the server-side protocol.
*
* @author Mark Little (mark@arjuna.com)
* @version $Id: ServerTransaction.java 2342 2006-03-30 13:06:17Z  $
* @since JTS 1.0.
*
* @message com.arjuna.ats.internal.jts.orbspecific.interposition.coordinator.generror
*          {0} caught exception: {1}
*/

/*
* This class shouldn't need to be synchronized much since any given instance
* should be assigned to at most one resource.
*/

public class ServerTransaction extends ArjunaTransactionImple
{

  public ServerTransaction (Uid actUid, Control myParent)
  {
    this(actUid, myParent, null);
  }

  public ServerTransaction (Uid actUid, Control myParent, ArjunaTransactionImple parentImpl)
  {
    super(actUid, myParent, parentImpl);

    if (jtsLogger.logger.isDebugEnabled())
    {
      jtsLogger.logger.debug(DebugLevel.CONSTRUCTORS, VisibilityLevel.VIS_PUBLIC, com.arjuna.ats.jts.logging.FacilityCode.FAC_OTS, "ServerTransaction::ServerTransaction ( "
          + actUid
          + ", Control myParent, "
          + ((parentImpl != null) ? parentImpl.get_uid()
              : Uid.nullUid()) + " )");
    }

    _savingUid = new Uid();
    _sync = null;
    _beforeCompleted = false;
    _recoveryCoordinator = null;
    _prepState = ActionStatus.COMMITTING;
  }

  public void finalize ()
  {
    if (jtsLogger.logger.isDebugEnabled())
    {
      jtsLogger.logger.debug(DebugLevel.DESTRUCTORS, VisibilityLevel.VIS_PUBLIC, com.arjuna.ats.jts.logging.FacilityCode.FAC_OTS, "ServerTransaction.finalize ( "
          + get_uid() + " )");
    }

    _savingUid = null;

    if (_sync != null)
    {
      _sync.destroy();
      _sync = null;
    }

    /*
     * Remember to destroy the recovery coordinator.
     */

    _recoveryCoordinator = null;

    super.finalize();
  }

  public String type ()
  {
    return typeName();
  }

  public Uid getSavingUid ()
  {
    return _savingUid;
  }

  /**
   * @message com.arjuna.ats.internal.jts.orbspecific.interposition.coordinator.syncerror
   *          {0} - synchronizations have not been called!
   */

  public final int doPrepare ()
  {
    if (jtsLogger.logger.isDebugEnabled())
    {
      jtsLogger.logger.debug(DebugLevel.FUNCTIONS, VisibilityLevel.VIS_PUBLIC, com.arjuna.ats.jts.logging.FacilityCode.FAC_OTS, "ServerTransaction::doPrepare ( "
          + get_uid() + " )");
    }

    /*
     * If transaction has already been prepared then return error status.
     */

    org.omg.CosTransactions.Status s = get_status();

    if ((s != org.omg.CosTransactions.Status.StatusActive) &&
        (s != org.omg.CosTransactions.Status.StatusMarkedRollback))
    {
      return TwoPhaseOutcome.INVALID_TRANSACTION;
    }

    _prepState = ActionStatus.PREPARED;

    /*
     * If we do not have an interposed synchronization then
     * before_completions will not have been called yet. So, do it now.
     */

    if (!_interposedSynch)
    {
        if ((s != org.omg.CosTransactions.Status.StatusMarkedRollback) || TxControl.isBeforeCompletionWhenRollbackOnly())
        {
      try
      {
        doBeforeCompletion();
      }
      catch (Exception e)
      {
        /*
         * Transaction will have been put into a state which forces it
         * to rollback, so do nothing here.
         */
      }     
        }
    }

    if (!_beforeCompleted && (_sync != null))
    {
        /*
         * Synchronizations should have been called by now if we have them!
         */

        if (jtsLogger.loggerI18N.isWarnEnabled())
        {
            jtsLogger.loggerI18N.warn("com.arjuna.ats.internal.jts.orbspecific.interposition.coordinator.sycerror", new Object[]
                                                                                                                               { "ServerTransaction.doPrepare" });
        }

        /*
         * Prevent commit!
         */

        super.preventCommit();
    }
               
    int res = super.prepare(true);

    /*
     * If read-only, the coordinator will not talk to us again, so do commit
     * now and destroy the transaction.
     *
     * Otherwise, the transaction is destroyed when the commit/abort/forget
     * protocol completes.
     */

    if (res == TwoPhaseOutcome.PREPARE_READONLY)
    {
      doPhase2Commit();
    }

    return res;
  }

  public final void doForget ()
  {
    super.destroyAction();
  }

  /**
   * @message com.arjuna.ats.internal.jts.orbspecific.interposition.coordinator.txnotprepared
   *          {0} - transaction not in prepared state: {1}
   */

  public final int doPhase2Commit ()
  {
    if (jtsLogger.logger.isDebugEnabled())
    {
      jtsLogger.logger.debug(DebugLevel.FUNCTIONS, VisibilityLevel.VIS_PUBLIC, com.arjuna.ats.jts.logging.FacilityCode.FAC_OTS, "ServerTransaction::doPhase2Commit ( "
          + get_uid() + " )");
    }

    /*
     * If the transaction has already terminated, then return the status.
     */

    org.omg.CosTransactions.Status s = get_status();

    if (s != org.omg.CosTransactions.Status.StatusPrepared)
    {
      if (jtsLogger.loggerI18N.isWarnEnabled())
      {
        jtsLogger.loggerI18N.warn("com.arjuna.ats.internal.jts.orbspecific.interposition.coordinator.txnotprepared", new Object[]
        { "ServerTransaction.doPhase2Commit", Utility.stringStatus(s) });
      }

      return finalStatus();
    }

    super.phase2Commit(true);

    /*
     * Now do after completion stuff.
     */

    try
    {
      doAfterCompletion(get_status());
    }
    catch (Exception e)
    {
    }

    if (parentTransaction != null)
      parentTransaction.removeChildAction(this);

    super.destroyAction();

    ActionManager.manager().remove(get_uid());

    return finalStatus();
  }

  public final int doPhase2Abort ()
  {
    if (jtsLogger.logger.isDebugEnabled())
    {
      jtsLogger.logger.debug(DebugLevel.FUNCTIONS, VisibilityLevel.VIS_PUBLIC, com.arjuna.ats.jts.logging.FacilityCode.FAC_OTS, "ServerTransaction::doPhase2Abort ( "
          + get_uid() + " )");
    }

    /*
     * If the transaction has already terminated, then return the status. If
     * there hasn't been a heuristic outcome then we try to massage the result
     * to be consistent with what the caller expects: the fact that the
     * transaction is marked as committed during prepare without any problems means
     * that the intentions lists are zero so it's fine to say that it aborted instead.
     */

    org.omg.CosTransactions.Status s = get_status();

    if ((s == org.omg.CosTransactions.Status.StatusCommitted)
        || (s == org.omg.CosTransactions.Status.StatusRolledBack))
    {
        int status = finalStatus();
       
        switch (status)
        {
        case ActionStatus.COMMITTED:
        case ActionStatus.COMMITTING:
        case ActionStatus.ABORTED:
        case ActionStatus.ABORTING:
            return ActionStatus.ABORTED;
        default:
            return status;
        }
    }

    super.phase2Abort(true);
   
    /*
     * Now do after completion stuff.
     */

    try
    {
      doAfterCompletion(get_status());
    }
    catch (Exception e)
    {
    }

    if (parentTransaction != null)
    {
      parentTransaction.removeChildAction(this);
    }

    super.destroyAction();

    ActionManager.manager().remove(get_uid());

    return finalStatus();
  }

  /*
   * Called for one-phase commit.
   */

  public void doCommit (boolean report_heuristics) throws HeuristicHazard,
      SystemException
  {
    int outcome = super.status();

    if ((outcome == ActionStatus.RUNNING)
        || (outcome == ActionStatus.ABORT_ONLY)) // have we already been
                             // committed?
    {
      if (!_interposedSynch)
      {
          if ((outcome != ActionStatus.ABORT_ONLY) || TxControl.isBeforeCompletionWhenRollbackOnly())
          {
        try
        {
          doBeforeCompletion();
        }
        catch (Exception e)
        {
          /*
           * Transaction will have been put into a state which forces
           * it to rollback, so do nothing here.
           */
        }     
          }
      }

      outcome = super.End(report_heuristics);
    }
    else
    {
      /*
       * Differentiate between us committing the transaction and some
       * other thread doing it.
       */

      if (parentTransaction != null)
        parentTransaction.removeChildAction(this);

      throw new INVALID_TRANSACTION(ExceptionCodes.INVALID_ACTION,
          CompletionStatus.COMPLETED_NO);
    }

    /*
     * Now do after completion stuff.
     */

    try
    {
      doAfterCompletion(get_status());
    }
    catch (Exception e)
    {
    }

    if (parentTransaction != null)
      parentTransaction.removeChildAction(this);

    super.destroyAction();

    switch (outcome)
    {
    case ActionStatus.COMMITTED:
    case ActionStatus.H_COMMIT:
    case ActionStatus.COMMITTING: // in case asynchronous commit!
      return;
    case ActionStatus.ABORTED:
    case ActionStatus.H_ROLLBACK:
      throw new TRANSACTION_ROLLEDBACK(ExceptionCodes.FAILED_TO_COMMIT,
          CompletionStatus.COMPLETED_NO);
    case ActionStatus.H_HAZARD:
    default:
      throw new HeuristicHazard();
    }
  }

  public void rollback () throws SystemException
  {
    super.rollback();
  }

  /**
   * Registering a synchronization with interposition is a bit complicated!
   * Synchronizations must be called prior to prepare; if no
   * interposed-synchronization is used then either synchronizations would be
   * registered locally (and then ignored by the commit protocol) or they
   * would need to be registered remotely, which would mean a cross-address
   * space call for each synchronization!
   *
   * The first time a synchronization is registered locally, we register a
   * proxy back with the real coordinator. When that transaction commits, it
   * will call this proxy, which will then drive the locally registered
   * synchronizations (actually it calls appropriate on the transaction to do
   * this.)
   *
   * However, one-phase commit complicates matters even more since we call
   * commit on the interposed coordinator, which runs through the commit and
   * then the after_completion code before returning to the real coordinator's
   * commit call. Rather than separate commit and synchronization code
   * completely from the transaction (in which case we could just call the
   * commit portion here) we let after_completion get called before returning
   * the commit response, and simply ignore the real coordinator's subsequent
   * call to after_completion.
   */

  public synchronized void register_synchronization (Synchronization theSync)
      throws Inactive, SynchronizationUnavailable, SystemException
  {
    if (!is_top_level_transaction()) // are we a top-level transaction?
    {
      throw new SynchronizationUnavailable();
    }
    else
    {
      /*
       * If we support interposed synchronizations then add one now,
       * otherwise just add all synchronizations locally.
       */

      if (_interposedSynch)
      {
        if (_sync == null)
        {
          _sync = new ServerSynchronization(this);

          Coordinator realCoord = null;

          /*
           * First register interposed-synchronization.
           */

          try
          {
            ServerControl control = (ServerControl) super.controlHandle;

            if (controlHandle != null)
            {
              realCoord = control.originalCoordinator();

              if (realCoord != null)
              {
                realCoord.register_synchronization(_sync.getSynchronization());
              }
              else
                throw new BAD_OPERATION(
                    ExceptionCodes.NO_TRANSACTION,
                    CompletionStatus.COMPLETED_NO);
            }
            else
              throw new BAD_OPERATION(
                  ExceptionCodes.NO_TRANSACTION,
                  CompletionStatus.COMPLETED_NO);
          }
          catch (Inactive e1)
          {
            realCoord = null;

            throw e1;
          }
          catch (SynchronizationUnavailable e2)
          {
            realCoord = null;

            throw e2;
          }
          catch (SystemException e3)
          {
            realCoord = null;

            throw e3;
          }

          realCoord = null;
        }
      }

      /*
       * Now register the synchronization locally.
       */

      super.register_synchronization(theSync);
    }
  }

  /*
   * These methods are here to make protected methods in
   * ArjunaTransactionImple available to ServerSynchronization.
   */

  public void doBeforeCompletion () throws SystemException
  {
    _beforeCompleted = true;

    super.doBeforeCompletion();
  }

  public void doAfterCompletion (org.omg.CosTransactions.Status s)
      throws SystemException
  {
    super.doAfterCompletion(s);
  }

  public static String typeName ()
  {
    return "/StateManager/BasicAction/TwoPhaseCoordinator/ArjunaTransactionImple/ServerTransaction";
  }

  public final synchronized void setRecoveryCoordinator (RecoveryCoordinator recCoord)
  {
    _recoveryCoordinator = recCoord;
  }

  /*
   * If this is a top-level transaction then we should have a recovery
   * coordinator reference, so save it away.
   */

  public boolean save_state (OutputObjectState os, int ot)
  {
    try
    {
      if (_recoveryCoordinator != null)
      {
        os.packBoolean(true);
        os.packString(ORBManager.getORB().orb().object_to_string(_recoveryCoordinator));
      }
      else
        os.packBoolean(false);

      return super.save_state(os, ot);
    }
    catch (IOException e)
    {
      if (jtsLogger.logger.isWarnEnabled())
      {
        jtsLogger.loggerI18N.warn("com.arjuna.ats.internal.jts.orbspecific.interposition.coordinator.generror", new Object[]
        { "ServerTransaction.save_state", e });
      }
    }

    return false;
  }

  public boolean restore_state (InputObjectState os, int ot)
  {
    try
    {
      boolean haveRecCoord = os.unpackBoolean();

      if (haveRecCoord)
      {
        try
        {
          String ior = os.unpackString();
          org.omg.CORBA.Object objRef = ORBManager.getORB().orb().string_to_object(ior);
          _recoveryCoordinator = RecoveryCoordinatorHelper.narrow(objRef);
        }
        catch (Exception e)
        {
          if (jtsLogger.logger.isWarnEnabled())
          {
            jtsLogger.loggerI18N.warn("com.arjuna.ats.internal.jts.orbspecific.interposition.coordinator.generror", new Object[]
            { "ServerTransaction.restore_state", e });
          }

          return false;
        }
      }
      else
        _recoveryCoordinator = null;

      return super.restore_state(os, ot);
    }
    catch (IOException ex)
    {
      if (jtsLogger.logger.isWarnEnabled())
      {
        jtsLogger.loggerI18N.warn("com.arjuna.ats.internal.jts.orbspecific.interposition.coordinator.generror", new Object[]
        { "ServerTransaction.restore_state", ex });
      }
    }

    return false;
  }

  public String toString ()
  {
    return "ServerTransaction < " + get_uid() + " >";
  }

  /**
   * Used during crash recovery. The Uid is the identity of the state which
   * this transaction's log is stored in. It is not the identity of the
   * transaction!
   *
   * Therefore you may pass nullUid to the base transaction and rely on activating the
   * transaction state to set up the transaction id.
   */

  protected ServerTransaction (Uid recoveringActUid)
  {
      super(recoveringActUid);

    if (jtsLogger.logger.isDebugEnabled())
    {
      jtsLogger.logger.debug(DebugLevel.CONSTRUCTORS, VisibilityLevel.VIS_PUBLIC, com.arjuna.ats.jts.logging.FacilityCode.FAC_OTS, "ServerTransaction::ServerTransaction ( "
          + recoveringActUid + " )");
    }

    _savingUid = new Uid(recoveringActUid);
    _sync = null;
    _beforeCompleted = false;
    _recoveryCoordinator = null;
    _prepState = ActionStatus.COMMITTING;
  }

  protected final synchronized int preparedStatus ()
  {
    return _prepState;
  }

  private final int finalStatus ()
  {
    int heuristic = super.getHeuristicDecision();

    switch (heuristic)
    {
    case TwoPhaseOutcome.PREPARE_OK:
    case TwoPhaseOutcome.FINISH_OK:
      return super.status();
    case TwoPhaseOutcome.HEURISTIC_ROLLBACK:
      return ActionStatus.H_ROLLBACK;
    case TwoPhaseOutcome.HEURISTIC_COMMIT:
      return ActionStatus.H_COMMIT;
    case TwoPhaseOutcome.HEURISTIC_MIXED:
      return ActionStatus.H_MIXED;
    case TwoPhaseOutcome.HEURISTIC_HAZARD:
    default:
      return ActionStatus.H_HAZARD;
    }
  }

  protected RecoveryCoordinator _recoveryCoordinator;

  private Uid _savingUid;

  private ServerSynchronization _sync;

  private boolean _beforeCompleted;

  private int _prepState;

  private static boolean _interposedSynch = false;

  static
  {
    String inter = jtsPropertyManager.propertyManager.getProperty(com.arjuna.ats.jts.common.Environment.SUPPORT_INTERPOSED_SYNCHRONIZATION);

    if (inter != null)
    {
      if (inter.compareTo("YES") == 0)
        _interposedSynch = true;
    }
  }

}
TOP

Related Classes of com.arjuna.ats.internal.jts.orbspecific.interposition.coordinator.ServerTransaction

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.