docs: public final void cleanup() throws ResourceException {
          final boolean isTraceOn = TraceComponent.isAnyTracingEnabled();
  
          if (isTraceOn && tc.isEntryEnabled())
              Tr.entry(this, tc, "cleanup");
  
          // Save the first exception to occur, continue processing, and throw it later.
          // This allows us to ensure all handles are dissociated and transactions are
          // rolled back, even if something fails early on in the cleanup processing.
          ResourceException firstX = null;
  
          if (inRequest && !isAborted())
              try {
                  inRequest = false;
                  mcf.jdbcRuntime.endRequest(sqlConn);
              } catch (SQLException x) {
                  if (!isAborted()) {
                      FFDCFilter.processException(x, getClass().getName(), "2682", this);
                      firstX = new DataStoreAdapterException("DSA_ERROR", x, getClass());
                  }
                  Tr.debug(tc, "Error during end request in cleanup.", x);
              }
  
          // According to the JCA 1.5 spec, all remaining handles must be invalidated on
          // cleanup.  This is achieved by closing the handles.  Dissociating the handles would
          // not be adequate because dissociated handles may be used again.  
          // Skip the closeHandles processing if there are no handles. 
  
          ResourceException handleX = numHandlesInUse < 1 ? null : closeHandles();
          if (handleX != null && firstX == null)
              firstX = handleX;
  
          try {
              cleanupTransactions(true); 
          } catch (ResourceException resX) {
              // No FFDC code needed; already done in cleanupTransactions method.
              if (firstX == null)
                  firstX = resX;
          }
  
          // Reset the thread id we are tracking for multithreaded access detection.  When the
          // ManagedConnection is handed out of the pool, it may be given to a different thread.
          threadID = null;
  
          // At this point, all of the most important stuff has been cleaned up.  Handles are
          // dissociated and transactions are rolled back.  Now we may throw any exceptions
          // which previously occurred.
  
          if (firstX != null) {
              if (isTraceOn && tc.isEntryEnabled()) 
                  Tr.exit(this, tc, "cleanup", firstX);
  
              throw firstX;
          }
  
          // Cleanup ManagedConnection and Connection states in a separate method. 
          cleanupStates();
  
          // Throw an exception if finalize is invoked and this ManagedConnection was never
          // destroyed. 
  
          if (fatalErrorCount == -1) 
          {
              ResourceException x = new DataStoreAdapterException("CONN_NEVER_CLOSED", null, getClass());
              if (isTraceOn && tc.isEntryEnabled())
                  Tr.exit(this, tc, "cleanup", "Exception"); 
              throw x;
          }
  
          inCleanup = false;
  
          // Reset to null so that it gets refreshed on next use.
          transactional = null; 
  
          if (isTraceOn && tc.isEntryEnabled())
              Tr.exit(this, tc, "cleanup"); 
      }