LDAP-265, LDAP-268: Added the ability to automatically map to/from DN values in ODM. Added some much needed unit tests for ODM functionality.
This commit is contained in:
@@ -1736,8 +1736,8 @@ public class LdapTemplate implements LdapOperations, InitializingBean {
|
||||
log.debug(String.format("Reading Entry at - %s$1", dn));
|
||||
}
|
||||
|
||||
// TODO: validate class before lookup
|
||||
// getEntityData(clazz);
|
||||
// Make sure the class is OK before doing the lookup
|
||||
odm.manageClass(clazz);
|
||||
|
||||
T result = lookup(dn, new ContextMapper<T>() {
|
||||
@Override
|
||||
@@ -1758,11 +1758,20 @@ public class LdapTemplate implements LdapOperations, InitializingBean {
|
||||
|
||||
@Override
|
||||
public void create(Object entry) {
|
||||
Assert.notNull(entry, "Entry must not be null");
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug(String.format("Creating entry - %s$1", entry));
|
||||
}
|
||||
|
||||
DirContextAdapter context = new DirContextAdapter(odm.getId(entry));
|
||||
Name id = odm.getId(entry);
|
||||
if(id == null) {
|
||||
id = odm.getCalculatedId(entry);
|
||||
}
|
||||
|
||||
Assert.notNull(id, String.format("Unable to determine id for entry %s", entry.toString()));
|
||||
|
||||
DirContextAdapter context = new DirContextAdapter(id);
|
||||
odm.mapToLdapDataEntry(entry, context);
|
||||
|
||||
bind(context);
|
||||
@@ -1770,13 +1779,42 @@ public class LdapTemplate implements LdapOperations, InitializingBean {
|
||||
|
||||
@Override
|
||||
public void update(Object entry) {
|
||||
Assert.notNull(entry, "Entry must not be null");
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug(String.format("Updating entry - %s$1", entry));
|
||||
}
|
||||
|
||||
DirContextOperations context = lookupContext(odm.getId(entry));
|
||||
odm.mapToLdapDataEntry(entry, context);
|
||||
modifyAttributes(context);
|
||||
Name originalId = odm.getId(entry);
|
||||
Name calculatedId = odm.getCalculatedId(entry);
|
||||
|
||||
if(originalId != null && calculatedId != null && !originalId.equals(calculatedId)) {
|
||||
// The DN has changed - remove the original entry and bind the new one
|
||||
// (because other data may have changed as well
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug(String.format("Calculated DN of %s; of entry %s differs from explicitly specified one; %s - moving",
|
||||
calculatedId, entry, originalId));
|
||||
}
|
||||
|
||||
unbind(originalId);
|
||||
|
||||
DirContextAdapter context = new DirContextAdapter(calculatedId);
|
||||
odm.mapToLdapDataEntry(entry, context);
|
||||
|
||||
bind(context);
|
||||
} else {
|
||||
// DN is the same, just modify the attributes
|
||||
|
||||
Name id = originalId;
|
||||
if(id == null) {
|
||||
id = calculatedId;
|
||||
}
|
||||
|
||||
Assert.notNull(id, String.format("Unable to determine id for entry %s", entry.toString()));
|
||||
|
||||
DirContextOperations context = lookupContext(id);
|
||||
odm.mapToLdapDataEntry(entry, context);
|
||||
modifyAttributes(context);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
package org.springframework.ldap.odm.annotations;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* @author Mattias Hellborg Arthursson
|
||||
*/
|
||||
@Target(ElementType.FIELD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface DnAttribute {
|
||||
String value();
|
||||
int index() default -1;
|
||||
}
|
||||
@@ -22,4 +22,12 @@ public @interface Entry {
|
||||
* @return A list of LDAP classes which the annotated Java class represents.
|
||||
*/
|
||||
String[] objectClasses();
|
||||
|
||||
/**
|
||||
* The base DN of this entry. If specified, this will be prepended to all calculated
|
||||
* distinguished names for entries of the annotated class.
|
||||
*
|
||||
* @return the base DN for entries of this class
|
||||
*/
|
||||
String base() default "";
|
||||
}
|
||||
|
||||
@@ -56,6 +56,8 @@ public interface ObjectDirectoryMapper {
|
||||
*/
|
||||
Name getId(Object entry);
|
||||
|
||||
Name getCalculatedId(Object entry);
|
||||
|
||||
/**
|
||||
* Use the specified search filter and return a new one that only applies to entries of the specified class.
|
||||
* In effect this means padding the original filter with an objectclass condition.
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
package org.springframework.ldap.odm.core.impl;
|
||||
|
||||
import org.springframework.ldap.odm.annotations.Attribute;
|
||||
import org.springframework.ldap.odm.annotations.DnAttribute;
|
||||
import org.springframework.ldap.odm.annotations.Id;
|
||||
import org.springframework.ldap.odm.annotations.Transient;
|
||||
|
||||
import javax.naming.Name;
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.GenericArrayType;
|
||||
@@ -8,11 +14,6 @@ import java.lang.reflect.Type;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.naming.Name;
|
||||
|
||||
import org.springframework.ldap.odm.annotations.Attribute;
|
||||
import org.springframework.ldap.odm.annotations.Id;
|
||||
|
||||
/*
|
||||
* Extract attribute meta-data from the @Attribute annotation, the @Id annotation
|
||||
* and via reflection.
|
||||
@@ -47,7 +48,11 @@ import org.springframework.ldap.odm.annotations.Id;
|
||||
|
||||
// Is this the objectClass attribute
|
||||
private boolean isObjectClass;
|
||||
|
||||
|
||||
private boolean isTransient = false;
|
||||
|
||||
private DnAttribute dnAttribute;
|
||||
|
||||
// Extract information from the @Attribute annotation:
|
||||
// syntax, isBinary, isObjectClass and name.
|
||||
private boolean processAttributeAnnotation(Field field) {
|
||||
@@ -157,10 +162,24 @@ import org.springframework.ldap.odm.annotations.Id;
|
||||
// Extract meta-data from the given field
|
||||
public AttributeMetaData(Field field) {
|
||||
this.field=field;
|
||||
|
||||
|
||||
this.dnAttribute = field.getAnnotation(DnAttribute.class);
|
||||
if(this.dnAttribute != null && !field.getType().equals(String.class)) {
|
||||
throw new MetaDataException(String.format("%s is of type %s, but only String attributes can be declared as @DnAttributes",
|
||||
field.toString(),
|
||||
field.getType().toString()));
|
||||
}
|
||||
|
||||
Transient transientAnnotation = field.getAnnotation(Transient.class);
|
||||
if(transientAnnotation != null) {
|
||||
this.isTransient = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// Reflection data
|
||||
determineFieldType(field);
|
||||
|
||||
|
||||
|
||||
// Data from the @Attribute annotation
|
||||
boolean foundAttributeAnnotation=processAttributeAnnotation(field);
|
||||
|
||||
@@ -181,6 +200,7 @@ import org.springframework.ldap.odm.annotations.Id;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public String getSyntax() {
|
||||
return syntax;
|
||||
}
|
||||
@@ -205,6 +225,18 @@ import org.springframework.ldap.odm.annotations.Id;
|
||||
return isId;
|
||||
}
|
||||
|
||||
public boolean isTransient() {
|
||||
return isTransient;
|
||||
}
|
||||
|
||||
public DnAttribute getDnAttribute() {
|
||||
return dnAttribute;
|
||||
}
|
||||
|
||||
public boolean isDnAttribute() {
|
||||
return dnAttribute != null;
|
||||
}
|
||||
|
||||
public boolean isObjectClass() {
|
||||
return isObjectClass;
|
||||
}
|
||||
|
||||
@@ -22,9 +22,14 @@ import org.springframework.LdapDataEntry;
|
||||
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.ConverterManagerImpl;
|
||||
import org.springframework.ldap.support.LdapNameBuilder;
|
||||
import org.springframework.ldap.support.LdapUtils;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
import javax.naming.Name;
|
||||
import javax.naming.NamingEnumeration;
|
||||
@@ -68,9 +73,9 @@ public class DefaultObjectDirectoryMapper implements ObjectDirectoryMapper {
|
||||
this.converterManager = converterManager;
|
||||
}
|
||||
|
||||
private static final class EntityData {
|
||||
private final ObjectMetaData metaData;
|
||||
private final Filter ocFilter;
|
||||
static final class EntityData {
|
||||
final ObjectMetaData metaData;
|
||||
final Filter ocFilter;
|
||||
|
||||
private EntityData(ObjectMetaData metaData, Filter ocFilter) {
|
||||
this.metaData=metaData;
|
||||
@@ -120,7 +125,7 @@ public class DefaultObjectDirectoryMapper implements ObjectDirectoryMapper {
|
||||
// Check we have all of the necessary converters for the class
|
||||
for (Field field : metaData) {
|
||||
AttributeMetaData attributeInfo = metaData.getAttribute(field);
|
||||
if (!attributeInfo.isId() && !(attributeInfo.isObjectClass())) {
|
||||
if (!attributeInfo.isTransient() && !attributeInfo.isId() && !(attributeInfo.isObjectClass())) {
|
||||
Class<?> jndiClass = (attributeInfo.isBinary()) ? byte[].class : String.class;
|
||||
Class<?> javaClass = attributeInfo.getValueClass();
|
||||
if (!converterManager.canConvert(jndiClass, attributeInfo.getSyntax(), javaClass)) {
|
||||
@@ -176,36 +181,18 @@ public class DefaultObjectDirectoryMapper implements ObjectDirectoryMapper {
|
||||
// Grab the meta data for the current field
|
||||
AttributeMetaData attributeInfo = metaData.getAttribute(field);
|
||||
// We dealt with the object class field about, and the DN is set by the call to write the object to LDAP
|
||||
if (!attributeInfo.isId() && !(attributeInfo.isObjectClass())) {
|
||||
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;
|
||||
// Multi valued?
|
||||
if (!attributeInfo.isList()) {
|
||||
// Single valued - get the value of the field
|
||||
Object fieldValue = field.get(entry);
|
||||
// Ignore null field values
|
||||
if (fieldValue != null) {
|
||||
// Convert the field value to the required type and write it into the JNDI context
|
||||
context.setAttributeValue(attributeInfo.getName().toString(), converterManager.convert(fieldValue,
|
||||
attributeInfo.getSyntax(), targetClass));
|
||||
}
|
||||
} else { // Multi-valued
|
||||
// We need to build up a list of of the values
|
||||
List<String> attributeValues = new ArrayList<String>();
|
||||
// Get the list of values
|
||||
Collection<?> fieldValues = (Collection<?>)field.get(entry);
|
||||
// Ignore null lists
|
||||
if (fieldValues != null) {
|
||||
for (final Object o : fieldValues) {
|
||||
// Ignore null values
|
||||
if (o != null) {
|
||||
attributeValues.add((String)converterManager.convert(o, attributeInfo.getSyntax(),
|
||||
targetClass));
|
||||
}
|
||||
}
|
||||
context.setAttributeValues(attributeInfo.getName().toString(), attributeValues.toArray());
|
||||
}
|
||||
populateSingleValueAttribute(entry, context, field, attributeInfo, targetClass);
|
||||
|
||||
} else {
|
||||
// Multi-valued
|
||||
populateMultiValueAttribute(entry, context, field, attributeInfo, targetClass);
|
||||
|
||||
}
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new InvalidEntryException(String.format("Can't set attribute %1$s", attributeInfo.getName()),
|
||||
@@ -215,6 +202,35 @@ 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>();
|
||||
// Get the list of values
|
||||
Collection<?> fieldValues = (Collection<?>)field.get(entry);
|
||||
// Ignore null lists
|
||||
if (fieldValues != null) {
|
||||
for (final Object o : fieldValues) {
|
||||
// Ignore null values
|
||||
if (o != null) {
|
||||
attributeValues.add((String)converterManager.convert(o, attributeInfo.getSyntax(),
|
||||
targetClass));
|
||||
}
|
||||
}
|
||||
context.setAttributeValues(attributeInfo.getName().toString(), attributeValues.toArray());
|
||||
}
|
||||
}
|
||||
|
||||
private void populateSingleValueAttribute(Object entry, LdapDataEntry context, Field field, AttributeMetaData attributeInfo, Class<?> targetClass) throws IllegalAccessException {
|
||||
// Single valued - get the value of the field
|
||||
Object fieldValue = field.get(entry);
|
||||
// Ignore null field values
|
||||
if (fieldValue != null) {
|
||||
// Convert the field value to the required type and write it into the JNDI context
|
||||
context.setAttributeValue(attributeInfo.getName().toString(), converterManager.convert(fieldValue,
|
||||
attributeInfo.getSyntax(), targetClass));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T mapFromLdapDataEntry(LdapDataEntry context, Class<T> clazz) {
|
||||
if (LOG.isDebugEnabled()) {
|
||||
@@ -237,7 +253,7 @@ public class DefaultObjectDirectoryMapper implements ObjectDirectoryMapper {
|
||||
NamingEnumeration<? extends Attribute> attributesEnumeration = attributes.getAll();
|
||||
// Loop through all of the JNDI attributes
|
||||
while (attributesEnumeration.hasMoreElements()) {
|
||||
Attribute currentAttribute = (Attribute)attributesEnumeration.nextElement();
|
||||
Attribute currentAttribute = attributesEnumeration.nextElement();
|
||||
// Add the current attribute to the map keyed on the lowercased (case indep) id of the attribute
|
||||
attributeValueMap.put(new CaseIgnoreString(currentAttribute.getID()), currentAttribute);
|
||||
}
|
||||
@@ -248,53 +264,27 @@ public class DefaultObjectDirectoryMapper implements ObjectDirectoryMapper {
|
||||
// Get the current field
|
||||
AttributeMetaData attributeInfo = metaData.getAttribute(field);
|
||||
// We deal with the Id field specially
|
||||
if (!attributeInfo.isId()) {
|
||||
Name dn = context.getDn();
|
||||
if (!attributeInfo.isTransient() && !attributeInfo.isId()) {
|
||||
// Not the ID - but is is multi valued?
|
||||
if (!attributeInfo.isList()) {
|
||||
// No - its single valued, grab the JNDI attribute that corresponds to the metadata on the
|
||||
// current field
|
||||
Attribute attribute = attributeValueMap.get(attributeInfo.getName());
|
||||
// There is no guarantee that this attribute is present in the directory - so ignore nulls
|
||||
if (attribute != null) {
|
||||
// Grab the JNDI value
|
||||
Object value = attribute.get();
|
||||
// Check the value is not null
|
||||
if (value != null) {
|
||||
// Convert the JNDI value to its Java representation - this will throw if the
|
||||
// conversion fails
|
||||
Object convertedValue = converterManager.convert(value, attributeInfo.getSyntax(),
|
||||
attributeInfo.getValueClass());
|
||||
// Set it in the Java version
|
||||
field.set(result, convertedValue);
|
||||
}
|
||||
}
|
||||
} else { // We are dealing with a multi valued attribute
|
||||
// We need to build up a list of values
|
||||
List<Object> fieldValues = new ArrayList<Object>();
|
||||
// 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
|
||||
if (currentAttribute != null) {
|
||||
// Loop through the values of the JNDI attribute
|
||||
NamingEnumeration<?> valuesEmumeration = currentAttribute.getAll();
|
||||
while (valuesEmumeration.hasMore()) {
|
||||
// Get the current value
|
||||
Object value = valuesEmumeration.nextElement();
|
||||
// Check the value is not null
|
||||
if (value != null) {
|
||||
// Convert the value to its Java representation and add it to our working list
|
||||
fieldValues.add(converterManager.convert(value, attributeInfo.getSyntax(),
|
||||
attributeInfo.getValueClass()));
|
||||
}
|
||||
}
|
||||
}
|
||||
// Now we need to set the List in to a Java object
|
||||
field.set(result, fieldValues);
|
||||
populateSingleValueField(result, attributeValueMap, field, attributeInfo);
|
||||
} else {
|
||||
// We are dealing with a multi valued attribute
|
||||
populateMultiValueField(result, attributeValueMap, field, attributeInfo);
|
||||
}
|
||||
} else { // The id field
|
||||
field.set(result, converterManager.convert(context.getDn(), attributeInfo.getSyntax(),
|
||||
} else if(attributeInfo.isId()) { // The id field
|
||||
field.set(result, converterManager.convert(dn, attributeInfo.getSyntax(),
|
||||
attributeInfo.getValueClass()));
|
||||
}
|
||||
|
||||
DnAttribute dnAttribute = attributeInfo.getDnAttribute();
|
||||
if(dnAttribute != null) {
|
||||
String dnValue = LdapUtils.getStringValue(dn, dnAttribute.value());
|
||||
field.set(result, dnValue);
|
||||
}
|
||||
}
|
||||
|
||||
// If this is the objectclass attribute then check that values correspond to the metadata we have
|
||||
@@ -315,7 +305,6 @@ public class DefaultObjectDirectoryMapper implements ObjectDirectoryMapper {
|
||||
throw new InvalidEntryException(String.format("No object classes were returned for class %1$s",
|
||||
clazz.getName()));
|
||||
}
|
||||
|
||||
} catch (NamingException ne) {
|
||||
throw new InvalidEntryException(String.format("Problem creating %1$s from LDAP Entry %2$s",
|
||||
clazz, context), ne);
|
||||
@@ -333,6 +322,48 @@ public class DefaultObjectDirectoryMapper implements ObjectDirectoryMapper {
|
||||
return result;
|
||||
}
|
||||
|
||||
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>();
|
||||
// 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
|
||||
if (currentAttribute != null) {
|
||||
// Loop through the values of the JNDI attribute
|
||||
NamingEnumeration<?> valuesEmumeration = currentAttribute.getAll();
|
||||
while (valuesEmumeration.hasMore()) {
|
||||
// Get the current value
|
||||
Object value = valuesEmumeration.nextElement();
|
||||
// Check the value is not null
|
||||
if (value != null) {
|
||||
// Convert the value to its Java representation and add it to our working list
|
||||
fieldValues.add(converterManager.convert(value, attributeInfo.getSyntax(),
|
||||
attributeInfo.getValueClass()));
|
||||
}
|
||||
}
|
||||
}
|
||||
// Now we need to set the List in to a Java object
|
||||
field.set(result, fieldValues);
|
||||
}
|
||||
|
||||
private <T> void populateSingleValueField(T result, Map<CaseIgnoreString, Attribute> attributeValueMap, Field field, AttributeMetaData attributeInfo) throws NamingException, IllegalAccessException {
|
||||
Attribute attribute = attributeValueMap.get(attributeInfo.getName());
|
||||
// There is no guarantee that this attribute is present in the directory - so ignore nulls
|
||||
if (attribute != null) {
|
||||
// Grab the JNDI value
|
||||
Object value = attribute.get();
|
||||
// Check the value is not null
|
||||
if (value != null) {
|
||||
// Convert the JNDI value to its Java representation - this will throw if the
|
||||
// conversion fails
|
||||
Object convertedValue = converterManager.convert(value, attributeInfo.getSyntax(),
|
||||
attributeInfo.getValueClass());
|
||||
// Set it in the Java version
|
||||
field.set(result, convertedValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Name getId(Object entry) {
|
||||
try {
|
||||
@@ -343,6 +374,31 @@ public class DefaultObjectDirectoryMapper implements ObjectDirectoryMapper {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Name getCalculatedId(Object entry) {
|
||||
Assert.notNull(entry, "Entry must not be null");
|
||||
EntityData entityData = getEntityData(entry.getClass());
|
||||
if(entityData.metaData.canCalculateDn()) {
|
||||
Set<AttributeMetaData> dnAttributes = entityData.metaData.getDnAttributes();
|
||||
LdapNameBuilder ldapNameBuilder = LdapNameBuilder.newLdapName(entityData.metaData.getBase());
|
||||
|
||||
for (AttributeMetaData dnAttribute : dnAttributes) {
|
||||
Object dnFieldValue = ReflectionUtils.getField(dnAttribute.getField(), entry);
|
||||
if(dnFieldValue == null) {
|
||||
throw new IllegalStateException(
|
||||
String.format("DnAttribute for field %s on class %s is null; cannot build DN",
|
||||
dnAttribute.getField().getName(), entry.getClass().getName()));
|
||||
}
|
||||
|
||||
ldapNameBuilder.add(dnAttribute.getDnAttribute().value(), dnFieldValue.toString());
|
||||
}
|
||||
|
||||
return ldapNameBuilder.build();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Filter filterFor(Class<?> clazz, Filter baseFilter) {
|
||||
Filter ocFilter = getEntityData(clazz).ocFilter;
|
||||
@@ -355,6 +411,11 @@ public class DefaultObjectDirectoryMapper implements ObjectDirectoryMapper {
|
||||
return andFilter.append(ocFilter).append(baseFilter);
|
||||
}
|
||||
|
||||
// For testing purposes
|
||||
ConcurrentMap<Class<?>, EntityData> getMetaDataMap() {
|
||||
return metaDataMap;
|
||||
}
|
||||
|
||||
static boolean collectionContainsAll(Collection<?> collection, Set<?> shouldBePresent) {
|
||||
for (Object o : shouldBePresent) {
|
||||
if(!collection.contains(o)) {
|
||||
|
||||
@@ -1,18 +1,22 @@
|
||||
package org.springframework.ldap.odm.core.impl;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.ldap.odm.annotations.Entry;
|
||||
import org.springframework.ldap.odm.annotations.Id;
|
||||
import org.springframework.ldap.odm.annotations.Transient;
|
||||
import org.springframework.ldap.support.LdapUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import javax.naming.Name;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
|
||||
/*
|
||||
* An internal class to process the meta-data and reflection data for an entry.
|
||||
@@ -26,7 +30,23 @@ import org.springframework.ldap.odm.annotations.Transient;
|
||||
|
||||
private Map<Field, AttributeMetaData> fieldToAttribute = new HashMap<Field, AttributeMetaData>();
|
||||
|
||||
private Set<CaseIgnoreString> objectClasses = new HashSet<CaseIgnoreString>();
|
||||
private Set<AttributeMetaData> dnAttributes = new TreeSet<AttributeMetaData>(new Comparator<AttributeMetaData>() {
|
||||
@Override
|
||||
public int compare(AttributeMetaData a1, AttributeMetaData a2) {
|
||||
if(!a1.isDnAttribute() || !a2.isDnAttribute()) {
|
||||
// Not interesting to compare these.
|
||||
return 0;
|
||||
}
|
||||
|
||||
return Integer.compare(a1.getDnAttribute().index(), a2.getDnAttribute().index());
|
||||
}
|
||||
});
|
||||
|
||||
private boolean indexedDnAttributes = false;
|
||||
|
||||
private Set<CaseIgnoreString> objectClasses = new LinkedHashSet<CaseIgnoreString>();
|
||||
|
||||
private Name base = LdapUtils.emptyLdapName();
|
||||
|
||||
public Set<CaseIgnoreString> getObjectClasses() {
|
||||
return objectClasses;
|
||||
@@ -55,7 +75,7 @@ import org.springframework.ldap.odm.annotations.Transient;
|
||||
}
|
||||
|
||||
// Get object class metadata - the @Entity annotation
|
||||
Entry entity = (Entry)clazz.getAnnotation(Entry.class);
|
||||
Entry entity = clazz.getAnnotation(Entry.class);
|
||||
if (entity != null) {
|
||||
// Default objectclass name to the class name unless it's specified
|
||||
// in @Entity(name={objectclass1, objectclass2});
|
||||
@@ -67,6 +87,11 @@ import org.springframework.ldap.odm.annotations.Transient;
|
||||
} else {
|
||||
objectClasses.add(new CaseIgnoreString(clazz.getSimpleName()));
|
||||
}
|
||||
|
||||
String base = entity.base();
|
||||
if(StringUtils.hasText(base)) {
|
||||
this.base = LdapUtils.newLdapName(base);
|
||||
}
|
||||
} else {
|
||||
throw new MetaDataException(String.format("Class %1$s must have a class level %2$s annotation", clazz,
|
||||
Entry.class));
|
||||
@@ -83,11 +108,11 @@ import org.springframework.ldap.odm.annotations.Transient;
|
||||
// So we can write to private fields
|
||||
field.setAccessible(true);
|
||||
|
||||
// Skip transient and synthetic fields
|
||||
if (field.getAnnotation(Transient.class) != null || field.isSynthetic()) {
|
||||
// Skip synthetic fields
|
||||
if (field.isSynthetic()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
AttributeMetaData currentAttributeMetaData=new AttributeMetaData(field);
|
||||
if (currentAttributeMetaData.isId()) {
|
||||
if (idAttribute!=null) {
|
||||
@@ -98,6 +123,10 @@ import org.springframework.ldap.odm.annotations.Transient;
|
||||
idAttribute=currentAttributeMetaData;
|
||||
}
|
||||
fieldToAttribute.put(field, currentAttributeMetaData);
|
||||
|
||||
if(currentAttributeMetaData.isDnAttribute()) {
|
||||
dnAttributes.add(currentAttributeMetaData);
|
||||
}
|
||||
}
|
||||
|
||||
if (idAttribute == null) {
|
||||
@@ -106,16 +135,58 @@ import org.springframework.ldap.odm.annotations.Transient;
|
||||
clazz));
|
||||
}
|
||||
|
||||
postProcessDnAttributes(clazz);
|
||||
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug(String.format("Extracted metadata from %1$s as %2$s", clazz, this));
|
||||
}
|
||||
}
|
||||
|
||||
private void postProcessDnAttributes(Class<?> clazz) {
|
||||
boolean hasIndexed = false;
|
||||
boolean hasNonIndexed = false;
|
||||
|
||||
for (AttributeMetaData dnAttribute : dnAttributes) {
|
||||
int declaredIndex = dnAttribute.getDnAttribute().index();
|
||||
|
||||
if(declaredIndex != -1) {
|
||||
hasIndexed = true;
|
||||
}
|
||||
|
||||
if(declaredIndex == -1) {
|
||||
hasNonIndexed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(hasIndexed && hasNonIndexed) {
|
||||
throw new MetaDataException(String.format("At least one DnAttribute declared on class %s is indexed, " +
|
||||
"which means that all DnAttributes must be indexed", clazz.toString()));
|
||||
}
|
||||
|
||||
indexedDnAttributes = hasIndexed;
|
||||
}
|
||||
|
||||
int size() {
|
||||
return fieldToAttribute.size();
|
||||
}
|
||||
|
||||
boolean canCalculateDn() {
|
||||
return dnAttributes.size() > 0 && indexedDnAttributes;
|
||||
}
|
||||
|
||||
public Set<AttributeMetaData> getDnAttributes() {
|
||||
return dnAttributes;
|
||||
}
|
||||
|
||||
Name getBase() {
|
||||
return base;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("objectsClasses=%1$s | idField=%2$s | attributes=%3$s",
|
||||
|
||||
@@ -19,9 +19,11 @@ package org.springframework.ldap.core;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.ldap.NameNotFoundException;
|
||||
import org.springframework.ldap.odm.core.ObjectDirectoryMapper;
|
||||
import org.springframework.ldap.support.LdapUtils;
|
||||
|
||||
import javax.naming.Name;
|
||||
import javax.naming.NamingException;
|
||||
import javax.naming.directory.BasicAttributes;
|
||||
import javax.naming.directory.DirContext;
|
||||
import javax.naming.ldap.LdapContext;
|
||||
@@ -49,6 +51,7 @@ public class LdapTemplateLookupTest {
|
||||
private ContextMapper contextMapperMock;
|
||||
|
||||
private LdapTemplate tested;
|
||||
private ObjectDirectoryMapper odmMock;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
@@ -60,12 +63,12 @@ public class LdapTemplateLookupTest {
|
||||
|
||||
// Setup Name mock
|
||||
nameMock = mock(Name.class);
|
||||
|
||||
contextMapperMock = mock(ContextMapper.class);
|
||||
|
||||
attributesMapperMock = mock(AttributesMapper.class);
|
||||
odmMock = mock(ObjectDirectoryMapper.class);
|
||||
|
||||
tested = new LdapTemplate(contextSourceMock);
|
||||
tested.setObjectDirectoryMapper(odmMock);
|
||||
}
|
||||
|
||||
private void expectGetReadOnlyContext() {
|
||||
@@ -192,6 +195,26 @@ public class LdapTemplateLookupTest {
|
||||
assertSame(transformed, actual);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFindByDn() throws NamingException {
|
||||
expectGetReadOnlyContext();
|
||||
|
||||
Object transformed = new Object();
|
||||
Class<Object> expectedClass = Object.class;
|
||||
|
||||
DirContextAdapter expectedContext = new DirContextAdapter();
|
||||
when(dirContextMock.lookup(nameMock)).thenReturn(expectedContext);
|
||||
when(odmMock.mapFromLdapDataEntry(expectedContext, expectedClass)).thenReturn(transformed);
|
||||
|
||||
// Perform test
|
||||
Object result = tested.findByDn(nameMock, expectedClass);
|
||||
assertSame(transformed, result);
|
||||
|
||||
verify(odmMock).manageClass(expectedClass);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void testLookup_String_ContextMapper() throws Exception {
|
||||
expectGetReadOnlyContext();
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
package org.springframework.ldap.core;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.ldap.odm.core.ObjectDirectoryMapper;
|
||||
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Mockito.doCallRealMethod;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* @author Mattias Hellborg Arthursson
|
||||
*/
|
||||
public class LdapTemplateOdmTest {
|
||||
|
||||
private LdapTemplate tested;
|
||||
private ObjectDirectoryMapper odmMock;
|
||||
|
||||
@Before
|
||||
public void prepareTestedClass() {
|
||||
tested = mock(LdapTemplate.class);
|
||||
|
||||
doCallRealMethod().when(tested).setObjectDirectoryMapper(any(ObjectDirectoryMapper.class));
|
||||
odmMock = mock(ObjectDirectoryMapper.class);
|
||||
|
||||
tested.setObjectDirectoryMapper(odmMock);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testFindByDn() {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -20,18 +20,23 @@ import org.hamcrest.BaseMatcher;
|
||||
import org.hamcrest.Description;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.springframework.LdapDataEntry;
|
||||
import org.springframework.dao.EmptyResultDataAccessException;
|
||||
import org.springframework.dao.IncorrectResultSizeDataAccessException;
|
||||
import org.springframework.ldap.LimitExceededException;
|
||||
import org.springframework.ldap.NameNotFoundException;
|
||||
import org.springframework.ldap.PartialResultException;
|
||||
import org.springframework.ldap.UncategorizedLdapException;
|
||||
import org.springframework.ldap.filter.EqualsFilter;
|
||||
import org.springframework.ldap.odm.core.ObjectDirectoryMapper;
|
||||
import org.springframework.ldap.support.LdapUtils;
|
||||
|
||||
import javax.naming.Binding;
|
||||
import javax.naming.CompositeName;
|
||||
import javax.naming.Name;
|
||||
import javax.naming.NamingEnumeration;
|
||||
import javax.naming.NamingException;
|
||||
import javax.naming.directory.BasicAttributes;
|
||||
import javax.naming.directory.DirContext;
|
||||
import javax.naming.directory.ModificationItem;
|
||||
@@ -47,13 +52,17 @@ import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.argThat;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.doNothing;
|
||||
import static org.mockito.Mockito.doThrow;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.springframework.ldap.query.LdapQueryBuilder.query;
|
||||
|
||||
/**
|
||||
* Unit tests for the LdapTemplate class.
|
||||
@@ -92,42 +101,33 @@ public class LdapTemplateTest {
|
||||
private DirContext authenticatedContextMock;
|
||||
|
||||
private AuthenticatedLdapEntryContextCallback entryContextCallbackMock;
|
||||
private ObjectDirectoryMapper odmMock;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
|
||||
// Setup ContextSource mock
|
||||
contextSourceMock = mock(ContextSource.class);
|
||||
|
||||
// Setup LdapContext mock
|
||||
dirContextMock = mock(LdapContext.class);
|
||||
|
||||
// Setup NamingEnumeration mock
|
||||
namingEnumerationMock = mock(NamingEnumeration.class);
|
||||
|
||||
// Setup Name mock
|
||||
nameMock = mock(Name.class);
|
||||
|
||||
nameMock = LdapUtils.emptyLdapName();
|
||||
// Setup Handler mock
|
||||
handlerMock = mock(NameClassPairCallbackHandler.class);
|
||||
|
||||
contextMapperMock = mock(ContextMapper.class);
|
||||
|
||||
attributesMapperMock = mock(AttributesMapper.class);
|
||||
|
||||
contextExecutorMock = mock(ContextExecutor.class);
|
||||
|
||||
searchExecutorMock = mock(SearchExecutor.class);
|
||||
|
||||
dirContextProcessorMock = mock(DirContextProcessor.class);
|
||||
|
||||
dirContextOperationsMock = mock(DirContextOperations.class);
|
||||
|
||||
authenticatedContextMock = mock(DirContext.class);
|
||||
|
||||
entryContextCallbackMock = mock(AuthenticatedLdapEntryContextCallback.class);
|
||||
odmMock = mock(ObjectDirectoryMapper.class);
|
||||
|
||||
tested = new LdapTemplate(contextSourceMock);
|
||||
tested = new LdapTemplate(contextSourceMock);
|
||||
tested.setObjectDirectoryMapper(odmMock);
|
||||
}
|
||||
|
||||
private void expectGetReadWriteContext() {
|
||||
@@ -591,7 +591,6 @@ public class LdapTemplateTest {
|
||||
|
||||
Object expectedObject = new Object();
|
||||
SearchResult searchResult = new SearchResult("", expectedObject, new BasicAttributes());
|
||||
|
||||
singleSearchResult(searchControlsOneLevel(), searchResult);
|
||||
|
||||
Object expectedResult = expectedObject;
|
||||
@@ -607,6 +606,79 @@ public class LdapTemplateTest {
|
||||
assertSame(expectedResult, list.get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFindOne() throws Exception {
|
||||
Class<Object> expectedClass = Object.class;
|
||||
|
||||
when(contextSourceMock.getReadOnlyContext()).thenReturn(dirContextMock);
|
||||
when(odmMock.filterFor(expectedClass,
|
||||
new EqualsFilter("ou", "somevalue"))).thenReturn(new EqualsFilter("ou", "somevalue"));
|
||||
|
||||
DirContextAdapter expectedObject = new DirContextAdapter();
|
||||
SearchResult searchResult = new SearchResult("", expectedObject, new BasicAttributes());
|
||||
singleSearchResult(searchControlsRecursive(), searchResult);
|
||||
|
||||
Object expectedResult = expectedObject;
|
||||
when(odmMock.mapFromLdapDataEntry(expectedObject, expectedClass)).thenReturn(expectedResult);
|
||||
|
||||
Object result = tested.findOne(query()
|
||||
.where("ou").is("somevalue"), expectedClass);
|
||||
|
||||
verify(namingEnumerationMock).close();
|
||||
verify(dirContextMock).close();
|
||||
|
||||
assertSame(expectedResult, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void verifyThatFindOneThrowsEmptyResultIfNoResult() throws Exception {
|
||||
Class<Object> expectedClass = Object.class;
|
||||
|
||||
when(contextSourceMock.getReadOnlyContext()).thenReturn(dirContextMock);
|
||||
when(odmMock.filterFor(expectedClass,
|
||||
new EqualsFilter("ou", "somevalue"))).thenReturn(new EqualsFilter("ou", "somevalue"));
|
||||
|
||||
noSearchResults(searchControlsRecursive());
|
||||
|
||||
try {
|
||||
tested.findOne(query().where("ou").is("somevalue"), expectedClass);
|
||||
fail("EmptyResultDataAccessException expected");
|
||||
} catch (EmptyResultDataAccessException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
|
||||
verify(namingEnumerationMock).close();
|
||||
verify(dirContextMock).close();
|
||||
verify(odmMock, never()).mapFromLdapDataEntry(any(LdapDataEntry.class), any(Class.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void verifyThatFindOneThrowsIncorrectResultSizeDataAccessExceptionWhenMoreResults() throws Exception {
|
||||
Class<Object> expectedClass = Object.class;
|
||||
|
||||
when(contextSourceMock.getReadOnlyContext()).thenReturn(dirContextMock);
|
||||
when(odmMock.filterFor(expectedClass,
|
||||
new EqualsFilter("ou", "somevalue"))).thenReturn(new EqualsFilter("ou", "somevalue"));
|
||||
|
||||
DirContextAdapter expectedObject = new DirContextAdapter();
|
||||
SearchResult searchResult = new SearchResult("", expectedObject, new BasicAttributes());
|
||||
|
||||
setupSearchResults(searchControlsRecursive(), new SearchResult[]{searchResult, searchResult});
|
||||
|
||||
Object expectedResult = expectedObject;
|
||||
when(odmMock.mapFromLdapDataEntry(expectedObject, expectedClass)).thenReturn(expectedResult, expectedResult);
|
||||
|
||||
try {
|
||||
tested.findOne(query().where("ou").is("somevalue"), expectedClass);
|
||||
fail("EmptyResultDataAccessException expected");
|
||||
} catch (IncorrectResultSizeDataAccessException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
|
||||
verify(namingEnumerationMock).close();
|
||||
verify(dirContextMock).close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearch_ContextMapper_ReturningAttrs() throws Exception {
|
||||
expectGetReadOnlyContext();
|
||||
@@ -963,6 +1035,128 @@ public class LdapTemplateTest {
|
||||
verify(dirContextMock).close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateWithIdSpecified() throws NamingException {
|
||||
expectGetReadWriteContext();
|
||||
|
||||
Object expectedObject = new Object();
|
||||
LdapName expectedName = LdapUtils.newLdapName("ou=someOu");
|
||||
when(odmMock.getId(expectedObject)).thenReturn(expectedName);
|
||||
|
||||
ArgumentCaptor<DirContextAdapter> ctxCaptor = ArgumentCaptor.forClass(DirContextAdapter.class);
|
||||
doNothing().when(odmMock).mapToLdapDataEntry(eq(expectedObject), ctxCaptor.capture());
|
||||
|
||||
tested.create(expectedObject);
|
||||
|
||||
verify(dirContextMock).bind(expectedName, ctxCaptor.getValue(), null);
|
||||
verify(dirContextMock).close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateWithCalculatedId() throws NamingException {
|
||||
expectGetReadWriteContext();
|
||||
|
||||
Object expectedObject = new Object();
|
||||
LdapName expectedName = LdapUtils.newLdapName("ou=someOu");
|
||||
when(odmMock.getId(expectedObject)).thenReturn(null);
|
||||
when(odmMock.getCalculatedId(expectedObject)).thenReturn(expectedName);
|
||||
|
||||
ArgumentCaptor<DirContextAdapter> ctxCaptor = ArgumentCaptor.forClass(DirContextAdapter.class);
|
||||
doNothing().when(odmMock).mapToLdapDataEntry(eq(expectedObject), ctxCaptor.capture());
|
||||
|
||||
tested.create(expectedObject);
|
||||
|
||||
verify(dirContextMock).bind(expectedName, ctxCaptor.getValue(), null);
|
||||
verify(dirContextMock).close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateWithNoIdAvailableThrows() throws NamingException {
|
||||
Object expectedObject = new Object();
|
||||
when(odmMock.getId(expectedObject)).thenReturn(null);
|
||||
when(odmMock.getCalculatedId(expectedObject)).thenReturn(null);
|
||||
|
||||
try {
|
||||
tested.create(expectedObject);
|
||||
fail("IllegalArgumentException expected");
|
||||
} catch (IllegalArgumentException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateWithIdSpecified() throws NamingException {
|
||||
when(contextSourceMock.getReadOnlyContext()).thenReturn(dirContextMock);
|
||||
when(contextSourceMock.getReadWriteContext()).thenReturn(dirContextMock);
|
||||
LdapName expectedName = LdapUtils.newLdapName("ou=someOu");
|
||||
|
||||
ModificationItem[] expectedModificationItems = new ModificationItem[0];
|
||||
DirContextOperations ctxMock = mock(DirContextOperations.class);
|
||||
when(ctxMock.getDn()).thenReturn(expectedName);
|
||||
when(ctxMock.isUpdateMode()).thenReturn(true);
|
||||
when(ctxMock.getModificationItems()).thenReturn(expectedModificationItems);
|
||||
|
||||
Object expectedObject = new Object();
|
||||
when(odmMock.getId(expectedObject)).thenReturn(expectedName);
|
||||
when(odmMock.getCalculatedId(expectedObject)).thenReturn(null);
|
||||
|
||||
when(dirContextMock.lookup(expectedName)).thenReturn(ctxMock);
|
||||
|
||||
tested.update(expectedObject);
|
||||
|
||||
verify(odmMock).mapToLdapDataEntry(expectedObject, ctxMock);
|
||||
verify(dirContextMock).modifyAttributes(expectedName, expectedModificationItems);
|
||||
|
||||
verify(dirContextMock, times(2)).close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateWithIdCalculated() throws NamingException {
|
||||
when(contextSourceMock.getReadOnlyContext()).thenReturn(dirContextMock);
|
||||
when(contextSourceMock.getReadWriteContext()).thenReturn(dirContextMock);
|
||||
LdapName expectedName = LdapUtils.newLdapName("ou=someOu");
|
||||
|
||||
ModificationItem[] expectedModificationItems = new ModificationItem[0];
|
||||
DirContextOperations ctxMock = mock(DirContextOperations.class);
|
||||
when(ctxMock.getDn()).thenReturn(expectedName);
|
||||
when(ctxMock.isUpdateMode()).thenReturn(true);
|
||||
when(ctxMock.getModificationItems()).thenReturn(expectedModificationItems);
|
||||
|
||||
Object expectedObject = new Object();
|
||||
when(odmMock.getId(expectedObject)).thenReturn(null);
|
||||
when(odmMock.getCalculatedId(expectedObject)).thenReturn(expectedName);
|
||||
|
||||
when(dirContextMock.lookup(expectedName)).thenReturn(ctxMock);
|
||||
|
||||
tested.update(expectedObject);
|
||||
|
||||
verify(odmMock).mapToLdapDataEntry(expectedObject, ctxMock);
|
||||
verify(dirContextMock).modifyAttributes(expectedName, expectedModificationItems);
|
||||
|
||||
verify(dirContextMock, times(2)).close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateWithIdChanged() throws NamingException {
|
||||
Object expectedObject = new Object();
|
||||
|
||||
when(contextSourceMock.getReadWriteContext()).thenReturn(dirContextMock, dirContextMock);
|
||||
LdapName expectedOriginalName = LdapUtils.newLdapName("ou=someOu");
|
||||
LdapName expectedNewName = LdapUtils.newLdapName("ou=someOtherOu");
|
||||
|
||||
ArgumentCaptor<DirContextAdapter> ctxCaptor = ArgumentCaptor.forClass(DirContextAdapter.class);
|
||||
doNothing().when(odmMock).mapToLdapDataEntry(eq(expectedObject), ctxCaptor.capture());
|
||||
|
||||
when(odmMock.getId(expectedObject)).thenReturn(expectedOriginalName);
|
||||
when(odmMock.getCalculatedId(expectedObject)).thenReturn(expectedNewName);
|
||||
|
||||
tested.update(expectedObject);
|
||||
|
||||
verify(dirContextMock).unbind(expectedOriginalName);
|
||||
verify(dirContextMock).bind(expectedNewName, ctxCaptor.getValue(), null);
|
||||
verify(dirContextMock, times(2)).close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnbind() throws Exception {
|
||||
expectGetReadWriteContext();
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
package org.springframework.ldap.odm.core.impl;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.matchers.JUnitMatchers;
|
||||
import org.springframework.ldap.support.LdapUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import javax.naming.Name;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.springframework.ldap.query.LdapQueryBuilder.query;
|
||||
|
||||
/**
|
||||
* @author Mattias Hellborg Arthursson
|
||||
*/
|
||||
public class DefaultObjectDirectoryMapperTest {
|
||||
|
||||
private DefaultObjectDirectoryMapper tested;
|
||||
|
||||
@Before
|
||||
public void prepareTestedInstance() {
|
||||
tested = new DefaultObjectDirectoryMapper();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMapping() {
|
||||
tested.manageClass(UnitTestPerson.class);
|
||||
|
||||
DefaultObjectDirectoryMapper.EntityData entityData = tested.getMetaDataMap().get(UnitTestPerson.class);
|
||||
|
||||
assertNotNull(entityData);
|
||||
assertEquals(query().
|
||||
where("objectclass").is("inetOrgPerson")
|
||||
.and("objectclass").is("organizationalPerson")
|
||||
.and("objectclass").is("person")
|
||||
.and("objectclass").is("top")
|
||||
.filter(), entityData.ocFilter);
|
||||
|
||||
assertEquals(7, entityData.metaData.size());
|
||||
|
||||
AttributeMetaData idAttribute = entityData.metaData.getIdAttribute();
|
||||
assertEquals("dn", idAttribute.getField().getName());
|
||||
assertTrue(idAttribute.isId());
|
||||
assertFalse(idAttribute.isBinary());
|
||||
assertFalse(idAttribute.isDnAttribute());
|
||||
assertFalse(idAttribute.isTransient());
|
||||
assertFalse(idAttribute.isList());
|
||||
|
||||
assertField(entityData, "fullName", "cn", "cn", false, false, false);
|
||||
assertField(entityData, "lastName", "sn", null, false, false, false);
|
||||
assertField(entityData, "description", "description", null, false, false, true);
|
||||
assertField(entityData, "country", null, "c", false, true, false);
|
||||
assertField(entityData, "company", null, "ou", false, true, false);
|
||||
assertField(entityData, "telephoneNumber", "telephoneNumber", null, false, false, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInvalidType() {
|
||||
try {
|
||||
tested.manageClass(UnitTestPersonWithInvalidFieldType.class);
|
||||
} catch (InvalidEntryException expected) {
|
||||
assertThat(expected.getMessage(), JUnitMatchers.containsString("Missing converter from"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIndexedDnAttributes() {
|
||||
tested.manageClass(UnitTestPersonWithIndexedDnAttributes.class);
|
||||
|
||||
UnitTestPersonWithIndexedDnAttributes testPerson = new UnitTestPersonWithIndexedDnAttributes();
|
||||
testPerson.setFullName("Some Person");
|
||||
testPerson.setCompany("Some Company");
|
||||
testPerson.setCountry("Sweden");
|
||||
|
||||
|
||||
Name calculatedId = tested.getCalculatedId(testPerson);
|
||||
assertEquals(LdapUtils.newLdapName("cn=Some Person, ou=Some Company, c=Sweden"), calculatedId);
|
||||
}
|
||||
|
||||
@Test(expected = MetaDataException.class)
|
||||
public void testIndexedDnAttributesRequiresThatAllAreIndexed() {
|
||||
tested.manageClass(UnitTestPersonWithIndexedAndUnindexedDnAttributes.class);
|
||||
}
|
||||
|
||||
private void assertField(DefaultObjectDirectoryMapper.EntityData entityData,
|
||||
String fieldName,
|
||||
String expectedAttributeName,
|
||||
String expectedDnAttributeName,
|
||||
boolean expectedBinary,
|
||||
boolean expectedTransient,
|
||||
boolean expectedList) {
|
||||
|
||||
for (Field field : entityData.metaData) {
|
||||
if (fieldName.equals(field.getName())) {
|
||||
AttributeMetaData attribute = entityData.metaData.getAttribute(field);
|
||||
if (StringUtils.hasLength(expectedAttributeName)) {
|
||||
assertEquals(expectedAttributeName, attribute.getName().toString());
|
||||
} else {
|
||||
assertNull(attribute.getName());
|
||||
}
|
||||
|
||||
if (StringUtils.hasLength(expectedDnAttributeName)) {
|
||||
assertTrue(attribute.isDnAttribute());
|
||||
assertEquals(expectedDnAttributeName, attribute.getDnAttribute().value());
|
||||
} else {
|
||||
assertFalse(attribute.isDnAttribute());
|
||||
}
|
||||
|
||||
assertEquals(expectedBinary, attribute.isBinary());
|
||||
assertEquals(expectedTransient, attribute.isTransient());
|
||||
assertEquals(expectedList, attribute.isList());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* 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.core.impl;
|
||||
|
||||
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 org.springframework.ldap.odm.annotations.Transient;
|
||||
|
||||
import javax.naming.Name;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Mattias Hellborg Arthursson
|
||||
*/
|
||||
@Entry(objectClasses = {"inetOrgPerson", "organizationalPerson", "person", "top"})
|
||||
public class UnitTestPerson {
|
||||
@Id
|
||||
private Name dn;
|
||||
|
||||
@Attribute(name = "cn")
|
||||
@DnAttribute("cn")
|
||||
private String fullName;
|
||||
|
||||
@Attribute(name = "sn")
|
||||
private String lastName;
|
||||
|
||||
@Attribute(name = "description")
|
||||
private List<String> description;
|
||||
|
||||
@Transient
|
||||
@DnAttribute("c")
|
||||
private String country;
|
||||
|
||||
@Transient
|
||||
@DnAttribute("ou")
|
||||
private String company;
|
||||
|
||||
// This should be automatically found
|
||||
private String telephoneNumber;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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.core.impl;
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* @author Mattias Hellborg Arthursson
|
||||
*/
|
||||
@Entry(objectClasses = {"inetOrgPerson", "organizationalPerson", "person", "top"})
|
||||
public class UnitTestPersonWithIndexedAndUnindexedDnAttributes {
|
||||
@Id
|
||||
private Name dn;
|
||||
|
||||
@DnAttribute(value = "cn", index=2)
|
||||
private String fullName;
|
||||
|
||||
// This makes the entry invalid
|
||||
@DnAttribute(value = "ou")
|
||||
private String company;
|
||||
|
||||
@DnAttribute(value= "c", index=0)
|
||||
private String country;
|
||||
|
||||
public void setFullName(String fullName) {
|
||||
this.fullName = fullName;
|
||||
}
|
||||
|
||||
public void setCompany(String company) {
|
||||
this.company = company;
|
||||
}
|
||||
|
||||
public void setCountry(String country) {
|
||||
this.country = country;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* 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.core.impl;
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* @author Mattias Hellborg Arthursson
|
||||
*/
|
||||
@Entry(objectClasses = {"inetOrgPerson", "organizationalPerson", "person", "top"})
|
||||
public class UnitTestPersonWithIndexedDnAttributes {
|
||||
@Id
|
||||
private Name dn;
|
||||
|
||||
@DnAttribute(value = "cn", index=2)
|
||||
private String fullName;
|
||||
|
||||
@DnAttribute(value = "ou", index=1)
|
||||
private String company;
|
||||
|
||||
@DnAttribute(value= "c", index=0)
|
||||
private String country;
|
||||
|
||||
public void setFullName(String fullName) {
|
||||
this.fullName = fullName;
|
||||
}
|
||||
|
||||
public void setCompany(String company) {
|
||||
this.company = company;
|
||||
}
|
||||
|
||||
public void setCountry(String country) {
|
||||
this.country = country;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* 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.core.impl;
|
||||
|
||||
import org.springframework.ldap.odm.annotations.Attribute;
|
||||
import org.springframework.ldap.odm.annotations.Entry;
|
||||
import org.springframework.ldap.odm.annotations.Id;
|
||||
|
||||
import javax.naming.Name;
|
||||
|
||||
/**
|
||||
* @author Mattias Hellborg Arthursson
|
||||
*/
|
||||
@Entry(objectClasses = {"inetOrgPerson", "organizationalPerson", "person", "top"})
|
||||
public class UnitTestPersonWithInvalidFieldType {
|
||||
@Id
|
||||
private Name dn;
|
||||
|
||||
@Attribute(name = "cn")
|
||||
private Class<?> fullName;
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
Sample application demonstrating how to do the most basic stuff in Spring LDAP using the Object-Directory Mapping facilities.
|
||||
A very simple dao implementation is provided in org.springframework.ldap.samples.plain.dao.PersonDaoImpl
|
||||
A very simple dao implementation is provided in org.springframework.ldap.samples.plain.dao.OdmPersonDaoImpl
|
||||
It demonstrates some basic operations using Spring LDAP Object-Directory Mapping.
|
||||
|
||||
The core Spring application context of the sample is defined in resources/applicationContext.xml.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2005-2010 the original author or authors.
|
||||
* 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.
|
||||
@@ -13,10 +13,11 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.ldap.samples.plain.dao;
|
||||
package org.springframework.ldap.samples.odm.dao;
|
||||
|
||||
import org.springframework.ldap.core.AttributesMapper;
|
||||
import org.springframework.ldap.core.LdapTemplate;
|
||||
import org.springframework.ldap.samples.plain.dao.PersonDao;
|
||||
import org.springframework.ldap.samples.plain.domain.Person;
|
||||
import org.springframework.ldap.support.LdapNameBuilder;
|
||||
|
||||
@@ -28,33 +29,23 @@ import java.util.List;
|
||||
import static org.springframework.ldap.query.LdapQueryBuilder.query;
|
||||
|
||||
/**
|
||||
* Default implementation of PersonDao. This implementation uses
|
||||
* DirContextAdapter for managing attribute values. We use a ContextMapper
|
||||
* to map from the found contexts to our domain objects. This is especially useful
|
||||
* since we in this case have properties in our domain objects that depend on parts of the DN.
|
||||
*
|
||||
* We could have worked with Attributes and an AttributesMapper implementation
|
||||
* instead, but working with Attributes is a bore and also, working with
|
||||
* AttributesMapper objects (or, indeed Attributes) does not give us access to
|
||||
* the distinguished name. However, we do use it in one method that only needs a
|
||||
* single attribute: {@link #getAllPersonNames()}.
|
||||
* Default implementation of PersonDao. This implementation uses the Object-Directory Mapping feature,
|
||||
* which requires the entity classes to be annotated, but relieves the programmer from the tedious
|
||||
* task of mapping to and from entity objects, using attribute or dn component values.
|
||||
*
|
||||
* @author Mattias Hellborg Arthursson
|
||||
* @author Ulrik Sandberg
|
||||
*/
|
||||
public class PersonDaoImpl implements PersonDao {
|
||||
public class OdmPersonDaoImpl implements PersonDao {
|
||||
|
||||
private LdapTemplate ldapTemplate;
|
||||
|
||||
@Override
|
||||
public void create(Person person) {
|
||||
person.setDn(buildDn(person));
|
||||
ldapTemplate.create(person);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(Person person) {
|
||||
person.setDn(buildDn(person));
|
||||
ldapTemplate.update(person);
|
||||
}
|
||||
|
||||
@@ -85,11 +76,6 @@ public class PersonDaoImpl implements PersonDao {
|
||||
LdapName dn = buildDn(country, company, fullname);
|
||||
Person person = ldapTemplate.findByDn(dn, Person.class);
|
||||
|
||||
// TODO: This needs to happen automatically
|
||||
person.setCountry(country);
|
||||
person.setCompany(company);
|
||||
person.setFullName(fullname);
|
||||
|
||||
return person;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2005-2010 the original author or authors.
|
||||
* 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.
|
||||
@@ -20,6 +20,7 @@ import org.apache.commons.lang.builder.HashCodeBuilder;
|
||||
import org.apache.commons.lang.builder.ToStringBuilder;
|
||||
import org.apache.commons.lang.builder.ToStringStyle;
|
||||
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 org.springframework.ldap.odm.annotations.Transient;
|
||||
@@ -38,6 +39,7 @@ public class Person {
|
||||
private Name dn;
|
||||
|
||||
@Attribute(name = "cn")
|
||||
@DnAttribute(value = "cn", index = 2)
|
||||
private String fullName;
|
||||
|
||||
@Attribute(name = "sn")
|
||||
@@ -47,9 +49,11 @@ public class Person {
|
||||
private String description;
|
||||
|
||||
@Transient
|
||||
@DnAttribute(value = "c", index = 0)
|
||||
private String country;
|
||||
|
||||
@Transient
|
||||
@DnAttribute(value = "ou", index = 1)
|
||||
private String company;
|
||||
|
||||
@Attribute(name = "telephoneNumber")
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
</bean>
|
||||
|
||||
<bean id="personDao"
|
||||
class="org.springframework.ldap.samples.plain.dao.PersonDaoImpl">
|
||||
class="org.springframework.ldap.samples.odm.dao.OdmPersonDaoImpl">
|
||||
<property name="ldapTemplate" ref="ldapTemplate" />
|
||||
</bean>
|
||||
|
||||
|
||||
@@ -13,12 +13,13 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.ldap.samples.plain.dao;
|
||||
package org.springframework.ldap.samples.odm.dao;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.ldap.NameNotFoundException;
|
||||
import org.springframework.ldap.samples.plain.dao.PersonDao;
|
||||
import org.springframework.ldap.samples.plain.domain.Person;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests;
|
||||
@@ -81,7 +82,10 @@ public class PersonDaoSampleIntegrationTest extends
|
||||
assertEquals(
|
||||
"Another description", result
|
||||
.getDescription());
|
||||
} finally {
|
||||
} catch(Exception e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
finally {
|
||||
personDao.delete(person);
|
||||
try {
|
||||
personDao.findByPrimaryKey(
|
||||
@@ -23,7 +23,7 @@
|
||||
</bean>
|
||||
|
||||
<bean id="personDao"
|
||||
class="org.springframework.ldap.samples.plain.dao.PersonDaoImpl">
|
||||
class="org.springframework.ldap.samples.odm.dao.OdmPersonDaoImpl">
|
||||
<property name="ldapTemplate" ref="ldapTemplate" />
|
||||
</bean>
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2005-2010 the original author or authors.
|
||||
* 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.
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
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 org.springframework.ldap.odm.annotations.Transient;
|
||||
|
||||
import javax.naming.Name;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Mattias Hellborg Arthursson
|
||||
*/
|
||||
@Entry(objectClasses = { "inetOrgPerson", "organizationalPerson", "person", "top" })
|
||||
public class PersonWithDnAnnotations {
|
||||
@Id
|
||||
private Name dn;
|
||||
|
||||
@Attribute(name = "cn")
|
||||
@DnAttribute(value="cn", index=2)
|
||||
private String commonName;
|
||||
|
||||
@Attribute(name = "sn")
|
||||
private String surname;
|
||||
|
||||
@Attribute(name = "description")
|
||||
private List<String> desc;
|
||||
|
||||
@Attribute(name = "uid")
|
||||
private List<String> userId;
|
||||
|
||||
@Attribute(name = "telephoneNumber")
|
||||
private String telephoneNumber;
|
||||
|
||||
@DnAttribute(value="ou", index=1)
|
||||
@Transient
|
||||
private String company;
|
||||
|
||||
@DnAttribute(value="c", index=0)
|
||||
@Transient
|
||||
private String country;
|
||||
|
||||
public Name getDn() {
|
||||
return dn;
|
||||
}
|
||||
|
||||
public void setDn(Name dn) {
|
||||
this.dn = dn;
|
||||
}
|
||||
|
||||
public String getCommonName() {
|
||||
return commonName;
|
||||
}
|
||||
|
||||
public void setCommonName(String commonName) {
|
||||
this.commonName = commonName;
|
||||
}
|
||||
|
||||
public String getSurname() {
|
||||
return surname;
|
||||
}
|
||||
|
||||
public void setSurname(String surname) {
|
||||
this.surname = surname;
|
||||
}
|
||||
|
||||
public List<String> getDesc() {
|
||||
return desc;
|
||||
}
|
||||
|
||||
public void setDesc(List<String> desc) {
|
||||
this.desc = desc;
|
||||
}
|
||||
|
||||
public List<String> getUserId() {
|
||||
return userId;
|
||||
}
|
||||
|
||||
public void setUserId(List<String> userId) {
|
||||
this.userId = userId;
|
||||
}
|
||||
|
||||
public String getTelephoneNumber() {
|
||||
return telephoneNumber;
|
||||
}
|
||||
|
||||
public void setTelephoneNumber(String telephoneNumber) {
|
||||
this.telephoneNumber = telephoneNumber;
|
||||
}
|
||||
|
||||
public String getCompany() {
|
||||
return company;
|
||||
}
|
||||
|
||||
public void setCompany(String company) {
|
||||
this.company = company;
|
||||
}
|
||||
|
||||
public String getCountry() {
|
||||
return country;
|
||||
}
|
||||
|
||||
public void setCountry(String country) {
|
||||
this.country = country;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
* 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 java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.springframework.ldap.query.LdapQueryBuilder.query;
|
||||
|
||||
/**
|
||||
* @author Mattias Hellborg Arthursson
|
||||
*/
|
||||
@ContextConfiguration(locations = {"/conf/ldapTemplateTestContext.xml"})
|
||||
public class LdapTemplateOdmWithDnAnnotationsITest extends AbstractLdapTemplateIntegrationTest {
|
||||
@Autowired
|
||||
private LdapTemplate tested;
|
||||
|
||||
@Test
|
||||
public void testFindOne() {
|
||||
PersonWithDnAnnotations person = tested.findOne(query()
|
||||
.where("cn").is("Some Person3"), PersonWithDnAnnotations.class);
|
||||
|
||||
assertNotNull(person);
|
||||
assertEquals("Some Person3", person.getCommonName());
|
||||
assertEquals("Person3", person.getSurname());
|
||||
assertEquals("Sweden, Company1, Some Person3", person.getDesc().get(0));
|
||||
assertEquals("+46 555-123654", person.getTelephoneNumber());
|
||||
|
||||
// Automatically calculated
|
||||
assertEquals("company1", person.getCompany());
|
||||
assertEquals("Sweden", person.getCountry());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFindByDn() {
|
||||
PersonWithDnAnnotations person = tested.findByDn(LdapUtils.newLdapName("cn=Some Person3,ou=company1,c=Sweden"),
|
||||
PersonWithDnAnnotations.class);
|
||||
|
||||
assertNotNull(person);
|
||||
assertEquals("Some Person3", person.getCommonName());
|
||||
assertEquals("Person3", person.getSurname());
|
||||
assertEquals("Sweden, Company1, Some Person3", person.getDesc().get(0));
|
||||
assertEquals("+46 555-123654", person.getTelephoneNumber());
|
||||
|
||||
// Automatically calculated
|
||||
assertEquals("company1", person.getCompany());
|
||||
assertEquals("Sweden", person.getCountry());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFindInCountry() {
|
||||
List<PersonWithDnAnnotations> persons = tested.find(query()
|
||||
.base("c=Sweden")
|
||||
.where("cn").isPresent(), PersonWithDnAnnotations.class);
|
||||
|
||||
assertEquals(4, persons.size());
|
||||
|
||||
PersonWithDnAnnotations person = findPerson(persons, "Some Person3");
|
||||
|
||||
// Automatically calculated
|
||||
assertEquals("company1", person.getCompany());
|
||||
assertEquals("Sweden", person.getCountry());
|
||||
}
|
||||
|
||||
private PersonWithDnAnnotations findPerson(List<PersonWithDnAnnotations> persons, String cn) {
|
||||
for (PersonWithDnAnnotations person : persons) {
|
||||
if(person.getCommonName().equals(cn)) {
|
||||
return person;
|
||||
}
|
||||
}
|
||||
|
||||
fail(String.format("Person with cn %s not found", cn));
|
||||
// we'll never get here
|
||||
return null;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateWithCalculatedDn() {
|
||||
PersonWithDnAnnotations person = new PersonWithDnAnnotations();
|
||||
|
||||
// Don't explicitly set DN.
|
||||
person.setCommonName("New Person");
|
||||
person.setSurname("Person");
|
||||
person.setDesc(Arrays.asList("This is the description"));
|
||||
person.setTelephoneNumber("0123456");
|
||||
person.setCompany("company1");
|
||||
person.setCountry("Sweden");
|
||||
|
||||
tested.create(person);
|
||||
|
||||
assertEquals(6, tested.findAll(PersonWithDnAnnotations.class).size());
|
||||
|
||||
person = tested.findByDn(LdapUtils.newLdapName("cn=New Person,ou=company1,c=Sweden"),
|
||||
PersonWithDnAnnotations.class);
|
||||
|
||||
assertEquals("New Person", person.getCommonName());
|
||||
assertEquals("Person", person.getSurname());
|
||||
assertEquals("This is the description", person.getDesc().get(0));
|
||||
assertEquals("0123456", person.getTelephoneNumber());
|
||||
|
||||
// Automatically calculated
|
||||
assertEquals("company1", person.getCompany());
|
||||
assertEquals("Sweden", person.getCountry());
|
||||
}
|
||||
|
||||
// @Test
|
||||
// public void testUpdate() {
|
||||
// Person person = tested.findOne(query()
|
||||
// .where("cn").is("Some Person3"), Person.class);
|
||||
//
|
||||
// person.setDesc(Arrays.asList("New Description"));
|
||||
// tested.update(person);
|
||||
//
|
||||
// person = tested.findOne(query()
|
||||
// .where("cn").is("Some Person3"), Person.class);
|
||||
//
|
||||
// assertEquals("Some Person3", person.getCommonName());
|
||||
// assertEquals("Person3", person.getSurname());
|
||||
// assertEquals("New Description", person.getDesc().get(0));
|
||||
// assertEquals("+46 555-123654", person.getTelephoneNumber());
|
||||
// }
|
||||
//
|
||||
// @Test
|
||||
// public void testDelete() {
|
||||
// Person person = tested.findOne(query()
|
||||
// .where("cn").is("Some Person3"), Person.class);
|
||||
//
|
||||
// tested.delete(person);
|
||||
//
|
||||
// try {
|
||||
// tested.findOne(query().where("cn").is("Some Person3"), Person.class);
|
||||
// fail("EmptyResultDataAccessException e");
|
||||
// } catch (EmptyResultDataAccessException e) {
|
||||
// assertTrue(true);
|
||||
// }
|
||||
// }
|
||||
}
|
||||
@@ -39,7 +39,7 @@ import static org.springframework.ldap.query.LdapQueryBuilder.query;
|
||||
* @author Mattias Hellborg Arthursson
|
||||
*/
|
||||
@ContextConfiguration(locations = {"/conf/ldapTemplateTestContext.xml"})
|
||||
public class LdapTemplateOdmITest extends AbstractLdapTemplateIntegrationTest {
|
||||
public class LdapTemplateOdmWithNoDnAnnotationsITest extends AbstractLdapTemplateIntegrationTest {
|
||||
@Autowired
|
||||
private LdapTemplate tested;
|
||||
|
||||
Reference in New Issue
Block a user