Table of Contents
Spring LDAP (http://www.springframework.org/ldap)
is a library for simpler LDAP programming in Java, built on the same
principles as the JdbcTemplate
in Spring JDBC. It completely eliminates the need to worry about creating
and closing LdapContext
and looping through
NamingEnumeration
. It also provides a more
comprehensive unchecked Exception hierarchy, built on Spring's
DataAccessException
. As a bonus, it also contains
classes for dynamically building LDAP filters and DNs (Distinguished
Names), LDAP attribute management, and client-side LDAP transaction management.
Consider, for example, a method that should search some storage for all persons and return their names in a list. Using JDBC, we would create a connection and execute a query using a statement. We would then loop over the result set and retrieve the column we want, adding it to a list. In contrast, using Java LDAP, we would create a context and perform a search using a search filter. We would then loop over the resulting naming enumeration and retrieve the attribute we want, adding it to a list.
The traditional way of implementing this person name search method in Java LDAP looks like this, where the code marked as bold actually performs tasks related to the business purpose of the method:
package com.example.dao; public class TraditionalPersonDaoImpl implements PersonDao { public List getAllPersonNames() { Hashtable env = new Hashtable(); env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); env.put(Context.PROVIDER_URL, "ldap://localhost:389/dc=example,dc=com"); DirContext ctx; try { ctx = new InitialDirContext(env); } catch (NamingException e) { throw new RuntimeException(e); } LinkedList list = new LinkedList(); NamingEnumeration results = null; try { SearchControls controls = new SearchControls(); controls.setSearchScope(SearchControls.SUBTREE_SCOPE); results = ctx.search("", "(objectclass=person)", controls); while (results.hasMore()) { SearchResult searchResult = (SearchResult) results.next(); Attributes attributes = searchResult.getAttributes(); Attribute attr = attributes.get("cn"); String cn = (String) attr.get(); list.add(cn); } } catch (NameNotFoundException e) { // The base context was not found. // Just clean up and exit. } catch (NamingException e) { throw new RuntimeException(e); } finally { if (results != null) { try { results.close(); } catch (Exception e) { // Never mind this. } } if (ctx != null) { try { ctx.close(); } catch (Exception e) { // Never mind this. } } } return list; } }
By using the Spring LDAP classes AttributesMapper
and LdapTemplate
, we get the exact same functionality
with the following code:
package com.example.dao; public class PersonDaoImpl implements PersonDao { private LdapTemplate ldapTemplate; public void setLdapTemplate(LdapTemplate ldapTemplate) { this.ldapTemplate = ldapTemplate; } public List getAllPersonNames() { return ldapTemplate.search( "", "(objectclass=person)", new AttributesMapper() { public Object mapFromAttributes(Attributes attrs) throws NamingException { return attrs.get("cn").get(); } }); } }
The amount of boiler-plate code is significantly less than in the
traditional example. The LdapTemplate
version of the
search method performs the search, maps the attributes to a string using
the given AttributesMapper
, collects the strings in an
internal list, and finally returns the list.
Note that the PersonDaoImpl
code simply assumes
that it has an LdapTemplate
instance, rather than
looking one up somewhere. It provides a set method for this purpose. There
is nothing Spring-specific about this "Inversion of Control". Anyone that
can create an instance of PersonDaoImpl
can also set
the LdapTemplate
on it. However, Spring provides a very
flexible and easy way of achieving
this. The Spring container can be told to wire up an instance of
LdapTemplate
with its required dependencies and inject
it into the PersonDao
instance. This wiring can be
defined in various ways, but the most common is through XML:
<beans> <bean id="contextSource" class="org.springframework.ldap.core.support.LdapContextSource"> <property name="url" value="ldap://localhost:389" /> <property name="base" value="dc=example,dc=com" /> <property name="userDn" value="cn=Manager" /> <property name="password" value="secret" /> </bean> <bean id="ldapTemplate" class="org.springframework.ldap.core.LdapTemplate"> <constructor-arg ref="contextSource" /> </bean> <bean id="personDao" class="com.example.dao.PersonDaoImpl"> <property name="ldapTemplate" ref="ldapTemplate" /> </bean> </beans>