/**
   * Notifies that an application has closed the connection.
   *
   * <p>Remove and close the UserPoolItem associated with the PoolItem. If it's the last
   * UserPoolItem, move to the idle state.
   */
  public void connectionClosed(ConnectionEvent event) {
    Object handle = event.getConnectionHandle();

    if (!_hasConnectionError && handle == null && _shareHead != null) {
      log.fine(
          L.l(
              "JCA close event '{0}' for {1} did not have a connection handle.  Please notify the JCA resource provider.",
              event, _mConn));
    }

    UserPoolItem ptr = _shareHead;
    UserPoolItem prev = null;

    while (ptr != null) {
      UserPoolItem next = ptr.getShareNext();

      Object userConn = ptr.getUserConnection();

      if (userConn == handle || handle == null) {
        if (prev != null) prev.setShareNext(next);
        else _shareHead = next;

        ptr.close();
      } else prev = ptr;

      ptr = next;
    }

    if (_shareHead == null) {
      toIdle();
      return;
    }
  }
  /**
   * Make this connection active.
   *
   * @return true if the pool item is valid, false if it should be removed.
   */
  synchronized UserPoolItem toActive(
      Subject subject, ConnectionRequestInfo info, UserPoolItem oldPoolItem)
      throws ResourceException {
    long now = Alarm.getCurrentTime();

    long maxIdleTime = _cm.getMaxIdleTime();
    long maxPoolTime = _cm.getMaxPoolTime();

    if (_hasConnectionError) return null;
    else if (0 < maxIdleTime && _poolEventTime + maxIdleTime < now) return null;
    else if (0 < maxPoolTime && _poolStartTime + maxPoolTime < now) return null;
    else if (_shareHead != null)
      throw new IllegalStateException(L.l("trying to activate active pool item."));

    _poolEventTime = now;
    _isXATransaction = _xaResource != null; // disable LT-optim by default

    UserPoolItem userPoolItem = null;

    if (oldPoolItem != null) {
      Object uConn = oldPoolItem.getUserConnection();

      if (uConn != null) _mConn.associateConnection(uConn);

      oldPoolItem.associatePoolItem(this);

      userPoolItem = oldPoolItem;
    } else userPoolItem = new UserPoolItem(_cm, this);

    if (!isValid(subject, info, userPoolItem)) return null;

    _subject = subject;
    _requestInfo = info;
    userPoolItem.associate(this, _mcf, subject, info);

    if (log.isLoggable(Level.FINE)) log.fine("allocate " + this);

    if (_cm.getSaveAllocationStackTrace())
      _allocationStackTrace =
          new IllegalStateException(L.l("Connection {0} allocation stack trace", this));

    return userPoolItem;
  }
  /** Returns true for a valid connection. */
  boolean isValid(Subject subject, ConnectionRequestInfo requestInfo, UserPoolItem userPoolItem) {
    try {
      ManagedConnection mConn = getManagedConnection();

      if (mConn == null) return false;

      Object userConn = userPoolItem.getUserConnection();

      if (userConn == null) {
        userConn = mConn.getConnection(subject, requestInfo);

        userPoolItem.setUserConnection(userConn);
      }

      return userConn != null;
    } catch (ResourceException e) {
      log.log(Level.WARNING, e.toString(), e);

      return false;
    }
  }