docs: public final void end(int flag) throws XAException
      {
          if (tc.isEntryEnabled()) Tr.entry(tc, "end", new Object[]{_resource, Util.printFlag(flag), printState(_state)});
          if (tcSummary.isDebugEnabled()) Tr.debug(tcSummary, "xa_end", new Object[]{this, "flags = " + Util.printFlag(flag)});
  
          int newstate;
          int rc = -1;  // not an XA RC
  
          switch (flag)
          {
              case XAResource.TMSUCCESS:
                  // xa_end(SUCCESS) on a suspended branch can be ended without a resumed start
                  if (_state == ACTIVE || _state == SUSPENDED)
                  {
                      newstate = IDLE;
                  }
                  else //  NOT_ASSOCIATED || ROLLBACK_ONLY || IDLE || FAILED
                  {
                      if (tc.isEntryEnabled()) Tr.exit(tc, "end");
                      return;
                  }
                  break;
              case XAResource.TMFAIL:
                  // If the branch has already been marked rollback only then we do not need to
                  // re-issue xa_end as we will get another round of xa_rb* flows.
                  // If its idle, we dont need to issue xa_end
                  if (_state == ROLLBACK_ONLY || _state == IDLE || _state == FAILED)
                  {
                      if (tc.isEntryEnabled()) Tr.exit(tc, "end");
                      return;
                  }
                  newstate = ROLLBACK_ONLY;
                  break;
              case XAResource.TMSUSPEND:
                  if (!_supportSuspend)
                  {
                      if (tc.isEventEnabled()) Tr.event(tc, "TMSUSPEND is not supported.");
                      throw new XAException(XAException.XAER_INVAL);
                  }
                  else if (_state == FAILED || _state == IDLE)
                  {
                      if (tc.isEventEnabled()) Tr.event(tc, "TMSUSPEND in invalid state.");
                      throw new XAException(XAException.XAER_PROTO);
                  }
                  else if (_state != ACTIVE)
                  {
                      if (tc.isEntryEnabled()) Tr.exit(tc, "end");
                      return;
                  }
                  newstate = SUSPENDED;
                  break;
              default:
                  Tr.warning(tc, "WTRN0023_INVALID_XAEND_FLAG", Util.printFlag(flag));
                  throw new XAException(XAException.XAER_INVAL);
          }
  
          try
          {
              _resource.end(_xid, flag);
              rc = XAResource.XA_OK;
  
              //
              // update XAResource's state 
              //
              _state = newstate;
          }
          catch (XAException xae)
          {
              processXAException("end", xae);
              rc = xae.errorCode;
  
              if (xae.errorCode >= XAException.XA_RBBASE && xae.errorCode <= XAException.XA_RBEND)
                  _state = ROLLBACK_ONLY;
              else
                  _state = FAILED;
  
              throw xae;
          }
          catch (Throwable t)
          { 
              _state = FAILED;
              processThrowable("end", t);
          }
          finally
          {
              if (tc.isEntryEnabled()) Tr.exit(tc, "end");
              if (tcSummary.isDebugEnabled()) Tr.debug(tcSummary, "xa_end result:", XAReturnCodeHelper.convertXACode(rc));
          }
      }