/**
   * Recover abandoned objects which have been checked out but not used since longer than the
   * removeAbandonedTimeout.
   *
   * @param ac The configuration to use to identify abandoned objects
   */
  private void removeAbandoned(AbandonedConfig ac) {
    // Generate a list of abandoned objects to remove
    final long now = System.currentTimeMillis();
    final long timeout = now - (ac.getRemoveAbandonedTimeout() * 1000L);
    ArrayList<PooledObject<T>> remove = new ArrayList<>();
    Iterator<PooledObject<T>> it = allObjects.values().iterator();
    while (it.hasNext()) {
      PooledObject<T> pooledObject = it.next();
      synchronized (pooledObject) {
        if (pooledObject.getState() == PooledObjectState.ALLOCATED
            && pooledObject.getLastUsedTime() <= timeout) {
          pooledObject.markAbandoned();
          remove.add(pooledObject);
        }
      }
    }

    // Now remove the abandoned objects
    Iterator<PooledObject<T>> itr = remove.iterator();
    while (itr.hasNext()) {
      PooledObject<T> pooledObject = itr.next();
      if (ac.getLogAbandoned()) {
        pooledObject.printStackTrace(ac.getLogWriter());
      }
      try {
        invalidateObject(pooledObject.getObject());
      } catch (Exception e) {
        e.printStackTrace();
      }
    }
  }
 /**
  * Sets the abandoned object removal configuration.
  *
  * @param abandonedConfig the new configuration to use. This is used by value.
  * @see AbandonedConfig
  */
 public void setAbandonedConfig(AbandonedConfig abandonedConfig) {
   if (abandonedConfig == null) {
     this.abandonedConfig = null;
   } else {
     this.abandonedConfig = new AbandonedConfig();
     this.abandonedConfig.setLogAbandoned(abandonedConfig.getLogAbandoned());
     this.abandonedConfig.setLogWriter(abandonedConfig.getLogWriter());
     this.abandonedConfig.setRemoveAbandonedOnBorrow(abandonedConfig.getRemoveAbandonedOnBorrow());
     this.abandonedConfig.setRemoveAbandonedOnMaintenance(
         abandonedConfig.getRemoveAbandonedOnMaintenance());
     this.abandonedConfig.setRemoveAbandonedTimeout(abandonedConfig.getRemoveAbandonedTimeout());
     this.abandonedConfig.setUseUsageTracking(abandonedConfig.getUseUsageTracking());
   }
 }
 /**
  * Obtain the timeout before which an object will be considered to be abandoned by this pool.
  *
  * @return The abandoned object timeout in seconds if abandoned object removal is configured for
  *     this pool; Integer.MAX_VALUE otherwise.
  * @see AbandonedConfig#getRemoveAbandonedTimeout()
  */
 @Override
 public int getRemoveAbandonedTimeout() {
   AbandonedConfig ac = this.abandonedConfig;
   return ac != null ? ac.getRemoveAbandonedTimeout() : Integer.MAX_VALUE;
 }