/** Removes a connection */
  void removeItem(ManagedPoolItem item, ManagedConnection mConn) {
    synchronized (_connectionPool) {
      _idlePool.remove(mConn);

      _connectionPool.remove(item);
      _connectionPool.notifyAll();
    }

    try {
      item.destroy();
    } catch (Exception e) {
      log.log(Level.WARNING, e.toString(), e);
    }
  }
  /** Alarm listener. */
  @Override
  public void handleAlarm(Alarm alarm) {
    if (!_lifecycle.isActive()) return;

    try {
      _alarmConnections.clear();

      synchronized (_connectionPool) {
        _alarmConnections.addAll(_connectionPool);
      }

      for (int i = _alarmConnections.size() - 1; i >= 0; i--) {
        ManagedPoolItem item = _alarmConnections.get(i);

        if (!item.isValid()) item.destroy();
      }

      _alarmConnections.clear();

      fillIdlePool();
    } finally {
      if (!_lifecycle.isActive()) {
      } else if (0 < _idleTimeout && _idleTimeout < 1000) _alarm.queue(1000);
      else if (1000 < _idleTimeout && _idleTimeout < 60000) _alarm.queue(_idleTimeout);
      else _alarm.queue(60000);
    }
  }
  /** Starts creation of an overflow connection. */
  private boolean startCreateOverflow() throws ResourceException {
    int size = _connectionPool.size();
    int createCount = _createCount.incrementAndGet();

    if (createCount + size <= _maxConnections + _maxOverflowConnections) return true;

    _createCount.decrementAndGet();
    String message =
        L.l(
            "{0} cannot create overflow connection after {1}ms"
                + " (pool-size={2}"
                + ", max-connections={3}"
                + ", create-count={4}"
                + ", max-create-connections={5}"
                + ", max-overflow-connections={6})",
            this,
            _connectionWaitTimeout,
            _connectionPool.size(),
            _maxConnections,
            _createCount.get(),
            _maxCreateConnections,
            _maxOverflowConnections);

    HealthStatusService.updateCurrentHealthStatus(this, HealthStatus.WARNING, message);

    throw new ResourceException(message);
  }
  /*
   * Removes a connection from the pool.
   */
  public void markForPoolRemoval(ManagedConnection mConn) {
    synchronized (_connectionPool) {
      for (int i = _connectionPool.size() - 1; i >= 0; i--) {
        ManagedPoolItem poolItem = _connectionPool.get(i);

        if (poolItem.getManagedConnection() == mConn) {
          poolItem.setConnectionError();
          return;
        }
      }
    }
  }
  private ManagedPoolItem findPoolItem(ManagedConnection mConn) {
    synchronized (_connectionPool) {
      for (int i = _connectionPool.size() - 1; i >= 0; i--) {
        ManagedPoolItem testPoolItem = _connectionPool.get(i);

        if (testPoolItem.getManagedConnection() == mConn) {
          return testPoolItem;
        }
      }

      return null;
    }
  }
  /** Adds a connection to the idle pool. */
  void toIdle(ManagedPoolItem item) {
    try {
      if (_maxConnections < _connectionPool.size() || item.isConnectionError()) {
        return;
      }

      ManagedConnection mConn = item.getManagedConnection();

      if (mConn == null) {
        return;
      }

      mConn.cleanup();

      long now = CurrentTime.getCurrentTime();

      if (_idlePool.size() == 0) _idlePoolExpire = now + _idleTimeout;

      if (_idlePoolExpire < now) {
        // shrink the idle pool when non-empty for idleTimeout
        _idlePoolExpire = now + _idleTimeout;
      } else if (_idlePool.add(mConn)) {
        item = null;
        return;
      }
    } catch (Exception e) {
      log.log(Level.FINE, e.toString(), e);
    } finally {
      notifyConnectionAvailable();

      if (item != null) item.destroy();
    }
  }
  /** Finds the pool item joined to this one. return null. */
  ManagedPoolItem findJoin(UserTransactionImpl uTrans, ManagedPoolItem item) {
    if (!uTrans.isActive()) return null;

    ArrayList<ManagedXAResource> poolItems = uTrans.getXaResources();
    int length = poolItems.size();

    for (int i = 0; i < length; i++) {
      ManagedXAResource resource = poolItems.get(i);

      if (resource instanceof ManagedPoolItem) {
        ManagedPoolItem poolItem = (ManagedPoolItem) resource;

        if (poolItem.isJoin(item)) return poolItem;
      }
    }

    return null;
  }
  /** Clears the idle connections in the pool. */
  @Override
  public void clear() {
    ArrayList<ManagedPoolItem> pool = _connectionPool;

    if (pool == null) return;

    ArrayList<ManagedPoolItem> clearItems = new ArrayList<ManagedPoolItem>();

    synchronized (_connectionPool) {
      _idlePool.clear();

      clearItems.addAll(pool);

      pool.clear();
    }

    for (int i = 0; i < clearItems.size(); i++) {
      ManagedPoolItem poolItem = clearItems.get(i);

      try {
        poolItem.destroy();
      } catch (Throwable e) {
        log.log(Level.WARNING, e.toString(), e);
      }
    }
  }
  /** Allocates a resource matching the parameters. If none matches, return null. */
  private UserPoolItem allocateShared(
      UserTransactionImpl transaction,
      ManagedConnectionFactory mcf,
      Subject subject,
      ConnectionRequestInfo info) {
    if (!transaction.isActive()) return null;

    ArrayList<ManagedXAResource> poolItems = transaction.getXaResources();
    int length = poolItems.size();

    for (int i = 0; i < length; i++) {
      ManagedXAResource xaResource = poolItems.get(i);

      if (xaResource instanceof ManagedPoolItem) {
        ManagedPoolItem poolItem = (ManagedPoolItem) xaResource;

        UserPoolItem item = poolItem.allocateXA(mcf, subject, info);

        if (item != null) return item;
      }
    }

    return null;
  }
  /** Destroys the manager. */
  public void destroy() {
    stop();

    if (!_lifecycle.toDestroy()) return;

    ArrayList<ManagedPoolItem> pool;

    synchronized (_connectionPool) {
      pool = new ArrayList<ManagedPoolItem>(_connectionPool);
      _connectionPool.clear();

      if (_idlePool != null) _idlePool.clear();
    }

    for (int i = 0; i < pool.size(); i++) {
      ManagedPoolItem poolItem = pool.get(i);

      try {
        poolItem.destroy();
      } catch (Throwable e) {
        log.log(Level.WARNING, e.toString(), e);
      }
    }
  }
  /** Creates a new connection. */
  private UserPoolItem createConnection(
      ManagedConnectionFactory mcf,
      Subject subject,
      ConnectionRequestInfo info,
      UserPoolItem oldPoolItem)
      throws ResourceException {
    boolean isValid = false;
    ManagedPoolItem poolItem = null;

    try {
      ManagedConnection mConn = mcf.createManagedConnection(subject, info);

      if (mConn == null)
        throw new ResourceException(
            L.l("'{0}' did not return a connection from createManagedConnection", mcf));

      poolItem = new ManagedPoolItem(this, mcf, mConn);

      UserPoolItem userPoolItem;

      // Ensure the connection is still valid
      userPoolItem = poolItem.toActive(subject, info, oldPoolItem);

      if (userPoolItem == null) {
        throw new ResourceException(L.l("Connection '{0}' was not valid on creation", poolItem));
      }

      _connectionCreateCountTotal.incrementAndGet();

      synchronized (_connectionPool) {
        _connectionPool.add(poolItem);
      }

      poolItem = null;
      isValid = true;

      return userPoolItem;
    } finally {
      if (!isValid) {
        _connectionFailCountTotal.incrementAndGet();
        _lastFailTime = CurrentTime.getCurrentTime();
      }

      // server/308b - connection removed on rollback-only, when it's
      // theoretically possible to reuse it
      if (poolItem != null) poolItem.destroy();
    }
  }
  private void fillIdlePool() {
    int count = _minIdleCount;

    try {
      while (_connectionPool.size() < _minIdleCount && count-- >= 0 && _lifecycle.isActive()) {
        Subject subject = null;
        ConnectionRequestInfo info = null;

        UserPoolItem userPoolItem;

        userPoolItem = createConnection(_mcf, subject, info, null);

        if (userPoolItem != null) userPoolItem.toIdle();
      }
    } catch (Exception e) {
      e.printStackTrace();

      log.log(Level.FINE, e.toString(), e);
    }
  }
 /** True if a connection can be created, i.e. below max-connections and max-create-connections. */
 private boolean isCreateAvailable() {
   return (_connectionPool.size() < _maxConnections && _createCount.get() < _maxCreateConnections);
 }
  /**
   * Allocates the pool item for a connection, creating one if necessary.
   *
   * @param mcf the driver's ManagedConnectionFactory for creating pooled connections
   * @param subject the user's authentication credentials
   * @param info the user's extra connection information
   */
  UserPoolItem allocatePoolConnection(
      ManagedConnectionFactory mcf,
      Subject subject,
      ConnectionRequestInfo info,
      UserPoolItem oldPoolItem)
      throws ResourceException {
    long expireTime = CurrentTime.getCurrentTimeActual() + _connectionWaitTimeout;

    if (!_lifecycle.isActive()) {
      throw new IllegalStateException(
          L.l("{0}: Can't allocate connection because the connection pool is closed.", this));
    }

    do {
      UserPoolItem userPoolItem = allocateIdleConnection(mcf, subject, info, oldPoolItem);

      if (userPoolItem != null) return userPoolItem;

      // if no item in pool, try to create one
      if (startCreateConnection()) {
        try {
          return createConnection(mcf, subject, info, oldPoolItem);
        } finally {
          finishCreateConnection();
        }
      }
    } while (_lifecycle.isActive() && waitForAvailableConnection(expireTime));

    if (!_lifecycle.isActive())
      throw new IllegalStateException(
          L.l("{0}: Can't allocate connection because the connection pool is closed.", this));

    String message =
        (this
            + " pool throttled create timeout"
            + " (pool-size="
            + _connectionPool.size()
            + ", max-connections="
            + _maxConnections
            + ", create-count="
            + _createCount.get()
            + ", max-create-connections="
            + _maxCreateConnections
            + ")");

    HealthStatusService.updateCurrentHealthStatus(this, HealthStatus.WARNING, message);

    if (startCreateOverflow()) {
      try {
        return createConnection(mcf, subject, info, oldPoolItem);
      } finally {
        finishCreateConnection();
      }
    }

    message =
        (this
            + " pool overflow failed to create"
            + " (pool-size="
            + _connectionPool.size()
            + ", max-connections="
            + _maxConnections
            + ", create-count="
            + _createCount.get()
            + ", max-create-connections="
            + _maxCreateConnections
            + ")");

    HealthStatusService.updateCurrentHealthStatus(this, HealthStatus.CRITICAL, message);

    throw new ResourceException(
        L.l("Can't create overflow connection connection-max={0}", _maxConnections));
  }
 /** Returns the active connections. */
 @Override
 public int getConnectionActiveCount() {
   return _connectionPool.size() - _idlePool.size();
 }
 /** Returns the total connections. */
 @Override
 public int getConnectionCount() {
   return _connectionPool.size();
 }