diff --git a/core/src/main/java/org/springframework/ldap/NoSuchAttributeException.java b/core/src/main/java/org/springframework/ldap/NoSuchAttributeException.java
index b7739bb9..7fa42abb 100644
--- a/core/src/main/java/org/springframework/ldap/NoSuchAttributeException.java
+++ b/core/src/main/java/org/springframework/ldap/NoSuchAttributeException.java
@@ -25,8 +25,11 @@ package org.springframework.ldap;
*/
public class NoSuchAttributeException extends NamingException {
- public NoSuchAttributeException(
- javax.naming.directory.NoSuchAttributeException cause) {
- super(cause);
- }
+ public NoSuchAttributeException(String message) {
+ super(message);
+ }
+
+ public NoSuchAttributeException(javax.naming.directory.NoSuchAttributeException cause) {
+ super(cause);
+ }
}
diff --git a/core/src/main/java/org/springframework/ldap/core/AttributesMapperCallbackHandler.java b/core/src/main/java/org/springframework/ldap/core/AttributesMapperCallbackHandler.java
index dfbdd552..1ac45216 100644
--- a/core/src/main/java/org/springframework/ldap/core/AttributesMapperCallbackHandler.java
+++ b/core/src/main/java/org/springframework/ldap/core/AttributesMapperCallbackHandler.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2005-2007 the original author or authors.
+ * Copyright 2005-2008 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.
diff --git a/core/src/main/java/org/springframework/ldap/core/DirContextAdapter.java b/core/src/main/java/org/springframework/ldap/core/DirContextAdapter.java
index 2a112f74..f3f71d80 100644
--- a/core/src/main/java/org/springframework/ldap/core/DirContextAdapter.java
+++ b/core/src/main/java/org/springframework/ldap/core/DirContextAdapter.java
@@ -42,6 +42,7 @@ import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.springframework.ldap.NoSuchAttributeException;
import org.springframework.ldap.support.LdapUtils;
import org.springframework.util.StringUtils;
@@ -709,25 +710,36 @@ public class DirContextAdapter implements DirContextOperations {
* (java.lang.String)
*/
public String[] getStringAttributes(String name) {
- String[] attributes;
-
- Attribute attribute = originalAttrs.get(name);
- if (attribute != null && attribute.size() > 0) {
- attributes = new String[attribute.size()];
- for (int i = 0; i < attribute.size(); i++) {
- try {
- attributes[i] = (String) attribute.get(i);
- }
- catch (NamingException e) {
- throw LdapUtils.convertLdapException(e);
- }
- }
+ try {
+ return (String[]) collectAttributeValuesAsList(name).toArray(new String[0]);
}
- else {
+ catch (NoSuchAttributeException e) {
+ // The attribute does not exist - contract says to return null.
return null;
}
+ }
- return attributes;
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.springframework.ldap.core.DirContextOperations#getObjectAttributes
+ * (java.lang.String)
+ */
+ public Object[] getObjectAttributes(String name) {
+ try {
+ return collectAttributeValuesAsList(name).toArray(new Object[0]);
+ }
+ catch (NoSuchAttributeException e) {
+ // The attribute does not exist - contract says to return null.
+ return null;
+ }
+ }
+
+ private List collectAttributeValuesAsList(String name) {
+ List list = new LinkedList();
+ LdapUtils.collectAttributeValues(originalAttrs, name, list);
+ return list;
}
/*
@@ -735,24 +747,15 @@ public class DirContextAdapter implements DirContextOperations {
* getAttributeSortedStringSet(java.lang.String)
*/
public SortedSet getAttributeSortedStringSet(String name) {
- TreeSet attrSet = new TreeSet();
-
- Attribute attribute = originalAttrs.get(name);
- if (attribute != null) {
- for (int i = 0; i < attribute.size(); i++) {
- try {
- attrSet.add(attribute.get(i));
- }
- catch (NamingException e) {
- throw LdapUtils.convertLdapException(e);
- }
- }
+ try {
+ TreeSet attrSet = new TreeSet();
+ LdapUtils.collectAttributeValues(originalAttrs, name, attrSet);
+ return attrSet;
}
- else {
+ catch (NoSuchAttributeException e) {
+ // The attribute does not exist - contract says to return null.
return null;
}
-
- return attrSet;
}
/**
@@ -1299,4 +1302,5 @@ public class DirContextAdapter implements DirContextOperations {
public boolean isReferral() {
return StringUtils.hasLength(referralUrl);
}
+
}
diff --git a/core/src/main/java/org/springframework/ldap/core/DirContextOperations.java b/core/src/main/java/org/springframework/ldap/core/DirContextOperations.java
index 8d16db99..892a96c6 100644
--- a/core/src/main/java/org/springframework/ldap/core/DirContextOperations.java
+++ b/core/src/main/java/org/springframework/ldap/core/DirContextOperations.java
@@ -144,16 +144,30 @@ public interface DirContextOperations extends DirContext, AttributeModifications
* Get all values of a String attribute.
*
* @param name name of the attribute.
- *
- * @return all registered values of the attribute.
+ * @return a (possibly empty) array containing all registered values of the
+ * attribute as Strings if the attribute is defined or null
+ * otherwise.
+ * @throws ArrayStoreException if any of the attribute values is not a
+ * String.
*/
String[] getStringAttributes(String name);
+ /**
+ * Get all values of an Object attribute.
+ *
+ * @param name name of the attribute.
+ * @return a (possibly empty) array containing all registered values of the
+ * attribute if the attribute is defined or null otherwise.
+ * @since 1.3
+ */
+ Object[] getObjectAttributes(String name);
+
/**
* Get all String values of the attribute as a SortedSet.
*
* @param name name of the attribute.
- * @return a SortedSet containing all values of the attribute.
+ * @return a SortedSet containing all values of the attribute,
+ * or null if the attribute does not exist.
*/
SortedSet getAttributeSortedStringSet(String name);
diff --git a/core/src/main/java/org/springframework/ldap/support/AttributeValueCallbackHandler.java b/core/src/main/java/org/springframework/ldap/support/AttributeValueCallbackHandler.java
new file mode 100644
index 00000000..44118eb3
--- /dev/null
+++ b/core/src/main/java/org/springframework/ldap/support/AttributeValueCallbackHandler.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2005-2008 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;
+
+/**
+ * Callback interface for use when looping through Attribute values.
+ *
+ * @author Mattias Hellborg Arthursson
+ */
+public interface AttributeValueCallbackHandler {
+ /**
+ * Implement to take handle one of the Attribute values.
+ *
+ * @param attributeName the name of the Attribute.
+ * @param attributeValue the value.
+ * @param index the index of the value within the Attribute.
+ */
+ void handleAttributeValue(String attributeName, Object attributeValue, int index);
+}
diff --git a/core/src/main/java/org/springframework/ldap/support/LdapUtils.java b/core/src/main/java/org/springframework/ldap/support/LdapUtils.java
index 80c453e8..52d2d37a 100644
--- a/core/src/main/java/org/springframework/ldap/support/LdapUtils.java
+++ b/core/src/main/java/org/springframework/ldap/support/LdapUtils.java
@@ -16,12 +16,17 @@
package org.springframework.ldap.support;
+import java.util.Collection;
+
+import javax.naming.directory.Attribute;
+import javax.naming.directory.Attributes;
import javax.naming.directory.DirContext;
import javax.naming.ldap.LdapContext;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.ldap.NamingException;
+import org.springframework.ldap.NoSuchAttributeException;
import org.springframework.util.Assert;
/**
@@ -65,9 +70,9 @@ public final class LdapUtils {
}
/**
- * Convert the specified checked
- * {@link javax.naming.NamingException NamingException} to a Spring LDAP
- * runtime {@link org.springframework.ldap.NamingException NamingException}
+ * Convert the specified checked {@link javax.naming.NamingException
+ * NamingException} to a Spring LDAP runtime
+ * {@link org.springframework.ldap.NamingException NamingException}
* equivalent.
*
* @param ex the original checked NamingException to convert
@@ -127,8 +132,9 @@ public final class LdapUtils {
return new org.springframework.ldap.InvalidSearchFilterException(
(javax.naming.directory.InvalidSearchFilterException) ex);
}
-
- // this class is abstract, so it can never be of exactly this class; using instanceof
+
+ // this class is abstract, so it can never be of exactly this class;
+ // using instanceof
if (ex instanceof javax.naming.ldap.LdapReferralException) {
return new org.springframework.ldap.LdapReferralException((javax.naming.ldap.LdapReferralException) ex);
}
@@ -212,16 +218,74 @@ public final class LdapUtils {
* Get the actual class of the supplied DirContext instance; LdapContext or
* DirContext.
*
- * @param context
- * the DirContext instance to check.
+ * @param context the DirContext instance to check.
* @return LdapContext.class if context is an LdapContext, DirContext.class
- * otherwise.
+ * otherwise.
*/
public static Class getActualTargetClass(DirContext context) {
- if (context instanceof LdapContext) {
- return LdapContext.class;
- }
-
- return DirContext.class;
+ if (context instanceof LdapContext) {
+ return LdapContext.class;
+ }
+
+ return DirContext.class;
+ }
+
+ /**
+ * Collect all the values of a the specified attribute from the supplied
+ * Attributes.
+ *
+ * @param attributes The Attributes; not null.
+ * @param name The name of the Attribute to get values for.
+ * @param collection the collection to collect the values in.
+ * @throws NoSuchAttributeException if no attribute with the specified name
+ * exists.
+ */
+ public static void collectAttributeValues(Attributes attributes, String name, Collection collection) {
+ Assert.notNull(attributes, "Attributes must not be null");
+ Attribute attribute = attributes.get(name);
+ if (attribute == null) {
+ throw new NoSuchAttributeException("No attribute with name '" + name + "'");
+ }
+
+ iterateAttributeValues(attribute, new CollectingAttributeValueCallbackHandler(collection));
+ }
+
+ /**
+ * Iterate through all the values of the specified Attribute calling back to
+ * the specified callbackHandler.
+ * @param attribute the Attribute to work with; not null.
+ * @param callbackHandler the callbackHandler; not null.
+ */
+ public static void iterateAttributeValues(Attribute attribute, AttributeValueCallbackHandler callbackHandler) {
+ Assert.notNull(attribute, "Attribute must not be null");
+ Assert.notNull(callbackHandler, "callbackHandler must not be null");
+
+ for (int i = 0; i < attribute.size(); i++) {
+ try {
+ callbackHandler.handleAttributeValue(attribute.getID(), attribute.get(i), i);
+ }
+ catch (javax.naming.NamingException e) {
+ throw LdapUtils.convertLdapException(e);
+ }
+ }
+ }
+
+ /**
+ * An {@link AttributeValueCallbackHandler} to collect values in a supplied
+ * collection.
+ *
+ * @author Mattias Hellborg Arthursson
+ */
+ private final static class CollectingAttributeValueCallbackHandler implements AttributeValueCallbackHandler {
+ private final Collection collection;
+
+ public CollectingAttributeValueCallbackHandler(Collection collection) {
+ Assert.notNull(collection, "Collection must not be null");
+ this.collection = collection;
+ }
+
+ public final void handleAttributeValue(String attributeName, Object attributeValue, int index) {
+ collection.add(attributeValue);
+ }
}
}
diff --git a/core/src/test/java/org/springframework/ldap/core/DirContextAdapterTest.java b/core/src/test/java/org/springframework/ldap/core/DirContextAdapterTest.java
index da6c4405..50975e25 100644
--- a/core/src/test/java/org/springframework/ldap/core/DirContextAdapterTest.java
+++ b/core/src/test/java/org/springframework/ldap/core/DirContextAdapterTest.java
@@ -16,6 +16,9 @@
package org.springframework.ldap.core;
+import java.util.Iterator;
+import java.util.SortedSet;
+
import javax.naming.Name;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
@@ -107,11 +110,78 @@ public class DirContextAdapterTest extends TestCase {
assertEquals(2, s.length);
}
+ public void testGetStringAttributesExistsWithInvalidType() throws Exception {
+ final Attributes attrs = new BasicAttributes();
+ Attribute multi = new BasicAttribute("abc");
+ multi.add(new Object());
+ attrs.put(multi);
+ class TestableDirContextAdapter extends DirContextAdapter {
+ public TestableDirContextAdapter() {
+ super(attrs, null);
+ }
+ }
+ tested = new TestableDirContextAdapter();
+ try {
+ tested.getStringAttributes("abc");
+ fail("ClassCastException expected");
+ }
+ catch (ArrayStoreException expected) {
+ assertTrue(true);
+ }
+ }
+
+ public void testGetStringAttributesExistsEmpty() throws Exception {
+ final Attributes attrs = new BasicAttributes();
+ Attribute multi = new BasicAttribute("abc");
+ attrs.put(multi);
+ class TestableDirContextAdapter extends DirContextAdapter {
+ public TestableDirContextAdapter() {
+ super(attrs, null);
+ }
+ }
+ tested = new TestableDirContextAdapter();
+ String s[] = tested.getStringAttributes("abc");
+ assertNotNull(s);
+ assertEquals(0, s.length);
+ }
+
public void testGetStringAttributesNotExists() throws Exception {
String s[] = tested.getStringAttributes("abc");
assertNull(s);
}
+ public void testGetAttributesSortedStringSetExists() throws Exception {
+ final Attributes attrs = new BasicAttributes();
+ Attribute multi = new BasicAttribute("abc");
+ multi.add("123");
+ multi.add("234");
+ attrs.put(multi);
+ class TestableDirContextAdapter extends DirContextAdapter {
+ public TestableDirContextAdapter() {
+ super(attrs, null);
+ }
+ }
+ tested = new TestableDirContextAdapter();
+ SortedSet s = tested.getAttributeSortedStringSet("abc");
+ assertNotNull(s);
+ assertEquals(2, s.size());
+ Iterator it = s.iterator();
+ assertEquals("123", it.next());
+ assertEquals("234", it.next());
+ }
+
+ public void testGetAttributesSortedStringSetNotExists() throws Exception {
+ final Attributes attrs = new BasicAttributes();
+ class TestableDirContextAdapter extends DirContextAdapter {
+ public TestableDirContextAdapter() {
+ super(attrs, null);
+ }
+ }
+ tested = new TestableDirContextAdapter();
+ SortedSet s = tested.getAttributeSortedStringSet("abc");
+ assertNull(s);
+ }
+
public void testAddAttributeValue() throws NamingException {
// Perform test
tested.addAttributeValue("abc", "123");
@@ -653,7 +723,7 @@ public class DirContextAdapterTest extends TestCase {
}
tested = new TestableDirContextAdapter();
assertTrue(tested.isUpdateMode());
- tested.setAttributeValues("title", new String[] {"Jim", "George", "Juergen" }, true);
+ tested.setAttributeValues("title", new String[] { "Jim", "George", "Juergen" }, true);
// change
ModificationItem[] mods = tested.getModificationItems();
diff --git a/core/src/test/java/org/springframework/ldap/support/LdapUtilsTest.java b/core/src/test/java/org/springframework/ldap/support/LdapUtilsTest.java
new file mode 100644
index 00000000..22794c2a
--- /dev/null
+++ b/core/src/test/java/org/springframework/ldap/support/LdapUtilsTest.java
@@ -0,0 +1,92 @@
+package org.springframework.ldap.support;
+
+import java.util.LinkedList;
+
+import javax.naming.directory.BasicAttribute;
+import javax.naming.directory.BasicAttributes;
+
+import junit.framework.TestCase;
+
+import org.easymock.MockControl;
+import org.springframework.ldap.NoSuchAttributeException;
+
+public class LdapUtilsTest extends TestCase {
+
+ private MockControl handlerControl;
+
+ private AttributeValueCallbackHandler handlerMock;
+
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ handlerControl = MockControl.createControl(AttributeValueCallbackHandler.class);
+ handlerMock = (AttributeValueCallbackHandler) handlerControl.getMock();
+ }
+
+ protected void tearDown() throws Exception {
+ super.tearDown();
+
+ handlerControl = null;
+ handlerMock = null;
+ }
+
+ public void testCollectAttributeValues() {
+ String expectedAttributeName = "someAttribute";
+ BasicAttribute expectedAttribute = new BasicAttribute(expectedAttributeName);
+ expectedAttribute.add("value1");
+ expectedAttribute.add("value2");
+
+ BasicAttributes attributes = new BasicAttributes();
+ attributes.put(expectedAttribute);
+
+ LinkedList list = new LinkedList();
+ LdapUtils.collectAttributeValues(attributes, expectedAttributeName, list);
+
+ assertEquals(2, list.size());
+ assertEquals("value1", list.get(0));
+ assertEquals("value2", list.get(1));
+ }
+
+ public void testCollectAttributeValuesThrowsExceptionWhenAttributeNotPresent() {
+ String expectedAttributeName = "someAttribute";
+ BasicAttributes attributes = new BasicAttributes();
+
+ LinkedList list = new LinkedList();
+ try {
+ LdapUtils.collectAttributeValues(attributes, expectedAttributeName, list);
+ fail("NoSuchAttributeException expected");
+ }
+ catch (NoSuchAttributeException expected) {
+ assertTrue(true);
+ }
+ }
+
+ public void testIterateAttributeValues() {
+ String expectedAttributeName = "someAttribute";
+
+ BasicAttribute expectedAttribute = new BasicAttribute(expectedAttributeName);
+ expectedAttribute.add("value1");
+ expectedAttribute.add("value2");
+
+ handlerMock.handleAttributeValue(expectedAttributeName, "value1", 0);
+ handlerMock.handleAttributeValue(expectedAttributeName, "value2", 1);
+
+ handlerControl.replay();
+
+ LdapUtils.iterateAttributeValues(expectedAttribute, handlerMock);
+
+ handlerControl.verify();
+ }
+
+ public void testIterateAttributeValuesWithEmptyAttribute() {
+ String expectedAttributeName = "someAttribute";
+
+ BasicAttribute expectedAttribute = new BasicAttribute(expectedAttributeName);
+
+ handlerControl.replay();
+
+ LdapUtils.iterateAttributeValues(expectedAttribute, handlerMock);
+
+ handlerControl.verify();
+ }
+}