diff --git a/core/src/main/java/org/springframework/ldap/core/IncrementalAttributesMapper.java b/core/src/main/java/org/springframework/ldap/core/IncrementalAttributesMapper.java
new file mode 100644
index 00000000..40bdf13a
--- /dev/null
+++ b/core/src/main/java/org/springframework/ldap/core/IncrementalAttributesMapper.java
@@ -0,0 +1,76 @@
+/*
+ * 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.core;
+
+import javax.naming.NamingException;
+import javax.naming.directory.Attributes;
+import java.util.List;
+
+/**
+ * Utility that helps with reading all attribute values from Active Directory using Incremental Retrieval of
+ * Multi-valued Properties.
+ *
+ * @author Mattias Hellborg Arthursson
+ * @since 1.3.2
+ * @see Incremental Retrieval of Multi-valued Properties
+ * @see {@link org.springframework.ldap.core.support.DefaultIncrementalAttributesMapper}
+ */
+public interface IncrementalAttributesMapper extends AttributesMapper {
+ /**
+ * Get all of the collected values for the specified attribute.
+ *
+ * @param attributeName the attribute to get values for.
+ * @return the collected values for the specified attribute. Will be null
+ * if the requested attribute has not been returned by the server (attribute did not exist).
+ */
+ List getValues(String attributeName);
+
+ /**
+ * Get all collected values for all managed attributes as an Attributes instance.
+ *
+ * @return an Attributes instance populated with all collected values.
+ */
+ Attributes getCollectedAttributes();
+
+ /**
+ * Check whether another query iteration is required to get all values for all attributes.
+ *
+ * @return true if there are more values for at least one of the managed attributes,
+ * false otherwise.
+ */
+ boolean hasMore();
+
+ /**
+ * Get properly formatted attributes for use in the next query. The attribute names included will
+ * include Range specifiers as needed and only the attributes that have not been retrieved in full
+ * will be included.
+ *
+ * @return an array of Strings to be used as input to e.g.
+ * {@link org.springframework.ldap.core.LdapTemplate#lookup(javax.naming.Name, String[], org.springframework.ldap.core.AttributesMapper)}
+ * in the next iteration.
+ */
+ String[] getAttributesForLookup();
+
+ /**
+ * Goes through all of the attributes to record their values and figure out whether a new query iteration
+ * is needed to get more values.
+ *
+ * @param attributes attributes from a SearchResult.
+ * @return this instance.
+ * @throws javax.naming.NamingException
+ */
+ Object mapFromAttributes(Attributes attributes) throws NamingException;
+}
diff --git a/core/src/main/java/org/springframework/ldap/core/support/DefaultIncrementalAttributesMapper.java b/core/src/main/java/org/springframework/ldap/core/support/DefaultIncrementalAttributesMapper.java
new file mode 100644
index 00000000..f99ba9e7
--- /dev/null
+++ b/core/src/main/java/org/springframework/ldap/core/support/DefaultIncrementalAttributesMapper.java
@@ -0,0 +1,434 @@
+/*
+ * 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.core.support;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.ldap.core.AttributesMapper;
+import org.springframework.ldap.core.DistinguishedName;
+import org.springframework.ldap.core.IncrementalAttributesMapper;
+import org.springframework.ldap.core.LdapOperations;
+
+import javax.naming.Name;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.directory.Attribute;
+import javax.naming.directory.Attributes;
+import javax.naming.directory.BasicAttribute;
+import javax.naming.directory.BasicAttributes;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Utility class that helps with reading all attribute values from Active Directory using Incremental Retrieval of
+ * Multi-valued Properties.
+ *
Example usage of this attribute mapper: + *
+ * List values = DefaultIncrementalAttributeMapper.lookupAttributeValues(ldapTemplate, theDn, "oneAttribute");
+ * Attributes attrs = DefaultIncrementalAttributeMapper.lookupAttributeValues(ldapTemplate, theDn, new Object[]{"oneAttribute", "anotherAttribute"});
+ *
+ * For greater control, e.g. explicitly specifying the requested page size, create and use an instance yourself:
+ *
+ *
+ * IncrementalAttributesMapper incrementalAttributeMapper = new DefaultIncrementalAttributeMapper(10, "someAttribute");
+ * while (incrementalAttributeMapper.hasMore()) {
+ * ldap.lookup(entrDn, incrementalAttributeMapper.getAttributesForLookup(), incrementalAttributeMapper);
+ * }
+ *
+ * List values = incrementalAttributeMapper.getValues("someAttribute");
+ *
+ *
+ * + * NOTE: Instances of this class are highly stateful and must not be reused or shared between threads in any way. + *
+ *+ * NOTE: Instances of this class can only be used with lookups. No support is given for searches. + *
+ * + * @author Marius Scurtescu + * @author Mattias Hellborg Arthursson + * @see Incremental Retrieval of Multi-valued Properties + * @see #lookupAttributes(org.springframework.ldap.core.LdapOperations, javax.naming.Name, String[]) + * @see #lookupAttributeValues(org.springframework.ldap.core.LdapOperations, javax.naming.Name, String) + * @since 1.3.2 + */ +public class DefaultIncrementalAttributesMapper implements AttributesMapper, IncrementalAttributesMapper { + private final static Log log = LogFactory.getLog(DefaultIncrementalAttributesMapper.class); + + private Map stateMap = new LinkedHashMap(); + private Set rangedAttributesInNextIteration = new LinkedHashSet(); + + /** + * This guy will be used when an unmapped attribute is encountered. This really should never happen, + * but this saves us a number of null checks. + */ + private final static IncrementalAttributeState NOT_FOUND_ATTRIBUTE_STATE = new IncrementalAttributeState() { + public String getRequestedAttributeName() { + throw new UnsupportedOperationException("This method should never be called"); + } + + public boolean hasMore() { + return false; + } + + public void calculateNextRange(RangeOption responseRange) { + // Nothing to do here + } + + public String getAttributeNameForQuery() { + throw new UnsupportedOperationException("This method should never be called"); + } + + public void processValues(Attributes attributes, String attributeName) throws NamingException { + // Nothing to do here + } + + public List getValues() { + return null; + } + }; + + /** + * Create an instance for the requested attribute. + * + * @param attributeName the name of the attribute that this instance handles. + * This is the attribute name that will be requested, and whose + * values are managed. + */ + public DefaultIncrementalAttributesMapper(String attributeName) { + this(RangeOption.TERMINAL_END_OF_RANGE, attributeName); + } + + /** + * Create an instance for the requested attributes. + * + * @param attributeNames the name of the attributes that this instance handles. + * These are the attribute names that will be requested, and whose + * values are managed. + */ + public DefaultIncrementalAttributesMapper(String[] attributeNames) { + this(RangeOption.TERMINAL_END_OF_RANGE, attributeNames); + } + + /** + * Create an instance for the requested attribute with a specific page size. + * + * @param pageSize the requested page size that will be included in range query attribute names. + * @param attributeName the name of the attribute that this instance handles. + * This is the attribute name that will be requested, and whose + * values are managed. + */ + public DefaultIncrementalAttributesMapper(int pageSize, String attributeName) { + this(pageSize, new String[]{attributeName}); + } + + /** + * Create an instance for the requested attributes with a specific page size. + * + * @param pageSize the requested page size that will be included in range query attribute names. + * @param attributeNames the name of the attributes that this instance handles. + * These are the attribute names that will be requested, and whose + * values are managed. + */ + public DefaultIncrementalAttributesMapper(int pageSize, String[] attributeNames) { + for (int i = 0; i < attributeNames.length; i++) { + String attributeName = attributeNames[i]; + this.stateMap.put(attributeName, new DefaultIncrementalAttributeState(attributeName, pageSize)); + this.rangedAttributesInNextIteration.add(attributeName); + } + } + + public final Object mapFromAttributes(Attributes attributes) throws NamingException { + if (!hasMore()) { + throw new IllegalStateException("No more attributes!"); + } + + // Reset the affected attributes. + rangedAttributesInNextIteration = new HashSet(); + + NamingEnumeration attributeNameEnum = attributes.getIDs(); + while (attributeNameEnum.hasMore()) { + String attributeName = (String) attributeNameEnum.next(); + + String[] attributeNameSplit = attributeName.split(";"); + IncrementalAttributeState state = getState(attributeNameSplit[0]); + if (attributeNameSplit.length == 1) { + // No range specification for this attribute + state.processValues(attributes, attributeName); + } else { + for (int i = 0; i < attributeNameSplit.length; i++) { + String option = attributeNameSplit[i]; + + RangeOption responseRange = RangeOption.parse(option); + + if (responseRange != null) { + state.processValues(attributes, attributeName); + state.calculateNextRange(responseRange); + if (state.hasMore()) { + rangedAttributesInNextIteration.add(state.getRequestedAttributeName()); + } + } + } + } + } + + return this; + } + + private IncrementalAttributeState getState(String attributeName) { + Object mappedState = stateMap.get(attributeName); + if (mappedState == null) { + log.warn("Attribute '" + attributeName + "' is not handled by this instance"); + mappedState = NOT_FOUND_ATTRIBUTE_STATE; + } + + return (IncrementalAttributeState) mappedState; + } + + public final List getValues(String attributeName) { + return getState(attributeName).getValues(); + } + + public Attributes getCollectedAttributes() { + BasicAttributes attributes = new BasicAttributes(); + + Set attributeNames = stateMap.keySet(); + for (Iterator iterator = attributeNames.iterator(); iterator.hasNext(); ) { + String attributeName = (String) iterator.next(); + + BasicAttribute oneAttribute = new BasicAttribute(attributeName); + List values = getValues(attributeName); + if (values != null) { + for (Iterator valueIterator = values.iterator(); valueIterator.hasNext(); ) { + Object oneValue = valueIterator.next(); + oneAttribute.add(oneValue); + } + } + + attributes.put(oneAttribute); + } + + return attributes; + } + + public final boolean hasMore() { + return rangedAttributesInNextIteration.size() > 0; + } + + public final String[] getAttributesForLookup() { + String[] result = new String[rangedAttributesInNextIteration.size()]; + int index = 0; + for (Iterator iterator = rangedAttributesInNextIteration.iterator(); iterator.hasNext(); ) { + String next = (String) iterator.next(); + IncrementalAttributeState state = (IncrementalAttributeState) stateMap.get(next); + result[index++] = state.getAttributeNameForQuery(); + } + + return result; + } + + /** + * Lookup all values for the specified attribute, looping through the results incrementally if necessary. + * + * @param ldapOperations The instance to use for performing the actual lookup. + * @param dn The distinguished name of the object to find. + * @param attribute name of the attribute to request. + * @return an Attributes instance, populated with all found values for the requested attribute. + * Nevernull, though the actual attribute may not be set if it was not
+ * set on the requested object.
+ */
+ public static Attributes lookupAttributes(LdapOperations ldapOperations, String dn, String attribute) {
+ return lookupAttributes(ldapOperations, new DistinguishedName(dn), attribute);
+ }
+
+ /**
+ * Lookup all values for the specified attributes, looping through the results incrementally if necessary.
+ *
+ * @param ldapOperations The instance to use for performing the actual lookup.
+ * @param dn The distinguished name of the object to find.
+ * @param attributes names of the attributes to request.
+ * @return an Attributes instance, populated with all found values for the requested attributes.
+ * Never null, though the actual attributes may not be set if they was not
+ * set on the requested object.
+ */
+ public static Attributes lookupAttributes(LdapOperations ldapOperations, String dn, String[] attributes) {
+ return lookupAttributes(ldapOperations, new DistinguishedName(dn), attributes);
+ }
+
+ /**
+ * Lookup all values for the specified attribute, looping through the results incrementally if necessary.
+ *
+ * @param ldapOperations The instance to use for performing the actual lookup.
+ * @param dn The distinguished name of the object to find.
+ * @param attribute name of the attribute to request.
+ * @return an Attributes instance, populated with all found values for the requested attribute.
+ * Never null, though the actual attribute may not be set if it was not
+ * set on the requested object.
+ */
+ public static Attributes lookupAttributes(LdapOperations ldapOperations, Name dn, String attribute) {
+ return lookupAttributes(ldapOperations, dn, new String[]{attribute});
+ }
+
+ /**
+ * Lookup all values for the specified attributes, looping through the results incrementally if necessary.
+ *
+ * @param ldapOperations The instance to use for performing the actual lookup.
+ * @param dn The distinguished name of the object to find.
+ * @param attributes names of the attributes to request.
+ * @return an Attributes instance, populated with all found values for the requested attributes.
+ * Never null, though the actual attributes may not be set if they was not
+ * set on the requested object.
+ */
+ public static Attributes lookupAttributes(LdapOperations ldapOperations, Name dn, String[] attributes) {
+ return loopForAllAttributeValues(ldapOperations, dn, attributes).getCollectedAttributes();
+ }
+
+ /**
+ * Lookup all values for the specified attribute, looping through the results incrementally if necessary.
+ *
+ * @param ldapOperations The instance to use for performing the actual lookup.
+ * @param dn The distinguished name of the object to find.
+ * @param attribute name of the attribute to request.
+ * @return a list with all attribute values found for the requested attribute.
+ * Never null, an empty list indicates that the attribute was not set or empty.
+ */
+ public static List lookupAttributeValues(LdapOperations ldapOperations, String dn, String attribute) {
+ return lookupAttributeValues(ldapOperations, new DistinguishedName(dn), attribute);
+ }
+
+ /**
+ * Lookup all values for the specified attribute, looping through the results incrementally if necessary.
+ *
+ * @param ldapOperations The instance to use for performing the actual lookup.
+ * @param dn The distinguished name of the object to find.
+ * @param attribute name of the attribute to request.
+ * @return a list with all attribute values found for the requested attribute.
+ * Never null, an empty list indicates that the attribute was not set or empty.
+ */
+ public static List lookupAttributeValues(LdapOperations ldapOperations, Name dn, String attribute) {
+ List values = loopForAllAttributeValues(ldapOperations, dn, new String[]{attribute}).getValues(attribute);
+ if(values == null) {
+ values = Collections.emptyList();
+ }
+
+ return values;
+ }
+
+ private static DefaultIncrementalAttributesMapper loopForAllAttributeValues(LdapOperations ldapOperations, Name dn, String[] attributes) {
+ DefaultIncrementalAttributesMapper mapper = new DefaultIncrementalAttributesMapper(attributes);
+ while (mapper.hasMore()) {
+ ldapOperations.lookup(dn, mapper.getAttributesForLookup(), mapper);
+ }
+ return mapper;
+ }
+
+ /**
+ * This class keeps track of the state of an individual attribute in the process of collecting
+ * multi-value attributes using ranges. Holds the values collected thus far, the next applicable range,
+ * and the actual (requested) attribute name.
+ */
+ private final static class DefaultIncrementalAttributeState implements IncrementalAttributeState {
+ private final String actualAttributeName;
+ private List values = null;
+ private final int pageSize;
+ boolean more = true;
+
+ private RangeOption requestRange;
+
+ private DefaultIncrementalAttributeState(String actualAttributeName, int pageSize) {
+ this.actualAttributeName = actualAttributeName;
+ this.pageSize = pageSize;
+ this.requestRange = new RangeOption(0, pageSize);
+ }
+
+ public boolean hasMore() {
+ return more;
+ }
+
+ public String getRequestedAttributeName() {
+ return actualAttributeName;
+ }
+
+ public void calculateNextRange(RangeOption responseRange) {
+ more = requestRange.compareTo(responseRange) > 0;
+
+ if (more) {
+ requestRange = responseRange.nextRange(pageSize);
+ }
+ }
+
+ public String getAttributeNameForQuery() {
+ StringBuilder attributeBuilder = new StringBuilder(actualAttributeName);
+
+ if (!(requestRange.isFullRange())) {
+ attributeBuilder.append(';');
+ requestRange.appendTo(attributeBuilder);
+ }
+
+ return attributeBuilder.toString();
+ }
+
+ public void processValues(Attributes attributes, String attributeName) throws NamingException {
+ Attribute attribute = attributes.get(attributeName);
+ NamingEnumeration valueEnum = attribute.getAll();
+
+ initValuesIfApplicable();
+ while (valueEnum.hasMore()) {
+ values.add(valueEnum.next());
+ }
+ }
+
+ private void initValuesIfApplicable() {
+ if (values == null) {
+ values = new LinkedList();
+ }
+ }
+
+ public List getValues() {
+ if (values != null) {
+ return new ArrayList(values);
+ } else {
+ return null;
+ }
+ }
+ }
+
+ /**
+ * @author Mattias Hellborg Arthursson
+ */
+ private static interface IncrementalAttributeState {
+ boolean hasMore();
+
+ void calculateNextRange(RangeOption responseRange);
+
+ String getAttributeNameForQuery();
+
+ String getRequestedAttributeName();
+
+ void processValues(Attributes attributes, String attributeName) throws NamingException;
+
+ List getValues();
+ }
+}
diff --git a/core/src/main/java/org/springframework/ldap/support/ad/RangeOption.java b/core/src/main/java/org/springframework/ldap/core/support/RangeOption.java
similarity index 95%
rename from core/src/main/java/org/springframework/ldap/support/ad/RangeOption.java
rename to core/src/main/java/org/springframework/ldap/core/support/RangeOption.java
index a08238e3..d7800f5d 100644
--- a/core/src/main/java/org/springframework/ldap/support/ad/RangeOption.java
+++ b/core/src/main/java/org/springframework/ldap/core/support/RangeOption.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.springframework.ldap.support.ad;
+package org.springframework.ldap.core.support;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
@@ -24,10 +24,10 @@ import java.util.regex.Matcher;
*
* @author Marius Scurtescu
*
- * @see IncrementalAttributeMapper
+ * @see DefaultIncrementalAttributesMapper
* @since 1.3.2
*/
-public class RangeOption implements Comparable {
+class RangeOption implements Comparable {
public static final int TERMINAL_END_OF_RANGE = -1;
public static final int TERMINAL_MISSING = -2;
@@ -79,13 +79,12 @@ public class RangeOption implements Comparable {
public String toString() {
StringBuilder rangeBuilder = new StringBuilder();
-
- toString(rangeBuilder);
+ appendTo(rangeBuilder);
return rangeBuilder.toString();
}
- public void toString(StringBuilder rangeBuilder) {
+ public void appendTo(StringBuilder rangeBuilder) {
rangeBuilder.append("Range=").append(initial);
if (!isTerminalMissing()) {
diff --git a/core/src/main/java/org/springframework/ldap/core/support/package.html b/core/src/main/java/org/springframework/ldap/core/support/package.html
index 30162db2..48f06935 100644
--- a/core/src/main/java/org/springframework/ldap/core/support/package.html
+++ b/core/src/main/java/org/springframework/ldap/core/support/package.html
@@ -1,7 +1,7 @@
-Support classes the core Spring LDAP package.
+Support classes for the core Spring LDAP package.
diff --git a/core/src/main/java/org/springframework/ldap/support/ad/AttributeValueProcessor.java b/core/src/main/java/org/springframework/ldap/support/ad/AttributeValueProcessor.java
deleted file mode 100644
index b5e25618..00000000
--- a/core/src/main/java/org/springframework/ldap/support/ad/AttributeValueProcessor.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * 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.support.ad;
-
-/**
- * @since 1.3.2
- * @author Marius Scurtescu
- */
-public interface AttributeValueProcessor {
- public void process(Object value);
-}
diff --git a/core/src/main/java/org/springframework/ldap/support/ad/IncrementalAttributeMapper.java b/core/src/main/java/org/springframework/ldap/support/ad/IncrementalAttributeMapper.java
deleted file mode 100644
index a80fd060..00000000
--- a/core/src/main/java/org/springframework/ldap/support/ad/IncrementalAttributeMapper.java
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * 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.support.ad;
-
-import org.springframework.ldap.core.AttributesMapper;
-
-import javax.naming.directory.Attributes;
-import javax.naming.directory.Attribute;
-import javax.naming.NamingException;
-import javax.naming.NamingEnumeration;
-
-/**
- * Utility class that helps with reading all attribute values from Active Directory using Incremental Retrieval of
- * Multi-valued Properties.
- *
- * Example usage of this attribute mapper: - *
- * public void retrieveAttributeIncrementally(LdapTemplate ldap, LdapName entrDn, String attributeName, AttributeValueProcessor valueProcessor)
- * {
- * IncrementalAttributeMapper incrementalAttributeMapper = new IncrementalAttributeMapper(attributeName, valueProcessor);
- *
- * while (incrementalAttributeMapper.hasMore())
- * {
- * ldap.lookup(entrDn, incrementalAttributeMapper.getAttributesArray(), incrementalAttributeMapper);
- * }
- * }
- *
- *
- * @author Marius Scurtescu
- * @see Incremental Retrieval of Multi-valued Properties
- * @since 1.3.2
- */
-public class IncrementalAttributeMapper implements AttributesMapper {
- private final String attributeName;
- private final AttributeValueProcessor valueProcessor;
-
- private boolean more = true;
- private int pageSize;
- private RangeOption requestRange = new RangeOption(0, pageSize);
- private boolean omitFullRange = true;
-
- public IncrementalAttributeMapper(String attributeName, AttributeValueProcessor valueProcessor) {
- this(attributeName, valueProcessor, RangeOption.TERMINAL_END_OF_RANGE);
- }
-
- public IncrementalAttributeMapper(String attributeName, AttributeValueProcessor valueProcessor, int pageSize) {
- this.attributeName = attributeName;
- this.pageSize = pageSize;
- this.requestRange = new RangeOption(0, pageSize);
- this.valueProcessor = valueProcessor;
- }
-
- public boolean isOmitFullRange() {
- return omitFullRange;
- }
-
- public void setOmitFullRange(boolean omitFullRange) {
- this.omitFullRange = omitFullRange;
- }
-
- public Object mapFromAttributes(Attributes attributes) throws NamingException {
- if (!more) {
- throw new IllegalStateException("No more attributes!");
- }
-
- more = false;
-
- NamingEnumeration attributeNameEnum = attributes.getIDs();
-
- while (attributeNameEnum.hasMore()) {
- String attributeName = (String) attributeNameEnum.next();
-
- if (attributeName.equals(this.attributeName)) {
- processValues(attributes, this.attributeName);
- } else if (attributeName.startsWith(this.attributeName + ";")) {
- String[] attributeNameSplit = attributeName.split(";");
- for (int i = 0; i < attributeNameSplit.length; i++) {
- String option = attributeNameSplit[i];
-
- RangeOption responseRange = RangeOption.parse(option);
-
- if (responseRange != null) {
- more = requestRange.compareTo(responseRange) > 0;
-
- if (more) {
- requestRange = responseRange.nextRange(pageSize);
- }
-
- processValues(attributes, attributeName);
- }
- }
- }
- }
-
- return this;
- }
-
- private void processValues(Attributes attributes, String attributeName) throws NamingException {
- Attribute attribute = attributes.get(attributeName);
- NamingEnumeration valueEnum = attribute.getAll();
-
- while (valueEnum.hasMore()) {
- valueProcessor.process(valueEnum.next());
- }
- }
-
- public boolean hasMore() {
- return more;
- }
-
- public String[] getAttributesArray() {
- StringBuilder attributeBuilder = new StringBuilder(attributeName);
-
- if (!(omitFullRange && requestRange.isFullRange())) {
- attributeBuilder.append(';');
-
- requestRange.toString(attributeBuilder);
- }
-
- return new String[]{attributeBuilder.toString()};
- }
-}
diff --git a/core/src/main/java/org/springframework/ldap/support/ad/ListAttributeValueProcessor.java b/core/src/main/java/org/springframework/ldap/support/ad/ListAttributeValueProcessor.java
deleted file mode 100644
index 2e1a6961..00000000
--- a/core/src/main/java/org/springframework/ldap/support/ad/ListAttributeValueProcessor.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * 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.support.ad;
-
-import java.util.LinkedList;
-import java.util.List;
-
-/**
- * @since 1.3.2
- * @author Marius Scurtescu
- */
-public class ListAttributeValueProcessor implements AttributeValueProcessor {
- private List values = new LinkedList();
-
- public void process(Object value) {
- values.add(value);
- }
-
- public List getValues() {
- return values;
- }
-}
diff --git a/core/src/main/java/org/springframework/ldap/support/ad/package.html b/core/src/main/java/org/springframework/ldap/support/ad/package.html
deleted file mode 100644
index ff67bc21..00000000
--- a/core/src/main/java/org/springframework/ldap/support/ad/package.html
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
-Support classes for Active Directory-specific functionality.
-
-
-
diff --git a/core/src/main/java/org/springframework/ldap/transaction/compensating/ModifyAttributesOperationRecorder.java b/core/src/main/java/org/springframework/ldap/transaction/compensating/ModifyAttributesOperationRecorder.java
index 12ddd7ab..3d83f455 100644
--- a/core/src/main/java/org/springframework/ldap/transaction/compensating/ModifyAttributesOperationRecorder.java
+++ b/core/src/main/java/org/springframework/ldap/transaction/compensating/ModifyAttributesOperationRecorder.java
@@ -15,22 +15,22 @@
*/
package org.springframework.ldap.transaction.compensating;
-import java.util.HashSet;
-import java.util.Set;
+import org.springframework.ldap.core.AttributesMapper;
+import org.springframework.ldap.core.LdapOperations;
+import org.springframework.ldap.core.support.DefaultIncrementalAttributesMapper;
+import org.springframework.ldap.core.IncrementalAttributesMapper;
+import org.springframework.transaction.compensating.CompensatingTransactionOperationExecutor;
+import org.springframework.transaction.compensating.CompensatingTransactionOperationRecorder;
+import org.springframework.util.Assert;
import javax.naming.Name;
-import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.BasicAttribute;
import javax.naming.directory.DirContext;
import javax.naming.directory.ModificationItem;
-
-import org.springframework.ldap.core.AttributesMapper;
-import org.springframework.ldap.core.LdapOperations;
-import org.springframework.transaction.compensating.CompensatingTransactionOperationExecutor;
-import org.springframework.transaction.compensating.CompensatingTransactionOperationRecorder;
-import org.springframework.util.Assert;
+import java.util.HashSet;
+import java.util.Set;
/**
* A {@link CompensatingTransactionOperationRecorder} keeping track of
@@ -71,8 +71,16 @@ public class ModifyAttributesOperationRecorder implements
// Get the current values of all referred Attributes.
String[] attributeNameArray = (String[]) set.toArray(new String[set
.size()]);
- Attributes currentAttributes = (Attributes) ldapOperations.lookup(dn,
- attributeNameArray, getAttributesMapper());
+
+ // LDAP-234: We need to explicitly an IncrementalAttributesMapper in
+ // case we're working against AD and there are too many attribute values to be returned
+ // by one query.
+ IncrementalAttributesMapper attributesMapper = getAttributesMapper(attributeNameArray);
+ while (attributesMapper.hasMore()) {
+ ldapOperations.lookup(dn, attributesMapper.getAttributesForLookup(), attributesMapper);
+ }
+
+ Attributes currentAttributes = attributesMapper.getCollectedAttributes();
// Get a compensating ModificationItem for each of the incoming
// modification.
@@ -93,13 +101,8 @@ public class ModifyAttributesOperationRecorder implements
* @return the {@link AttributesMapper} to use for getting the current
* Attributes of the target DN.
*/
- AttributesMapper getAttributesMapper() {
- return new AttributesMapper() {
- public Object mapFromAttributes(Attributes attributes)
- throws NamingException {
- return attributes;
- }
- };
+ IncrementalAttributesMapper getAttributesMapper(String[] attributeNames) {
+ return new DefaultIncrementalAttributesMapper(attributeNames);
}
/**
diff --git a/core/src/test/java/org/springframework/ldap/core/support/DefaultIncrementalAttributesMapperTest.java b/core/src/test/java/org/springframework/ldap/core/support/DefaultIncrementalAttributesMapperTest.java
new file mode 100644
index 00000000..ffc646e6
--- /dev/null
+++ b/core/src/test/java/org/springframework/ldap/core/support/DefaultIncrementalAttributesMapperTest.java
@@ -0,0 +1,188 @@
+/*
+ * 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.core.support;
+
+import junit.framework.TestCase;
+import org.springframework.ldap.core.support.DefaultIncrementalAttributesMapper;
+import org.springframework.ldap.core.support.RangeOption;
+
+import javax.naming.directory.Attribute;
+import javax.naming.directory.Attributes;
+import javax.naming.directory.BasicAttribute;
+import javax.naming.directory.BasicAttributes;
+
+/**
+ * IncrementalAttributesMapper Tester.
+ *
+ * @author Marius Scurtescu
+ * @author Mattias Hellborg Arthursson
+ */
+public class DefaultIncrementalAttributesMapperTest extends TestCase {
+ private DefaultIncrementalAttributesMapper tested;
+
+ public DefaultIncrementalAttributesMapperTest(String name) {
+ super(name);
+ }
+
+ public void setUp() throws Exception {
+ tested = new DefaultIncrementalAttributesMapper("member");
+ }
+
+ public void tearDown() throws Exception {
+ tested = null;
+ }
+
+ public void testGetAttributesArray() throws Exception {
+ String[] attributes = tested.getAttributesForLookup();
+
+ assertEquals(1, attributes.length);
+ assertEquals("member", attributes[0]);
+
+ tested = new DefaultIncrementalAttributesMapper(10, "member");
+
+ attributes = tested.getAttributesForLookup();
+
+ assertEquals(1, attributes.length);
+ assertEquals("member;Range=0-10", attributes[0]);
+ }
+
+ public void testGetAttributesArrayWithTwoAttributes() {
+ tested = new DefaultIncrementalAttributesMapper(20, new String[]{"member", "cn"});
+ String[] attributes = tested.getAttributesForLookup();
+
+ assertEquals(2, attributes.length);
+
+ assertEquals("member;Range=0-20", attributes[0]);
+ assertEquals("cn;Range=0-20", attributes[1]);
+ }
+
+ public void testLoopEmpty() throws Exception {
+ assertTrue(tested.hasMore());
+
+ Attributes attributes = new BasicAttributes();
+
+ tested.mapFromAttributes(attributes);
+
+ assertFalse(tested.hasMore());
+ assertNull(tested.getValues("member"));
+ }
+
+ public void testLoop() throws Exception {
+ Attributes attributes = createAttributes("member", new RangeOption(0, 10));
+
+ tested.mapFromAttributes(attributes);
+
+ assertTrue(tested.hasMore());
+ assertEquals(11, tested.getValues("member").size());
+
+ attributes = createAttributes("member", new RangeOption(11), 5);
+
+ tested.mapFromAttributes(attributes);
+
+ assertFalse(tested.hasMore());
+ assertEquals(16, tested.getValues("member").size());
+ }
+
+ public void test1LoopWithPageSizeExact() throws Exception {
+ tested = new DefaultIncrementalAttributesMapper(10, "member");
+
+ Attributes attributes = createAttributes("member", new RangeOption(0, 10));
+
+ tested.mapFromAttributes(attributes);
+
+ assertFalse(tested.hasMore());
+ assertEquals(11, tested.getValues("member").size());
+ }
+
+ public void test2LoopsWithPageSizeExact() throws Exception {
+ tested = new DefaultIncrementalAttributesMapper(20, "member");
+
+ Attributes attributes = createAttributes("member", new RangeOption(0, 10));
+
+ tested.mapFromAttributes(attributes);
+
+ assertTrue(tested.hasMore());
+ assertEquals(11, tested.getValues("member").size());
+
+ attributes = createAttributes("member", new RangeOption(11, 30));
+
+ tested.mapFromAttributes(attributes);
+
+ assertFalse(tested.hasMore());
+ assertEquals(31, tested.getValues("member").size());
+ }
+
+ public void test2LoopsWithPageSize() throws Exception {
+ tested = new DefaultIncrementalAttributesMapper(20, "member");
+
+ Attributes attributes = createAttributes("member", new RangeOption(0, 10));
+
+ tested.mapFromAttributes(attributes);
+
+ assertTrue(tested.hasMore());
+ assertEquals(11, tested.getValues("member").size());
+
+ attributes = createAttributes("member", new RangeOption(11), 5);
+
+ tested.mapFromAttributes(attributes);
+
+ assertFalse(tested.hasMore());
+ assertEquals(16, tested.getValues("member").size());
+ }
+
+ public void testLoopWithTwoRangedAttributesLoopOnOneAttribute() throws Exception {
+ tested = new DefaultIncrementalAttributesMapper(10, new String[]{"member", "cn"});
+
+ Attributes attributes = createAttributes("member", new RangeOption(0, 5));
+ attributes.put(createRangeAttribute("cn", new RangeOption(0, 10), 10));
+
+ tested.mapFromAttributes(attributes);
+
+ assertTrue(tested.hasMore());
+ assertEquals(6, tested.getValues("member").size());
+ assertEquals(10, tested.getValues("cn").size());
+
+ assertEquals(1, tested.getAttributesForLookup().length);
+
+ attributes = createAttributes("member", new RangeOption(6), 5);
+
+ tested.mapFromAttributes(attributes);
+
+ assertFalse(tested.hasMore());
+ assertEquals(11, tested.getValues("member").size());
+ }
+ private Attributes createAttributes(String attributeName, RangeOption range) {
+ return createAttributes(attributeName, range, range.getTerminal() - range.getInitial() + 1);
+ }
+
+ private Attributes createAttributes(String attributeName, RangeOption range, int valueCnt) {
+ Attributes attributes = new BasicAttributes();
+
+ Attribute attribute = createRangeAttribute(attributeName, range, valueCnt);
+ attributes.put(attribute);
+
+ return attributes;
+
+ }
+
+ private Attribute createRangeAttribute(String attributeName, RangeOption range, int valueCnt) {
+ Attribute attribute = new BasicAttribute(attributeName + ";" + range.toString());
+ for (int i = 0; i < valueCnt; i++) {
+ attribute.add("value" + (range.getInitial() + i - 1));
+ }
+ return attribute;
+ }
+}
diff --git a/core/src/test/java/org/springframework/ldap/support/ad/RangeOptionTest.java b/core/src/test/java/org/springframework/ldap/core/support/RangeOptionTest.java
similarity index 97%
rename from core/src/test/java/org/springframework/ldap/support/ad/RangeOptionTest.java
rename to core/src/test/java/org/springframework/ldap/core/support/RangeOptionTest.java
index 31428355..f8e5e05b 100644
--- a/core/src/test/java/org/springframework/ldap/support/ad/RangeOptionTest.java
+++ b/core/src/test/java/org/springframework/ldap/core/support/RangeOptionTest.java
@@ -13,12 +13,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.springframework.ldap.support.ad;
+package org.springframework.ldap.core.support;
import junit.framework.TestCase;
+import org.springframework.ldap.core.support.RangeOption;
/**
- * IncrementalAttributeMapper Tester.
+ * IncrementalAttributesMapper Tester.
*
* @author Marius Scurtescu
*/
diff --git a/core/src/test/java/org/springframework/ldap/support/ad/IncrementalAttributeMapperTest.java b/core/src/test/java/org/springframework/ldap/support/ad/IncrementalAttributeMapperTest.java
deleted file mode 100644
index 882eec3a..00000000
--- a/core/src/test/java/org/springframework/ldap/support/ad/IncrementalAttributeMapperTest.java
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * 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.support.ad;
-
-import junit.framework.TestCase;
-
-import javax.naming.directory.Attribute;
-import javax.naming.directory.Attributes;
-import javax.naming.directory.BasicAttribute;
-import javax.naming.directory.BasicAttributes;
-
-/**
- * IncrementalAttributeMapper Tester.
- *
- * @author Marius Scurtescu
- */
-public class IncrementalAttributeMapperTest extends TestCase {
- private IncrementalAttributeMapper incrementalAttributeMapper;
- private ListAttributeValueProcessor valueProcessor;
-
- public IncrementalAttributeMapperTest(String name) {
- super(name);
- }
-
- public void setUp() throws Exception {
- valueProcessor = new ListAttributeValueProcessor();
- incrementalAttributeMapper = new IncrementalAttributeMapper("member", valueProcessor);
- }
-
- public void tearDown() throws Exception {
- incrementalAttributeMapper = null;
- valueProcessor = null;
- }
-
- public void testGetAttributesArray() throws Exception {
- String[] attributes = incrementalAttributeMapper.getAttributesArray();
-
- assertEquals(1, attributes.length);
- assertEquals("member", attributes[0]);
-
- incrementalAttributeMapper = new IncrementalAttributeMapper("member", valueProcessor, 10);
-
- attributes = incrementalAttributeMapper.getAttributesArray();
-
- assertEquals(1, attributes.length);
- assertEquals("member;Range=0-10", attributes[0]);
- }
-
- public void testLoopEmpty() throws Exception {
- assertTrue(incrementalAttributeMapper.hasMore());
-
- Attributes attributes = new BasicAttributes();
-
- incrementalAttributeMapper.mapFromAttributes(attributes);
-
- assertFalse(incrementalAttributeMapper.hasMore());
- assertEquals(0, valueProcessor.getValues().size());
- }
-
- public void testLoop() throws Exception {
- Attributes attributes = createAttributes(new RangeOption(0, 10), true);
-
- incrementalAttributeMapper.mapFromAttributes(attributes);
-
- assertTrue(incrementalAttributeMapper.hasMore());
- assertEquals(11, valueProcessor.getValues().size());
-
- attributes = createAttributes(new RangeOption(11), 5, false);
-
- incrementalAttributeMapper.mapFromAttributes(attributes);
-
- assertFalse(incrementalAttributeMapper.hasMore());
- assertEquals(16, valueProcessor.getValues().size());
- }
-
- public void test1LoopWithPageSizeExact() throws Exception {
- incrementalAttributeMapper = new IncrementalAttributeMapper("member", valueProcessor, 10);
-
- Attributes attributes = createAttributes(new RangeOption(0, 10), true);
-
- incrementalAttributeMapper.mapFromAttributes(attributes);
-
- assertFalse(incrementalAttributeMapper.hasMore());
- assertEquals(11, valueProcessor.getValues().size());
- }
-
- public void test2LoopsWithPageSizeExact() throws Exception {
- incrementalAttributeMapper = new IncrementalAttributeMapper("member", valueProcessor, 20);
-
- Attributes attributes = createAttributes(new RangeOption(0, 10), true);
-
- incrementalAttributeMapper.mapFromAttributes(attributes);
-
- assertTrue(incrementalAttributeMapper.hasMore());
- assertEquals(11, valueProcessor.getValues().size());
-
- attributes = createAttributes(new RangeOption(11, 30), false);
-
- incrementalAttributeMapper.mapFromAttributes(attributes);
-
- assertFalse(incrementalAttributeMapper.hasMore());
- assertEquals(31, valueProcessor.getValues().size());
- }
-
- public void test2LoopsWithPageSize() throws Exception {
- incrementalAttributeMapper = new IncrementalAttributeMapper("member", valueProcessor, 20);
-
- Attributes attributes = createAttributes(new RangeOption(0, 10), true);
-
- incrementalAttributeMapper.mapFromAttributes(attributes);
-
- assertTrue(incrementalAttributeMapper.hasMore());
- assertEquals(11, valueProcessor.getValues().size());
-
- attributes = createAttributes(new RangeOption(11), 5, false);
-
- incrementalAttributeMapper.mapFromAttributes(attributes);
-
- assertFalse(incrementalAttributeMapper.hasMore());
- assertEquals(16, valueProcessor.getValues().size());
- }
-
- private Attributes createAttributes(RangeOption range, boolean emptyPlain) {
- return createAttributes(range, range.getTerminal() - range.getInitial() + 1, emptyPlain);
- }
-
- private Attributes createAttributes(RangeOption range, int valueCnt, boolean emptyPlain) {
- Attributes attributes = new BasicAttributes();
-
- if (emptyPlain) {
- attributes.put(new BasicAttribute("member"));
- }
-
- Attribute attribute = new BasicAttribute("member;" + range.toString());
- for (int i = 0; i < valueCnt; i++) {
- attribute.add("value" + (range.getInitial() + i - 1));
- }
- attributes.put(attribute);
-
- return attributes;
-
- }
-}
diff --git a/core/src/test/java/org/springframework/ldap/transaction/compensating/ModifyAttributesOperationRecorderTest.java b/core/src/test/java/org/springframework/ldap/transaction/compensating/ModifyAttributesOperationRecorderTest.java
index afe8a7c3..0d8ae53b 100644
--- a/core/src/test/java/org/springframework/ldap/transaction/compensating/ModifyAttributesOperationRecorderTest.java
+++ b/core/src/test/java/org/springframework/ldap/transaction/compensating/ModifyAttributesOperationRecorderTest.java
@@ -15,6 +15,13 @@
*/
package org.springframework.ldap.transaction.compensating;
+import junit.framework.TestCase;
+import org.easymock.MockControl;
+import org.springframework.ldap.core.DistinguishedName;
+import org.springframework.ldap.core.LdapOperations;
+import org.springframework.ldap.core.IncrementalAttributesMapper;
+import org.springframework.transaction.compensating.CompensatingTransactionOperationExecutor;
+
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
@@ -23,16 +30,6 @@ import javax.naming.directory.BasicAttributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.ModificationItem;
-import junit.framework.TestCase;
-
-import org.easymock.MockControl;
-import org.springframework.ldap.core.AttributesMapper;
-import org.springframework.ldap.core.DistinguishedName;
-import org.springframework.ldap.core.LdapOperations;
-import org.springframework.ldap.transaction.compensating.ModifyAttributesOperationExecutor;
-import org.springframework.ldap.transaction.compensating.ModifyAttributesOperationRecorder;
-import org.springframework.transaction.compensating.CompensatingTransactionOperationExecutor;
-
public class ModifyAttributesOperationRecorderTest extends TestCase {
private MockControl ldapOperationsControl;
@@ -40,7 +37,7 @@ public class ModifyAttributesOperationRecorderTest extends TestCase {
private MockControl attributesMapperControl;
- private AttributesMapper attributesMapperMock;
+ private IncrementalAttributesMapper attributesMapperMock;
private ModifyAttributesOperationRecorder tested;
@@ -49,8 +46,8 @@ public class ModifyAttributesOperationRecorderTest extends TestCase {
ldapOperationsMock = (LdapOperations) ldapOperationsControl.getMock();
attributesMapperControl = MockControl
- .createControl(AttributesMapper.class);
- attributesMapperMock = (AttributesMapper) attributesMapperControl
+ .createControl(IncrementalAttributesMapper.class);
+ attributesMapperMock = (IncrementalAttributesMapper) attributesMapperControl
.getMock();
tested = new ModifyAttributesOperationRecorder(ldapOperationsMock);
@@ -79,14 +76,14 @@ public class ModifyAttributesOperationRecorderTest extends TestCase {
public void testRecordOperation() {
final ModificationItem incomingItem = new ModificationItem(
DirContext.ADD_ATTRIBUTE, new BasicAttribute("attribute1"));
- ModificationItem[] incomingMods = new ModificationItem[] { incomingItem };
+ ModificationItem[] incomingMods = new ModificationItem[]{incomingItem};
final ModificationItem compensatingItem = new ModificationItem(
DirContext.ADD_ATTRIBUTE, new BasicAttribute("attribute2"));
final Attributes expectedAttributes = new BasicAttributes();
tested = new ModifyAttributesOperationRecorder(ldapOperationsMock) {
- AttributesMapper getAttributesMapper() {
+ IncrementalAttributesMapper getAttributesMapper(String[] attributeNames) {
return attributesMapperMock;
}
@@ -101,14 +98,24 @@ public class ModifyAttributesOperationRecorderTest extends TestCase {
DistinguishedName expectedName = new DistinguishedName("cn=john doe");
ldapOperationsControl.setDefaultMatcher(MockControl.ARRAY_MATCHER);
- ldapOperationsControl.expectAndReturn(ldapOperationsMock.lookup(
- expectedName, new String[] { "attribute1" },
- attributesMapperMock), expectedAttributes);
+
+ attributesMapperControl.expectAndReturn(
+ attributesMapperMock.hasMore(), true);
+ attributesMapperControl.expectAndReturn(
+ attributesMapperMock.getAttributesForLookup(),
+ new String[]{"attribute1"});
+ ldapOperationsControl.expectAndReturn(
+ ldapOperationsMock.lookup(expectedName, new String[]{"attribute1"}, attributesMapperMock),
+ expectedAttributes);
+ attributesMapperControl.expectAndReturn(attributesMapperMock.hasMore(), false);
+ attributesMapperControl.expectAndReturn(
+ attributesMapperMock.getCollectedAttributes(),
+ expectedAttributes);
replay();
// Perform test
CompensatingTransactionOperationExecutor operation = tested
- .recordOperation(new Object[] { expectedName, incomingMods });
+ .recordOperation(new Object[]{expectedName, incomingMods});
verify();
// Verify outcome
diff --git a/settings.gradle b/settings.gradle
index f60e1219..44e4a90e 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -13,10 +13,11 @@ include 'samples/demos/demo'
include 'samples/demos/demo-tiger'
include 'samples/samples-utils'
include 'samples/simple-odm'
+include 'test-support'
include 'test/integration-tests'
include 'test/integration-tests-openldap'
include 'test/integration-tests-sunone'
-include 'test-support'
+include 'test/integration-tests-ad'
rootProject.children.each { p->
def name = p.name
diff --git a/src/docbkx/index.xml b/src/docbkx/index.xml
index 02c50711..4cb586d7 100644
--- a/src/docbkx/index.xml
+++ b/src/docbkx/index.xml
@@ -50,4 +50,5 @@
org.springframework.ldap.core.support.DefaultIncrementalAttributesMapper
+ helps working with this kind of attributes, as follows:
+