docs: public void processConnectionClosedEvent(WSJdbcConnection handle) 
      throws ResourceException {
          //A connection handle was closed - must notify the connection manager
          // of the close on the handle.  JDBC connection handles
          // which are closed are not allowed to be reused because there is no
          // guarantee that the user will not try to reuse an already closed JDBC handle.
  
          // Only send the event if the application is requesting the close. 
          if (cleaningUpHandles)
              return;
  
          final boolean isTraceOn = TraceComponent.isAnyTracingEnabled();
  
          // Fill in the ConnectionEvent only if needed. 
          connEvent.recycle(ConnectionEvent.CONNECTION_CLOSED, null, handle);
  
          if (isTraceOn && tc.isEventEnabled())
              Tr.event(this, tc, "Firing CONNECTION CLOSED", handle);
  
          try {
              removeHandle(handle); 
  
              // - Remove resetting autocommit in connection close time
          } catch (NullPointerException nullX) {
              // No FFDC code needed.  ManagedConnection is already closed.
  
              // A ConnectionError situation may
              // trigger a ManagedConnection close before the handle sends the ConnectionClosed
              // event.  When the event is sent the ManagedConnection is already closed.  If so,
              // just do a no-op here.
              if (handlesInUse == null) {
                  if (isTraceOn && tc.isEventEnabled())
                      Tr.event(this, tc, "ManagedConnection already closed"); 
                  return;
              } else
                  throw nullX;
          }
  
          if (numHandlesInUse == 0) 
          {
              if (haveVendorConnectionPropertiesChanged) {
                  try {
  
                      helper.doConnectionVendorPropertyReset(this.sqlConn, CONNECTION_VENDOR_DEFAULT_PROPERTIES);
                  } catch (SQLException sqle) {
                      FFDCFilter.processException(sqle, getClass().getName(), "1905", this);
                      throw new DataStoreAdapterException("DSA_ERROR", sqle, getClass());
                  }
  
                  haveVendorConnectionPropertiesChanged = false;
              }
          } 
  
          // loop through the listeners
          // Not synchronized because of contract that listeners will only be changed on
          // ManagedConnection create/destroy. 
  
          for (int i = 0; i < numListeners; i++) {
              // send Connection Closed event to the current listener
              ivEventListeners[i].connectionClosed(connEvent); 
          }
  
          // Replace ConnectionEvent caching with a single reusable instance per
          // ManagedConnection. 
      }