LDAP-316 - Optional support for apache commons-pool2 added.
This commit is contained in:
committed by
Rob Winch
parent
05b89c3b45
commit
4cefc5b147
@@ -19,7 +19,8 @@ dependencies {
|
||||
"org.springframework:spring-jdbc:$springVersion",
|
||||
"org.springframework:spring-orm:$springVersion",
|
||||
"com.mysema.querydsl:querydsl-apt:$queryDslVersion",
|
||||
"commons-pool:commons-pool:$commonsPoolVersion"
|
||||
"commons-pool:commons-pool:$commonsPoolVersion",
|
||||
"org.apache.commons:commons-pool2:$commonsPool2Version"
|
||||
|
||||
provided "com.sun:ldapbp:1.0"
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2005-2013 the original author or authors.
|
||||
* Copyright 2005-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -27,6 +27,8 @@ import org.springframework.ldap.core.support.LdapContextSource;
|
||||
import org.springframework.ldap.pool.PoolExhaustedAction;
|
||||
import org.springframework.ldap.pool.factory.PoolingContextSource;
|
||||
import org.springframework.ldap.pool.validation.DefaultDirContextValidator;
|
||||
import org.springframework.ldap.pool2.factory.PoolConfig;
|
||||
import org.springframework.ldap.pool2.factory.PooledContextSource;
|
||||
import org.springframework.ldap.transaction.compensating.manager.TransactionAwareContextSourceProxy;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
@@ -72,6 +74,19 @@ public class ContextSourceParser implements BeanDefinitionParser {
|
||||
private static final String ATT_VALIDATION_QUERY_FILTER = "validation-query-filter";
|
||||
private static final String ATT_VALIDATION_QUERY_SEARCH_CONTROLS_REF = "validation-query-search-controls-ref";
|
||||
private static final String ATT_NON_TRANSIENT_EXCEPTIONS = "non-transient-exceptions";
|
||||
private static final String ATT_MAX_IDLE_PER_KEY = "max-idle-per-key";
|
||||
private static final String ATT_MIN_IDLE_PER_KEY = "min-idle-per-key";
|
||||
private static final String ATT_MAX_TOTAL_PER_KEY = "max-total-per-key";
|
||||
private static final String ATT_EVICTION_POLICY_CLASS = "eviction-policy-class";
|
||||
private static final String ATT_FAIRNESS = "fairness";
|
||||
private static final String ATT_JMX_ENABLE = "jmx-enable";
|
||||
private static final String ATT_JMX_NAME_BASE = "jmx-name-base";
|
||||
private static final String ATT_JMX_NAME_PREFIX = "jmx-name-prefix";
|
||||
private static final String ATT_LIFO = "lifo";
|
||||
private static final String ATT_BLOCK_WHEN_EXHAUSTED = "block-when-exhausted";
|
||||
private static final String ATT_TEST_ON_CREATE = "test-on-create";
|
||||
private static final String ATT_SOFT_MIN_EVICTABLE_IDLE_TIME_MILLIS = "soft-min-evictable-idle-time-millis";
|
||||
|
||||
|
||||
private static final String ATT_USERNAME = "username";
|
||||
static final String DEFAULT_ID = "contextSource";
|
||||
@@ -83,6 +98,19 @@ public class ContextSourceParser implements BeanDefinitionParser {
|
||||
private static final int DEFAULT_EVICTION_RUN_MILLIS = -1;
|
||||
private static final int DEFAULT_TESTS_PER_EVICTION_RUN = 3;
|
||||
private static final int DEFAULT_EVICTABLE_MILLIS = 1000 * 60 * 30;
|
||||
private static final int DEFAULT_MAX_TOTAL_PER_KEY = 8;
|
||||
private static final int DEFAULT_MAX_IDLE_PER_KEY = 8;
|
||||
private static final int DEFAULT_MIN_IDLE_PER_KEY = 0;
|
||||
private static final String DEFAULT_EVICTION_POLICY_CLASS_NAME =
|
||||
"org.apache.commons.pool2.impl.DefaultEvictionPolicy";
|
||||
private static final boolean DEFAULT_FAIRNESS = false;
|
||||
private static final boolean DEFAULT_JMX_ENABLE = true;
|
||||
private static final String DEFAULT_JMX_NAME_BASE = null;
|
||||
private static final String DEFAULT_JMX_NAME_PREFIX = "ldap-pool";
|
||||
private static final boolean DEFAULT_LIFO = true;
|
||||
private static final int DEFAULT_MAX_WAIT_MILLIS = -1;
|
||||
private static final boolean DEFAULT_BLOCK_WHEN_EXHAUSTED = true;
|
||||
private static final int DEFAULT_SOFT_MIN_EVICTABLE_IDLE_TIME_MILLIS = -1;
|
||||
|
||||
@Override
|
||||
public BeanDefinition parse(Element element, ParserContext parserContext) {
|
||||
@@ -150,7 +178,12 @@ public class ContextSourceParser implements BeanDefinitionParser {
|
||||
boolean nativePooling) {
|
||||
|
||||
Element poolingElement = DomUtils.getChildElementByTagName(element, Elements.POOLING);
|
||||
if(poolingElement == null) {
|
||||
Element pooling2Element = DomUtils.getChildElementByTagName(element, Elements.POOLING2);
|
||||
|
||||
if (pooling2Element != null && poolingElement != null) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format("%s cannot be enabled together with %s.", Elements.POOLING2, Elements.POOLING));
|
||||
} else if (poolingElement == null && pooling2Element == null) {
|
||||
return targetContextSourceDefinition;
|
||||
}
|
||||
|
||||
@@ -159,26 +192,44 @@ public class ContextSourceParser implements BeanDefinitionParser {
|
||||
String.format("%s cannot be enabled together with %s", ATT_NATIVE_POOLING, Elements.POOLING));
|
||||
}
|
||||
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(PoolingContextSource.class);
|
||||
builder.addPropertyValue("contextSource", targetContextSourceDefinition);
|
||||
if (pooling2Element != null) {
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(PooledContextSource.class);
|
||||
builder.addPropertyValue("contextSource", targetContextSourceDefinition);
|
||||
|
||||
builder.addPropertyValue("maxActive", getInt(poolingElement, ATT_MAX_ACTIVE, DEFAULT_MAX_ACTIVE));
|
||||
builder.addPropertyValue("maxTotal", getInt(poolingElement, ATT_MAX_TOTAL, DEFAULT_MAX_TOTAL));
|
||||
builder.addPropertyValue("maxIdle", getInt(poolingElement, ATT_MAX_IDLE, DEFAULT_MAX_IDLE));
|
||||
builder.addPropertyValue("minIdle", getInt(poolingElement, ATT_MIN_IDLE, DEFAULT_MIN_IDLE));
|
||||
builder.addPropertyValue("maxWait", getInt(poolingElement, ATT_MAX_WAIT, DEFAULT_MAX_WAIT));
|
||||
String whenExhausted = getString(poolingElement, ATT_WHEN_EXHAUSTED, PoolExhaustedAction.BLOCK.name());
|
||||
builder.addPropertyValue("whenExhaustedAction", PoolExhaustedAction.valueOf(whenExhausted).getValue());
|
||||
populatePoolConfigProperties(builder, pooling2Element);
|
||||
|
||||
boolean testOnBorrow = getBoolean(poolingElement, ATT_TEST_ON_BORROW, false);
|
||||
boolean testOnReturn = getBoolean(poolingElement, ATT_TEST_ON_RETURN, false);
|
||||
boolean testWhileIdle = getBoolean(poolingElement, ATT_TEST_WHILE_IDLE, false);
|
||||
boolean testOnBorrow = getBoolean(pooling2Element, ATT_TEST_ON_BORROW, false);
|
||||
boolean testOnReturn = getBoolean(pooling2Element, ATT_TEST_ON_RETURN, false);
|
||||
boolean testWhileIdle = getBoolean(pooling2Element, ATT_TEST_WHILE_IDLE, false);
|
||||
boolean testOnCreate = getBoolean(pooling2Element, ATT_TEST_ON_CREATE, false);
|
||||
|
||||
if(testOnBorrow || testOnReturn || testWhileIdle) {
|
||||
populatePoolValidationProperties(builder, poolingElement, testOnBorrow, testOnReturn, testWhileIdle);
|
||||
if (testOnBorrow || testOnCreate || testWhileIdle || testOnReturn) {
|
||||
populatePoolValidationProperties(builder, pooling2Element);
|
||||
}
|
||||
|
||||
return builder.getBeanDefinition();
|
||||
} else {
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(PoolingContextSource.class);
|
||||
builder.addPropertyValue("contextSource", targetContextSourceDefinition);
|
||||
|
||||
builder.addPropertyValue("maxActive", getInt(poolingElement, ATT_MAX_ACTIVE, DEFAULT_MAX_ACTIVE));
|
||||
builder.addPropertyValue("maxTotal", getInt(poolingElement, ATT_MAX_TOTAL, DEFAULT_MAX_TOTAL));
|
||||
builder.addPropertyValue("maxIdle", getInt(poolingElement, ATT_MAX_IDLE, DEFAULT_MAX_IDLE));
|
||||
builder.addPropertyValue("minIdle", getInt(poolingElement, ATT_MIN_IDLE, DEFAULT_MIN_IDLE));
|
||||
builder.addPropertyValue("maxWait", getInt(poolingElement, ATT_MAX_WAIT, DEFAULT_MAX_WAIT));
|
||||
String whenExhausted = getString(poolingElement, ATT_WHEN_EXHAUSTED, PoolExhaustedAction.BLOCK.name());
|
||||
builder.addPropertyValue("whenExhaustedAction", PoolExhaustedAction.valueOf(whenExhausted).getValue());
|
||||
|
||||
boolean testOnBorrow = getBoolean(poolingElement, ATT_TEST_ON_BORROW, false);
|
||||
boolean testOnReturn = getBoolean(poolingElement, ATT_TEST_ON_RETURN, false);
|
||||
boolean testWhileIdle = getBoolean(poolingElement, ATT_TEST_WHILE_IDLE, false);
|
||||
|
||||
if (testOnBorrow || testOnReturn || testWhileIdle) {
|
||||
populatePoolValidationProperties(builder, poolingElement, testOnBorrow, testOnReturn, testWhileIdle);
|
||||
}
|
||||
|
||||
return builder.getBeanDefinition();
|
||||
}
|
||||
|
||||
return builder.getBeanDefinition();
|
||||
}
|
||||
|
||||
private void populatePoolValidationProperties(BeanDefinitionBuilder builder, Element element,
|
||||
@@ -216,6 +267,63 @@ public class ContextSourceParser implements BeanDefinitionParser {
|
||||
builder.addPropertyValue("nonTransientExceptions", nonTransientExceptionClasses);
|
||||
}
|
||||
|
||||
|
||||
private void populatePoolValidationProperties(BeanDefinitionBuilder builder, Element element) {
|
||||
|
||||
BeanDefinitionBuilder validatorBuilder = BeanDefinitionBuilder.rootBeanDefinition(
|
||||
org.springframework.ldap.pool2.validation.DefaultDirContextValidator.class);
|
||||
validatorBuilder.addPropertyValue("base", getString(element, ATT_VALIDATION_QUERY_BASE, ""));
|
||||
validatorBuilder.addPropertyValue("filter",
|
||||
getString(element, ATT_VALIDATION_QUERY_FILTER,
|
||||
org.springframework.ldap.pool2.validation.DefaultDirContextValidator.DEFAULT_FILTER));
|
||||
String searchControlsRef = element.getAttribute(ATT_VALIDATION_QUERY_SEARCH_CONTROLS_REF);
|
||||
if(StringUtils.hasText(searchControlsRef)) {
|
||||
validatorBuilder.addPropertyReference("searchControls", searchControlsRef);
|
||||
}
|
||||
builder.addPropertyValue("dirContextValidator", validatorBuilder.getBeanDefinition());
|
||||
|
||||
String nonTransientExceptions = getString(element, ATT_NON_TRANSIENT_EXCEPTIONS, CommunicationException.class.getName());
|
||||
String[] strings = StringUtils.commaDelimitedListToStringArray(nonTransientExceptions);
|
||||
Set<Class<?>> nonTransientExceptionClasses = new HashSet<Class<?>>();
|
||||
for (String className : strings) {
|
||||
try {
|
||||
nonTransientExceptionClasses.add(ClassUtils.getDefaultClassLoader().loadClass(className));
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new IllegalArgumentException(String.format("%s is not a valid class name", className), e);
|
||||
}
|
||||
}
|
||||
|
||||
builder.addPropertyValue("nonTransientExceptions", nonTransientExceptionClasses);
|
||||
}
|
||||
|
||||
private void populatePoolConfigProperties(BeanDefinitionBuilder builder, Element element) {
|
||||
BeanDefinitionBuilder configBuilder = BeanDefinitionBuilder
|
||||
.rootBeanDefinition(PoolConfig.class);
|
||||
|
||||
configBuilder.addPropertyValue("maxTotal", getInt(element, ATT_MAX_TOTAL, DEFAULT_MAX_TOTAL));
|
||||
configBuilder.addPropertyValue("maxTotalPerKey", getInt(element, ATT_MAX_TOTAL_PER_KEY, DEFAULT_MAX_TOTAL_PER_KEY));
|
||||
configBuilder.addPropertyValue("maxIdlePerKey", getInt(element, ATT_MAX_IDLE_PER_KEY, DEFAULT_MAX_IDLE_PER_KEY));
|
||||
configBuilder.addPropertyValue("minIdlePerKey", getInt(element, ATT_MIN_IDLE_PER_KEY, DEFAULT_MIN_IDLE_PER_KEY));
|
||||
configBuilder.addPropertyValue("evictionPolicyClassName", getString(element, ATT_EVICTION_POLICY_CLASS, DEFAULT_EVICTION_POLICY_CLASS_NAME));
|
||||
configBuilder.addPropertyValue("fairness", getBoolean(element, ATT_FAIRNESS, DEFAULT_FAIRNESS));
|
||||
configBuilder.addPropertyValue("jmxEnabled", getBoolean(element, ATT_JMX_ENABLE, DEFAULT_JMX_ENABLE));
|
||||
configBuilder.addPropertyValue("jmxNameBase", getString(element, ATT_JMX_NAME_BASE, DEFAULT_JMX_NAME_BASE));
|
||||
configBuilder.addPropertyValue("jmxNamePrefix", getString(element, ATT_JMX_NAME_PREFIX, DEFAULT_JMX_NAME_PREFIX));
|
||||
configBuilder.addPropertyValue("lifo", getBoolean(element, ATT_LIFO, DEFAULT_LIFO));
|
||||
configBuilder.addPropertyValue("maxWaitMillis", getInt(element, ATT_MAX_WAIT, DEFAULT_MAX_WAIT_MILLIS));
|
||||
configBuilder.addPropertyValue("blockWhenExhausted", getBoolean(element, ATT_BLOCK_WHEN_EXHAUSTED, DEFAULT_BLOCK_WHEN_EXHAUSTED));
|
||||
configBuilder.addPropertyValue("testOnBorrow", getBoolean(element, ATT_TEST_ON_BORROW, false));
|
||||
configBuilder.addPropertyValue("testOnCreate", getBoolean(element, ATT_TEST_ON_CREATE, false));
|
||||
configBuilder.addPropertyValue("testOnReturn", getBoolean(element, ATT_TEST_ON_RETURN, false));
|
||||
configBuilder.addPropertyValue("testWhileIdle", getBoolean(element, ATT_TEST_WHILE_IDLE, false));
|
||||
configBuilder.addPropertyValue("timeBetweenEvictionRunsMillis", getInt(element, ATT_EVICTION_RUN_MILLIS, DEFAULT_EVICTION_RUN_MILLIS));
|
||||
configBuilder.addPropertyValue("numTestsPerEvictionRun", getInt(element, ATT_TESTS_PER_EVICTION_RUN, DEFAULT_TESTS_PER_EVICTION_RUN));
|
||||
configBuilder.addPropertyValue("minEvictableIdleTimeMillis", getInt(element, ATT_EVICTABLE_TIME_MILLIS, DEFAULT_EVICTABLE_MILLIS));
|
||||
configBuilder.addPropertyValue("softMinEvictableIdleTimeMillis", getInt(element, ATT_SOFT_MIN_EVICTABLE_IDLE_TIME_MILLIS, DEFAULT_SOFT_MIN_EVICTABLE_IDLE_TIME_MILLIS));
|
||||
|
||||
builder.addConstructorArgValue(configBuilder.getBeanDefinition());
|
||||
}
|
||||
|
||||
static class UrlsFactory {
|
||||
public static String[] urls(String value) {
|
||||
return StringUtils.commaDelimitedListToStringArray(value);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2005-2013 the original author or authors.
|
||||
* Copyright 2005-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -18,10 +18,12 @@ package org.springframework.ldap.config;
|
||||
|
||||
/**
|
||||
* @author Mattias Hellborg Arthursson
|
||||
* @author Anindya Chatterjee
|
||||
*/
|
||||
public abstract class Elements {
|
||||
public static final String CONTEXT_SOURCE = "context-source";
|
||||
public static final String POOLING = "pooling";
|
||||
public static final String POOLING2 = "pooling2";
|
||||
public static final String LDAP_TEMPLATE = "ldap-template";
|
||||
public static final String TRANSACTION_MANAGER = "transaction-manager";
|
||||
public static final String REPOSITORIES = "repositories";
|
||||
|
||||
@@ -0,0 +1,390 @@
|
||||
/*
|
||||
* Copyright 2005-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.ldap.pool2;
|
||||
|
||||
|
||||
import org.apache.commons.pool2.KeyedObjectPool;
|
||||
import org.springframework.ldap.pool2.factory.PooledContextSource;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import javax.naming.*;
|
||||
import java.util.Hashtable;
|
||||
|
||||
/**
|
||||
* Used by {@link PooledContextSource} to wrap a {@link Context}, delegating most methods
|
||||
* to the underlying context, retains a reference to the pool the context was checked out
|
||||
* from and returns itself to the pool when {@link #close()} is called.
|
||||
*
|
||||
* @since 2.0
|
||||
* @author Eric Dalquist
|
||||
*/
|
||||
public class DelegatingContext implements Context {
|
||||
private KeyedObjectPool keyedObjectPool;
|
||||
private Context delegateContext;
|
||||
private final DirContextType dirContextType;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new delegating context for the specified pool, context and context type.
|
||||
*
|
||||
* @param keyedObjectPool The pool the delegate context was checked out from.
|
||||
* @param delegateContext The context to delegate operations to.
|
||||
* @param dirContextType The type of context, used as a key for the pool.
|
||||
* @throws IllegalArgumentException if any of the arguments are null
|
||||
*/
|
||||
public DelegatingContext(KeyedObjectPool keyedObjectPool, Context delegateContext, DirContextType dirContextType) {
|
||||
Assert.notNull(keyedObjectPool, "keyedObjectPool may not be null");
|
||||
Assert.notNull(delegateContext, "delegateContext may not be null");
|
||||
Assert.notNull(dirContextType, "dirContextType may not be null");
|
||||
|
||||
this.keyedObjectPool = keyedObjectPool;
|
||||
this.delegateContext = delegateContext;
|
||||
this.dirContextType = dirContextType;
|
||||
}
|
||||
|
||||
|
||||
//***** Helper Methods *****//
|
||||
|
||||
/**
|
||||
* @return The direct delegate for this context proxy
|
||||
*/
|
||||
public Context getDelegateContext() {
|
||||
return this.delegateContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursivley inspect delegates until a non-delegating context is found.
|
||||
*
|
||||
* @return The innermost (real) Context that is being delegated to.
|
||||
*/
|
||||
public Context getInnermostDelegateContext() {
|
||||
final Context delegateContext = this.getDelegateContext();
|
||||
|
||||
if (delegateContext instanceof DelegatingContext) {
|
||||
return ((DelegatingContext)delegateContext).getInnermostDelegateContext();
|
||||
}
|
||||
|
||||
return delegateContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws NamingException If the delegate is null, {@link #close()} has been called.
|
||||
*/
|
||||
protected void assertOpen() throws NamingException {
|
||||
if (this.delegateContext == null) {
|
||||
throw new NamingException("Context is closed.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//***** Object methods *****//
|
||||
|
||||
/**
|
||||
* @see Object#equals(Object)
|
||||
*/
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (!(obj instanceof Context)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final Context thisContext = this.getInnermostDelegateContext();
|
||||
Context otherContext = (Context)obj;
|
||||
if (otherContext instanceof DelegatingContext) {
|
||||
otherContext = ((DelegatingContext)otherContext).getInnermostDelegateContext();
|
||||
}
|
||||
|
||||
return thisContext == otherContext || (thisContext != null && thisContext.equals(otherContext));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Object#hashCode()
|
||||
*/
|
||||
public int hashCode() {
|
||||
final Context context = this.getInnermostDelegateContext();
|
||||
return (context != null ? context.hashCode() : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Object#toString()
|
||||
*/
|
||||
public String toString() {
|
||||
final Context context = this.getInnermostDelegateContext();
|
||||
return (context != null ? context.toString() : "Context is closed");
|
||||
}
|
||||
|
||||
|
||||
//***** Context Interface Delegates *****//
|
||||
|
||||
/**
|
||||
* @see Context#addToEnvironment(String, Object)
|
||||
*/
|
||||
public Object addToEnvironment(String propName, Object propVal) throws NamingException {
|
||||
throw new UnsupportedOperationException("Cannot call addToEnvironment on a pooled context");
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Context#bind(Name, Object)
|
||||
*/
|
||||
public void bind(Name name, Object obj) throws NamingException {
|
||||
this.assertOpen();
|
||||
this.getDelegateContext().bind(name, obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Context#bind(String, Object)
|
||||
*/
|
||||
public void bind(String name, Object obj) throws NamingException {
|
||||
this.assertOpen();
|
||||
this.getDelegateContext().bind(name, obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Context#close()
|
||||
*/
|
||||
public void close() throws NamingException {
|
||||
final Context context = this.getInnermostDelegateContext();
|
||||
if (context == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
//Get a local reference so the member can be nulled earlier
|
||||
this.delegateContext = null;
|
||||
|
||||
//Return the object to the Pool and then null the pool reference
|
||||
try {
|
||||
boolean valid = true;
|
||||
|
||||
if (context instanceof FailureAwareContext) {
|
||||
FailureAwareContext failureAwareContext = (FailureAwareContext) context;
|
||||
if(failureAwareContext.hasFailed()) {
|
||||
valid = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (valid) {
|
||||
this.keyedObjectPool.returnObject(this.dirContextType, context);
|
||||
} else {
|
||||
this.keyedObjectPool.invalidateObject(this.dirContextType, context);
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
final NamingException namingException = new NamingException("Failed to return delegate Context to pool.");
|
||||
namingException.setRootCause(e);
|
||||
throw namingException;
|
||||
}
|
||||
finally {
|
||||
this.keyedObjectPool = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Context#composeName(Name, Name)
|
||||
*/
|
||||
public Name composeName(Name name, Name prefix) throws NamingException {
|
||||
this.assertOpen();
|
||||
return this.getDelegateContext().composeName(name, prefix);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Context#composeName(String, String)
|
||||
*/
|
||||
public String composeName(String name, String prefix) throws NamingException {
|
||||
this.assertOpen();
|
||||
return this.getDelegateContext().composeName(name, prefix);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Context#createSubcontext(Name)
|
||||
*/
|
||||
public Context createSubcontext(Name name) throws NamingException {
|
||||
throw new UnsupportedOperationException("Cannot call createSubcontext on a pooled context");
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Context#createSubcontext(String)
|
||||
*/
|
||||
public Context createSubcontext(String name) throws NamingException {
|
||||
throw new UnsupportedOperationException("Cannot call createSubcontext on a pooled context");
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Context#destroySubcontext(Name)
|
||||
*/
|
||||
public void destroySubcontext(Name name) throws NamingException {
|
||||
throw new UnsupportedOperationException("Cannot call destroySubcontext on a pooled context");
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Context#destroySubcontext(String)
|
||||
*/
|
||||
public void destroySubcontext(String name) throws NamingException {
|
||||
throw new UnsupportedOperationException("Cannot call destroySubcontext on a pooled context");
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Context#getEnvironment()
|
||||
*/
|
||||
public Hashtable<?, ?> getEnvironment() throws NamingException {
|
||||
this.assertOpen();
|
||||
return this.getDelegateContext().getEnvironment();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Context#getNameInNamespace()
|
||||
*/
|
||||
public String getNameInNamespace() throws NamingException {
|
||||
this.assertOpen();
|
||||
return this.getDelegateContext().getNameInNamespace();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Context#getNameParser(Name)
|
||||
*/
|
||||
public NameParser getNameParser(Name name) throws NamingException {
|
||||
this.assertOpen();
|
||||
return this.getDelegateContext().getNameParser(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Context#getNameParser(String)
|
||||
*/
|
||||
public NameParser getNameParser(String name) throws NamingException {
|
||||
this.assertOpen();
|
||||
return this.getDelegateContext().getNameParser(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Context#list(Name)
|
||||
*/
|
||||
public NamingEnumeration<NameClassPair> list(Name name) throws NamingException {
|
||||
this.assertOpen();
|
||||
return this.getDelegateContext().list(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Context#list(String)
|
||||
*/
|
||||
public NamingEnumeration<NameClassPair> list(String name) throws NamingException {
|
||||
this.assertOpen();
|
||||
return this.getDelegateContext().list(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Context#listBindings(Name)
|
||||
*/
|
||||
public NamingEnumeration<Binding> listBindings(Name name) throws NamingException {
|
||||
this.assertOpen();
|
||||
return this.getDelegateContext().listBindings(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Context#listBindings(String)
|
||||
*/
|
||||
public NamingEnumeration<Binding> listBindings(String name) throws NamingException {
|
||||
this.assertOpen();
|
||||
return this.getDelegateContext().listBindings(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Context#lookup(Name)
|
||||
*/
|
||||
public Object lookup(Name name) throws NamingException {
|
||||
this.assertOpen();
|
||||
return this.getDelegateContext().lookup(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Context#lookup(String)
|
||||
*/
|
||||
public Object lookup(String name) throws NamingException {
|
||||
this.assertOpen();
|
||||
return this.getDelegateContext().lookup(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Context#lookupLink(Name)
|
||||
*/
|
||||
public Object lookupLink(Name name) throws NamingException {
|
||||
this.assertOpen();
|
||||
return this.getDelegateContext().lookupLink(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Context#lookupLink(String)
|
||||
*/
|
||||
public Object lookupLink(String name) throws NamingException {
|
||||
this.assertOpen();
|
||||
return this.getDelegateContext().lookupLink(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Context#rebind(Name, Object)
|
||||
*/
|
||||
public void rebind(Name name, Object obj) throws NamingException {
|
||||
this.assertOpen();
|
||||
this.getDelegateContext().rebind(name, obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Context#rebind(String, Object)
|
||||
*/
|
||||
public void rebind(String name, Object obj) throws NamingException {
|
||||
this.assertOpen();
|
||||
this.getDelegateContext().rebind(name, obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Context#removeFromEnvironment(String)
|
||||
*/
|
||||
public Object removeFromEnvironment(String propName) throws NamingException {
|
||||
throw new UnsupportedOperationException("Cannot call removeFromEnvironment on a pooled context");
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Context#rename(Name, Name)
|
||||
*/
|
||||
public void rename(Name oldName, Name newName) throws NamingException {
|
||||
this.assertOpen();
|
||||
this.getDelegateContext().rename(oldName, newName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Context#rename(String, String)
|
||||
*/
|
||||
public void rename(String oldName, String newName) throws NamingException {
|
||||
this.assertOpen();
|
||||
this.getDelegateContext().rename(oldName, newName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Context#unbind(Name)
|
||||
*/
|
||||
public void unbind(Name name) throws NamingException {
|
||||
this.assertOpen();
|
||||
this.getDelegateContext().unbind(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Context#unbind(String)
|
||||
*/
|
||||
public void unbind(String name) throws NamingException {
|
||||
this.assertOpen();
|
||||
this.getDelegateContext().unbind(name);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,361 @@
|
||||
/*
|
||||
* Copyright 2005-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.ldap.pool2;
|
||||
|
||||
import org.apache.commons.pool2.KeyedObjectPool;
|
||||
import org.springframework.ldap.core.DirContextProxy;
|
||||
import org.springframework.ldap.pool2.DirContextType;
|
||||
import org.springframework.ldap.pool2.factory.PooledContextSource;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import javax.naming.Context;
|
||||
import javax.naming.Name;
|
||||
import javax.naming.NamingEnumeration;
|
||||
import javax.naming.NamingException;
|
||||
import javax.naming.directory.*;
|
||||
|
||||
|
||||
/**
|
||||
* Used by {@link PooledContextSource} to wrap a {@link DirContext}, delegating most methods
|
||||
* to the underlying context. This class extends {@link DelegatingContext} which handles returning
|
||||
* the context to the pool on a call to {@link #close()}
|
||||
*
|
||||
* @since 2.0
|
||||
* @author Eric Dalquist
|
||||
* @author Anindya Chatterjee
|
||||
*/
|
||||
public class DelegatingDirContext extends DelegatingContext implements DirContext, DirContextProxy {
|
||||
private DirContext delegateDirContext;
|
||||
|
||||
/**
|
||||
* Create a new delegating dir context for the specified pool, context and context type.
|
||||
*
|
||||
* @param keyedObjectPool The pool the delegate context was checked out from.
|
||||
* @param delegateDirContext The dir context to delegate operations to.
|
||||
* @param dirContextType The type of context, used as a key for the pool.
|
||||
* @throws IllegalArgumentException if any of the arguments are null
|
||||
*/
|
||||
public DelegatingDirContext(KeyedObjectPool keyedObjectPool,
|
||||
DirContext delegateDirContext, DirContextType dirContextType) {
|
||||
super(keyedObjectPool, delegateDirContext, dirContextType);
|
||||
Assert.notNull(delegateDirContext, "delegateDirContext may not be null");
|
||||
|
||||
this.delegateDirContext = delegateDirContext;
|
||||
}
|
||||
|
||||
|
||||
//***** Helper Methods *****//
|
||||
|
||||
/**
|
||||
* @return The direct delegate for this dir context proxy
|
||||
*/
|
||||
public DirContext getDelegateDirContext() {
|
||||
return this.delegateDirContext;
|
||||
}
|
||||
|
||||
public Context getDelegateContext() {
|
||||
return this.getDelegateDirContext();
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursivley inspect delegates until a non-delegating dir context is found.
|
||||
*
|
||||
* @return The innermost (real) DirContext that is being delegated to.
|
||||
*/
|
||||
public DirContext getInnermostDelegateDirContext() {
|
||||
final DirContext delegateDirContext = this.getDelegateDirContext();
|
||||
|
||||
if (delegateDirContext instanceof DelegatingDirContext) {
|
||||
return ((DelegatingDirContext)delegateDirContext).getInnermostDelegateDirContext();
|
||||
}
|
||||
|
||||
return delegateDirContext;
|
||||
}
|
||||
|
||||
protected void assertOpen() throws NamingException {
|
||||
if (this.delegateDirContext == null) {
|
||||
throw new NamingException("DirContext is closed.");
|
||||
}
|
||||
|
||||
super.assertOpen();
|
||||
}
|
||||
|
||||
|
||||
//***** Object methods *****//
|
||||
|
||||
/**
|
||||
* @see Object#equals(Object)
|
||||
*/
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (!(obj instanceof DirContext)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final DirContext thisDirContext = this.getInnermostDelegateDirContext();
|
||||
DirContext otherDirContext = (DirContext)obj;
|
||||
if (otherDirContext instanceof DelegatingDirContext) {
|
||||
otherDirContext = ((DelegatingDirContext)otherDirContext).getInnermostDelegateDirContext();
|
||||
}
|
||||
|
||||
return thisDirContext == otherDirContext || (thisDirContext != null && thisDirContext.equals(otherDirContext));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Object#hashCode()
|
||||
*/
|
||||
public int hashCode() {
|
||||
final DirContext context = this.getInnermostDelegateDirContext();
|
||||
return (context != null ? context.hashCode() : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Object#toString()
|
||||
*/
|
||||
public String toString() {
|
||||
final DirContext context = this.getInnermostDelegateDirContext();
|
||||
return (context != null ? context.toString() : "DirContext is closed");
|
||||
}
|
||||
|
||||
|
||||
//***** DirContextProxy Interface Methods *****//
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.ldap.core.DirContextProxy#getTargetContext()
|
||||
*/
|
||||
public DirContext getTargetContext() {
|
||||
return this.getInnermostDelegateDirContext();
|
||||
}
|
||||
|
||||
|
||||
//***** DirContext Interface Delegates *****//
|
||||
|
||||
/**
|
||||
* @see DirContext#bind(Name, Object, Attributes)
|
||||
*/
|
||||
public void bind(Name name, Object obj, Attributes attrs) throws NamingException {
|
||||
this.assertOpen();
|
||||
this.getDelegateDirContext().bind(name, obj, attrs);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DirContext#bind(String, Object, Attributes)
|
||||
*/
|
||||
public void bind(String name, Object obj, Attributes attrs) throws NamingException {
|
||||
this.assertOpen();
|
||||
this.getDelegateDirContext().bind(name, obj, attrs);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DirContext#createSubcontext(Name, Attributes)
|
||||
*/
|
||||
public DirContext createSubcontext(Name name, Attributes attrs) throws NamingException {
|
||||
throw new UnsupportedOperationException("Cannot call createSubcontext on a pooled context");
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DirContext#createSubcontext(String, Attributes)
|
||||
*/
|
||||
public DirContext createSubcontext(String name, Attributes attrs) throws NamingException {
|
||||
throw new UnsupportedOperationException("Cannot call createSubcontext on a pooled context");
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DirContext#getAttributes(Name, String[])
|
||||
*/
|
||||
public Attributes getAttributes(Name name, String[] attrIds) throws NamingException {
|
||||
this.assertOpen();
|
||||
return this.getDelegateDirContext().getAttributes(name, attrIds);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DirContext#getAttributes(Name)
|
||||
*/
|
||||
public Attributes getAttributes(Name name) throws NamingException {
|
||||
this.assertOpen();
|
||||
return this.getDelegateDirContext().getAttributes(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DirContext#getAttributes(String, String[])
|
||||
*/
|
||||
public Attributes getAttributes(String name, String[] attrIds) throws NamingException {
|
||||
this.assertOpen();
|
||||
return this.getDelegateDirContext().getAttributes(name, attrIds);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DirContext#getAttributes(String)
|
||||
*/
|
||||
public Attributes getAttributes(String name) throws NamingException {
|
||||
this.assertOpen();
|
||||
return this.getDelegateDirContext().getAttributes(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DirContext#getSchema(Name)
|
||||
*/
|
||||
public DirContext getSchema(Name name) throws NamingException {
|
||||
throw new UnsupportedOperationException("Cannot call getSchema on a pooled context");
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DirContext#getSchema(String)
|
||||
*/
|
||||
public DirContext getSchema(String name) throws NamingException {
|
||||
throw new UnsupportedOperationException("Cannot call getSchema on a pooled context");
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DirContext#getSchemaClassDefinition(Name)
|
||||
*/
|
||||
public DirContext getSchemaClassDefinition(Name name) throws NamingException {
|
||||
throw new UnsupportedOperationException("Cannot call getSchemaClassDefinition on a pooled context");
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DirContext#getSchemaClassDefinition(String)
|
||||
*/
|
||||
public DirContext getSchemaClassDefinition(String name) throws NamingException {
|
||||
throw new UnsupportedOperationException("Cannot call getSchemaClassDefinition on a pooled context");
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DirContext#modifyAttributes(Name, int, Attributes)
|
||||
*/
|
||||
public void modifyAttributes(Name name, int modOp, Attributes attrs) throws NamingException {
|
||||
this.assertOpen();
|
||||
this.getDelegateDirContext().modifyAttributes(name, modOp, attrs);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DirContext#modifyAttributes(Name, ModificationItem[])
|
||||
*/
|
||||
public void modifyAttributes(Name name, ModificationItem[] mods) throws NamingException {
|
||||
this.assertOpen();
|
||||
this.getDelegateDirContext().modifyAttributes(name, mods);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DirContext#modifyAttributes(String, int, Attributes)
|
||||
*/
|
||||
public void modifyAttributes(String name, int modOp, Attributes attrs) throws NamingException {
|
||||
this.assertOpen();
|
||||
this.getDelegateDirContext().modifyAttributes(name, modOp, attrs);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DirContext#modifyAttributes(String, ModificationItem[])
|
||||
*/
|
||||
public void modifyAttributes(String name, ModificationItem[] mods) throws NamingException {
|
||||
this.assertOpen();
|
||||
this.getDelegateDirContext().modifyAttributes(name, mods);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DirContext#rebind(Name, Object, Attributes)
|
||||
*/
|
||||
public void rebind(Name name, Object obj, Attributes attrs) throws NamingException {
|
||||
this.assertOpen();
|
||||
this.getDelegateDirContext().rebind(name, obj, attrs);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DirContext#rebind(String, Object, Attributes)
|
||||
*/
|
||||
public void rebind(String name, Object obj, Attributes attrs) throws NamingException {
|
||||
this.assertOpen();
|
||||
this.getDelegateDirContext().rebind(name, obj, attrs);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DirContext#search(Name, Attributes, String[])
|
||||
*/
|
||||
public NamingEnumeration<SearchResult> search(Name name, Attributes matchingAttributes, String[] attributesToReturn) throws NamingException {
|
||||
this.assertOpen();
|
||||
return this.getDelegateDirContext().search(name, matchingAttributes, attributesToReturn);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DirContext#search(Name, Attributes)
|
||||
*/
|
||||
public NamingEnumeration<SearchResult> search(Name name, Attributes matchingAttributes) throws NamingException {
|
||||
this.assertOpen();
|
||||
return this.getDelegateDirContext().search(name, matchingAttributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DirContext#search(Name, String, Object[], SearchControls)
|
||||
*/
|
||||
public NamingEnumeration<SearchResult> search(Name name, String filterExpr, Object[] filterArgs, SearchControls cons) throws NamingException {
|
||||
this.assertOpen();
|
||||
return this.getDelegateDirContext().search(name, filterExpr, filterArgs, cons);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DirContext#search(Name, String, SearchControls)
|
||||
*/
|
||||
public NamingEnumeration<SearchResult> search(Name name, String filter, SearchControls cons) throws NamingException {
|
||||
this.assertOpen();
|
||||
return this.getDelegateDirContext().search(name, filter, cons);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DirContext#search(String, Attributes, String[])
|
||||
*/
|
||||
public NamingEnumeration<SearchResult> search(String name, Attributes matchingAttributes, String[] attributesToReturn) throws NamingException {
|
||||
this.assertOpen();
|
||||
return this.getDelegateDirContext().search(name, matchingAttributes, attributesToReturn);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DirContext#search(String, Attributes)
|
||||
*/
|
||||
public NamingEnumeration<SearchResult> search(String name, Attributes matchingAttributes) throws NamingException {
|
||||
this.assertOpen();
|
||||
return this.getDelegateDirContext().search(name, matchingAttributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DirContext#search(String, String, Object[], SearchControls)
|
||||
*/
|
||||
public NamingEnumeration<SearchResult> search(String name, String filterExpr, Object[] filterArgs, SearchControls cons) throws NamingException {
|
||||
this.assertOpen();
|
||||
return this.getDelegateDirContext().search(name, filterExpr, filterArgs, cons);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DirContext#search(String, String, SearchControls)
|
||||
*/
|
||||
public NamingEnumeration<SearchResult> search(String name, String filter, SearchControls cons) throws NamingException {
|
||||
this.assertOpen();
|
||||
return this.getDelegateDirContext().search(name, filter, cons);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DelegatingContext#close()
|
||||
*/
|
||||
public void close() throws NamingException {
|
||||
if (this.delegateDirContext == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
super.close();
|
||||
this.delegateDirContext = null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,202 @@
|
||||
/*
|
||||
* Copyright 2005-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.ldap.pool2;
|
||||
|
||||
import org.apache.commons.pool2.KeyedObjectPool;
|
||||
import org.springframework.ldap.pool2.DirContextType;
|
||||
import org.springframework.ldap.pool2.factory.PooledContextSource;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import javax.naming.NamingException;
|
||||
import javax.naming.directory.DirContext;
|
||||
import javax.naming.ldap.Control;
|
||||
import javax.naming.ldap.ExtendedRequest;
|
||||
import javax.naming.ldap.ExtendedResponse;
|
||||
import javax.naming.ldap.LdapContext;
|
||||
|
||||
/**
|
||||
* Used by {@link PooledContextSource} to wrap a {@link LdapContext}, delegating most methods
|
||||
* to the underlying context. This class extends {@link DelegatingDirContext} which handles returning
|
||||
* the context to the pool on a call to {@link #close()}
|
||||
*
|
||||
* @since 2.0
|
||||
* @author Eric Dalquist
|
||||
* @author Anindya Chatterjee
|
||||
*/
|
||||
public class DelegatingLdapContext extends DelegatingDirContext implements LdapContext {
|
||||
private LdapContext delegateLdapContext;
|
||||
|
||||
/**
|
||||
* Create a new delegating ldap context for the specified pool, context and context type.
|
||||
*
|
||||
* @param keyedObjectPool The pool the delegate context was checked out from.
|
||||
* @param delegateLdapContext The ldap context to delegate operations to.
|
||||
* @param dirContextType The type of context, used as a key for the pool.
|
||||
* @throws IllegalArgumentException if any of the arguments are null
|
||||
*/
|
||||
public DelegatingLdapContext(KeyedObjectPool keyedObjectPool,
|
||||
LdapContext delegateLdapContext, DirContextType dirContextType) {
|
||||
super(keyedObjectPool, delegateLdapContext, dirContextType);
|
||||
Assert.notNull(delegateLdapContext, "delegateLdapContext may not be null");
|
||||
|
||||
this.delegateLdapContext = delegateLdapContext;
|
||||
}
|
||||
|
||||
|
||||
//***** Helper Methods *****//
|
||||
|
||||
/**
|
||||
* @return The direct delegate for this ldap context proxy
|
||||
*/
|
||||
public LdapContext getDelegateLdapContext() {
|
||||
return this.delegateLdapContext;
|
||||
}
|
||||
|
||||
// cannot return subtype in overridden method unless Java5
|
||||
public DirContext getDelegateDirContext() {
|
||||
return this.getDelegateLdapContext();
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursivley inspect delegates until a non-delegating ldap context is found.
|
||||
*
|
||||
* @return The innermost (real) DirContext that is being delegated to.
|
||||
*/
|
||||
public LdapContext getInnermostDelegateLdapContext() {
|
||||
final LdapContext delegateLdapContext = this.getDelegateLdapContext();
|
||||
|
||||
if (delegateLdapContext instanceof DelegatingLdapContext) {
|
||||
return ((DelegatingLdapContext)delegateLdapContext).getInnermostDelegateLdapContext();
|
||||
}
|
||||
|
||||
return delegateLdapContext;
|
||||
}
|
||||
|
||||
protected void assertOpen() throws NamingException {
|
||||
if (this.delegateLdapContext == null) {
|
||||
throw new NamingException("LdapContext is closed.");
|
||||
}
|
||||
|
||||
super.assertOpen();
|
||||
}
|
||||
|
||||
|
||||
//***** Object methods *****//
|
||||
|
||||
/**
|
||||
* @see Object#equals(Object)
|
||||
*/
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (!(obj instanceof LdapContext)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final LdapContext thisLdapContext = this.getInnermostDelegateLdapContext();
|
||||
LdapContext otherLdapContext = (LdapContext)obj;
|
||||
if (otherLdapContext instanceof DelegatingLdapContext) {
|
||||
otherLdapContext = ((DelegatingLdapContext)otherLdapContext).getInnermostDelegateLdapContext();
|
||||
}
|
||||
|
||||
return thisLdapContext == otherLdapContext || (thisLdapContext != null && thisLdapContext.equals(otherLdapContext));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Object#hashCode()
|
||||
*/
|
||||
public int hashCode() {
|
||||
final LdapContext context = this.getInnermostDelegateLdapContext();
|
||||
return (context != null ? context.hashCode() : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Object#toString()
|
||||
*/
|
||||
public String toString() {
|
||||
final LdapContext context = this.getInnermostDelegateLdapContext();
|
||||
return (context != null ? context.toString() : "LdapContext is closed");
|
||||
}
|
||||
|
||||
|
||||
//***** LdapContext Interface Delegates *****//
|
||||
|
||||
/**
|
||||
* @see LdapContext#extendedOperation(ExtendedRequest)
|
||||
*/
|
||||
public ExtendedResponse extendedOperation(ExtendedRequest request) throws NamingException {
|
||||
this.assertOpen();
|
||||
return this.getDelegateLdapContext().extendedOperation(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see LdapContext#getConnectControls()
|
||||
*/
|
||||
public Control[] getConnectControls() throws NamingException {
|
||||
this.assertOpen();
|
||||
return this.getDelegateLdapContext().getConnectControls();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see LdapContext#getRequestControls()
|
||||
*/
|
||||
public Control[] getRequestControls() throws NamingException {
|
||||
this.assertOpen();
|
||||
return this.getDelegateLdapContext().getRequestControls();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see LdapContext#getResponseControls()
|
||||
*/
|
||||
public Control[] getResponseControls() throws NamingException {
|
||||
this.assertOpen();
|
||||
return this.getDelegateLdapContext().getResponseControls();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see LdapContext#newInstance(Control[])
|
||||
*/
|
||||
public LdapContext newInstance(Control[] requestControls) throws NamingException {
|
||||
throw new UnsupportedOperationException("Cannot call newInstance on a pooled context");
|
||||
}
|
||||
|
||||
/**
|
||||
* @see LdapContext#reconnect(Control[])
|
||||
*/
|
||||
public void reconnect(Control[] connCtls) throws NamingException {
|
||||
throw new UnsupportedOperationException("Cannot call reconnect on a pooled context");
|
||||
}
|
||||
|
||||
/**
|
||||
* @see LdapContext#setRequestControls(Control[])
|
||||
*/
|
||||
public void setRequestControls(Control[] requestControls) throws NamingException {
|
||||
throw new UnsupportedOperationException("Cannot call setRequestControls on a pooled context");
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DelegatingDirContext#close()
|
||||
*/
|
||||
public void close() throws NamingException {
|
||||
if (this.delegateLdapContext == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
super.close();
|
||||
this.delegateLdapContext = null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2005-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.ldap.pool2;
|
||||
|
||||
import org.springframework.ldap.core.ContextSource;
|
||||
|
||||
import javax.naming.directory.DirContext;
|
||||
|
||||
|
||||
/**
|
||||
* An enum representing the two types of {@link DirContext}s that can be returned by a
|
||||
* {@link ContextSource}.
|
||||
*
|
||||
* @author Eric Dalquist
|
||||
*/
|
||||
public final class DirContextType {
|
||||
private String name;
|
||||
|
||||
private DirContextType(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* The type of {@link DirContext} returned by {@link ContextSource#getReadOnlyContext()}
|
||||
*/
|
||||
public static final DirContextType READ_ONLY = new DirContextType("READ_ONLY");
|
||||
|
||||
/**
|
||||
* The type of {@link DirContext} returned by {@link ContextSource#getReadWriteContext()}
|
||||
*/
|
||||
public static final DirContextType READ_WRITE = new DirContextType("READ_WRITE");
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright 2005-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.ldap.pool2;
|
||||
|
||||
/**
|
||||
* @author Mattias Hellborg Arthursson
|
||||
*/
|
||||
public interface FailureAwareContext {
|
||||
boolean hasFailed();
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 2005-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.ldap.pool2;
|
||||
|
||||
import org.apache.commons.pool2.KeyedObjectPool;
|
||||
import org.springframework.ldap.pool2.factory.MutablePooledContextSource;
|
||||
|
||||
import javax.naming.NamingException;
|
||||
import javax.naming.ldap.Control;
|
||||
import javax.naming.ldap.LdapContext;
|
||||
|
||||
/**
|
||||
* Used by {@link MutablePooledContextSource} to wrap a {@link LdapContext},
|
||||
* delegating most methods to the underlying context. This class extends
|
||||
* {@link DelegatingLdapContext}, allowing request controls to be set on the
|
||||
* wrapped ldap context. This enables the Spring LDAP pooling to be used for
|
||||
* scenarios such as paged results.
|
||||
*
|
||||
* @since 2.0
|
||||
* @author Ulrik Sandberg
|
||||
* @author Anindya Chatterjee
|
||||
*/
|
||||
public class MutableDelegatingLdapContext extends DelegatingLdapContext {
|
||||
|
||||
/**
|
||||
* Create a new mutable delegating ldap context for the specified pool,
|
||||
* context and context type.
|
||||
*
|
||||
* @param keyedObjectPool The pool the delegate context was checked out
|
||||
* from.
|
||||
* @param delegateLdapContext The ldap context to delegate operations to.
|
||||
* @param dirContextType The type of context, used as a key for the pool.
|
||||
* @throws IllegalArgumentException if any of the arguments are null
|
||||
*/
|
||||
public MutableDelegatingLdapContext(KeyedObjectPool keyedObjectPool, LdapContext delegateLdapContext,
|
||||
DirContextType dirContextType) {
|
||||
super(keyedObjectPool, delegateLdapContext, dirContextType);
|
||||
}
|
||||
|
||||
public void setRequestControls(Control[] requestControls) throws NamingException {
|
||||
assertOpen();
|
||||
getDelegateLdapContext().setRequestControls(requestControls);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,321 @@
|
||||
/*
|
||||
* Copyright 2005-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.ldap.pool2.factory;
|
||||
|
||||
import org.apache.commons.pool2.BaseKeyedPooledObjectFactory;
|
||||
import org.apache.commons.pool2.PooledObject;
|
||||
import org.apache.commons.pool2.impl.DefaultPooledObject;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.ldap.core.ContextSource;
|
||||
import org.springframework.ldap.core.DirContextProxy;
|
||||
import org.springframework.ldap.pool2.DirContextType;
|
||||
import org.springframework.ldap.pool2.FailureAwareContext;
|
||||
import org.springframework.ldap.pool2.validation.DirContextValidator;
|
||||
import org.springframework.ldap.support.LdapUtils;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import javax.naming.CommunicationException;
|
||||
import javax.naming.directory.DirContext;
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Factory that creates {@link DirContext} instances for pooling via a
|
||||
* configured {@link ContextSource}. The {@link DirContext}s are keyed based
|
||||
* on if they are read only or read/write. The expected key type is the
|
||||
* {@link org.springframework.ldap.pool2.DirContextType} enum.
|
||||
*
|
||||
* <br>
|
||||
* <br>
|
||||
* Configuration: <table border="1">
|
||||
* <tr>
|
||||
* <th align="left">Property</th>
|
||||
* <th align="left">Description</th>
|
||||
* <th align="left">Required</th>
|
||||
* <th align="left">Default</th>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td valign="top">contextSource</td>
|
||||
* <td valign="top"> The {@link ContextSource} to get {@link DirContext}s from
|
||||
* for adding to the pool. </td>
|
||||
* <td valign="top">Yes</td>
|
||||
* <td valign="top">null</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td valign="top">dirContextValidator</td>
|
||||
* <td valign="top"> The {@link DirContextValidator} to use to validate
|
||||
* {@link DirContext}s. This is only required if the pool has validation of any
|
||||
* kind turned on. </td>
|
||||
* <td valign="top">No</td>
|
||||
* <td valign="top">null</td>
|
||||
* </tr>
|
||||
* </table>
|
||||
*
|
||||
* @since 2.0
|
||||
* @author Eric Dalquist <a
|
||||
* href="mailto:eric.dalquist@doit.wisc.edu">eric.dalquist@doit.wisc.edu</a>
|
||||
* @author Mattias Hellborg Arthursson
|
||||
* @author Anindya Chatterjee
|
||||
*/
|
||||
class DirContextPooledObjectFactory extends BaseKeyedPooledObjectFactory {
|
||||
/**
|
||||
* Logger for this class and subclasses
|
||||
*/
|
||||
protected final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
private static final Set<Class<? extends Throwable>> DEFAULT_NONTRANSIENT_EXCEPTIONS
|
||||
= new HashSet<Class<? extends Throwable>>(){{
|
||||
add(CommunicationException.class);
|
||||
}};
|
||||
|
||||
private ContextSource contextSource;
|
||||
|
||||
private DirContextValidator dirContextValidator;
|
||||
|
||||
private Set<Class<? extends Throwable>> nonTransientExceptions = DEFAULT_NONTRANSIENT_EXCEPTIONS;
|
||||
|
||||
void setNonTransientExceptions(Collection<Class<? extends Throwable>> nonTransientExceptions) {
|
||||
this.nonTransientExceptions = new HashSet<Class<? extends Throwable>>(nonTransientExceptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the contextSource
|
||||
*/
|
||||
public ContextSource getContextSource() {
|
||||
return this.contextSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param contextSource
|
||||
* the contextSource to set
|
||||
*/
|
||||
public void setContextSource(ContextSource contextSource) {
|
||||
if (contextSource == null) {
|
||||
throw new IllegalArgumentException("contextSource may not be null");
|
||||
}
|
||||
|
||||
this.contextSource = contextSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the dirContextValidator
|
||||
*/
|
||||
public DirContextValidator getDirContextValidator() {
|
||||
return this.dirContextValidator;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param dirContextValidator
|
||||
* the dirContextValidator to set
|
||||
*/
|
||||
public void setDirContextValidator(DirContextValidator dirContextValidator) {
|
||||
if (dirContextValidator == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"dirContextValidator may not be null");
|
||||
}
|
||||
|
||||
this.dirContextValidator = dirContextValidator;
|
||||
}
|
||||
|
||||
private Object makeFailureAwareProxy(DirContext readOnlyContext) {
|
||||
return Proxy.newProxyInstance(DirContextProxy.class
|
||||
.getClassLoader(),
|
||||
new Class<?>[]{
|
||||
LdapUtils.getActualTargetClass(readOnlyContext),
|
||||
DirContextProxy.class,
|
||||
FailureAwareContext.class},
|
||||
new FailureAwareContextProxy(readOnlyContext));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see BaseKeyedPooledObjectFactory#validateObject(Object, PooledObject)
|
||||
*
|
||||
* */
|
||||
@Override
|
||||
public boolean validateObject(Object key, PooledObject pooledObject) {
|
||||
Assert.notNull(this.dirContextValidator,
|
||||
"DirContextValidator may not be null");
|
||||
Assert.isTrue(key instanceof DirContextType,
|
||||
"key must be a DirContextType");
|
||||
Assert.notNull(pooledObject,
|
||||
"The Object to validate must not be null");
|
||||
Assert.isTrue(pooledObject.getObject() instanceof DirContext,
|
||||
"The Object to validate must be of type '" + DirContext.class
|
||||
+ "'");
|
||||
|
||||
try {
|
||||
final DirContextType contextType = (DirContextType) key;
|
||||
final DirContext dirContext = (DirContext) pooledObject.getObject();
|
||||
return this.dirContextValidator.validateDirContext(contextType,
|
||||
dirContext);
|
||||
} catch (Exception e) {
|
||||
this.logger.warn("Failed to validate '" + pooledObject.getObject()
|
||||
+ "' due to an unexpected exception.", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see BaseKeyedPooledObjectFactory#destroyObject(Object, PooledObject)
|
||||
*
|
||||
* */
|
||||
@Override
|
||||
public void destroyObject(Object key, PooledObject pooledObject) throws Exception {
|
||||
Assert.notNull(pooledObject,
|
||||
"The Object to destroy must not be null");
|
||||
Assert.isTrue(pooledObject.getObject() instanceof DirContext,
|
||||
"The Object to destroy must be of type '" + DirContext.class
|
||||
+ "'");
|
||||
|
||||
try {
|
||||
final DirContext dirContext = (DirContext) pooledObject.getObject();
|
||||
if (this.logger.isDebugEnabled()) {
|
||||
this.logger.debug("Closing " + key + " DirContext='"
|
||||
+ dirContext + "'");
|
||||
}
|
||||
dirContext.close();
|
||||
if (this.logger.isDebugEnabled()) {
|
||||
this.logger.debug("Closed " + key + " DirContext='"
|
||||
+ dirContext + "'");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
this.logger.warn(
|
||||
"An exception occured while closing '" + pooledObject.getObject() + "'", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see BaseKeyedPooledObjectFactory#create(Object)
|
||||
*
|
||||
* */
|
||||
@Override
|
||||
public Object create(Object key) throws Exception {
|
||||
Assert.notNull(this.contextSource, "ContextSource may not be null");
|
||||
Assert.isTrue(key instanceof DirContextType,
|
||||
"key must be a DirContextType");
|
||||
|
||||
final DirContextType contextType = (DirContextType) key;
|
||||
if (this.logger.isDebugEnabled()) {
|
||||
this.logger.debug("Creating a new " + contextType + " DirContext");
|
||||
}
|
||||
|
||||
if (contextType == DirContextType.READ_WRITE) {
|
||||
final DirContext readWriteContext = this.contextSource
|
||||
.getReadWriteContext();
|
||||
|
||||
if (this.logger.isDebugEnabled()) {
|
||||
this.logger.debug("Created new " + DirContextType.READ_WRITE
|
||||
+ " DirContext='" + readWriteContext + "'");
|
||||
}
|
||||
|
||||
return makeFailureAwareProxy(readWriteContext);
|
||||
} else if (contextType == DirContextType.READ_ONLY) {
|
||||
|
||||
final DirContext readOnlyContext = this.contextSource
|
||||
.getReadOnlyContext();
|
||||
|
||||
if (this.logger.isDebugEnabled()) {
|
||||
this.logger.debug("Created new " + DirContextType.READ_ONLY
|
||||
+ " DirContext='" + readOnlyContext + "'");
|
||||
}
|
||||
|
||||
return makeFailureAwareProxy(readOnlyContext);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unrecognized ContextType: "
|
||||
+ contextType);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see BaseKeyedPooledObjectFactory#wrap(Object)
|
||||
*
|
||||
* */
|
||||
@Override
|
||||
public PooledObject wrap(Object value) {
|
||||
return new DefaultPooledObject(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invocation handler that checks thrown exceptions against the configured {@link #nonTransientExceptions},
|
||||
* marking the Context as invalid on match.
|
||||
*
|
||||
* @author Mattias Hellborg Arthursson
|
||||
* @since 2.0
|
||||
*/
|
||||
private class FailureAwareContextProxy implements
|
||||
InvocationHandler {
|
||||
|
||||
private DirContext target;
|
||||
|
||||
private boolean hasFailed = false;
|
||||
|
||||
public FailureAwareContextProxy(DirContext target) {
|
||||
Assert.notNull(target, "Target must not be null");
|
||||
this.target = 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 {
|
||||
|
||||
String methodName = method.getName();
|
||||
if (methodName.equals("getTargetContext")) {
|
||||
return target;
|
||||
} else if (methodName.equals("hasFailed")) {
|
||||
return hasFailed;
|
||||
}
|
||||
|
||||
try {
|
||||
return method.invoke(target, args);
|
||||
}
|
||||
catch (InvocationTargetException e) {
|
||||
Throwable targetException = e.getTargetException();
|
||||
Class<? extends Throwable> targetExceptionClass = targetException.getClass();
|
||||
|
||||
boolean nonTransientEncountered = false;
|
||||
for (Class<? extends Throwable> clazz : nonTransientExceptions) {
|
||||
if(clazz.isAssignableFrom(targetExceptionClass)) {
|
||||
logger.info(
|
||||
String.format("An %s - explicitly configured to be a non-transient exception - encountered; eagerly invalidating the target context.",
|
||||
targetExceptionClass));
|
||||
nonTransientEncountered = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(nonTransientEncountered) {
|
||||
hasFailed = true;
|
||||
} else {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug(String.format("An %s - not explicitly configured to be a non-transient exception - encountered; ignoring.",
|
||||
targetExceptionClass));
|
||||
}
|
||||
}
|
||||
|
||||
throw targetException;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright 2005-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.ldap.pool2.factory;
|
||||
|
||||
import org.springframework.dao.DataAccessResourceFailureException;
|
||||
import org.springframework.ldap.pool2.DirContextType;
|
||||
import org.springframework.ldap.pool2.DelegatingDirContext;
|
||||
import org.springframework.ldap.pool2.MutableDelegatingLdapContext;
|
||||
|
||||
import javax.naming.directory.DirContext;
|
||||
import javax.naming.ldap.LdapContext;
|
||||
|
||||
/**
|
||||
* A {@link PooledContextSource} subclass that creates
|
||||
* {@link MutableDelegatingLdapContext} instances. This enables the Spring LDAP
|
||||
* pooling to be used in scenarios that require request controls to be set, such
|
||||
* as paged results.
|
||||
*
|
||||
* @since 2.0
|
||||
* @author Anindya Chatterjee
|
||||
*/
|
||||
public class MutablePooledContextSource extends PooledContextSource {
|
||||
/**
|
||||
* Creates a new pooling context source, setting up the DirContext object
|
||||
* factory and generic keyed object pool.
|
||||
*
|
||||
* @param poolConfig pool configurations to set.
|
||||
*/
|
||||
public MutablePooledContextSource(PoolConfig poolConfig) {
|
||||
super(poolConfig);
|
||||
}
|
||||
|
||||
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 MutableDelegatingLdapContext(this.keyedObjectPool, (LdapContext) dirContext, dirContextType);
|
||||
}
|
||||
|
||||
return new DelegatingDirContext(this.keyedObjectPool, dirContext, dirContextType);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,332 @@
|
||||
/*
|
||||
* Copyright 2005-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.ldap.pool2.factory;
|
||||
|
||||
|
||||
import org.apache.commons.pool2.impl.GenericKeyedObjectPoolConfig;
|
||||
|
||||
/**
|
||||
* A wrapper class for the pool configuration. It helps to create an instance of
|
||||
* {@link GenericKeyedObjectPoolConfig}.
|
||||
*
|
||||
* @author Anindya Chatterjee
|
||||
* @since 2.0
|
||||
*/
|
||||
public class PoolConfig {
|
||||
private int maxIdlePerKey = 8;
|
||||
private int maxTotal = -1;
|
||||
private int maxTotalPerKey = 8;
|
||||
private int minIdlePerKey = 0;
|
||||
private boolean blockWhenExhausted = true;
|
||||
private String evictionPolicyClassName = "org.apache.commons.pool2.impl.DefaultEvictionPolicy";
|
||||
private boolean fairness = false;
|
||||
private boolean jmxEnabled = true;
|
||||
private String jmxNameBase = null;
|
||||
private String jmxNamePrefix = "ldap-pool";
|
||||
private boolean lifo = true;
|
||||
private long maxWaitMillis = -1L;
|
||||
private long minEvictableIdleTimeMillis = 1000L * 60L * 30L;
|
||||
private int numTestsPerEvictionRun = 3;
|
||||
private long softMinEvictableIdleTimeMillis = -1L;
|
||||
private boolean testOnBorrow = false;
|
||||
private boolean testOnCreate = false;
|
||||
private boolean testOnReturn = false;
|
||||
private boolean testWhileIdle = false;
|
||||
private long timeBetweenEvictionRunsMillis = -1L;
|
||||
|
||||
|
||||
/**
|
||||
* @see org.apache.commons.pool2.impl.GenericKeyedObjectPoolConfig#setMaxIdlePerKey(int)
|
||||
*
|
||||
*/
|
||||
public void setMaxIdlePerKey(int maxIdlePerKey) {
|
||||
this.maxIdlePerKey = maxIdlePerKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.apache.commons.pool2.impl.GenericKeyedObjectPoolConfig#setMaxTotal(int)
|
||||
*
|
||||
*/
|
||||
public void setMaxTotal(int maxTotal) {
|
||||
this.maxTotal = maxTotal;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.apache.commons.pool2.impl.GenericKeyedObjectPoolConfig#setMaxTotalPerKey(int)
|
||||
*/
|
||||
public void setMaxTotalPerKey(int maxTotalPerKey) {
|
||||
this.maxTotalPerKey = maxTotalPerKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.apache.commons.pool2.impl.GenericKeyedObjectPoolConfig#setMinIdlePerKey(int)
|
||||
*/
|
||||
public void setMinIdlePerKey(int minIdlePerKey) {
|
||||
this.minIdlePerKey = minIdlePerKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.apache.commons.pool2.impl.GenericKeyedObjectPoolConfig#setBlockWhenExhausted(boolean)
|
||||
*/
|
||||
public void setBlockWhenExhausted(boolean blockWhenExhausted) {
|
||||
this.blockWhenExhausted = blockWhenExhausted;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.apache.commons.pool2.impl.GenericKeyedObjectPoolConfig#setEvictionPolicyClassName(String)
|
||||
*/
|
||||
public void setEvictionPolicyClassName(String evictionPolicyClassName) {
|
||||
this.evictionPolicyClassName = evictionPolicyClassName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.apache.commons.pool2.impl.GenericKeyedObjectPoolConfig#setFairness(boolean)
|
||||
*/
|
||||
public void setFairness(boolean fairness) {
|
||||
this.fairness = fairness;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.apache.commons.pool2.impl.GenericKeyedObjectPoolConfig#setJmxEnabled(boolean)
|
||||
*/
|
||||
public void setJmxEnabled(boolean jmxEnabled) {
|
||||
this.jmxEnabled = jmxEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.apache.commons.pool2.impl.GenericKeyedObjectPoolConfig#setJmxNameBase(String)
|
||||
*/
|
||||
public void setJmxNameBase(String jmxNameBase) {
|
||||
this.jmxNameBase = jmxNameBase;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.apache.commons.pool2.impl.GenericKeyedObjectPoolConfig#setJmxNamePrefix(String)
|
||||
*/
|
||||
public void setJmxNamePrefix(String jmxNamePrefix) {
|
||||
this.jmxNamePrefix = jmxNamePrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.apache.commons.pool2.impl.GenericKeyedObjectPoolConfig#setLifo(boolean)
|
||||
*/
|
||||
public void setLifo(boolean lifo) {
|
||||
this.lifo = lifo;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.apache.commons.pool2.impl.GenericKeyedObjectPoolConfig#setMaxWaitMillis(long)
|
||||
*/
|
||||
public void setMaxWaitMillis(long maxWaitMillis) {
|
||||
this.maxWaitMillis = maxWaitMillis;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.apache.commons.pool2.impl.GenericKeyedObjectPoolConfig#setMinEvictableIdleTimeMillis(long)
|
||||
*/
|
||||
public void setMinEvictableIdleTimeMillis(long minEvictableIdleTimeMillis) {
|
||||
this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.apache.commons.pool2.impl.GenericKeyedObjectPoolConfig#setNumTestsPerEvictionRun(int)
|
||||
*/
|
||||
public void setNumTestsPerEvictionRun(int numTestsPerEvictionRun) {
|
||||
this.numTestsPerEvictionRun = numTestsPerEvictionRun;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.apache.commons.pool2.impl.GenericKeyedObjectPoolConfig#setSoftMinEvictableIdleTimeMillis(long)
|
||||
*/
|
||||
public void setSoftMinEvictableIdleTimeMillis(long softMinEvictableIdleTimeMillis) {
|
||||
this.softMinEvictableIdleTimeMillis = softMinEvictableIdleTimeMillis;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.apache.commons.pool2.impl.GenericKeyedObjectPoolConfig#setTestOnBorrow(boolean)
|
||||
*/
|
||||
public void setTestOnBorrow(boolean testOnBorrow) {
|
||||
this.testOnBorrow = testOnBorrow;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.apache.commons.pool2.impl.GenericKeyedObjectPoolConfig#setTestOnCreate(boolean)
|
||||
*/
|
||||
public void setTestOnCreate(boolean testOnCreate) {
|
||||
this.testOnCreate = testOnCreate;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.apache.commons.pool2.impl.GenericKeyedObjectPoolConfig#setTestOnReturn(boolean)
|
||||
*/
|
||||
public void setTestOnReturn(boolean testOnReturn) {
|
||||
this.testOnReturn = testOnReturn;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.apache.commons.pool2.impl.GenericKeyedObjectPoolConfig#setTestWhileIdle(boolean)
|
||||
*/
|
||||
public void setTestWhileIdle(boolean testWhileIdle) {
|
||||
this.testWhileIdle = testWhileIdle;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.apache.commons.pool2.impl.GenericKeyedObjectPoolConfig#setTimeBetweenEvictionRunsMillis(long)
|
||||
*/
|
||||
public void setTimeBetweenEvictionRunsMillis(long timeBetweenEvictionRunsMillis) {
|
||||
this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see GenericKeyedObjectPoolConfig#getMaxIdlePerKey()
|
||||
*/
|
||||
public int getMaxIdlePerKey() {
|
||||
return maxIdlePerKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see GenericKeyedObjectPoolConfig#getMaxTotal()
|
||||
*/
|
||||
public int getMaxTotal() {
|
||||
return maxTotal;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see GenericKeyedObjectPoolConfig#getMaxIdlePerKey()
|
||||
*/
|
||||
public int getMaxTotalPerKey() {
|
||||
return maxTotalPerKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see GenericKeyedObjectPoolConfig#getMinIdlePerKey()
|
||||
*/
|
||||
public int getMinIdlePerKey() {
|
||||
return minIdlePerKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see GenericKeyedObjectPoolConfig#getBlockWhenExhausted()
|
||||
*/
|
||||
public boolean isBlockWhenExhausted() {
|
||||
return blockWhenExhausted;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see GenericKeyedObjectPoolConfig#getEvictionPolicyClassName()
|
||||
*/
|
||||
public String getEvictionPolicyClassName() {
|
||||
return evictionPolicyClassName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see GenericKeyedObjectPoolConfig#getFairness()
|
||||
*/
|
||||
public boolean isFairness() {
|
||||
return fairness;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see GenericKeyedObjectPoolConfig#getJmxEnabled()
|
||||
*/
|
||||
public boolean isJmxEnabled() {
|
||||
return jmxEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see GenericKeyedObjectPoolConfig#getJmxNameBase()
|
||||
*/
|
||||
public String getJmxNameBase() {
|
||||
return jmxNameBase;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see GenericKeyedObjectPoolConfig#getJmxNamePrefix()
|
||||
*/
|
||||
public String getJmxNamePrefix() {
|
||||
return jmxNamePrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see GenericKeyedObjectPoolConfig#getLifo()
|
||||
*/
|
||||
public boolean isLifo() {
|
||||
return lifo;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see GenericKeyedObjectPoolConfig#getMaxWaitMillis()
|
||||
*/
|
||||
public long getMaxWaitMillis() {
|
||||
return maxWaitMillis;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see GenericKeyedObjectPoolConfig#getMinEvictableIdleTimeMillis()
|
||||
*/
|
||||
public long getMinEvictableIdleTimeMillis() {
|
||||
return minEvictableIdleTimeMillis;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see GenericKeyedObjectPoolConfig#getNumTestsPerEvictionRun()
|
||||
*/
|
||||
public int getNumTestsPerEvictionRun() {
|
||||
return numTestsPerEvictionRun;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see GenericKeyedObjectPoolConfig#getSoftMinEvictableIdleTimeMillis()
|
||||
*/
|
||||
public long getSoftMinEvictableIdleTimeMillis() {
|
||||
return softMinEvictableIdleTimeMillis;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see GenericKeyedObjectPoolConfig#getTestOnBorrow()
|
||||
*/
|
||||
public boolean isTestOnBorrow() {
|
||||
return testOnBorrow;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see GenericKeyedObjectPoolConfig#getTestOnCreate()
|
||||
*/
|
||||
public boolean isTestOnCreate() {
|
||||
return testOnCreate;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see GenericKeyedObjectPoolConfig#getTestOnReturn()
|
||||
*/
|
||||
public boolean isTestOnReturn() {
|
||||
return testOnReturn;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see GenericKeyedObjectPoolConfig#getTestWhileIdle()
|
||||
*/
|
||||
public boolean isTestWhileIdle() {
|
||||
return testWhileIdle;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see GenericKeyedObjectPoolConfig#getTimeBetweenEvictionRunsMillis()
|
||||
*/
|
||||
public long getTimeBetweenEvictionRunsMillis() {
|
||||
return timeBetweenEvictionRunsMillis;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,310 @@
|
||||
/*
|
||||
* Copyright 2005-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.ldap.pool2.factory;
|
||||
|
||||
import org.apache.commons.pool2.impl.GenericKeyedObjectPool;
|
||||
import org.apache.commons.pool2.impl.GenericKeyedObjectPoolConfig;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.dao.DataAccessResourceFailureException;
|
||||
import org.springframework.ldap.core.ContextSource;
|
||||
import org.springframework.ldap.core.support.DelegatingBaseLdapPathContextSourceSupport;
|
||||
import org.springframework.ldap.pool2.DirContextType;
|
||||
import org.springframework.ldap.pool2.validation.DirContextValidator;
|
||||
import org.springframework.ldap.pool2.DelegatingDirContext;
|
||||
import org.springframework.ldap.pool2.DelegatingLdapContext;
|
||||
|
||||
import javax.naming.directory.DirContext;
|
||||
import javax.naming.ldap.LdapContext;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* A {@link ContextSource} implementation that wraps an object pool and another
|
||||
* {@link ContextSource}. {@link DirContext}s are retrieved from the pool which
|
||||
* maintains them.
|
||||
*
|
||||
* NOTE: This implementation is based on apache commons-pool2.
|
||||
* <br>
|
||||
* <br>
|
||||
* Configuration:
|
||||
* <table border="1" summary="Configuration">
|
||||
* <tr>
|
||||
* <th align="left">Property</th> <th align="left">Description</th> <th
|
||||
* align="left">Required</th> <th align="left">Default</th>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td valign="top">contextSource</td>
|
||||
* <td valign="top">
|
||||
* The {@link ContextSource} to get {@link DirContext}s from for adding to the
|
||||
* pool.</td>
|
||||
* <td valign="top">Yes</td>
|
||||
* <td valign="top">null</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td valign="top">dirContextValidator</td>
|
||||
* <td valign="top">
|
||||
* The {@link org.springframework.ldap.pool2.validation.DirContextValidator} to use for validating {@link DirContext}s.
|
||||
* Required if any of the test/validate options are enabled.</td>
|
||||
* <td valign="top">No</td>
|
||||
* <td valign="top">null</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td valign="top">poolConfig</td>
|
||||
* <td valign="top">The {@link PoolConfig} to configure the pool.</td>
|
||||
* <td valign="top">No</td>
|
||||
* <td valign="top">null</td>
|
||||
* </tr>
|
||||
* </table>
|
||||
*
|
||||
* @since 2.0
|
||||
* @author Eric Dalquist
|
||||
* @author Anindya Chatterjee
|
||||
*/
|
||||
public class PooledContextSource
|
||||
extends DelegatingBaseLdapPathContextSourceSupport
|
||||
implements ContextSource, DisposableBean {
|
||||
/**
|
||||
* The logger for this class and sub-classes
|
||||
*/
|
||||
protected final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
protected final GenericKeyedObjectPool keyedObjectPool;
|
||||
|
||||
private final DirContextPooledObjectFactory dirContextPooledObjectFactory;
|
||||
|
||||
private PoolConfig poolConfig;
|
||||
|
||||
/**
|
||||
* Creates a new pooling context source, setting up the DirContext object
|
||||
* factory and generic keyed object pool.
|
||||
*/
|
||||
public PooledContextSource(PoolConfig poolConfig) {
|
||||
this.dirContextPooledObjectFactory = new DirContextPooledObjectFactory();
|
||||
if (poolConfig != null) {
|
||||
this.poolConfig = poolConfig;
|
||||
GenericKeyedObjectPoolConfig objectPoolConfig = getConfig(poolConfig);
|
||||
this.keyedObjectPool =
|
||||
new GenericKeyedObjectPool(this.dirContextPooledObjectFactory, objectPoolConfig);
|
||||
} else {
|
||||
this.keyedObjectPool =
|
||||
new GenericKeyedObjectPool(this.dirContextPooledObjectFactory);
|
||||
}
|
||||
}
|
||||
|
||||
// ***** Pool Property Configuration *****//
|
||||
|
||||
/**
|
||||
* @return the poolConfig
|
||||
* */
|
||||
public PoolConfig getPoolConfig() {
|
||||
return poolConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see GenericKeyedObjectPool#getNumIdle()
|
||||
* */
|
||||
public int getNumIdle() {
|
||||
return this.keyedObjectPool.getNumIdle();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see GenericKeyedObjectPool#getNumIdle(Object)
|
||||
* */
|
||||
public int getNumIdleRead() {
|
||||
return this.keyedObjectPool.getNumIdle(DirContextType.READ_ONLY);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see GenericKeyedObjectPool#getNumIdle(Object)
|
||||
* */
|
||||
public int getNumIdleWrite() {
|
||||
return this.keyedObjectPool.getNumIdle(DirContextType.READ_WRITE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see GenericKeyedObjectPool#getNumActive()
|
||||
* */
|
||||
public int getNumActive() {
|
||||
return this.keyedObjectPool.getNumActive();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see GenericKeyedObjectPool#getNumActive(Object)
|
||||
* */
|
||||
public int getNumActiveRead() {
|
||||
return this.keyedObjectPool.getNumActive(DirContextType.READ_ONLY);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see GenericKeyedObjectPool#getNumActive(Object)
|
||||
* */
|
||||
public int getNumActiveWrite() {
|
||||
return this.keyedObjectPool.getNumActive(DirContextType.READ_WRITE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see GenericKeyedObjectPool#getNumWaiters()
|
||||
* */
|
||||
public int getNumWaiters() {
|
||||
return this.keyedObjectPool.getNumWaiters();
|
||||
}
|
||||
|
||||
// ***** Object Factory Property Configuration *****//
|
||||
|
||||
/**
|
||||
* @return the contextSource
|
||||
*/
|
||||
public ContextSource getContextSource() {
|
||||
return this.dirContextPooledObjectFactory.getContextSource();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the dirContextValidator
|
||||
*/
|
||||
public DirContextValidator getDirContextValidator() {
|
||||
return this.dirContextPooledObjectFactory.getDirContextValidator();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param contextSource the contextSource to set
|
||||
* Required
|
||||
*/
|
||||
public void setContextSource(ContextSource contextSource) {
|
||||
this.dirContextPooledObjectFactory.setContextSource(contextSource);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param dirContextValidator the dirContextValidator to set
|
||||
* Required
|
||||
*/
|
||||
public void setDirContextValidator(DirContextValidator dirContextValidator) {
|
||||
this.dirContextPooledObjectFactory.setDirContextValidator(dirContextValidator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the exception classes that are to be interpreted as no-transient with regards to eager
|
||||
* context invalidation. If one of the configured exceptions (or subclasses of them)
|
||||
* is thrown by any method on a pooled DirContext, that instance will immediately be marked
|
||||
* as invalid without any additional testing (i.e. testOnReturn).
|
||||
* This allows for more efficient management of dead connections.
|
||||
* Default is {@link javax.naming.CommunicationException}.
|
||||
*
|
||||
* @param nonTransientExceptions the exception classes that should be interpreted as non-transient
|
||||
* with regards to eager invalidation.
|
||||
* @since 2.0
|
||||
*/
|
||||
public void setNonTransientExceptions(Collection<Class<? extends Throwable>> nonTransientExceptions) {
|
||||
this.dirContextPooledObjectFactory.setNonTransientExceptions(nonTransientExceptions);
|
||||
}
|
||||
|
||||
|
||||
// ***** 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 occurred while closing the underlying pool.", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ContextSource getTarget() {
|
||||
return getContextSource();
|
||||
}
|
||||
|
||||
// ***** ContextSource interface methods *****//
|
||||
|
||||
@Override
|
||||
public DirContext getReadOnlyContext() {
|
||||
return this.getContext(DirContextType.READ_ONLY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DirContext getReadWriteContext() {
|
||||
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 retrieving 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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DirContext getContext(String principal, String credentials) {
|
||||
throw new UnsupportedOperationException("Not supported for this implementation");
|
||||
}
|
||||
|
||||
private GenericKeyedObjectPoolConfig getConfig(PoolConfig poolConfig) {
|
||||
GenericKeyedObjectPoolConfig objectPoolConfig = new GenericKeyedObjectPoolConfig();
|
||||
|
||||
objectPoolConfig.setMaxTotalPerKey(poolConfig.getMaxTotalPerKey());
|
||||
objectPoolConfig.setMaxTotal(poolConfig.getMaxTotal());
|
||||
|
||||
objectPoolConfig.setMaxIdlePerKey(poolConfig.getMaxIdlePerKey());
|
||||
objectPoolConfig.setMinIdlePerKey(poolConfig.getMinIdlePerKey());
|
||||
|
||||
objectPoolConfig.setTestWhileIdle(poolConfig.isTestWhileIdle());
|
||||
objectPoolConfig.setTestOnReturn(poolConfig.isTestOnReturn());
|
||||
objectPoolConfig.setTestOnCreate(poolConfig.isTestOnCreate());
|
||||
objectPoolConfig.setTestOnBorrow(poolConfig.isTestOnBorrow());
|
||||
|
||||
objectPoolConfig.setTimeBetweenEvictionRunsMillis(poolConfig.getTimeBetweenEvictionRunsMillis());
|
||||
objectPoolConfig.setEvictionPolicyClassName(poolConfig.getEvictionPolicyClassName());
|
||||
objectPoolConfig.setMinEvictableIdleTimeMillis(poolConfig.getMinEvictableIdleTimeMillis());
|
||||
objectPoolConfig.setNumTestsPerEvictionRun(poolConfig.getNumTestsPerEvictionRun());
|
||||
objectPoolConfig.setSoftMinEvictableIdleTimeMillis(poolConfig.getSoftMinEvictableIdleTimeMillis());
|
||||
|
||||
objectPoolConfig.setJmxEnabled(poolConfig.isJmxEnabled());
|
||||
objectPoolConfig.setJmxNameBase(poolConfig.getJmxNameBase());
|
||||
objectPoolConfig.setJmxNamePrefix(poolConfig.getJmxNamePrefix());
|
||||
|
||||
objectPoolConfig.setMaxWaitMillis(poolConfig.getMaxWaitMillis());
|
||||
|
||||
objectPoolConfig.setFairness(poolConfig.isFairness());
|
||||
objectPoolConfig.setBlockWhenExhausted(poolConfig.isBlockWhenExhausted());
|
||||
objectPoolConfig.setLifo(poolConfig.isLifo());
|
||||
|
||||
return objectPoolConfig;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<html>
|
||||
<body>
|
||||
|
||||
Core classes for the pooling library based on commons-pool2 library.
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,7 @@
|
||||
<html>
|
||||
<body>
|
||||
|
||||
Base classes for the pooling library based on commons-pool2 library.
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,191 @@
|
||||
/*
|
||||
* Copyright 2005-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.ldap.pool2.validation;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.ldap.pool2.DirContextType;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import javax.naming.NamingEnumeration;
|
||||
import javax.naming.directory.DirContext;
|
||||
import javax.naming.directory.SearchControls;
|
||||
import javax.naming.directory.SearchResult;
|
||||
|
||||
/**
|
||||
* Default {@link DirContext} validator that executes {@link DirContext#search(String, String, SearchControls)}. The
|
||||
* name, filter and {@link SearchControls} are all configurable. There is no special handling for read only versus
|
||||
* read write {@link DirContext}s.
|
||||
*
|
||||
* <br>
|
||||
* <br>
|
||||
* Configuration:
|
||||
* <table border="1" summary="Configuration">
|
||||
* <tr>
|
||||
* <th align="left">Property</th>
|
||||
* <th align="left">Description</th>
|
||||
* <th align="left">Required</th>
|
||||
* <th align="left">Default</th>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td valign="top">base</td>
|
||||
* <td valign="top">
|
||||
* The name parameter to the search method.
|
||||
* </td>
|
||||
* <td valign="top">No</td>
|
||||
* <td valign="top">""</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td valign="top">filter</td>
|
||||
* <td valign="top">
|
||||
* The filter parameter to the search method.
|
||||
* </td>
|
||||
* <td valign="top">No</td>
|
||||
* <td valign="top">"objectclass=*"</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td valign="top">searchControls</td>
|
||||
* <td valign="top">
|
||||
* The {@link SearchControls} parameter to the search method.
|
||||
* </td>
|
||||
* <td valign="top">No</td>
|
||||
* <td valign="top">
|
||||
* {@link SearchControls#setCountLimit(long)} = 1<br>
|
||||
* {@link SearchControls#setReturningAttributes(String[])} = new String[] { "objectclass" }<br>
|
||||
* {@link SearchControls#setTimeLimit(int)} = 500
|
||||
* </td>
|
||||
* </tr>
|
||||
* </table>
|
||||
*
|
||||
* @author Eric Dalquist
|
||||
*/
|
||||
public class DefaultDirContextValidator implements DirContextValidator {
|
||||
public static final String DEFAULT_FILTER = "objectclass=*";
|
||||
private static final int DEFAULT_TIME_LIMIT = 500;
|
||||
|
||||
/**
|
||||
* Logger for this class and sub-classes
|
||||
*/
|
||||
protected final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
private String base;
|
||||
private String filter;
|
||||
private SearchControls searchControls;
|
||||
|
||||
/**
|
||||
* Create the default validator, creates {@link SearchControls} with search scope <code>OBJECT_SCOPE</code>,
|
||||
* a countLimit of 1, returningAttributes of objectclass and timeLimit of 500.
|
||||
* The default base is an empty string and the default filter is objectclass=*
|
||||
*/
|
||||
public DefaultDirContextValidator() {
|
||||
this(SearchControls.OBJECT_SCOPE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a validator with all the defaults of the default constructor, but with the search scope set to the
|
||||
* referred value.
|
||||
*
|
||||
* @param searchScope The searchScope to be set in the default <code>SearchControls</code>
|
||||
*/
|
||||
public DefaultDirContextValidator(int searchScope) {
|
||||
this.searchControls = new SearchControls();
|
||||
this.searchControls.setSearchScope(searchScope);
|
||||
this.searchControls.setCountLimit(1);
|
||||
this.searchControls.setReturningAttributes(new String[] { "objectclass" });
|
||||
this.searchControls.setTimeLimit(DEFAULT_TIME_LIMIT);
|
||||
|
||||
this.base = "";
|
||||
|
||||
this.filter = DEFAULT_FILTER;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the baseName
|
||||
*/
|
||||
public String getBase() {
|
||||
return this.base;
|
||||
}
|
||||
/**
|
||||
* @param base the baseName to set
|
||||
*/
|
||||
public void setBase(String base) {
|
||||
this.base = base;
|
||||
}
|
||||
/**
|
||||
* @return the filter
|
||||
*/
|
||||
public String getFilter() {
|
||||
return this.filter;
|
||||
}
|
||||
/**
|
||||
* @param filter the filter to set
|
||||
*/
|
||||
public void setFilter(String filter) {
|
||||
if (filter == null) {
|
||||
throw new IllegalArgumentException("filter may not be null");
|
||||
}
|
||||
|
||||
this.filter = filter;
|
||||
}
|
||||
/**
|
||||
* @return the searchControls
|
||||
*/
|
||||
public SearchControls getSearchControls() {
|
||||
return this.searchControls;
|
||||
}
|
||||
/**
|
||||
* @param searchControls the searchControls to set
|
||||
*/
|
||||
public void setSearchControls(SearchControls searchControls) {
|
||||
if (searchControls == null) {
|
||||
throw new IllegalArgumentException("searchControls may not be null");
|
||||
}
|
||||
|
||||
this.searchControls = searchControls;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @see DirContextValidator#validateDirContext(DirContextType, DirContext)
|
||||
*/
|
||||
public boolean validateDirContext(DirContextType contextType, DirContext dirContext) {
|
||||
Assert.notNull(contextType, "contextType may not be null");
|
||||
Assert.notNull(dirContext, "dirContext may not be null");
|
||||
|
||||
try {
|
||||
final NamingEnumeration<SearchResult> searchResults = dirContext.search(this.base, this.filter, this.searchControls);
|
||||
|
||||
if (searchResults.hasMore()) {
|
||||
if (this.logger.isDebugEnabled()) {
|
||||
this.logger.debug("DirContext '" + dirContext + "' passed validation.");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
if(this.logger.isDebugEnabled()) {
|
||||
this.logger.debug("DirContext '" + dirContext + "' failed validation with an exception.", e);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.logger.isInfoEnabled()) {
|
||||
this.logger.info("DirContext '" + dirContext + "' failed validation.");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2005-2010 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.ldap.pool2.validation;
|
||||
|
||||
import org.springframework.ldap.core.ContextSource;
|
||||
import org.springframework.ldap.pool2.DirContextType;
|
||||
|
||||
import javax.naming.directory.DirContext;
|
||||
|
||||
/**
|
||||
* A validator for {@link DirContext}s.
|
||||
*
|
||||
* @author Eric Dalquist
|
||||
*/
|
||||
public interface DirContextValidator {
|
||||
/**
|
||||
* Validates the {@link DirContext}. A valid {@link DirContext} should be able
|
||||
* to answer queries and if applicable write to the directory.
|
||||
*
|
||||
* @param contextType The type of the {@link DirContext}, refers to if {@link ContextSource#getReadOnlyContext()} or {@link ContextSource#getReadWriteContext()} was called to create the {@link DirContext}
|
||||
* @param dirContext The {@link DirContext} to validate.
|
||||
* @return <code>true</code> if the {@link DirContext} operated correctly during validation.
|
||||
*/
|
||||
boolean validateDirContext(DirContextType contextType, DirContext dirContext);
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<html>
|
||||
<body>
|
||||
|
||||
Connection validation support for the pooling library.
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -262,6 +262,209 @@
|
||||
</xs:attribute>
|
||||
</xs:attributeGroup>
|
||||
|
||||
<xs:attributeGroup name="pooling2.attlist">
|
||||
<xs:attribute name="max-total" type="xs:integer">
|
||||
<xs:annotation>
|
||||
<xs:documentation>
|
||||
The overall maximum number of active connections (for all types) that can be allocated from
|
||||
this pool at the same time, or non-positive for no limit. Default is -1 (no limit).
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="max-total-per-key" type="xs:integer">
|
||||
<xs:annotation>
|
||||
<xs:documentation>
|
||||
The limit on the number of object instances allocated by the pool (checked out or idle),
|
||||
per key. When the limit is reached, the sub-pool is said to be exhausted. A negative value
|
||||
indicates no limit. Default is 8.
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="max-idle-per-key" type="xs:integer">
|
||||
<xs:annotation>
|
||||
<xs:documentation>
|
||||
The maximum number of active connections per type (read-only|read-write) that can remain idle in the pool,
|
||||
without extra ones being released, or non-positive for no limit. Default is 8.
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="min-idle-per-key" type="xs:integer">
|
||||
<xs:annotation>
|
||||
<xs:documentation>
|
||||
The minimum number of active connections per type (read-only|read-write) that can remain
|
||||
idle in the pool, without extra ones being created, or zero to create none. Default is 0.
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="max-wait" type="xs:integer">
|
||||
<xs:annotation>
|
||||
<xs:documentation>
|
||||
The maximum number of milliseconds that the pool will wait (when there are no available connections)
|
||||
for a connection to be returned before throwing an exception, or non-positive to wait indefinitely.
|
||||
Default is -1.
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="block-when-exhausted" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>
|
||||
Sets to wait until a new object is available. If max-wait is positive a NoSuchElementException
|
||||
is thrown if no new object is available after the maxWait time expires..
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="test-on-create" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>
|
||||
Sets whether objects created for the pool will be validated before borrowing. If the object
|
||||
fails to validate, then borrowing will fail. Default is false.
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="test-on-borrow" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>
|
||||
The indication of whether objects will be validated before being borrowed from the pool.
|
||||
If the object fails to validate, it will be dropped from the pool, and an attempt to borrow another will be made.
|
||||
Default is false.
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="test-on-return" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>
|
||||
The indication of whether objects will be validated before being returned to the pool.
|
||||
Default is false.
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="test-while-idle" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>
|
||||
The indication of whether objects will be validated by the idle object evictor (if any).
|
||||
If an object fails to validate, it will be dropped from the pool.
|
||||
Default is false.
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="eviction-run-interval-millis" type="xs:int">
|
||||
<xs:annotation>
|
||||
<xs:documentation>
|
||||
The number of milliseconds to sleep between runs of the idle object evictor thread. When non-positive,
|
||||
no idle object evictor thread will be run. Default is -1.
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="tests-per-eviction-run" type="xs:int">
|
||||
<xs:annotation>
|
||||
<xs:documentation>
|
||||
The number of objects to examine during each run of the idle object evictor thread (if any).
|
||||
Default is 3.
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="min-evictable-time-millis" type="xs:int">
|
||||
<xs:annotation>
|
||||
<xs:documentation>
|
||||
The minimum amount of time an object may sit idle in the pool before it is eligible
|
||||
for eviction by the idle object evictor (if any). Default is 1000 * 60 * 30.
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="soft-min-evictable-idle-time-millis" type="xs:int">
|
||||
<xs:annotation>
|
||||
<xs:documentation>
|
||||
The minimum amount of time an object may sit idle in the pool before it is eligible for
|
||||
eviction by the idle object evictor, with the extra condition that at least minimum number
|
||||
of object instances per key remain in the pool. This settings is overridden by min-evictable-time-millis if
|
||||
it is set to a positive value. Default is -1.
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="eviction-policy-class" type="xs:string">
|
||||
<xs:annotation>
|
||||
<xs:documentation>
|
||||
The name of the eviction policy implementation that is used by this pool. The Pool will
|
||||
attempt to load the class using the thread context class loader. If that fails, the Pool
|
||||
will attempt to load the class using the class loader that loaded this class. Default is
|
||||
org.apache.commons.pool2.impl.DefaultEvictionPolicy.
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="fairness" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>
|
||||
Sets whether or not the pool serves threads waiting to borrow connections fairly.
|
||||
True means that waiting threads are served as if waiting in a FIFO queue. Default is false.
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="jmx-enable" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>
|
||||
Sets whether JMX will be enabled with the platform MBean server for the pool. Default
|
||||
is true.
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="jmx-name-base" type="xs:string">
|
||||
<xs:annotation>
|
||||
<xs:documentation>
|
||||
The value of the JMX name base that will be used as part of the name assigned
|
||||
to JMX enabled pools. Default is null.
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="jmx-name-prefix" type="xs:string">
|
||||
<xs:annotation>
|
||||
<xs:documentation>
|
||||
The value of the JMX name prefix that will be used as part of the name assigned
|
||||
to JMX enabled pools. Default value is pool.
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="lifo" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>
|
||||
Sets whether the pool has LIFO (last in, first out) behaviour with
|
||||
respect to idle objects - always returning the most recently used object
|
||||
from the pool, or as a FIFO (first in, first out) queue, where the pool
|
||||
always returns the oldest object in the idle object pool. Default is true.
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="validation-query-base" type="xs:string">
|
||||
<xs:annotation>
|
||||
<xs:documentation>
|
||||
The base dn to use for validation searches. Default is LdapUtils.emptyPath().
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="validation-query-filter" type="xs:string">
|
||||
<xs:annotation>
|
||||
<xs:documentation>
|
||||
The filter to use for validation queries. Default is (objectclass=*).
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="validation-query-search-controls-ref" type="xs:token">
|
||||
<xs:annotation>
|
||||
<xs:documentation>
|
||||
Id of the SearchControls instance to use for searches. Default is searchScope=OBJECT_SCOPE;
|
||||
countLimit: 1; timeLimit: 500; returningAttributes: [objectclass].
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="non-transient-exceptions" type="xs:string">
|
||||
<xs:annotation>
|
||||
<xs:documentation>
|
||||
Id of the SearchControls instance to use for searches. Default is searchScope=OBJECT_SCOPE;
|
||||
countLimit: 1; timeLimit: 500; returningAttributes: [objectclass].
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
</xs:attributeGroup>
|
||||
|
||||
<xs:element name="context-source">
|
||||
<xs:annotation>
|
||||
<xs:documentation>
|
||||
@@ -269,18 +472,32 @@
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:complexType>
|
||||
<xs:sequence minOccurs="0" maxOccurs="1">
|
||||
<xs:element name="pooling">
|
||||
<xs:annotation>
|
||||
<xs:documentation>
|
||||
Defines the settings to use for the Spring LDAP connection pooling support.
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:complexType>
|
||||
<xs:attributeGroup ref="ldap:pooling.attlist" />
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
<xs:choice minOccurs="0" maxOccurs="1">
|
||||
<xs:sequence>
|
||||
<xs:element name="pooling">
|
||||
<xs:annotation>
|
||||
<xs:documentation>
|
||||
Defines the settings to use for the Spring LDAP connection pooling support.
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:complexType>
|
||||
<xs:attributeGroup ref="ldap:pooling.attlist" />
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
<xs:sequence>
|
||||
<xs:element name="pooling2">
|
||||
<xs:annotation>
|
||||
<xs:documentation>
|
||||
Defines the settings to use for the Spring LDAP connection pooling support based on commons-pool2 library.
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:complexType>
|
||||
<xs:attributeGroup ref="ldap:pooling2.attlist" />
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:choice>
|
||||
<xs:attributeGroup ref="ldap:context-source.attlist" />
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2005-2013 the original author or authors.
|
||||
* Copyright 2005-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,6 +17,7 @@
|
||||
package org.springframework.ldap.config;
|
||||
|
||||
import org.apache.commons.pool.impl.GenericKeyedObjectPool;
|
||||
import org.apache.commons.pool2.impl.GenericKeyedObjectPoolConfig;
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
@@ -27,6 +28,7 @@ import org.springframework.ldap.core.support.DirContextAuthenticationStrategy;
|
||||
import org.springframework.ldap.core.support.LdapContextSource;
|
||||
import org.springframework.ldap.pool.factory.PoolingContextSource;
|
||||
import org.springframework.ldap.pool.validation.DefaultDirContextValidator;
|
||||
import org.springframework.ldap.pool2.factory.PooledContextSource;
|
||||
import org.springframework.ldap.support.LdapUtils;
|
||||
import org.springframework.ldap.transaction.compensating.TempEntryRenamingStrategy;
|
||||
import org.springframework.ldap.transaction.compensating.manager.ContextSourceAndDataSourceTransactionManager;
|
||||
@@ -36,9 +38,12 @@ import org.springframework.ldap.transaction.compensating.support.DefaultTempEntr
|
||||
import org.springframework.ldap.transaction.compensating.support.DifferentSubtreeTempEntryRenamingStrategy;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
|
||||
import javax.management.MBeanServer;
|
||||
import javax.management.ObjectName;
|
||||
import javax.naming.CannotProceedException;
|
||||
import javax.naming.CommunicationException;
|
||||
import javax.naming.directory.SearchControls;
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
@@ -124,6 +129,7 @@ public class LdapTemplateNamespaceHandlerTest {
|
||||
assertSame(authenticationStrategy, getInternalState(contextSource, "authenticationStrategy"));
|
||||
assertEquals(baseEnv, getInternalState(contextSource, "baseEnv"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void verifyParseWithCustomValues() {
|
||||
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("/ldap-namespace-config-values.xml");
|
||||
@@ -360,4 +366,132 @@ public class LdapTemplateNamespaceHandlerTest {
|
||||
|
||||
assertNotNull(repository);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void verifyParsePooling2Defaults() {
|
||||
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("/ldap-namespace-config-pooling2-defaults.xml");
|
||||
|
||||
ContextSource outerContextSource = ctx.getBean(ContextSource.class);
|
||||
assertNotNull(outerContextSource);
|
||||
assertTrue(outerContextSource instanceof TransactionAwareContextSourceProxy);
|
||||
|
||||
ContextSource pooledContextSource = ((TransactionAwareContextSourceProxy) outerContextSource).getTarget();
|
||||
assertNotNull(pooledContextSource);
|
||||
assertTrue(pooledContextSource instanceof PooledContextSource);
|
||||
assertNotNull(getInternalState(pooledContextSource, "poolConfig"));
|
||||
|
||||
Object objectFactory = getInternalState(pooledContextSource, "dirContextPooledObjectFactory");
|
||||
assertNotNull(getInternalState(objectFactory, "contextSource"));
|
||||
assertNull(getInternalState(objectFactory, "dirContextValidator"));
|
||||
Set<Class<? extends Throwable>> nonTransientExceptions =
|
||||
(Set<Class<? extends Throwable>>) getInternalState(objectFactory, "nonTransientExceptions");
|
||||
assertEquals(1, nonTransientExceptions.size());
|
||||
assertTrue(nonTransientExceptions.contains(CommunicationException.class));
|
||||
|
||||
org.apache.commons.pool2.impl.GenericKeyedObjectPool objectPool =
|
||||
(org.apache.commons.pool2.impl.GenericKeyedObjectPool) getInternalState(pooledContextSource, "keyedObjectPool");
|
||||
assertEquals(8, objectPool.getMaxIdlePerKey());
|
||||
assertEquals(-1, objectPool.getMaxTotal());
|
||||
assertEquals(8, objectPool.getMaxTotalPerKey());
|
||||
assertEquals(0, objectPool.getMinIdlePerKey());
|
||||
assertEquals(true, objectPool.getBlockWhenExhausted());
|
||||
assertEquals(GenericKeyedObjectPoolConfig.DEFAULT_EVICTION_POLICY_CLASS_NAME, objectPool.getEvictionPolicyClassName());
|
||||
assertEquals(false, objectPool.getFairness());
|
||||
|
||||
// ensures the pool is registered
|
||||
ObjectName oname = objectPool.getJmxName();
|
||||
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
|
||||
Set<ObjectName> result = mbs.queryNames(oname, null);
|
||||
assertEquals(1, result.size());
|
||||
|
||||
assertEquals(true, objectPool.getLifo());
|
||||
assertEquals(-1L, objectPool.getMaxWaitMillis());
|
||||
assertEquals(1000L*60L*30L, objectPool.getMinEvictableIdleTimeMillis());
|
||||
assertEquals(3, objectPool.getNumTestsPerEvictionRun());
|
||||
assertEquals(-1L, objectPool.getSoftMinEvictableIdleTimeMillis());
|
||||
assertEquals(-1L, objectPool.getTimeBetweenEvictionRunsMillis());
|
||||
assertEquals(false, objectPool.getTestOnBorrow());
|
||||
assertEquals(false, objectPool.getTestOnCreate());
|
||||
assertEquals(false, objectPool.getTestOnReturn());
|
||||
assertEquals(false, objectPool.getTestWhileIdle());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void verifyParsePool2SizeSet() {
|
||||
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("/ldap-namespace-config-pool2-configured-poolsize.xml");
|
||||
|
||||
ContextSource outerContextSource = ctx.getBean(ContextSource.class);
|
||||
assertNotNull(outerContextSource);
|
||||
|
||||
ContextSource pooledContextSource = ((TransactionAwareContextSourceProxy) outerContextSource).getTarget();
|
||||
assertNotNull(pooledContextSource);
|
||||
|
||||
org.apache.commons.pool2.impl.GenericKeyedObjectPool objectPool =
|
||||
(org.apache.commons.pool2.impl.GenericKeyedObjectPool) getInternalState(pooledContextSource, "keyedObjectPool");
|
||||
assertEquals(12, objectPool.getMaxTotal());
|
||||
assertEquals(20, objectPool.getMaxIdlePerKey());
|
||||
assertEquals(10, objectPool.getMaxTotalPerKey());
|
||||
assertEquals(13, objectPool.getMaxWaitMillis());
|
||||
assertEquals(14, objectPool.getMinIdlePerKey());
|
||||
assertEquals(true, objectPool.getBlockWhenExhausted());
|
||||
assertEquals("org.springframework.ldap.pool2.DummyEvictionPolicy", objectPool.getEvictionPolicyClassName());
|
||||
assertEquals(true, objectPool.getFairness());
|
||||
assertEquals(false, objectPool.getLifo());
|
||||
|
||||
// ensures the pool is registered
|
||||
ObjectName oname = objectPool.getJmxName();
|
||||
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
|
||||
Set<ObjectName> result = mbs.queryNames(oname, null);
|
||||
assertEquals(1, result.size());
|
||||
assertEquals("org.springframework.ldap.pool2:type=ldap-pool,name=test-pool", oname.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void verifyParsePool2ValidationSet() {
|
||||
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("/ldap-namespace-config-pool2-test-specified.xml");
|
||||
|
||||
ContextSource outerContextSource = ctx.getBean(ContextSource.class);
|
||||
assertNotNull(outerContextSource);
|
||||
|
||||
ContextSource pooledContextSource = ((TransactionAwareContextSourceProxy) outerContextSource).getTarget();
|
||||
assertNotNull(pooledContextSource);
|
||||
|
||||
org.apache.commons.pool2.impl.GenericKeyedObjectPool objectPool =
|
||||
(org.apache.commons.pool2.impl.GenericKeyedObjectPool) getInternalState(pooledContextSource, "keyedObjectPool");
|
||||
assertEquals(123, objectPool.getMinEvictableIdleTimeMillis());
|
||||
assertEquals(321, objectPool.getTimeBetweenEvictionRunsMillis());
|
||||
assertEquals(22, objectPool.getNumTestsPerEvictionRun());
|
||||
assertEquals(12, objectPool.getSoftMinEvictableIdleTimeMillis());
|
||||
|
||||
assertEquals(true, objectPool.getTestOnBorrow());
|
||||
assertEquals(true, objectPool.getTestOnReturn());
|
||||
assertEquals(true, objectPool.getTestOnCreate());
|
||||
assertEquals(true, objectPool.getTestWhileIdle());
|
||||
|
||||
Object objectFactory = getInternalState(pooledContextSource, "dirContextPooledObjectFactory");
|
||||
org.springframework.ldap.pool2.validation.DefaultDirContextValidator validator =
|
||||
(org.springframework.ldap.pool2.validation.DefaultDirContextValidator) getInternalState(objectFactory, "dirContextValidator");
|
||||
assertEquals("ou=test", validator.getBase());
|
||||
assertEquals("objectclass=person", validator.getFilter());
|
||||
|
||||
SearchControls searchControls = ctx.getBean(SearchControls.class);
|
||||
assertEquals("objectclass=person", validator.getFilter());
|
||||
assertSame(searchControls, validator.getSearchControls());
|
||||
|
||||
Set<Class<? extends Throwable>> nonTransientExceptions =
|
||||
(Set<Class<? extends Throwable>>) getInternalState(objectFactory, "nonTransientExceptions");
|
||||
assertEquals(2, nonTransientExceptions.size());
|
||||
assertTrue(nonTransientExceptions.contains(CommunicationException.class));
|
||||
assertTrue(nonTransientExceptions.contains(CannotProceedException.class));
|
||||
}
|
||||
|
||||
@Test(expected = BeansException.class)
|
||||
public void verifyParseWithPool2AndNativePoolingWillFail() {
|
||||
new ClassPathXmlApplicationContext("/ldap-namespace-config-pool2-with-native.xml");
|
||||
}
|
||||
|
||||
@Test(expected = BeansException.class)
|
||||
public void verifyParseWithPool1AndPool2WillFail() {
|
||||
new ClassPathXmlApplicationContext("/ldap-namespace-config-pool2-with-pool1.xml");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright 2005-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.ldap.pool2;
|
||||
|
||||
import org.apache.commons.pool2.KeyedObjectPool;
|
||||
import org.junit.Before;
|
||||
import org.springframework.ldap.core.ContextSource;
|
||||
import org.springframework.ldap.pool2.validation.DirContextValidator;
|
||||
|
||||
import javax.naming.Context;
|
||||
import javax.naming.directory.DirContext;
|
||||
import javax.naming.ldap.LdapContext;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* Contains mocks common to many tests for the connection pool.
|
||||
*
|
||||
* @author Ulrik Sandberg
|
||||
*/
|
||||
public abstract class AbstractPoolTestCase {
|
||||
|
||||
protected Context contextMock;
|
||||
|
||||
protected DirContext dirContextMock;
|
||||
|
||||
protected LdapContext ldapContextMock;
|
||||
|
||||
protected KeyedObjectPool keyedObjectPoolMock;
|
||||
|
||||
protected ContextSource contextSourceMock;
|
||||
|
||||
protected DirContextValidator dirContextValidatorMock;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
contextMock = mock(Context.class);
|
||||
dirContextMock = mock(DirContext.class);
|
||||
ldapContextMock = mock(LdapContext.class);
|
||||
keyedObjectPoolMock = mock(KeyedObjectPool.class);
|
||||
contextSourceMock = mock(ContextSource.class);
|
||||
dirContextValidatorMock = mock(DirContextValidator.class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,409 @@
|
||||
/*
|
||||
* Copyright 2005-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.ldap.pool2;
|
||||
|
||||
import org.apache.commons.pool2.KeyedObjectPool;
|
||||
import org.junit.Test;
|
||||
|
||||
import javax.naming.Context;
|
||||
import javax.naming.Name;
|
||||
import javax.naming.NamingException;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
/**
|
||||
* @author Eric Dalquist <a
|
||||
* href="mailto:eric.dalquist@doit.wisc.edu">eric.dalquist@doit.wisc.edu</a>
|
||||
*/
|
||||
public class DelegatingContextTest extends AbstractPoolTestCase {
|
||||
|
||||
@Test
|
||||
public void testConstructorAssertions() {
|
||||
try {
|
||||
new DelegatingContext(null, contextMock, DirContextType.READ_ONLY);
|
||||
fail("IllegalArgumentException expected");
|
||||
} catch (IllegalArgumentException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
|
||||
try {
|
||||
new DelegatingContext(keyedObjectPoolMock, null,
|
||||
DirContextType.READ_ONLY);
|
||||
fail("IllegalArgumentException expected");
|
||||
} catch (IllegalArgumentException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
|
||||
try {
|
||||
new DelegatingContext(keyedObjectPoolMock, contextMock, null);
|
||||
fail("IllegalArgumentException expected");
|
||||
} catch (IllegalArgumentException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHelperMethods() throws Exception {
|
||||
// Wrap the Context once
|
||||
final DelegatingContext delegatingContext = new DelegatingContext(
|
||||
keyedObjectPoolMock, contextMock, DirContextType.READ_ONLY);
|
||||
|
||||
final Context delegateContext = delegatingContext.getDelegateContext();
|
||||
assertEquals(contextMock, delegateContext);
|
||||
|
||||
final Context innerDelegateContext = delegatingContext
|
||||
.getInnermostDelegateContext();
|
||||
assertEquals(contextMock, innerDelegateContext);
|
||||
|
||||
delegatingContext.assertOpen();
|
||||
|
||||
// Wrap the wrapper
|
||||
KeyedObjectPool secondKeyedObjectPoolMock = mock(KeyedObjectPool.class);
|
||||
|
||||
final DelegatingContext delegatingContext2 = new DelegatingContext(
|
||||
secondKeyedObjectPoolMock, delegatingContext,
|
||||
DirContextType.READ_ONLY);
|
||||
|
||||
final Context delegateContext2 = delegatingContext2
|
||||
.getDelegateContext();
|
||||
assertEquals(delegatingContext, delegateContext2);
|
||||
|
||||
final Context innerDelegateContext2 = delegatingContext2
|
||||
.getInnermostDelegateContext();
|
||||
assertEquals(contextMock, innerDelegateContext2);
|
||||
|
||||
delegatingContext2.assertOpen();
|
||||
|
||||
// Close the outer wrapper
|
||||
delegatingContext2.close();
|
||||
|
||||
final Context delegateContext2closed = delegatingContext2
|
||||
.getDelegateContext();
|
||||
assertNull(delegateContext2closed);
|
||||
|
||||
final Context innerDelegateContext2closed = delegatingContext2
|
||||
.getInnermostDelegateContext();
|
||||
assertNull(innerDelegateContext2closed);
|
||||
|
||||
try {
|
||||
delegatingContext2.assertOpen();
|
||||
fail("delegatingContext2.assertOpen() should have thrown a NamingException");
|
||||
} catch (NamingException ne) {
|
||||
// Expected
|
||||
}
|
||||
|
||||
// Close the outer wrapper
|
||||
delegatingContext.close();
|
||||
|
||||
final Context delegateContextclosed = delegatingContext
|
||||
.getDelegateContext();
|
||||
assertNull(delegateContextclosed);
|
||||
|
||||
final Context innerDelegateContextclosed = delegatingContext
|
||||
.getInnermostDelegateContext();
|
||||
assertNull(innerDelegateContextclosed);
|
||||
|
||||
try {
|
||||
delegatingContext.assertOpen();
|
||||
fail("delegatingContext.assertOpen() should have thrown a NamingException");
|
||||
} catch (NamingException ne) {
|
||||
// Expected
|
||||
}
|
||||
|
||||
verify(keyedObjectPoolMock).returnObject(DirContextType.READ_ONLY, contextMock);
|
||||
verify(secondKeyedObjectPoolMock)
|
||||
.returnObject(DirContextType.READ_ONLY, contextMock);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testObjectMethods() throws Exception {
|
||||
// Wrap the Context once
|
||||
final DelegatingContext delegatingContext = new DelegatingContext(
|
||||
keyedObjectPoolMock, contextMock, DirContextType.READ_ONLY);
|
||||
assertEquals(contextMock.toString(), delegatingContext.toString());
|
||||
delegatingContext.hashCode(); // Run it to make sure it doesn't fail
|
||||
|
||||
assertTrue(delegatingContext.equals(delegatingContext));
|
||||
assertFalse(delegatingContext.equals(new Object()));
|
||||
|
||||
final DelegatingContext delegatingContext2 = new DelegatingContext(
|
||||
keyedObjectPoolMock, contextMock, DirContextType.READ_ONLY);
|
||||
assertTrue(delegatingContext.equals(delegatingContext2));
|
||||
assertTrue(delegatingContext2.equals(delegatingContext));
|
||||
assertTrue(delegatingContext.equals(contextMock));
|
||||
|
||||
// Close the contextMock and try again
|
||||
delegatingContext.close();
|
||||
|
||||
assertEquals("Context is closed", delegatingContext.toString());
|
||||
assertEquals(0, delegatingContext.hashCode()); // Run it to make sure
|
||||
// it doesn't fail
|
||||
|
||||
assertTrue(delegatingContext.equals(delegatingContext));
|
||||
assertFalse(delegatingContext.equals(new Object()));
|
||||
|
||||
assertFalse(delegatingContext.equals(delegatingContext2));
|
||||
assertFalse(delegatingContext2.equals(delegatingContext));
|
||||
assertFalse(delegatingContext.equals(contextMock));
|
||||
|
||||
verify(keyedObjectPoolMock).returnObject(DirContextType.READ_ONLY, contextMock);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnsupportedMethods() throws Exception {
|
||||
final DelegatingContext delegatingContext = new DelegatingContext(
|
||||
keyedObjectPoolMock, contextMock, DirContextType.READ_ONLY);
|
||||
|
||||
try {
|
||||
delegatingContext.addToEnvironment(null, null);
|
||||
fail("DelegatingContext.addToEnvironment Should have thrown an UnsupportedOperationException");
|
||||
} catch (UnsupportedOperationException uoe) {
|
||||
// Expected
|
||||
}
|
||||
try {
|
||||
delegatingContext.createSubcontext((Name) null);
|
||||
fail("DelegatingContext.createSubcontext Should have thrown an UnsupportedOperationException");
|
||||
} catch (UnsupportedOperationException uoe) {
|
||||
// Expected
|
||||
}
|
||||
try {
|
||||
delegatingContext.createSubcontext((String) null);
|
||||
fail("DelegatingContext.createSubcontext Should have thrown an UnsupportedOperationException");
|
||||
} catch (UnsupportedOperationException uoe) {
|
||||
// Expected
|
||||
}
|
||||
try {
|
||||
delegatingContext.destroySubcontext((Name) null);
|
||||
fail("DelegatingContext.destroySubcontext Should have thrown an UnsupportedOperationException");
|
||||
} catch (UnsupportedOperationException uoe) {
|
||||
// Expected
|
||||
}
|
||||
try {
|
||||
delegatingContext.destroySubcontext((String) null);
|
||||
fail("DelegatingContext.destroySubcontext Should have thrown an UnsupportedOperationException");
|
||||
} catch (UnsupportedOperationException uoe) {
|
||||
// Expected
|
||||
}
|
||||
try {
|
||||
delegatingContext.removeFromEnvironment(null);
|
||||
fail("DelegatingContext.removeFromEnvironment Should have thrown an UnsupportedOperationException");
|
||||
} catch (UnsupportedOperationException uoe) {
|
||||
// Expected
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAllMethodsOpened() throws Exception {
|
||||
final DelegatingContext delegatingContext = new DelegatingContext(
|
||||
keyedObjectPoolMock, contextMock, DirContextType.READ_ONLY);
|
||||
|
||||
delegatingContext.bind((Name) null, null);
|
||||
delegatingContext.bind((String) null, null);
|
||||
delegatingContext.composeName((Name) null, (Name) null);
|
||||
delegatingContext.composeName((String) null, (String) null);
|
||||
delegatingContext.getEnvironment();
|
||||
delegatingContext.getNameInNamespace();
|
||||
delegatingContext.getNameParser((Name) null);
|
||||
delegatingContext.getNameParser((String) null);
|
||||
delegatingContext.list((Name) null);
|
||||
delegatingContext.list((String) null);
|
||||
delegatingContext.listBindings((Name) null);
|
||||
delegatingContext.listBindings((String) null);
|
||||
delegatingContext.lookup((Name) null);
|
||||
delegatingContext.lookup((String) null);
|
||||
delegatingContext.lookupLink((Name) null);
|
||||
delegatingContext.lookupLink((String) null);
|
||||
delegatingContext.rebind((Name) null, null);
|
||||
delegatingContext.rebind((String) null, null);
|
||||
delegatingContext.rename((Name) null, (Name) null);
|
||||
delegatingContext.rename((String) null, (String) null);
|
||||
delegatingContext.unbind((Name) null);
|
||||
delegatingContext.unbind((String) null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAllMethodsClosed() throws Exception {
|
||||
final DelegatingContext delegatingContext = new DelegatingContext(
|
||||
keyedObjectPoolMock, contextMock, DirContextType.READ_ONLY);
|
||||
|
||||
delegatingContext.close();
|
||||
|
||||
try {
|
||||
delegatingContext.bind((Name) null, null);
|
||||
fail("DelegatingContext.bind should have thrown a NamingException");
|
||||
} catch (NamingException ne) {
|
||||
// Expected
|
||||
}
|
||||
try {
|
||||
delegatingContext.bind((String) null, null);
|
||||
fail("DelegatingContext.bind should have thrown a NamingException");
|
||||
} catch (NamingException ne) {
|
||||
// Expected
|
||||
}
|
||||
try {
|
||||
delegatingContext.composeName((Name) null, (Name) null);
|
||||
fail("DelegatingContext.composeName should have thrown a NamingException");
|
||||
} catch (NamingException ne) {
|
||||
// Expected
|
||||
}
|
||||
try {
|
||||
delegatingContext.composeName((String) null, (String) null);
|
||||
fail("DelegatingContext.composeName should have thrown a NamingException");
|
||||
} catch (NamingException ne) {
|
||||
// Expected
|
||||
}
|
||||
try {
|
||||
delegatingContext.getEnvironment();
|
||||
fail("DelegatingContext.getEnvironment should have thrown a NamingException");
|
||||
} catch (NamingException ne) {
|
||||
// Expected
|
||||
}
|
||||
try {
|
||||
delegatingContext.getNameInNamespace();
|
||||
fail("DelegatingContext.getNameInNamespace should have thrown a NamingException");
|
||||
} catch (NamingException ne) {
|
||||
// Expected
|
||||
}
|
||||
try {
|
||||
delegatingContext.getNameParser((Name) null);
|
||||
fail("DelegatingContext.getNameParser should have thrown a NamingException");
|
||||
} catch (NamingException ne) {
|
||||
// Expected
|
||||
}
|
||||
try {
|
||||
delegatingContext.getNameParser((String) null);
|
||||
fail("DelegatingContext.getNameParser should have thrown a NamingException");
|
||||
} catch (NamingException ne) {
|
||||
// Expected
|
||||
}
|
||||
try {
|
||||
delegatingContext.list((Name) null);
|
||||
fail("DelegatingContext.list should have thrown a NamingException");
|
||||
} catch (NamingException ne) {
|
||||
// Expected
|
||||
}
|
||||
try {
|
||||
delegatingContext.list((String) null);
|
||||
fail("DelegatingContext.list should have thrown a NamingException");
|
||||
} catch (NamingException ne) {
|
||||
// Expected
|
||||
}
|
||||
try {
|
||||
delegatingContext.listBindings((Name) null);
|
||||
fail("DelegatingContext.listBindings should have thrown a NamingException");
|
||||
} catch (NamingException ne) {
|
||||
// Expected
|
||||
}
|
||||
try {
|
||||
delegatingContext.listBindings((String) null);
|
||||
fail("DelegatingContext.listBindings should have thrown a NamingException");
|
||||
} catch (NamingException ne) {
|
||||
// Expected
|
||||
}
|
||||
try {
|
||||
delegatingContext.lookup((Name) null);
|
||||
fail("DelegatingContext.lookup should have thrown a NamingException");
|
||||
} catch (NamingException ne) {
|
||||
// Expected
|
||||
}
|
||||
try {
|
||||
delegatingContext.lookup((String) null);
|
||||
fail("DelegatingContext.lookup should have thrown a NamingException");
|
||||
} catch (NamingException ne) {
|
||||
// Expected
|
||||
}
|
||||
try {
|
||||
delegatingContext.lookupLink((Name) null);
|
||||
fail("DelegatingContext.lookupLink should have thrown a NamingException");
|
||||
} catch (NamingException ne) {
|
||||
// Expected
|
||||
}
|
||||
try {
|
||||
delegatingContext.lookupLink((String) null);
|
||||
fail("DelegatingContext.lookupLink should have thrown a NamingException");
|
||||
} catch (NamingException ne) {
|
||||
// Expected
|
||||
}
|
||||
try {
|
||||
delegatingContext.rebind((Name) null, null);
|
||||
fail("DelegatingContext.rebind should have thrown a NamingException");
|
||||
} catch (NamingException ne) {
|
||||
// Expected
|
||||
}
|
||||
try {
|
||||
delegatingContext.rebind((String) null, null);
|
||||
fail("DelegatingContext.rebind should have thrown a NamingException");
|
||||
} catch (NamingException ne) {
|
||||
// Expected
|
||||
}
|
||||
try {
|
||||
delegatingContext.rename((Name) null, (Name) null);
|
||||
fail("DelegatingContext.rename should have thrown a NamingException");
|
||||
} catch (NamingException ne) {
|
||||
// Expected
|
||||
}
|
||||
try {
|
||||
delegatingContext.rename((String) null, (String) null);
|
||||
fail("DelegatingContext.rename should have thrown a NamingException");
|
||||
} catch (NamingException ne) {
|
||||
// Expected
|
||||
}
|
||||
try {
|
||||
delegatingContext.unbind((Name) null);
|
||||
fail("DelegatingContext.unbind should have thrown a NamingException");
|
||||
} catch (NamingException ne) {
|
||||
// Expected
|
||||
}
|
||||
try {
|
||||
delegatingContext.unbind((String) null);
|
||||
fail("DelegatingContext.unbind should have thrown a NamingException");
|
||||
} catch (NamingException ne) {
|
||||
// Expected
|
||||
}
|
||||
|
||||
verify(keyedObjectPoolMock).returnObject(DirContextType.READ_ONLY, contextMock);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDoubleClose() throws Exception {
|
||||
final DelegatingContext delegatingContext = new DelegatingContext(
|
||||
keyedObjectPoolMock, contextMock, DirContextType.READ_ONLY);
|
||||
|
||||
delegatingContext.close();
|
||||
|
||||
// noop close
|
||||
delegatingContext.close();
|
||||
|
||||
verify(keyedObjectPoolMock, times(1)).returnObject(DirContextType.READ_ONLY, contextMock);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPoolExceptionOnClose() throws Exception {
|
||||
doThrow(new Exception("Fake Pool returnObject Exception"))
|
||||
.when(keyedObjectPoolMock).returnObject(DirContextType.READ_ONLY, contextMock);
|
||||
|
||||
final DelegatingContext delegatingContext = new DelegatingContext(
|
||||
keyedObjectPoolMock, contextMock, DirContextType.READ_ONLY);
|
||||
|
||||
try {
|
||||
delegatingContext.close();
|
||||
fail("DelegatingContext.close should have thrown a NamingException");
|
||||
} catch (NamingException ne) {
|
||||
// Expected
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,381 @@
|
||||
/*
|
||||
* Copyright 2005-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.ldap.pool2;
|
||||
|
||||
import org.apache.commons.pool2.KeyedObjectPool;
|
||||
import org.junit.Test;
|
||||
|
||||
import javax.naming.Context;
|
||||
import javax.naming.Name;
|
||||
import javax.naming.NamingException;
|
||||
import javax.naming.directory.Attributes;
|
||||
import javax.naming.directory.DirContext;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
/**
|
||||
* @author Eric Dalquist <a
|
||||
* href="mailto:eric.dalquist@doit.wisc.edu">eric.dalquist@doit.wisc.edu</a>
|
||||
*/
|
||||
public class DelegatingDirContextTest extends AbstractPoolTestCase {
|
||||
@Test
|
||||
public void testConstructorAssertions() {
|
||||
try {
|
||||
new DelegatingDirContext(keyedObjectPoolMock, null,
|
||||
DirContextType.READ_ONLY);
|
||||
fail("IllegalArgumentException expected");
|
||||
} catch (IllegalArgumentException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
|
||||
try {
|
||||
new DelegatingDirContext(keyedObjectPoolMock, dirContextMock, null);
|
||||
fail("IllegalArgumentException expected");
|
||||
} catch (IllegalArgumentException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHelperMethods() throws Exception {
|
||||
|
||||
// Wrap the DirContext once
|
||||
final DelegatingDirContext delegatingDirContext = new DelegatingDirContext(
|
||||
keyedObjectPoolMock, dirContextMock, DirContextType.READ_ONLY);
|
||||
|
||||
final Context delegateContext = delegatingDirContext
|
||||
.getDelegateContext();
|
||||
assertEquals(dirContextMock, delegateContext);
|
||||
|
||||
final DirContext delegateDirContext = delegatingDirContext
|
||||
.getDelegateDirContext();
|
||||
assertEquals(dirContextMock, delegateDirContext);
|
||||
|
||||
final DirContext innerDelegateDirContext = delegatingDirContext
|
||||
.getInnermostDelegateDirContext();
|
||||
assertEquals(dirContextMock, innerDelegateDirContext);
|
||||
|
||||
delegatingDirContext.assertOpen();
|
||||
|
||||
// Wrap the wrapper
|
||||
KeyedObjectPool secondKeyedObjectPoolMock = mock(KeyedObjectPool.class);
|
||||
|
||||
final DelegatingDirContext delegatingDirContext2 = new DelegatingDirContext(
|
||||
secondKeyedObjectPoolMock, delegatingDirContext,
|
||||
DirContextType.READ_ONLY);
|
||||
|
||||
final DirContext delegateDirContext2 = delegatingDirContext2
|
||||
.getDelegateDirContext();
|
||||
assertEquals(delegatingDirContext, delegateDirContext2);
|
||||
|
||||
final DirContext innerDelegateDirContext2 = delegatingDirContext2
|
||||
.getInnermostDelegateDirContext();
|
||||
assertEquals(dirContextMock, innerDelegateDirContext2);
|
||||
|
||||
delegatingDirContext2.assertOpen();
|
||||
|
||||
// Close the outer wrapper
|
||||
delegatingDirContext2.close();
|
||||
|
||||
final DirContext delegateContext2closed = delegatingDirContext2
|
||||
.getDelegateDirContext();
|
||||
assertNull(delegateContext2closed);
|
||||
|
||||
final DirContext innerDelegateContext2closed = delegatingDirContext2
|
||||
.getInnermostDelegateDirContext();
|
||||
assertNull(innerDelegateContext2closed);
|
||||
|
||||
try {
|
||||
delegatingDirContext2.assertOpen();
|
||||
fail("delegatingDirContext2.assertOpen() should have thrown a NamingException");
|
||||
} catch (NamingException ne) {
|
||||
// Expected
|
||||
}
|
||||
|
||||
// Close the outer wrapper
|
||||
delegatingDirContext.close();
|
||||
|
||||
final DirContext delegateDirContextClosed = delegatingDirContext
|
||||
.getDelegateDirContext();
|
||||
assertNull(delegateDirContextClosed);
|
||||
|
||||
final DirContext innerDelegateDirContextClosed = delegatingDirContext
|
||||
.getInnermostDelegateDirContext();
|
||||
assertNull(innerDelegateDirContextClosed);
|
||||
|
||||
try {
|
||||
delegatingDirContext.assertOpen();
|
||||
fail("delegatingDirContext.assertOpen() should have thrown a NamingException");
|
||||
} catch (NamingException ne) {
|
||||
// Expected
|
||||
}
|
||||
|
||||
verify(secondKeyedObjectPoolMock)
|
||||
.returnObject(DirContextType.READ_ONLY, dirContextMock);
|
||||
verify(keyedObjectPoolMock).returnObject(DirContextType.READ_ONLY, dirContextMock);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testObjectMethods() throws Exception {
|
||||
// Wrap the DirContext once
|
||||
final DelegatingDirContext delegatingDirContext = new DelegatingDirContext(
|
||||
keyedObjectPoolMock, dirContextMock, DirContextType.READ_ONLY);
|
||||
assertEquals(dirContextMock.toString(), delegatingDirContext.toString());
|
||||
delegatingDirContext.hashCode(); // Run it to make sure it doesn't
|
||||
// fail
|
||||
|
||||
assertTrue(delegatingDirContext.equals(delegatingDirContext));
|
||||
assertFalse(delegatingDirContext.equals(new Object()));
|
||||
|
||||
final DelegatingDirContext delegatingDirContext2 = new DelegatingDirContext(
|
||||
keyedObjectPoolMock, dirContextMock, DirContextType.READ_ONLY);
|
||||
assertTrue(delegatingDirContext.equals(delegatingDirContext2));
|
||||
assertTrue(delegatingDirContext2.equals(delegatingDirContext));
|
||||
assertTrue(delegatingDirContext.equals(dirContextMock));
|
||||
|
||||
// Close the context and try again
|
||||
delegatingDirContext.close();
|
||||
|
||||
assertEquals("DirContext is closed", delegatingDirContext.toString());
|
||||
assertEquals(0, delegatingDirContext.hashCode()); // Run it to make
|
||||
// sure it doesn't
|
||||
// fail
|
||||
|
||||
assertTrue(delegatingDirContext.equals(delegatingDirContext));
|
||||
assertFalse(delegatingDirContext.equals(new Object()));
|
||||
|
||||
assertFalse(delegatingDirContext.equals(delegatingDirContext2));
|
||||
assertFalse(delegatingDirContext2.equals(delegatingDirContext));
|
||||
assertFalse(delegatingDirContext.equals(dirContextMock));
|
||||
|
||||
verify(keyedObjectPoolMock).returnObject(DirContextType.READ_ONLY, dirContextMock);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnsupportedMethods() throws Exception {
|
||||
final DelegatingDirContext delegatingDirContext = new DelegatingDirContext(
|
||||
keyedObjectPoolMock, dirContextMock, DirContextType.READ_ONLY);
|
||||
|
||||
try {
|
||||
delegatingDirContext.createSubcontext((Name) null, null);
|
||||
fail("DelegatingDirContext.createSubcontext Should have thrown an UnsupportedOperationException");
|
||||
} catch (UnsupportedOperationException uoe) {
|
||||
// Expected
|
||||
}
|
||||
try {
|
||||
delegatingDirContext.createSubcontext((String) null, null);
|
||||
fail("DelegatingDirContext.createSubcontext Should have thrown an UnsupportedOperationException");
|
||||
} catch (UnsupportedOperationException uoe) {
|
||||
// Expected
|
||||
}
|
||||
try {
|
||||
delegatingDirContext.getSchema((Name) null);
|
||||
fail("DelegatingDirContext.getSchema Should have thrown an UnsupportedOperationException");
|
||||
} catch (UnsupportedOperationException uoe) {
|
||||
// Expected
|
||||
}
|
||||
try {
|
||||
delegatingDirContext.getSchema((String) null);
|
||||
fail("DelegatingDirContext.getSchema Should have thrown an UnsupportedOperationException");
|
||||
} catch (UnsupportedOperationException uoe) {
|
||||
// Expected
|
||||
}
|
||||
try {
|
||||
delegatingDirContext.getSchemaClassDefinition((Name) null);
|
||||
fail("DelegatingDirContext.getSchemaClassDefinition Should have thrown an UnsupportedOperationException");
|
||||
} catch (UnsupportedOperationException uoe) {
|
||||
// Expected
|
||||
}
|
||||
try {
|
||||
delegatingDirContext.getSchemaClassDefinition((String) null);
|
||||
fail("DelegatingDirContext.getSchemaClassDefinition Should have thrown an UnsupportedOperationException");
|
||||
} catch (UnsupportedOperationException uoe) {
|
||||
// Expected
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAllMethodsOpened() throws Exception {
|
||||
final DelegatingDirContext delegatingDirContext = new DelegatingDirContext(
|
||||
keyedObjectPoolMock, dirContextMock, DirContextType.READ_ONLY);
|
||||
|
||||
delegatingDirContext.bind((Name) null, null, null);
|
||||
delegatingDirContext.bind((String) null, null, null);
|
||||
delegatingDirContext.getAttributes((Name) null, null);
|
||||
delegatingDirContext.getAttributes((Name) null);
|
||||
delegatingDirContext.getAttributes((String) null, null);
|
||||
delegatingDirContext.getAttributes((String) null);
|
||||
delegatingDirContext.modifyAttributes((Name) null, 0, null);
|
||||
delegatingDirContext.modifyAttributes((Name) null, null);
|
||||
delegatingDirContext.modifyAttributes((String) null, 0, null);
|
||||
delegatingDirContext.modifyAttributes((String) null, null);
|
||||
delegatingDirContext.rebind((Name) null, null, null);
|
||||
delegatingDirContext.rebind((String) null, null, null);
|
||||
delegatingDirContext.search((Name) null, (Attributes) null, null);
|
||||
delegatingDirContext.search((Name) null, null);
|
||||
delegatingDirContext.search((Name) null, null, null, null);
|
||||
delegatingDirContext.search((Name) null, (String) null, null);
|
||||
delegatingDirContext.search((String) null, (Attributes) null, null);
|
||||
delegatingDirContext.search((String) null, null);
|
||||
delegatingDirContext.search((String) null, null, null, null);
|
||||
delegatingDirContext.search((String) null, (String) null, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAllMethodsClosed() throws Exception {
|
||||
final DelegatingDirContext delegatingDirContext = new DelegatingDirContext(
|
||||
keyedObjectPoolMock, dirContextMock, DirContextType.READ_ONLY);
|
||||
|
||||
delegatingDirContext.close();
|
||||
|
||||
try {
|
||||
delegatingDirContext.bind((Name) null, null, null);
|
||||
fail("DelegatingDirContext.bind should have thrown a NamingException");
|
||||
} catch (NamingException ne) {
|
||||
// Expected
|
||||
}
|
||||
try {
|
||||
delegatingDirContext.bind((String) null, null, null);
|
||||
fail("DelegatingDirContext.bind should have thrown a NamingException");
|
||||
} catch (NamingException ne) {
|
||||
// Expected
|
||||
}
|
||||
try {
|
||||
delegatingDirContext.getAttributes((Name) null, null);
|
||||
fail("DelegatingDirContext.getAttributes should have thrown a NamingException");
|
||||
} catch (NamingException ne) {
|
||||
// Expected
|
||||
}
|
||||
try {
|
||||
delegatingDirContext.getAttributes((Name) null);
|
||||
fail("DelegatingDirContext.getAttributes should have thrown a NamingException");
|
||||
} catch (NamingException ne) {
|
||||
// Expected
|
||||
}
|
||||
try {
|
||||
delegatingDirContext.getAttributes((String) null, null);
|
||||
fail("DelegatingDirContext.getAttributes should have thrown a NamingException");
|
||||
} catch (NamingException ne) {
|
||||
// Expected
|
||||
}
|
||||
try {
|
||||
delegatingDirContext.getAttributes((String) null);
|
||||
fail("DelegatingDirContext.getAttributes should have thrown a NamingException");
|
||||
} catch (NamingException ne) {
|
||||
// Expected
|
||||
}
|
||||
try {
|
||||
delegatingDirContext.modifyAttributes((Name) null, 0, null);
|
||||
fail("DelegatingDirContext.modifyAttributes should have thrown a NamingException");
|
||||
} catch (NamingException ne) {
|
||||
// Expected
|
||||
}
|
||||
try {
|
||||
delegatingDirContext.modifyAttributes((Name) null, null);
|
||||
fail("DelegatingDirContext.modifyAttributes should have thrown a NamingException");
|
||||
} catch (NamingException ne) {
|
||||
// Expected
|
||||
}
|
||||
try {
|
||||
delegatingDirContext.modifyAttributes((String) null, 0, null);
|
||||
fail("DelegatingDirContext.modifyAttributes should have thrown a NamingException");
|
||||
} catch (NamingException ne) {
|
||||
// Expected
|
||||
}
|
||||
try {
|
||||
delegatingDirContext.modifyAttributes((String) null, null);
|
||||
fail("DelegatingDirContext.modifyAttributes should have thrown a NamingException");
|
||||
} catch (NamingException ne) {
|
||||
// Expected
|
||||
}
|
||||
try {
|
||||
delegatingDirContext.rebind((Name) null, null, null);
|
||||
fail("DelegatingDirContext.rebind should have thrown a NamingException");
|
||||
} catch (NamingException ne) {
|
||||
// Expected
|
||||
}
|
||||
try {
|
||||
delegatingDirContext.rebind((String) null, null, null);
|
||||
fail("DelegatingDirContext.rebind should have thrown a NamingException");
|
||||
} catch (NamingException ne) {
|
||||
// Expected
|
||||
}
|
||||
try {
|
||||
delegatingDirContext.search((Name) null, (Attributes) null, null);
|
||||
fail("DelegatingDirContext.search should have thrown a NamingException");
|
||||
} catch (NamingException ne) {
|
||||
// Expected
|
||||
}
|
||||
try {
|
||||
delegatingDirContext.search((Name) null, null);
|
||||
fail("DelegatingDirContext.search should have thrown a NamingException");
|
||||
} catch (NamingException ne) {
|
||||
// Expected
|
||||
}
|
||||
try {
|
||||
delegatingDirContext.search((Name) null, null, null, null);
|
||||
fail("DelegatingDirContext.search should have thrown a NamingException");
|
||||
} catch (NamingException ne) {
|
||||
// Expected
|
||||
}
|
||||
try {
|
||||
delegatingDirContext.search((Name) null, (String) null, null);
|
||||
fail("DelegatingDirContext.search should have thrown a NamingException");
|
||||
} catch (NamingException ne) {
|
||||
// Expected
|
||||
}
|
||||
try {
|
||||
delegatingDirContext.search((String) null, (Attributes) null, null);
|
||||
fail("DelegatingDirContext.search should have thrown a NamingException");
|
||||
} catch (NamingException ne) {
|
||||
// Expected
|
||||
}
|
||||
try {
|
||||
delegatingDirContext.search((String) null, null);
|
||||
fail("DelegatingDirContext.search should have thrown a NamingException");
|
||||
} catch (NamingException ne) {
|
||||
// Expected
|
||||
}
|
||||
try {
|
||||
delegatingDirContext.search((String) null, null, null, null);
|
||||
fail("DelegatingDirContext.search should have thrown a NamingException");
|
||||
} catch (NamingException ne) {
|
||||
// Expected
|
||||
}
|
||||
try {
|
||||
delegatingDirContext.search((String) null, (String) null, null);
|
||||
fail("DelegatingDirContext.search should have thrown a NamingException");
|
||||
} catch (NamingException ne) {
|
||||
// Expected
|
||||
}
|
||||
|
||||
verify(keyedObjectPoolMock).returnObject(DirContextType.READ_ONLY, dirContextMock);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDoubleClose() throws Exception {
|
||||
final DelegatingDirContext delegatingDirContext = new DelegatingDirContext(
|
||||
keyedObjectPoolMock, dirContextMock, DirContextType.READ_ONLY);
|
||||
|
||||
delegatingDirContext.close();
|
||||
|
||||
// noop close
|
||||
delegatingDirContext.close();
|
||||
|
||||
verify(keyedObjectPoolMock, times(1)).returnObject(DirContextType.READ_ONLY, dirContextMock);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,250 @@
|
||||
/*
|
||||
* Copyright 2005-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.ldap.pool2;
|
||||
|
||||
import org.apache.commons.pool2.KeyedObjectPool;
|
||||
import org.junit.Test;
|
||||
|
||||
import javax.naming.NamingException;
|
||||
import javax.naming.directory.DirContext;
|
||||
import javax.naming.ldap.LdapContext;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
/**
|
||||
* @author Eric Dalquist <a
|
||||
* href="mailto:eric.dalquist@doit.wisc.edu">eric.dalquist@doit.wisc.edu</a>
|
||||
*/
|
||||
public class DelegatingLdapContextTest extends AbstractPoolTestCase {
|
||||
@Test
|
||||
public void testConstructorAssertions() {
|
||||
try {
|
||||
new DelegatingLdapContext(keyedObjectPoolMock, null,
|
||||
DirContextType.READ_ONLY);
|
||||
fail("IllegalArgumentException expected");
|
||||
} catch (IllegalArgumentException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
|
||||
try {
|
||||
new DelegatingLdapContext(keyedObjectPoolMock, ldapContextMock,
|
||||
null);
|
||||
fail("IllegalArgumentException expected");
|
||||
} catch (IllegalArgumentException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHelperMethods() throws Exception {
|
||||
// Wrap the LdapContext once
|
||||
final DelegatingLdapContext delegatingLdapContext = new DelegatingLdapContext(
|
||||
keyedObjectPoolMock, ldapContextMock, DirContextType.READ_ONLY);
|
||||
|
||||
final DirContext delegateDirContext = delegatingLdapContext
|
||||
.getDelegateDirContext();
|
||||
assertEquals(ldapContextMock, delegateDirContext);
|
||||
|
||||
final LdapContext delegateLdapContext = delegatingLdapContext
|
||||
.getDelegateLdapContext();
|
||||
assertEquals(ldapContextMock, delegateLdapContext);
|
||||
|
||||
final LdapContext innerDelegateLdapContext = delegatingLdapContext
|
||||
.getInnermostDelegateLdapContext();
|
||||
assertEquals(ldapContextMock, innerDelegateLdapContext);
|
||||
|
||||
delegatingLdapContext.assertOpen();
|
||||
|
||||
// Wrap the wrapper
|
||||
KeyedObjectPool secondKeyedObjectPoolMock = mock(KeyedObjectPool.class);
|
||||
|
||||
final DelegatingLdapContext delegatingLdapContext2 = new DelegatingLdapContext(
|
||||
secondKeyedObjectPoolMock, delegatingLdapContext,
|
||||
DirContextType.READ_ONLY);
|
||||
|
||||
final LdapContext delegateLdapContext2 = delegatingLdapContext2
|
||||
.getDelegateLdapContext();
|
||||
assertEquals(delegatingLdapContext, delegateLdapContext2);
|
||||
|
||||
final LdapContext innerDelegateLdapContext2 = delegatingLdapContext2
|
||||
.getInnermostDelegateLdapContext();
|
||||
assertEquals(ldapContextMock, innerDelegateLdapContext2);
|
||||
|
||||
delegatingLdapContext2.assertOpen();
|
||||
|
||||
// Close the outer wrapper
|
||||
delegatingLdapContext2.close();
|
||||
|
||||
final LdapContext delegateContext2closed = delegatingLdapContext2
|
||||
.getDelegateLdapContext();
|
||||
assertNull(delegateContext2closed);
|
||||
|
||||
final LdapContext innerDelegateContext2closed = delegatingLdapContext2
|
||||
.getInnermostDelegateLdapContext();
|
||||
assertNull(innerDelegateContext2closed);
|
||||
|
||||
try {
|
||||
delegatingLdapContext2.assertOpen();
|
||||
fail("delegatingLdapContext2.assertOpen() should have thrown a NamingException");
|
||||
} catch (NamingException ne) {
|
||||
// Expected
|
||||
}
|
||||
|
||||
// Close the outer wrapper
|
||||
delegatingLdapContext.close();
|
||||
|
||||
final LdapContext delegateLdapContextClosed = delegatingLdapContext
|
||||
.getDelegateLdapContext();
|
||||
assertNull(delegateLdapContextClosed);
|
||||
|
||||
final LdapContext innerDelegateLdapContextClosed = delegatingLdapContext
|
||||
.getInnermostDelegateLdapContext();
|
||||
assertNull(innerDelegateLdapContextClosed);
|
||||
|
||||
try {
|
||||
delegatingLdapContext.assertOpen();
|
||||
fail("delegatingLdapContext.assertOpen() should have thrown a NamingException");
|
||||
} catch (NamingException ne) {
|
||||
// Expected
|
||||
}
|
||||
|
||||
verify(secondKeyedObjectPoolMock)
|
||||
.returnObject(DirContextType.READ_ONLY, ldapContextMock);
|
||||
verify(keyedObjectPoolMock).returnObject(DirContextType.READ_ONLY, ldapContextMock);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testObjectMethods() throws Exception {
|
||||
// Wrap the LdapContext once
|
||||
final DelegatingLdapContext delegatingLdapContext = new DelegatingLdapContext(
|
||||
keyedObjectPoolMock, ldapContextMock, DirContextType.READ_ONLY);
|
||||
assertEquals(ldapContextMock.toString(),
|
||||
delegatingLdapContext.toString());
|
||||
delegatingLdapContext.hashCode(); // Run it to make sure it doesn't fail
|
||||
|
||||
assertTrue(delegatingLdapContext.equals(delegatingLdapContext));
|
||||
assertFalse(delegatingLdapContext.equals(new Object()));
|
||||
|
||||
final DelegatingLdapContext delegatingLdapContext2 = new DelegatingLdapContext(
|
||||
keyedObjectPoolMock, ldapContextMock, DirContextType.READ_ONLY);
|
||||
assertTrue(delegatingLdapContext.equals(delegatingLdapContext2));
|
||||
assertTrue(delegatingLdapContext2.equals(delegatingLdapContext));
|
||||
assertTrue(delegatingLdapContext.equals(ldapContextMock));
|
||||
|
||||
// Close the context and try again
|
||||
delegatingLdapContext.close();
|
||||
|
||||
assertEquals("LdapContext is closed", delegatingLdapContext.toString());
|
||||
assertEquals(0, delegatingLdapContext.hashCode()); // Run it to make
|
||||
// sure it doesn't
|
||||
// fail
|
||||
|
||||
assertTrue(delegatingLdapContext.equals(delegatingLdapContext));
|
||||
assertFalse(delegatingLdapContext.equals(new Object()));
|
||||
|
||||
assertFalse(delegatingLdapContext.equals(delegatingLdapContext2));
|
||||
assertFalse(delegatingLdapContext2.equals(delegatingLdapContext));
|
||||
assertFalse(delegatingLdapContext.equals(ldapContextMock));
|
||||
|
||||
verify(keyedObjectPoolMock).returnObject(DirContextType.READ_ONLY, ldapContextMock);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnsupportedMethods() throws Exception {
|
||||
final DelegatingLdapContext delegatingLdapContext = new DelegatingLdapContext(
|
||||
keyedObjectPoolMock, ldapContextMock, DirContextType.READ_ONLY);
|
||||
|
||||
try {
|
||||
delegatingLdapContext.newInstance(null);
|
||||
fail("DelegatingLdapContext.newInstance Should have thrown an UnsupportedOperationException");
|
||||
} catch (UnsupportedOperationException uoe) {
|
||||
// Expected
|
||||
}
|
||||
try {
|
||||
delegatingLdapContext.reconnect(null);
|
||||
fail("DelegatingLdapContext.reconnect Should have thrown an UnsupportedOperationException");
|
||||
} catch (UnsupportedOperationException uoe) {
|
||||
// Expected
|
||||
}
|
||||
try {
|
||||
delegatingLdapContext.setRequestControls(null);
|
||||
fail("DelegatingLdapContext.setRequestControls Should have thrown an UnsupportedOperationException");
|
||||
} catch (UnsupportedOperationException uoe) {
|
||||
// Expected
|
||||
}
|
||||
}
|
||||
|
||||
// nice
|
||||
@Test
|
||||
public void testAllMethodsOpened() throws Exception {
|
||||
final DelegatingLdapContext delegatingLdapContext = new DelegatingLdapContext(
|
||||
keyedObjectPoolMock, ldapContextMock, DirContextType.READ_ONLY);
|
||||
|
||||
delegatingLdapContext.extendedOperation(null);
|
||||
delegatingLdapContext.getConnectControls();
|
||||
delegatingLdapContext.getRequestControls();
|
||||
delegatingLdapContext.getResponseControls();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAllMethodsClosed() throws Exception {
|
||||
final DelegatingLdapContext delegatingLdapContext = new DelegatingLdapContext(
|
||||
keyedObjectPoolMock, ldapContextMock, DirContextType.READ_ONLY);
|
||||
|
||||
delegatingLdapContext.close();
|
||||
|
||||
try {
|
||||
delegatingLdapContext.extendedOperation(null);
|
||||
fail("DelegatingLdapContext.extendedOperation should have thrown a NamingException");
|
||||
} catch (NamingException ne) {
|
||||
// Expected
|
||||
}
|
||||
try {
|
||||
delegatingLdapContext.getConnectControls();
|
||||
fail("DelegatingLdapContext.getConnectControls should have thrown a NamingException");
|
||||
} catch (NamingException ne) {
|
||||
// Expected
|
||||
}
|
||||
try {
|
||||
delegatingLdapContext.getRequestControls();
|
||||
fail("DelegatingLdapContext.getRequestControls should have thrown a NamingException");
|
||||
} catch (NamingException ne) {
|
||||
// Expected
|
||||
}
|
||||
try {
|
||||
delegatingLdapContext.getResponseControls();
|
||||
fail("DelegatingLdapContext.getResponseControls should have thrown a NamingException");
|
||||
} catch (NamingException ne) {
|
||||
// Expected
|
||||
}
|
||||
|
||||
verify(keyedObjectPoolMock).returnObject(DirContextType.READ_ONLY, ldapContextMock);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDoubleClose() throws Exception {
|
||||
final DelegatingLdapContext delegatingLdapContext = new DelegatingLdapContext(
|
||||
keyedObjectPoolMock, ldapContextMock, DirContextType.READ_ONLY);
|
||||
|
||||
delegatingLdapContext.close();
|
||||
|
||||
// noop close
|
||||
delegatingLdapContext.close();
|
||||
|
||||
verify(keyedObjectPoolMock, times(1)).returnObject(DirContextType.READ_ONLY, ldapContextMock);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2005-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.ldap.pool2;
|
||||
|
||||
import org.apache.commons.pool2.PooledObject;
|
||||
import org.apache.commons.pool2.impl.EvictionConfig;
|
||||
import org.apache.commons.pool2.impl.EvictionPolicy;
|
||||
|
||||
/**
|
||||
* A dummy {@link EvictionPolicy} implementation to test pool2 config.
|
||||
*
|
||||
* @author Anindya Chatterjee
|
||||
* */
|
||||
public class DummyEvictionPolicy implements EvictionPolicy {
|
||||
|
||||
/**
|
||||
* @see EvictionPolicy#evict(EvictionConfig, PooledObject, int)
|
||||
*
|
||||
* */
|
||||
@Override
|
||||
public boolean evict(EvictionConfig config, PooledObject underTest, int idleCount) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2005-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.ldap.pool2;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
/**
|
||||
* Unit tests for the MutableDelegatingLdapContext class.
|
||||
*
|
||||
* @author Ulrik Sandberg
|
||||
*/
|
||||
public class MutableDelegatingLdapContextTest extends AbstractPoolTestCase {
|
||||
@Test
|
||||
public void testSupportedMethodsAllowedToCall() throws Exception {
|
||||
final MutableDelegatingLdapContext delegatingLdapContext = new MutableDelegatingLdapContext(
|
||||
keyedObjectPoolMock, ldapContextMock, DirContextType.READ_ONLY);
|
||||
|
||||
delegatingLdapContext.setRequestControls(null);
|
||||
|
||||
verify(ldapContextMock).setRequestControls(null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,227 @@
|
||||
/*
|
||||
* Copyright 2005-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.ldap.pool2.factory;
|
||||
|
||||
import org.apache.commons.pool2.PooledObject;
|
||||
import org.apache.commons.pool2.impl.DefaultPooledObject;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.internal.util.reflection.Whitebox;
|
||||
import org.springframework.ldap.core.ContextSource;
|
||||
import org.springframework.ldap.pool2.DirContextType;
|
||||
import org.springframework.ldap.pool2.validation.DirContextValidator;
|
||||
import org.springframework.ldap.pool2.AbstractPoolTestCase;
|
||||
|
||||
import javax.naming.directory.DirContext;
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.Proxy;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
/**
|
||||
* @author Eric Dalquist
|
||||
* @author Anindya Chatterjee
|
||||
*/
|
||||
public class DirContextPooledObjectFactoryTest extends AbstractPoolTestCase {
|
||||
|
||||
@Test
|
||||
public void testProperties() throws Exception {
|
||||
final DirContextPooledObjectFactory objectFactory = new DirContextPooledObjectFactory();
|
||||
|
||||
try {
|
||||
objectFactory.setContextSource(null);
|
||||
fail("DirContextPooledObjectFactory.setContextSource should have thrown an IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException iae) {
|
||||
// Expected
|
||||
}
|
||||
|
||||
objectFactory.setContextSource(contextSourceMock);
|
||||
final ContextSource contextSource2 = objectFactory.getContextSource();
|
||||
assertEquals(contextSourceMock, contextSource2);
|
||||
|
||||
|
||||
try {
|
||||
objectFactory.setDirContextValidator(null);
|
||||
fail("DirContextPooledObjectFactory.setDirContextValidator should have thrown an IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException iae) {
|
||||
// Expected
|
||||
}
|
||||
|
||||
objectFactory.setDirContextValidator(dirContextValidatorMock);
|
||||
final DirContextValidator dirContextValidator2 = objectFactory.getDirContextValidator();
|
||||
assertEquals(dirContextValidatorMock, dirContextValidator2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMakeObjectAssertions() throws Exception {
|
||||
final DirContextPooledObjectFactory objectFactory = new DirContextPooledObjectFactory();
|
||||
|
||||
try {
|
||||
objectFactory.makeObject(DirContextType.READ_ONLY);
|
||||
fail("IllegalArgumentException expected");
|
||||
} catch (IllegalArgumentException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
|
||||
objectFactory.setContextSource(contextSourceMock);
|
||||
|
||||
try {
|
||||
objectFactory.makeObject(null);
|
||||
fail("IllegalArgumentException expected");
|
||||
} catch (IllegalArgumentException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMakeObjectReadOnly() throws Exception {
|
||||
final DirContextPooledObjectFactory objectFactory = new DirContextPooledObjectFactory();
|
||||
|
||||
DirContext readOnlyContextMock = mock(DirContext.class);
|
||||
|
||||
when(contextSourceMock.getReadOnlyContext()).thenReturn(readOnlyContextMock);
|
||||
objectFactory.setContextSource(contextSourceMock);
|
||||
|
||||
final PooledObject createdDirContext = objectFactory.makeObject(DirContextType.READ_ONLY);
|
||||
InvocationHandler invocationHandler = Proxy.getInvocationHandler(createdDirContext.getObject());
|
||||
assertEquals(readOnlyContextMock, Whitebox.getInternalState(invocationHandler, "target"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMakeObjectReadWrite() throws Exception {
|
||||
final DirContextPooledObjectFactory objectFactory = new DirContextPooledObjectFactory();
|
||||
|
||||
DirContext readWriteContextMock = mock(DirContext.class);
|
||||
|
||||
when(contextSourceMock.getReadWriteContext()).thenReturn(readWriteContextMock);
|
||||
objectFactory.setContextSource(contextSourceMock);
|
||||
|
||||
final PooledObject createdDirContext = objectFactory.makeObject(DirContextType.READ_WRITE);
|
||||
|
||||
InvocationHandler invocationHandler = Proxy.getInvocationHandler(createdDirContext.getObject());
|
||||
assertEquals(readWriteContextMock, Whitebox.getInternalState(invocationHandler, "target"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidateObjectAssertions() throws Exception {
|
||||
final DirContextPooledObjectFactory objectFactory = new DirContextPooledObjectFactory();
|
||||
|
||||
try {
|
||||
PooledObject pooledObject = new DefaultPooledObject(dirContextMock);
|
||||
objectFactory.validateObject(DirContextType.READ_ONLY, pooledObject);
|
||||
fail("IllegalArgumentException expected");
|
||||
} catch (IllegalArgumentException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
|
||||
objectFactory.setDirContextValidator(dirContextValidatorMock);
|
||||
|
||||
try {
|
||||
PooledObject pooledObject = new DefaultPooledObject(dirContextMock);
|
||||
objectFactory.validateObject(null, pooledObject);
|
||||
fail("IllegalArgumentException expected");
|
||||
} catch (IllegalArgumentException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
|
||||
try {
|
||||
PooledObject pooledObject = new DefaultPooledObject(dirContextMock);
|
||||
objectFactory.validateObject(new Object(), pooledObject);
|
||||
fail("IllegalArgumentException expected");
|
||||
} catch (IllegalArgumentException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
|
||||
try {
|
||||
objectFactory.validateObject(DirContextType.READ_ONLY, null);
|
||||
fail("IllegalArgumentException expected");
|
||||
} catch (IllegalArgumentException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
|
||||
try {
|
||||
PooledObject pooledObject = new DefaultPooledObject(new Object());
|
||||
objectFactory.validateObject(DirContextType.READ_ONLY, pooledObject);
|
||||
fail("IllegalArgumentException expected");
|
||||
} catch (IllegalArgumentException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidateObject() throws Exception {
|
||||
when(dirContextValidatorMock
|
||||
.validateDirContext(DirContextType.READ_ONLY, dirContextMock))
|
||||
.thenReturn(true);
|
||||
|
||||
final DirContextPooledObjectFactory objectFactory = new DirContextPooledObjectFactory();
|
||||
objectFactory.setDirContextValidator(dirContextValidatorMock);
|
||||
|
||||
PooledObject pooledObject = new DefaultPooledObject(dirContextMock);
|
||||
final boolean valid = objectFactory.validateObject(DirContextType.READ_ONLY, pooledObject);
|
||||
assertTrue(valid);
|
||||
|
||||
//Check exception in validator
|
||||
DirContextValidator secondDirContextValidatorMock = mock(DirContextValidator.class);
|
||||
|
||||
when(secondDirContextValidatorMock.validateDirContext(DirContextType.READ_ONLY, dirContextMock))
|
||||
.thenThrow(new RuntimeException("Failed to validate"));
|
||||
objectFactory.setDirContextValidator(secondDirContextValidatorMock);
|
||||
|
||||
final boolean valid2 = objectFactory.validateObject(DirContextType.READ_ONLY, pooledObject);
|
||||
assertFalse(valid2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDestroyObjectAssertions() throws Exception {
|
||||
final DirContextPooledObjectFactory objectFactory = new DirContextPooledObjectFactory();
|
||||
|
||||
try {
|
||||
objectFactory.destroyObject(DirContextType.READ_ONLY, null);
|
||||
fail("IllegalArgumentException expected");
|
||||
} catch (IllegalArgumentException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
|
||||
try {
|
||||
PooledObject pooledObject = new DefaultPooledObject(new Object());
|
||||
objectFactory.validateObject(DirContextType.READ_ONLY, pooledObject);
|
||||
fail("IllegalArgumentException expected");
|
||||
} catch (IllegalArgumentException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDestroyObject() throws Exception {
|
||||
final DirContextPooledObjectFactory objectFactory = new DirContextPooledObjectFactory();
|
||||
|
||||
PooledObject pooledObject = new DefaultPooledObject(dirContextMock);
|
||||
objectFactory.destroyObject(DirContextType.READ_ONLY, pooledObject);
|
||||
|
||||
DirContext throwingDirContextMock = Mockito.mock(DirContext.class);
|
||||
|
||||
doThrow(new RuntimeException("Failed to close"))
|
||||
.when(throwingDirContextMock).close();
|
||||
|
||||
pooledObject = new DefaultPooledObject(throwingDirContextMock);
|
||||
objectFactory.destroyObject(DirContextType.READ_ONLY, pooledObject);
|
||||
verify(dirContextMock).close();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 2005-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.ldap.pool2.factory;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.ldap.pool2.AbstractPoolTestCase;
|
||||
import org.springframework.ldap.pool2.MutableDelegatingLdapContext;
|
||||
|
||||
import javax.naming.directory.DirContext;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* Unit tests for the MutablePoolingContextSource class.
|
||||
*
|
||||
* @author Ulrik Sandberg
|
||||
* @author Anindya Chatterjee
|
||||
*/
|
||||
public class MutablePooledContextSourceTest extends AbstractPoolTestCase {
|
||||
|
||||
@Test
|
||||
public void testGetReadOnlyLdapContext() throws Exception {
|
||||
|
||||
when(contextSourceMock.getReadOnlyContext()).thenReturn(ldapContextMock);
|
||||
|
||||
final MutablePooledContextSource poolingContextSource = new MutablePooledContextSource(null);
|
||||
poolingContextSource.setContextSource(contextSourceMock);
|
||||
|
||||
// Get a context
|
||||
final DirContext result = poolingContextSource.getReadOnlyContext();
|
||||
|
||||
assertEquals(MutableDelegatingLdapContext.class, result.getClass());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright 2005-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.ldap.pool2.factory;
|
||||
|
||||
import org.apache.commons.pool2.impl.GenericKeyedObjectPoolConfig;
|
||||
import org.junit.Test;
|
||||
import org.springframework.ldap.pool2.AbstractPoolTestCase;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* @author Anindya Chatterjee
|
||||
* */
|
||||
public class PoolConfigTest extends AbstractPoolTestCase {
|
||||
|
||||
@Test
|
||||
public void testProperties() {
|
||||
final PoolConfig poolConfig = new PoolConfig();
|
||||
|
||||
poolConfig.setMaxTotalPerKey(5);
|
||||
final int maxTotalPerKey = poolConfig.getMaxTotalPerKey();
|
||||
assertEquals(5, maxTotalPerKey);
|
||||
|
||||
poolConfig.setMaxIdlePerKey(500);
|
||||
final int maxIdle = poolConfig.getMaxIdlePerKey();
|
||||
assertEquals(500, maxIdle);
|
||||
|
||||
poolConfig.setMaxTotal(5000);
|
||||
final int maxTotal = poolConfig.getMaxTotal();
|
||||
assertEquals(5000, maxTotal);
|
||||
|
||||
poolConfig.setMaxWaitMillis(2000L);
|
||||
final long maxWait = poolConfig.getMaxWaitMillis();
|
||||
assertEquals(2000L, maxWait);
|
||||
|
||||
poolConfig.setMinEvictableIdleTimeMillis(60000L);
|
||||
final long minEvictableIdleTimeMillis = poolConfig.getMinEvictableIdleTimeMillis();
|
||||
assertEquals(60000L, minEvictableIdleTimeMillis);
|
||||
|
||||
poolConfig.setMinIdlePerKey(100);
|
||||
final int minIdle = poolConfig.getMinIdlePerKey();
|
||||
assertEquals(100, minIdle);
|
||||
|
||||
poolConfig.setNumTestsPerEvictionRun(5);
|
||||
final int numTestsPerEvictionRun = poolConfig.getNumTestsPerEvictionRun();
|
||||
assertEquals(5, numTestsPerEvictionRun);
|
||||
|
||||
poolConfig.setTestOnBorrow(true);
|
||||
final boolean testOnBorrow = poolConfig.isTestOnBorrow();
|
||||
assertEquals(true, testOnBorrow);
|
||||
|
||||
poolConfig.setTestOnReturn(true);
|
||||
final boolean testOnReturn = poolConfig.isTestOnReturn();
|
||||
assertEquals(true, testOnReturn);
|
||||
|
||||
poolConfig.setTestWhileIdle(true);
|
||||
final boolean testWhileIdle = poolConfig.isTestWhileIdle();
|
||||
assertEquals(true, testWhileIdle);
|
||||
|
||||
poolConfig.setTestOnCreate(true);
|
||||
final boolean testOnCreate = poolConfig.isTestOnCreate();
|
||||
assertEquals(true, testOnCreate);
|
||||
|
||||
poolConfig.setTimeBetweenEvictionRunsMillis(120000L);
|
||||
final long timeBetweenEvictionRunsMillis = poolConfig.getTimeBetweenEvictionRunsMillis();
|
||||
assertEquals(120000L, timeBetweenEvictionRunsMillis);
|
||||
|
||||
poolConfig.setSoftMinEvictableIdleTimeMillis(120000L);
|
||||
final long softMinEvictableIdleTimeMillis = poolConfig.getSoftMinEvictableIdleTimeMillis();
|
||||
assertEquals(120000L, softMinEvictableIdleTimeMillis);
|
||||
|
||||
poolConfig.setBlockWhenExhausted(true);
|
||||
final boolean whenExhaustedAction = poolConfig.isBlockWhenExhausted();
|
||||
assertEquals(GenericKeyedObjectPoolConfig.DEFAULT_BLOCK_WHEN_EXHAUSTED, whenExhaustedAction);
|
||||
|
||||
poolConfig.setEvictionPolicyClassName(GenericKeyedObjectPoolConfig.DEFAULT_EVICTION_POLICY_CLASS_NAME);
|
||||
final String evictionPolicyClassName = poolConfig.getEvictionPolicyClassName();
|
||||
assertEquals(GenericKeyedObjectPoolConfig.DEFAULT_EVICTION_POLICY_CLASS_NAME, evictionPolicyClassName);
|
||||
|
||||
poolConfig.setFairness(true);
|
||||
final boolean fairness = poolConfig.isFairness();
|
||||
assertEquals(true, fairness);
|
||||
|
||||
poolConfig.setJmxEnabled(true);
|
||||
final boolean jmxEnabled = poolConfig.isJmxEnabled();
|
||||
assertEquals(true, jmxEnabled);
|
||||
|
||||
poolConfig.setJmxNameBase("test");
|
||||
final String jmxBaseName = poolConfig.getJmxNameBase();
|
||||
assertEquals("test", jmxBaseName);
|
||||
|
||||
poolConfig.setJmxNamePrefix("pool");
|
||||
final String prefix = poolConfig.getJmxNamePrefix();
|
||||
assertEquals("pool", prefix);
|
||||
|
||||
poolConfig.setLifo(true);
|
||||
final boolean lifo = poolConfig.isLifo();
|
||||
assertEquals(true, lifo);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,237 @@
|
||||
/*
|
||||
* Copyright 2005-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.ldap.pool2.factory;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.dao.DataAccessResourceFailureException;
|
||||
import org.springframework.ldap.core.ContextSource;
|
||||
import org.springframework.ldap.pool2.validation.DirContextValidator;
|
||||
import org.springframework.ldap.pool2.AbstractPoolTestCase;
|
||||
|
||||
import javax.naming.directory.DirContext;
|
||||
import javax.naming.ldap.LdapContext;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* @author Eric Dalquist
|
||||
* @author Anindya Chatterjee
|
||||
*/
|
||||
public class PooledContextSourceTest extends AbstractPoolTestCase {
|
||||
|
||||
@Test
|
||||
public void testProperties() throws Exception {
|
||||
final PoolConfig poolConfig = new PoolConfig();
|
||||
poolConfig.setMaxIdlePerKey(500);
|
||||
poolConfig.setMinIdlePerKey(100);
|
||||
poolConfig.setMaxTotal(5000);
|
||||
poolConfig.setMaxTotalPerKey(5);
|
||||
poolConfig.setMaxWaitMillis(2000L);
|
||||
poolConfig.setMinEvictableIdleTimeMillis(60000L);
|
||||
poolConfig.setNumTestsPerEvictionRun(5);
|
||||
poolConfig.setTestOnBorrow(true);
|
||||
poolConfig.setTestOnReturn(true);
|
||||
poolConfig.setTestWhileIdle(true);
|
||||
poolConfig.setTestOnCreate(true);
|
||||
poolConfig.setTimeBetweenEvictionRunsMillis(120000L);
|
||||
poolConfig.setSoftMinEvictableIdleTimeMillis(120000L);
|
||||
poolConfig.setBlockWhenExhausted(true);
|
||||
poolConfig.setFairness(true);
|
||||
poolConfig.setJmxEnabled(true);
|
||||
poolConfig.setJmxNameBase("test");
|
||||
poolConfig.setJmxNamePrefix("pool");
|
||||
poolConfig.setLifo(true);
|
||||
|
||||
final PooledContextSource PooledContextSource = new PooledContextSource(poolConfig);
|
||||
|
||||
try {
|
||||
PooledContextSource.setContextSource(null);
|
||||
fail("PooledContextSource.setBaseName should have thrown an IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException iae) {
|
||||
// Expected
|
||||
}
|
||||
PooledContextSource.setContextSource(contextSourceMock);
|
||||
final ContextSource contextSource2 = PooledContextSource.getContextSource();
|
||||
assertEquals(contextSourceMock, contextSource2);
|
||||
|
||||
try {
|
||||
PooledContextSource.setDirContextValidator(null);
|
||||
fail("PooledContextSource.setDirContextValidator should have thrown an IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException iae) {
|
||||
// Expected
|
||||
}
|
||||
PooledContextSource.setDirContextValidator(dirContextValidatorMock);
|
||||
final DirContextValidator dirContextValidator2 = PooledContextSource.getDirContextValidator();
|
||||
assertEquals(dirContextValidatorMock, dirContextValidator2);
|
||||
|
||||
final int numActive = PooledContextSource.getNumActive();
|
||||
assertEquals(0, numActive);
|
||||
|
||||
final int numIdle = PooledContextSource.getNumIdle();
|
||||
assertEquals(0, numIdle);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetReadOnlyContextPool() throws Exception {
|
||||
DirContext secondDirContextMock = mock(DirContext.class);
|
||||
|
||||
when(contextSourceMock.getReadOnlyContext()).thenReturn(dirContextMock, secondDirContextMock);
|
||||
|
||||
final PooledContextSource PooledContextSource = new PooledContextSource(null);
|
||||
PooledContextSource.setContextSource(contextSourceMock);
|
||||
|
||||
//Get a context
|
||||
final DirContext readOnlyContext1 = PooledContextSource.getReadOnlyContext();
|
||||
assertEquals(readOnlyContext1, dirContextMock); //Order reversed because the 'wrapper' has the needed equals logic
|
||||
assertEquals(1, PooledContextSource.getNumActive());
|
||||
assertEquals(0, PooledContextSource.getNumIdle());
|
||||
|
||||
//Close the context
|
||||
readOnlyContext1.close();
|
||||
assertEquals(0, PooledContextSource.getNumActive());
|
||||
assertEquals(1, PooledContextSource.getNumIdle());
|
||||
|
||||
//Get the context again
|
||||
final DirContext readOnlyContext2 = PooledContextSource.getReadOnlyContext();
|
||||
assertEquals(readOnlyContext2, dirContextMock); //Order reversed because the 'wrapper' has the needed equals logic
|
||||
assertEquals(1, PooledContextSource.getNumActive());
|
||||
assertEquals(0, PooledContextSource.getNumIdle());
|
||||
|
||||
//Get a new context
|
||||
final DirContext readOnlyContext3 = PooledContextSource.getReadOnlyContext();
|
||||
assertEquals(readOnlyContext3, secondDirContextMock); //Order reversed because the 'wrapper' has the needed equals logic
|
||||
assertEquals(2, PooledContextSource.getNumActive());
|
||||
assertEquals(0, PooledContextSource.getNumIdle());
|
||||
|
||||
//Close context
|
||||
readOnlyContext2.close();
|
||||
assertEquals(1, PooledContextSource.getNumActive());
|
||||
assertEquals(1, PooledContextSource.getNumIdle());
|
||||
|
||||
//Close context
|
||||
readOnlyContext3.close();
|
||||
assertEquals(0, PooledContextSource.getNumActive());
|
||||
assertEquals(2, PooledContextSource.getNumIdle());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetReadWriteContextPool() throws Exception {
|
||||
DirContext secondDirContextMock = mock(DirContext.class);
|
||||
|
||||
when(contextSourceMock.getReadWriteContext()).thenReturn(dirContextMock, secondDirContextMock);
|
||||
|
||||
final PooledContextSource PooledContextSource = new PooledContextSource(null);
|
||||
PooledContextSource.setContextSource(contextSourceMock);
|
||||
|
||||
//Get a context
|
||||
final DirContext readOnlyContext1 = PooledContextSource.getReadWriteContext();
|
||||
assertEquals(readOnlyContext1, dirContextMock); //Order reversed because the 'wrapper' has the needed equals logic
|
||||
assertEquals(1, PooledContextSource.getNumActive());
|
||||
assertEquals(0, PooledContextSource.getNumIdle());
|
||||
|
||||
//Close the context
|
||||
readOnlyContext1.close();
|
||||
assertEquals(0, PooledContextSource.getNumActive());
|
||||
assertEquals(1, PooledContextSource.getNumIdle());
|
||||
|
||||
//Get the context again
|
||||
final DirContext readOnlyContext2 = PooledContextSource.getReadWriteContext();
|
||||
assertEquals(readOnlyContext2, dirContextMock); //Order reversed because the 'wrapper' has the needed equals logic
|
||||
assertEquals(1, PooledContextSource.getNumActive());
|
||||
assertEquals(0, PooledContextSource.getNumIdle());
|
||||
|
||||
//Get a new context
|
||||
final DirContext readOnlyContext3 = PooledContextSource.getReadWriteContext();
|
||||
assertEquals(readOnlyContext3, secondDirContextMock); //Order reversed because the 'wrapper' has the needed equals logic
|
||||
assertEquals(2, PooledContextSource.getNumActive());
|
||||
assertEquals(0, PooledContextSource.getNumIdle());
|
||||
|
||||
//Close context
|
||||
readOnlyContext2.close();
|
||||
assertEquals(1, PooledContextSource.getNumActive());
|
||||
assertEquals(1, PooledContextSource.getNumIdle());
|
||||
|
||||
//Close context
|
||||
readOnlyContext3.close();
|
||||
assertEquals(0, PooledContextSource.getNumActive());
|
||||
assertEquals(2, PooledContextSource.getNumIdle());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetContextException() throws Exception {
|
||||
when(contextSourceMock.getReadWriteContext())
|
||||
.thenThrow(new RuntimeException("Problem getting context"));
|
||||
|
||||
final PooledContextSource PooledContextSource = new PooledContextSource(null);
|
||||
PooledContextSource.setContextSource(contextSourceMock);
|
||||
|
||||
try {
|
||||
PooledContextSource.getReadWriteContext();
|
||||
fail("PooledContextSource.getReadWriteContext should have thrown DataAccessResourceFailureException");
|
||||
}
|
||||
catch (DataAccessResourceFailureException darfe) {
|
||||
// Expected
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetReadOnlyLdapContext() throws Exception {
|
||||
LdapContext secondLdapContextMock = mock(LdapContext.class);
|
||||
|
||||
when(contextSourceMock.getReadOnlyContext()).thenReturn(ldapContextMock, secondLdapContextMock);
|
||||
|
||||
final PooledContextSource pooledContextSource = new PooledContextSource(null);
|
||||
pooledContextSource.setContextSource(contextSourceMock);
|
||||
|
||||
//Get a context
|
||||
final DirContext readOnlyContext1 = pooledContextSource.getReadOnlyContext();
|
||||
assertEquals(readOnlyContext1, ldapContextMock); //Order reversed because the 'wrapper' has the needed equals logic
|
||||
assertEquals(1, pooledContextSource.getNumActive());
|
||||
assertEquals(0, pooledContextSource.getNumIdle());
|
||||
|
||||
//Close the context
|
||||
readOnlyContext1.close();
|
||||
assertEquals(0, pooledContextSource.getNumActive());
|
||||
assertEquals(1, pooledContextSource.getNumIdle());
|
||||
|
||||
//Get the context again
|
||||
final DirContext readOnlyContext2 = pooledContextSource.getReadOnlyContext();
|
||||
assertEquals(readOnlyContext2, ldapContextMock); //Order reversed because the 'wrapper' has the needed equals logic
|
||||
assertEquals(1, pooledContextSource.getNumActive());
|
||||
assertEquals(0, pooledContextSource.getNumIdle());
|
||||
|
||||
//Get a new context
|
||||
final DirContext readOnlyContext3 = pooledContextSource.getReadOnlyContext();
|
||||
assertEquals(readOnlyContext3, secondLdapContextMock); //Order reversed because the 'wrapper' has the needed equals logic
|
||||
assertEquals(2, pooledContextSource.getNumActive());
|
||||
assertEquals(0, pooledContextSource.getNumIdle());
|
||||
|
||||
//Close context
|
||||
readOnlyContext2.close();
|
||||
assertEquals(1, pooledContextSource.getNumActive());
|
||||
assertEquals(1, pooledContextSource.getNumIdle());
|
||||
|
||||
//Close context
|
||||
readOnlyContext3.close();
|
||||
assertEquals(0, pooledContextSource.getNumActive());
|
||||
assertEquals(2, pooledContextSource.getNumIdle());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ldap="http://www.springframework.org/schema/ldap"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/ldap http://www.springframework.org/schema/ldap/spring-ldap.xsd">
|
||||
|
||||
<ldap:context-source password="apassword" url="ldap://localhost:389" username="uid=admin">
|
||||
<ldap:pooling2
|
||||
max-total-per-key="10"
|
||||
max-idle-per-key="20"
|
||||
max-total="12"
|
||||
max-wait="13"
|
||||
min-idle-per-key="14"
|
||||
block-when-exhausted="true"
|
||||
eviction-policy-class="org.springframework.ldap.pool2.DummyEvictionPolicy"
|
||||
fairness="true"
|
||||
jmx-enable="true"
|
||||
jmx-name-base="org.springframework.ldap.pool2:type=ldap-pool,name="
|
||||
jmx-name-prefix="test-pool"
|
||||
lifo="false" />
|
||||
</ldap:context-source>
|
||||
|
||||
<ldap:ldap-template />
|
||||
</beans>
|
||||
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ldap="http://www.springframework.org/schema/ldap"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/ldap http://www.springframework.org/schema/ldap/spring-ldap.xsd">
|
||||
|
||||
<ldap:context-source password="apassword" url="ldap://localhost:389" username="uid=admin">
|
||||
<ldap:pooling2
|
||||
test-on-borrow="true"
|
||||
test-on-return="true"
|
||||
test-while-idle="true"
|
||||
test-on-create="true"
|
||||
min-evictable-time-millis="123"
|
||||
eviction-run-interval-millis="321"
|
||||
tests-per-eviction-run="22"
|
||||
soft-min-evictable-idle-time-millis="12"
|
||||
validation-query-base="ou=test"
|
||||
validation-query-filter="objectclass=person"
|
||||
validation-query-search-controls-ref="searchControls"
|
||||
non-transient-exceptions="javax.naming.CannotProceedException,javax.naming.CommunicationException" />
|
||||
</ldap:context-source>
|
||||
|
||||
<bean class="javax.naming.directory.SearchControls" id="searchControls" />
|
||||
|
||||
<ldap:ldap-template />
|
||||
</beans>
|
||||
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ldap="http://www.springframework.org/schema/ldap"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/ldap http://www.springframework.org/schema/ldap/spring-ldap.xsd">
|
||||
|
||||
<!--
|
||||
The below is invalid, since native pooling is not supported together with Spring LDAP pooling.
|
||||
-->
|
||||
<ldap:context-source
|
||||
password="apassword" url="ldap://localhost:389" username="uid=admin"
|
||||
native-pooling="true">
|
||||
<ldap:pooling2 />
|
||||
</ldap:context-source>
|
||||
|
||||
<ldap:ldap-template />
|
||||
</beans>
|
||||
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ldap="http://www.springframework.org/schema/ldap"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/ldap http://www.springframework.org/schema/ldap/spring-ldap.xsd">
|
||||
|
||||
<!-- Invalid pool configuration. Only one of them can be used at the same time. -->
|
||||
<ldap:context-source
|
||||
password="apassword" url="ldap://localhost:389" username="uid=admin">
|
||||
<ldap:pooling />
|
||||
<ldap:pooling2 />
|
||||
</ldap:context-source>
|
||||
|
||||
<ldap:ldap-template />
|
||||
</beans>
|
||||
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ldap="http://www.springframework.org/schema/ldap"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/ldap http://www.springframework.org/schema/ldap/spring-ldap.xsd">
|
||||
|
||||
<ldap:context-source password="apassword" url="ldap://localhost:389" username="uid=admin">
|
||||
<ldap:pooling2 />
|
||||
</ldap:context-source>
|
||||
|
||||
<ldap:ldap-template />
|
||||
</beans>
|
||||
@@ -20,6 +20,7 @@ ext.mockitoVersion = '1.10.19'
|
||||
ext.queryDslVersion = '3.6.3'
|
||||
ext.slf4jVersion = '1.7.12'
|
||||
ext.powerMockVersion = '1.6.2'
|
||||
ext.commonsPool2Version = '2.4.2'
|
||||
|
||||
ext.powerMockDependencies = [
|
||||
"org.powermock:powermock-core:$powerMockVersion",
|
||||
|
||||
Reference in New Issue
Block a user