Relational mapping frameworks like Hibernate and JPA have offered
developers the ability to use annotations to map database tables to Java
objects for some time. The Spring Framework LDAP project now offers the
same ability with respect to directories through the use of the
org.springframework.ldap.odm
package (sometimes abbreviated
as o.s.l.odm
).
The org.springframework.ldap.odm.OdmManager
interface,
and its implementation, is the central class in the ODM package. The
OdmManager
orchestrates the process of reading objects from
the directory and mapping the data to annotated Java object classes. This
interface provides access to the underlying directory instance through the
following methods:
<T> T read(Class<T> clazz, Name
dn)
void create(Object entry)
void update(Object entry)
void delete(Object entry)
<T> List<T> findAll(Class<T> clazz, Name
base, SearchControls searchControls)
<T> List<T> search(Class<T> clazz, Name
base, String filter, SearchControls searchControls)
A reference to an implementation of this interface can be obtained
through the
org.springframework.ldap.odm.core.impl.OdmManagerImplFactoryBean
.
A basic configuration of this factory would be as follows:
Example 12.1. Configuring the OdmManager Factory
<beans> ... <bean id="odmManager" class="org.springframework.ldap.odm.core.impl.OdmManagerImplFactoryBean"> <property name="converterManager" ref="converterManager" /> <property name="contextSource" ref="contextSource" /> <property name="managedClasses"> <set> <value>com.example.dao.SimplePerson</value> </set> </property> </bean> ... </beans>
The factory requires the list of entity classes to be managed by the
OdmManager
to be explicitly declared. These classes should be
properly annotated as defined in the next section. The
converterManager
referenced in the above definition is
described in Section 12.4, “Type Conversion”.
Entity classes managed by the OdmManager
are required
to be annotated with the annotations in the
org.springframework.ldap.odm.annotations
package. The
available annotations are:
@Entry
- Class level annotation indicating the
objectClass
definitions to which the entity
maps. (required)
@Id
- Indicates the entity DN; the field declaring
this attribute must be a derivative of the
javax.naming.Name
class.
(required)
@Attribute
- Indicates the mapping of a directory
attribute to the object class field.
@Transient
- Indicates the field is not persistent
and should be ignored by the OdmManager
.
The @Entry
and @Id
attributes are
required to be declared on managed classes. @Entry
is used to
specify which object classes the entity maps too. All object classes for
which fields are mapped are required to be declared. Also, in order for a
directory entry to be considered a match to the managed entity, all object
classes declared by the directory entry must match be declared by in the
@Entry
annotation.
The @Id
annotation is used to map the distinguished
name of the entry to a field. The field must be an instance of
javax.naming.Name
or a subclass of it.
The @Attribute
annotation is used to map object
class fields to entity fields. @Attribute
is required to
declare the name of the object class property to which the field maps and
may optionally declare the syntax OID of the LDAP attribute, to guarantee
exact matching. @Attribute
also provides the type declaration
which allows you to indicate whether the attribute is regarded as binary
based or string based by the LDAP JNDI provider.
The @Transient
annotation is used to indicate the
field should be ignored by the OdmManager
and not mapped to
an underlying LDAP property.
The OdmManager
relies on the
org.springframework.ldap.odm.typeconversion
package to
convert LDAP attributes to Java fields. The main interface in this class
is the
org.springframework.ldap.odm.typeconversion.ConverterManager
.
The default ConverterManager
implementation uses the
following algorithm when parsing objects to convert fields:
Try to find and use a Converter
registered for
the fromClass
, syntax
and
toClass
and use it.
If this fails, then if the toClass
isAssignableFrom
the
fromClass
then just assign it.
If this fails try to find and use a
Converter
registered for the
fromClass
and the toClass
ignoring the
syntax.
If this fails then throw a
ConverterException
.
Implementations of the ConverterManager
interface can
be obtained from the
o.s.l.odm.typeconversion.impl.ConvertManagerFactoryBean
.
The factory bean requires converter configurations to be declared in the
bean configuration.
The converterConfig property accepts a set of
ConverterConfig
classes, each one defining some conversion
logic. A converter config is an instance of
o.s.l.odm.typeconversion.impl.ConverterManagerFactoryBean.ConverterConfig
.
The config defines a set of source classes, the set of target classes, and
an implementation of the
org.springframework.ldap.odm.typeconversion.impl.Converter
interface which provides the logic to convert from the
fromClass
to the toClass
. A sample configuration
is provided in the following example:
Example 12.2. Configuring the Converter Manager Factory
<bean id="fromStringConverter" class="org.springframework.ldap.odm.typeconversion.impl.converters.FromStringConverter" /> <bean id="toStringConverter" class="org.springframework.ldap.odm.typeconversion.impl.converters.ToStringConverter" /> <bean id="converterManager" class="org.springframework.ldap.odm.typeconversion.impl.ConverterManagerFactoryBean"> <property name="converterConfig"> <set> <bean class="org.springframework.ldap.odm.\ typeconversion.impl.ConverterManagerFactoryBean$ConverterConfig"> <property name="fromClasses"> <set> <value>java.lang.String</value> </set> </property> <property name="toClasses"> <set> <value>java.lang.Byte</value> <value>java.lang.Short</value> <value>java.lang.Integer</value> <value>java.lang.Long</value> <value>java.lang.Float</value> <value>java.lang.Double</value> <value>java.lang.Boolean</value> </set> </property> <property name="converter" ref="fromStringConverter" /> </bean> <bean class="org.springframework.ldap.odm.\ typeconversion.impl.ConverterManagerFactoryBean$ConverterConfig"> <property name="fromClasses"> <set> <value>java.lang.Byte</value> <value>java.lang.Short</value> <value>java.lang.Integer</value> <value>java.lang.Long</value> <value>java.lang.Float</value> <value>java.lang.Double</value> <value>java.lang.Boolean</value> </set> </property> <property name="toClasses"> <set> <value>java.lang.String</value> </set> </property> <property name="converter" ref="toStringConverter" /> </bean> </set> </property> </bean>
After all components are configured, directory interaction can be
achieved through a reference to the OdmManager
, as shown in
this example:
Example 12.3. Execution
public class App { private static Log log = LogFactory.getLog(App.class); private static final SearchControls searchControls = new SearchControls(SearchControls.SUBTREE_SCOPE, 100, 10000, null, true, false); public static void main( String[] args ) { try { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); OdmManager manager = (OdmManager) context.getBean("odmManager"); List<SimplePerson> people = manager.search(SimplePerson.class, new DistinguishedName("dc=example,dc=com"), "uid=*", searchControls); log.info("People found: " + people.size()); for (SimplePerson person : people) { log.info( person ); } } catch (Exception e) { e.printStackTrace(); } } }