Patch from Jasper on July 24.
This commit is contained in:
@@ -25,6 +25,7 @@
|
||||
|
||||
<bean id="referencedEntryEditorFactory" singleton="true"
|
||||
class="org.springframework.ldap.odm.attributetypes.ReferencedEntryEditorFactory">
|
||||
<constructor-arg value="${base}" />
|
||||
<constructor-arg ref="ldapTemplate"/>
|
||||
</bean>
|
||||
|
||||
|
||||
@@ -11,6 +11,12 @@ import java.lang.annotation.Retention;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* The <code>DirAttribute</code> describes the mapping between a bean property and an LDAP attribute.
|
||||
* For example <pre>@DirAttribute("uid")</pre> maps a bean property to the directory attribute
|
||||
* 'uid'. A <code>DirAttribute</code> without a value designates that the attribute has the same name
|
||||
* as the bean property.
|
||||
*/
|
||||
@Documented
|
||||
@Target({FIELD})
|
||||
@Retention(RUNTIME)
|
||||
|
||||
@@ -11,7 +11,16 @@ import java.lang.annotation.Retention;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
|
||||
/**
|
||||
* The <code>NamingAttribute</code> annotation identifies the name of the attribute that forms
|
||||
* the first part of a Distinguished Name. For example, in the Distinguished Name
|
||||
* 'uid=x232, ou=people' the naming attribute is 'uid'. The <code>NamingAttribute</code> together
|
||||
* with a <code>NamingSuffix</code> tell the Object Directory Mapper how to serialize a java object
|
||||
* to and from an LDAP repository.
|
||||
* Example: <pre>@NamingAttribute("uid")</pre>
|
||||
*
|
||||
* @see NamingSuffix
|
||||
*/
|
||||
@Documented
|
||||
@Target({TYPE})
|
||||
@Retention(RUNTIME)
|
||||
|
||||
@@ -10,12 +10,15 @@ import static java.lang.annotation.ElementType.TYPE;
|
||||
import java.lang.annotation.Retention;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
import java.lang.annotation.Target;
|
||||
/*
|
||||
* Copyright 2006 by Sensis. All Rights Reserved.
|
||||
*
|
||||
* This software is the proprietary information of Majitek. Use is subject to license terms.
|
||||
*/
|
||||
|
||||
/**
|
||||
* The <code>NamingSuffix</code> annotation describes where in an LDAP repository an entry resides.
|
||||
* For example an object annotated with:
|
||||
* <pre>@NamingSuffix({"ou=people", "dc=example", "dc=com"})</pre>
|
||||
* will be persisted under the branch 'com/example/people' in the LDAP repository.
|
||||
*
|
||||
* @see NamingAttribute
|
||||
*/
|
||||
@Documented
|
||||
@Target({TYPE})
|
||||
@Retention(RUNTIME)
|
||||
|
||||
@@ -11,6 +11,11 @@ import java.lang.annotation.Retention;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* The <code>ObjectClasses</code> annotation describes which Object Classes an LDAP entry contains
|
||||
* attributes for.
|
||||
* Example: <pre>@ObjectClasses({"person", "organizationalPerson", "inetorgperson"})</pre>
|
||||
*/
|
||||
@Documented
|
||||
@Target({TYPE})
|
||||
@Retention(RUNTIME)
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
<html>
|
||||
<body>
|
||||
|
||||
Contains the annotations for mapping a java object to an LDAP entry.
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -16,14 +16,23 @@ import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* LdapTypeConverter is responsible for the conversion of LDAP attributes returned in String form
|
||||
* to native java types and vice versa. Mostly it leverages Spring's property editors, however
|
||||
* it registers some custom editors to:
|
||||
* to native java types and vice versa. It it leverages Spring's property editors, with
|
||||
* some custom editors to:
|
||||
* <li>
|
||||
* <ul>convert from Generalized Time strings to java.util.Date</ul>
|
||||
* <ul>convert generalized time strings to <code>java.util.Date.</code></ul>
|
||||
* <ul>convert dn strings to <code>javax.naming.ldap.LdapName</code> or
|
||||
* <code>org.springframework.ldap.core.DistinguishedName</code>.
|
||||
* <code>org.springframework.ldap.core.DistinguishedName</code>.</ul>
|
||||
* </li>
|
||||
* </p>
|
||||
* <p>
|
||||
* Additional custom editors may be created at runtime to if an Object Directory Map
|
||||
* contains references to other mapped objects (eg. A role of type Role.class containing
|
||||
* references to members of type Person.class)
|
||||
*
|
||||
* </p>
|
||||
*
|
||||
*/
|
||||
public class LdapTypeConverter extends SimpleTypeConverter
|
||||
{
|
||||
|
||||
@@ -6,47 +6,60 @@
|
||||
package org.springframework.ldap.odm.attributetypes;
|
||||
|
||||
import org.springframework.ldap.core.LdapTemplate;
|
||||
import org.springframework.ldap.core.DistinguishedName;
|
||||
import org.springframework.ldap.odm.mapping.MappingException;
|
||||
import org.springframework.ldap.odm.mapping.ObjectDirectoryMapper;
|
||||
|
||||
import javax.naming.InvalidNameException;
|
||||
import javax.naming.ldap.LdapName;
|
||||
import java.beans.PropertyEditorSupport;
|
||||
|
||||
/** ReferencedEntryEditor is responsible for converting references in an object
|
||||
* directory map from distinguished name strings to the target type and vice versa.
|
||||
*/
|
||||
public class ReferencedEntryEditor extends PropertyEditorSupport
|
||||
{
|
||||
private DistinguishedName base;
|
||||
private LdapTemplate ldapTemplate;
|
||||
private ObjectDirectoryMapper objectDirectoryMapper;
|
||||
|
||||
public ReferencedEntryEditor(LdapTemplate ldapTemplate,
|
||||
public ReferencedEntryEditor(DistinguishedName baseDn,
|
||||
LdapTemplate ldapTemplate,
|
||||
ObjectDirectoryMapper objectDirectoryMapper)
|
||||
{
|
||||
this.base = baseDn;
|
||||
this.ldapTemplate = ldapTemplate;
|
||||
this.objectDirectoryMapper = objectDirectoryMapper;
|
||||
}
|
||||
|
||||
/** Builds a distinguished name from the instance value */
|
||||
public String getAsText()
|
||||
{
|
||||
try
|
||||
{
|
||||
return objectDirectoryMapper.buildDn(getValue()).toString();
|
||||
DistinguishedName value = (DistinguishedName) base.clone();
|
||||
value.append((DistinguishedName) objectDirectoryMapper.buildDn(getValue()));
|
||||
return value.toString();
|
||||
}
|
||||
catch (MappingException e)
|
||||
{
|
||||
throw new RuntimeException(
|
||||
"Mapping exception: " + getValue().getClass().getSimpleName());
|
||||
throw new RuntimeException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/** Sets the value of the editor by performing a lookup and mapping the result
|
||||
* to the target type using an object directory mapper.
|
||||
* @param text The distinguished name of an ldap entry.
|
||||
* @throws IllegalArgumentException
|
||||
*/
|
||||
public void setAsText(String text) throws IllegalArgumentException
|
||||
{
|
||||
try
|
||||
DistinguishedName dn = new DistinguishedName(text);
|
||||
if (dn.startsWith(base))
|
||||
{
|
||||
setValue(ldapTemplate.lookup(new LdapName(text), objectDirectoryMapper));
|
||||
}
|
||||
catch (InvalidNameException e)
|
||||
{
|
||||
throw new IllegalArgumentException(e.getMessage(), e);
|
||||
for (int i = 0; i < base.size(); i++)
|
||||
{
|
||||
dn.removeFirst();
|
||||
}
|
||||
}
|
||||
setValue(ldapTemplate.lookup(dn, objectDirectoryMapper));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
/*
|
||||
* Copyright 2005 by Majitek. All Rights Reserved.
|
||||
*
|
||||
* This software is the proprietary information of Majitek. Use is subject to license terms.
|
||||
*/
|
||||
|
||||
package org.springframework.ldap.odm.attributetypes;
|
||||
|
||||
public class ReferencedEntryEditorCreationException extends Exception
|
||||
{
|
||||
public ReferencedEntryEditorCreationException(String message, Exception cause)
|
||||
{
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ package org.springframework.ldap.odm.attributetypes;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.ldap.core.DistinguishedName;
|
||||
import org.springframework.ldap.core.LdapTemplate;
|
||||
import org.springframework.ldap.odm.mapping.MappingException;
|
||||
import org.springframework.ldap.odm.mapping.ObjectDirectoryMapper;
|
||||
@@ -15,21 +16,37 @@ import org.springframework.ldap.odm.mapping.ObjectDirectoryMapperFactory;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* ReferencedEntryEditorFactory is a factory for assembling ReferencedEntryEditors.
|
||||
*
|
||||
* @see ReferencedEntryEditor
|
||||
*/
|
||||
public class ReferencedEntryEditorFactory
|
||||
{
|
||||
private static final Log LOGGER = LogFactory.getLog(ReferencedEntryEditorFactory.class);
|
||||
private String base;
|
||||
private ObjectDirectoryMapperFactory odmFactory;
|
||||
private LdapTemplate ldapTemplate;
|
||||
private Map<Class, ReferencedEntryEditor> referencedEntryEditors;
|
||||
|
||||
public ReferencedEntryEditorFactory(LdapTemplate ldapTemplate)
|
||||
public ReferencedEntryEditorFactory(String base, LdapTemplate ldapTemplate)
|
||||
{
|
||||
this.base = base;
|
||||
this.ldapTemplate = ldapTemplate;
|
||||
this.referencedEntryEditors = new HashMap();
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to build a ReferencedEntryEditor for the given type. If Object Directory
|
||||
* Mapping for the given type is successful an editor is returned, otherwise a
|
||||
* <code>MappingException</code> is thrown.
|
||||
*
|
||||
* @param clazz the type to build a ReferencedEntryEditor for.
|
||||
* @return A ReferencedEntryEditor for the given type.
|
||||
*
|
||||
*/
|
||||
public ReferencedEntryEditor referencedEntryEditorForClass(Class clazz)
|
||||
throws ReferencedEntryEditorCreationException
|
||||
throws MappingException
|
||||
{
|
||||
if (referencedEntryEditors.containsKey(clazz))
|
||||
{
|
||||
@@ -41,21 +58,18 @@ public class ReferencedEntryEditorFactory
|
||||
LOGGER.debug("Attempting to create a referenced entry editor for class: "
|
||||
+ clazz.getSimpleName());
|
||||
|
||||
try
|
||||
{
|
||||
ObjectDirectoryMapper odm = odmFactory.objectDirectoryMapperForClass(clazz);
|
||||
ReferencedEntryEditor referencedEntryEditor =
|
||||
new ReferencedEntryEditor(ldapTemplate, odm);
|
||||
referencedEntryEditors.put(clazz, referencedEntryEditor);
|
||||
return referencedEntryEditor;
|
||||
}
|
||||
catch (MappingException e)
|
||||
{
|
||||
throw new ReferencedEntryEditorCreationException(e.getMessage(), e);
|
||||
}
|
||||
ObjectDirectoryMapper odm = odmFactory.objectDirectoryMapperForClass(clazz);
|
||||
ReferencedEntryEditor referencedEntryEditor =
|
||||
new ReferencedEntryEditor(new DistinguishedName(base), ldapTemplate, odm);
|
||||
referencedEntryEditors.put(clazz, referencedEntryEditor);
|
||||
return referencedEntryEditor;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mapperFactory the <code>ObjectDirectoryMapperFactory</code> to use when attempting
|
||||
* to build a <code>ReferencedEntryEditor</code>.
|
||||
*/
|
||||
public void setObjectDirectoryMapperFactory(ObjectDirectoryMapperFactory
|
||||
mapperFactory)
|
||||
{
|
||||
|
||||
@@ -11,7 +11,7 @@ import javax.naming.ldap.LdapName;
|
||||
import java.util.Date;
|
||||
|
||||
|
||||
/* Should be able to support any of Spring's conversion types. Add a test case if you add one */
|
||||
/** This list of types supported for mapping between ldap attributes and bean properties. */
|
||||
public enum ValidConversionType
|
||||
{
|
||||
BYTE_ARRAY(byte[].class),
|
||||
@@ -38,11 +38,7 @@ public enum ValidConversionType
|
||||
|
||||
}
|
||||
|
||||
public Class getClazz()
|
||||
{
|
||||
return clazz;
|
||||
}
|
||||
|
||||
/** Returns the enumeration of types as a human-friendly string. */
|
||||
public static String listTypes()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
@@ -50,7 +46,7 @@ public enum ValidConversionType
|
||||
{
|
||||
ValidConversionType validType = ValidConversionType.values()[i];
|
||||
sb.append("\n");
|
||||
sb.append(validType.getClazz().getSimpleName());
|
||||
sb.append(validType.clazz.getSimpleName());
|
||||
if (i != ValidConversionType.values().length - 1)
|
||||
{
|
||||
sb.append(",");
|
||||
@@ -59,11 +55,12 @@ public enum ValidConversionType
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/** Returns true if the argument is a member of this enumeration. */
|
||||
public static boolean isValidConversionType(Class returnType)
|
||||
{
|
||||
for (ValidConversionType type : ValidConversionType.values())
|
||||
{
|
||||
if (returnType.equals(type.getClazz()))
|
||||
if (returnType.equals(type.clazz))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -71,5 +68,7 @@ public enum ValidConversionType
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
<html>
|
||||
<body>
|
||||
|
||||
Contains support classes used to assemble an <code>LdapDao</code> implementation.
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -5,6 +5,11 @@
|
||||
*/
|
||||
package org.springframework.ldap.odm.dao;
|
||||
|
||||
/**
|
||||
* Thrown by <code>LdapDao</code> under exceptional circumstances.
|
||||
*
|
||||
* @see LdapDao
|
||||
*/
|
||||
public class DaoException extends RuntimeException
|
||||
{
|
||||
public DaoException(String message)
|
||||
|
||||
@@ -8,21 +8,36 @@ package org.springframework.ldap.odm.dao;
|
||||
import javax.naming.Name;
|
||||
import java.util.List;
|
||||
|
||||
/** A realization of the Data Access Object (DAO) pattern using object directory mapping. */
|
||||
public interface LdapDao
|
||||
{
|
||||
/** Persists the mapped object dirObject in the LDAP repository. */
|
||||
void create(Object dirObject);
|
||||
|
||||
/** Retrieves the entry in the LDAP repository corresponding to the mapped object dirObject,
|
||||
* and updates the attributes to match the values in dirObject.
|
||||
*/
|
||||
void update(Object dirObject);
|
||||
|
||||
/** If an entry exists in the repository corresponding to the mapped object dirObject, it is
|
||||
* updated, otherwise it is created.
|
||||
*/
|
||||
void createOrUpdate(Object dirObject);
|
||||
|
||||
/** if an entry exists in the repository corresponding to the mapped object dirObject,
|
||||
* it is deleted.
|
||||
*/
|
||||
void delete(Object dirObject);
|
||||
|
||||
/** Retrieves a uniquely named entry from the repository and maps it the class returnType. */
|
||||
Object findByNamingAttribute(String namingValue, Class returnType);
|
||||
|
||||
/** Retrieves a uniquely named entry from the repository and maps it the class returnType. */
|
||||
public Object findByDn(Name dn, Class returnType);
|
||||
|
||||
/** Find all entries in the repository that match the object classes declared on ofType. */
|
||||
List findAll(Class ofType);
|
||||
|
||||
/** Search for entries in the repository and map results to class returnType. */
|
||||
List filterByBeanProperty(String value, String beanPropertyName, Class returnType);
|
||||
}
|
||||
|
||||
@@ -17,6 +17,9 @@ import org.springframework.ldap.odm.mapping.ObjectDirectoryMapperFactory;
|
||||
import javax.naming.Name;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* An implementation of the <code>LdapDao</code> interface.
|
||||
*/
|
||||
public class LdapDaoImpl implements LdapDao
|
||||
{
|
||||
static final Log LOGGER = LogFactory.getLog(LdapDaoImpl.class);
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
<html>
|
||||
<body>
|
||||
|
||||
Provides a realization of the Data Access Object (DAO) pattern using object directory mapping.
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -14,6 +14,10 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* An abstract base class implementing an <code>ObjectDirectoryMap</code>. Actual parsing of
|
||||
* mapping information needs to be implemented in a concrete sub class.
|
||||
*/
|
||||
public abstract class AbstractObjectDirectoryMap implements ObjectDirectoryMap
|
||||
{
|
||||
protected static final Log LOGGER = LogFactory.getLog(AnnotationObjectDirectoryMap.class);
|
||||
@@ -34,26 +38,24 @@ public abstract class AbstractObjectDirectoryMap implements ObjectDirectoryMap
|
||||
beanPropertyNameKeys = new HashMap();
|
||||
attributeNameKeys = new HashMap();
|
||||
|
||||
parseNamingAttribute();
|
||||
parseObjectClasses();
|
||||
parseNamingSuffix();
|
||||
this.namingAttribute = parseNamingAttribute();
|
||||
this.objectClasses = parseObjectClasses();
|
||||
this.namingSuffix = parseNamingSuffix();
|
||||
mapAttributesToBeanProperties();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ********************************Template *****************************************
|
||||
/* ********************************Template *****************************************
|
||||
*/
|
||||
protected abstract void parseNamingAttribute() throws MappingException;
|
||||
protected abstract String parseNamingAttribute() throws MappingException;
|
||||
|
||||
protected abstract void parseObjectClasses() throws MappingException;
|
||||
protected abstract String[] parseObjectClasses() throws MappingException;
|
||||
|
||||
protected abstract void parseNamingSuffix() throws MappingException;
|
||||
protected abstract DistinguishedName parseNamingSuffix() throws MappingException;
|
||||
|
||||
protected abstract void mapAttributesToBeanProperties() throws MappingException;
|
||||
|
||||
/**
|
||||
* **********************************************************************************
|
||||
/* **********************************************************************************
|
||||
*/
|
||||
|
||||
protected void map(String beanPropertyName, String toAttributeName)
|
||||
|
||||
@@ -14,6 +14,20 @@ import org.springframework.util.StringUtils;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
/** An implementation of an <code>ObjectDirectoryMap</code> based on Annotations. A class that is
|
||||
* to be serialized to and from and LDAP repository must include the following annotations:
|
||||
* <ul>
|
||||
* <li>NamingAttribute</li>
|
||||
* <li>ObjectClasses</li>
|
||||
* <li>NamingSuffix</li>
|
||||
* <li>DirAttribute</li>
|
||||
* </ul>
|
||||
*
|
||||
* @see org.springframework.ldap.odm.annotations.NamingAttribute
|
||||
* @see org.springframework.ldap.odm.annotations.ObjectClasses
|
||||
* @see org.springframework.ldap.odm.annotations.NamingSuffix
|
||||
* @see org.springframework.ldap.odm.annotations.DirAttribute
|
||||
*/
|
||||
public class AnnotationObjectDirectoryMap extends AbstractObjectDirectoryMap
|
||||
{
|
||||
|
||||
@@ -22,10 +36,10 @@ public class AnnotationObjectDirectoryMap extends AbstractObjectDirectoryMap
|
||||
super(clazz);
|
||||
}
|
||||
|
||||
protected void parseNamingAttribute() throws MappingException
|
||||
protected String parseNamingAttribute() throws MappingException
|
||||
{
|
||||
NamingAttribute attnNamingAttr = (NamingAttribute) clazz.getAnnotation(NamingAttribute.class);
|
||||
namingAttribute = attnNamingAttr != null ? attnNamingAttr.value() : null;
|
||||
String namingAttribute = attnNamingAttr != null ? attnNamingAttr.value() : null;
|
||||
|
||||
if (namingAttribute == null)
|
||||
{
|
||||
@@ -33,12 +47,13 @@ public class AnnotationObjectDirectoryMap extends AbstractObjectDirectoryMap
|
||||
+ clazz.getSimpleName()
|
||||
+ ". The @NamingAttribute annotation is required.");
|
||||
}
|
||||
return namingAttribute;
|
||||
}
|
||||
|
||||
protected void parseObjectClasses() throws MappingException
|
||||
protected String[] parseObjectClasses() throws MappingException
|
||||
{
|
||||
ObjectClasses attnObjectClasses = (ObjectClasses) clazz.getAnnotation(ObjectClasses.class);
|
||||
objectClasses = attnObjectClasses != null ? attnObjectClasses.value() : null;
|
||||
String[] objectClasses = attnObjectClasses != null ? attnObjectClasses.value() : null;
|
||||
|
||||
if (objectClasses == null)
|
||||
{
|
||||
@@ -54,9 +69,10 @@ public class AnnotationObjectDirectoryMap extends AbstractObjectDirectoryMap
|
||||
+ "for example: @ObjectClasses({\"top\", \"inetorgperson\"}), and not: "
|
||||
+ "@ObjectClasses({\"top,inetorgperson\"})");
|
||||
}
|
||||
return objectClasses;
|
||||
}
|
||||
|
||||
protected void parseNamingSuffix() throws MappingException
|
||||
protected DistinguishedName parseNamingSuffix() throws MappingException
|
||||
{
|
||||
NamingSuffix attnNamingSuffix = (NamingSuffix) clazz.getAnnotation(NamingSuffix.class);
|
||||
String[] namingSuffixElements = attnNamingSuffix != null ? attnNamingSuffix.value() : null;
|
||||
@@ -77,7 +93,7 @@ public class AnnotationObjectDirectoryMap extends AbstractObjectDirectoryMap
|
||||
+ "@NamingSuffix({\"ou=people,dc=example,dc=com\"})");
|
||||
}
|
||||
|
||||
namingSuffix = new DistinguishedName();
|
||||
DistinguishedName namingSuffix = new DistinguishedName();
|
||||
for (int i = namingSuffixElements.length - 1; i >= 0; i--)
|
||||
{
|
||||
String[] nameValue = namingSuffixElements[i].split("=");
|
||||
@@ -88,6 +104,7 @@ public class AnnotationObjectDirectoryMap extends AbstractObjectDirectoryMap
|
||||
}
|
||||
namingSuffix.add(nameValue[0].trim(), nameValue[1].trim());
|
||||
}
|
||||
return namingSuffix;
|
||||
}
|
||||
|
||||
protected void mapAttributesToBeanProperties()
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
package org.springframework.ldap.odm.mapping;
|
||||
|
||||
/** Thrown when an attempt to create an Object Directory Map for a given class is unsuccessful. */
|
||||
public class MappingException extends Exception
|
||||
{
|
||||
|
||||
|
||||
@@ -7,24 +7,46 @@
|
||||
package org.springframework.ldap.odm.mapping;
|
||||
|
||||
import org.springframework.ldap.core.DistinguishedName;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* <code>ObjectDirectoryMap</code> encapsulates the information required to serialize a java bean
|
||||
* to and from an LDAP repository. An <code>ObjectDirectoryMapper</code> performs the
|
||||
* serialization using this information.
|
||||
*
|
||||
* @see ObjectDirectoryMapper
|
||||
*/
|
||||
public interface ObjectDirectoryMap
|
||||
{
|
||||
/** The attribute name corresponding to a bean property name. */
|
||||
String attributeNameFor(String beanPropertyName);
|
||||
|
||||
/** The set of attribute names in the Object Directory Map. */
|
||||
Set<String> attributeNames();
|
||||
|
||||
/** The bean property name corresponding to an attribute name. */
|
||||
String beanPropertyNameFor(String attributeName);
|
||||
|
||||
/** The set of bean property names in the Object Directory Map. */
|
||||
Set<String> beanPropertyNames();
|
||||
|
||||
/** The <code>Class</code> that the Object Directory Map corresponds to. */
|
||||
Class getClazz();
|
||||
|
||||
/** The name of the attribute corresponding to the first element in a distinguished
|
||||
* name. For example, in the distinguished name 'uid=admin, ou=people, dc=example, dc=com',
|
||||
* the naming attribute is 'uid'.
|
||||
*/
|
||||
String getNamingAttribute();
|
||||
|
||||
/**
|
||||
* The distinguished name representing the branch in the directory where an entity
|
||||
* is persisted.
|
||||
*/
|
||||
DistinguishedName getNamingSuffix();
|
||||
|
||||
/**
|
||||
* The ldap object classes that an entity declares.
|
||||
*/
|
||||
String[] getObjectClasses();
|
||||
}
|
||||
|
||||
@@ -11,15 +11,27 @@ import org.springframework.ldap.core.ContextMapper;
|
||||
|
||||
import javax.naming.Name;
|
||||
|
||||
/** An <code>ObjectDirectoryMapper</code> performs serialization between java beans and and
|
||||
* an LDAP repository using the information in an <code>ObjectDirectoryMap</code>.
|
||||
*
|
||||
* @see ObjectDirectoryMap
|
||||
*/
|
||||
public interface ObjectDirectoryMapper extends ContextMapper, ContextAssembler
|
||||
{
|
||||
/** Map the supplied object to the specified context. */
|
||||
Object mapFromContext(Object ctx);
|
||||
|
||||
/** Map a single LDAP Context to an object. */
|
||||
void mapToContext(Object beanInstance, Object ctx);
|
||||
|
||||
/** Builds a DistinguishedName from an object instance. */
|
||||
Name buildDn(Object beanInstance) throws MappingException;
|
||||
|
||||
/** Builds a DistinguishedName given the value of the naming attribute. */
|
||||
Name buildDn(String namingAttributeValue) throws MappingException;
|
||||
|
||||
/** Returns the <code>ObjectDirectoryMap</code> that the <code>ObjectDirectoryMapper</code>
|
||||
* corresponds to.
|
||||
*/
|
||||
ObjectDirectoryMap getObjectDirectoryMap();
|
||||
}
|
||||
|
||||
@@ -13,6 +13,15 @@ import org.springframework.ldap.odm.attributetypes.ReferencedEntryEditorFactory;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* <code>ObjectDirectoryMapperFactory</code> is a factory for assembling
|
||||
* <code>ObjectDirectoryMappers</code>. It builds a registry of ObjectDirectoryMappers, such
|
||||
* that the first request for a mapper of a given type results in the attempt to build one.
|
||||
* Subsequent requests result in the return of a cached instance.
|
||||
*
|
||||
* @see ObjectDirectoryMapper
|
||||
* @see org.springframework.ldap.odm.attributetypes.ReferencedEntryEditorFactory
|
||||
*/
|
||||
public class ObjectDirectoryMapperFactory
|
||||
{
|
||||
private static final Log LOGGER = LogFactory.getLog(ObjectDirectoryMapperFactory.class);
|
||||
@@ -29,6 +38,13 @@ public class ObjectDirectoryMapperFactory
|
||||
this.referencedEntryEditorFactory.setObjectDirectoryMapperFactory(this);
|
||||
}
|
||||
|
||||
/** Attempts to return an ObjectDirectoryMapper for the given class. Upon the first encounter
|
||||
* of the given class, mapping is attempted. If mapping is successful the mapper is returned.
|
||||
* Subsequent requests for the given class return a cached mapper.
|
||||
* @param clazz
|
||||
* @return ObjectDirectoryMapper
|
||||
* @throws MappingException when the mapping information for the given class contains errors.
|
||||
*/
|
||||
public ObjectDirectoryMapper objectDirectoryMapperForClass(Class clazz)
|
||||
throws MappingException
|
||||
{
|
||||
|
||||
@@ -12,7 +12,6 @@ import org.springframework.beans.TypeMismatchException;
|
||||
import org.springframework.ldap.core.DirContextAdapter;
|
||||
import org.springframework.ldap.core.DistinguishedName;
|
||||
import org.springframework.ldap.odm.attributetypes.LdapTypeConverter;
|
||||
import org.springframework.ldap.odm.attributetypes.ReferencedEntryEditorCreationException;
|
||||
import org.springframework.ldap.odm.attributetypes.ReferencedEntryEditorFactory;
|
||||
import org.springframework.ldap.odm.attributetypes.ValidConversionType;
|
||||
import org.springframework.ldap.odm.util.AttributeWrapper;
|
||||
@@ -23,6 +22,9 @@ import java.lang.reflect.Method;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* An implemtation of the <code>ObjectDirectoryMapper</code> interface.
|
||||
*/
|
||||
public class ObjectDirectoryMapperImpl implements ObjectDirectoryMapper
|
||||
{
|
||||
private static final Log LOGGER = LogFactory.getLog(ObjectDirectoryMapperImpl.class);
|
||||
@@ -89,8 +91,8 @@ public class ObjectDirectoryMapperImpl implements ObjectDirectoryMapper
|
||||
{
|
||||
try
|
||||
{
|
||||
String beanPropertyName = odm.beanPropertyNameFor(attributeName);
|
||||
Object beanPropertyValue = propertyGetters.get(beanPropertyName).invoke(beanInstance);
|
||||
Method propertyGetter = propertyGetters.get(odm.beanPropertyNameFor(attributeName));
|
||||
Object beanPropertyValue = propertyGetter.invoke(beanInstance);
|
||||
LOGGER.trace("mapToContext() attribute:" + attributeName + ", value: " + beanPropertyValue);
|
||||
|
||||
if (beanPropertyValue != null)
|
||||
@@ -153,7 +155,7 @@ public class ObjectDirectoryMapperImpl implements ObjectDirectoryMapper
|
||||
if (odm == null)
|
||||
{
|
||||
throw new IllegalArgumentException("Error creating mapper."
|
||||
+ ". AbstractObjectDirectoryMap argugment is null");
|
||||
+ ". ObjectDirectoryMap argugment is null");
|
||||
}
|
||||
|
||||
if (this.typeConverter == null)
|
||||
@@ -206,11 +208,12 @@ public class ObjectDirectoryMapperImpl implements ObjectDirectoryMapper
|
||||
{
|
||||
try
|
||||
{
|
||||
Class componentType = returnType.isArray() ? returnType.getComponentType() : returnType;
|
||||
Class componentType =
|
||||
returnType.isArray() ? returnType.getComponentType() : returnType;
|
||||
typeConverter.registerCustomEditor(componentType,
|
||||
refEditorFactory.referencedEntryEditorForClass(componentType));
|
||||
}
|
||||
catch (ReferencedEntryEditorCreationException e)
|
||||
catch (MappingException e)
|
||||
{
|
||||
throw new MappingException(odm.getClazz().getSimpleName() + "."
|
||||
+ getter.getName()
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
<html>
|
||||
<body>
|
||||
|
||||
Contains support classes used to assemble an <code>LdapDao</code> implementation.
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
<html>
|
||||
<body>
|
||||
|
||||
This document is the API specification for the Spring LDAP Object Directory Mapping Framework.
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -8,6 +8,7 @@ package org.springframework.ldap.odm.util;
|
||||
import javax.naming.NamingException;
|
||||
import javax.naming.directory.Attribute;
|
||||
|
||||
/** Adds the ability to <code>Attribute</code> to return all values as Object */
|
||||
public class AttributeWrapper
|
||||
{
|
||||
private Attribute attribute;
|
||||
@@ -17,6 +18,11 @@ public class AttributeWrapper
|
||||
this.attribute = attribute;
|
||||
}
|
||||
|
||||
/** Returns all of an Attribute's values as an object. If the attribute contains a
|
||||
* single value the return type is Object, otherwise the return type is Object[].
|
||||
* @return All of an Attribute's values.
|
||||
* @throws NamingException
|
||||
*/
|
||||
public Object getAllAsObject() throws NamingException
|
||||
{
|
||||
if (attribute.size() == 1)
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
<html>
|
||||
<body>
|
||||
|
||||
Contains utility classes.
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -27,7 +27,7 @@ public class ReferencedEntryEditorFactoryTest extends TestCase
|
||||
ldapTemplate = EasyMock.createStrictMock(LdapTemplate.class);
|
||||
odmFactory = EasyMock.createStrictMock(ObjectDirectoryMapperFactory.class);
|
||||
odm = EasyMock.createStrictMock(ObjectDirectoryMapper.class);
|
||||
editorFactory = new ReferencedEntryEditorFactory(ldapTemplate);
|
||||
editorFactory = new ReferencedEntryEditorFactory(null, ldapTemplate);
|
||||
editorFactory.setObjectDirectoryMapperFactory(odmFactory);
|
||||
}
|
||||
|
||||
@@ -36,7 +36,6 @@ public class ReferencedEntryEditorFactoryTest extends TestCase
|
||||
* the referenced entity.
|
||||
*
|
||||
* @throws MappingException
|
||||
* @throws ReferencedEntryEditorCreationException
|
||||
*
|
||||
*/
|
||||
public void testReferencedEditorForClass_successfulMapping()
|
||||
@@ -52,7 +51,7 @@ public class ReferencedEntryEditorFactoryTest extends TestCase
|
||||
//is only called once.
|
||||
editorFactory.referencedEntryEditorForClass(TestReferencedEntry.class);
|
||||
}
|
||||
catch (ReferencedEntryEditorCreationException e)
|
||||
catch (MappingException e)
|
||||
{
|
||||
fail();
|
||||
}
|
||||
@@ -65,13 +64,13 @@ public class ReferencedEntryEditorFactoryTest extends TestCase
|
||||
*
|
||||
* @throws org.springframework.ldap.odm.mapping.MappingException
|
||||
*
|
||||
* @throws ReferencedEntryEditorCreationException
|
||||
*
|
||||
*/
|
||||
public void testReferencedEditorForClass_unsuccessfulMapping()
|
||||
throws MappingException
|
||||
{
|
||||
ReferencedEntryEditorFactory editorFactory = new ReferencedEntryEditorFactory(ldapTemplate);
|
||||
ReferencedEntryEditorFactory editorFactory =
|
||||
new ReferencedEntryEditorFactory(null, ldapTemplate);
|
||||
editorFactory.setObjectDirectoryMapperFactory(odmFactory);
|
||||
|
||||
EasyMock.expect(odmFactory.objectDirectoryMapperForClass(TestReferencedEntry.class))
|
||||
@@ -84,7 +83,7 @@ public class ReferencedEntryEditorFactoryTest extends TestCase
|
||||
editorFactory.referencedEntryEditorForClass(TestReferencedEntry.class);
|
||||
fail("Should've thrown exception");
|
||||
}
|
||||
catch (ReferencedEntryEditorCreationException e)
|
||||
catch (MappingException e)
|
||||
{
|
||||
//expected behaviour
|
||||
}
|
||||
|
||||
@@ -27,7 +27,8 @@ public class ReferencedEntryEditorTest extends TestCase
|
||||
super.setUp();
|
||||
ldapTemplate = EasyMock.createStrictMock(LdapTemplate.class);
|
||||
objectDirectoryMapper = EasyMock.createStrictMock(ObjectDirectoryMapper.class);
|
||||
editor = new ReferencedEntryEditor(ldapTemplate, objectDirectoryMapper);
|
||||
editor = new ReferencedEntryEditor(new DistinguishedName("dc=example, dc=com"),
|
||||
ldapTemplate, objectDirectoryMapper);
|
||||
}
|
||||
|
||||
public void testGetAsText() throws MappingException
|
||||
@@ -68,15 +69,8 @@ public class ReferencedEntryEditorTest extends TestCase
|
||||
|
||||
public void testSetAsText()
|
||||
{
|
||||
LdapName referenceName = null;
|
||||
try
|
||||
{
|
||||
referenceName = new LdapName("uid = referencedEntry, ou=foobars");
|
||||
}
|
||||
catch (InvalidNameException e)
|
||||
{
|
||||
}
|
||||
|
||||
DistinguishedName referenceName =
|
||||
new DistinguishedName("uid = referencedEntry, ou=foobars");
|
||||
TestReferencedEntry referencedEntry = new TestReferencedEntry();
|
||||
|
||||
EasyMock.expect(ldapTemplate.lookup(referenceName, objectDirectoryMapper))
|
||||
@@ -88,6 +82,21 @@ public class ReferencedEntryEditorTest extends TestCase
|
||||
verifyMocks();
|
||||
}
|
||||
|
||||
public void testSetAsTextRemovingBaseDn()
|
||||
{
|
||||
DistinguishedName referenceName =
|
||||
new DistinguishedName("uid = referencedEntry, ou=foobars");
|
||||
TestReferencedEntry referencedEntry = new TestReferencedEntry();
|
||||
|
||||
|
||||
EasyMock.expect(ldapTemplate.lookup(referenceName, objectDirectoryMapper))
|
||||
.andReturn(referencedEntry);
|
||||
|
||||
replayMocks();
|
||||
editor.setAsText("uid = referencedEntry, ou=foobars, dc=example, dc=com");
|
||||
verifyMocks();
|
||||
}
|
||||
|
||||
private void verifyMocks()
|
||||
{
|
||||
EasyMock.verify(ldapTemplate);
|
||||
|
||||
@@ -25,6 +25,13 @@ public class UnitTestRole
|
||||
@DirAttribute("roleOccupant")
|
||||
private UnitTestPerson[] members;
|
||||
|
||||
public UnitTestRole(String roleName, String description, UnitTestPerson[] members)
|
||||
{
|
||||
this.roleName = roleName;
|
||||
this.description = description;
|
||||
this.members = members;
|
||||
}
|
||||
|
||||
public String getRoleName()
|
||||
{
|
||||
return roleName;
|
||||
|
||||
@@ -25,14 +25,14 @@ public class ObjectDirectoryMapperImplTest extends TestCase
|
||||
private static final Log LOGGER = LogFactory.getLog(ObjectDirectoryMapperImplTest.class);
|
||||
private LdapTypeConverter typeConverter;
|
||||
private ReferencedEntryEditorFactory refEditorFactory;
|
||||
private AnnotationObjectDirectoryMap objectDirectoryMap;
|
||||
private AnnotationObjectDirectoryMap personOdm;
|
||||
|
||||
protected void setUp() throws Exception
|
||||
{
|
||||
super.setUp();
|
||||
this.typeConverter = new LdapTypeConverter();
|
||||
this.refEditorFactory = EasyMock.createMock(ReferencedEntryEditorFactory.class);
|
||||
this.objectDirectoryMap = new AnnotationObjectDirectoryMap(UnitTestPerson.class);
|
||||
this.personOdm = new AnnotationObjectDirectoryMap(UnitTestPerson.class);
|
||||
}
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ public class ObjectDirectoryMapperImplTest extends TestCase
|
||||
try
|
||||
{
|
||||
ObjectDirectoryMapperImpl mapper =
|
||||
new ObjectDirectoryMapperImpl(objectDirectoryMap, null, refEditorFactory);
|
||||
new ObjectDirectoryMapperImpl(personOdm, null, refEditorFactory);
|
||||
fail("Should've thrown exception.");
|
||||
}
|
||||
catch (IllegalArgumentException e)
|
||||
@@ -61,7 +61,7 @@ public class ObjectDirectoryMapperImplTest extends TestCase
|
||||
try
|
||||
{
|
||||
ObjectDirectoryMapperImpl mapper =
|
||||
new ObjectDirectoryMapperImpl(objectDirectoryMap, typeConverter, null);
|
||||
new ObjectDirectoryMapperImpl(personOdm, typeConverter, null);
|
||||
fail("Should've thrown exception.");
|
||||
}
|
||||
catch (IllegalArgumentException e)
|
||||
@@ -75,7 +75,7 @@ public class ObjectDirectoryMapperImplTest extends TestCase
|
||||
try
|
||||
{
|
||||
ObjectDirectoryMapperImpl mapper =
|
||||
new ObjectDirectoryMapperImpl(objectDirectoryMap, typeConverter, refEditorFactory);
|
||||
new ObjectDirectoryMapperImpl(personOdm, typeConverter, refEditorFactory);
|
||||
UnitTestPerson person = new UnitTestPerson();
|
||||
person.setIdentifier("x332");
|
||||
person.setFullName("Mr Bean");
|
||||
@@ -98,7 +98,7 @@ public class ObjectDirectoryMapperImplTest extends TestCase
|
||||
try
|
||||
{
|
||||
ObjectDirectoryMapperImpl mapper =
|
||||
new ObjectDirectoryMapperImpl(objectDirectoryMap, typeConverter, refEditorFactory);
|
||||
new ObjectDirectoryMapperImpl(personOdm, typeConverter, refEditorFactory);
|
||||
UnitTestPerson person = null;
|
||||
mapper.buildDn(person);
|
||||
fail("Should've thrown mapping exception - argument is null");
|
||||
@@ -110,7 +110,7 @@ public class ObjectDirectoryMapperImplTest extends TestCase
|
||||
try
|
||||
{
|
||||
ObjectDirectoryMapperImpl mapper =
|
||||
new ObjectDirectoryMapperImpl(objectDirectoryMap, typeConverter, refEditorFactory);
|
||||
new ObjectDirectoryMapperImpl(personOdm, typeConverter, refEditorFactory);
|
||||
String namingAttributeValue = null;
|
||||
mapper.buildDn(namingAttributeValue);
|
||||
fail("Should've thrown mapping exception - argument is null");
|
||||
@@ -121,28 +121,29 @@ public class ObjectDirectoryMapperImplTest extends TestCase
|
||||
}
|
||||
}
|
||||
|
||||
public void testMapToContext()
|
||||
public void testMapToContext()
|
||||
{
|
||||
try
|
||||
{
|
||||
ObjectDirectoryMapperImpl mapper =
|
||||
new ObjectDirectoryMapperImpl(objectDirectoryMap, typeConverter, refEditorFactory);
|
||||
new ObjectDirectoryMapperImpl(personOdm, typeConverter, refEditorFactory);
|
||||
|
||||
UnitTestPerson entity = new UnitTestPerson();
|
||||
entity.setIdentifier("x232");
|
||||
entity.setFullName("Mr Bean");
|
||||
entity.setEmailAddress("bean@bean.com");
|
||||
entity.setPassword("fred".getBytes());
|
||||
entity.setAcceptEmails(false);
|
||||
entity.setResetLogin(new Date(1L));
|
||||
entity.setCreator(new DistinguishedName(
|
||||
UnitTestPerson person = new UnitTestPerson();
|
||||
person.setIdentifier("x232");
|
||||
person.setFullName("Mr Bean");
|
||||
person.setEmailAddress("bean@bean.com");
|
||||
person.setPassword("fred".getBytes());
|
||||
person.setAcceptEmails(false);
|
||||
person.setResetLogin(new Date(1L));
|
||||
person.setCreator(new DistinguishedName(
|
||||
"uid=amAdmin,ou=people,dc=myretsu,dc=com"));
|
||||
entity.setFailedLogins(3);
|
||||
person.setFailedLogins(3);
|
||||
person.setDescription(new String[]{"the quick", "brown fox"});
|
||||
|
||||
replayMocks();
|
||||
EasyMock.replay(refEditorFactory);
|
||||
|
||||
DirContextAdapter ctxAdapter = new DirContextAdapter();
|
||||
mapper.mapToContext(entity, ctxAdapter);
|
||||
mapper.mapToContext(person, ctxAdapter);
|
||||
|
||||
Assert.assertEquals("x232", ctxAdapter.getStringAttribute("uid"));
|
||||
Assert.assertEquals("Mr Bean", ctxAdapter.getStringAttribute("cn"));
|
||||
@@ -153,8 +154,10 @@ public class ObjectDirectoryMapperImplTest extends TestCase
|
||||
Assert.assertEquals("3", ctxAdapter.getStringAttribute("failedlogins"));
|
||||
Assert.assertEquals("uid=amAdmin, ou=people, dc=myretsu, dc=com",
|
||||
ctxAdapter.getStringAttribute("creatorname"));
|
||||
Assert.assertEquals("the quick", ctxAdapter.getStringAttributes("description")[0]);
|
||||
|
||||
EasyMock.verify(refEditorFactory);
|
||||
|
||||
verifyMocks();
|
||||
}
|
||||
catch (MappingException e)
|
||||
{
|
||||
@@ -166,20 +169,20 @@ public class ObjectDirectoryMapperImplTest extends TestCase
|
||||
public void testMapFromContext() throws MappingException
|
||||
{
|
||||
ObjectDirectoryMapperImpl mapper =
|
||||
new ObjectDirectoryMapperImpl(objectDirectoryMap, typeConverter, refEditorFactory);
|
||||
new ObjectDirectoryMapperImpl(personOdm, typeConverter, refEditorFactory);
|
||||
DirContextAdapter ctxAdapter = new DirContextAdapter();
|
||||
ctxAdapter.setAttributeValue("acceptemails", "false");
|
||||
ctxAdapter.setAttributeValue("creatorname", "uid=admin, ou=people");
|
||||
ctxAdapter.setAttributeValue("mail", "person@person.com");
|
||||
|
||||
replayMocks();
|
||||
EasyMock.replay(refEditorFactory);
|
||||
|
||||
UnitTestPerson person = (UnitTestPerson) mapper.mapFromContext(ctxAdapter);
|
||||
Assert.assertEquals(person.getAcceptEmails(), Boolean.FALSE);
|
||||
Assert.assertEquals(person.getCreator(), new DistinguishedName("uid=admin, ou=people"));
|
||||
Assert.assertEquals(person.getEmailAddress(), "person@person.com");
|
||||
|
||||
verifyMocks();
|
||||
EasyMock.verify(refEditorFactory);
|
||||
|
||||
|
||||
}
|
||||
@@ -187,19 +190,9 @@ public class ObjectDirectoryMapperImplTest extends TestCase
|
||||
public void testGetObjectDirectoryMap() throws MappingException
|
||||
{
|
||||
ObjectDirectoryMapperImpl mapper =
|
||||
new ObjectDirectoryMapperImpl(objectDirectoryMap, typeConverter, refEditorFactory);
|
||||
new ObjectDirectoryMapperImpl(personOdm, typeConverter, refEditorFactory);
|
||||
Assert.assertNotNull(mapper.getObjectDirectoryMap());
|
||||
}
|
||||
|
||||
private void verifyMocks()
|
||||
{
|
||||
EasyMock.verify(refEditorFactory);
|
||||
}
|
||||
|
||||
private void replayMocks()
|
||||
{
|
||||
EasyMock.replay(refEditorFactory);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user