docs: private EJBException mapException(Throwable ex)
      {
          EJBException ejbex;
          boolean createdEx = true;
          Exception causeEx = null;
  
          if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled())
              Tr.entry(tc, "mapException: " + ex);
  
          // -----------------------------------------------------------------------
          // First, obtain the message text used to create the exception.
          //
          // If the message being mapped ends up being 'replaced', then the
          // replacement should have the same message text.
          //
          // getBaseMessage insures that the message text does NOT include the
          // name of the exception class, nor any chained exception text.
          // -----------------------------------------------------------------------
          String message = ExceptionUtil.getBaseMessage(ex);
  
          // -----------------------------------------------------------------------
          // Second, get the cause of the exception being mapped.
          //
          // findCause will remove any internal EJB Container exceptions from
          // the exception chain.
          //
          // Also, if the cause is not a subclass of Throwable, then it must
          // be 'wrapped' in an Exception, as EJBException does not allow
          // Throwable on any of its constructors.  However, the 'cause' on
          // throwable will still be set to the intended cause.  This will allow
          // getCause() to work as expected, even though EJBException does not
          // support Throwable.
          // -----------------------------------------------------------------------
          Throwable cause = ExceptionUtil.findCause(ex);
  
          if (cause != null)
          {
              if (cause instanceof Exception)
              {
                  causeEx = (Exception) cause;
              }
              else
              {
                  causeEx = new Exception("See nested Throwable", cause);
              }
          }
  
          // -----------------------------------------------------------------------
          // Next, map Throwable to an EJBException to return.
          //
          // These mappings are prescribed by the EJB & ActivitySession specs.
          //
          // Note: When adding new mappings, do NOT call 'initCause', as that
          //       will be performed below, and handles the fact that EJBException
          //       may not be created with a throwable.
          //
          // Caution: Do NOT look at the cause to perform mapping. If an exception
          //          is 'wrapped' in another exception, it likely was wrapped
          //          by another EJB method call, and a failure from a downstream
          //          method call should NOT be treated the same here.
          //          If it appears the cause needs to be examined, then instead,
          //          find the code that wrapped the cause, and stop wrapping it.
          // -----------------------------------------------------------------------
          if (ex instanceof CSIException)
          {
              ejbex = mapCSIException((CSIException) ex, causeEx, cause);
              createdEx = false;
          }
          else if (ex instanceof NoSuchObjectException)
          {
              ejbex = new NoSuchEJBException(message, causeEx);
          }
          else if (ex instanceof EJBStoppedException) // d350987
          {
              // Don't just replace the EJBStoppedException, but nest it as the
              // cause so applications may check for it.
              cause = ex;
              causeEx = (Exception) ex;
              ejbex = new NoSuchEJBException((String) null, causeEx);
          }
          else if (ex instanceof TransactionRequiredException)
          {
              ejbex = new EJBTransactionRequiredException(message); // d395666
          }
          else if (ex instanceof TransactionRolledbackException)
          {
              ejbex = new EJBTransactionRolledbackException(message, causeEx); // d395666
          }
          else if (ex instanceof InvalidTransactionException)
          {
              ejbex = new InvalidTransactionLocalException(message, causeEx);
          }
          else if (ex instanceof AccessException)
          {
              ejbex = new EJBAccessException(message); // d395666
          }
          //        else if (ex instanceof ActivityRequiredException)
  //        {
  //            ejbex = new ActivityRequiredLocalException(message, causeEx);
  //        }
  //        else if (ex instanceof InvalidActivityException)
  //        {
  //            ejbex = new InvalidActivityLocalException(message, causeEx);
  //        }
  //        else if (ex instanceof ActivityCompletedException)
  //        {
  //            ejbex = new ActivityCompletedLocalException(message, causeEx);
  //        }
          else if (ex instanceof BeanNotReentrantException)
          {
              BeanNotReentrantException bnre = (BeanNotReentrantException) ex;
              if (bnre.isTimeout())
              {
                  // EJB 3.1 has defined an exception for this purpose.      d653777.1
                  ejbex = new ConcurrentAccessTimeoutException(message);
              }
              else
              {
                  // EJB 3.0 has defined an exception for this purpose.      d366807.6
                  ejbex = new ConcurrentAccessException(message, causeEx);
              }
          }
          else
          {
              // --------------------------------------------------------------------
              // All other exceptions are just be mapped to an EJBException.
              //
              // If the exception is an EJBException, it will just be returned
              // (with the throwable cause filled in), else the exception will
              // just be wrapped in an EJBException, with the stack and cause
              // set appropriately.
              // --------------------------------------------------------------------
              ejbex = ExceptionUtil.EJBException(ex);
              createdEx = false;
          }
  
          // -----------------------------------------------------------------------
          // Finally, EJBException doesn't normally set the cause on Throwable,
          // so let's do that to be nice :-) and clear the stack of the
          // EJBException, as it is mostly confusing and causes very
          // similar stacks to be printed out twice.
          //
          // Note that this code, especially clearing of the stack, is only
          // performed for EJBExceptions that were created in this method.
          // EJBExceptions that will just be propagated should NOT have the
          // stack cleared, as they were likely thrown by the customer.
          // -----------------------------------------------------------------------
          if (createdEx)
          {
              if (causeEx != null)
              {
                  // Intentionally, the 'cause' is set as the 'cause', and not
                  // 'causeEx'.  They will be the same, except when 'causeEx'
                  // is just a silly wrapper around a Throwable.
                  //
                  // Geronimo EJBException.getCause returns getCausedbyException, so
                  // we do not expect this code to be used.                     F53643
                  if (ejbex.getCause() == null) { //F743-16279
                      // Use the 'real' cause here, not the possibly wrapped one.
                      ejbex.initCause(cause);
                  }
              }
              else
              {
                  ejbex.setStackTrace(ex.getStackTrace());
              }
          }
  
          if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled())
              Tr.exit(tc, "mapException returning: " + ejbex);
  
          return ejbex;
      }