in src/main/java/org/apache/commons/pool3/impl/GenericObjectPool.java [504:592]
private PooledObject<T> create(final Duration maxWaitDuration) throws E {
final Instant startInstant = Instant.now();
Duration remainingWaitDuration = maxWaitDuration.isNegative() ? Duration.ZERO : maxWaitDuration;
int localMaxTotal = getMaxTotal();
// This simplifies the code later in this method
if (localMaxTotal < 0) {
localMaxTotal = Integer.MAX_VALUE;
}
final Instant localStartInstant = Instant.now();
// 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) {
// remainingWaitDuration handles spurious wakeup from wait().
remainingWaitDuration = remainingWaitDuration.minus(durationSince(startInstant));
synchronized (makeObjectCountLock) {
final long newCreateCount = createCount.incrementAndGet();
if (newCreateCount > localMaxTotal) {
// The pool is currently at capacity or in the process of
// making enough new objects to take it to capacity.
createCount.decrementAndGet();
if (makeObjectCount == 0) {
// There are no makeObject() calls in progress so the
// pool 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 {
wait(makeObjectCountLock, remainingWaitDuration);
} catch (final InterruptedException e) {
// Don't surface exception type of internal locking mechanism.
throw cast(e);
}
}
} else {
// The pool is not at capacity. Create a new object.
makeObjectCount++;
create = Boolean.TRUE;
}
}
// Do not block more if remainingWaitDuration > 0.
if (create == null && remainingWaitDuration.compareTo(Duration.ZERO) > 0 &&
durationSince(localStartInstant).compareTo(remainingWaitDuration) >= 0) {
create = Boolean.FALSE;
}
}
if (!create.booleanValue()) {
return null;
}
final PooledObject<T> p;
try {
p = factory.makeObject();
if (PooledObject.isNull(p)) {
createCount.decrementAndGet();
throw new NullPointerException(String.format("%s.makeObject() = null", factory.getClass().getSimpleName()));
}
if (getTestOnCreate() && !factory.validateObject(p)) {
createCount.decrementAndGet();
return null;
}
} catch (final Throwable e) {
createCount.decrementAndGet();
throw e;
} finally {
synchronized (makeObjectCountLock) {
makeObjectCount--;
makeObjectCountLock.notifyAll();
}
}
final AbandonedConfig ac = this.abandonedConfig;
if (ac != null && ac.getLogAbandoned()) {
p.setLogAbandoned(true);
p.setRequireFullStackTrace(ac.getRequireFullStackTrace());
}
createdCount.incrementAndGet();
allObjects.put(new IdentityWrapper<>(p.getObject()), p);
return p;
}