docs: @Override
      public void connectionClosed(ConnectionEvent event) {
  
          final boolean isTracingEnabled = TraceComponent.isAnyTracingEnabled();
  
          if (isTracingEnabled && tc.isEntryEnabled()) {
              Tr.entry(this, tc, "connectionClosed");
          }
  
          if (event.getId() == ConnectionEvent.CONNECTION_CLOSED) {
              if (!mcWrapper.isParkedWrapper()) {
  
                  if (isTracingEnabled && tc.isDebugEnabled()) {
                      //Tr.debug(this, tc, "Closing handle for ManagedConnection@" + Integer.toHexString(mc.hashCode()) + " from pool " + mcWrapper.gConfigProps.pmiName + " from mcWrapper " + mcWrapper.toString() + " from mc " + mc);
                      // Omit handle info.
                      //Tr.debug(this, tc, "***Connection Close Request*** Handle Name: " + event.getConnectionHandle().toString() + "  Connection Pool: " + mcWrapper.getPoolManager().toString() + "  Details: : " + mcWrapper.toString() );
                      //          I only removed the connection handle toString, since this is the one getting the null pointer exception.
                      //          The trace component code will check for null first before calling toString on the handle.
                      //          Any new debug should not use the .toString() to prevent null pointer exceptions in trace.
                      //          Changed trace string to only dump pool manager name not entire pool.
                      Tr.debug(this, tc, "***Connection Close Request*** Handle Name: " + event.getConnectionHandle() + "  Connection Pool: "
                                         + mcWrapper.getPoolManager().getGConfigProps().getXpathId() + "  Details: : " + mcWrapper);
  
                  }
  
                  ConnectionManager cm = mcWrapper.getConnectionManagerWithoutStateCheck();
  
                  if (cm != null && cm.handleToThreadMap != null) {
                      cm.handleToThreadMap.clear();
                  }
                  if (cm != null && cm.handleToCMDMap != null) {
                      cm.handleToCMDMap.clear();
                  }
  
                  if (!(mcWrapper.gConfigProps.isSmartHandleSupport() && (cm != null && cm.shareable()))) {
  
                      Object conHandle = event.getConnectionHandle();
                      if (null == conHandle) {
                          Tr.warning(tc, "CONNECTION_CLOSED_NULL_HANDLE_J2CA0148", event);
                      } else {
                          mcWrapper.removeFromHandleList(conHandle);
                          // TODO - need to implement - Notify the CHM to stop tracking the handle because it has been closed.
                      }
                  }
  
                  /*
                   * Decrement the number of open connections for Managed Connection and see if
                   * all the connections are now closed. If they are all closed and the MC is not
                   * associated with a transaction, then return it to the pool. If all the handles
                   * are closed and the MC is associated with a transaction, then do nothing.
                   * The MC will be released back to the pool at the end of the transaction when
                   * afterCompletion is called on one of the transactional wrapper objects.
                   */
                  mcWrapper.decrementHandleCount();
  
                  if (mcWrapper.getHandleCount() == 0) {
  
                      /*
                       * If we are processing a NoTransaction resource, then we are essentially done with
                       * the "transaction" when all of the connection handles are closed. We have to
                       * perform this extra cleanup because of the dual purpose of the involvedInTransaction
                       * method on the MCWrapper.
                       */
  
                      if (mcWrapper.getTranWrapperId() == MCWrapper.NOTXWRAPPER) {
                          mcWrapper.transactionComplete();
                      }
  
                      // Deleted calling mcWrapper.transactionComplete() for RRS Local Tran
  
                      /*
                       * If the ManagedConnection is not associated with a
                       * transaction any more, return it to the pool.
                       */
  
                      if (!mcWrapper.involvedInTransaction()) {
  
                          /*
                           * The ManagedConnection is not associated with a transactional
                           * context so return it to the pool. We need to check if the MC was
                           * shareable or not. If it was shareable, then we need to extract the
                           * coordinator from the MCWrapper and send it into releaseToPoolManager.
                           * If it was unshareable, then we just pass null into the
                           * releaseToPoolManager method and it releases it back to the pool.
                           */
  
                          try {
                              mcWrapper.releaseToPoolManager();
                          } catch (Exception ex) {
                              // Nothing to do here. PoolManager has already logged it.
                              // Since we are in cleanup mode, we will not surface a Runtime exception to the ResourceAdapter
                              FFDCFilter.processException(ex, "com.ibm.ejs.j2c.ConnectionEventListener.connectionClosed", "197", this);
                              if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) {
                                  Tr.debug(this, tc,
                                           "connectionClosed: Closing connection in pool " + mcWrapper.gConfigProps.getXpathId()
                                                     + " caught exception, but will continue processing: ",
                                           ex);
                              }
                          }
                      }
                  }
              }
          } else {
              // Connection Event passed in doesn't match the method called.
              // This should never happen unless there is an error in the ResourceAdapter.
              processBadEvent("connectionClosed", ConnectionEvent.CONNECTION_CLOSED, event);
          }
  
          if (isTracingEnabled && tc.isEntryEnabled()) {
              Tr.exit(this, tc, "connectionClosed");
          }
  
          return;
  
      }