docs: @Override
      public final synchronized void rollback(ContainerTx tx)
                      throws RemoteException
      {
          final boolean isTraceOn = TraceComponent.isAnyTracingEnabled();
          if (isTraceOn && tc.isEntryEnabled())
              Tr.entry(tc, "rollback: " + StateStrs[state], tx);
  
          if (removed) {
              if (isTraceOn && tc.isEntryEnabled())
                  Tr.exit(tc, "rollback: removed");
              return;
          }
  
          switch (state)
          {
          // These are the "normal" rollback points
              case COMMITTING_OUTSIDE_METHOD:
              case TX_METHOD_READY:
              case AFTER_BEGIN: // d159152
  
                  setState(METHOD_READY);
                  break;
  
              // We also could be rolledback "unexpectedly" at these points
              case TX_IN_METHOD:
              case REMOVING: // d159152
  
                  setState(IN_METHOD);
                  break;
  
              // Rollback in the DESTROYED state can/should only occur if there
              // was an exception from the customer beforeCompletion method.
              // Otherwise, the bean should have been delisted.                d160910
              case DESTROYED:
                  if (ivBeforeCompletion != null || sessionSync != null)
                  {
                      if (isTraceOn && tc.isDebugEnabled())
                          Tr.debug(tc, "SessionSynchronization.beforeCompletion exception?");
                  }
                  else
                  {
                      if (isTraceOn && tc.isEntryEnabled())
                          Tr.exit(tc, "rollback: InvalidBeanOStateException: " +
                                      StateStrs[state]);
                      throw new InvalidBeanOStateException(StateStrs[state],
                                      "COMMITTING_OUTSIDE_METHOD | " +
                                                      "TX_METHOD_READY | TX_IN_METHOD");
                  }
                  break;
  
              default:
                  if (isTraceOn && tc.isEntryEnabled())
                      Tr.exit(tc, "rollback: InvalidBeanOStateException: " +
                                  StateStrs[state]);
                  throw new InvalidBeanOStateException(StateStrs[state],
                                  "COMMITTING_OUTSIDE_METHOD | " +
                                                  "TX_METHOD_READY | TX_IN_METHOD");
  
          }
  
          if (tx.ivRemoveBeanO == this)
          {
              completeRemoveMethod(tx); // d647928
          }
          else
          {
              // Perform normal afterCompletion processing.... calling
              // afterCompletion if present.
              // Save the above determined state and set to AFTER_COMPLETION for
              // the duration of the afterCompletion callback.                d159152
              int savedState = state;
              setState(AFTER_COMPLETION);
  
              // Session Synchronization AfterCompletion needs to be called if either
              // the annotation (or XML) was specified or the bean implemented
              // the interface and a global transaction is active.        F743-25855
              if ((ivAfterCompletion != null || sessionSync != null) &&
                  tx.isTransactionGlobal())
              {
                  EJBThreadData threadData = EJSContainer.getThreadData();
  
                  threadData.pushContexts(this);
                  try
                  {
                      if (ivAfterCompletion != null) {
                          invokeSessionSynchMethod(ivAfterCompletion, new Object[] { false });
                      } else {
                          sessionSync.afterCompletion(false);
                      }
                  } finally
                  {
                      threadData.popContexts();
                  }
              }
  
              setState(savedState); // d159152
          }
  
          // currentTx is now reset in atCommit/atRollback AFTER the final pin
          // is undone.                                                      d258770
          // currentTx = null;                                            // PQ99986
  
          if (isTraceOn && tc.isEntryEnabled())
              Tr.exit(tc, "rollback: " + StateStrs[state]);
      }