From a0da075ec48f4fa7e0d3fc7c0770c607d3b6b8a7 Mon Sep 17 00:00:00 2001 From: Mattias Arthursson Date: Mon, 18 Aug 2008 18:51:58 +0000 Subject: [PATCH] Added getContext(principal, credentials) method to ContextSource to enable explicit authentication. Refactored AbstractContextSource to enable the new method and so that DirContextAuthenticationStrategy does not interfere with anonymous contexts. Changed defaults in integraion-tests-openldap to target server spring-ldap-test.dyndns.org and use TLS. --- .../ldap/core/ContextSource.java | 51 +- .../core/support/AbstractContextSource.java | 64 +- .../pool/factory/PoolingContextSource.java | 739 +++++++++--------- ...mpensatingTransactionOperationFactory.java | 257 +++--- .../TransactionAwareContextSourceProxy.java | 4 + .../core/support/LdapContextSourceTest.java | 60 +- .../src/test/resources/conf/ldap.properties | 2 +- .../conf/ldapTemplateTestContext.xml | 4 + .../core/support/LdapContextSourcelITest.java | 27 + 9 files changed, 619 insertions(+), 589 deletions(-) diff --git a/mvn-build/core/src/main/java/org/springframework/ldap/core/ContextSource.java b/mvn-build/core/src/main/java/org/springframework/ldap/core/ContextSource.java index 87656e44..5c142d13 100644 --- a/mvn-build/core/src/main/java/org/springframework/ldap/core/ContextSource.java +++ b/mvn-build/core/src/main/java/org/springframework/ldap/core/ContextSource.java @@ -21,7 +21,10 @@ import javax.naming.directory.DirContext; import org.springframework.ldap.NamingException; /** - * Interface used by {@link LdapTemplate} to create LDAP contexts. + * A ContextSource is responsible for configuring and creating + * DirContext instances. It is typically used from + * {@link LdapTemplate} to acquiring contexts for LDAP operations, but may be + * used standalone to perform LDAP authentication. * * @see org.springframework.ldap.core.LdapTemplate * @@ -30,22 +33,34 @@ import org.springframework.ldap.NamingException; */ public interface ContextSource { - /** - * Gets a read-only DirContext. The returned DirContext must be possible to - * perform read-only operations on. - * - * @return A DirContext instance, never null. - * @throws NamingException - * if some error occurs creating an DirContext. - */ - public DirContext getReadOnlyContext() throws NamingException; + /** + * Gets a read-only DirContext. The returned + * DirContext must be possible to perform read-only operations + * on. + * + * @return A DirContext instance, never null. + * @throws NamingException if some error occurs creating an DirContext. + */ + public DirContext getReadOnlyContext() throws NamingException; - /** - * Gets a read-write DirContext. - * - * @return A DirContext instance, never null. - * @throws NamingException - * if some error occurs creating an DirContext. - */ - public DirContext getReadWriteContext() throws NamingException; + /** + * Gets a read-write DirContext instance. + * + * @return A DirContext instance, never null. + * @throws NamingException if some error occurs creating an + * DirContext. + */ + public DirContext getReadWriteContext() throws NamingException; + + /** + * Gets a DirContext instance authenticated using the supplied + * principal and credentials. + * + * @param principal The principal (typically a distinguished name of a user + * in the LDAP tree) to use for authentication. + * @param credentials The credentials to use for authentication. + * @return an authenticated DirContext instance, never + * null. + */ + public DirContext getContext(String principal, String credentials) throws NamingException; } \ No newline at end of file diff --git a/mvn-build/core/src/main/java/org/springframework/ldap/core/support/AbstractContextSource.java b/mvn-build/core/src/main/java/org/springframework/ldap/core/support/AbstractContextSource.java index d1149fcb..b16a88af 100644 --- a/mvn-build/core/src/main/java/org/springframework/ldap/core/support/AbstractContextSource.java +++ b/mvn-build/core/src/main/java/org/springframework/ldap/core/support/AbstractContextSource.java @@ -38,15 +38,16 @@ import org.springframework.ldap.support.LdapUtils; * returns an authenticated * DirContext implementation for both read-only and * read-write operations. To have an anonymous environment created for read-only - * operations, set the anonymousReadOnly property to true. + * operations, set the anonymousReadOnly property to + * true. *

* Implementing classes need to implement - * {@link #getDirContextInstance(Hashtable)} to create a DirContext instance of - * the desired type. + * {@link #getDirContextInstance(Hashtable)} to create a DirContext + * instance of the desired type. *

- * If an {@link AuthenticationSource} is set, this will be used for getting user principal - * and password for each new connection, otherwise a default one will be created - * using the specified userDn and password. + * If an {@link AuthenticationSource} is set, this will be used for getting user + * principal and password for each new connection, otherwise a default one will + * be created using the specified userDn and password. *

* Note: When using implementations of this class outside of a Spring * Context it is necessary to call {@link #afterPropertiesSet()} when all @@ -99,6 +100,19 @@ public abstract class AbstractContextSource implements BaseLdapPathContextSource private DirContextAuthenticationStrategy authenticationStrategy = new SimpleDirContextAuthenticationStrategy(); + public DirContext getContext(String principal, String credentials) { + DirContext ctx = createContext(getAuthenticatedEnv(principal, credentials)); + + try { + authenticationStrategy.processContextAfterCreation(ctx, principal, credentials); + return ctx; + } + catch (NamingException e) { + closeContext(ctx); + throw LdapUtils.convertLdapException(e); + } + } + /* * (non-Javadoc) * @@ -106,7 +120,7 @@ public abstract class AbstractContextSource implements BaseLdapPathContextSource */ public DirContext getReadOnlyContext() { if (!anonymousReadOnly) { - return createContext(getAuthenticatedEnv()); + return getContext(authenticationSource.getPrincipal(), authenticationSource.getCredentials()); } else { return createContext(getAnonymousEnv()); @@ -119,7 +133,7 @@ public abstract class AbstractContextSource implements BaseLdapPathContextSource * @see org.springframework.ldap.core.ContextSource#getReadWriteContext() */ public DirContext getReadWriteContext() { - return createContext(getAuthenticatedEnv()); + return getContext(authenticationSource.getPrincipal(), authenticationSource.getCredentials()); } /** @@ -129,13 +143,14 @@ public abstract class AbstractContextSource implements BaseLdapPathContextSource * {@link DirContextAuthenticationStrategy} on this instance. * * @param env the environment to modify. + * @param principal the principal to authenticate with. + * @param credentials the credentials to authenticate with. * @see DirContextAuthenticationStrategy * @see #setAuthenticationStrategy(DirContextAuthenticationStrategy) */ - protected void setupAuthenticatedEnvironment(Hashtable env) { + protected void setupAuthenticatedEnvironment(Hashtable env, String principal, String credentials) { try { - authenticationStrategy.setupEnvironment(env, authenticationSource.getPrincipal(), authenticationSource - .getCredentials()); + authenticationStrategy.setupEnvironment(env, principal, credentials); } catch (NamingException e) { throw LdapUtils.convertLdapException(e); @@ -203,7 +218,10 @@ public abstract class AbstractContextSource implements BaseLdapPathContextSource /* * (non-Javadoc) - * @see org.springframework.ldap.core.support.BaseLdapPathSource#getBaseLdapPath() + * + * @see + * org.springframework.ldap.core.support.BaseLdapPathSource#getBaseLdapPath + * () */ public DistinguishedName getBaseLdapPath() { return getBase().immutableDistinguishedName(); @@ -211,7 +229,9 @@ public abstract class AbstractContextSource implements BaseLdapPathContextSource /* * (non-Javadoc) - * @see org.springframework.ldap.core.support.BaseLdapPathSource#getBaseLdapPathAsString() + * + * @seeorg.springframework.ldap.core.support.BaseLdapPathSource# + * getBaseLdapPathAsString() */ public String getBaseLdapPathAsString() { return getBaseLdapPath().toString(); @@ -231,9 +251,6 @@ public abstract class AbstractContextSource implements BaseLdapPathContextSource try { ctx = getDirContextInstance(environment); - authenticationStrategy.processContextAfterCreation(ctx, authenticationSource.getPrincipal(), - authenticationSource.getCredentials()); - if (log.isInfoEnabled()) { Hashtable ctxEnv = ctx.getEnvironment(); String ldapUrl = (String) ctxEnv.get(Context.PROVIDER_URL); @@ -283,8 +300,8 @@ public abstract class AbstractContextSource implements BaseLdapPathContextSource /** * Get the DirObjectFactory to use. * - * @return the DirObjectFactory to be used. null means that - * no DirObjectFactory will be used. + * @return the DirObjectFactory to be used. null means that no + * DirObjectFactory will be used. */ public Class getDirObjectFactory() { return dirObjectFactory; @@ -445,10 +462,10 @@ public abstract class AbstractContextSource implements BaseLdapPathContextSource } } - protected Hashtable getAuthenticatedEnv() { + protected Hashtable getAuthenticatedEnv(String principal, String credentials) { // The authenticated environment should always be rebuilt. Hashtable env = new Hashtable(getAnonymousEnv()); - setupAuthenticatedEnvironment(env); + setupAuthenticatedEnvironment(env, principal, credentials); return env; } @@ -502,8 +519,8 @@ public abstract class AbstractContextSource implements BaseLdapPathContextSource * Get whether an anonymous environment should be used for read-only * operations. * - * @return true if an anonymous environment should be used - * for read-only operations, false otherwise. + * @return true if an anonymous environment should be used for + * read-only operations, false otherwise. */ public boolean isAnonymousReadOnly() { return anonymousReadOnly; @@ -511,8 +528,7 @@ public abstract class AbstractContextSource implements BaseLdapPathContextSource /** * Set the {@link DirContextAuthenticationStrategy} to use for preparing the - * environment and processing the created DirContext - * instances. + * environment and processing the created DirContext instances. * * @param authenticationStrategy the * {@link DirContextAuthenticationStrategy} to use; default is diff --git a/mvn-build/core/src/main/java/org/springframework/ldap/pool/factory/PoolingContextSource.java b/mvn-build/core/src/main/java/org/springframework/ldap/pool/factory/PoolingContextSource.java index fb692584..38f3c992 100644 --- a/mvn-build/core/src/main/java/org/springframework/ldap/pool/factory/PoolingContextSource.java +++ b/mvn-build/core/src/main/java/org/springframework/ldap/pool/factory/PoolingContextSource.java @@ -32,375 +32,408 @@ import org.springframework.ldap.pool.DirContextType; import org.springframework.ldap.pool.validation.DirContextValidator; /** - * A {@link ContextSource} implementation that wraps an object pool and another {@link ContextSource}. - * {@link DirContext}s are retrieved from the pool which maintains them. + * A {@link ContextSource} implementation that wraps an object pool and another + * {@link ContextSource}. {@link DirContext}s are retrieved from the pool which + * maintains them. * * *
*
* Configuration: * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * *
PropertyDescriptionRequiredDefault
contextSource - * The {@link ContextSource} to get {@link DirContext}s from for adding to the pool. - * Yesnull
dirContextValidator - * The {@link DirContextValidator} to use for validating {@link DirContext}s. Required - * if any of the test/validate options are enabled. - * Nonull
minIdle{@link GenericKeyedObjectPool#setMinIdle(int)}No0
maxIdle{@link GenericKeyedObjectPool#setMaxIdle(int)}No8
maxActive{@link GenericKeyedObjectPool#setMaxActive(int)}No8
maxTotal{@link GenericKeyedObjectPool#setMaxTotal(int)}No-1
maxWait{@link GenericKeyedObjectPool#setMaxWait(long)}No-1L
whenExhaustedAction{@link GenericKeyedObjectPool#setWhenExhaustedAction(byte)}No{@link GenericKeyedObjectPool#WHEN_EXHAUSTED_BLOCK}
testOnBorrow{@link GenericKeyedObjectPool#setTestOnBorrow(boolean)}Nofalse
testOnReturn{@link GenericKeyedObjectPool#setTestOnReturn(boolean)}Nofalse
testWhileIdle{@link GenericKeyedObjectPool#setTestWhileIdle(boolean)}Nofalse
timeBetweenEvictionRunsMillis{@link GenericKeyedObjectPool#setTimeBetweenEvictionRunsMillis(long)}No-1L
minEvictableIdleTimeMillis{@link GenericKeyedObjectPool#setMinEvictableIdleTimeMillis(long)}No1000L * 60L * 30L
numTestsPerEvictionRun{@link GenericKeyedObjectPool#setNumTestsPerEvictionRun(int)}No3
Property Description Required Default
contextSource + * The {@link ContextSource} to get {@link DirContext}s from for adding to the + * pool.Yesnull
dirContextValidator + * The {@link DirContextValidator} to use for validating {@link DirContext}s. + * Required if any of the test/validate options are enabled.Nonull
minIdle{@link GenericKeyedObjectPool#setMinIdle(int)}No0
maxIdle{@link GenericKeyedObjectPool#setMaxIdle(int)}No8
maxActive{@link GenericKeyedObjectPool#setMaxActive(int)}No8
maxTotal{@link GenericKeyedObjectPool#setMaxTotal(int)}No-1
maxWait{@link GenericKeyedObjectPool#setMaxWait(long)}No-1L
whenExhaustedAction{@link GenericKeyedObjectPool#setWhenExhaustedAction(byte)}No{@link GenericKeyedObjectPool#WHEN_EXHAUSTED_BLOCK}
testOnBorrow{@link GenericKeyedObjectPool#setTestOnBorrow(boolean)}Nofalse
testOnReturn{@link GenericKeyedObjectPool#setTestOnReturn(boolean)}Nofalse
testWhileIdle{@link GenericKeyedObjectPool#setTestWhileIdle(boolean)}Nofalse
timeBetweenEvictionRunsMillis + * {@link GenericKeyedObjectPool#setTimeBetweenEvictionRunsMillis(long)}No-1L
minEvictableIdleTimeMillis + * {@link GenericKeyedObjectPool#setMinEvictableIdleTimeMillis(long)}No1000L * 60L * 30L
numTestsPerEvictionRun + * {@link GenericKeyedObjectPool#setNumTestsPerEvictionRun(int)}No3
* * * @author Eric Dalquist */ public class PoolingContextSource implements ContextSource, DisposableBean { - /** - * The logger for this class and sub-classes - */ - protected final Log logger = LogFactory.getLog(this.getClass()); - - protected final GenericKeyedObjectPool keyedObjectPool; - private final DirContextPoolableObjectFactory dirContextPoolableObjectFactory; - - /** - * Creates a new pooling context source, setting up the DirContext object factory - * and generic keyed object pool. - */ - public PoolingContextSource() { - this.dirContextPoolableObjectFactory = new DirContextPoolableObjectFactory(); - this.keyedObjectPool = new GenericKeyedObjectPool(); - this.keyedObjectPool.setFactory(this.dirContextPoolableObjectFactory); - } - - - //***** Pool Property Configuration *****// + /** + * The logger for this class and sub-classes + */ + protected final Log logger = LogFactory.getLog(this.getClass()); - /** - * @see org.apache.commons.pool.impl.GenericKeyedObjectPool#getMaxActive() - */ - public int getMaxActive() { - return this.keyedObjectPool.getMaxActive(); - } - /** - * @see org.apache.commons.pool.impl.GenericKeyedObjectPool#getMaxIdle() - */ - public int getMaxIdle() { - return this.keyedObjectPool.getMaxIdle(); - } - /** - * @see org.apache.commons.pool.impl.GenericKeyedObjectPool#getMaxTotal() - */ - public int getMaxTotal() { - return this.keyedObjectPool.getMaxTotal(); - } - /** - * @see org.apache.commons.pool.impl.GenericKeyedObjectPool#getMaxWait() - */ - public long getMaxWait() { - return this.keyedObjectPool.getMaxWait(); - } - /** - * @see org.apache.commons.pool.impl.GenericKeyedObjectPool#getMinEvictableIdleTimeMillis() - */ - public long getMinEvictableIdleTimeMillis() { - return this.keyedObjectPool.getMinEvictableIdleTimeMillis(); - } - /** - * @see org.apache.commons.pool.impl.GenericKeyedObjectPool#getMinIdle() - */ - public int getMinIdle() { - return this.keyedObjectPool.getMinIdle(); - } - /** - * @see org.apache.commons.pool.impl.GenericKeyedObjectPool#getNumActive() - */ - public int getNumActive() { - return this.keyedObjectPool.getNumActive(); - } - /** - * @see org.apache.commons.pool.impl.GenericKeyedObjectPool#getNumIdle() - */ - public int getNumIdle() { - return this.keyedObjectPool.getNumIdle(); - } - /** - * @see org.apache.commons.pool.impl.GenericKeyedObjectPool#getNumTestsPerEvictionRun() - */ - public int getNumTestsPerEvictionRun() { - return this.keyedObjectPool.getNumTestsPerEvictionRun(); - } - /** - * @see org.apache.commons.pool.impl.GenericKeyedObjectPool#getTestOnBorrow() - */ - public boolean getTestOnBorrow() { - return this.keyedObjectPool.getTestOnBorrow(); - } - /** - * @see org.apache.commons.pool.impl.GenericKeyedObjectPool#getTestOnReturn() - */ - public boolean getTestOnReturn() { - return this.keyedObjectPool.getTestOnReturn(); - } - /** - * @see org.apache.commons.pool.impl.GenericKeyedObjectPool#getTestWhileIdle() - */ - public boolean getTestWhileIdle() { - return this.keyedObjectPool.getTestWhileIdle(); - } - /** - * @see org.apache.commons.pool.impl.GenericKeyedObjectPool#getTimeBetweenEvictionRunsMillis() - */ - public long getTimeBetweenEvictionRunsMillis() { - return this.keyedObjectPool.getTimeBetweenEvictionRunsMillis(); - } - /** - * @see org.apache.commons.pool.impl.GenericKeyedObjectPool#getWhenExhaustedAction() - */ - public byte getWhenExhaustedAction() { - return this.keyedObjectPool.getWhenExhaustedAction(); - } - /** - * @see org.apache.commons.pool.impl.GenericKeyedObjectPool#setMaxActive(int) - */ - public void setMaxActive(int maxActive) { - this.keyedObjectPool.setMaxActive(maxActive); - } - /** - * @see org.apache.commons.pool.impl.GenericKeyedObjectPool#setMaxIdle(int) - */ - public void setMaxIdle(int maxIdle) { - this.keyedObjectPool.setMaxIdle(maxIdle); - } - /** - * @see org.apache.commons.pool.impl.GenericKeyedObjectPool#setMaxTotal(int) - */ - public void setMaxTotal(int maxTotal) { - this.keyedObjectPool.setMaxTotal(maxTotal); - } - /** - * @see org.apache.commons.pool.impl.GenericKeyedObjectPool#setMaxWait(long) - */ - public void setMaxWait(long maxWait) { - this.keyedObjectPool.setMaxWait(maxWait); - } - /** - * @see org.apache.commons.pool.impl.GenericKeyedObjectPool#setMinEvictableIdleTimeMillis(long) - */ - public void setMinEvictableIdleTimeMillis(long minEvictableIdleTimeMillis) { - this.keyedObjectPool.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis); - } - /** - * @see org.apache.commons.pool.impl.GenericKeyedObjectPool#setMinIdle(int) - */ - public void setMinIdle(int poolSize) { - this.keyedObjectPool.setMinIdle(poolSize); - } - /** - * @see org.apache.commons.pool.impl.GenericKeyedObjectPool#setNumTestsPerEvictionRun(int) - */ - public void setNumTestsPerEvictionRun(int numTestsPerEvictionRun) { - this.keyedObjectPool.setNumTestsPerEvictionRun(numTestsPerEvictionRun); - } - /** - * @see org.apache.commons.pool.impl.GenericKeyedObjectPool#setTestOnBorrow(boolean) - */ - public void setTestOnBorrow(boolean testOnBorrow) { - this.keyedObjectPool.setTestOnBorrow(testOnBorrow); - } - /** - * @see org.apache.commons.pool.impl.GenericKeyedObjectPool#setTestOnReturn(boolean) - */ - public void setTestOnReturn(boolean testOnReturn) { - this.keyedObjectPool.setTestOnReturn(testOnReturn); - } - /** - * @see org.apache.commons.pool.impl.GenericKeyedObjectPool#setTestWhileIdle(boolean) - */ - public void setTestWhileIdle(boolean testWhileIdle) { - this.keyedObjectPool.setTestWhileIdle(testWhileIdle); - } - /** - * @see org.apache.commons.pool.impl.GenericKeyedObjectPool#setTimeBetweenEvictionRunsMillis(long) - */ - public void setTimeBetweenEvictionRunsMillis(long timeBetweenEvictionRunsMillis) { - this.keyedObjectPool.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis); - } - /** - * @see org.apache.commons.pool.impl.GenericKeyedObjectPool#setWhenExhaustedAction(byte) - */ - public void setWhenExhaustedAction(byte whenExhaustedAction) { - this.keyedObjectPool.setWhenExhaustedAction(whenExhaustedAction); - } - - - //***** Object Factory Property Configuration *****// - - /** - * @return the contextSource - */ - public ContextSource getContextSource() { - return this.dirContextPoolableObjectFactory.getContextSource(); - } - /** - * @return the dirContextValidator - */ - public DirContextValidator getDirContextValidator() { - return this.dirContextPoolableObjectFactory.getDirContextValidator(); - } - /** - * @param contextSource the contextSource to set - * @Required - */ - public void setContextSource(ContextSource contextSource) { - this.dirContextPoolableObjectFactory.setContextSource(contextSource); - } - /** - * @param dirContextValidator the dirContextValidator to set - * @Required - */ - public void setDirContextValidator(DirContextValidator dirContextValidator) { - this.dirContextPoolableObjectFactory.setDirContextValidator(dirContextValidator); - } + protected final GenericKeyedObjectPool keyedObjectPool; - - //***** DisposableBean interface methods *****// + private final DirContextPoolableObjectFactory dirContextPoolableObjectFactory; - /* (non-Javadoc) - * @see org.springframework.beans.factory.DisposableBean#destroy() - */ - public void destroy() throws Exception { - try { - this.keyedObjectPool.close(); - } - catch (Exception e) { - this.logger.warn("An exception occured while closing the underlying pool.", e); - } - } - - - //***** ContextSource interface methods *****// - - /* - * @see ContextSource#getReadOnlyContext() - */ - public DirContext getReadOnlyContext() throws NamingException { - return this.getContext(DirContextType.READ_ONLY); - } + /** + * Creates a new pooling context source, setting up the DirContext object + * factory and generic keyed object pool. + */ + public PoolingContextSource() { + this.dirContextPoolableObjectFactory = new DirContextPoolableObjectFactory(); + this.keyedObjectPool = new GenericKeyedObjectPool(); + this.keyedObjectPool.setFactory(this.dirContextPoolableObjectFactory); + } - /* - * @see ContextSource#getReadWriteContext() - */ - public DirContext getReadWriteContext() throws NamingException { - return this.getContext(DirContextType.READ_WRITE); - } + // ***** Pool Property Configuration *****// - /** - * Gets a DirContext of the specified type from the keyed object pool. - * - * @param dirContextType The type of context to return. - * @return A wrapped DirContext of the specified type. - * @throws DataAccessResourceFailureException If retreiving the object from the pool throws an exception - */ - protected DirContext getContext(DirContextType dirContextType) { - final DirContext dirContext; - try { - dirContext = (DirContext)this.keyedObjectPool.borrowObject(dirContextType); - } - catch (Exception e) { - throw new DataAccessResourceFailureException("Failed to borrow DirContext from pool.", e); - } - - if (dirContext instanceof LdapContext) { - return new DelegatingLdapContext(this.keyedObjectPool, (LdapContext)dirContext, dirContextType); - } + /** + * @see org.apache.commons.pool.impl.GenericKeyedObjectPool#getMaxActive() + */ + public int getMaxActive() { + return this.keyedObjectPool.getMaxActive(); + } - return new DelegatingDirContext(this.keyedObjectPool, dirContext, dirContextType); - } + /** + * @see org.apache.commons.pool.impl.GenericKeyedObjectPool#getMaxIdle() + */ + public int getMaxIdle() { + return this.keyedObjectPool.getMaxIdle(); + } + + /** + * @see org.apache.commons.pool.impl.GenericKeyedObjectPool#getMaxTotal() + */ + public int getMaxTotal() { + return this.keyedObjectPool.getMaxTotal(); + } + + /** + * @see org.apache.commons.pool.impl.GenericKeyedObjectPool#getMaxWait() + */ + public long getMaxWait() { + return this.keyedObjectPool.getMaxWait(); + } + + /** + * @see org.apache.commons.pool.impl.GenericKeyedObjectPool#getMinEvictableIdleTimeMillis() + */ + public long getMinEvictableIdleTimeMillis() { + return this.keyedObjectPool.getMinEvictableIdleTimeMillis(); + } + + /** + * @see org.apache.commons.pool.impl.GenericKeyedObjectPool#getMinIdle() + */ + public int getMinIdle() { + return this.keyedObjectPool.getMinIdle(); + } + + /** + * @see org.apache.commons.pool.impl.GenericKeyedObjectPool#getNumActive() + */ + public int getNumActive() { + return this.keyedObjectPool.getNumActive(); + } + + /** + * @see org.apache.commons.pool.impl.GenericKeyedObjectPool#getNumIdle() + */ + public int getNumIdle() { + return this.keyedObjectPool.getNumIdle(); + } + + /** + * @see org.apache.commons.pool.impl.GenericKeyedObjectPool#getNumTestsPerEvictionRun() + */ + public int getNumTestsPerEvictionRun() { + return this.keyedObjectPool.getNumTestsPerEvictionRun(); + } + + /** + * @see org.apache.commons.pool.impl.GenericKeyedObjectPool#getTestOnBorrow() + */ + public boolean getTestOnBorrow() { + return this.keyedObjectPool.getTestOnBorrow(); + } + + /** + * @see org.apache.commons.pool.impl.GenericKeyedObjectPool#getTestOnReturn() + */ + public boolean getTestOnReturn() { + return this.keyedObjectPool.getTestOnReturn(); + } + + /** + * @see org.apache.commons.pool.impl.GenericKeyedObjectPool#getTestWhileIdle() + */ + public boolean getTestWhileIdle() { + return this.keyedObjectPool.getTestWhileIdle(); + } + + /** + * @see org.apache.commons.pool.impl.GenericKeyedObjectPool#getTimeBetweenEvictionRunsMillis() + */ + public long getTimeBetweenEvictionRunsMillis() { + return this.keyedObjectPool.getTimeBetweenEvictionRunsMillis(); + } + + /** + * @see org.apache.commons.pool.impl.GenericKeyedObjectPool#getWhenExhaustedAction() + */ + public byte getWhenExhaustedAction() { + return this.keyedObjectPool.getWhenExhaustedAction(); + } + + /** + * @see org.apache.commons.pool.impl.GenericKeyedObjectPool#setMaxActive(int) + */ + public void setMaxActive(int maxActive) { + this.keyedObjectPool.setMaxActive(maxActive); + } + + /** + * @see org.apache.commons.pool.impl.GenericKeyedObjectPool#setMaxIdle(int) + */ + public void setMaxIdle(int maxIdle) { + this.keyedObjectPool.setMaxIdle(maxIdle); + } + + /** + * @see org.apache.commons.pool.impl.GenericKeyedObjectPool#setMaxTotal(int) + */ + public void setMaxTotal(int maxTotal) { + this.keyedObjectPool.setMaxTotal(maxTotal); + } + + /** + * @see org.apache.commons.pool.impl.GenericKeyedObjectPool#setMaxWait(long) + */ + public void setMaxWait(long maxWait) { + this.keyedObjectPool.setMaxWait(maxWait); + } + + /** + * @see org.apache.commons.pool.impl.GenericKeyedObjectPool#setMinEvictableIdleTimeMillis(long) + */ + public void setMinEvictableIdleTimeMillis(long minEvictableIdleTimeMillis) { + this.keyedObjectPool.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis); + } + + /** + * @see org.apache.commons.pool.impl.GenericKeyedObjectPool#setMinIdle(int) + */ + public void setMinIdle(int poolSize) { + this.keyedObjectPool.setMinIdle(poolSize); + } + + /** + * @see org.apache.commons.pool.impl.GenericKeyedObjectPool#setNumTestsPerEvictionRun(int) + */ + public void setNumTestsPerEvictionRun(int numTestsPerEvictionRun) { + this.keyedObjectPool.setNumTestsPerEvictionRun(numTestsPerEvictionRun); + } + + /** + * @see org.apache.commons.pool.impl.GenericKeyedObjectPool#setTestOnBorrow(boolean) + */ + public void setTestOnBorrow(boolean testOnBorrow) { + this.keyedObjectPool.setTestOnBorrow(testOnBorrow); + } + + /** + * @see org.apache.commons.pool.impl.GenericKeyedObjectPool#setTestOnReturn(boolean) + */ + public void setTestOnReturn(boolean testOnReturn) { + this.keyedObjectPool.setTestOnReturn(testOnReturn); + } + + /** + * @see org.apache.commons.pool.impl.GenericKeyedObjectPool#setTestWhileIdle(boolean) + */ + public void setTestWhileIdle(boolean testWhileIdle) { + this.keyedObjectPool.setTestWhileIdle(testWhileIdle); + } + + /** + * @see org.apache.commons.pool.impl.GenericKeyedObjectPool#setTimeBetweenEvictionRunsMillis(long) + */ + public void setTimeBetweenEvictionRunsMillis(long timeBetweenEvictionRunsMillis) { + this.keyedObjectPool.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis); + } + + /** + * @see org.apache.commons.pool.impl.GenericKeyedObjectPool#setWhenExhaustedAction(byte) + */ + public void setWhenExhaustedAction(byte whenExhaustedAction) { + this.keyedObjectPool.setWhenExhaustedAction(whenExhaustedAction); + } + + // ***** Object Factory Property Configuration *****// + + /** + * @return the contextSource + */ + public ContextSource getContextSource() { + return this.dirContextPoolableObjectFactory.getContextSource(); + } + + /** + * @return the dirContextValidator + */ + public DirContextValidator getDirContextValidator() { + return this.dirContextPoolableObjectFactory.getDirContextValidator(); + } + + /** + * @param contextSource the contextSource to set + * @Required + */ + public void setContextSource(ContextSource contextSource) { + this.dirContextPoolableObjectFactory.setContextSource(contextSource); + } + + /** + * @param dirContextValidator the dirContextValidator to set + * @Required + */ + public void setDirContextValidator(DirContextValidator dirContextValidator) { + this.dirContextPoolableObjectFactory.setDirContextValidator(dirContextValidator); + } + + // ***** DisposableBean interface methods *****// + + /* + * (non-Javadoc) + * + * @see org.springframework.beans.factory.DisposableBean#destroy() + */ + public void destroy() throws Exception { + try { + this.keyedObjectPool.close(); + } + catch (Exception e) { + this.logger.warn("An exception occured while closing the underlying pool.", e); + } + } + + // ***** ContextSource interface methods *****// + + /* + * @see ContextSource#getReadOnlyContext() + */ + public DirContext getReadOnlyContext() throws NamingException { + return this.getContext(DirContextType.READ_ONLY); + } + + /* + * @see ContextSource#getReadWriteContext() + */ + public DirContext getReadWriteContext() throws NamingException { + return this.getContext(DirContextType.READ_WRITE); + } + + /** + * Gets a DirContext of the specified type from the keyed object pool. + * + * @param dirContextType The type of context to return. + * @return A wrapped DirContext of the specified type. + * @throws DataAccessResourceFailureException If retreiving the object from + * the pool throws an exception + */ + protected DirContext getContext(DirContextType dirContextType) { + final DirContext dirContext; + try { + dirContext = (DirContext) this.keyedObjectPool.borrowObject(dirContextType); + } + catch (Exception e) { + throw new DataAccessResourceFailureException("Failed to borrow DirContext from pool.", e); + } + + if (dirContext instanceof LdapContext) { + return new DelegatingLdapContext(this.keyedObjectPool, (LdapContext) dirContext, dirContextType); + } + + return new DelegatingDirContext(this.keyedObjectPool, dirContext, dirContextType); + } + + public DirContext getContext(String principal, String credentials) throws NamingException { + throw new UnsupportedOperationException("Not supported for this implementation"); + } } diff --git a/mvn-build/core/src/main/java/org/springframework/ldap/transaction/compensating/LdapCompensatingTransactionOperationFactory.java b/mvn-build/core/src/main/java/org/springframework/ldap/transaction/compensating/LdapCompensatingTransactionOperationFactory.java index 968b7396..64023b2b 100644 --- a/mvn-build/core/src/main/java/org/springframework/ldap/transaction/compensating/LdapCompensatingTransactionOperationFactory.java +++ b/mvn-build/core/src/main/java/org/springframework/ldap/transaction/compensating/LdapCompensatingTransactionOperationFactory.java @@ -40,155 +40,144 @@ import org.springframework.transaction.compensating.CompensatingTransactionOpera * @author Mattias Arthursson * @since 1.2 */ -public class LdapCompensatingTransactionOperationFactory implements - CompensatingTransactionOperationFactory { - private static Log log = LogFactory - .getLog(LdapCompensatingTransactionOperationFactory.class); +public class LdapCompensatingTransactionOperationFactory implements CompensatingTransactionOperationFactory { + private static Log log = LogFactory.getLog(LdapCompensatingTransactionOperationFactory.class); - private TempEntryRenamingStrategy renamingStrategy; + private TempEntryRenamingStrategy renamingStrategy; - /** - * Constructor. - * - * @param renamingStrategy - * the {@link TempEntryRenamingStrategy} to supply to relevant - * operations. - */ - public LdapCompensatingTransactionOperationFactory( - TempEntryRenamingStrategy renamingStrategy) { - this.renamingStrategy = renamingStrategy; - } + /** + * Constructor. + * + * @param renamingStrategy the {@link TempEntryRenamingStrategy} to supply + * to relevant operations. + */ + public LdapCompensatingTransactionOperationFactory(TempEntryRenamingStrategy renamingStrategy) { + this.renamingStrategy = renamingStrategy; + } - /* - * @see org.springframework.transaction.compensating.CompensatingTransactionOperationFactory#createRecordingOperation(java.lang.Object, - * java.lang.String) - */ - public CompensatingTransactionOperationRecorder createRecordingOperation( - Object resource, String operation) { - if (StringUtils - .equals(operation, LdapTransactionUtils.BIND_METHOD_NAME)) { - log.debug("Bind operation recorded"); - return new BindOperationRecorder( - createLdapOperationsInstance((DirContext) resource)); - } else if (StringUtils.equals(operation, - LdapTransactionUtils.REBIND_METHOD_NAME)) { - log.debug("Rebind operation recorded"); - return new RebindOperationRecorder( - createLdapOperationsInstance((DirContext) resource), - renamingStrategy); - } else if (StringUtils.equals(operation, - LdapTransactionUtils.RENAME_METHOD_NAME)) { - log.debug("Rename operation recorded"); - return new RenameOperationRecorder( - createLdapOperationsInstance((DirContext) resource)); - } else if (StringUtils.equals(operation, - LdapTransactionUtils.MODIFY_ATTRIBUTES_METHOD_NAME)) { - return new ModifyAttributesOperationRecorder( - createLdapOperationsInstance((DirContext) resource)); - } else if (StringUtils.equals(operation, - LdapTransactionUtils.UNBIND_METHOD_NAME)) { - return new UnbindOperationRecorder( - createLdapOperationsInstance((DirContext) resource), - renamingStrategy); - } + /* + * @seeorg.springframework.transaction.compensating. + * CompensatingTransactionOperationFactory + * #createRecordingOperation(java.lang.Object, java.lang.String) + */ + public CompensatingTransactionOperationRecorder createRecordingOperation(Object resource, String operation) { + if (StringUtils.equals(operation, LdapTransactionUtils.BIND_METHOD_NAME)) { + log.debug("Bind operation recorded"); + return new BindOperationRecorder(createLdapOperationsInstance((DirContext) resource)); + } + else if (StringUtils.equals(operation, LdapTransactionUtils.REBIND_METHOD_NAME)) { + log.debug("Rebind operation recorded"); + return new RebindOperationRecorder(createLdapOperationsInstance((DirContext) resource), renamingStrategy); + } + else if (StringUtils.equals(operation, LdapTransactionUtils.RENAME_METHOD_NAME)) { + log.debug("Rename operation recorded"); + return new RenameOperationRecorder(createLdapOperationsInstance((DirContext) resource)); + } + else if (StringUtils.equals(operation, LdapTransactionUtils.MODIFY_ATTRIBUTES_METHOD_NAME)) { + return new ModifyAttributesOperationRecorder(createLdapOperationsInstance((DirContext) resource)); + } + else if (StringUtils.equals(operation, LdapTransactionUtils.UNBIND_METHOD_NAME)) { + return new UnbindOperationRecorder(createLdapOperationsInstance((DirContext) resource), renamingStrategy); + } - log - .warn("No suitable CompensatingTransactionOperationRecorder found for method " - + operation + ". Operation will not be transacted."); - return new NullOperationRecorder(); - } + log.warn("No suitable CompensatingTransactionOperationRecorder found for method " + operation + + ". Operation will not be transacted."); + return new NullOperationRecorder(); + } - LdapOperations createLdapOperationsInstance(DirContext ctx) { - return new LdapTemplate(new SingleContextSource(ctx)); - } + LdapOperations createLdapOperationsInstance(DirContext ctx) { + return new LdapTemplate(new SingleContextSource(ctx)); + } - /** - * A {@link ContextSource} implementation using returning - * {@link NonClosingDirContextInvocationHandler} proxies on the same - * DirContext instance for each call. - * - * @author Mattias Arthursson - */ - static class SingleContextSource implements ContextSource { - private DirContext ctx; + /** + * A {@link ContextSource} implementation using returning + * {@link NonClosingDirContextInvocationHandler} proxies on the same + * DirContext instance for each call. + * + * @author Mattias Arthursson + */ + static class SingleContextSource implements ContextSource { + private DirContext ctx; - /** - * Constructor. - * - * @param ctx - * the target DirContext. - */ - public SingleContextSource(DirContext ctx) { - this.ctx = ctx; - } + /** + * Constructor. + * + * @param ctx the target DirContext. + */ + public SingleContextSource(DirContext ctx) { + this.ctx = ctx; + } - /* - * @see org.springframework.ldap.ContextSource#getReadOnlyContext() - */ - public DirContext getReadOnlyContext() throws NamingException { - return getNonClosingDirContextProxy(ctx); - } + /* + * @see org.springframework.ldap.ContextSource#getReadOnlyContext() + */ + public DirContext getReadOnlyContext() throws NamingException { + return getNonClosingDirContextProxy(ctx); + } - /* - * @see org.springframework.ldap.ContextSource#getReadWriteContext() - */ - public DirContext getReadWriteContext() throws NamingException { - return getNonClosingDirContextProxy(ctx); - } + /* + * @see org.springframework.ldap.ContextSource#getReadWriteContext() + */ + public DirContext getReadWriteContext() throws NamingException { + return getNonClosingDirContextProxy(ctx); + } - private DirContext getNonClosingDirContextProxy(DirContext context) { - return (DirContext) Proxy.newProxyInstance(DirContextProxy.class - .getClassLoader(), new Class[] { - LdapTransactionUtils.getActualTargetClass(context), - DirContextProxy.class }, - new NonClosingDirContextInvocationHandler(context)); + private DirContext getNonClosingDirContextProxy(DirContext context) { + return (DirContext) Proxy.newProxyInstance(DirContextProxy.class.getClassLoader(), new Class[] { + LdapTransactionUtils.getActualTargetClass(context), DirContextProxy.class }, + new NonClosingDirContextInvocationHandler(context)); - } - } + } - /** - * A proxy for DirContext forwarding all operation to the target DirContext, - * but making sure that no close operations will be - * performed. - * - * @author Mattias Arthursson - */ - public static class NonClosingDirContextInvocationHandler implements - InvocationHandler { + public DirContext getContext(String principal, String credentials) throws NamingException { + throw new UnsupportedOperationException("Not a valid operation for this type of ContextSource"); + } + } - private DirContext target; + /** + * A proxy for DirContext forwarding all operation to the target DirContext, + * but making sure that no close operations will be performed. + * + * @author Mattias Arthursson + */ + public static class NonClosingDirContextInvocationHandler implements InvocationHandler { - public NonClosingDirContextInvocationHandler(DirContext target) { - this.target = target; - } + private DirContext target; - /* - * @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object, - * java.lang.reflect.Method, java.lang.Object[]) - */ - public Object invoke(Object proxy, Method method, Object[] args) - throws Throwable { + public NonClosingDirContextInvocationHandler(DirContext target) { + this.target = target; + } - String methodName = method.getName(); - if (methodName.equals("getTargetContext")) { - return target; - } else if (methodName.equals("equals")) { - // Only consider equal when proxies are identical. - return (proxy == args[0] ? Boolean.TRUE : Boolean.FALSE); - } else if (methodName.equals("hashCode")) { - // Use hashCode of Connection proxy. - return new Integer(proxy.hashCode()); - } else if (methodName.equals("close")) { - // Never close the target context, as this class will only be - // used for operations concerning the compensating transactions. - return null; - } + /* + * @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object, + * java.lang.reflect.Method, java.lang.Object[]) + */ + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - try { - return method.invoke(target, args); - } catch (InvocationTargetException e) { - throw e.getTargetException(); - } - } - } + String methodName = method.getName(); + if (methodName.equals("getTargetContext")) { + return target; + } + else if (methodName.equals("equals")) { + // Only consider equal when proxies are identical. + return (proxy == args[0] ? Boolean.TRUE : Boolean.FALSE); + } + else if (methodName.equals("hashCode")) { + // Use hashCode of Connection proxy. + return new Integer(proxy.hashCode()); + } + else if (methodName.equals("close")) { + // Never close the target context, as this class will only be + // used for operations concerning the compensating transactions. + return null; + } + + try { + return method.invoke(target, args); + } + catch (InvocationTargetException e) { + throw e.getTargetException(); + } + } + } } diff --git a/mvn-build/core/src/main/java/org/springframework/ldap/transaction/compensating/manager/TransactionAwareContextSourceProxy.java b/mvn-build/core/src/main/java/org/springframework/ldap/transaction/compensating/manager/TransactionAwareContextSourceProxy.java index cacf52d8..97df4ff2 100644 --- a/mvn-build/core/src/main/java/org/springframework/ldap/transaction/compensating/manager/TransactionAwareContextSourceProxy.java +++ b/mvn-build/core/src/main/java/org/springframework/ldap/transaction/compensating/manager/TransactionAwareContextSourceProxy.java @@ -98,4 +98,8 @@ public class TransactionAwareContextSourceProxy implements ContextSource { } return getTransactionAwareDirContextProxy(ctx, target); } + + public DirContext getContext(String principal, String credentials) throws NamingException { + throw new UnsupportedOperationException("Not supported on a transacted ContextSource"); + } } diff --git a/mvn-build/core/src/test/java/org/springframework/ldap/core/support/LdapContextSourceTest.java b/mvn-build/core/src/test/java/org/springframework/ldap/core/support/LdapContextSourceTest.java index abce5c51..c4f1a4de 100644 --- a/mvn-build/core/src/test/java/org/springframework/ldap/core/support/LdapContextSourceTest.java +++ b/mvn-build/core/src/test/java/org/springframework/ldap/core/support/LdapContextSourceTest.java @@ -23,7 +23,6 @@ import javax.naming.Context; import junit.framework.TestCase; -import org.springframework.ldap.core.AuthenticationSource; import org.springframework.ldap.core.DistinguishedName; /** @@ -200,7 +199,7 @@ public class LdapContextSourceTest extends TestCase { tested.setPassword("secret"); tested.afterPropertiesSet(); - Hashtable env = tested.getAuthenticatedEnv(); + Hashtable env = tested.getAuthenticatedEnv("cn=Some User", "secret"); assertEquals("ldap://ldap.example.com:389/dc=example,dc=se", env.get(Context.PROVIDER_URL)); assertEquals("true", env.get(LdapContextSource.SUN_LDAP_POOLING_FLAG)); assertEquals("cn=Some User", env.get(Context.SECURITY_PRINCIPAL)); @@ -210,41 +209,6 @@ public class LdapContextSourceTest extends TestCase { assertEquals(new DistinguishedName("dc=example,dc=se"), env.get(DefaultDirObjectFactory.JNDI_ENV_BASE_PATH_KEY)); } - public void testGetAuthenticatedEnv_DummyAuthenticationProvider() throws Exception { - tested.setBase("dc=example,dc=se"); - tested.setUrl("ldap://ldap.example.com:389"); - tested.setPooled(true); - DummyAuthenticationProvider authenticationProvider = new DummyAuthenticationProvider(); - tested.setAuthenticationSource(authenticationProvider); - authenticationProvider.setPrincipal("cn=Some User"); - authenticationProvider.setCredentials("secret"); - tested.afterPropertiesSet(); - - Hashtable env = tested.getAuthenticatedEnv(); - assertEquals("ldap://ldap.example.com:389/dc=example,dc=se", env.get(Context.PROVIDER_URL)); - assertEquals("true", env.get(LdapContextSource.SUN_LDAP_POOLING_FLAG)); - assertEquals("cn=Some User", env.get(Context.SECURITY_PRINCIPAL)); - assertEquals("secret", env.get(Context.SECURITY_CREDENTIALS)); - } - - public void testGetAuthenticatedEnv_DummyAuthenticationProvider_Changed() throws Exception { - tested.setBase("dc=example,dc=se"); - tested.setUrl("ldap://ldap.example.com:389"); - tested.setPooled(true); - DummyAuthenticationProvider authenticationProvider = new DummyAuthenticationProvider(); - tested.setAuthenticationSource(authenticationProvider); - authenticationProvider.setPrincipal("cn=Some User"); - authenticationProvider.setCredentials("secret"); - tested.afterPropertiesSet(); - - authenticationProvider.setPrincipal("cn=Some Other User"); - authenticationProvider.setCredentials("other secret"); - - Hashtable env = tested.getAuthenticatedEnv(); - assertEquals("cn=Some Other User", env.get(Context.SECURITY_PRINCIPAL)); - assertEquals("other secret", env.get(Context.SECURITY_CREDENTIALS)); - } - public void testGetAnonymousEnvWhenCacheIsOff() throws Exception { tested.setBase("dc=example,dc=se"); tested.setUrl("ldap://ldap.example.com:389"); @@ -263,26 +227,4 @@ public class LdapContextSourceTest extends TestCase { env = tested.getAnonymousEnv(); assertEquals("ldap://ldap2.example.com:389/dc=example,dc=se", env.get(Context.PROVIDER_URL)); } - - private class DummyAuthenticationProvider implements AuthenticationSource { - private String principal; - - private String credentials; - - public void setCredentials(String credentials) { - this.credentials = credentials; - } - - public void setPrincipal(String principal) { - this.principal = principal; - } - - public String getPrincipal() { - return principal; - } - - public String getCredentials() { - return credentials; - } - } } diff --git a/mvn-build/integration-tests-openldap/src/test/resources/conf/ldap.properties b/mvn-build/integration-tests-openldap/src/test/resources/conf/ldap.properties index fee074ac..b7834cce 100644 --- a/mvn-build/integration-tests-openldap/src/test/resources/conf/ldap.properties +++ b/mvn-build/integration-tests-openldap/src/test/resources/conf/ldap.properties @@ -1,4 +1,4 @@ -itest.openldap.serverAddress=127.0.0.1 +itest.openldap.serverAddress=spring-ldap-test.dyndns.org userDn=cn=admin,dc=jayway,dc=se password=secret base=dc=jayway,dc=se diff --git a/mvn-build/integration-tests-openldap/src/test/resources/conf/ldapTemplateTestContext.xml b/mvn-build/integration-tests-openldap/src/test/resources/conf/ldapTemplateTestContext.xml index 5965e369..b8dbc97b 100644 --- a/mvn-build/integration-tests-openldap/src/test/resources/conf/ldapTemplateTestContext.xml +++ b/mvn-build/integration-tests-openldap/src/test/resources/conf/ldapTemplateTestContext.xml @@ -15,6 +15,10 @@ + + + +