in src/main/java/org/apache/commons/pool3/impl/GenericKeyedObjectPool.java [734:836]
private PooledObject<T> create(final K key) throws E {
int maxTotalPerKeySave = getMaxTotalPerKey(); // Per key
if (maxTotalPerKeySave < 0) {
maxTotalPerKeySave = Integer.MAX_VALUE;
}
final int maxTotal = getMaxTotal(); // All keys
final ObjectDeque<T> objectDeque = poolMap.get(key);
// Check against the overall limit
boolean loop = true;
while (loop) {
final int newNumTotal = numTotal.incrementAndGet();
if (maxTotal > -1 && newNumTotal > maxTotal) {
numTotal.decrementAndGet();
if (getNumIdle() == 0) {
return null;
}
clearOldest();
} else {
loop = false;
}
}
// Flag that indicates if create should:
// - TRUE: call the factory to create an object
// - FALSE: return null
// - null: loop and re-test the condition that determines whether to
// call the factory
Boolean create = null;
while (create == null) {
synchronized (objectDeque.makeObjectCountLock) {
final long newCreateCount = objectDeque.getCreateCount().incrementAndGet();
// Check against the per key limit
if (newCreateCount > maxTotalPerKeySave) {
// The key is currently at capacity or in the process of
// making enough new objects to take it to capacity.
objectDeque.getCreateCount().decrementAndGet();
if (objectDeque.makeObjectCount == 0) {
// There are no makeObject() calls in progress for this
// key so the key is at capacity. Do not attempt to
// create a new object. Return and wait for an object to
// be returned.
create = Boolean.FALSE;
} else {
// There are makeObject() calls in progress that might
// bring the pool to capacity. Those calls might also
// fail so wait until they complete and then re-test if
// the pool is at capacity or not.
try {
objectDeque.makeObjectCountLock.wait();
} catch (final InterruptedException e) {
throw cast(e);
}
}
} else {
// The pool is not at capacity. Create a new object.
objectDeque.makeObjectCount++;
create = Boolean.TRUE;
}
}
}
if (!create.booleanValue()) {
numTotal.decrementAndGet();
return null;
}
PooledObject<T> p = null;
try {
p = factory.makeObject(key);
if (PooledObject.isNull(p)) {
numTotal.decrementAndGet();
objectDeque.getCreateCount().decrementAndGet();
throw new NullPointerException(String.format("%s.makeObject() = null", factory.getClass().getSimpleName()));
}
if (getTestOnCreate() && !factory.validateObject(key, p)) {
numTotal.decrementAndGet();
objectDeque.getCreateCount().decrementAndGet();
return null;
}
} catch (final Exception e) {
numTotal.decrementAndGet();
objectDeque.getCreateCount().decrementAndGet();
throw e;
} finally {
synchronized (objectDeque.makeObjectCountLock) {
objectDeque.makeObjectCount--;
objectDeque.makeObjectCountLock.notifyAll();
}
}
final AbandonedConfig ac = this.abandonedConfig;
if (ac != null && ac.getLogAbandoned()) {
p.setLogAbandoned(true);
p.setRequireFullStackTrace(ac.getRequireFullStackTrace());
}
createdCount.incrementAndGet();
objectDeque.getAllObjects().put(IdentityWrapper.on(p), p);
return p;
}