Fix for LDAP-130, LDAP-137:

Added getObjectAttributes() method
Eliminated code duplication in getStringAttributes, getObjectAttributes and getAttributeSortedStringSet
Added AttributeValueCallbackHandler and iterator methods in LdapUtils
We are now following the same contract as Attributes and Attribute - 
if the Attribute does not exist all of the above methods now return null, if the Attribute is there but empty
the result will be an empty array or set.
This commit is contained in:
Mattias Arthursson
2008-10-23 07:37:26 +00:00
parent 14db0238c2
commit 76b37c7987
8 changed files with 331 additions and 52 deletions

View File

@@ -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);
}
}

View File

@@ -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.

View File

@@ -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);
}
}

View File

@@ -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 <code>null</code>
* 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 <code>null</code> otherwise.
* @since 1.3
*/
Object[] getObjectAttributes(String name);
/**
* Get all String values of the attribute as a <code>SortedSet</code>.
*
* @param name name of the attribute.
* @return a <code>SortedSet</code> containing all values of the attribute.
* @return a <code>SortedSet</code> containing all values of the attribute,
* or <code>null</code> if the attribute does not exist.
*/
SortedSet getAttributeSortedStringSet(String name);

View File

@@ -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);
}

View File

@@ -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 <code>null</code>.
* @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 <code>null</code>.
* @param callbackHandler the callbackHandler; not <code>null</code>.
*/
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);
}
}
}

View File

@@ -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();

View File

@@ -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();
}
}