docs: public int distributePrepare(boolean subordinate, boolean optimise)
                      throws RollbackException, SystemException, HeuristicMixedException,
                      HeuristicHazardException, HeuristicRollbackException {
          if (tc.isEntryEnabled())
              Tr.entry(tc, "distributePrepare", new Object[] { this, subordinate, optimise });
  
          _diagnosticsRequired = false;
  
          _prepareResult = XA_RDONLY;
  
          try {
              //
              // LIDB1673.22/PQ72718
              // If we are a subordinate and we have a OnePhaseResource enlisted, then we cannot prepare
              // the 1PC resource, so rollback the transaction.  Note: if we are a "real" subordinate but
              // have received a C1P from the superior, the subordinate flag is set to false, ie we appear
              // as a superior for voting and logging as the superior has handed overall responsibility.
              //
              if (subordinate && (_onePhaseResourceEnlisted != null)) {
                  Tr.error(tc, "WTRN0064_SUBORDINATE_COMMIT_OF_1PC_RESOURCE");
  
                  if (tc.isEventEnabled())
                      Tr.event(tc, "Subordinate contains 1PC resource, rolling back transaction");
                  if (tc.isEntryEnabled())
                      Tr.exit(tc, "distributePrepare", "RollbackException");
                  throw new RollbackException();
              }
  
              final long startTime = System.currentTimeMillis();
  
              // Prepare the async resources if needed
              // Two calls are needed before and after preparing resources to enable ordering if required
              if (gotAsyncResources()) {
                  prePreparePrepareAsyncResources();
                  prePrepareGetAsyncPrepareResults(startTime);
              }
  
              // If we have priority defined resources, sort the list prior to prepare
              if (_gotPriorityResourcesEnlisted) {
                  // Take the one phase resource out of the list while we sort
                  if (_onePhaseResourceEnlisted != null)
                      _resourceObjects.remove(0);
                  sortPreparePriorityResources();
                  if (_onePhaseResourceEnlisted != null)
                      _resourceObjects.add(0, _onePhaseResourceEnlisted);
              }
  
              // Browse through the participants, preparing them, and obtain a consolidated
              // result.  We should stop after the first rollback vote.  If there is only a
              // single resource that remains we issue a commit_one_phase.  If only one resource
              // votes commit, commit is issued immediately with no logging.
              // If there are no Resource references, return the read-only vote.
              for (int i = _resourceObjects.size(); --i >= 0;) {
                  final JTAResource currResource = _resourceObjects.get(i);
  
                  if ((i == 0)
                      && (_okVoteCount == 0)
                      && (optimise) // (!subordinate)
                      && !gotAsyncResources()
                      && (currResource instanceof ResourceSupportsOnePhaseCommit)
                      && (_onePhaseResourceEnlisted == null)) {
                      // This is the last resource to be processed (i==0), no other resources have voted to commit
                      // (okVoteCount==0), this node is in control of the transaction (!subordinate) and the resource
                      // supports processing of a one phase commit flow (instance of RSOPC). Under these conditions,
                      // we can drive a 1PC flow to the resource without any need to LPS logging.
  
                      try {
                          flowCommitOnePhase(false);
  
                          //
                          // Set return value to ONEPHASE so that the TransactionImpl knows
                          // we have optimized.
                          //
                          _prepareResult = ONE_PHASE_OPT;
                      } catch (RollbackException rbe) {
                          // No FFDC Code Needed.
  
                          // We must intercept a RollbackException and convert it into a ONE_PHASE_OPT_ROLLBACK
                          // return so that TransactionImpl knows that the only resource not to vote read only
                          // has been rolledback so there is no need to distribute rollback.
                          _prepareResult = ONE_PHASE_OPT_ROLLBACK;
                      } finally {
                          // Heuristic cases are thrown to caller
                          if (tc.isEntryEnabled())
                              Tr.exit(tc, "distributePrepare",
                                      (_prepareResult == ONE_PHASE_OPT ? "ONE_PHASE_OPT" :
                                                      (_prepareResult == ONE_PHASE_OPT_ROLLBACK ? "ONE_PHASE_OPT_ROLLBACK" : "HEURISTIC")));
                      }
  
                      return _prepareResult;
                  } else if ((i == 0) && (_onePhaseResourceEnlisted != null) && (!subordinate)) {
                      // Process OnePhaseResource later by call to commitLastAgent from TransactionImpl
                  } else {
                      final int currResult = prepareResource(currResource);
  
                      // Take an action depending on the participant's vote.
                      if (currResult == XAResource.XA_OK) {
                          //
                          // Update the resource state to prepared.
                          //
                          currResource.setResourceStatus(StatefulResource.PREPARED);
  
                          if (_prepareResult == XA_RDONLY) {
                              _prepareResult = XA_OK;
                          }
  
                          _okVoteCount++;
                      } else {
                          //
                          // Set the state of a participant that votes read-only to completed as it
                          // replies.  The consolidated vote does not change.
                          //
                          currResource.setResourceStatus(StatefulResource.COMPLETED);
                      }
  
                      // Check if the transaction has been marked rollback by operator interface
                      if (_transaction.getRollbackOnly()) {
                          final Throwable toThrow = new RollbackException();
                          if (tc.isEntryEnabled())
                              Tr.exit(tc, "distributePrepare", toThrow);
                          throw (RollbackException) toThrow;
                      }
                  }
              } // end for..
  
              // Get the asynchronous results
              if (gotAsyncResources()) {
                  postPreparePrepareAsyncResources();
                  postPrepareGetAsyncPrepareResults(startTime);
              }
  
              // Have we only had one XA_OK vote? If so we can commit the single resource without
              // writing any prepare information to the recovery log.
  
              if ((_okVoteCount == 1) && optimise && _onePhaseResourceEnlisted == null) {
                  if (tc.isDebugEnabled())
                      Tr.debug(tc, "Transaction contains one non-READ-ONLY Resource, attempting to Optimize.");
                  _prepareResult = ONE_PHASE_OPT;
                  distributeCommit();
              } else if (_okVoteCount > 0) {
                  // We have more than one prepared Resource so we can't optimize
                  // and must write to the recovery log as usual.  (Distributed Only)
                  logResources();
  
                  // Sort the resources now for z/OS logging.  Note this will update
                  // resource priorities for commitLastInPhase cases.
                  // Take the one phase resource out of the list while we sort
                  // as on z/OS we have not yet called commitlastAgent.
                  if (_onePhaseResourceEnlisted != null)
                      _resourceObjects.remove(0);
                  sortResources();
                  if (_onePhaseResourceEnlisted != null)
                      _resourceObjects.add(0, _onePhaseResourceEnlisted);
              }
          } finally {
              if (_diagnosticsRequired) {
                  logDiagnostics(JTAResourceBase.PREPARE_DIAGNOSTICS);
              }
          }
  
          if (tc.isEntryEnabled())
              Tr.exit(tc, "distributePrepare", XAReturnCodeHelper.convertXACode(_prepareResult));
          return _prepareResult;
      }