Package com.arjuna.ats.internal.jta.resources.arjunacore

Source Code of com.arjuna.ats.internal.jta.resources.arjunacore.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 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) 1998, 1999, 2000, 2001,
*
* Arjuna Solutions Limited,
* Newcastle upon Tyne,
* Tyne and Wear,
* UK.
*
* $Id: XAResourceRecord.java 2342 2006-03-30 13:06:17Z  $
*/

package com.arjuna.ats.internal.jta.resources.arjunacore;

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.RecoverableXAConnection;
import com.arjuna.ats.jta.xa.XidImple;
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.common.util.logging.*;

import com.arjuna.ats.internal.jta.transaction.arjunacore.TransactionImple;
import com.arjuna.ats.internal.jta.xa.TxInfo;
import com.arjuna.ats.internal.jta.resources.XAResourceErrorHandler;
import com.arjuna.ats.internal.jta.recovery.arjunacore.XARecoveryModule;

import com.arjuna.ats.arjuna.ObjectType;
import com.arjuna.ats.arjuna.coordinator.AbstractRecord;
import com.arjuna.ats.arjuna.coordinator.TwoPhaseOutcome;
import com.arjuna.ats.arjuna.coordinator.RecordType;
import com.arjuna.ats.arjuna.common.*;
import com.arjuna.ats.arjuna.state.*;
import com.arjuna.ats.arjuna.gandiva.ClassName;
import com.arjuna.ats.arjuna.recovery.RecoveryModule;
import com.arjuna.ats.arjuna.recovery.RecoveryManager;

import java.util.Vector;
import java.util.Enumeration;

import java.io.*;

import javax.transaction.xa.Xid;
import javax.transaction.xa.XAResource;

import javax.transaction.xa.XAException;

/**
* @author Mark Little (mark_little@hp.com)
* @version $Id: XAResourceRecord.java 2342 2006-03-30 13:06:17Z  $
* @since JTS 1.2.4.
*/

public class XAResourceRecord extends AbstractRecord
{

  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.
   */

  public XAResourceRecord(TransactionImple tx, XAResource res, Xid xid,
      Object[] params)
  {
    super(new Uid(), null, ObjectType.ANDPERSISTENT);

    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;
    _heuristic = TwoPhaseOutcome.FINISH_OK;

    _theTransaction = tx;
  }

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

  public final Xid getXid()
  {
    return _tranID;
  }

  public Uid order()
  {
    if (_theXAResource instanceof StartXAResource)
      return START_XARESOURCE;
    else
    {
      if (_theXAResource instanceof EndXAResource)
        return END_XARESOURCE;
      else
        return super.order();
    }
  }

  public boolean propagateOnCommit()
  {
    return false; // cannot ever be nested!
  }

  public int typeIs()
  {
    return RecordType.JTA_RECORD;
  }

  public ClassName className()
  {
    return new ClassName("RecordType.JTA_RECORD");
  }

  public Object value()
  {
    return _theXAResource;
  }

  /**
   * @message com.arjuna.ats.internal.jta.resources.arjunacore.setvalue
   *          [com.arjuna.ats.internal.jta.resources.arjunacore.setvalue] {0}
   *          called illegally.
   */

  public void setValue(Object o)
  {
    if (jtaLogger.loggerI18N.isWarnEnabled())
    {
      jtaLogger.loggerI18N
          .warn(
              "com.arjuna.ats.internal.jta.resources.arjunacore.setvalue",
              new Object[]
              { "XAResourceRecord::set_value()" });
    }
  }

  public int nestedAbort()
  {
    return TwoPhaseOutcome.FINISH_OK;
  }

  public int nestedCommit()
  {
    return TwoPhaseOutcome.FINISH_OK;
  }

  /*
   * XA is not subtransaction aware.
   */

  public int nestedPrepare()
  {
    return TwoPhaseOutcome.PREPARE_OK; // do nothing
  }

  /**
   * @message com.arjuna.ats.internal.jta.resources.arjunacore.preparenulltx
   *          [com.arjuna.ats.internal.jta.resources.arjunacore.preparenulltx]
   *          {0} - null transaction!
   * @message com.arjuna.ats.internal.jta.resources.arjunacore.preparefailed
   *       [com.arjuna.ats.internal.jta.resources.arjunacore.preparefailed]
   *       {0} - prepare failed with exception {1}
   */

  public int topLevelPrepare()
  {
    if (jtaLogger.logger.isDebugEnabled())
    {
      jtaLogger.logger.debug(DebugLevel.FUNCTIONS,
          VisibilityLevel.VIS_PUBLIC,
          com.arjuna.ats.jta.logging.FacilityCode.FAC_JTA,
          "XAResourceRecord.topLevelPrepare for " + _tranID);
    }

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

      return TwoPhaseOutcome.PREPARE_READONLY;
    }

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

      removeConnection();

      return TwoPhaseOutcome.PREPARE_NOTOK;
    }

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

      _prepared = true;

      if (_theXAResource.prepare(_tranID) == XAResource.XA_RDONLY)
      {
        return TwoPhaseOutcome.PREPARE_READONLY;
      }
      else
        return TwoPhaseOutcome.PREPARE_OK;
    }
    catch (XAException e1)
    {
      if (jtaLogger.loggerI18N.isWarnEnabled())
      {
        jtaLogger.loggerI18N
            .warn(
                "com.arjuna.ats.internal.jta.resources.arjunacore.preparefailed",
                new Object[]
                { "XAResourceRecord.prepare", 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))
        return TwoPhaseOutcome.HEURISTIC_HAZARD;
     
      return TwoPhaseOutcome.PREPARE_NOTOK;
    }
    catch (Exception e2)
    {
      if (jtaLogger.loggerI18N.isWarnEnabled())
      {
        jtaLogger.loggerI18N
            .warn(
                "com.arjuna.ats.internal.jta.resources.arjunacore.preparefailed",
                new Object[]
                { "XAResourceRecord.prepare", e2 });
      }

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

      return TwoPhaseOutcome.PREPARE_NOTOK;
    }
  }

  /**
   * @message com.arjuna.ats.internal.jta.resources.arjunacore.rollbacknulltx
   *          [com.arjuna.ats.internal.jta.resources.arjunacore.rollbacknulltx]
   *          {0} - null transaction!
   * @message com.arjuna.ats.internal.jta.resources.arjunacore.rollbackxaerror
   *          [com.arjuna.ats.internal.jta.resources.arjunacore.rollbackxaerror]
   *          {0} - xa error {1}
   */

  public int topLevelAbort()
  {
    if (jtaLogger.logger.isDebugEnabled())
    {
      jtaLogger.logger.debug(DebugLevel.FUNCTIONS,
          VisibilityLevel.VIS_PUBLIC,
          com.arjuna.ats.jta.logging.FacilityCode.FAC_JTA,
          "XAResourceRecord.topLevelAbort for " + _tranID);
    }

    if (!_valid)
      return TwoPhaseOutcome.FINISH_ERROR;

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

      return TwoPhaseOutcome.FINISH_OK;
    }

    if (_tranID == null)
    {
      if (jtaLogger.loggerI18N.isWarnEnabled())
      {
        jtaLogger.loggerI18N
            .warn(
                "com.arjuna.ats.internal.jta.resources.arjunacore.rollbacknulltx",
                new Object[]
                { "XAResourceRecord.rollback" });
      }

      return TwoPhaseOutcome.FINISH_ERROR;
    }
    else
    {
      if (_theXAResource != null)
      {
        if (_heuristic != TwoPhaseOutcome.FINISH_OK)
          return _heuristic;

        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.arjunacore.rollbackxaerror",
                      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:
              return TwoPhaseOutcome.HEURISTIC_HAZARD;
            case XAException.XA_HEURCOM:
              return TwoPhaseOutcome.HEURISTIC_COMMIT;
            case XAException.XA_HEURMIX:
              return TwoPhaseOutcome.HEURISTIC_MIXED;
            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:
              break;
            default:
              return TwoPhaseOutcome.FINISH_ERROR;
            }
          }
        }
        catch (Exception e2)
        {
          e2.printStackTrace();

          return TwoPhaseOutcome.FINISH_ERROR;
        }
        finally
        {
          if (!_prepared)
            removeConnection();
        }
      }
      else
        return TwoPhaseOutcome.FINISH_ERROR;
    }

    return TwoPhaseOutcome.FINISH_OK;
  }

  /**
   * @message com.arjuna.ats.internal.jta.resources.arjunacore.commitnulltx
   *          [com.arjuna.ats.internal.jta.resources.arjunacore.commitnulltx]
   *          {0} - null transaction!
   * @message com.arjuna.ats.internal.jta.resources.arjunacore.commitxaerror
   *          [com.arjuna.ats.internal.jta.resources.arjunacore.commitxaerror]
   *          {0} - xa error {1}
   */

  public int topLevelCommit()
  {
    if (jtaLogger.logger.isDebugEnabled())
    {
      jtaLogger.logger.debug(DebugLevel.FUNCTIONS,
          VisibilityLevel.VIS_PUBLIC,
          com.arjuna.ats.jta.logging.FacilityCode.FAC_JTA,
          "XAResourceRecord.topLevelCommit for " + _tranID);
    }

    if (!_prepared)
      return TwoPhaseOutcome.NOT_PREPARED;

    if (_tranID == null)
    {
      if (jtaLogger.loggerI18N.isWarnEnabled())
      {
        jtaLogger.loggerI18N
            .warn(
                "com.arjuna.ats.internal.jta.resources.arjunacore.commitnulltx",
                new Object[]
                { "XAResourceRecord.commit" });
      }

      return TwoPhaseOutcome.FINISH_ERROR;
    }
    else
    {
      if (_theXAResource != null)
      {
        if (_heuristic != TwoPhaseOutcome.FINISH_OK)
          return _heuristic;

        try
        {
          _theXAResource.commit(_tranID, false);
        }
        catch (XAException e1)
        {
          if (notAProblem(e1, true))
          {
            // some other thread got there first (probably)
          }
          else
          {
            if (jtaLogger.loggerI18N.isWarnEnabled())
            {
              jtaLogger.loggerI18N
                  .warn(
                      "com.arjuna.ats.internal.jta.resources.arjunacore.commitxaerror",
                      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:
              return TwoPhaseOutcome.HEURISTIC_HAZARD;
            case XAException.XA_HEURCOM:  // what about forget? OTS doesn't support this code here.
              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:
              return TwoPhaseOutcome.HEURISTIC_ROLLBACK;
            case XAException.XA_HEURMIX:
              return TwoPhaseOutcome.HEURISTIC_MIXED;
            case XAException.XAER_NOTA:
            case XAException.XAER_PROTO:
              break;
            case XAException.XA_RETRY:
              return TwoPhaseOutcome.FINISH_ERROR;
            case XAException.XAER_INVAL:
            case XAException.XAER_RMFAIL: // resource manager
                            // failed, did it
                            // rollback?
              return TwoPhaseOutcome.HEURISTIC_HAZARD;
            default:
              return TwoPhaseOutcome.HEURISTIC_HAZARD;
            }
          }
        }
        catch (Exception e2)
        {
          return TwoPhaseOutcome.FINISH_ERROR;
        }
        finally
        {
          removeConnection();
        }
      }
      else
        return TwoPhaseOutcome.FINISH_ERROR;
    }

    return TwoPhaseOutcome.FINISH_OK;
  }

  /**
   * 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);
  }

  public int nestedOnePhaseCommit()
  {
    return TwoPhaseOutcome.FINISH_ERROR;
  }

  /**
   * 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.arjunacore.opcnulltx
   *          [com.arjuna.ats.internal.jta.resources.arjunacore.opcnulltx] {0} -
   *          null transaction!
   * @message com.arjuna.ats.internal.jta.resources.arjunacore.opcerror
   *          [com.arjuna.ats.internal.jta.resources.arjunacore.opcerror] {0}
   *          caught: {1}
   */

  public int topLevelOnePhaseCommit()
  {
    if (jtaLogger.logger.isDebugEnabled())
    {
      jtaLogger.logger.debug(DebugLevel.FUNCTIONS,
          VisibilityLevel.VIS_PUBLIC,
          com.arjuna.ats.jta.logging.FacilityCode.FAC_JTA,
          "XAResourceRecord.topLevelOnePhaseCommit for " + _tranID);
    }

    if (_tranID == null)
    {
      if (jtaLogger.loggerI18N.isWarnEnabled())
      {
        jtaLogger.loggerI18N
            .warn(
                "com.arjuna.ats.internal.jta.resources.arjunacore.opcnulltx",
                new Object[]
                { "XAResourceRecord.1pc" });
      }

      return TwoPhaseOutcome.FINISH_ERROR;
    }
    else
    {
      if (_theXAResource != null)
      {
        if (_heuristic != TwoPhaseOutcome.FINISH_OK)
          return _heuristic;

        try
        {
          /*
           * TODO in Oracle the end is not needed. Is this common
           * across other RMs?
           */
         
          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))
          {
            return TwoPhaseOutcome.FINISH_ERROR;
          }

          switch (e1.errorCode)
          {
          case XAException.XA_HEURHAZ:
          case XAException.XA_HEURMIX:
            return TwoPhaseOutcome.HEURISTIC_HAZARD;
          case XAException.XA_HEURCOM:
            forget() ;
            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:
            forget() ;
            return TwoPhaseOutcome.FINISH_ERROR;
          case XAException.XAER_NOTA:
          case XAException.XAER_PROTO:
            break;
          case XAException.XAER_INVAL:
          case XAException.XAER_RMFAIL: // resource manager failed,
                          // did it rollback?
            return TwoPhaseOutcome.FINISH_ERROR;
            //             return TwoPhaseOutcome.HEURISTIC_HAZARD;
          default:
            return TwoPhaseOutcome.FINISH_ERROR;
          //             return TwoPhaseOutcome.HEURISTIC_ROLLBACK;
          }
        }
        catch (Exception e2)
        {
          if (jtaLogger.loggerI18N.isWarnEnabled())
          {
            jtaLogger.loggerI18N
                .warn(
                    "com.arjuna.ats.internal.jta.resources.arjunacore.opcerror",
                    new Object[]
                    { "XAResourceRecord.commit_one_phase",
                        e2 });
          }

          return TwoPhaseOutcome.FINISH_ERROR;
        }
        finally
        {
          removeConnection();
        }
      }
      else
        return TwoPhaseOutcome.FINISH_ERROR;
    }

    return TwoPhaseOutcome.FINISH_OK;
  }

  public boolean forgetHeuristic()
  {
    if (jtaLogger.logger.isDebugEnabled())
    {
      jtaLogger.logger.debug(DebugLevel.FUNCTIONS,
          VisibilityLevel.VIS_PUBLIC,
          com.arjuna.ats.jta.logging.FacilityCode.FAC_JTA,
          "XAResourceRecord.forget for " + _tranID);
    }

    forget() ;

    removeConnection();

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

  /*
   * Independant recovery cannot occur. Must be driven by the recovery of the
   * local transaction, i.e., top-down recovery.
   */

  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");
    }

    return XARecoveryResource.FAILED_TO_RECOVER;
  }

  public static AbstractRecord create()
  {
    return new XAResourceRecord();
  }

  public static void remove(AbstractRecord toDelete)
  {
    toDelete = null;
  }

    /**
     * @message com.arjuna.ats.internal.jta.resources.arjunacore.savestate
     *          [com.arjuna.ats.internal.jta.resources.arjunacore.savestate]
     *          Could not serialize a Serializable XAResource!
     */

  public boolean save_state(OutputObjectState os, int t)
  {
    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);

          // don't allow the packing of a null resource

          if (_theXAResource == null)
            throw new NotSerializableException();

          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.arjunacore.savestate");
          }
            }
        }
      }
      else
      {
        os.packInt(RecoverableXAConnection.AUTO_RECOVERY);
        os.packString(_recoveryObject.getClass().getName());

        _recoveryObject.packInto(os);
      }

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

      res = false;
    }

    if (res)
      res = res && super.save_state(os, t);

    return res;
  }

  /**
   * @message com.arjuna.ats.internal.jta.resources.arjunacore.restorestate
   *          [com.arjuna.ats.internal.jta.resources.arjunacore.restorestate]
   *          Exception on attempting to restore XAResource
   * @message com.arjuna.ats.internal.jta.resources.arjunacore.norecoveryxa
   *          [com.arjuna.ats.internal.jta.resources.arjunacore.norecoveryxa]
   *          Could not find new XAResource to use for recovering non-serializable XAResource {0}
   */

  public boolean restore_state(InputObjectState os, int t)
  {
    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.arjunacore.restorestate",
                      ex);
            }
           
            return false;
          }
        }
        else
        {
          /*
           * Lookup new XAResource via XARecoveryModule if possible.
           */

          _theXAResource = getNewXAResource();
         
          if (_theXAResource == null)
          {
            jtaLogger.loggerI18N.warn("com.arjuna.ats.internal.jta.resources.arjunacore.norecoveryxa",
                new Object[]{_tranID});
          }
        }
      }
      else
      {
        String creatorName = os.unpackString();
        Class c = Thread.currentThread().getContextClassLoader()
            .loadClass(creatorName);

        _recoveryObject = (RecoverableXAConnection) c.newInstance();

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

        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);
        }
      }

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

      res = false;
    }

    if (res)
      res = res && super.restore_state(os, t);

    return res;
  }

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

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

  public boolean doSave()
  {
    return true;
  }

  public void merge(AbstractRecord a)
  {
  }

  public void alter(AbstractRecord a)
  {
  }

  public boolean shouldAdd(AbstractRecord a)
  {
    return false;
  }

  public boolean shouldAlter(AbstractRecord a)
  {
    return false;
  }

  public boolean shouldMerge(AbstractRecord a)
  {
    return false;
  }

  public boolean shouldReplace(AbstractRecord a)
  {
    return false;
  }

  protected XAResourceRecord()
  {
    super();

    _theXAResource = null;
    _recoveryObject = null;
    _tranID = null;
    _prepared = true;
    _heuristic = TwoPhaseOutcome.FINISH_OK;
    _valid = true;
    _theTransaction = null;
  }

  protected XAResourceRecord(Uid u)
  {
    super(u, null, ObjectType.ANDPERSISTENT);

    _theXAResource = null;
    _recoveryObject = null;
    _tranID = null;
    _prepared = true;
    _heuristic = TwoPhaseOutcome.FINISH_OK;
    _valid = true;
    _theTransaction = null;
  }

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

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

  /**
   * This routine finds the new XAResource for the transaction that used the
   * old resource we couldn't serialize. It does this by looking up the
   * XARecoveryModule in the recovery manager and asking it for the
   * XAResource. The recovery manager will then look through its list of
   * registered XARecoveryResource implementations for the appropriate
   * instance. If the XARecoveryModule hasn't been initialised yet then this
   * routine will fail, but on the next scan it should work.
   */

  private final XAResource getNewXAResource()
  {
    RecoveryManager recMan = RecoveryManager.manager();
    Vector recoveryModules = recMan.getModules();

    if (recoveryModules != null)
    {
      Enumeration modules = recoveryModules.elements();

      while (modules.hasMoreElements())
      {
        RecoveryModule m = (RecoveryModule) modules.nextElement();

        if (m instanceof XARecoveryModule)
        {
          return ((XARecoveryModule) m).getNewXAResource(_tranID);
        }
      }
    }

    return null;
  }

  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;
  }

  /*
   * 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 _valid;
  private int _heuristic;
  private TransactionImple _theTransaction;

  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.arjunacore.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.