/**
   * This method invoked rollback on the Resource that is passed as a parameter.
   *
   * <p>This procedure may be called as the main procedure of a new thread, which must be done for
   * remote Resource objects during resync to avoid the possibility of deadlock during resync.
   *
   * <p>It is called directly when the Resource is not a proxy.
   *
   * @param res The Resource to be rolled back.
   * @return
   * @see
   */
  void rollbackOrphan(Resource res) {

    try {
      res.rollback();
    } catch (Throwable exc) {

      // If the rollback raised a heuristic exception, it can
      // only be reported in a message as it will never reach
      // the Coordinator.

      if (exc instanceof HeuristicCommit
          || exc instanceof HeuristicMixed
          || exc instanceof HeuristicHazard) {
        _logger.log(Level.WARNING, "jts.heuristic_exception", exc.toString());
      } else {
      }
    }

    // We must release the proxy now.

    res._release();
  }
  // same as replay_completion(res) : added for delegated recovery support
  public Status replay_completion(Resource res, String logPath) throws NotPrepared {

    if (_logger.isLoggable(Level.FINE)) {
      _logger.logp(
          Level.FINE,
          "RecoveryCoordinatorImpl",
          "replay_completion()",
          "replay_completion on Resource:" + res);
    }

    Status result = Status.StatusRolledBack;

    CoordinatorImpl coord = DelegatedRecoveryManager.getCoordinator(globalTID, logPath);
    if (coord != null) {
      try {
        result = coord.get_status();
      } catch (SystemException exc) {
      }
    }

    switch (result.value()) {

        /*
         * If the transaction is still active, raise the NotPrepared
         * exception. The Coordinator must be marked rollback-only at
         * this point because we cannot allow the transaction to
         * complete if a participant has failed.
         */

      case Status._StatusActive:
      case Status._StatusMarkedRollback:
        try {
          coord.rollback_only();
        } catch (Throwable exc) {
        }

        throw new NotPrepared();

        /*
         * If the transaction is prepared, the caller must wait for the
         * Coordinator to tell it what to do, so return an unknown status, and
         * do nothing.  Note that if this Coordinator is sitting waiting for
         * its superior, this could take a int time.
         */

      case Status._StatusPrepared:
        result = Status.StatusUnknown;
        break;

        /*
         * If the transaction has been committed, the caller will receive
         * a commit.
         *
         * GDH If the transaction is commiting then we pass this on
         * to the caller. This state (added in OTS 1.1 means that
         * TopCoordinator.recover must now accept the COMMITTING state.
         */

      case Status._StatusCommitting:
        // MODIFICATION (Ram Jeyaraman) commented out the code below,
        // since a StatusCommitting will be upgraded to Committed in
        // the subordinate.
        /*
        // (Ram Jeyaraman) let the subordinate wait, and allow the root
        // finish driving the commit.
        result = Status.StatusUnknown;
        */
        break;

      case Status._StatusCommitted:
        break;

      case Status._StatusRolledBack:

        // If the transaction has been rolled back, and there is
        // no Coordinator for the transaction, we must invoke rollback
        // directly, as it will not be done otherwise.  However for
        // proxies, this rollback cannot be done from this thread as
        // it would cause deadlock in the server requesting resync.

        if (coord == null) {

          if (!Configuration.getProxyChecker().isProxy(res)) {
            rollbackOrphan(res);
          } else {

            // We must pass a duplicate of the proxy to the
            // rollback thread because this proxy will be destroyed
            // when the replay_completion request returns
            // to the remote server.

            try {
              OrphanRollbackThread rollbackThread =
                  new OrphanRollbackThread(this, (Resource) res._duplicate());
              rollbackThread.start();
            } catch (SystemException exc) {
            }
          }
        }

        break;

        /*
         * In any other situation, assume that the transaction has been rolled
         * back. As there is a Coordinator, it will direct the Resource to roll
         * back.
         */

      default:
        result = Status.StatusRolledBack;
    }

    return result;
  }