1. Introduction

1.1. Overview

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>

1.2. Packaging overview

At a minimum, to use Spring LDAP you need:

  • spring-ldap-core (the Spring LDAP library)

  • spring-core (miscellaneous utility classes used internally by the framework)

  • spring-beans (contains interfaces and classes for manipulating Java beans)

  • commons-logging (a simple logging facade, used internally)

  • commons-lang (misc utilities, used internally)

In addition to the required dependencies the following optional dependencies are required for certain functionality:

  • spring-context (If your application is wired up using the Spring Application Context - adds the ability for application objects to obtain resources using a consistent API. Definitely needed if you are planning on using the BaseLdapPathBeanPostProcessor.)

  • spring-tx (If you are planning to use the client side compensating transaction support)

  • spring-jdbc (If you are planning to use the client side compensating transaction support)

  • ldapbp (Sun LDAP Booster Pack - if you will use the LDAP v3 Server controls integration and you're not using Java5 or higher)

  • commons-pool (If you are planning to use the pooling functionality)

  • spring-batch (If you are planning to use the LDIF parsing functionality together with Spring Batch)

1.3. Package structure

This section provides an overview of the logical package structure of the Spring LDAP codebase. The dependencies for each package are clearly noted.

Figure 1.1. Spring LDAP package structure

Spring LDAP package structure

1.3.1. org.springframework.transaction.compensating

The transaction.compensating package contains the generic compensating transaction support. This is not LDAP-specific or JNDI-specific in any way.

  • Dependencies: commons-logging

1.3.2. org.springframework.ldap

The ldap package contains the exceptions of the library. These exceptions form an unchecked hierarchy that mirrors the NamingException hierarchy.

  • Dependencies: spring-core

1.3.3. org.springframework.ldap.core

The ldap.core package contains the central abstractions of the library. These abstractions include AuthenticationSource, ContextSource, DirContextProcessor, and NameClassPairCallbackHandler. This package also contains the central class LdapTemplate, plus various mappers and executors.

  • Dependencies: ldap, ldap.support, spring-beans, spring-core, spring-tx, commons-lang, commons-logging

1.3.4. org.springframework.ldap.core.support

The ldap.core.support package contains supporting implementations of some of the core interfaces.

  • Dependencies: ldap, ldap.core, ldap.support, spring-core, spring-beans, spring-context, commons-lang, commons-logging

1.3.5. org.springframework.ldap.core.simple

The ldap.core.simple package contains Java5-specific parts of Spring LDAP. It's mainly a simplification layer that takes advantage of the generics support in Java5, in order to get typesafe context mappers as well as typesafe search and lookup methods.

  • Dependencies: ldap.core

1.3.6. org.springframework.ldap.pool

The ldap.pool package contains support for detailed pool configuration on a per-ContextSource basis. Pooling support is provided by PoolingContextSource which can wrap any ContextSource and pool both read-only and read-write DirContext objects. Jakarta Commons-Pool is used to provide the underlying pool implementation.

  • Dependencies: ldap.core, commons-lang, commons-pool

1.3.7. org.springframework.ldap.pool.factory

The ldap.pool.factory package contains the actual pooling context source and other classes for context creation.

  • Dependencies: ldap, ldap.core, ldap.pool, ldap.pool.validation, spring-beans, spring-tx, commons-lang, commons-logging, commons-pool

1.3.8. org.springframework.ldap.pool.validation

The ldap.pool.validation package contains the connection validation support.

  • Dependencies: ldap.pool, commons-lang, commons-logging

1.3.9. org.springframework.ldap.support

The ldap.support package contains supporting utilities, like the exception translation mechanism.

  • Dependencies: ldap, spring-core, commons-lang, commons-logging

1.3.10. org.springframework.ldap.authentication

The ldap.authentication package contains an implementation of the AuthenticationSource interface that can be used if the user should be allowed to read some information even though not logged in.

  • Dependencies: ldap.core, spring-beans, commons-lang

1.3.11. org.springframework.ldap.control

The ldap.control package contains an abstract implementation of the DirContextProcessor interface that can be used as a basis for processing RequestControls and ResponseControls. There is also a concrete implementation that handles paged search results and one that handles sorting. The LDAP Booster Pack is used to get support for controls, unless Java5 is used.

  • Dependencies: ldap, ldap.core, LDAP booster pack (optional), spring-core, commons-lang, commons-logging

1.3.12. org.springframework.ldap.filter

The ldap.filter package contains the Filter abstraction and several implementations of it.

  • Dependencies: ldap.core, spring-core, commons-lang

1.3.13. org.springframework.ldap.transaction.compensating

The ldap.transaction.compensating package contains the core LDAP-specific implementation of compensating transactions.

  • Dependencies: ldap.core, ldap.core.support, transaction.compensating, spring-core, commons-lang, commons-logging

1.3.14. org.springframework.ldap.transaction.compensating.manager

The ldap.transaction.compensating.manager package contains the core implementation classes for client-side compensating transactions.

  • Dependencies: ldap, ldap.core, ldap.support, ldap.transaction.compensating, ldap.transaction.compensating.support, transaction.compensating, spring-tx, spring-jdbc, spring-orm, commons-logging

1.3.15. org.springframework.ldap.transaction.compensating.support

The ldap.transaction.compensating.support package contains useful helper classes for client-side compensating transactions.

  • Dependencies: ldap.core, ldap.transaction.compensating

1.3.16. org.springframework.ldap.ldif

The ldap.ldif package provides support for parsing LDIF files.

  • Dependencies: ldap.core

1.3.17. org.springframework.ldap.ldif.batch

The ldap.ldif.batch package provides the classes necessary to use the LDIF parser in the Spring Batch framework.

  • Dependencies: ldap.core, ldap.ldif.parser, spring-batch, spring-core, spring-beans, commons-logging

1.3.18. org.springframework.ldap.ldif.parser

The ldap.ldif.parser package provides the parser classes and interfaces.

  • Dependencies: ldap.core, ldap.schema, ldap.ldif, ldap.ldif.support, spring-core, spring-beans, commons-lang, commons-logging

1.3.19. org.springframework.ldap.ldif.support

The ldap.ldif.support package provides the necessary auxiliary classes utilized by the LDIF Parser.

  • Dependencies: ldap.core, ldap.ldif, commons-lang, commons-logging

1.3.20. org.springframework.ldap.odm

The ldap.odm package provides the classes and interfaces enabling annotation based object-directory mapping.

  • Dependencies: ldap, ldap.core, ldap.core.simple, ldap.filter, spring-beans, commons-cli, commons-logging, freemarker

For the exact list of jar dependencies, see the Spring LDAP Maven2 Project Object Model (POM) files in the source tree.

1.4. Support

Spring LDAP 1.3 is supported on Spring 2.0 and later.

The community support forum is located at http://forum.springframework.org, and the project web page is http://www.springframework.org/ldap.