A Complete PersonDao Class

To illustrate the power of Spring LDAP, here is a complete Person DAO implementation for LDAP in just 68 lines:

Example 3.7. A complete PersonDao class

package com.example.dao;

import java.util.List;

import javax.naming.Name;
import javax.naming.NamingException;
import javax.naming.directory.Attributes;

import org.springframework.ldap.core.AttributesMapper;
import org.springframework.ldap.core.ContextMapper;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.ldap.core.DirContextAdapter;
import org.springframework.ldap.core.support.DistinguishedName;
import org.springframework.ldap.filter.AndFilter;
import org.springframework.ldap.filter.EqualsFilter;
import org.springframework.ldap.filter.WhitespaceWildcardsFilter;

public class PersonDaoImpl implements PersonDao {
   private LdapTemplate ldapTemplate;

   public void setLdapTemplate(LdapTemplate ldapTemplate) {
      this.ldapTemplate = ldapTemplate;
   }

   public void create(Person person) {
      DirContextAdapter context = new DirContextAdapter(buildDn(person));
      mapToContext(person, context);
      ldapTemplate.bind(context);
   }

   public void update(Person person) {
      Name dn = buildDn(person);
      DirContextOperations context = ldapTemplate.lookupContext(dn);
      mapToContext(person, context);
      ldapTemplate.modifyAttributes(context);
   }

   public void delete(Person person) {
      ldapTemplate.unbind(buildDn(person));
   }

   public Person findByPrimaryKey(String name, String company, String country) {
      Name dn = buildDn(name, company, country);
      return (Person) ldapTemplate.lookup(dn, getContextMapper());
   }

   public List findByName(String name) {
      AndFilter filter = new AndFilter();
      filter.and(new EqualsFilter("objectclass", "person")).and(new WhitespaceWildcardsFilter("cn",name));
      return ldapTemplate.search(DistinguishedName.EMPTY_PATH, filter.encode(), getContextMapper());
   }

   public List findAll() {
      EqualsFilter filter = new EqualsFilter("objectclass", "person");
      return ldapTemplate.search(DistinguishedName.EMPTY_PATH, filter.encode(), getContextMapper());
   }

   protected ContextMapper getContextMapper() {
      return new PersonContextMapper();
   }

   protected Name buildDn(Person person) {
      return buildDn(person.getFullname(), person.getCompany(), person.getCountry());
   }

   protected Name buildDn(String fullname, String company, String country) {
      DistinguishedName dn = new DistinguishedName();
      dn.add("c", country);
      dn.add("ou", company);
      dn.add("cn", fullname);
      return dn;
   }

   protected void mapToContext(Person person, DirContextOperations context) {
      context.setAttributeValues("objectclass", new String[] {"top", "person"});
      context.setAttributeValue("cn", person.getFullName());
      context.setAttributeValue("sn", person.getLastName());
      context.setAttributeValue("description", person.getDescription());
   }

   private static class PersonContextMapper extends AbstractContextMapper {
      public Object doMapFromContext(DirContextOperations context) {
         Person person = new Person();
         person.setFullName(context.getStringAttribute("cn"));
         person.setLastName(context.getStringAttribute("sn"));
         person.setDescription(context.getStringAttribute("description"));
         return person;
      }
   }
}

Note

In several cases the Distinguished Name (DN) of an object is constructed using properties of the object. E.g. in the above example, the country, company and full name of the Person are used in the DN, which means that updating any of these properties will actually require moving the entry in the LDAP tree using the rename() operation in addition to updating the Attribute values. Since this is highly implementation specific this is something you'll need to keep track of yourself - either by disallowing the user to change these properties or performing the rename() operation in your update() method if needed.