LDAP-248: DirContextAdapter now handles javax.naming.Name instances properly with regards to equality
LDAP-274: ODM now uses standard Spring converter (if present). LDAP-275: Support for different Collection types in ODM
This commit is contained in:
@@ -13,6 +13,7 @@ dependencies {
|
||||
"org.springframework:spring-beans:$springVersion",
|
||||
"org.springframework:spring-tx:$springVersion",
|
||||
"org.springframework.data:spring-data-commons:$springDataVersion"
|
||||
"org.slf4j:slf4j-api:$slf4jVersion"
|
||||
|
||||
provided "commons-pool:commons-pool:$commonsPoolVersion",
|
||||
"com.sun:ldapbp:1.0",
|
||||
@@ -24,6 +25,7 @@ dependencies {
|
||||
testCompile "junit:junit:$junitVersion",
|
||||
"commons-lang:commons-lang:$commonsLangVersion",
|
||||
"gsbase:gsbase:$gsbaseVersion",
|
||||
"org.mockito:mockito-core:$mockitoVersion"
|
||||
"org.mockito:mockito-core:$mockitoVersion",
|
||||
"org.slf4j:slf4j-log4j12:$slf4jVersion"
|
||||
}
|
||||
|
||||
|
||||
@@ -47,9 +47,14 @@ public interface LdapDataEntry {
|
||||
|
||||
/**
|
||||
* Set the with the name <code>name</code> to the <code>value</code>.
|
||||
* If the value is a {@link Name} instance, equality for Distinguished
|
||||
* Names will be used for calculating attribute modifications.
|
||||
*
|
||||
* @param name name of the attribute.
|
||||
* @param value value to set the attribute to.
|
||||
* @throws IllegalArgumentException if the value is a {@link Name} instance
|
||||
* and one or several of the currently present attribute values is <strong>not</strong>
|
||||
* {@link Name} instances or Strings representing valid Distinguished Names.
|
||||
*/
|
||||
public void setAttributeValue(String name, Object value);
|
||||
|
||||
@@ -62,8 +67,14 @@ public interface LdapDataEntry {
|
||||
* objects or if one or more object has changed. Reordering the objects will
|
||||
* not cause an update.
|
||||
*
|
||||
* If the values are {@link Name} instances, equality for Distinguished
|
||||
* Names will be used for calculating attribute modifications.
|
||||
*
|
||||
* @param name The id of the attribute.
|
||||
* @param values Attribute values.
|
||||
* @throws IllegalArgumentException if value is a {@link Name} instance
|
||||
* and one or several of the currently present attribute values is <strong>not</strong>
|
||||
* {@link Name} instances or Strings representing valid Distinguished Names.
|
||||
*/
|
||||
void setAttributeValues(String name, Object[] values);
|
||||
|
||||
@@ -78,10 +89,15 @@ public interface LdapDataEntry {
|
||||
* Reordering the objects will only cause an update if orderMatters is set
|
||||
* to true.
|
||||
*
|
||||
* If the values are {@link Name} instances, equality for Distinguished
|
||||
* Names will be used for calculating attribute modifications.
|
||||
* @param name The id of the attribute.
|
||||
* @param values Attribute values.
|
||||
* @param orderMatters If <code>true</code>, it will be changed even if data
|
||||
* was just reordered.
|
||||
* @throws IllegalArgumentException if value is a {@link Name} instance
|
||||
* and one or several of the currently present attribute values is <strong>not</strong>
|
||||
* {@link Name} instances or Strings representing valid Distinguished Names.
|
||||
*/
|
||||
void setAttributeValues(String name, Object[] values, boolean orderMatters);
|
||||
|
||||
@@ -91,9 +107,15 @@ public interface LdapDataEntry {
|
||||
* will be no duplicates of an added value - it the value exists it will not
|
||||
* be added again.
|
||||
*
|
||||
* If the value is a {@link Name} instance, equality for Distinguished
|
||||
* Names will be used for calculating attribute modifications.
|
||||
*
|
||||
* @param name the name of the Attribute to which the specified value should
|
||||
* be added.
|
||||
* @param value the Attribute value to add.
|
||||
* @throws IllegalArgumentException if value is a {@link Name} instance
|
||||
* and one or several of the currently present attribute values is <strong>not</strong>
|
||||
* {@link Name} instances or Strings representing valid Distinguished Names.
|
||||
*/
|
||||
void addAttributeValue(String name, Object value);
|
||||
|
||||
@@ -104,6 +126,9 @@ public interface LdapDataEntry {
|
||||
* this method makes sure that the there will be no duplicates of an added
|
||||
* value - it the value exists it will not be added again.
|
||||
*
|
||||
* If the value is a {@link Name} instance, equality for Distinguished
|
||||
* Names will be used for calculating attribute modifications.
|
||||
*
|
||||
* @param name the name of the Attribute to which the specified value should
|
||||
* be added.
|
||||
* @param value the Attribute value to add.
|
||||
@@ -111,6 +136,9 @@ public interface LdapDataEntry {
|
||||
* regardless of whether there is an identical value already, allowing for
|
||||
* duplicate attribute values; <code>false</code> will not add the value if
|
||||
* it already exists.
|
||||
* @throws IllegalArgumentException if value is a {@link Name} instance
|
||||
* and one or several of the currently present attribute values is <strong>not</strong>
|
||||
* {@link Name} instances or Strings representing valid Distinguished Names.
|
||||
*/
|
||||
void addAttributeValue(String name, Object value,
|
||||
boolean addIfDuplicateExists);
|
||||
@@ -119,9 +147,15 @@ public interface LdapDataEntry {
|
||||
* Remove a value from the Attribute with the specified name. If the
|
||||
* Attribute doesn't exist, do nothing.
|
||||
*
|
||||
* If the value is a {@link Name} instance, equality for Distinguished
|
||||
* Names will be used for calculating attribute modifications.
|
||||
*
|
||||
* @param name the name of the Attribute from which the specified value
|
||||
* should be removed.
|
||||
* @param value the value to remove.
|
||||
* @throws IllegalArgumentException if value is a {@link Name} instance
|
||||
* and one or several of the currently present attribute values is <strong>not</strong>
|
||||
* {@link Name} instances or Strings representing valid Distinguished Names.
|
||||
*/
|
||||
void removeAttributeValue(String name, Object value);
|
||||
|
||||
|
||||
@@ -33,8 +33,6 @@ 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 javax.naming.directory.DirContext;
|
||||
import javax.naming.directory.ModificationItem;
|
||||
import javax.naming.directory.SearchControls;
|
||||
@@ -60,10 +58,27 @@ import java.util.TreeSet;
|
||||
* this class keeps track of the changes made to its attributes, making them
|
||||
* available as an array of <code>ModificationItem</code> objects, suitable as
|
||||
* input to {@link LdapTemplate#modifyAttributes(DirContextOperations)}.
|
||||
*
|
||||
* Note that this is not a complete implementation of DirContext. Several
|
||||
* methods are not relevant for the intended usage of this class, so they
|
||||
* throw UnsupportOperationException.
|
||||
*
|
||||
* <p>
|
||||
* This class is aware of the specifics of {@link Name} instances with regards
|
||||
* to equality when working with attribute values. This comes in very handy
|
||||
* when working with e.g. security groups and modifications of them. If
|
||||
* {@link Name} instances are supplied to one of the Attribute manipulation
|
||||
* methods (e.g. {@link #addAttributeValue(String, Object)},
|
||||
* {@link #removeAttributeValue(String, Object)}, {@link #setAttributeValue(String, Object)},
|
||||
* or {@link #setAttributeValues(String, Object[])}), the produced modifications
|
||||
* will be calculated using {@link Name} equality. This means that if an the <code>member</code>
|
||||
* has a value of <code>"cn=John Doe,ou=People"</code>, and we call
|
||||
* <code>addAttributeValue("member", LdapUtils.newLdapName("CN=John Doe,OU=People")</code>,
|
||||
* this will <strong>not</strong> be considered a modification since the two DN
|
||||
* strings represent the same distinguished name (case and spacing between attributes is
|
||||
* disregarded).
|
||||
* </p>
|
||||
* <p>
|
||||
* Note that this is not a complete implementation of DirContext. Several
|
||||
* methods are not relevant for the intended usage of this class, so they
|
||||
* throw UnsupportOperationException.
|
||||
* </p>
|
||||
*
|
||||
* @see #setAttributeValue(String, Object)
|
||||
* @see #setAttributeValues(String, Object[])
|
||||
@@ -90,7 +105,7 @@ public class DirContextAdapter implements DirContextOperations {
|
||||
|
||||
private static Logger log = LoggerFactory.getLogger(DirContextAdapter.class);
|
||||
|
||||
private final Attributes originalAttrs;
|
||||
private final NameAwareAttributes originalAttrs;
|
||||
|
||||
private LdapName dn;
|
||||
|
||||
@@ -98,7 +113,7 @@ public class DirContextAdapter implements DirContextOperations {
|
||||
|
||||
private boolean updateMode = false;
|
||||
|
||||
private Attributes updatedAttrs;
|
||||
private NameAwareAttributes updatedAttrs;
|
||||
|
||||
private String referralUrl;
|
||||
|
||||
@@ -160,10 +175,10 @@ public class DirContextAdapter implements DirContextOperations {
|
||||
public DirContextAdapter(Attributes attrs, Name dn, Name base,
|
||||
String referralUrl) {
|
||||
if (attrs != null) {
|
||||
this.originalAttrs = attrs;
|
||||
this.originalAttrs = new NameAwareAttributes(attrs);
|
||||
}
|
||||
else {
|
||||
this.originalAttrs = new BasicAttributes(true);
|
||||
this.originalAttrs = new NameAwareAttributes();
|
||||
}
|
||||
|
||||
if (dn != null) {
|
||||
@@ -193,9 +208,9 @@ public class DirContextAdapter implements DirContextOperations {
|
||||
* @param master The adapter to be copied.
|
||||
*/
|
||||
protected DirContextAdapter(DirContextAdapter master) {
|
||||
this.originalAttrs = (Attributes) master.originalAttrs.clone();
|
||||
this.originalAttrs = (NameAwareAttributes) master.originalAttrs.clone();
|
||||
this.dn = master.dn;
|
||||
this.updatedAttrs = (Attributes) master.updatedAttrs.clone();
|
||||
this.updatedAttrs = (NameAwareAttributes) master.updatedAttrs.clone();
|
||||
this.updateMode = master.updateMode;
|
||||
}
|
||||
|
||||
@@ -209,21 +224,14 @@ public class DirContextAdapter implements DirContextOperations {
|
||||
public void setUpdateMode(boolean mode) {
|
||||
this.updateMode = mode;
|
||||
if (updateMode) {
|
||||
updatedAttrs = new BasicAttributes(true);
|
||||
updatedAttrs = new NameAwareAttributes();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.springframework.ldap.support.DirContextOperations#isUpdateMode()
|
||||
*/
|
||||
public boolean isUpdateMode() {
|
||||
return updateMode;
|
||||
}
|
||||
|
||||
/*
|
||||
* @seeorg.springframework.ldap.support.DirContextOperations#
|
||||
* getNamesOfModifiedAttributes()
|
||||
*/
|
||||
public String[] getNamesOfModifiedAttributes() {
|
||||
|
||||
List<String> tmpList = new ArrayList<String>();
|
||||
@@ -264,10 +272,6 @@ public class DirContextAdapter implements DirContextOperations {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* @seeorg.springframework.ldap.support.AttributeModificationsAware#
|
||||
* getModificationItems()
|
||||
*/
|
||||
public ModificationItem[] getModificationItems() {
|
||||
if (!updateMode) {
|
||||
return new ModificationItem[0];
|
||||
@@ -280,7 +284,7 @@ public class DirContextAdapter implements DirContextOperations {
|
||||
|
||||
// find attributes that have been changed, removed or added
|
||||
while (attributesEnumeration.hasMore()) {
|
||||
Attribute oneAttr = attributesEnumeration.next();
|
||||
NameAwareAttribute oneAttr = (NameAwareAttribute) attributesEnumeration.next();
|
||||
|
||||
collectModifications(oneAttr, tmpList);
|
||||
}
|
||||
@@ -313,9 +317,17 @@ public class DirContextAdapter implements DirContextOperations {
|
||||
* @param modificationList the list in which to add the modifications.
|
||||
* @throws NamingException if thrown by called Attribute methods.
|
||||
*/
|
||||
private void collectModifications(Attribute changedAttr,
|
||||
private void collectModifications(NameAwareAttribute changedAttr,
|
||||
List<ModificationItem> modificationList) throws NamingException {
|
||||
Attribute currentAttribute = originalAttrs.get(changedAttr.getID());
|
||||
NameAwareAttribute currentAttribute = originalAttrs.get(changedAttr.getID());
|
||||
if(changedAttr.hasValuesAsNames()) {
|
||||
try {
|
||||
currentAttribute.initValuesAsNames();
|
||||
} catch(IllegalArgumentException e) {
|
||||
log.warn("Incompatible attributes; changed attribute has Name values but " +
|
||||
"original cannot be converted to this");
|
||||
}
|
||||
}
|
||||
|
||||
if (changedAttr.equals(currentAttribute)) {
|
||||
// No changes
|
||||
@@ -368,15 +380,16 @@ public class DirContextAdapter implements DirContextOperations {
|
||||
throws NamingException {
|
||||
|
||||
Attribute originalClone = (Attribute) originalAttr.clone();
|
||||
Attribute addedValuesAttribute = new BasicAttribute(originalAttr
|
||||
Attribute addedValuesAttribute = new NameAwareAttribute(originalAttr
|
||||
.getID());
|
||||
|
||||
for (int i = 0; i < changedAttr.size(); i++) {
|
||||
Object attributeValue = changedAttr.get(i);
|
||||
if (!originalClone.remove(attributeValue)) {
|
||||
addedValuesAttribute.add(attributeValue);
|
||||
}
|
||||
}
|
||||
NamingEnumeration<?> allValues = changedAttr.getAll();
|
||||
while(allValues.hasMoreElements()) {
|
||||
Object attributeValue = allValues.nextElement();
|
||||
if (!originalClone.remove(attributeValue)) {
|
||||
addedValuesAttribute.add(attributeValue);
|
||||
}
|
||||
}
|
||||
|
||||
// We have now traversed and removed all values from the original that
|
||||
// were also present in the new values. The remaining values in the
|
||||
@@ -552,19 +565,10 @@ public class DirContextAdapter implements DirContextOperations {
|
||||
return originalAttrs.get(attrId) != null;
|
||||
}
|
||||
|
||||
/*
|
||||
* @see
|
||||
* org.springframework.ldap.support.DirContextOperations#getStringAttribute
|
||||
* (java.lang.String)
|
||||
*/
|
||||
public String getStringAttribute(String name) {
|
||||
return (String) getObjectAttribute(name);
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.springframework.ldap.support.DirContextOperations#getObjectAttribute
|
||||
* (java.lang.String)
|
||||
*/
|
||||
public Object getObjectAttribute(String name) {
|
||||
Attribute oneAttr = originalAttrs.get(name);
|
||||
if (oneAttr == null || oneAttr.size() == 0) { // LDAP-215
|
||||
@@ -579,19 +583,11 @@ public class DirContextAdapter implements DirContextOperations {
|
||||
}
|
||||
|
||||
// LDAP-215
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.ldap.core.DirContextOperations#attributeExists(java.lang.String)
|
||||
*/
|
||||
public boolean attributeExists(String name) {
|
||||
Attribute oneAttr = originalAttrs.get(name);
|
||||
return oneAttr != null;
|
||||
}
|
||||
|
||||
/*
|
||||
* @see
|
||||
* org.springframework.ldap.support.DirContextOperations#setAttributeValue
|
||||
* (java.lang.String, java.lang.Object)
|
||||
*/
|
||||
public void setAttributeValue(String name, Object value) {
|
||||
// new entry
|
||||
if (!updateMode && value != null) {
|
||||
@@ -600,7 +596,7 @@ public class DirContextAdapter implements DirContextOperations {
|
||||
|
||||
// updating entry
|
||||
if (updateMode) {
|
||||
BasicAttribute attribute = new BasicAttribute(name);
|
||||
Attribute attribute = new NameAwareAttribute(name);
|
||||
if (value != null) {
|
||||
attribute.add(value);
|
||||
}
|
||||
@@ -608,13 +604,6 @@ public class DirContextAdapter implements DirContextOperations {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see
|
||||
* org.springframework.ldap.core.DirContextOperations#addAttributeValue(
|
||||
* java.lang.String, java.lang.Object)
|
||||
*/
|
||||
public void addAttributeValue(String name, Object value) {
|
||||
addAttributeValue(name, value, DONT_ADD_IF_DUPLICATE_EXISTS);
|
||||
}
|
||||
@@ -654,13 +643,6 @@ public class DirContextAdapter implements DirContextOperations {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see
|
||||
* org.springframework.ldap.core.DirContextOperations#removeAttributeValue
|
||||
* (java.lang.String, java.lang.Object)
|
||||
*/
|
||||
public void removeAttributeValue(String name, Object value) {
|
||||
if (!updateMode && value != null) {
|
||||
Attribute attr = originalAttrs.get(name);
|
||||
@@ -686,23 +668,13 @@ public class DirContextAdapter implements DirContextOperations {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* @see
|
||||
* org.springframework.ldap.support.DirContextOperations#setAttributeValues
|
||||
* (java.lang.String, java.lang.Object[])
|
||||
*/
|
||||
public void setAttributeValues(String name, Object[] values) {
|
||||
setAttributeValues(name, values, ORDER_DOESNT_MATTER);
|
||||
}
|
||||
|
||||
/*
|
||||
* @see
|
||||
* org.springframework.ldap.support.DirContextOperations#setAttributeValues
|
||||
* (java.lang.String, java.lang.Object[], boolean)
|
||||
*/
|
||||
public void setAttributeValues(String name, Object[] values,
|
||||
boolean orderMatters) {
|
||||
Attribute a = new BasicAttribute(name, orderMatters);
|
||||
Attribute a = new NameAwareAttribute(name, orderMatters);
|
||||
|
||||
for (int i = 0; values != null && i < values.length; i++) {
|
||||
a.add(values[i]);
|
||||
@@ -720,9 +692,6 @@ public class DirContextAdapter implements DirContextOperations {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.springframework.ldap.support.DirContextOperations#update()
|
||||
*/
|
||||
public void update() {
|
||||
NamingEnumeration<? extends Attribute> attributesEnumeration = null;
|
||||
|
||||
@@ -751,14 +720,9 @@ public class DirContextAdapter implements DirContextOperations {
|
||||
}
|
||||
|
||||
// Reset the attributes to be updated
|
||||
updatedAttrs = new BasicAttributes(true);
|
||||
updatedAttrs = new NameAwareAttributes();
|
||||
}
|
||||
|
||||
/*
|
||||
* @see
|
||||
* org.springframework.ldap.core.DirContextOperations#getStringAttributes
|
||||
* (java.lang.String)
|
||||
*/
|
||||
public String[] getStringAttributes(String name) {
|
||||
try {
|
||||
List<String> objects = collectAttributeValuesAsList(name, String.class);
|
||||
@@ -770,13 +734,6 @@ public class DirContextAdapter implements DirContextOperations {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see
|
||||
* org.springframework.ldap.core.DirContextOperations#getObjectAttributes
|
||||
* (java.lang.String)
|
||||
*/
|
||||
public Object[] getObjectAttributes(String name) {
|
||||
try {
|
||||
List<Object> list = collectAttributeValuesAsList(name, Object.class);
|
||||
@@ -864,7 +821,7 @@ public class DirContextAdapter implements DirContextOperations {
|
||||
throw new NameNotFoundException();
|
||||
}
|
||||
|
||||
Attributes a = new BasicAttributes(true);
|
||||
Attributes a = new NameAwareAttributes();
|
||||
Attribute target;
|
||||
for (String attrId : attrIds) {
|
||||
target = originalAttrs.get(attrId);
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
package org.springframework.ldap.core;
|
||||
|
||||
import javax.naming.NamingEnumeration;
|
||||
import javax.naming.NamingException;
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* @author Mattias Hellborg Arthursson
|
||||
*/
|
||||
final class IterableNamingEnumeration<T> implements NamingEnumeration<T> {
|
||||
private final Iterator<T> iterator;
|
||||
|
||||
IterableNamingEnumeration(Iterable<T> iterable) {
|
||||
this.iterator = iterable.iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public T next() {
|
||||
return iterator.next();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasMore() {
|
||||
return iterator.hasNext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws NamingException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasMoreElements() {
|
||||
return hasMore();
|
||||
}
|
||||
|
||||
@Override
|
||||
public T nextElement() {
|
||||
return next();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,348 @@
|
||||
/*
|
||||
* Copyright 2005-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.ldap.core;
|
||||
|
||||
import org.springframework.ldap.InvalidNameException;
|
||||
import org.springframework.ldap.support.LdapUtils;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
import javax.naming.Name;
|
||||
import javax.naming.NamingEnumeration;
|
||||
import javax.naming.NamingException;
|
||||
import javax.naming.directory.Attribute;
|
||||
import javax.naming.directory.DirContext;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Used internally to make DirContextAdapter properly handle Names as values.
|
||||
*
|
||||
* @author Mattias Hellborg Arthursson
|
||||
* @since 2.0
|
||||
*/
|
||||
public class NameAwareAttribute implements Attribute {
|
||||
|
||||
private final String id;
|
||||
private final boolean orderMatters;
|
||||
private final Set<Object> values = new LinkedHashSet<Object>();
|
||||
private Map<Name, String> valuesAsNames = new HashMap<Name, String>();
|
||||
|
||||
/**
|
||||
* Construct a new instance with the specified id and one value.
|
||||
* @param id the attribute id
|
||||
* @param value the value to start off with
|
||||
*/
|
||||
public NameAwareAttribute(String id, Object value) {
|
||||
this(id);
|
||||
values.add(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new instance from the supplied Attribute.
|
||||
*
|
||||
* @param attribute the Attribute to copy.
|
||||
*/
|
||||
public NameAwareAttribute(Attribute attribute) {
|
||||
this(attribute.getID(), attribute.isOrdered());
|
||||
try {
|
||||
NamingEnumeration<?> values = attribute.getAll();
|
||||
while(values.hasMore()) {
|
||||
this.add(values.next());
|
||||
}
|
||||
} catch (NamingException e) {
|
||||
throw LdapUtils.convertLdapException(e);
|
||||
}
|
||||
|
||||
if (attribute instanceof NameAwareAttribute) {
|
||||
NameAwareAttribute nameAwareAttribute = (NameAwareAttribute) attribute;
|
||||
populateValuesAsNames(nameAwareAttribute, this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new instance with the specified id and no values.
|
||||
* @param id the attribute id
|
||||
*/
|
||||
public NameAwareAttribute(String id) {
|
||||
this(id, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new instance with the specified id, no values and order significance as specified.
|
||||
* @param id the attribute id
|
||||
* @param orderMatters whether order has significance in this attribute.
|
||||
*/
|
||||
public NameAwareAttribute(String id, boolean orderMatters) {
|
||||
this.id = id;
|
||||
this.orderMatters = orderMatters;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NamingEnumeration<?> getAll() {
|
||||
return new IterableNamingEnumeration<Object>(values);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get() {
|
||||
if(values.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return values.iterator().next();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return values.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getID() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object attrVal) {
|
||||
return values.contains(attrVal);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(Object attrVal) {
|
||||
if (attrVal instanceof Name) {
|
||||
initValuesAsNames();
|
||||
|
||||
Name name = LdapUtils.newLdapName((Name) attrVal);
|
||||
String currentValue = valuesAsNames.get(name);
|
||||
String nameAsString = name.toString();
|
||||
if(currentValue == null) {
|
||||
valuesAsNames.put(name, name.toString());
|
||||
values.add(nameAsString);
|
||||
return true;
|
||||
} else {
|
||||
if(!currentValue.equals(nameAsString)) {
|
||||
values.remove(currentValue);
|
||||
values.add(nameAsString);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return values.add(attrVal);
|
||||
}
|
||||
|
||||
public void initValuesAsNames() {
|
||||
if(hasValuesAsNames()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Map<Name, String> valuesAsNames = new HashMap<Name, String>();
|
||||
for (Object value : values) {
|
||||
if (value instanceof String) {
|
||||
String s = (String) value;
|
||||
try {
|
||||
valuesAsNames.put(LdapUtils.newLdapName(s), s);
|
||||
} catch (InvalidNameException e) {
|
||||
throw new IllegalArgumentException("This instance has values that are not valid distinguished names; " +
|
||||
"cannot handle Name values");
|
||||
}
|
||||
} else {
|
||||
throw new IllegalArgumentException("This instance has non-string attribute values; " +
|
||||
"cannot handle Name values");
|
||||
}
|
||||
}
|
||||
|
||||
this.valuesAsNames = valuesAsNames;
|
||||
}
|
||||
|
||||
public boolean hasValuesAsNames() {
|
||||
return !valuesAsNames.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(Object attrval) {
|
||||
if (attrval instanceof Name) {
|
||||
initValuesAsNames();
|
||||
|
||||
Name name = LdapUtils.newLdapName((Name) attrval);
|
||||
String removedValue = valuesAsNames.remove(name);
|
||||
if(removedValue != null) {
|
||||
values.remove(removedValue);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
return values.remove(attrval);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
values.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DirContext getAttributeSyntaxDefinition() throws NamingException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DirContext getAttributeDefinition() throws NamingException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOrdered() {
|
||||
return orderMatters;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get(int ix) throws NamingException {
|
||||
Iterator<Object> iterator = values.iterator();
|
||||
|
||||
try {
|
||||
Object value = iterator.next();
|
||||
for(int i = 0; i < ix; i++) {
|
||||
value = iterator.next();
|
||||
}
|
||||
|
||||
return value;
|
||||
} catch (NoSuchElementException e) {
|
||||
throw new IndexOutOfBoundsException("No value at index i");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object remove(int ix) {
|
||||
Iterator<Object> iterator = values.iterator();
|
||||
|
||||
try {
|
||||
Object value = iterator.next();
|
||||
for(int i = 0; i < ix; i++) {
|
||||
value = iterator.next();
|
||||
}
|
||||
|
||||
iterator.remove();
|
||||
return value;
|
||||
} catch (NoSuchElementException e) {
|
||||
throw new IndexOutOfBoundsException("No value at index i");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(int ix, Object attrVal) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object set(int ix, Object attrVal) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object clone() {
|
||||
return new NameAwareAttribute(this);
|
||||
}
|
||||
|
||||
private void populateValuesAsNames(NameAwareAttribute from, NameAwareAttribute to) {
|
||||
Set<Map.Entry<Name, String>> entries = from.valuesAsNames.entrySet();
|
||||
for (Map.Entry<Name, String> entry : entries) {
|
||||
to.valuesAsNames.put(LdapUtils.newLdapName(entry.getKey()), entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
NameAwareAttribute that = (NameAwareAttribute) o;
|
||||
|
||||
if (id != null ? !id.equals(that.id) : that.id != null) return false;
|
||||
if(this.values.size() != that.values.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(this.orderMatters != that.orderMatters || this.size() != that.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(this.hasValuesAsNames() != that.hasValuesAsNames()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Set<?> myValues = this.values;
|
||||
Set<?> theirValues = that.values;
|
||||
if(this.hasValuesAsNames()) {
|
||||
// We have Name values - compare these to get
|
||||
// syntactically correct comparison of the values
|
||||
|
||||
myValues = this.valuesAsNames.keySet();
|
||||
theirValues = that.valuesAsNames.keySet();
|
||||
}
|
||||
|
||||
if(orderMatters) {
|
||||
Iterator<?> thisIterator = myValues.iterator();
|
||||
Iterator<?> thatIterator = theirValues.iterator();
|
||||
while(thisIterator.hasNext()) {
|
||||
if(!ObjectUtils.nullSafeEquals(thisIterator.next(), thatIterator.next())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
} else {
|
||||
for (Object value : myValues) {
|
||||
if(!CollectionUtils.contains(theirValues.iterator(), value)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = id != null ? id.hashCode() : 0;
|
||||
|
||||
int valuesHash = 7;
|
||||
Set<?> myValues = this.values;
|
||||
if(hasValuesAsNames()) {
|
||||
myValues = valuesAsNames.keySet();
|
||||
}
|
||||
|
||||
for (Object value : myValues) {
|
||||
result += ObjectUtils.nullSafeHashCode(value);
|
||||
}
|
||||
result = 31 * result + valuesHash;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("NameAwareAttribute; id: %s; hasValuesAsNames: %s; orderMatters: %s; values: %s",
|
||||
id, hasValuesAsNames(), orderMatters, values);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Copyright 2005-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.ldap.core;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import javax.naming.NamingEnumeration;
|
||||
import javax.naming.directory.Attribute;
|
||||
import javax.naming.directory.Attributes;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Used internally to help DirContextAdapter properly handle Names as values.
|
||||
*
|
||||
* @author Mattias Hellborg Arthursson
|
||||
* @since 2.0
|
||||
*/
|
||||
public class NameAwareAttributes implements Attributes {
|
||||
private Map<String, NameAwareAttribute> attributes = new HashMap<String, NameAwareAttribute>();
|
||||
|
||||
/**
|
||||
* Create an empty instance
|
||||
*/
|
||||
public NameAwareAttributes() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new instance, populated with the data from the supplied instance.
|
||||
* @param attributes the instance to copy.
|
||||
*/
|
||||
public NameAwareAttributes(Attributes attributes) {
|
||||
NamingEnumeration<? extends Attribute> allAttributes = attributes.getAll();
|
||||
while(allAttributes.hasMoreElements()) {
|
||||
Attribute attribute = allAttributes.nextElement();
|
||||
put(new NameAwareAttribute(attribute));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCaseIgnored() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return attributes.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public NameAwareAttribute get(String attrID) {
|
||||
Assert.hasLength(attrID, "Attribute ID must not be empty");
|
||||
return attributes.get(attrID.toLowerCase());
|
||||
}
|
||||
|
||||
@Override
|
||||
public NamingEnumeration<? extends Attribute> getAll() {
|
||||
return new IterableNamingEnumeration<NameAwareAttribute>(attributes.values());
|
||||
}
|
||||
|
||||
@Override
|
||||
public NamingEnumeration<String> getIDs() {
|
||||
return new IterableNamingEnumeration<String>(attributes.keySet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Attribute put(String attrID, Object val) {
|
||||
Assert.hasLength(attrID, "Attribute ID must not be empty");
|
||||
NameAwareAttribute newAttribute = new NameAwareAttribute(attrID, val);
|
||||
attributes.put(attrID.toLowerCase(), newAttribute);
|
||||
|
||||
return newAttribute;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Attribute put(Attribute attr) {
|
||||
Assert.notNull(attr, "Attribute must not be null");
|
||||
NameAwareAttribute newAttribute = new NameAwareAttribute(attr);
|
||||
attributes.put(attr.getID().toLowerCase(), newAttribute);
|
||||
|
||||
return newAttribute;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Attribute remove(String attrID) {
|
||||
Assert.hasLength(attrID, "Attribute ID must not be empty");
|
||||
return attributes.remove(attrID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object clone() {
|
||||
return new NameAwareAttributes(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
NameAwareAttributes that = (NameAwareAttributes) o;
|
||||
|
||||
if (attributes != null ? !attributes.equals(that.attributes) : that.attributes != null) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return attributes != null ? attributes.hashCode() : 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("NameAwareAttribute; attributes: %s", attributes.toString());
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.springframework.ldap.odm.core.impl;
|
||||
|
||||
import org.springframework.ldap.UncategorizedLdapException;
|
||||
import org.springframework.ldap.odm.annotations.Attribute;
|
||||
import org.springframework.ldap.odm.annotations.DnAttribute;
|
||||
import org.springframework.ldap.odm.annotations.Id;
|
||||
@@ -27,8 +28,13 @@ import java.lang.reflect.Field;
|
||||
import java.lang.reflect.GenericArrayType;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
|
||||
/*
|
||||
* Extract attribute meta-data from the @Attribute annotation, the @Id annotation
|
||||
@@ -60,8 +66,10 @@ import java.util.Set;
|
||||
private boolean isId;
|
||||
|
||||
// Is this field multi-valued represented by a List
|
||||
private boolean isList;
|
||||
|
||||
private boolean isCollection;
|
||||
|
||||
private Class<? extends Collection> collectionClass;
|
||||
|
||||
// Is this the objectClass attribute
|
||||
private boolean isObjectClass;
|
||||
|
||||
@@ -112,18 +120,14 @@ import java.util.Set;
|
||||
// Determine the class of data stored in the field
|
||||
Class<?> fieldType = field.getType();
|
||||
|
||||
// We support only lists for multi-valued attributes, as we must allow duplicate values
|
||||
if (Set.class.isAssignableFrom(fieldType)) {
|
||||
throw new MetaDataException(String.format("Only lists are allowed for multivlaued attributes, errpr in field %1$s in Entry class %2$s",
|
||||
field, field.getDeclaringClass()));
|
||||
}
|
||||
isList = List.class.isAssignableFrom(fieldType);
|
||||
isCollection = Collection.class.isAssignableFrom(fieldType);
|
||||
|
||||
valueClass=null;
|
||||
if (!isList) {
|
||||
if (!isCollection) {
|
||||
// It's not a list so assume its single valued - so just take the field type
|
||||
valueClass = fieldType;
|
||||
} else {
|
||||
determineCollectionClass(fieldType);
|
||||
// It's multi-valued - so we need to look at the signature in
|
||||
// the class file to find the generic type - this is supported for class file
|
||||
// format 49 and greater which corresponds to java 5 and later.
|
||||
@@ -156,7 +160,33 @@ import java.util.Set;
|
||||
field, field.getDeclaringClass()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void determineCollectionClass(Class<?> fieldType) {
|
||||
if(fieldType.isInterface()) {
|
||||
if(Collection.class.equals(fieldType) || List.class.equals(fieldType)) {
|
||||
collectionClass = ArrayList.class;
|
||||
} else if(SortedSet.class.equals(fieldType)) {
|
||||
collectionClass = TreeSet.class;
|
||||
} else if(Set.class.isAssignableFrom(fieldType)) {
|
||||
collectionClass = LinkedHashSet.class;
|
||||
} else {
|
||||
throw new MetaDataException(String.format("Collection class %s is not supported", fieldType));
|
||||
}
|
||||
} else {
|
||||
collectionClass = (Class<? extends Collection>) fieldType;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public Collection<Object> newCollectionInstance() {
|
||||
try {
|
||||
return (Collection<Object>) collectionClass.newInstance();
|
||||
} catch (Exception e) {
|
||||
throw new UncategorizedLdapException("Failed to instantiate collection class", e);
|
||||
}
|
||||
}
|
||||
|
||||
// Extract information from the @Id annotation:
|
||||
// isId
|
||||
private boolean processIdAnnotation(Field field, Class<?> fieldType) {
|
||||
@@ -210,7 +240,7 @@ import java.util.Set;
|
||||
}
|
||||
|
||||
// If this is the objectclass attribute then it must be of type List<String>
|
||||
if (isObjectClass() && (!isList() || valueClass!=String.class)) {
|
||||
if (isObjectClass() && (!isCollection() || valueClass!=String.class)) {
|
||||
throw new MetaDataException(String.format("The type of the objectclass attribute must be List<String> in classs %1$s",
|
||||
field.getDeclaringClass()));
|
||||
}
|
||||
@@ -233,8 +263,8 @@ import java.util.Set;
|
||||
return name;
|
||||
}
|
||||
|
||||
public boolean isList() {
|
||||
return isList;
|
||||
public boolean isCollection() {
|
||||
return isCollection;
|
||||
}
|
||||
|
||||
public boolean isId() {
|
||||
@@ -261,6 +291,16 @@ import java.util.Set;
|
||||
return valueClass;
|
||||
}
|
||||
|
||||
public Class<?> getJndiClass() {
|
||||
if(isBinary()) {
|
||||
return byte[].class;
|
||||
} else if(Name.class.isAssignableFrom(valueClass)) {
|
||||
return Name.class;
|
||||
} else {
|
||||
return String.class;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
@@ -269,6 +309,6 @@ import java.util.Set;
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("name=%1$s | field=%2$s | valueClass=%3$s | syntax=%4$s| isBinary=%5$s | isId=%6$s | isList=%7$s | isObjectClass=%8$s",
|
||||
getName(), getField(), getValueClass().getName(), getSyntax(), isBinary(), isId(), isList(), isObjectClass());
|
||||
getName(), getField(), getValueClass().getName(), getSyntax(), isBinary(), isId(), isCollection(), isObjectClass());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,12 +19,14 @@ package org.springframework.ldap.odm.core.impl;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.LdapDataEntry;
|
||||
import org.springframework.core.SpringVersion;
|
||||
import org.springframework.ldap.filter.AndFilter;
|
||||
import org.springframework.ldap.filter.EqualsFilter;
|
||||
import org.springframework.ldap.filter.Filter;
|
||||
import org.springframework.ldap.odm.annotations.DnAttribute;
|
||||
import org.springframework.ldap.odm.core.ObjectDirectoryMapper;
|
||||
import org.springframework.ldap.odm.typeconversion.ConverterManager;
|
||||
import org.springframework.ldap.odm.typeconversion.impl.ConversionServiceConverterManager;
|
||||
import org.springframework.ldap.odm.typeconversion.impl.ConverterManagerImpl;
|
||||
import org.springframework.ldap.support.LdapNameBuilder;
|
||||
import org.springframework.ldap.support.LdapUtils;
|
||||
@@ -66,7 +68,16 @@ public class DefaultObjectDirectoryMapper implements ObjectDirectoryMapper {
|
||||
|
||||
|
||||
public DefaultObjectDirectoryMapper() {
|
||||
this.converterManager = new ConverterManagerImpl();
|
||||
if(isAtLeast30()) {
|
||||
this.converterManager = new ConversionServiceConverterManager();
|
||||
} else {
|
||||
this.converterManager = new ConverterManagerImpl();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private boolean isAtLeast30() {
|
||||
return SpringVersion.getVersion().compareTo("3.0") > 0;
|
||||
}
|
||||
|
||||
public void setConverterManager(ConverterManager converterManager) {
|
||||
@@ -126,7 +137,7 @@ public class DefaultObjectDirectoryMapper implements ObjectDirectoryMapper {
|
||||
for (Field field : metaData) {
|
||||
AttributeMetaData attributeInfo = metaData.getAttribute(field);
|
||||
if (!attributeInfo.isTransient() && !attributeInfo.isId() && !(attributeInfo.isObjectClass())) {
|
||||
Class<?> jndiClass = (attributeInfo.isBinary()) ? byte[].class : String.class;
|
||||
Class<?> jndiClass = attributeInfo.getJndiClass();
|
||||
Class<?> javaClass = attributeInfo.getValueClass();
|
||||
if (!converterManager.canConvert(jndiClass, attributeInfo.getSyntax(), javaClass)) {
|
||||
throw new InvalidEntryException(String.format(
|
||||
@@ -184,9 +195,9 @@ public class DefaultObjectDirectoryMapper implements ObjectDirectoryMapper {
|
||||
if (!attributeInfo.isTransient() && !attributeInfo.isId() && !(attributeInfo.isObjectClass())) {
|
||||
try {
|
||||
// If this is a "binary" object the JNDI expects a byte[] otherwise a String
|
||||
Class<?> targetClass = (attributeInfo.isBinary()) ? byte[].class : String.class;
|
||||
Class<?> targetClass = attributeInfo.getJndiClass();
|
||||
// Multi valued?
|
||||
if (!attributeInfo.isList()) {
|
||||
if (!attributeInfo.isCollection()) {
|
||||
populateSingleValueAttribute(entry, context, field, attributeInfo, targetClass);
|
||||
|
||||
} else {
|
||||
@@ -204,7 +215,7 @@ public class DefaultObjectDirectoryMapper implements ObjectDirectoryMapper {
|
||||
|
||||
private void populateMultiValueAttribute(Object entry, LdapDataEntry context, Field field, AttributeMetaData attributeInfo, Class<?> targetClass) throws IllegalAccessException {
|
||||
// We need to build up a list of of the values
|
||||
List<String> attributeValues = new ArrayList<String>();
|
||||
List<Object> attributeValues = new ArrayList<Object>();
|
||||
// Get the list of values
|
||||
Collection<?> fieldValues = (Collection<?>)field.get(entry);
|
||||
// Ignore null lists
|
||||
@@ -212,7 +223,7 @@ public class DefaultObjectDirectoryMapper implements ObjectDirectoryMapper {
|
||||
for (final Object o : fieldValues) {
|
||||
// Ignore null values
|
||||
if (o != null) {
|
||||
attributeValues.add((String)converterManager.convert(o, attributeInfo.getSyntax(),
|
||||
attributeValues.add(converterManager.convert(o, attributeInfo.getSyntax(),
|
||||
targetClass));
|
||||
}
|
||||
}
|
||||
@@ -269,7 +280,7 @@ public class DefaultObjectDirectoryMapper implements ObjectDirectoryMapper {
|
||||
Name dn = context.getDn();
|
||||
if (!attributeInfo.isTransient() && !attributeInfo.isId()) {
|
||||
// Not the ID - but is is multi valued?
|
||||
if (!attributeInfo.isList()) {
|
||||
if (!attributeInfo.isCollection()) {
|
||||
// No - its single valued, grab the JNDI attribute that corresponds to the metadata on the
|
||||
// current field
|
||||
populateSingleValueField(result, attributeValueMap, field, attributeInfo);
|
||||
@@ -326,7 +337,7 @@ public class DefaultObjectDirectoryMapper implements ObjectDirectoryMapper {
|
||||
|
||||
private <T> void populateMultiValueField(T result, Map<CaseIgnoreString, Attribute> attributeValueMap, Field field, AttributeMetaData attributeInfo) throws NamingException, IllegalAccessException {
|
||||
// We need to build up a list of values
|
||||
List<Object> fieldValues = new ArrayList<Object>();
|
||||
Collection<Object> fieldValues = attributeInfo.newCollectionInstance();
|
||||
// Grab the attribute from the JNDI representation
|
||||
Attribute currentAttribute = attributeValueMap.get(attributeInfo.getName());
|
||||
// There is no guarantee that this attribute is present in the directory - so ignore nulls
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright 2005-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.ldap.odm.typeconversion.impl;
|
||||
|
||||
import org.springframework.core.convert.support.GenericConversionService;
|
||||
import org.springframework.ldap.odm.typeconversion.ConverterManager;
|
||||
import org.springframework.ldap.support.LdapUtils;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
import javax.naming.Name;
|
||||
|
||||
/**
|
||||
* @author Mattias Hellborg Arthursson
|
||||
* @since 2.0
|
||||
*/
|
||||
public class ConversionServiceConverterManager implements ConverterManager {
|
||||
private GenericConversionService conversionService;
|
||||
private final static String DEFAULT_CONVERSION_SERVICE_CLASS =
|
||||
"org.springframework.core.convert.support.DefaultConversionService";
|
||||
|
||||
public ConversionServiceConverterManager(GenericConversionService conversionService) {
|
||||
this.conversionService = conversionService;
|
||||
}
|
||||
|
||||
public ConversionServiceConverterManager() {
|
||||
ClassLoader defaultClassLoader = ClassUtils.getDefaultClassLoader();
|
||||
if(ClassUtils.isPresent(DEFAULT_CONVERSION_SERVICE_CLASS, defaultClassLoader)) {
|
||||
try {
|
||||
Class<?> clazz = ClassUtils.forName(DEFAULT_CONVERSION_SERVICE_CLASS, defaultClassLoader);
|
||||
conversionService = (GenericConversionService) clazz.newInstance();
|
||||
} catch (Exception e) {
|
||||
ReflectionUtils.handleReflectionException(e);
|
||||
}
|
||||
} else {
|
||||
conversionService = new GenericConversionService();
|
||||
}
|
||||
|
||||
prePopulateWithNameConverter();
|
||||
}
|
||||
|
||||
private void prePopulateWithNameConverter() {
|
||||
conversionService.addConverter(new StringToNameConverter());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canConvert(Class<?> fromClass, String syntax, Class<?> toClass) {
|
||||
return conversionService.canConvert(fromClass, toClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T convert(Object source, String syntax, Class<T> toClass) {
|
||||
return conversionService.convert(source, toClass);
|
||||
}
|
||||
|
||||
public final static class NameToStringConverter
|
||||
implements org.springframework.core.convert.converter.Converter<Name, String> {
|
||||
@Override
|
||||
public String convert(Name source) {
|
||||
if(source == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return source.toString();
|
||||
}
|
||||
}
|
||||
|
||||
public final static class StringToNameConverter
|
||||
implements org.springframework.core.convert.converter.Converter<String, Name> {
|
||||
|
||||
@Override
|
||||
public Name convert(String source) {
|
||||
if(source == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return LdapUtils.newLdapName(source);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package org.springframework.ldap.odm.typeconversion.impl;
|
||||
|
||||
/**
|
||||
* @author Mattias Hellborg Arthursson
|
||||
*/
|
||||
public class StringConverter {
|
||||
}
|
||||
@@ -42,7 +42,7 @@ import static org.junit.Assert.fail;
|
||||
|
||||
/**
|
||||
* Tests the DirContextAdapter class.
|
||||
*
|
||||
*
|
||||
* @author Andreas Ronge
|
||||
* @author Mattias Hellborg Arthursson
|
||||
* @author Ulrik Sandberg
|
||||
@@ -1114,7 +1114,7 @@ public class DirContextAdapterTest {
|
||||
/**
|
||||
* Test for LDAP-15: DirContextAdapter.setAttribute(). Verifies that setting
|
||||
* an Attribute should modify updatedAttrs if in update mode.
|
||||
*
|
||||
*
|
||||
* @throws NamingException
|
||||
*/
|
||||
@Test
|
||||
@@ -1223,4 +1223,133 @@ public class DirContextAdapterTest {
|
||||
DirContextAdapter tested = new DirContextAdapter("cn=john doe, ou=company");
|
||||
assertEquals(LdapUtils.newLdapName("cn=john doe, ou=company"), tested.getDn());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddDnAttributeValueIdentical() {
|
||||
BasicAttributes attributes = new BasicAttributes();
|
||||
attributes.put("uniqueMember", "cn=john doe, ou=company");
|
||||
|
||||
DirContextAdapter tested = new DirContextAdapter(attributes, LdapUtils.newLdapName("cn=administrators, ou=groups"));
|
||||
tested.setUpdateMode(true);
|
||||
|
||||
tested.addAttributeValue("uniqueMember", LdapUtils.newLdapName("cn=john doe, ou=company"));
|
||||
ModificationItem[] modificationItems = tested.getModificationItems();
|
||||
assertEquals(0, modificationItems.length);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddDnAttributeSyntacticallyEqual() {
|
||||
BasicAttributes attributes = new BasicAttributes();
|
||||
attributes.put("uniqueMember", "cn=john doe,OU=company");
|
||||
|
||||
DirContextAdapter tested = new DirContextAdapter(attributes, LdapUtils.newLdapName("cn=administrators, ou=groups"));
|
||||
tested.setUpdateMode(true);
|
||||
|
||||
tested.addAttributeValue("uniqueMember", LdapUtils.newLdapName("cn=john doe, ou=company"));
|
||||
ModificationItem[] modificationItems = tested.getModificationItems();
|
||||
assertEquals(0, modificationItems.length);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemoveDnAttributeSyntacticallyEqual() throws NamingException {
|
||||
BasicAttributes attributes = new BasicAttributes();
|
||||
attributes.put("uniqueMember", "cn=john doe,OU=company");
|
||||
|
||||
DirContextAdapter tested = new DirContextAdapter(attributes, LdapUtils.newLdapName("cn=administrators, ou=groups"));
|
||||
tested.setUpdateMode(true);
|
||||
|
||||
tested.removeAttributeValue("uniqueMember", LdapUtils.newLdapName("cn=john doe, ou=company"));
|
||||
ModificationItem[] modificationItems = tested.getModificationItems();
|
||||
assertEquals(1, modificationItems.length);
|
||||
|
||||
ModificationItem modificationItem = modificationItems[0];
|
||||
assertEquals(DirContext.REMOVE_ATTRIBUTE, modificationItem.getModificationOp());
|
||||
assertEquals("uniqueMember", modificationItem.getAttribute().getID());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemoveOneOfSeveralDnAttributeSyntacticallyEqual() throws NamingException {
|
||||
BasicAttributes attributes = new BasicAttributes();
|
||||
BasicAttribute attribute = new BasicAttribute("uniqueMember", "cn=john doe,OU=company");
|
||||
attribute.add("cn=jane doe, ou=company");
|
||||
attributes.put(attribute);
|
||||
|
||||
DirContextAdapter tested = new DirContextAdapter(attributes, LdapUtils.newLdapName("cn=administrators, ou=groups"));
|
||||
tested.setUpdateMode(true);
|
||||
|
||||
tested.removeAttributeValue("uniqueMember", LdapUtils.newLdapName("cn=john doe, ou=company"));
|
||||
ModificationItem[] modificationItems = tested.getModificationItems();
|
||||
assertEquals(1, modificationItems.length);
|
||||
|
||||
ModificationItem modificationItem = modificationItems[0];
|
||||
assertEquals(DirContext.REMOVE_ATTRIBUTE, modificationItem.getModificationOp());
|
||||
assertEquals("uniqueMember", modificationItem.getAttribute().getID());
|
||||
assertEquals("cn=john doe,OU=company", modificationItem.getAttribute().get());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddDnAttributeNewValue() throws NamingException {
|
||||
BasicAttributes attributes = new BasicAttributes();
|
||||
attributes.put("uniqueMember", "cn=john doe, ou=company");
|
||||
|
||||
DirContextAdapter tested = new DirContextAdapter(attributes, LdapUtils.newLdapName("cn=administrators, ou=groups"));
|
||||
tested.setUpdateMode(true);
|
||||
|
||||
tested.addAttributeValue("uniqueMember", LdapUtils.newLdapName("cn=jane doe, ou=company"));
|
||||
ModificationItem[] modificationItems = tested.getModificationItems();
|
||||
assertEquals(1, modificationItems.length);
|
||||
|
||||
ModificationItem modificationItem = modificationItems[0];
|
||||
assertEquals(DirContext.ADD_ATTRIBUTE, modificationItem.getModificationOp());
|
||||
assertEquals("uniqueMember", modificationItem.getAttribute().getID());
|
||||
assertEquals("cn=jane doe, ou=company", modificationItem.getAttribute().get());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetDnAttributeValueIdentical() {
|
||||
BasicAttributes attributes = new BasicAttributes();
|
||||
attributes.put("uniqueMember", "cn=john doe, ou=company");
|
||||
|
||||
DirContextAdapter tested = new DirContextAdapter(attributes, LdapUtils.newLdapName("cn=administrators, ou=groups"));
|
||||
tested.setUpdateMode(true);
|
||||
|
||||
tested.setAttributeValue("uniqueMember", LdapUtils.newLdapName("cn=john doe, ou=company"));
|
||||
ModificationItem[] modificationItems = tested.getModificationItems();
|
||||
assertEquals(0, modificationItems.length);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetDnAttributesValueIdentical() {
|
||||
BasicAttributes attributes = new BasicAttributes();
|
||||
attributes.put("uniqueMember", "cn=john doe, ou=company");
|
||||
|
||||
DirContextAdapter tested = new DirContextAdapter(attributes, LdapUtils.newLdapName("cn=administrators, ou=groups"));
|
||||
tested.setUpdateMode(true);
|
||||
|
||||
tested.setAttributeValues("uniqueMember", new Object[]{LdapUtils.newLdapName("cn=john doe, ou=company")});
|
||||
ModificationItem[] modificationItems = tested.getModificationItems();
|
||||
assertEquals(0, modificationItems.length);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetDnAttributesValuesOneNewEntry() throws NamingException {
|
||||
BasicAttributes attributes = new BasicAttributes();
|
||||
attributes.put("uniqueMember", "cn=john doe, ou=company");
|
||||
|
||||
DirContextAdapter tested = new DirContextAdapter(attributes, LdapUtils.newLdapName("cn=administrators, ou=groups"));
|
||||
tested.setUpdateMode(true);
|
||||
|
||||
tested.setAttributeValues("uniqueMember", new Object[]{
|
||||
LdapUtils.newLdapName("cn=john doe, ou=company"),
|
||||
LdapUtils.newLdapName("cn=jane doe, ou=company")
|
||||
});
|
||||
|
||||
ModificationItem[] modificationItems = tested.getModificationItems();
|
||||
assertEquals(1, modificationItems.length);
|
||||
|
||||
ModificationItem modificationItem = modificationItems[0];
|
||||
assertEquals(DirContext.ADD_ATTRIBUTE, modificationItem.getModificationOp());
|
||||
assertEquals("uniqueMember", modificationItem.getAttribute().getID());
|
||||
assertEquals("cn=jane doe, ou=company", modificationItem.getAttribute().get());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,247 @@
|
||||
package org.springframework.ldap.core;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.ldap.support.LdapUtils;
|
||||
|
||||
import javax.naming.NamingException;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* @author Mattias Hellborg Arthursson
|
||||
*/
|
||||
public class NameAwareAttributeTest {
|
||||
@Test
|
||||
public void testEqualsWithIdNotSame() {
|
||||
NameAwareAttribute attr1 = new NameAwareAttribute("someAttribute");
|
||||
NameAwareAttribute attr2 = new NameAwareAttribute("someOtherAttribute");
|
||||
|
||||
assertFalse(attr1.equals(attr2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEqualsWithSameIdNoValues() {
|
||||
NameAwareAttribute attr1 = new NameAwareAttribute("someAttribute");
|
||||
NameAwareAttribute attr2 = new NameAwareAttribute("someAttribute");
|
||||
|
||||
assertTrue(attr1.equals(attr2));
|
||||
assertEquals(attr1.hashCode(), attr2.hashCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEqualsUnorderedWithIdenticalAttributes() {
|
||||
NameAwareAttribute attr1 = new NameAwareAttribute("someAttribute");
|
||||
attr1.add("value1");
|
||||
attr1.add("value2");
|
||||
attr1.add("value3");
|
||||
NameAwareAttribute attr2 = new NameAwareAttribute("someAttribute");
|
||||
attr2.add("value1");
|
||||
attr2.add("value2");
|
||||
attr2.add("value3");
|
||||
|
||||
assertTrue(attr1.equals(attr2));
|
||||
assertEquals(attr1.hashCode(), attr2.hashCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEqualsUnorderedWithIdenticalArrayAttributes() {
|
||||
NameAwareAttribute attr1 = new NameAwareAttribute("someAttribute");
|
||||
attr1.add(new byte[]{1, 2, 3});
|
||||
attr1.add(new byte[]{3, 2, 1});
|
||||
attr1.add(new byte[]{1});
|
||||
NameAwareAttribute attr2 = new NameAwareAttribute("someAttribute");
|
||||
attr2.add(new byte[]{1, 2, 3});
|
||||
attr2.add(new byte[]{3, 2, 1});
|
||||
attr2.add(new byte[]{1});
|
||||
|
||||
assertTrue(attr1.equals(attr2));
|
||||
assertEquals(attr1.hashCode(), attr2.hashCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEqualsUnorderedWithDifferentOrderArrayAttributes() {
|
||||
NameAwareAttribute attr1 = new NameAwareAttribute("someAttribute");
|
||||
attr1.add(new byte[]{1, 2, 3});
|
||||
attr1.add(new byte[]{3, 2, 1});
|
||||
attr1.add(new byte[]{1});
|
||||
NameAwareAttribute attr2 = new NameAwareAttribute("someAttribute");
|
||||
attr2.add(new byte[]{3, 2, 1});
|
||||
attr2.add(new byte[]{1});
|
||||
attr2.add(new byte[]{1, 2, 3});
|
||||
|
||||
assertTrue(attr1.equals(attr2));
|
||||
assertEquals(attr1.hashCode(), attr2.hashCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEqualsUnorderedWithDifferentArrayAttributes() {
|
||||
NameAwareAttribute attr1 = new NameAwareAttribute("someAttribute");
|
||||
attr1.add(new byte[]{1, 2, 3});
|
||||
attr1.add(new byte[]{3, 2, 2});
|
||||
attr1.add(new byte[]{1});
|
||||
NameAwareAttribute attr2 = new NameAwareAttribute("someAttribute");
|
||||
attr2.add(new byte[]{1, 2, 3});
|
||||
attr2.add(new byte[]{3, 2, 1});
|
||||
attr2.add(new byte[]{1});
|
||||
|
||||
assertFalse(attr1.equals(attr2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEqualsUnorderedWithDifferentNumberOfArrayAttributes() {
|
||||
NameAwareAttribute attr1 = new NameAwareAttribute("someAttribute");
|
||||
attr1.add(new byte[]{1, 2, 3});
|
||||
attr1.add(new byte[]{3, 2, 1});
|
||||
attr1.add(new byte[]{1});
|
||||
NameAwareAttribute attr2 = new NameAwareAttribute("someAttribute");
|
||||
attr2.add(new byte[]{1, 2, 3});
|
||||
attr2.add(new byte[]{1});
|
||||
|
||||
assertFalse(attr1.equals(attr2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEqualsOrderedWithIdenticalArrayAttributes() {
|
||||
NameAwareAttribute attr1 = new NameAwareAttribute("someAttribute", true);
|
||||
attr1.add(new byte[]{1, 2, 3});
|
||||
attr1.add(new byte[]{3, 2, 1});
|
||||
attr1.add(new byte[]{1});
|
||||
NameAwareAttribute attr2 = new NameAwareAttribute("someAttribute", true);
|
||||
attr2.add(new byte[]{1, 2, 3});
|
||||
attr2.add(new byte[]{3, 2, 1});
|
||||
attr2.add(new byte[]{1});
|
||||
|
||||
assertTrue(attr1.equals(attr2));
|
||||
assertEquals(attr1.hashCode(), attr2.hashCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEqualsOrderedWithArrayAttributes() {
|
||||
NameAwareAttribute attr1 = new NameAwareAttribute("someAttribute", true);
|
||||
attr1.add(new byte[]{1, 2, 3});
|
||||
attr1.add(new byte[]{3, 2, 1});
|
||||
attr1.add(new byte[]{1});
|
||||
NameAwareAttribute attr2 = new NameAwareAttribute("someAttribute", true);
|
||||
attr2.add(new byte[]{1, 2, 3});
|
||||
attr2.add(new byte[]{3, 2, 1});
|
||||
attr2.add(new byte[]{1});
|
||||
|
||||
assertTrue(attr1.equals(attr2));
|
||||
assertEquals(attr1.hashCode(), attr2.hashCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEqualsOrderedWithDifferentOrderArrayAttributes() {
|
||||
NameAwareAttribute attr1 = new NameAwareAttribute("someAttribute", true);
|
||||
attr1.add(new byte[]{1, 2, 3});
|
||||
attr1.add(new byte[]{3, 2, 1});
|
||||
attr1.add(new byte[]{1});
|
||||
NameAwareAttribute attr2 = new NameAwareAttribute("someAttribute", true);
|
||||
attr2.add(new byte[]{3, 2, 1});
|
||||
attr2.add(new byte[]{1});
|
||||
attr2.add(new byte[]{1, 2, 3});
|
||||
|
||||
assertFalse(attr1.equals(attr2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSameDistinguishedNameValue() throws NamingException {
|
||||
String expectedName = "cn=John Doe,ou=People";
|
||||
|
||||
NameAwareAttribute attr1 = new NameAwareAttribute("someAttribute");
|
||||
attr1.add(LdapUtils.newLdapName(expectedName));
|
||||
NameAwareAttribute attr2 = new NameAwareAttribute("someAttribute");
|
||||
attr2.add(LdapUtils.newLdapName(expectedName));
|
||||
|
||||
assertEquals(attr1, attr2);
|
||||
assertEquals(attr1.hashCode(), attr2.hashCode());
|
||||
assertEquals(expectedName, attr1.get());
|
||||
assertEquals(expectedName, attr2.get());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEqualDistinguishedNameValue() throws NamingException {
|
||||
// The names here are syntactically equal, but differ in exact string representation
|
||||
String expectedName1 = "cn=John Doe, OU=People";
|
||||
String expectedName2 = "cn=John Doe,ou=People";
|
||||
|
||||
NameAwareAttribute attr1 = new NameAwareAttribute("someAttribute");
|
||||
attr1.add(LdapUtils.newLdapName(expectedName1));
|
||||
NameAwareAttribute attr2 = new NameAwareAttribute("someAttribute");
|
||||
attr2.add(LdapUtils.newLdapName(expectedName2));
|
||||
|
||||
assertEquals(attr1, attr2);
|
||||
assertEquals(attr1.hashCode(), attr2.hashCode());
|
||||
assertEquals(expectedName1, attr1.get());
|
||||
assertEquals(expectedName2, attr2.get());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEqualDistinguishedNameValueUninitialized() throws NamingException {
|
||||
// The names here are syntactically equal, but differ in exact string representation
|
||||
String expectedName1 = "cn=John Doe, OU=People";
|
||||
String expectedName2 = "cn=John Doe,ou=People";
|
||||
|
||||
NameAwareAttribute attr1 = new NameAwareAttribute("someAttribute");
|
||||
attr1.add(expectedName1);
|
||||
NameAwareAttribute attr2 = new NameAwareAttribute("someAttribute");
|
||||
attr2.add(LdapUtils.newLdapName(expectedName2));
|
||||
|
||||
assertFalse(attr1.equals(attr2));
|
||||
assertEquals(expectedName1, attr1.get());
|
||||
assertEquals(expectedName2, attr2.get());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEqualDistinguishedNameValueManuallyInitialized() throws NamingException {
|
||||
// The names here are syntactically equal, but differ in exact string representation
|
||||
String expectedName1 = "cn=John Doe, OU=People";
|
||||
String expectedName2 = "cn=John Doe,ou=People";
|
||||
|
||||
NameAwareAttribute attr1 = new NameAwareAttribute("someAttribute");
|
||||
attr1.add(expectedName1);
|
||||
NameAwareAttribute attr2 = new NameAwareAttribute("someAttribute");
|
||||
attr2.add(LdapUtils.newLdapName(expectedName2));
|
||||
|
||||
attr1.initValuesAsNames();
|
||||
|
||||
assertTrue(attr1.equals(attr2));
|
||||
assertEquals(attr1.hashCode(), attr2.hashCode());
|
||||
assertEquals(expectedName1, attr1.get());
|
||||
assertEquals(expectedName2, attr2.get());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnequalDistinguishedNameValue() throws NamingException {
|
||||
// The names here are syntactically equal, but differ in exact string representation
|
||||
String expectedName1 = "cn=Jane Doe,ou=People";
|
||||
String expectedName2 = "cn=John Doe,ou=People";
|
||||
|
||||
NameAwareAttribute attr1 = new NameAwareAttribute("someAttribute");
|
||||
attr1.add(LdapUtils.newLdapName(expectedName1));
|
||||
NameAwareAttribute attr2 = new NameAwareAttribute("someAttribute");
|
||||
attr2.add(LdapUtils.newLdapName(expectedName2));
|
||||
|
||||
assertFalse(attr1.equals(attr2));
|
||||
assertEquals(expectedName1, attr1.get());
|
||||
assertEquals(expectedName2, attr2.get());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testComparingWDistinguishedNameValueWithInvalidName() throws NamingException {
|
||||
// The names here are syntactically equal, but differ in exact string representation
|
||||
String expectedName1 = "cn=Jane Doe,ou=People";
|
||||
String expectedValue2 = "thisisnotavaliddn";
|
||||
|
||||
NameAwareAttribute attr1 = new NameAwareAttribute("someAttribute");
|
||||
attr1.add(LdapUtils.newLdapName(expectedName1));
|
||||
NameAwareAttribute attr2 = new NameAwareAttribute("someAttribute");
|
||||
attr2.add(expectedValue2);
|
||||
|
||||
assertFalse(attr1.equals(attr2));
|
||||
assertEquals(expectedName1, attr1.get());
|
||||
assertEquals(expectedValue2, attr2.get());
|
||||
}
|
||||
}
|
||||
@@ -18,12 +18,14 @@ package org.springframework.ldap.core.support;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.ldap.core.DirContextAdapter;
|
||||
import org.springframework.ldap.core.NameAwareAttributes;
|
||||
import org.springframework.ldap.support.LdapUtils;
|
||||
|
||||
import javax.naming.CompositeName;
|
||||
import javax.naming.Context;
|
||||
import javax.naming.InvalidNameException;
|
||||
import javax.naming.Name;
|
||||
import javax.naming.directory.Attributes;
|
||||
import javax.naming.directory.BasicAttributes;
|
||||
import java.util.Hashtable;
|
||||
|
||||
@@ -54,7 +56,7 @@ public class DefaultDirObjectFactoryTest {
|
||||
|
||||
@Test
|
||||
public void testGetObjectInstance() throws Exception {
|
||||
BasicAttributes expectedAttributes = new BasicAttributes();
|
||||
Attributes expectedAttributes = new NameAwareAttributes();
|
||||
expectedAttributes.put("someAttribute", "someValue");
|
||||
|
||||
DirContextAdapter adapter = (DirContextAdapter) tested.getObjectInstance(contextMock, DN, null,
|
||||
@@ -68,7 +70,7 @@ public class DefaultDirObjectFactoryTest {
|
||||
|
||||
@Test
|
||||
public void testGetObjectInstance_CompositeName() throws Exception {
|
||||
BasicAttributes expectedAttributes = new BasicAttributes();
|
||||
Attributes expectedAttributes = new NameAwareAttributes();
|
||||
expectedAttributes.put("someAttribute", "someValue");
|
||||
|
||||
CompositeName name = new CompositeName();
|
||||
@@ -85,7 +87,7 @@ public class DefaultDirObjectFactoryTest {
|
||||
|
||||
@Test
|
||||
public void testGetObjectInstance_nullObject() throws Exception {
|
||||
BasicAttributes expectedAttributes = new BasicAttributes();
|
||||
Attributes expectedAttributes = new NameAwareAttributes();
|
||||
expectedAttributes.put("someAttribute", "someValue");
|
||||
|
||||
DirContextAdapter adapter = (DirContextAdapter) tested.getObjectInstance(null, DN, null, new Hashtable(),
|
||||
@@ -97,7 +99,7 @@ public class DefaultDirObjectFactoryTest {
|
||||
|
||||
@Test
|
||||
public void testGetObjectInstance_ObjectNotContext() throws Exception {
|
||||
BasicAttributes expectedAttributes = new BasicAttributes();
|
||||
Attributes expectedAttributes = new NameAwareAttributes();
|
||||
expectedAttributes.put("someAttribute", "someValue");
|
||||
|
||||
DirContextAdapter adapter = (DirContextAdapter) tested.getObjectInstance(new Object(), DN, null,
|
||||
@@ -114,7 +116,7 @@ public class DefaultDirObjectFactoryTest {
|
||||
*/
|
||||
@Test
|
||||
public void testGetObjectInstance_BaseSet() throws Exception {
|
||||
BasicAttributes expectedAttributes = new BasicAttributes();
|
||||
Attributes expectedAttributes = new NameAwareAttributes();
|
||||
expectedAttributes.put("someAttribute", "someValue");
|
||||
|
||||
when(contextMock2.getNameInNamespace()).thenReturn("dc=jayway, dc=se");
|
||||
|
||||
@@ -51,7 +51,7 @@ public class DefaultObjectDirectoryMapperTest {
|
||||
assertFalse(idAttribute.isBinary());
|
||||
assertFalse(idAttribute.isDnAttribute());
|
||||
assertFalse(idAttribute.isTransient());
|
||||
assertFalse(idAttribute.isList());
|
||||
assertFalse(idAttribute.isCollection());
|
||||
|
||||
assertField(entityData, "fullName", "cn", "cn", false, false, false);
|
||||
assertField(entityData, "lastName", "sn", null, false, false, false);
|
||||
@@ -115,7 +115,7 @@ public class DefaultObjectDirectoryMapperTest {
|
||||
|
||||
assertEquals(expectedBinary, attribute.isBinary());
|
||||
assertEquals(expectedTransient, attribute.isTransient());
|
||||
assertEquals(expectedList, attribute.isList());
|
||||
assertEquals(expectedList, attribute.isCollection());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ ext.gsbaseVersion = '2.0.1'
|
||||
ext.log4jVersion = '1.2.15'
|
||||
ext.mockitoVersion = '1.9.5'
|
||||
ext.queryDslVersion = '3.2.4'
|
||||
ext.slf4jVersion = '1.7.5'
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
|
||||
@@ -9,7 +9,9 @@ dependencies {
|
||||
"org.springframework:spring-orm:$springVersion"
|
||||
|
||||
testCompile "org.springframework:spring-test:$springVersion",
|
||||
"junit:junit:$junitVersion"
|
||||
"junit:junit:$junitVersion",
|
||||
"org.slf4j:slf4j-log4j12:$slf4jVersion"
|
||||
|
||||
}
|
||||
|
||||
test.enabled = false // TODO this should be enabled depending on build parameter
|
||||
@@ -13,7 +13,9 @@ dependencies {
|
||||
"org.springframework:spring-test:$springVersion",
|
||||
"gsbase:gsbase:$gsbaseVersion",
|
||||
"junit:junit:$junitVersion",
|
||||
"com.sun:ldapbp:1.0"
|
||||
"com.sun:ldapbp:1.0",
|
||||
"org.slf4j:slf4j-log4j12:$slf4jVersion"
|
||||
|
||||
}
|
||||
|
||||
test.enabled = false // TODO this should be enabled depending on build parameter
|
||||
@@ -18,5 +18,7 @@ dependencies {
|
||||
"org.springframework:spring-context:$spring20Version",
|
||||
"org.springframework:spring-core:$spring20Version",
|
||||
"org.springframework:spring-dao:$spring20Version",
|
||||
"org.springframework:spring-beans:$spring20Version"
|
||||
"org.springframework:spring-beans:$spring20Version",
|
||||
"org.slf4j:slf4j-log4j12:$slf4jVersion"
|
||||
|
||||
}
|
||||
@@ -23,5 +23,7 @@ dependencies {
|
||||
"org.springframework:spring-core:$spring25Version",
|
||||
"org.springframework:spring-tx:$spring25Version",
|
||||
"org.springframework:spring-beans:$spring25Version",
|
||||
"junit:junit:$junitVersion"
|
||||
"junit:junit:$junitVersion",
|
||||
"org.slf4j:slf4j-log4j12:$slf4jVersion"
|
||||
|
||||
}
|
||||
|
||||
@@ -23,5 +23,6 @@ dependencies {
|
||||
"org.springframework:spring-core:$spring30Version",
|
||||
"org.springframework:spring-tx:$spring30Version",
|
||||
"org.springframework:spring-beans:$spring30Version",
|
||||
"junit:junit:$junitVersion"
|
||||
"junit:junit:$junitVersion",
|
||||
"org.slf4j:slf4j-log4j12:$slf4jVersion"
|
||||
}
|
||||
|
||||
@@ -13,7 +13,9 @@ dependencies {
|
||||
testCompile "junit:junit:$junitVersion",
|
||||
"org.springframework:spring-aop:$springVersion",
|
||||
"org.springframework:spring-aop:$springVersion",
|
||||
"gsbase:gsbase:$gsbaseVersion"
|
||||
"gsbase:gsbase:$gsbaseVersion",
|
||||
"org.slf4j:slf4j-log4j12:$slf4jVersion"
|
||||
|
||||
}
|
||||
|
||||
test.enabled = false // TODO this should be enabled depending on build parameter
|
||||
@@ -46,7 +46,9 @@ dependencies {
|
||||
"aspectj:aspectjweaver:1.5.3",
|
||||
"hsqldb:hsqldb:1.8.0.7",
|
||||
"junit:junit:$junitVersion",
|
||||
"org.springframework.security:spring-security-config:$springSecurityVersion"
|
||||
"org.springframework.security:spring-security-config:$springSecurityVersion",
|
||||
"org.slf4j:slf4j-log4j12:$slf4jVersion"
|
||||
|
||||
|
||||
testCompile("org.springframework.security:spring-security-ldap:$springSecurityVersion") {
|
||||
exclude group: "org.springframework.ldap", module: "spring-ldap-core"
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright 2005-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.ldap.itest.odm;
|
||||
|
||||
import org.springframework.ldap.odm.annotations.Attribute;
|
||||
import org.springframework.ldap.odm.annotations.DnAttribute;
|
||||
import org.springframework.ldap.odm.annotations.Entry;
|
||||
import org.springframework.ldap.odm.annotations.Id;
|
||||
|
||||
import javax.naming.Name;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author Mattias Hellborg Arthursson
|
||||
*/
|
||||
@Entry(objectClasses = {"top", "groupOfUniqueNames"}, base = "cn=groups")
|
||||
public class Group {
|
||||
|
||||
@Id
|
||||
private Name dn;
|
||||
|
||||
@Attribute(name="cn")
|
||||
@DnAttribute("cn")
|
||||
private String name;
|
||||
|
||||
@Attribute(name="uniqueMember")
|
||||
private Set<Name> members;
|
||||
|
||||
public Name getDn() {
|
||||
return dn;
|
||||
}
|
||||
|
||||
public void setDn(Name dn) {
|
||||
this.dn = dn;
|
||||
}
|
||||
|
||||
public Set<Name> getMembers() {
|
||||
return members;
|
||||
}
|
||||
|
||||
public void setMembers(Set<Name> members) {
|
||||
this.members = members;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public void addMember(Name member) {
|
||||
members.add(member);
|
||||
}
|
||||
|
||||
public void removeMember(Name member) {
|
||||
members.remove(member);
|
||||
}
|
||||
}
|
||||
@@ -58,6 +58,16 @@ public class LdapTemplateBindUnbindITest extends
|
||||
verifyCleanup();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBindGroupOfUniqueNamesWithNameValues() {
|
||||
DirContextAdapter ctx = new DirContextAdapter(LdapUtils.newLdapName("cn=TEST,ou=groups"));
|
||||
ctx.addAttributeValue("cn", "TEST");
|
||||
ctx.addAttributeValue("objectclass", "top");
|
||||
ctx.addAttributeValue("objectclass", "groupOfUniqueNames");
|
||||
ctx.addAttributeValue("uniqueMember", LdapUtils.newLdapName("cn=Some Person,ou=company1,c=Sweden,dc=jayway,dc=se"));
|
||||
tested.bind(ctx);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBindAndUnbindWithAttributesUsingLdapName() {
|
||||
Attributes attributes = setupAttributes();
|
||||
|
||||
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* Copyright 2005-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.ldap.itest.odm;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.ldap.core.LdapTemplate;
|
||||
import org.springframework.ldap.itest.AbstractLdapTemplateIntegrationTest;
|
||||
import org.springframework.ldap.support.LdapUtils;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
|
||||
import javax.naming.Name;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.springframework.ldap.query.LdapQueryBuilder.query;
|
||||
|
||||
/**
|
||||
* @author Mattias Hellborg Arthursson
|
||||
*/
|
||||
@ContextConfiguration(locations = {"/conf/ldapTemplateTestContext.xml"})
|
||||
public class LdapTemplateOdmGroupManipulationITest extends AbstractLdapTemplateIntegrationTest {
|
||||
@Autowired
|
||||
private LdapTemplate tested;
|
||||
|
||||
@Test
|
||||
public void testFindOne() {
|
||||
Group group = tested.findOne(query().where("cn").is("ROLE_USER"), Group.class);
|
||||
|
||||
assertNotNull(group);
|
||||
assertEquals("ROLE_USER", group.getName());
|
||||
assertEquals(5, group.getMembers().size());
|
||||
|
||||
Set<Name> members = group.getMembers();
|
||||
assertTrue(members.contains(LdapUtils.newLdapName("cn=Some Person,ou=company1,c=Sweden,dc=jayway,dc=se")));
|
||||
assertTrue(members.contains(LdapUtils.newLdapName("cn=Some Person2,ou=company1,c=Sweden,dc=jayway,dc=se")));
|
||||
assertTrue(members.contains(LdapUtils.newLdapName("cn=Some Person,ou=company1,c=Norway,dc=jayway,dc=se")));
|
||||
assertTrue(members.contains(LdapUtils.newLdapName("cn=Some Person,ou=company2,c=Sweden,dc=jayway,dc=se")));
|
||||
assertTrue(members.contains(LdapUtils.newLdapName("cn=Some Person3,ou=company1,c=Sweden,dc=jayway,dc=se")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemoveMember() {
|
||||
Group group = tested.findOne(query().where("cn").is("ROLE_USER"), Group.class);
|
||||
|
||||
group.removeMember(LdapUtils.newLdapName("cn=Some Person,ou=company1,c=Sweden,dc=jayway,dc=se"));
|
||||
tested.update(group);
|
||||
|
||||
Group verification = tested.findOne(query().where("cn").is("ROLE_USER"), Group.class);
|
||||
|
||||
Set<Name> members = verification.getMembers();
|
||||
assertEquals(4, members.size());
|
||||
assertFalse(members.contains(LdapUtils.newLdapName("cn=Some Person,ou=company1,c=Sweden,dc=jayway,dc=se")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemoveMemberSyntacticallyEqual() {
|
||||
Group group = tested.findOne(query().where("cn").is("ROLE_USER"), Group.class);
|
||||
|
||||
group.removeMember(LdapUtils.newLdapName("cn=Some Person,ou=company1,c=Sweden, DC=jayway,DC=se"));
|
||||
tested.update(group);
|
||||
|
||||
Group verification = tested.findOne(query().where("cn").is("ROLE_USER"), Group.class);
|
||||
|
||||
Set<Name> members = verification.getMembers();
|
||||
assertEquals(4, members.size());
|
||||
assertFalse(members.contains(LdapUtils.newLdapName("cn=Some Person,ou=company1,c=Sweden,dc=jayway,dc=se")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddMember() {
|
||||
Group group = tested.findOne(query().where("cn").is("ROLE_USER"), Group.class);
|
||||
|
||||
group.addMember(LdapUtils.newLdapName("cn=Some Person+sn=Person,ou=company1,c=Norway,dc=jayway,dc=se"));
|
||||
tested.update(group);
|
||||
|
||||
Group verification = tested.findOne(query().where("cn").is("ROLE_USER"), Group.class);
|
||||
|
||||
Set<Name> members = verification.getMembers();
|
||||
assertEquals(6, members.size());
|
||||
assertTrue(members.contains(LdapUtils.newLdapName("cn=Some Person+sn=Person,ou=company1,c=Norway,dc=jayway,dc=se")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddMemberDuplicate() {
|
||||
Group group = tested.findOne(query().where("cn").is("ROLE_USER"), Group.class);
|
||||
|
||||
group.addMember(LdapUtils.newLdapName("cn=Some Person,ou=company1,c=Sweden,dc=jayway,dc=se"));
|
||||
tested.update(group);
|
||||
|
||||
Group verification = tested.findOne(query().where("cn").is("ROLE_USER"), Group.class);
|
||||
|
||||
Set<Name> members = verification.getMembers();
|
||||
assertEquals(5, members.size());
|
||||
assertTrue(members.contains(LdapUtils.newLdapName("cn=Some Person,ou=company1,c=Sweden,dc=jayway,dc=se")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddMemberSyntacticallyEqualDuplicate() {
|
||||
Group group = tested.findOne(query().where("cn").is("ROLE_USER"), Group.class);
|
||||
|
||||
group.addMember(LdapUtils.newLdapName("cn=Some Person,ou=company1,c=Sweden,DC=jayway,DC=se"));
|
||||
tested.update(group);
|
||||
|
||||
Group verification = tested.findOne(query().where("cn").is("ROLE_USER"), Group.class);
|
||||
|
||||
Set<Name> members = verification.getMembers();
|
||||
assertEquals(5, members.size());
|
||||
assertTrue(members.contains(LdapUtils.newLdapName("cn=Some Person,ou=company1,c=Sweden,dc=jayway,dc=se")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetMembersSyntacticallyEqual() {
|
||||
Group group = tested.findOne(query().where("cn").is("ROLE_USER"), Group.class);
|
||||
|
||||
group.setMembers(new HashSet<Name>(){{
|
||||
add(LdapUtils.newLdapName("CN=Some Person,OU=company1, C=Sweden, DC=jayway,DC=se"));
|
||||
add(LdapUtils.newLdapName("CN=Some Person2, OU=company1,C=Sweden,DC=jayway, DC=se"));
|
||||
}});
|
||||
tested.update(group);
|
||||
|
||||
Group verification = tested.findOne(query().where("cn").is("ROLE_USER"), Group.class);
|
||||
|
||||
Set<Name> members = verification.getMembers();
|
||||
|
||||
assertEquals(2, members.size());
|
||||
assertTrue(members.contains(LdapUtils.newLdapName("cn=Some Person,ou=company1,c=Sweden,dc=jayway,dc=se")));
|
||||
assertTrue(members.contains(LdapUtils.newLdapName("cn=Some Person2,ou=company1,c=Sweden,dc=jayway,dc=se")));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user