Simplify directory access with Spring LDAP
Try a Spring-based approach to LDAP programming with JNDI
By Sunil D. Patil, JavaWorld.com, 06/26/07
Spring
LDAP is a Spring-based framework that simplifies LDAP programming on
the Java platform. In this step-by-step guide to using Spring LDAP you
will learn how the framework handles the low-level coding required by
most LDAP clients, so that you can focus on developing your
application's business logic. You will also practice simple CRUD
operations using Spring LDAP and learn about more advanced operations
such as creating dynamic filters and converting LDAP entries into Java
beans.
The Lightweight
Directory Access Protocol is an essential component of most large-scale
enterprise application deployments today. LDAP is primarily used to
store information related to user identity, such as a user's username,
password, and e-mail address. It is also used in security
implementations where it is necessary to store user access rights for
authentication and authorization purposes.
Java Naming and
Directory Interface (JDNI) is the API used for LDAP programming on the
Java platform. It defines a standard interface that can be used within
your application to interact with any LDAP server. Unfortunately, using
JNDI typically entails writing a lot of low-level, repetitive code.
JNDI makes far too much work of simple procedures, such as ensuring
that resources have been properly opened and closed. In addition, most
JNDI methods throw checked exceptions, which are time-consuming to
handle. Upon close inspection, it seems that 50 to 60 percent of the
time spent programming JNDI is wasted on handling repetitive tasks.
Spring LDAP is an
open source Java library designed to simplify LDAP programming on the
Java platform. Just as the Spring Framework takes much of the low-level
programming out of Java enterprise application development, Spring LDAP
frees you from the infrastructural details of using LDAP. Rather than
worrying about NamingException
s and getting InitialContext
s,
you are free to concentrate on your application's business logic.
Spring LDAP also defines a comprehensive unchecked exception hierarchy
and provides helper classes for building LDAP filters and distinguished
names.
Spring LDAP and JNDI |
Note that the Spring LDAP framework does not replace JNDI. Rather, it provides wrapper and utility classes over JNDI to simplify
LDAP programming on the Java platform.
|
In
this article, a beginner's guide to using Spring LDAP, I will start by
developing a simple JNDI program for executing an LDAP search. I'll
then demonstrate how much easier it is to do the same thing using the
Spring LDAP framework. I'll show you how to use Spring LDAP's AttributeMapper
s
to map LDAP attributes to Java beans, and how to use its dynamic
filters to build queries. Finally, I'll provide a step-by-step
introduction to using the Spring LDAP framework to add, delete and
modify data in your LDAP server.
Note that this article assumes you are familiar with the concepts and terminology of the Spring Framework. See the Resources
section to learn more about the Spring Framework, LDAP and JNDI as well as to download the sample application.
A simple JNDI client
Listing 1 shows a simple JNDI program that will print out the cn attributes of all the Person
type objects on your console.
Listing 1. SimpleLDAPClient.java
public class SimpleLDAPClient {
public static void main(String[] args) {
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, "ldap://localhost:10389/ou=system");
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.SECURITY_PRINCIPAL, "uid=admin,ou=system");
env.put(Context.SECURITY_CREDENTIALS, "secret");
DirContext ctx = null;
NamingEnumeration results = null;
try {
ctx = new InitialDirContext(env);
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();
System.out.println(" Person Common Name = " + cn);
}
} catch (NamingException e) {
throw new RuntimeException(e);
} finally {
if (results != null) {
try {
results.close();
} catch (Exception e) {
}
}
if (ctx != null) {
try {
ctx.close();
} catch (Exception e) {
}
}
}
}
}
The first thing I've done in Listing 1 is to create an InitialDirContext
object, which is then used as the context for the following directory operations. When creating a new Context
object I configure properties such as the username, password and authentication mechanism that can be used to connect to
the LDAP server. I've managed this by creating a Hashtable
object, setting up all these properties as key/value pairs in the Hashtable
and passing the Hashtable
to the InitialDirContext
constructor.
The
immediate problem with this approach is that I've hard-coded all the
configuration parameters into a .java file. This works fine for my
example, but not for a real-world application. In a real-world
application I would want to store the connection properties in a
jndi.properties file and place that file in either my project's
classpath or its <JAVA_HOME>/lib folder. Upon creation of a new InitialDirContext
object, the JNDI API would look in both of those places for the jndi.properties file, then use it to create a connection
to the LDAP server.
JNDI configuration parameters
Listing 2 shows the JNDI configuration parameters for connecting to my LDAP server. I explain the meaning of the parameters
below.
Listing 2. JNDI configuration parameters for LDAP
java.naming.factory.initial=com.sun.jndi.ldap.LdapCtxFactory
java.naming.provider.url=ldap://localhost:10389/ou=system
java.naming.security.authentication=simple
java.naming.security.principal=uid=admin,ou=system
java.naming.security.credentials=secret
- Context.INITIAL_CONTEXT_FACTORY (
java.naming.factory.initial
) should be equal to the fully qualified class name that will be used to create a new initial context. If no value is specified
then the NoInitialContextException
is thrown.
- Context.PROVIDER_URL (
java.naming.provider.url
) should be equal to the URL of the LDAP server that you want to connect to. It should be in the format ldap://<hostname>:<port>
.
- Context.SECURITY_AUTHENTICATION (
java.naming.security.authentication
) represents the type of authentication mechanism you want to use. I've used a username and password for authentication in
my example, so the value of this property is simple.
- Context.SECURITY_PRINCIPAL (
java.naming.security.principal
) represents the distinguished username (DN) that should be used to establish a connection.
- Context.SECURITY_CREDENTIALS (
java.naming.security.credentials
) represents the user's password.
The JNDI client code
After getting the Context
object my next step is to create a SearchControl
object, which encapsulates the factors that determine the scope of my search and what will be returned. I want to search
the entire subtree rooted at the context, so I set the search scope to SUBTREE_SCOPE
by calling the setSearchScope()
method of SearchControl
, as previously shown in Listing 1.
Next, I call the search()
method of DirContext
, passing in (objectclass=person)
as the value of the filter. The search()
method will return a NamingEnumeration
object containing all the entries in the subtree of Context
, where objectclass
is equal to person
. After getting a NamingEnumeration
as my result object, I iterate through it and print a cn attribute for each Person
object.
That completes my explanation of the JNDI client code. Looking at SimpleLDAPClient.java, shown in Listing 1, you can easily see that more than half of the code goes toward opening and closing resources. Another
problem with the JNDI API is that most of its methods will throw a NamingException
or one of its subclasses in the case of an error. Because NamingException
is a checked exception, you must handle it if it is thrown, but can you really recover from an exception if your LDAP server
is down? No, you can't.
Most developers get around JNDI NamingException
s
by simply catching them and doing nothing. The trouble with this
solution is that it can cause you to lose important information.
Simplify directory access with Spring LDAP
Try a Spring-based approach to LDAP programming with JNDI
By Sunil D. Patil, JavaWorld.com, 06/26/07
Page 2 of 4
Getting started with Spring LDAP
Next, we'll see what happens when we write the same simple search client using Spring LDAP. I'll start by showing you how
to set up the Spring LDAP development environment, so that you can follow along with the example.
You
will need both the Spring Framework binaries and the Spring LDAP
binaries to run the following example. Spring LDAP requires J2SE 1.4
and is compatible with Spring Framework versions 1.2.8 and 2.0. The
sample code in this article is based on the 1.1.2 version of Spring
LDAP and has been tested using the Spring Framework 2.0.1.
Set up the Spring LDAP development environment as follows:
- If you are using an IDE like Eclipse, then create a Java project and name it "SpringLDAPFramework" (or something similar).
If you prefer not to use an IDE then simply download the sample code for this article. The sample code contains an Ant build script that you can use to build the example.
- Unzip the downloaded springbinaries
file into a folder, such as c:/temp. Add the
c:/temp/spring-framework-2.0.1/dist/spring.jar to the classpath of your
SpringLDAPFramework project.
- Likewise, unzip the springldapframework binaries into a folder such as c:/temp, then add C:/temp/spring-ldap-1.1.2/dist/spring-ldap-1.1.2.jar to the classpath of
your SpringLDAPFramework project.
Your Spring LDAP development environment is set up, and you are ready to start building a simple Spring LDAP application.
The ContactDAO interface
At heart the Spring Framework is a dependency injection framework,
which means that it supports programming to interfaces rather than
programming to classes. Spring LDAP takes a similar approach to
directory programming. The first step to creating a Spring LDAP client
is, therefore, to create a ContactDAO
interface that defines all the LDAP operations we want to perform. ContactDAO
is shown in Listing 3.
Listing 3. The ContactDAO interface
public interface ContactDAO {
public List getAllContactNames();
public List getContactDetails(String commonName, String lastName);
public void insertContact(ContactDTO contactDTO);
public void updateContact(ContactDTO contactDTO);
public void deleteContact(ContactDTO contactDTO);
}
Next, we'll create an LDAPContactDAO.java
class that implements the ContactDAO
interface. For now, we'll implement just one method in this class. The getAllContactNames()
method searches all objects where objectclass
is equal to person
and returns each object's cn in the form of a list. getAllContactNames()
is shown in Listing 4.
Listing 4. The getAllContactNames() method
public class LDAPContactDAO implements ContactDAO{
private LdapTemplate ldapTemplate;
public void setLdapTemplate(LdapTemplate ldapTemplate) {
this.ldapTemplate = ldapTemplate;
}
public List getAllContactNames() {
return ldapTemplate.search("", "(objectclass=person)",
new AttributesMapper() {
public Object mapFromAttributes(Attributes attrs)
throws NamingException {
return attrs.get("cn").get();
}
});
}
}
Now, note the ldapTemplate
property and setter method in Listing 4. setLdapTemplate()
is used to inject an LdapTemplate
object into the LDAPContactDAO
class. All the getAllContactNames()
method does is to call the search()
method of the LdapTemplate
class -- which is enough to get the job done. I'll explain all this in detail later in the discussion.
Working with the Spring context
Our next step is to create a Spring context file for the Spring LDAP example, as shown in Listing 5. (See the Resources section
to learn more about the Spring context file.)
Listing 5. springldap.xml
<beans>
<bean id="contextSource"
class="org.springframework.ldap.support.LdapContextSource">
<property name="url" value="ldap://localhost:10389" />
<property name="base" value="ou=system" />
<property name="userName" value="uid=admin,ou=system" />
<property name="password" value="secret" />
<property name="pool" value="true"/>
</bean>
<bean id="ldapTemplate" class="org.springframework.ldap.LdapTemplate">
<constructor-arg ref="contextSource" />
</bean>
<bean id="ldapContact"
class="com.javaworld.sample.LDAPContactDAO">
<property name="ldapTemplate" ref="ldapTemplate" />
</bean>
</beans>
In this example we are using an instance of the LdapContextSource
bean to manage the connection to our LDAP server. Note that you should use the DirContextSource
bean if you want to connect to an LDAP server with LDAPv2 compatibility. The LdapContextSource
bean has several properties that you can use to configure your LDAP connection, as follows:
- url should be equal to the LDAP server URL in the format of
ldap://<hostname>:<port>
. In this example we want to connect to an Apache Directory Server that is installed on a local machine. By default, Apache DS listens on port 10389, so the value of the url
property is ldap://localhost:10389
. If you want to connect to an LDAP server on a secured port, use ldaps://<hostname>:<securedport>
instead.
- base
is an optional property used to specify the value of the base suffix.
Once the base suffix is set, all LDAP operations start at this base
level. For the purposes of this example all LDAP operations are set to
start at the base level of "
ou=system
".
- userName is the username that should be used for getting an authenticated context. The username should be the distinguished name (DN)
of the user.
- password is the user password that should be used for getting an authentication context.
- pool is a boolean flag indicating that you want to pool LDAP connections in your application. By default, instances of
Context
and NamingEnumeration
s that are derived from Context
will share the same connection. This will change if you modify one of the Context
instances so that sharing is impossible -- for example by specifying new security credentials. In addition, you can set the
value of the com.sun.jndi.ldap.connect.pool
environment variable to true
while opening an LDAP connection. In that case JDNI will create a pool
of LDAP connections. Whenever you want to use a connection, JNDI will
return the connection from your pool. Once you are done with it, it
will go back into the pool. Specifying the value of the pool
property to true in your LdapContextSource
configuration will set the com.sun.jndi.ldap.connect.pool
property equal to true on the underlying LDAP connection.
Authentication in Spring LDAP
We've
set up the sample application so that we can get authenticated access
to our LDAP server, which will allow us to perform both read and write
operations. Note that some LDAP servers provide read-only anonymous
access, which allows you to connect to the server without user
credentials and perform read operations. You can get an anonymous
read-only connection by setting the server's anonymousReadOnly
property to true.
In Spring LDAP there are two ways to manage authentication. If you specify static authentication information (username and
password ) in your LdapContextSource
bean definition, the Spring LDAP framework will use these credentials to open all LDAP connections. Another approach is to
specify user credentials dynamically. For instance, if you were using Acegi Security System to manage the security of your Web application you could define Acegi's AuthenticationSource
bean in your LDAP context file. Thereafter, whenever the Spring LDAP framework wanted to open a new LDAP connection it would
pass control to the AuthenticationSource
object and get the username and password required to open the current connection. (See the Resources section to learn more
about dynamic authentication with Acegi Security System.)
The LdapContextSource
also takes a urls
property that can be used when you have multiple alternate LDAP
servers. In that case it will try connecting to each LDAP server one
after another until it is able to connect to a server successfully.
Note that this feature is implemented at the level of JNDI and not at
the level of the Spring LDAP framework. All the Spring LDAP framework
does is take list of the LDAP URLs, concatenate them in a string
separated with spaces, and set it as a value of Context.PROVIDER_URL
.
The Spring LDAP client
Finally, the complete Spring LDAP client is shown in Listing 6.
Listing 6. SpringFrameworkLDAPClient.java
public class SpringFrameworkLDAPClient {
public static void main(String[] args) {
try {
Resource resource = new ClassPathResource("com/javaworld/sample/springldap.xml");
BeanFactory factory = new XmlBeanFactory(resource);
ContactDAO ldapContact = (LDAPContactDAO)factory.getBean("ldapContact");
List contactList = ldapContact.getAllContactNames();
for( int i = 0 ; i < contactList.size(); i++){
System.out.println("Contact Name " + contactList.get(i));
}
} catch (DataAccessException e) {
System.out.println("Error occured " + e.getCause());
}
}
}
In the above class we first initialize the Spring Framework by creating a BeanFactory
object. Next, we ask the Spring Framework for an LDAPContactDAO
, and upon getting the object call its getAllContactNames()
method. This method returns a list reporting the cn of all the Person
type objects in the LDAP server. Finally, we iterate through the list and print it on the console.
If you execute the SpringFrameworkLDAPClient, it should return output similar to that of the JNDI-based SimpleLDAPClient.
In this case, however, the results are achieved with far less code, which is also more manageable.
Now
you've seen the difference between a simple JNDI program for
interacting with an LDAP server and the same program implemented using
the Spring LDAP framework. In the next sections I'll further explain
search queries using Spring LDAP, then get into some more advanced uses
of the framework, such as attribute mapping and creating dynamic
filters. I'll conclude with an introduction to CRUD operations using
Spring LDAP.
Search queries under the hood
At
the beginning of this article I briefly talked about the steps required
to execute simple search queries using Spring LDAP. A deeper
understanding of search queries will be useful later, when you are
using Spring LDAP for create, read, update and delete operations on
your LDAP server. When you make a call on the search()
method of the LdapTemplate
class, the resulting sequence of events is as follows:
- The
LdapTemplate
class calls the LdapContextSource
class's getReadOnlyContext()
method. The getReadOnlyContext()
method checks the value of the anonymousReadOnly
property. If the value is true, an anonymous connection is opened. Otherwise a connection is opened using the credentials supplied in your LDAP context
file.
- The Spring LDAP framework class defines a
DirContextProcessor
interface that you can implement if you want to execute some business logic either before or after a search. DirContextProcessor
defines two methods: preProcess()
, which gets called before a search, and postProcess()
, which gets called after a search. We haven't implemented the DirContextProcessor
interface for this simple example, so the Spring LDAP framework will use NullContextProcessor
, the default do-nothing implementation of the DirContextProcessor
interface.
- The
LdapTemplate
next calls the executeSearch()
method of the SearchExecutor
object. SearchExecutor
performs the actual LDAP search and returns the result.
- Once results are returned,
LdapTemplate
iterates through the results passing control to an instance of the AttributesMapper
class for every result. The mapFromAttributes()
method of the AttributesMapper
class gives you a chance to convert LDAP attributes into custom Java beans. Once control is returned from the mapFromAttributes()
method, the LdapTemplate
class takes the result and adds them to a List
.
- The
LdapTemplate
class calls the postProcess()
method of DirContextProcessor
class, giving you the opportunity to execute custom business logic.
- The
LdapTemplate
class takes care of closing resources in this last step. First it will call a closeNamingEnumeration()
method to close NamingEnumeration
objects returned by the search()
method. Next, it will call a closeContext()
method, which will close the connection to your LDAP server by calling the close()
method of the underlying Context
object.
Converting LDAP entries into custom Java beans
Spring LDAP uses an AttributesMapper
class to convert LDAP entries into Java beans. In this section I'll show you how to extend the Spring LDAP client to create
a ContactDTO
object for every Person
type object returned by an LDAP search. The first step is to create a simple Java bean with three attributes: commonName
, lastName
, and description
, as shown in Listing 7.
Listing 7. ContactDTO.java
public class ContactDTO {
String commonName;
String lastName;
String description;
public String getCommonName() {
return commonName;
}
public void setCommonName(String commonName) {
this.commonName = commonName;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}
Next, we create ContactAttributeMapper.java, as shown in Listing 8.
Listing 8. ContactAttributeMapper.java
public class ContactAttributeMapper implements AttributesMapper{
public Object mapFromAttributes(Attributes attributes) throws NamingException {
ContactDTO contactDTO = new ContactDTO();
String commonName = (String)attributes.get("cn").get();
if(commonName != null)
contactDTO.setCommonName(commonName);
String lastName = (String)attributes.get("sn").get();
if(lastName != null)
contactDTO.setLastName(lastName);
Attribute description = attributes.get("description");
if(description != null)
contactDTO.setDescription((String)description.get());
return contactDTO;
}
}
The ContactAttributeMapper
class implements AttributesMapper
, a simple interface used by Spring LDAP to convert LDAP attributes to custom Java beans. Upon getting results from an LDAP
server the Spring LDAP framework iterates through the results and will call a ContactAttributeMapper.mapFromAttributes()
method for each object returned by the server to convert attributes into custom Java beans.
In Listings 7 and 8 above, we created a new instance of ContactDTO
inside the mapFromAttributes
method. We then mapped the value of the cn attribute to commonName
; the value of the sn attribute to lastName
; and the value of the description attribute to the description
property of ContactDTO
. The mapFromAttributes()
method returns this newly created object of ContactDTO
and the Spring LDAP framework adds it to LinkedList
, which is the return value of the LdapTemplate.search()
method.
Remember to change the getAllPersonNames()
method so that it passes a ContactAttributeMapper
instead of a generic class, as shown in Listing 9.
Listing 9. getAllPersonNames() passes ContactAttributeMapper
public List getAllPersonNames() {
return ldapTemplate.search("", "(objectclass=person)",new ContactAttributeMapper());
}
Building dynamic filters
Until
now we have used the Spring LDAP framework to execute generic queries,
but in most cases you will want to execute more specific queries.
Spring LDAP defines multiple classes in the
org.springframework.ldap.support.filter package that facilitate the
creation of dynamic filters. In Listing 10, we extend the Spring LDAP
client with the getContactDetail()
method, which takes firstName
and lastName
as arguments and returns all Person
records for a given first name and last name.
Listing 10. getContactDetail()
public List getContactDetails(String firstName,String lastName){
AndFilter andFilter = new AndFilter();
andFilter.and(new EqualsFilter("objectclass","person"));
andFilter.and(new EqualsFilter("cn",firstName));
andFilter.and(new EqualsFilter("sn",lastName));
System.out.println("LDAP Query " + andFilter.encode());
return ldapTemplate.search("", andFilter.encode(),new ContactAttributeMapper());
}
In the above code we have specified that we want to search for contacts that meet three conditions: (1) the record must be
of type person; (2) the value of the cn attribute should be equal to firstName
; and (3) the value of sn should be equal to lastName
. The LDAP query for this search would be
(&(objectclass=person)(cn=<firstName>)(sn=<lastName>))
The first step to creating a dynamic filter is to create an instance of AndFilter
. Next, we set the filter conditions using Spring LDAP's filter classes, as follows:
EqualFilter("objectclass","person")
ensures that objectclass
is equal to person
.
EqualsFilter("cn",firstName)
ensures that only person
objects whose cn attribute value is equal to firstName
will be returned.
EqualsFilter("sn",lastName)
ensures that only person
objects whose sn attribute value is equal to lastName
will be returned.
AndFilter()
ensures that only those person records that meet all three requirements will be returned.
Once you have set the conditions you can retrieve the actual LDAP query generated by calling Filter.endcode()
. This method will return a string representing your custom dynamic filter. Pass this filter object to LdapTemplate.search()
and it will return only entries matching all three conditions. See the Resources section to learn more about creating dynamic filters.
Simplify directory access with Spring LDAP
Try a Spring-based approach to LDAP programming with JNDI
By Sunil D. Patil, JavaWorld.com, 06/26/07
Page 4 of 4
Using Spring LDAP for CRUD operations
In
some cases you will need to do more than read or search records in your
LDAP server. You will also need to add records, modify them, and delete
them. In this final section I'll show you how to perform these simple
CRUD operations using Spring LDAP. Listing 11 updates LDAPContactDAO.java (shown in Listing 4) with a new method for adding records to your LDAP server.
Listing 11. Add insertContact() to LDAPContactDAO.java
public void insertContact(ContactDTO contactDTO) {
Attributes personAttributes = new BasicAttributes();
BasicAttribute personBasicAttribute = new BasicAttribute("objectclass");
personBasicAttribute.add("person");
personAttributes.put(personBasicAttribute);
personAttributes.put("cn", contactDTO.getCommonName());
personAttributes.put("sn", contactDTO.getLastName());
personAttributes.put("description", contactDTO.getDescription());
DistinguishedName newContactDN = new DistinguishedName("ou=users");
newContactDN.add("cn", contactDTO.getCommonName());
ldapTemplate.bind(newContactDN, null, personAttributes);
}
Performance note |
LDAP
directory servers are intended primarily for read-only access and do
not perform well if you frequently modify the data they contain. Keep
CRUD operations to a minimum in your LDAP server. Otherwise, if your
design requires extensive data modification, you may want to consider
using an RDBMS, which is better suited to write operations than an LDAP
directory server. |
The insertContact()
method takes an object of the ContactDTO
type and adds it as a person type object in the LDAP server. The first thing that we do in this method is create a new instance
of the BasicAttribute
class where objectclass
is equal to person
. We then set commonName
as the value of the cn attribute; lastName
as the value of the sn attribute; and description
as the value of the description attribute. Once we are done, we pass ContactDTO
to the LdapTemplate.bind()
method, along with the DistinguishedName
object. DistinguishedName
is a utility class defined in the Spring LDAP framework that implements the Name
interface.
The first thing the bind()
method does is to read your username and password information and use
it to open a connection to the LDAP server. Note that you cannot use
anonymous access for write operations, so in this case you must supply
your username and password. Once your access permission has been
established the bind()
method is called and the record is added to the server.
Modifying data
Listing 12 shows how to modify data in your LDAP server by adding a method to LDAPContactDAO.java.
Listing 12. Add updateContact() to LDAPContactDAO.java
public void updateContact(ContactDTO contactDTO) {
Attributes personAttributes = new BasicAttributes();
BasicAttribute personBasicAttribute = new BasicAttribute("objectclass");
personBasicAttribute.add("person");
personAttributes.put(personBasicAttribute);
personAttributes.put("cn", contactDTO.getCommonName());
personAttributes.put("sn", contactDTO.getLastName());
personAttributes.put("description", contactDTO.getDescription());
DistinguishedName newContactDN = new DistinguishedName("ou=users");
newContactDN.add("cn", contactDTO.getCommonName());
ldapTemplate.rebind(newContactDN, null, personAttributes);
}
You may have noticed that the updateContact()
method is very similar to insertContact()
. The only difference between the methods is that at the end of updateContact()
you call LdapTemplate.rebind()
instead of bind()
. The difference between bind()
and rebind()
is that an NameAlreadyBoundException
will be thrown if you try to bind an attribute with the same name as an existing attribute. In the case of a rebind()
the new object would overwrite the existing entry.
Deleting data
if you want to delete data in your LDAP server you can do so by simply adding a delete method to LDAPContactDAO.java
, as shown in Listing 13.
Listing 13. Add deleteContact() to LDAPContactDAO.java
public void deleteContact(ContactDTO contactDTO) {
DistinguishedName newContactDN = new DistinguishedName("ou=users");
newContactDN.add("cn", contactDTO.getCommonName());
ldapTemplate.unbind(newContactDN);
}
All that is needed to delete a contact in an LDAP server is to pass a DistinguishedName
type object pointing to the record you want to delete to the LdapTemplate unbind()
method. The LdapTemplate will use this object and call the unbind()
operation on the underlying Context
object.
Summary
In
this article you've learned how the Spring LDAP framework minimizes the
low-level coding typically associated with LDAP clients. The Spring
LDAP framework does not replace JNDI but rather wraps and extends it to
simplify LDAP programming on the Java platform. In addition to building
a simple Spring LDAP client and performing basic CRUD operations,
you've learned how to set up dynamic filters and convert LDAP entries
to Java beans. See the Resources section to learn more about the Spring
LDAP framework and download the sample application that comes with this article.
Author Bio
Sunil Patil is a Java
Enterprise/Portlet developer working for Ascendant Technology in San
Francisco, California. He is the author of Java Portlets 101
(SourceBeat, April 2007) and has written numerous articles published by
O'Reilly Media. Sunil was a member of IBM's WebSphere Portal Server
development team for three years and is actively involved in the Pluto
community. In addition to being an IBM Certified WebSphere Portal Server
Application Developer for both v5.0 and v5.1, he is a Sun Microsystems
Certified Java Programmer, a Web component developer, and a business component
developer. You can view Sunil's blog at http://jroller.com/page/SunilPatil.