Package com.arjuna.ats.internal.jta.resources.jts.orbspecific

Source Code of com.arjuna.ats.internal.jta.resources.jts.orbspecific.XAResourceRecord

/*
* 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 General Public License, v. 2.0.
* 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 General Public License for more details.
* You should have received a copy of the GNU General Public License,
* v. 2.0 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: XAResourceRecord.java 2342 2006-03-30 13:06:17Z  $
*/

package com.arjuna.ats.internal.jta.resources.jts.orbspecific;

import com.arjuna.ats.jta.recovery.*;

import com.arjuna.ats.jta.common.jtaPropertyManager;
import com.arjuna.ats.jta.common.Environment;

import com.arjuna.ats.jta.xa.*;
import com.arjuna.ats.jta.utils.XAHelper;
import com.arjuna.ats.jta.logging.*;
import com.arjuna.ats.jta.resources.StartXAResource;
import com.arjuna.ats.jta.resources.EndXAResource;

import com.arjuna.ats.internal.jta.transaction.jts.TransactionImple;
import com.arjuna.ats.internal.jta.xa.TxInfo;
import com.arjuna.ats.internal.jta.resources.XAResourceErrorHandler;

import com.arjuna.ats.arjuna.common.*;
import com.arjuna.ats.arjuna.coordinator.TwoPhaseOutcome;
import com.arjuna.ats.arjuna.state.*;
import com.arjuna.ats.arjuna.objectstore.ObjectStore;
import com.arjuna.ats.arjuna.coordinator.RecordType;

import com.arjuna.ats.jts.utils.Utility;

import com.arjuna.ats.internal.jts.ORBManager;

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

import org.omg.CosTransactions.*;

import com.arjuna.ArjunaOTS.*;

import javax.transaction.xa.*;

import java.io.*;

import org.omg.CosTransactions.NotPrepared;
import org.omg.CosTransactions.HeuristicCommit;
import org.omg.CosTransactions.HeuristicMixed;
import org.omg.CosTransactions.HeuristicHazard;
import org.omg.CosTransactions.HeuristicRollback;
import org.omg.CORBA.OBJECT_NOT_EXIST;
import org.omg.CORBA.SystemException;
import org.omg.CORBA.UNKNOWN;
import org.omg.CORBA.TRANSACTION_ROLLEDBACK;

/**
* @message com.arjuna.ats.internal.jta.resources.jts.orbspecific.nulltransaction
*          [com.arjuna.ats.internal.jta.resources.jts.orbspecific.nulltransaction]
*          {0} - null transaction!
* @message com.arjuna.ats.internal.jta.resources.jts.orbspecific.xaerror
*          [com.arjuna.ats.internal.jta.resources.jts.orbspecific.xaerror] {0}
*          caused an XA error: {1}
* @message com.arjuna.ats.internal.jta.resources.jts.orbspecific.loadstateread
*          [com.arjuna.ats.internal.jta.resources.jts.orbspecific.loadstateread]
*          Reading state caught: {1}
*/

public class XAResourceRecord extends com.arjuna.ArjunaOTS.OTSAbstractRecordPOA
{

  public static final int XACONNECTION = 0;

  private static final Uid START_XARESOURCE = Uid.minUid() ;

  private static final Uid END_XARESOURCE = Uid.maxUid() ;

  /**
   * The params represent specific parameters we need to recreate the
   * connection to the database in the event of a failure. If they're not set
   * then recovery is out of our control.
   *
   * Could also use it to pass other information, such as the readonly flag.
   *
   * @message com.arjuna.ats.internal.jta.resources.jts.orbspecific.consterror
   *          [com.arjuna.ats.internal.jta.resources.jts.orbspecific.consterror]
   *          {0} caught exception during construction: {1}
   */

  public XAResourceRecord(TransactionImple tx, XAResource res, Xid xid,
      Object[] params)
  {
    if (jtaLogger.logger.isDebugEnabled())
    {
      jtaLogger.logger.debug(DebugLevel.CONSTRUCTORS,
          VisibilityLevel.VIS_PUBLIC,
          com.arjuna.ats.jta.logging.FacilityCode.FAC_JTA,
          "XAResourceRecord.XAResourceRecord ( " + xid + " )");
    }

    _theXAResource = res;
    _recoveryObject = null;
    _tranID = xid;

    _valid = true;

    if (params != null)
    {
      if (params.length >= XACONNECTION)
      {
        if (params[XACONNECTION] instanceof RecoverableXAConnection)
          _recoveryObject = (RecoverableXAConnection) params[XACONNECTION];
      }
    }

    _prepared = false;
    _committed = false;
    _heuristic = TwoPhaseOutcome.FINISH_OK;
    _objStore = null;
    _theUid = new Uid();
    _theReference = null;
    _recoveryCoordinator = null;

    _theTransaction = tx;

    if (_theXAResource instanceof StartXAResource)
      _cachedUidStringForm = START_XARESOURCE.stringForm();
    else
    {
      if (_theXAResource instanceof EndXAResource)
        _cachedUidStringForm = END_XARESOURCE.stringForm();
    }
  }

  public void finalize()
  {
    if (_theTransaction != null)
    {
      _theTransaction = null;
    }
  }

  public final Uid get_uid()
  {
    return _theUid;
  }

  public final synchronized org.omg.CosTransactions.Resource getResource()
  {
    if (_theReference == null)
    {
      ORBManager.getPOA().objectIsReady(this);

      _theReference = org.omg.CosTransactions.ResourceHelper
          .narrow(ORBManager.getPOA().corbaReference(this));
    }

    return _theReference;
  }

  public final Xid getXid()
  {
    return _tranID;
  }

  /**
   * @message com.arjuna.ats.internal.jta.resources.jts.orbspecific.preparefailed
   *          [com.arjuna.ats.internal.jta.resources.jts.orbspecific.preparefailed]
   *          XAResource prepare failed with: {1}
   */
 
  public org.omg.CosTransactions.Vote prepare() throws HeuristicMixed,
      HeuristicHazard, org.omg.CORBA.SystemException
  {
    if (jtaLogger.logger.isDebugEnabled())
    {
      jtaLogger.logger.debug(DebugLevel.FUNCTIONS,
          VisibilityLevel.VIS_PUBLIC,
          com.arjuna.ats.jta.logging.FacilityCode.FAC_JTA,
          "XAResourceRecord.prepare for " + _tranID);
    }

    if (!_valid || (_theXAResource == null))
    {
      removeConnection();

      return Vote.VoteReadOnly;
    }

    if (_tranID == null)
    {
      if (jtaLogger.loggerI18N.isWarnEnabled())
      {
        jtaLogger.loggerI18N
            .warn(
                "com.arjuna.ats.internal.jta.resources.jts.orbspecific.nulltransaction",
                new Object[]
                { "XAResourceRecord.prepare" });
      }

      removeConnection();

      return Vote.VoteRollback;
    }

    try
    {
      /*
       * Window of vulnerability versus performance trade-off: if we
       * create the resource log here then we slow things down in the case
       * the resource rolls back or returns read only (since we have
       * written data for no reason and now need to delete it). If we
       * create the resource log after we know the prepare outcome then
       * there's a chance we may crash between prepare and writing the
       * state.
       *
       * We go for the latter currently since failures are rare, but
       * performance is always required. The result is that the
       * transaction will roll back (since it won't get an ack from
       * prepare) and the resource won't be recovered. The sys. admin.
       * will have to clean up manually.
       *
       * Actually what will happen in the case of ATS is that the XA
       * recovery module will eventually roll back this resource when it
       * notices that there is no log entry for it.
       */

      if (endAssociation())
      {
        _theXAResource.end(_tranID, XAResource.TMSUCCESS);
      }

      if (_theXAResource.prepare(_tranID) == XAResource.XA_RDONLY)
      {
        removeConnection();

        return Vote.VoteReadOnly;
      }
      else
      {
        if (createState())
          return Vote.VoteCommit;
        else
          return Vote.VoteRollback;
      }
    }
    catch (XAException e1)
    {
      if (jtaLogger.loggerI18N.isWarnEnabled())
      {
        jtaLogger.loggerI18N
            .warn(
                "com.arjuna.ats.internal.jta.resources.jts.orbspecific.preparefailed",
                new Object[]
                { XAHelper
                    .printXAErrorCode(e1) });
      }
     
      /*
       * XA_RB*, XAER_RMERR, XAER_RMFAIL, XAER_NOTA, XAER_INVAL, or
       * XAER_PROTO.
       */
     
      if (_rollbackOptimization) // won't have rollback called on it
        removeConnection();
     
      if ((e1.errorCode == XAException.XAER_RMERR) || (e1.errorCode == XAException.XAER_RMFAIL))
        throw new HeuristicHazard();

      return Vote.VoteRollback;
    }
    catch (Exception e2)
    {
      if (jtaLogger.loggerI18N.isWarnEnabled())
      {
        jtaLogger.loggerI18N
            .warn(
                "com.arjuna.ats.internal.jta.resources.jts.orbspecific.preparefailed",
                new Object[]
                { e2 });
      }

      if (_rollbackOptimization) // won't have rollback called on it
        removeConnection();

      return Vote.VoteRollback;
    }
  }

  public void rollback() throws org.omg.CORBA.SystemException,
      HeuristicCommit, HeuristicMixed, HeuristicHazard
  {
    if (jtaLogger.logger.isDebugEnabled())
    {
      jtaLogger.logger.debug(DebugLevel.FUNCTIONS,
          VisibilityLevel.VIS_PUBLIC,
          com.arjuna.ats.jta.logging.FacilityCode.FAC_JTA,
          "XAResourceRecord.rollback for " + _tranID);
    }

    if (!_valid)
      return;

    if (_theTransaction != null
        && _theTransaction.getXAResourceState(_theXAResource) == TxInfo.OPTIMIZED_ROLLBACK)
    {
      /*
       * Already rolledback during delist.
       */

      return;
    }

    if (_tranID == null)
    {
      if (jtaLogger.loggerI18N.isWarnEnabled())
      {
        jtaLogger.loggerI18N
            .warn(
                "com.arjuna.ats.internal.jta.resources.jts.orbspecific.nulltransaction",
                new Object[]
                { "XAResourceRecord.rollback" });
      }
    }
    else
    {
      if (_theXAResource != null)
      {
        switch (_heuristic)
        {
        case TwoPhaseOutcome.HEURISTIC_HAZARD:
          throw new org.omg.CosTransactions.HeuristicHazard();
        case TwoPhaseOutcome.HEURISTIC_MIXED:
          throw new org.omg.CosTransactions.HeuristicMixed();
        default:
          break;
        }

        try
        {
          if (!_prepared)
          {
            if (endAssociation())
            {
              _theXAResource.end(_tranID, XAResource.TMSUCCESS);
            }
          }

          _theXAResource.rollback(_tranID);
        }
        catch (XAException e1)
        {
          if (notAProblem(e1, false))
          {
            // some other thread got there first (probably)
          }
          else
          {
            if (jtaLogger.loggerI18N.isWarnEnabled())
            {
              jtaLogger.loggerI18N
                  .warn(
                      "com.arjuna.ats.internal.jta.resources.jts.orbspecific.xaerror",
                      new Object[]
                      {
                          "XAResourceRecord.rollback",
                          XAHelper
                              .printXAErrorCode(e1) });
            }

            switch (e1.errorCode)
            {
            case XAException.XAER_RMERR:
              if (!_prepared)
                break; // just do the finally block
            case XAException.XA_HEURHAZ:
              updateState(TwoPhaseOutcome.HEURISTIC_HAZARD);

              throw new org.omg.CosTransactions.HeuristicHazard();
            case XAException.XA_HEURCOM:
              updateState(TwoPhaseOutcome.HEURISTIC_COMMIT);

              throw new org.omg.CosTransactions.HeuristicCommit();
            case XAException.XA_HEURMIX:
              updateState(TwoPhaseOutcome.HEURISTIC_MIXED);

              throw new org.omg.CosTransactions.HeuristicMixed();
            case XAException.XA_HEURRB: // forget?
            case XAException.XA_RBROLLBACK:
            case XAException.XA_RBEND:
            case XAException.XA_RBCOMMFAIL:
            case XAException.XA_RBDEADLOCK:
            case XAException.XA_RBINTEGRITY:
            case XAException.XA_RBOTHER:
            case XAException.XA_RBPROTO:
            case XAException.XA_RBTIMEOUT:
              destroyState();
              break;
            default:
              destroyState();

              if (_prepared)
                throw new org.omg.CosTransactions.HeuristicHazard();
              else
                throw new UNKNOWN();
            }
          }
        }
        catch (Exception e2)
        {
          e2.printStackTrace();

          throw new UNKNOWN();
        }
        finally
        {
          if (_prepared)
            destroyState();
          else
            removeConnection();
        }
      }
    }
  }

  public void commit() throws org.omg.CORBA.SystemException, NotPrepared,
      HeuristicRollback, HeuristicMixed, HeuristicHazard
  {
    if (jtaLogger.logger.isDebugEnabled())
    {
      jtaLogger.logger.debug(DebugLevel.FUNCTIONS,
          VisibilityLevel.VIS_PUBLIC,
          com.arjuna.ats.jta.logging.FacilityCode.FAC_JTA,
          "XAResourceRecord.commit for " + _tranID);
    }

    if (_tranID == null)
    {
      if (jtaLogger.loggerI18N.isWarnEnabled())
      {
        jtaLogger.loggerI18N
            .warn(
                "com.arjuna.ats.internal.jta.resources.jts.orbspecific.nulltransaction",
                new Object[]
                { "XAResourceRecord.commit" });
      }
    }
    else
    {
      if ((_theXAResource != null) && (!_committed))
      {
        switch (_heuristic)
        {
        case TwoPhaseOutcome.HEURISTIC_HAZARD:
          throw new org.omg.CosTransactions.HeuristicHazard();
        case TwoPhaseOutcome.HEURISTIC_MIXED:
          throw new org.omg.CosTransactions.HeuristicMixed();
        case TwoPhaseOutcome.HEURISTIC_ROLLBACK:
          throw new org.omg.CosTransactions.HeuristicRollback();
        default:
          break;
        }

        if (!_prepared)
          throw new NotPrepared();

        try
        {
          if (!_committed)
          {
            _committed = true;

            _theXAResource.commit(_tranID, false);

            destroyState();
          }
        }
        catch (XAException e1)
        {
          e1.printStackTrace();

          if (notAProblem(e1, true))
          {
            // some other thread got there first (probably)
            destroyState();
          }
          else
          {
            _committed = false;

            if (jtaLogger.loggerI18N.isWarnEnabled())
            {
              jtaLogger.loggerI18N
                  .warn(
                      "com.arjuna.ats.internal.jta.resources.jts.orbspecific.xaerror",
                      new Object[]
                      {
                          "XAResourceRecord.commit",
                          XAHelper
                              .printXAErrorCode(e1) });
            }

            /*
             * XA_HEURHAZ, XA_HEURCOM, XA_HEURRB, XA_HEURMIX,
             * XAER_RMERR, XAER_RMFAIL, XAER_NOTA, XAER_INVAL, or
             * XAER_PROTO.
             */
           
            switch (e1.errorCode)
            {
           
            case XAException.XA_HEURHAZ:
              updateState(TwoPhaseOutcome.HEURISTIC_HAZARD);

              throw new org.omg.CosTransactions.HeuristicHazard();
            case XAException.XA_HEURCOM:  // what about forget? OTS doesn't support this code here.
              destroyState();
              break;
            case XAException.XA_HEURRB:
            case XAException.XA_RBROLLBACK:
            case XAException.XA_RBCOMMFAIL:
            case XAException.XA_RBDEADLOCK:
            case XAException.XA_RBINTEGRITY:
            case XAException.XA_RBOTHER:
            case XAException.XA_RBPROTO:
            case XAException.XA_RBTIMEOUT:
            case XAException.XA_RBTRANSIENT:
            case XAException.XAER_RMERR:
              updateState(TwoPhaseOutcome.HEURISTIC_ROLLBACK);

              throw new org.omg.CosTransactions.HeuristicRollback();
            case XAException.XA_HEURMIX:
              updateState(TwoPhaseOutcome.HEURISTIC_MIXED);

              throw new org.omg.CosTransactions.HeuristicMixed();
            case XAException.XAER_NOTA:
            case XAException.XAER_PROTO:
              break;
            case XAException.XA_RETRY:
              throw new UNKNOWN();
            case XAException.XAER_INVAL:
            case XAException.XAER_RMFAIL: // resource manager
                            // failed, did it
                            // rollback?
              throw new org.omg.CosTransactions.HeuristicHazard();
            default:
              throw new org.omg.CosTransactions.HeuristicHazard();
            }
          }
        }
        catch (Exception e2)
        {
          _committed = false;

          throw new UNKNOWN();
        }
        finally
        {
          removeConnection();
        }
      }
    }
  }

  public org.omg.CosTransactions.Vote prepare_subtransaction()
      throws SystemException
  {
    return Vote.VoteRollback; // shouldn't be possible!
  }

  public void commit_subtransaction(Coordinator parent)
      throws SystemException
  {
    throw new UNKNOWN();
  }

  public void rollback_subtransaction() throws SystemException
  {
    throw new UNKNOWN();
  }

  public int type_id() throws SystemException
  {
    return RecordType.JTAX_RECORD;
  }

  public String uid() throws SystemException
  {
    if (_cachedUidStringForm == null)
      _cachedUidStringForm = _theUid.stringForm();

    return _cachedUidStringForm;
  }

  public boolean propagateOnAbort() throws SystemException
  {
    return false;
  }

  public boolean propagateOnCommit() throws SystemException
  {
    return false; // nesting not supported
  }

  public boolean saveRecord() throws SystemException
  {
    return true;
  }

  public void merge(OTSAbstractRecord record) throws SystemException
  {
  }

  public void alter(OTSAbstractRecord record) throws SystemException
  {
  }

  public boolean shouldAdd(OTSAbstractRecord record) throws SystemException
  {
    return false;
  }

  public boolean shouldAlter(OTSAbstractRecord record) throws SystemException
  {
    return false;
  }

  public boolean shouldMerge(OTSAbstractRecord record) throws SystemException
  {
    return false;
  }

  public boolean shouldReplace(OTSAbstractRecord record)
      throws SystemException
  {
    return false;
  }

  /**
   * Is the XAException a non-error when received in reply to commit or
   * rollback? It normally is, but may be overridden in recovery.
   */

  protected boolean notAProblem(XAException ex, boolean commit)
  {
    return XAResourceErrorHandler.notAProblem(_theXAResource, ex, commit);
  }

  /**
   * For commit_one_phase we can do whatever we want since the transaction
   * outcome is whatever we want. Therefore, we do not need to save any
   * additional recoverable state, such as a reference to the transaction
   * coordinator, since it will not have an intentions list anyway.
   *
   * @message com.arjuna.ats.internal.jta.resources.jts.orbspecific.coperror
   *          [com.arjuna.ats.internal.jta.resources.jts.orbspecific.coperror]
   *          Caught the following error while trying to single phase complete
   *          resource {0}
   */

  public void commit_one_phase() throws HeuristicHazard,
      org.omg.CORBA.SystemException
  {
    if (jtaLogger.logger.isDebugEnabled())
    {
      jtaLogger.logger.debug(DebugLevel.FUNCTIONS,
          VisibilityLevel.VIS_PUBLIC,
          com.arjuna.ats.jta.logging.FacilityCode.FAC_JTA,
          "XAResourceRecord.commit_one_phase for " + _tranID);
    }

    if (_tranID == null)
    {
      if (jtaLogger.loggerI18N.isWarnEnabled())
      {
        jtaLogger.loggerI18N
            .warn(
                "com.arjuna.ats.internal.jta.resources.jts.orbspecific.nulltransaction",
                new Object[]
                { "XAResourceRecord.commit_one_phase" });
      }
    }
    else
    {
      if (_theXAResource != null)
      {
        try
        {
          switch (_heuristic)
          {
          case TwoPhaseOutcome.HEURISTIC_HAZARD:
            throw new org.omg.CosTransactions.HeuristicHazard();
          default:
            break;
          }

          /*
           * TODO in Oracle, the end is not required. Is this
           * common to other RM implementations?
           */
         
          if (endAssociation())
          {
            _theXAResource.end(_tranID, XAResource.TMSUCCESS);
          }

          _theXAResource.commit(_tranID, true);
        }
        catch (XAException e1)
        {
          /*
           * XA_HEURHAZ, XA_HEURCOM, XA_HEURRB, XA_HEURMIX,
           * XAER_RMERR, XAER_RMFAIL, XAER_NOTA, XAER_INVAL, or
           * XAER_PROTO. XA_RB*
           */

          if ((e1.errorCode >= XAException.XA_RBBASE)
              && (e1.errorCode <= XAException.XA_RBEND))
          {
            throw new TRANSACTION_ROLLEDBACK();
          }
         
          switch (e1.errorCode)
          {
          case XAException.XA_HEURHAZ:
          case XAException.XA_HEURMIX:
            updateState(TwoPhaseOutcome.HEURISTIC_HAZARD);

            throw new org.omg.CosTransactions.HeuristicHazard();
          case XAException.XA_HEURCOM:
            handleForget() ;
            break;
          case XAException.XA_HEURRB:
          case XAException.XA_RBROLLBACK:
          case XAException.XA_RBCOMMFAIL:
          case XAException.XA_RBDEADLOCK:
          case XAException.XA_RBINTEGRITY:
          case XAException.XA_RBOTHER:
          case XAException.XA_RBPROTO:
          case XAException.XA_RBTIMEOUT:
          case XAException.XA_RBTRANSIENT:
          case XAException.XAER_RMERR:
            handleForget() ;
            throw new TRANSACTION_ROLLEDBACK();
          case XAException.XAER_NOTA:
          case XAException.XAER_PROTO:
            break;
          case XAException.XAER_INVAL:
          case XAException.XAER_RMFAIL: // resource manager failed,
                          // did it rollback?
            throw new UNKNOWN();
          default:
            throw new UNKNOWN();
          }
        }
        catch (SystemException ex)
        {
          ex.printStackTrace();
         
          throw ex;
        }
        catch (org.omg.CosTransactions.HeuristicHazard ex)
        {
          throw ex;
        }
        catch (Exception e2)
        {
          if (jtaLogger.loggerI18N.isWarnEnabled())
          {
            jtaLogger.loggerI18N
                .warn(
                    "com.arjuna.ats.internal.jta.resources.jts.orbspecific.coperror",
                    e2);
          }

          e2.printStackTrace();
         
          throw new UNKNOWN();
        }
        finally
        {
          removeConnection();
        }
      }
    }
  }

  public void forget() throws org.omg.CORBA.SystemException
  {
    if (jtaLogger.logger.isDebugEnabled())
    {
      jtaLogger.logger.debug(DebugLevel.FUNCTIONS,
          VisibilityLevel.VIS_PUBLIC,
          com.arjuna.ats.jta.logging.FacilityCode.FAC_JTA,
          "XAResourceRecord.forget for " + _tranID);
    }

    handleForget() ;

    destroyState();

    removeConnection();
  }
 
  private void handleForget()
  {
    if ((_theXAResource != null) && (_tranID != null))
    {
      try
      {
        _theXAResource.forget(_tranID);
      }
      catch (Exception e)
      {
      }
    }
  }

  /**
   *     @message com.arjuna.ats.internal.jta.resources.jts.orbspecific.saveState
   *          [com.arjuna.ats.internal.jta.resources.jts.orbspecific.saveState]
   *          Could not serialize a serializable XAResource!
   */
 
  public boolean saveState(OutputObjectState os)
  {
    boolean res = false;

    try
    {
      os.packInt(_heuristic);

      /*
       * Since we don't know what type of Xid we are using, leave it up to
       * XID to pack.
       */

      XidImple.pack(os, _tranID);

      /*
       * If no recovery object set then rely upon object serialisation!
       */

      if (_recoveryObject == null)
      {
        os.packInt(RecoverableXAConnection.OBJECT_RECOVERY);

        boolean shouldSerialize = false;
       
        try
        {
          if (_theXAResource instanceof Serializable)
            shouldSerialize = true;
         
          ByteArrayOutputStream s = new ByteArrayOutputStream();
          ObjectOutputStream o = new ObjectOutputStream(s);

          o.writeObject(_theXAResource);
          o.close();

          os.packBoolean(true);

          os.packBytes(s.toByteArray());
        }
        catch (NotSerializableException ex)
        {
          if (!shouldSerialize)
          {
            // have to rely upon XAResource.recover!
 
            os.packBoolean(false);   
          }     
          else
          {
            if (jtaLogger.loggerI18N.isWarnEnabled())
            {
              jtaLogger.loggerI18N.warn("com.arjuna.ats.internal.jta.resources.jts.orbspecific.saveState");
            }
           
            return false;
          }
        }
      }
      else
      {
        os.packInt(RecoverableXAConnection.AUTO_RECOVERY);
        os.packString(_recoveryObject.getClass().getName());

        _recoveryObject.packInto(os);
      }

      if (_recoveryCoordinator == null)
        os.packBoolean(false);
      else
      {
        os.packBoolean(true);

        String ior = ORBManager.getORB().orb().object_to_string(
            _recoveryCoordinator);

        os.packString(ior);

        ior = null;
      }

      res = true;
    }
    catch (Exception e)
    {
      e.printStackTrace();

      res = false;
    }

    return res;
  }

  /**
   * @message com.arjuna.ats.internal.jta.resources.jts.orbspecific.restoreerror1
   *          [com.arjuna.ats.internal.jta.resources.jts.orbspecific.restoreerror1]
   *          Exception on attempting to resource XAResource: {0}
   * @message com.arjuna.ats.internal.jta.resources.jts.orbspecific.restoreerror2
   *          [com.arjuna.ats.internal.jta.resources.jts.orbspecific.restoreerror2]
   *          Unexpected exception on attempting to resource XAResource: {0}
   * @message com.arjuna.ats.internal.jta.resources.jts.orbspecific.norecoveryxa
   *          [com.arjuna.ats.internal.jta.resources.jts.orbspecific.norecoveryxa]
   *          Could not find new XAResource to use for recovering
   *          non-serializable XAResource {0}
   */

  public boolean restoreState(InputObjectState os)
  {
    boolean res = false;

    try
    {
      _heuristic = os.unpackInt();
      _tranID = XidImple.unpack(os);

      _theXAResource = null;
      _recoveryObject = null;

      if (os.unpackInt() == RecoverableXAConnection.OBJECT_RECOVERY)
      {
        boolean haveXAResource = os.unpackBoolean();

        if (haveXAResource)
        {
          try
          {
            byte[] b = os.unpackBytes();

            ByteArrayInputStream s = new ByteArrayInputStream(b);
            ObjectInputStream o = new ObjectInputStream(s);

            _theXAResource = (XAResource) o.readObject();
            o.close();

            if (jtaLogger.logger.isDebugEnabled())
            {
              jtaLogger.logger
                  .debug(
                      DebugLevel.FUNCTIONS,
                      VisibilityLevel.VIS_PUBLIC,
                      com.arjuna.ats.jta.logging.FacilityCode.FAC_JTA,
                      "XAResourceRecord.restore_state - XAResource de-serialized");
            }
          }
          catch (Exception ex)
          {
            // not serializable in the first place!

            if (jtaLogger.loggerI18N.isWarnEnabled())
            {
              jtaLogger.loggerI18N
                  .warn(
                      "com.arjuna.ats.internal.jta.resources.jts.orbspecific.restoreerror1",
                      new Object[]
                      { ex });
            }
           
            return false;
          }
        }
      }
      else
      {
        String creatorName = os.unpackString();
        Class c = Thread.currentThread().getContextClassLoader()
            .loadClass(creatorName);

        _recoveryObject = (RecoverableXAConnection) c.newInstance();

        _recoveryObject.unpackFrom(os);
        _theXAResource = _recoveryObject.getResource();

        if (_theXAResource == null)
        {
          jtaLogger.loggerI18N
              .warn(
                  "com.arjuna.ats.internal.jta.resources.jts.orbspecific.norecoveryxa",
                  new Object[]
                  { _tranID });
        }

        if (jtaLogger.logger.isDebugEnabled())
        {
          jtaLogger.logger.debug(DebugLevel.FUNCTIONS,
              VisibilityLevel.VIS_PUBLIC,
              com.arjuna.ats.jta.logging.FacilityCode.FAC_JTA,
              "XAResourceRecord.restore_state - XAResource got from "
                  + creatorName);
        }
      }

      boolean haveRecCoord = os.unpackBoolean();

      if (haveRecCoord)
      {
        String ior = os.unpackString();

        if (ior == null)
          return false;
        else
        {
          org.omg.CORBA.Object objRef = ORBManager.getORB().orb()
              .string_to_object(ior);

          _recoveryCoordinator = RecoveryCoordinatorHelper
              .narrow(objRef);
        }
      }
      else
        _recoveryCoordinator = null;

      res = true;
    }
    catch (Exception e)
    {
      if (jtaLogger.loggerI18N.isWarnEnabled())
      {
        jtaLogger.loggerI18N
            .warn(
                "com.arjuna.ats.internal.jta.resources.jts.orbspecific.restoreerror2",
                new Object[]
                { e });
      }

      e.printStackTrace();

      res = false;
    }

    return res;
  }

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

  public static String typeName()
  {
    return "/CosTransactions/XAResourceRecord";
  }

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

  public final RecoveryCoordinator getRecoveryCoordinator()
  {
    return _recoveryCoordinator;
  }

  protected XAResourceRecord(Uid u)
  {
    _theXAResource = null;
    _recoveryObject = null;
    _tranID = null;
    _prepared = true;
    _committed = false;
    _heuristic = TwoPhaseOutcome.FINISH_OK;
    _theUid = new Uid(u);
    _objStore = null;
    _valid = false;
    _theReference = null;
    _recoveryCoordinator = null;
    _theTransaction = null;

    _valid = loadState();
  }

  /**
   * For those objects where the original XAResource could not be saved.
   */

  protected synchronized void setXAResource(XAResource res)
  {
    _theXAResource = res;
  }

  /**
   * @message com.arjuna.ats.internal.jta.resources.jts.orbspecific.notprepared
   *          [com.arjuna.ats.internal.jta.resources.jts.orbspecific.notprepared]
   *          {0} caught NotPrepared exception during recovery phase!
   * @message com.arjuna.ats.internal.jta.resources.jts.orbspecific.unexpected
   *          [com.arjuna.ats.internal.jta.resources.jts.orbspecific.unexpected]
   *          {0} caught unexpected exception: {1} during recovery phase!
   */

  protected int recover()
  {
    if (jtaLogger.logger.isDebugEnabled())
    {
      jtaLogger.logger.debug(DebugLevel.FUNCTIONS,
          VisibilityLevel.VIS_PROTECTED,
          com.arjuna.ats.jta.logging.FacilityCode.FAC_JTA,
          "XAResourceRecord.recover");
    }

    if (_valid)
    {
      org.omg.CosTransactions.Status s = org.omg.CosTransactions.Status.StatusUnknown;

      try
      {
        // force tx to rollback if not prepared

        s = _recoveryCoordinator.replay_completion(getResource());
      }
      catch (OBJECT_NOT_EXIST ex)
      {
        // no coordinator, so presumed abort.

        s = org.omg.CosTransactions.Status.StatusRolledBack;
      }
      catch (NotPrepared ex1)
      {
        if (jtaLogger.loggerI18N.isWarnEnabled())
        {
          jtaLogger.loggerI18N
              .warn(
                  "com.arjuna.ats.internal.jta.resources.jts.orbspecific.notprepared",
                  new Object[]
                  { "XAResourceRecord" });
        }

        return XARecoveryResource.TRANSACTION_NOT_PREPARED;
      }
      catch (java.lang.NullPointerException ne)
      {
        /*
         * No recovery coordinator!
         */
      }
      catch (Exception e)
      {
        e.printStackTrace();

        /*
         * Unknown error, so better to do nothing at this stage.
         */

        if (jtaLogger.loggerI18N.isWarnEnabled())
        {
          jtaLogger.loggerI18N
              .warn(
                  "com.arjuna.ats.internal.jta.resources.jts.orbspecific.unexpected",
                  new Object[]
                  { "XAResourceRecord", e });
        }

        return XARecoveryResource.FAILED_TO_RECOVER;
      }

      if (jtaLogger.logger.isDebugEnabled())
      {
        jtaLogger.logger.debug(DebugLevel.FUNCTIONS,
            VisibilityLevel.VIS_PROTECTED,
            com.arjuna.ats.jta.logging.FacilityCode.FAC_JTA,
            "XAResourceRecord.recover got status: "
                + Utility.stringStatus(s));
      }

      boolean doCommit = false;

      switch (s.value())
      {
      case org.omg.CosTransactions.Status._StatusUnknown:
        // some problem occurred

        return XARecoveryResource.FAILED_TO_RECOVER;
      case org.omg.CosTransactions.Status._StatusMarkedRollback:
      case org.omg.CosTransactions.Status._StatusRollingBack:
        // we should be told eventually, so wait

        return XARecoveryResource.WAITING_FOR_RECOVERY;
      case org.omg.CosTransactions.Status._StatusCommitted:

        doCommit = true;
        break;
      case org.omg.CosTransactions.Status._StatusRolledBack:
      case org.omg.CosTransactions.Status._StatusNoTransaction:
        // presumed abort

        doCommit = false;
        break;
      case org.omg.CosTransactions.Status._StatusCommitting:
        // leave it for now as we'll be driven top-down soon

        return XARecoveryResource.WAITING_FOR_RECOVERY;
      default:
        // wait

        return XARecoveryResource.FAILED_TO_RECOVER;
      }

      return doRecovery(doCommit);
    }

    return XARecoveryResource.FAILED_TO_RECOVER;
  }

  private final void setObjectStore()
  {
    if (_objStore == null)
      _objStore = new ObjectStore(null, ""); // interface gets default
  }

  /**
   * @message com.arjuna.ats.internal.jta.resources.jts.orbspecific.createstate
   *          [com.arjuna.ats.internal.jta.resources.jts.orbspecific.createstate]
   *          Committing of resource state failed.
   */

  private final boolean createState()
  {
    setObjectStore();

    if ((_theXAResource != null) && (_tranID != null)
        && (_objStore != null))
    {
      OutputObjectState os = new OutputObjectState();

      if (saveState(os))
      {
        try
        {
          _valid = _objStore.write_committed(_theUid, type(), os);
          _prepared = true;
        }
        catch (Exception e)
        {
          if (jtaLogger.loggerI18N.isWarnEnabled())
          {
            jtaLogger.loggerI18N
                .warn("com.arjuna.ats.internal.jta.resources.jts.orbspecific.createstate");
          }

          _valid = false;
        }
      }
      else
        _valid = false;
    }
    else
      _valid = false;

    return _valid;
  }

  /**
   * @message com.arjuna.ats.internal.jta.resources.jts.orbspecific.updatestate
   *          [com.arjuna.ats.internal.jta.resources.jts.orbspecific.updatestate]
   *          Updating of resource state failed.
   */

  private final boolean updateState(int h)
  {
    setObjectStore();

    if (_prepared) // only need do if we have prepared
    {
      OutputObjectState os = new OutputObjectState();

      _heuristic = h;

      if (saveState(os))
      {
        try
        {
          _valid = _objStore.write_committed(_theUid, type(), os);
        }
        catch (Exception e)
        {
          _valid = false;
        }
      }
      else
      {
        if (jtaLogger.loggerI18N.isWarnEnabled())
        {
          jtaLogger.loggerI18N
              .warn("com.arjuna.ats.internal.jta.resources.jts.orbspecific.updatestate");
        }

        _valid = false;
      }
    }

    return _valid;
  }

  private final boolean loadState()
  {
    setObjectStore();

    InputObjectState os = null;

    try
    {
      os = _objStore.read_committed(_theUid, type());
    }
    catch (Exception e)
    {
      if (jtaLogger.loggerI18N.isWarnEnabled())
      {
        jtaLogger.loggerI18N
            .warn(
                "com.arjuna.ats.internal.jta.resources.jts.orbspecific.loadstateread",
                e);
      }

      os = null;
    }

    if (os != null)
    {
      _valid = restoreState(os);

      os = null;
    }
    else
      _valid = false;

    return _valid;
  }

  private final boolean destroyState()
  {
    setObjectStore();

    if (_prepared && _valid)
    {
      try
      {
        _valid = _objStore.remove_committed(_theUid, type());
      }
      catch (Exception e)
      {
        e.printStackTrace();

        _valid = false;
      }
    }

    if (_recoveryObject != null)
      removeConnection();

    return _valid;
  }

  /**
   * @message com.arjuna.ats.internal.jta.resources.jts.orbspecific.remconn
   *          [com.arjuna.ats.internal.jta.resources.jts.orbspecific.remconn]
   *          Attempted shutdown of resource failed with:
   */

  private final void removeConnection()
  {
    /*
     * Should only be called once. Remove the connection so that user can
     * reuse the driver as though it were fresh (e.g., can do read only
     * optimisation).
     */

    if (_recoveryObject != null)
    {
      _recoveryObject.close();
      _recoveryObject = null;
    }

    if (_theTransaction != null)
      _theTransaction = null;

    try
    {
      if (_theReference != null)
      {       
        ORBManager.getPOA().shutdownObject(this);
        _theReference = null;
      }
    }
    catch (Exception e)
    {
      if (jtaLogger.loggerI18N.isWarnEnabled())
      {
        jtaLogger.loggerI18N
            .warn(
                "com.arjuna.ats.internal.jta.resources.jts.orbspecific.remconn",
                e);
      }
    }
  }

  /**
   * @message com.arjuna.ats.internal.jta.resources.jts.orbspecific.recfailed
   *          [com.arjuna.ats.internal.jta.resources.jts.orbspecific.recfailed]
   *          Recovery of resource failed when trying to call {0} got: {1}
   * @message com.arjuna.ats.internal.jta.recovery.jts.orbspecific.commit XA
   *          recovery committing {0}
   * @message com.arjuna.ats.internal.jta.recovery.jts.orbspecific.rollback XA
   *          recovery rolling back {0}
   */

  private final int doRecovery(boolean commit)
  {
    if (jtaLogger.logger.isDebugEnabled())
    {
      jtaLogger.logger.debug(DebugLevel.FUNCTIONS,
          VisibilityLevel.VIS_PRIVATE,
          com.arjuna.ats.jta.logging.FacilityCode.FAC_JTA,
          "XAResourceRecord.doRecovery ( " + commit + " )");
    }

    int result = XARecoveryResource.FAILED_TO_RECOVER;

    if ((_theXAResource != null) && (_tranID != null))
    {
      try
      {
        if (jtaLogger.logger.isInfoEnabled())
        {
          if (commit)
            jtaLogger.loggerI18N
                .info(
                    "com.arjuna.ats.internal.jta.recovery.jts.orbspecific.commit",
                    new Object[]
                    { _tranID });
          else
            jtaLogger.loggerI18N
                .info(
                    "com.arjuna.ats.internal.jta.recovery.jts.orbspecific.rollback",
                    new Object[]
                    { _tranID });
        }

        if (commit)
          commit();
        else
          rollback();

        // if those succeed, they will have removed any persistent state

        result = XARecoveryResource.RECOVERED_OK;
      }
      catch (Exception e2)
      {
        e2.printStackTrace();

        if (jtaLogger.loggerI18N.isWarnEnabled())
        {
          jtaLogger.loggerI18N
              .warn(
                  "com.arjuna.ats.internal.jta.resources.jts.orbspecific.recfailed",
                  new Object[]
                  { ((commit) ? "commit" : "rollback"), e2 });
        }
      }
    }

    return result;
  }

  /*
   * Ask the transaction whether or not this XAResource is still associated
   * with the thread, i.e., has end already been called on it?
   */

  private final boolean endAssociation()
  {
    boolean doEnd = true;

    if (_theTransaction != null)
    {
      if (_theTransaction.getXAResourceState(_theXAResource) == TxInfo.NOT_ASSOCIATED)
      {
        // end has been called so we don't need to do it again!
       
        doEnd = false;
      }
    }
    else
      doEnd = false; // recovery mode

    return doEnd;
  }

  protected XAResource _theXAResource;

  private RecoverableXAConnection _recoveryObject;
  private Xid _tranID;
  private boolean _prepared;
  private boolean _committed;
  private boolean _valid;
  private int _heuristic;
  private ObjectStore _objStore;
  private Uid _theUid;
  private org.omg.CosTransactions.Resource _theReference;
  private org.omg.CosTransactions.RecoveryCoordinator _recoveryCoordinator;
  private TransactionImple _theTransaction;

  // cached variables

  private String _cachedUidStringForm;
 
  private static boolean _rollbackOptimization = false;

  static
  {
    String optimization = jtaPropertyManager.propertyManager.getProperty(
        Environment.JTA_TM_IMPLEMENTATION, "OFF");

    if (optimization.equals("ON"))
      _rollbackOptimization = true;
  }

}
TOP

Related Classes of com.arjuna.ats.internal.jta.resources.jts.orbspecific.XAResourceRecord

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.