diff --git a/mvn-build/core/changelog.txt b/mvn-build/core/changelog.txt
index 005a464a..63b8db4c 100644
--- a/mvn-build/core/changelog.txt
+++ b/mvn-build/core/changelog.txt
@@ -13,6 +13,9 @@ http://www.ietf.org/rfc/rfc2696.txt
Changes in version 1.2.2 (XXX 2008)
-------------------------------------------
+* Made changes required for paged results to work when using Spring LDAP
+ connection pool with a single connection. (LDAP-114)
+
* Upgraded Acegi to 1.0.6.
* Upgraded commons-lang to 2.3.
diff --git a/mvn-build/core/src/main/java/org/springframework/ldap/control/AbstractRequestControlDirContextProcessor.java b/mvn-build/core/src/main/java/org/springframework/ldap/control/AbstractRequestControlDirContextProcessor.java
index 5ecdee02..4f5a05b4 100644
--- a/mvn-build/core/src/main/java/org/springframework/ldap/control/AbstractRequestControlDirContextProcessor.java
+++ b/mvn-build/core/src/main/java/org/springframework/ldap/control/AbstractRequestControlDirContextProcessor.java
@@ -34,10 +34,35 @@ import org.springframework.ldap.core.DirContextProcessor;
* @author Mattias Arthursson
* @author Ulrik Sandberg
*/
-public abstract class AbstractRequestControlDirContextProcessor implements
- DirContextProcessor {
- protected Log log = LogFactory
- .getLog(AbstractRequestControlDirContextProcessor.class);
+public abstract class AbstractRequestControlDirContextProcessor implements DirContextProcessor {
+ protected Log log = LogFactory.getLog(AbstractRequestControlDirContextProcessor.class);
+
+ private boolean replaceSameControlEnabled = true;
+
+ /**
+ * If there already exists a request control of the same class as the one
+ * created by {@link #createRequestControl()} in the context, the new
+ * control can either replace the existing one (default behavior) or be
+ * added.
+ *
+ * @return true if an already existing control will be replaced
+ */
+ public boolean isReplaceSameControlEnabled() {
+ return replaceSameControlEnabled;
+ }
+
+ /**
+ * If there already exists a request control of the same class as the one
+ * created by {@link #createRequestControl()} in the context, the new
+ * control can either replace the existing one (default behavior) or be
+ * added.
+ *
+ * @param replaceSameControlEnabled true if an already
+ * existing control should be replaced
+ */
+ public void setReplaceSameControlEnabled(boolean replaceSameControlEnabled) {
+ this.replaceSameControlEnabled = replaceSameControlEnabled;
+ }
/**
* Get the existing RequestControls from the LdapContext, call
@@ -50,20 +75,19 @@ public abstract class AbstractRequestControlDirContextProcessor implements
* postProcess uses DirContext, since it also works for LDAP
* v2. This is the reason that DirContext has to be cast to a LdapContext.
*
- * @param ctx
- * an LdapContext instance.
+ * @param ctx an LdapContext instance.
* @throws NamingException
- * @throws IllegalArgumentException
- * if the supplied DirContext is not an LdapContext.
+ * @throws IllegalArgumentException if the supplied DirContext is not an
+ * LdapContext.
*/
public void preProcess(DirContext ctx) throws NamingException {
LdapContext ldapContext;
if (ctx instanceof LdapContext) {
ldapContext = (LdapContext) ctx;
- } else {
- throw new IllegalArgumentException(
- "Request Control operations require LDAPv3 - "
- + "Context must be of type LdapContext");
+ }
+ else {
+ throw new IllegalArgumentException("Request Control operations require LDAPv3 - "
+ + "Context must be of type LdapContext");
}
Control[] requestControls = ldapContext.getRequestControls();
@@ -74,6 +98,12 @@ public abstract class AbstractRequestControlDirContextProcessor implements
Control[] newControls = new Control[requestControls.length + 1];
for (int i = 0; i < requestControls.length; i++) {
+ if (replaceSameControlEnabled && requestControls[i].getClass() == newControl.getClass()) {
+ log.debug("Replacing already existing control in context: " + newControl);
+ requestControls[i] = newControl;
+ ldapContext.setRequestControls(requestControls);
+ return;
+ }
newControls[i] = requestControls[i];
}
@@ -89,5 +119,4 @@ public abstract class AbstractRequestControlDirContextProcessor implements
* @return the new instance.
*/
public abstract Control createRequestControl();
-
}
diff --git a/mvn-build/core/src/main/java/org/springframework/ldap/pool/factory/PoolingContextSource.java b/mvn-build/core/src/main/java/org/springframework/ldap/pool/factory/PoolingContextSource.java
index 1e5b1f87..fb692584 100644
--- a/mvn-build/core/src/main/java/org/springframework/ldap/pool/factory/PoolingContextSource.java
+++ b/mvn-build/core/src/main/java/org/springframework/ldap/pool/factory/PoolingContextSource.java
@@ -146,7 +146,7 @@ public class PoolingContextSource implements ContextSource, DisposableBean {
*/
protected final Log logger = LogFactory.getLog(this.getClass());
- private final GenericKeyedObjectPool keyedObjectPool;
+ protected final GenericKeyedObjectPool keyedObjectPool;
private final DirContextPoolableObjectFactory dirContextPoolableObjectFactory;
/**
diff --git a/mvn-build/core/src/test/java/org/springframework/ldap/control/RequestControlDirContextProcessorTest.java b/mvn-build/core/src/test/java/org/springframework/ldap/control/RequestControlDirContextProcessorTest.java
index edaa3b48..335765e1 100644
--- a/mvn-build/core/src/test/java/org/springframework/ldap/control/RequestControlDirContextProcessorTest.java
+++ b/mvn-build/core/src/test/java/org/springframework/ldap/control/RequestControlDirContextProcessorTest.java
@@ -23,7 +23,8 @@ import javax.naming.ldap.LdapContext;
import junit.framework.TestCase;
import org.easymock.MockControl;
-import org.springframework.ldap.control.AbstractRequestControlDirContextProcessor;
+
+import com.sun.jndi.ldap.ctl.SortControl;
public class RequestControlDirContextProcessorTest extends TestCase {
@@ -106,12 +107,12 @@ public class RequestControlDirContextProcessorTest extends TestCase {
dirContextControl.verify();
}
- public void testPreProcess() throws NamingException {
+ public void testPreProcessWithExistingControlOfDifferentClassShouldAdd() throws Exception {
ldapContextControl.setDefaultMatcher(MockControl.ARRAY_MATCHER);
- ldapContextControl.expectAndDefaultReturn(ldapContextMock
- .getRequestControls(), new Control[] { requestControl2Mock });
- ldapContextMock.setRequestControls(new Control[] { requestControl2Mock,
- requestControlMock });
+ SortControl existingControl = new SortControl(new String[] { "cn" }, true);
+ ldapContextControl.expectAndDefaultReturn(ldapContextMock.getRequestControls(),
+ new Control[] { existingControl });
+ ldapContextMock.setRequestControls(new Control[] { existingControl, requestControlMock });
replay();
@@ -120,12 +121,11 @@ public class RequestControlDirContextProcessorTest extends TestCase {
verify();
}
- public void testPreProcess_NoExistingControls() throws NamingException {
+ public void testPreProcessWithExistingControlOfSameClassShouldReplace() throws Exception {
ldapContextControl.setDefaultMatcher(MockControl.ARRAY_MATCHER);
- ldapContextControl.expectAndDefaultReturn(ldapContextMock
- .getRequestControls(), new Control[0]);
- ldapContextMock
- .setRequestControls(new Control[] { requestControlMock });
+ ldapContextControl.expectAndDefaultReturn(ldapContextMock.getRequestControls(),
+ new Control[] { requestControl2Mock });
+ ldapContextMock.setRequestControls(new Control[] { requestControlMock });
replay();
@@ -134,12 +134,24 @@ public class RequestControlDirContextProcessorTest extends TestCase {
verify();
}
- public void testPreProcess_NullControls() throws NamingException {
+ public void testPreProcessWithExistingControlOfSameClassAndPropertyFalseShouldAdd() throws Exception {
ldapContextControl.setDefaultMatcher(MockControl.ARRAY_MATCHER);
- ldapContextControl.expectAndDefaultReturn(ldapContextMock
- .getRequestControls(), null);
- ldapContextMock
- .setRequestControls(new Control[] { requestControlMock });
+ ldapContextControl.expectAndDefaultReturn(ldapContextMock.getRequestControls(),
+ new Control[] { requestControl2Mock });
+ ldapContextMock.setRequestControls(new Control[] { requestControl2Mock, requestControlMock });
+
+ replay();
+
+ tested.setReplaceSameControlEnabled(false);
+ tested.preProcess(ldapContextMock);
+
+ verify();
+ }
+
+ public void testPreProcessWithNoExistingControlsShouldAdd() throws NamingException {
+ ldapContextControl.setDefaultMatcher(MockControl.ARRAY_MATCHER);
+ ldapContextControl.expectAndDefaultReturn(ldapContextMock.getRequestControls(), new Control[0]);
+ ldapContextMock.setRequestControls(new Control[] { requestControlMock });
replay();
@@ -148,11 +160,24 @@ public class RequestControlDirContextProcessorTest extends TestCase {
verify();
}
- public void testPreProcess_NotLdapContext() throws Exception {
+ public void testPreProcessWithNullControlsShouldAdd() throws NamingException {
+ ldapContextControl.setDefaultMatcher(MockControl.ARRAY_MATCHER);
+ ldapContextControl.expectAndDefaultReturn(ldapContextMock.getRequestControls(), null);
+ ldapContextMock.setRequestControls(new Control[] { requestControlMock });
+
+ replay();
+
+ tested.preProcess(ldapContextMock);
+
+ verify();
+ }
+
+ public void testPreProcessWhenNotLdapContextShouldFail() throws Exception {
try {
tested.preProcess(dirContextMock);
fail("IllegalArgumentException expected");
- } catch (IllegalArgumentException expected) {
+ }
+ catch (IllegalArgumentException expected) {
assertTrue(true);
}
}