edu.vt.middleware.ldap.pool.BlockingLdapPool Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of vt-ldap Show documentation
Show all versions of vt-ldap Show documentation
Library for performing common LDAP operations
/*
$Id: BlockingLdapPool.java 2241 2012-02-07 20:08:51Z dfisher $
Copyright (C) 2003-2010 Virginia Tech.
All rights reserved.
SEE LICENSE FOR MORE INFORMATION
Author: Middleware Services
Email: [email protected]
Version: $Revision: 2241 $
Updated: $Date: 2012-02-07 15:08:51 -0500 (Tue, 07 Feb 2012) $
*/
package edu.vt.middleware.ldap.pool;
import java.util.NoSuchElementException;
import java.util.concurrent.TimeUnit;
import edu.vt.middleware.ldap.Ldap;
/**
* BlockingLdapPool
implements a pool of ldap objects that has a
* set minimum and maximum size. The pool will not grow beyond the maximum size
* and when the pool is exhausted, requests for new objects will block. The
* length of time the pool will block is determined by {@link
* #getBlockWaitTime()}. By default the pool will block indefinitely and there
* is no guarantee that waiting threads will be serviced in the order in which
* they made their request. This implementation should be used when you need to
* control the exact number of ldap connections that can be created.
* See {@link AbstractLdapPool}.
*
* @author Middleware Services
* @version $Revision: 2241 $ $Date: 2012-02-07 15:08:51 -0500 (Tue, 07 Feb 2012) $
*/
public class BlockingLdapPool extends AbstractLdapPool
{
/** Time in milliseconds to wait for an available ldap object. */
private long blockWaitTime;
/** Creates a new ldap pool using {@link DefaultLdapFactory}. */
public BlockingLdapPool()
{
super(new LdapPoolConfig(), new DefaultLdapFactory());
}
/**
* Creates a new ldap pool with the supplied ldap factory.
*
* @param lf ldap factory
*/
public BlockingLdapPool(final LdapFactory lf)
{
super(new LdapPoolConfig(), lf);
}
/**
* Creates a new ldap pool with the supplied ldap config and factory.
*
* @param lpc ldap pool configuration
* @param lf ldap factory
*/
public BlockingLdapPool(final LdapPoolConfig lpc, final LdapFactory lf)
{
super(lpc, lf);
}
/**
* Returns the block wait time. Default time is 0, which will wait
* indefinitely.
*
* @return time in milliseconds to wait for available ldap objects
*/
public long getBlockWaitTime()
{
return this.blockWaitTime;
}
/**
* Sets the block wait time. Default time is 0, which will wait indefinitely.
*
* @param time in milliseconds to wait for available ldap objects
*/
public void setBlockWaitTime(final long time)
{
if (time >= 0) {
this.blockWaitTime = time;
}
}
/** {@inheritDoc} */
public Ldap checkOut()
throws LdapPoolException
{
Ldap l = null;
boolean create = false;
if (this.logger.isTraceEnabled()) {
this.logger.trace(
"waiting on pool lock for check out " + this.poolLock.getQueueLength());
}
this.poolLock.lock();
try {
// if an available object exists, use it
// if no available objects and the pool can grow, attempt to create
// otherwise the pool is full, block until an object is returned
if (this.available.size() > 0) {
try {
if (this.logger.isTraceEnabled()) {
this.logger.trace("retrieve available ldap object");
}
l = this.retrieveAvailable();
} catch (NoSuchElementException e) {
if (this.logger.isErrorEnabled()) {
this.logger.error("could not remove ldap object from list", e);
}
throw new IllegalStateException("Pool is empty", e);
}
} else if (this.active.size() < this.poolConfig.getMaxPoolSize()) {
if (this.logger.isTraceEnabled()) {
this.logger.trace("pool can grow, attempt to create ldap object");
}
create = true;
} else {
if (this.logger.isTraceEnabled()) {
this.logger.trace(
"pool is full, block until ldap object " +
"is available");
}
l = this.blockAvailable();
}
} finally {
this.poolLock.unlock();
}
if (create) {
// previous block determined a creation should occur
// block here until create occurs without locking the whole pool
// if the pool is already maxed or creates are failing,
// block until an object is available
this.checkOutLock.lock();
try {
boolean b = true;
this.poolLock.lock();
try {
if (
this.available.size() + this.active.size() ==
this.poolConfig.getMaxPoolSize()) {
b = false;
}
} finally {
this.poolLock.unlock();
}
if (b) {
l = this.createActive();
if (this.logger.isTraceEnabled()) {
this.logger.trace("created new active ldap object: " + l);
}
}
} finally {
this.checkOutLock.unlock();
}
if (l == null) {
if (this.available.size() == 0 && this.active.size() == 0) {
if (this.logger.isErrorEnabled()) {
this.logger.error("Could not service check out request");
}
throw new LdapPoolExhaustedException(
"Pool is empty and object creation failed");
}
if (this.logger.isDebugEnabled()) {
this.logger.debug(
"create failed, block until ldap object " +
"is available");
}
l = this.blockAvailable();
}
}
if (l != null) {
this.activateAndValidate(l);
} else {
if (this.logger.isErrorEnabled()) {
this.logger.error("Could not service check out request");
}
throw new LdapPoolExhaustedException(
"Pool is empty and object creation failed");
}
return l;
}
/**
* This attempts to retrieve an ldap object from the available queue.
*
* @return ldap object from the pool
*
* @throws NoSuchElementException if the available queue is empty
*/
protected Ldap retrieveAvailable()
{
Ldap l = null;
if (this.logger.isTraceEnabled()) {
this.logger.trace(
"waiting on pool lock for retrieve available " +
this.poolLock.getQueueLength());
}
this.poolLock.lock();
try {
final PooledLdap pl = this.available.remove();
this.active.add(new PooledLdap(pl.getLdap()));
l = pl.getLdap();
if (this.logger.isTraceEnabled()) {
this.logger.trace("retrieved available ldap object: " + l);
}
} finally {
this.poolLock.unlock();
}
return l;
}
/**
* This blocks until an ldap object can be aquired.
*
* @return ldap object from the pool
*
* @throws LdapPoolException if this method fails
* @throws BlockingTimeoutException if this pool is configured with a block
* time and it occurs
* @throws PoolInterruptedException if the current thread is interrupted
*/
protected Ldap blockAvailable()
throws LdapPoolException
{
Ldap l = null;
if (this.logger.isTraceEnabled()) {
this.logger.trace(
"waiting on pool lock for block available " +
this.poolLock.getQueueLength());
}
this.poolLock.lock();
try {
while (l == null) {
if (this.logger.isTraceEnabled()) {
this.logger.trace("available pool is empty, waiting...");
}
if (this.blockWaitTime > 0) {
if (
!this.poolNotEmpty.await(
this.blockWaitTime,
TimeUnit.MILLISECONDS)) {
if (this.logger.isDebugEnabled()) {
this.logger.debug("block time exceeded, throwing exception");
}
throw new BlockingTimeoutException("Block time exceeded");
}
} else {
this.poolNotEmpty.await();
}
if (this.logger.isTraceEnabled()) {
this.logger.trace("notified to continue...");
}
try {
l = this.retrieveAvailable();
} catch (NoSuchElementException e) {
if (this.logger.isTraceEnabled()) {
this.logger.trace("notified to continue but pool was empty");
}
}
}
} catch (InterruptedException e) {
if (this.logger.isErrorEnabled()) {
this.logger.error("waiting for available object interrupted", e);
}
throw new PoolInterruptedException(
"Interrupted while waiting for an available object",
e);
} finally {
this.poolLock.unlock();
}
return l;
}
/** {@inheritDoc} */
public void checkIn(final Ldap l)
{
final boolean valid = this.validateAndPassivate(l);
final PooledLdap pl = new PooledLdap(l);
if (this.logger.isTraceEnabled()) {
this.logger.trace(
"waiting on pool lock for check in " + this.poolLock.getQueueLength());
}
this.poolLock.lock();
try {
if (this.active.remove(pl)) {
if (valid) {
this.available.add(pl);
if (this.logger.isTraceEnabled()) {
this.logger.trace("returned active ldap object: " + l);
}
this.poolNotEmpty.signal();
}
} else if (this.available.contains(pl)) {
if (this.logger.isWarnEnabled()) {
this.logger.warn("returned available ldap object: " + l);
}
} else {
if (this.logger.isWarnEnabled()) {
this.logger.warn("attempt to return unknown ldap object: " + l);
}
}
} finally {
this.poolLock.unlock();
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy