/**
   * 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();
      }
    }
  }
  /**
   * Attempts to create a new wrapped pooled object.
   *
   * <p>If there are {@link #getMaxTotal()} objects already in circulation or in process of being
   * created, this method returns null.
   *
   * @return The new wrapped pooled object
   * @throws Exception if the object factory's {@code makeObject} fails
   */
  private PooledObject<T> create() throws Exception {
    int localMaxTotal = getMaxTotal();
    long newCreateCount = createCount.incrementAndGet();
    if (localMaxTotal > -1 && newCreateCount > localMaxTotal
        || newCreateCount > Integer.MAX_VALUE) {
      createCount.decrementAndGet();
      return null;
    }

    final PooledObject<T> p;
    try {
      p = factory.makeObject();
    } catch (Exception e) {
      createCount.decrementAndGet();
      throw e;
    }

    AbandonedConfig ac = this.abandonedConfig;
    if (ac != null && ac.getLogAbandoned()) {
      p.setLogAbandoned(true);
    }

    createdCount.incrementAndGet();
    allObjects.put(new IdentityWrapper<>(p.getObject()), p);
    return p;
  }
 /**
  * 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());
   }
 }
 /**
  * Will this pool identify and log any abandoned objects?
  *
  * @return {@code true} if abandoned object removal is configured for this pool and removal events
  *     are to be logged otherwise {@code false}
  * @see AbandonedConfig#getLogAbandoned()
  */
 @Override
 public boolean getLogAbandoned() {
   AbandonedConfig ac = this.abandonedConfig;
   return ac != null && ac.getLogAbandoned();
 }