Apache Directory Server is an open-source, Java-based implementation of numerous Internet protocols. The core of ApacheDS is a directory service that can store application data and perform search operations on different types of data. Protocol implementations work on top of the directory service to provide Internet services related to data storage, search, and retrieval.
Perhaps the most important feature of ApacheDS is the ability to expose its directory service using different protocols. This means you can store your application data (including runtime Java objects) in ApacheDS, and various clients can make use of your data using different protocols. The most important protocol implemented by ApacheDS is Lightweight Directory Access Protocol (LDAP). ApacheDS acts as an LDAP server, listens for requests, and coordinates with its internal core directory service to respond to LDAP requests.
In this two-part article, I'll introduce you to the core ApacheDS architecture and walk you through all the steps of storing your runtime Java objects in ApacheDS. Because I focus almost entirely on ApacheDS as an LDAP server implementation, much of this first half of the article is spent familiarizing you with LDAP functionality and terminology. Before I get into that, however, I'll introduce you to the modular, extensible architecture of ApacheDS and explain how you can use it to plug in new protocol implementations and Internet services to ApacheDS. Understanding the workings of the ApacheDS core directory service will help you understand later how it provides LDAP functionality.
You need to download and install ApacheDS and JXplorer to follow the discussion in this article. You may download the complete source code for the article at any time.
Directory services in ApacheDS
A directory service is an application that stores and organizes data. Directory services handle data that does not require frequent updates, such as the personal data of the users of a system (e.g., name, address, telephone numbers) or the manufacturing capability of a production hall (e.g., number, types, and production capacity of machines installed). Later in this article, I'll introduce an example application that incorporates these two types of data. For now, I'll focus on how ApacheDS provides directory services.
In Figure 1, you can see that ApacheDS implements a Java Naming and Directory Interface (JNDI) wrapper for its core directory service. JNDI is a Java interface that defines methods to perform directory operations such as storing data in a directory and searching for stored data. JNDI is part of both Java 2 Enterprise Edition (J2EE) and Java 2 Standard Edition (J2SE). Whereas J2SE only includes client-side JNDI support, J2EE containers normally include server-side JNDI implementations. A J2EE container can use the directory services of ApacheDS through its JNDI wrapper, as shown in Figure 1:
Figure 1. ApacheDS working inside a J2EE container

The set of interfaces in JNDI provides an abstraction of a directory service. JNDI implementations provide the actual logic to talk to a directory service (for example, the Java platform comes with a JNDI implementation for LDAP). You can use JNDI to talk to any type of directory service, as long as you have a JNDI implementation for that particular one. If you want to use JNDI in a Java-based client application, you'll need a client-side implementation of JNDI. A client-side JNDI implementation provides classes that implement JNDI interfaces to author requests for directory operations.
ApacheDS implements server-side JNDI. This means it includes classes that implement JNDI interfaces to respond to requests for directory operations. As I noted previously (and shown in Figure 1), a J2EE container can use the directory services of ApacheDS through its JNDI wrapper.
Figure 1 shows only one usage model for ApacheDS. ApacheDS isn't meant to be used only as a directory service embedded inside a J2EE container. You can use ApacheDS to implement any protocol that requires back-end directory services. You can even use it to serve various different types of protocols simultaneously; for example, the current ApacheDS implementation implements both LDAP and Kerberos. Furthermore, the list of protocols supported in ApacheDS is still growing.
ApacheDS has a flexible, extensible architecture that makes it possible to implement new protocols. In Figure 2, you can see a model of the ApacheDS architecture, which works on top of the JNDI wrapper shown in Figure 1:
Figure 2. The flexible and extensible architecture of ApacheDS

As you can see, ApacheDS uses a set of interfaces called Multipurpose Interfaces for Networked Applications (MINA). MINA enables new protocol implementation to be plugged into ApacheDS. I'll explain how MINA works before moving on.
The interfaces in MINA contain methods to generate protocol-specific factory objects. These factory objects provide a means to plug a new protocol implementation into ApacheDS. Protocol implementations implement MINA interfaces, and the ApacheDS framework relies on the methods included in MINA to talk to protocol implementations.
For example, MINA has an interface named ProtocolProvider that has a getCodecFactory() method. The ProtocolProvider.getCodecFactory() method returns
an object exposing another MINA interface named ProtocolCodecFactory.
Protocol implementations in ApacheDS implement the ProtocolProvider interface. For example, the LDAP
implementation in ApacheDS has a class named LDAPProtocolProvider that implements the ProtocolProvider interface.
The getCodecFactory() method in LDAPProtocolProvider returns an object that exposes
the ProtocolCodecFactory interface. This
ProtocolCodecFactory is a factory object that
the ApacheDS framework uses to create LDAP-specific encoding and
decoding objects.
ProtocolCodecFactory contains newEncoder() and newDecoder() methods, which return objects exposing
MINA's ProtocolEncoder and ProtocolDecoder interfaces. A
protocol-specific encoding object exposes the ProtocolEncoder interface and the decoding object
exposes the ProtocolDecoder interfaces.
MINA's encoding and decoding framework
As you can probably guess, the ApacheDS framework uses a
protocol-specific ProtocolDecoder instance to
decode a protocol request so it can understand its meaning before being able
to process the request. After decoding, ApacheDS processes the request.
For example, if the request was an LDAP search request, ApacheDS would
search for the required data in its back-end directory service and fetch
the search results.
After finding the required search results, the ApacheDS framework
uses a protocol-specific ProtocolEncoder
object to encode the search results. In the case of an LDAP search
request, ApacheDS would use the LDAP-specific ProtocolEncoder object to encode the search results
before sending the response to the requesting client.
MINA also has classes to handle services. Any service provider can register itself into a service registry and the protocol provider will be registered along with the provider classes that provide the service. The protocol provider then maps protocol requests to JNDI operations. A simple example is that of an LDAP search request being mapped to a JNDI search operation. Once the ApacheDS framework knows which JNDI operation needs to be invoked while processing a protocol request, it can generate an event.
The event-handling framework in MINA transmits the event to an appropriate handler. For example, if the request requires a JNDI search operation to be invoked, the search handler is invoked. MINA also maintains a pool of threads. If a handler is busy working on a previous operation, the event is temporarily stored in the thread pool until it is handled.
You can see the protocol providers, MINA interfaces and classes, and operation handlers working with JNDI in Figure 2.
Perhaps the greatest advantage of the ApacheDS architecture is its use of a common directory service (JNDI) for different protocol providers. This means you can use ApacheDS to expose your data to clients using different protocols. Because one of the most important protocols supported by ApacheDS is LDAP (and because you'll be using ApacheDS primarily as an LDAP server to store Java objects), I'll move on to a more in-depth discussion of LDAP. See Resources to learn more about the ApacheDS architecture.
The LDAP protocol defines request and response messages for directory operations. Directory operations include storing new data in a directory, searching for and retrieving stored data, deleting unwanted data, updating obsolete data, and similar operations. (See Resources for RFC 2251, the official LDAP specification that defines request and response messages to store, retrieve, update, and delete data in an LDAP directory.)
The LDAP message that you use to store new data (for example, your runtime Java object) in ApacheDS is called a bind message. A bind message transfers user data to an LDAP directory service, such as ApacheDS, and stores (or saves) the data in the directory.
LDAP doesn't care about the physical location of data storage. Instead LDAP specifies a Distinguished Name (DN) for every data entry stored in ApacheDS. Every DN has to be unique throughout the directory service. No two entries can have the same DN. You'll learn about the mechanism LDAP uses to ensure that each DN is unique later in the article.
In addition, the search mechanism in LDAP uses DNs. The next section introduces an example application scenario that will familiarize you with LDAP terminology and introduce LDAP's search mechanism. I'll use the example application throughout this two-part article.
For the sake of this application scenario, suppose you are designing a data management system for a manufacturing company. The company has employees, customers, partners, and vendors, all of whom are users of the data management system. The data management system is required to store data about the users in ApacheDS.
The system allows all users to set their own preferences about the way they use the system. For example, users can customize the data to be displayed in their personal default view when using the system and apply different presentation styles to different data elements. The system also allows special preferences depending on the type of a user. For example, employees of the company (internal organizational users) can set messaging preferences, customers can set shipping preferences, and vendors can set invoicing preferences.
A simple way to set up individual user preferences in ApacheDS is to
store preferences in the form of Java objects. For this application
scenario, you can start by designing a Preferences class
for all types of users. The Preferences class contains
methods that allow users to set preferences that are common to all types
of users (internal users, customers, and vendors, in this case). For
instance, the Preferences class might contain
a setStyles() method specifying the location
of a stylesheet. The stylesheet would be used to apply presentation
styles to different data elements.
You can also extend the Preferences class to
form a MessagingPreferences class, which will
include messaging preference for internal users. Similarly, you can design a ShippingPreferences class for customers and an
InvoicingPreferences class for vendors.
Listing 1 is a skeleton form of the Preferences,
MessagingPreferences, ShippingPreferences, and
InvoicingPreferences classes. For the sake of simplicity, I have
not included any methods (except the setStyles() method) in Listing 1. For now, I just want to demonstrate the storage of class instances in ApacheDS.
Listing 1. Java classes representing different types of user preferences
public class Preferences implements java.io.Serializable {
String styleSheetURL = null;
public void setStyles(String styleSheetURL){
this.styleSheetURL = styleSheetURL;
}
//Other methods of the Preferences class
}
public class MessagingPreferences extends Preferences {
//Methods of the MessagingPreferences class
}
public class ShippingPreferences extends Preferences {
//Methods of the ShippingPreferences class
}
public class InvoicingPreferences extends Preferences {
//Methods of the InvoicingPreferences class
} |
Suppose Alice is working in the commercial department of the manufacturing
company. She uses your data management system to store all her data
(name, department, e-mail address, telephone number, etc.) as well as her
preferences (in the form of a MessagingPreferences object) into ApacheDS. All her
data is stored in ApacheDS with a unique DN.
Now suppose Alice wants to change her messaging preferences using
your data management system. The data management system first uses
LDAP to search for Alice's named context to know its DN. When it
knows the DN, it fetches Alice's MessagingPreferences object from the DN, updates the
object with Alice's latest data, and stores the object back into
ApacheDS.
Now that you have an application scenario in mind, let's start exploring how you can use ApacheDS to make all this server-side magic happen.
You need to learn LDAP schemas to understand how to store any type of data (including a Java object) in ApacheDS. Moreover, it's helpful to view the data stored in an LDAP server in a graphical representation, where you can see it in tree form. For this, I'll show you how to use JXplorer, a Java-based open source client-side LDAP implementation that provides a browser view for the data stored in an LDAP server. Because I use JXplorer to introduce you to the LDAP schemas, you need to download and install JXplorer before going further.
If you haven't done so already, you'll also need to download ApacheDS now. Installation is pretty simple: You'll get a zip file that you can unzip to extract the JAR files of ApacheDS. Start the LDAP server in ApacheDS by running apacheds-main-0.9.jar from the command line as follows:
<JAVA_HOME>/java -jar apacheds-main-0.9.jar |
The LDAP server in ApacheDS is now live listening (by default) at
localhost:389, ready to serve LDAP requests
from client applications.
After starting ApacheDS, run JXplorer to get the browser view shown in Figure 3. As you can see, JXplorer is not yet connected to any LDAP server.
Figure 3. The first view when you start JXplorer

Next, you need to connect to ApacheDS. For this, you use the Connect command in the File menu of JXplorer. In the connection dialog box ("Open LDAP/DSML Connection"), fill in the values shown in Figure 4:
Figure 4. The connection dialog box

Note in Figure 4 that the host and port fields specify the address
where your ApacheDS is listening. You also need a username and a
password to connect to ApacheDS. ApacheDS comes with a default
administrative username (uid=admin,ou=system)
and password ("secret") pair, which you can use to connect to ApacheDS.
Note that I entered the default username in the User DN field and the default password in the Password field.
After you've entered the values in the connection dialog box, click OK. JXplorer sends a connection request to ApacheDS and after a moment, you see the screen shown in Figure 5. You are now connected to ApacheDS.
Figure 5. The first JXplorer screen after connecting to ApacheDS

The screen in Figure 5 is divided into two segments, very much like the Windows Explorer screen. The left side is a tree view and the right side shows the details of what you select from the tree view.
The left side has three tabs labeled Explore, Results, and Schema. The Explore tab helps you explore the data contained in ApacheDS. You use the Explore tab to view data entries in ApacheDS. The Results tab shows search results, and the Schema tab provides details of schemas supported by ApacheDS. For the most part, I'll use the Explore and Schema tabs in this discussion.
Note that Figure 5 shows the Explore tab selected, which gives details of the data contained in ApacheDS. Because I haven't stored any data in ApacheDS yet, what you are seeing now is the default data. For example, if you click the admin entry in Figure 5, you get the screen shown in Figure 6, which shows the default administrative entry that comes loaded with ApacheDS:
Figure 6. Details of the admin entry

The admin entry represents the administrator of ApacheDS, whose
username and password were entered in Figure 4.
The right portion of Figure 5 shows an HTML
view of the admin entry, which contains several fields, such as the User Password field. You can change the
administrator password by writing a new password in the password field and then clicking the Submit button.
Each entry on the right side of Figure 6
is actually an LDAP attribute. Many types of attributes are defined for
LDAP. A type of attribute is referred to as an attributeType in LDAP terminology.
Attributes are meant to contain data values (like the Common Name field contains the name of the ApacheDS
administrator as its value). You must define many aspects of data you
wish to store as an attribute value. For example, you need to
specify the data encoding (whether an attribute contains textual or
raw binary data).
Another important aspect of using data is to be able to search for it. For example, you may want to search for all data related to a user whose name or e-mail address you know, so you need to specify matching rules to be applied during the search operation. In the case of an e-mail address, you might want to perform a case-insensitive search.
JXplorer can show you the attribute types used to define the default administrative entry. Click the Table Editor tab on the right side of the screen shown in Figure 6; you see a Table Editor view like the one shown in Figure 7:
Figure 7. The Table Editor view of the admin entry

The table in Figure 7 contains an "attribute type" column and a "value" column. You can map several of the attribute types shown to the fields of Figure 6. For example, the cn and sn attribute
types of Figure 7 correspond to the Common Name
and Surname fields of Figure 6,
respectively.
This means attributes in a data entry have attribute types
associated with them. ApacheDS supports dozens of attribute types meant
for a wide range of purposes and specified in different Internet
standards. This article discusses a subset of the attribute types
supported by ApachDS, namely those used in storing Java objects.
In particular, I'll use cn, a multipurpose attribute type used to specify common names of any entity. You can use the cn attribute type to specify the name of a manager working in the commercial department of an enterprise, and you can also use it
to name a Java object. As you might guess, the sn attribute type is not general-purpose: it is
only used to specify the surname of a person.
Now that you know a thing or two about attribute types, take a look
at the objectClass attribute type, which has
four values in Figure 7: inetOrgPerson, organizationalPerson, person, and top. This
means the admin entry contains four object classes.
In fact, all data entries in ApacheDS use object classes. An object class is a collection of attribute types. If a data entry (like the admin entry in Figure 6 or Figure 7) is associated with an object class, the entry contains all the attribute types in the object class.
You can see for yourself the attribute types contained in the four object classes used by the admin entry. Click the Schema tab on the left side of Figure 7 to get the screen shown in Figure 8. The Schema tab displays information about the attribute types, object classes, and data formats that ApacheDS supports.
Figure 8. The Schema tab

Now expand the objectClasses entry on the left side of
the screen shown in Figure 8. The entry expands into a long, alphabetically arranged list of object types supported by ApacheDS. Look for the person object class in the list and click it.
You see the screen shown in Figure 9:
Figure 9. The person object class

In Figure 9, you can see the details of the person object class in the form of various fields. The fields that define an object class are as follows:
Table 1. Fields that define an object class
| DESC | Provides a textual description of the person object class. The person object class is defined in RFC 2256 (see Resources), which describes
many object classes and attribute types used by clients or users of an
LDAP directory service. For example, any person can be a user of an LDAP
service and therefore the person object class
defines the attributes that any person could have (such as the full name
of a person). | |
| MAY | Specifies a list of optional
attribute types included in the person
object class. For example, the person object
class optionally includes userPassword and
telephoneNumber attribute types, which are
used to hold the password and telephone number of a person. I'll show you
how to specify the details of an attribute type later in the article. | |
| MUST | Specifies the mandatory attribute types for the
person object class. The person object class contains just two mandatory attributes: sn and cn, which you already read about. | |
| NAME | Specifies the name of the object class. | |
| OID | Specifies an object identifier for the object class. Every LDAP object
class and attribute type must have a unique object identifier. RFC 2256
specifies the object identifier for the person object
class. For object identifiers to be unique, the Internet
Assigned Numbers Authority (see Resources)
issues object identifiers for free. You won't need to fetch any object
identifiers for this article because we won't define any new attribute
types. | |
| SUP | Specifies the parent
of the object class. The concept of inheritance (extending a
parent's capability to a child) in object classes is similar to
inheritance in object-oriented programming languages. Note from the
SUP attribute value in Figure 9 that the person
object class extends a class named top, which
is the superclass of all object classes. This means all object classes in LDAP
directly or indirectly extend the top object
class. |
Now look at the top object class shown in Figure 10, which contains just one attribute type named objectClass. As all object classes
extend from the top class, so the objectClass
attribute type is always present in all data entries, no matter which
object class the data entry is using. In simple terms, this means all data
entries should define the object class they are using.
Figure 10. The top object class

There are three types of object classes: abstract, structural, and
auxiliary. Knowing this, you can note that the top object class is abstract, which means it only exists so that other object classes can extend it. No data entry directly uses an abstract class.
On the other hand, the person object
class is structural. All data entries use structural classes. Structural
classes extend other structural as well as abstract classes. For example,
a structural class called organizationalPerson
(defined in RFC 2256) extends the person object class, which in turn extends the top object class.
The organizationalPerson object class
represents a specialized type of person who is working in an
organization. Therefore, it defines attributes that may apply to a
person working in an organization (for example, the job title of an office
worker). Figure 11 shows the organizationalPerson object class on a
JXplorer screen:
Figure 11. The organizationalPerson object class

Auxiliary object classes are meant to serve some very specific
purpose. This means auxiliary object classes
don't contain the general-purpose attribute types (such as the
cn and objectClass
attribute types discussed earlier) required in almost all data entries.
A data entry cannot entirely rely on an auxiliary object class. Therefore, a data entry that uses an auxiliary object class also has to use at least one structural class. I'll provide an example of an auxiliary class later in the article, when I begin to show you how to store Java objects in ApacheDS.
Now let's further consider the use of attribute types in ApacheDS. Expand the attributeTypes entry of the JXplorer screen shown in Figure 8 and you see the screen in Figure 12, which shows many attribute types. These attribute types are defined by several
specifications supported by ApacheDS (such as RFC 2713,
which defines attribute types and object classes for storing Java
objects in an LDAP directory; see Resources).
Figure 12. Attribute types supported by ApacheDS

Click the cn attribute entry shown in Figure 12 and you see a screen similar to the
one shown in Figure 13. Figure 13 displays the
fields that collectively define an attribute type:
Figure 13. The cn attribute type

You already know about several of the above-displayed fields from my earlier discussion about the person object class, so I'll only discuss the ones you haven't yet learned about:
Table 2. More fields
| EQUALITY | Specifies a matching rule that applies when you search for a data
entry with a particular attribute value. The value of this field for the
cn attribute type is caseIgnoreMatch. Using this attribute
type and value means that when you search for a person with a particular name the search operation will be case insensitive. |
| SUBSTR | Is similar to the EQUALITY field, except that the SUBSTR field specifies matching rules for search
performed to look for specified substrings instead of the complete
attribute value. I will demonstrate the affect of SUBSTR field in Part 2 of this article. |
Also look at the SYNTAX field in Figure 13, which contains an OID value. The OID
value identifies the syntax (or data format) for the attribute value.
Every attribute type defines the syntax of the data to be stored as the
attribute value. The OID in Figure 13 points to an LDAP syntax that is
used to store strings in an LDAP directory. The next section discusses
LDAP syntax.
If you click the Schema tab of JXplorer and then click the
ldapSyntaxes entry in that tab, you see an alphabetically
arranged list of LDAP syntax supported by ApacheDS. Find and click on
the one named Directory String. You see the screen shown in Figure 14, which shows the fields that define an LDAP syntax:
Figure 14. The Directory String syntax

The Directory String syntax stores string values in an LDAP directory. You can easily understand the
meaning of all the fields because they're similar to the fields I've
already explained. Do notice, however, that the OID field in Figure 14
exactly matches with the SYNTAX field of the cn attribute in Figure 13.
That's because the cn attribute type
follows the Directory String LDAP syntax.
This means LDAP treats names as strings.
Also have a look at Figure 15, which shows
another LDAP syntax called Octet String,
which represents a string of octets. A Java object is stored as a string
of octets, so you will be using the Octet String LDAP syntax in this
series of articles.
Figure 15. The Octet String syntax

'
With the Directory String and Octet String syntax in mind, you're ready to move on to the next step of making a data entry using ApacheDS.
At this point, you've learned enough about LDAP components and how they're implemented in ApacheDS to write a new data entry to ApacheDS. This exercise will help you understand how schema components such as object classes, attribute types, and syntax store or represent data entries in an LDAP directory.
Start by clicking the JXplorer Explore tab and then the Users entry in that tab. ApacheDS does not have any default users, so the Users entry is empty. Right-click the entry and you see a pop-up menu. Select the New command from the pop-up menu, and you get a dialog box named "Set Entry Object Classes," as shown in Figure 16:
Figure 16. The Set Entry Object Classes dialog box

The first thing you need to do is provide some information in the dialog box, which I discuss in the next section.
Using distinguished name syntax
As I mentioned at the beginning of my discussion of LDAP schemas, all
data in ApacheDS resides in the form of a tree. This means every data
entry has a parent except the root entry. The root entry in ApacheDS is
labeled system, which you can see in Figure 16.
Every data entry has a DN that should be
unique throughout the directory. RFC 2253 (see Resources) provides the syntax to write a
DN in the form of a string. According to RFC 2253, a DN
is written as a comma-separated list of components, with each component
having its value. Although you can use several components to define a
DN, I use only three of them in this article: ou, uid, and cn. Each
one has a different purpose:
- The
oucomponent specifies the name of an organizational unit. For the purpose of this article, you can imagine it is actually the name of a unit of data organization. You can structure different types of data in ApacheDS using this attribute. - The
uidcomponent provides a user identifier for the entry. Normally, you use this attribute to identify the users (for example, Alice) of ApacheDS. - The
cncomponent names Java objects.
The DN for the root system entry shown in
Figure 16 is ou=system. The "users" entry is the direct child of system, so the DN of users is ou=users,ou=system. Note that the first part of
the user's DN (ou=users) is called its relative
distinguished name (RDN).
The RDN of a child entry (for example, ou=users)
is prepended to its parent's DN (for example, ou=system) with a comma in between to form the DN
of the child entry (for example, ou=users,ou=system). No two immediate children of a
parent (that is, siblings) can have the same RDN. This ensures that
DNs are unique throughout the LDAP directory.
With this in mind, you can easily understand the meaning of the Parent DN and Enter RDN
fields shown in Figure 16. While creating a new
entry, you right-clicked the Users entry and so the Parent DN field appears already filled in with the
DN of the Users entry.
Your next step is to supply the RDN of the entry you want to create.
For the sake of the example application, you're creating a new user
named Alice, so you enter uid=Alice in the
Enter RDN field of Figure 16. This makes
uid=alice,ou=users,ou=system the DN of
Alice's entry.
Note that data query or search operations on distinguished names
(which I demonstrate in the second half of this article) are
case-insensitive. This means that for all practical purposes, there is no
difference between specifying uid=Alice or uid=alice as the value of the RDN field.
So far, so good. Next, you select the object classes you want your new entry to take. You can select any number of object classes for an entry. When you select an object class, you need to supply all the mandatory attributes included in the particular object class. In addition, you may also supply any of the optional attributes of the object class.
You'll recall that Alice works in the commercial department of the company for which you're building a data management system, so
she only needs the attributes that belong to the organizationalPerson object class, which I introduced
in Figure 11. Therefore, you add the organizationalPerson object class to the Selected
Classes list shown in Figure 16 and click OK.
You see the screen in Figure 17, which shows Alice's entry just after the Set Entry Object Classes dialog box. Notice from Figure 17 that Alice's uid value (which you just authored) is shown in blue:
Figure 17. Alice's entry just after the Set Entry Object Classes dialog box

Next, you need to supply values for the mandatory attributes (cn and sn, shown in bold
in Figure 15) and click Submit.
JXplorer then authors an LDAP request to make a new entry and sends the request to ApacheDS.
ApacheDS sends a confirmation response message back to JXplorer and JXplorer updates the data tree, as shown in Figure 16. You can see the resulting entry named Alice on the right side of Figure 18:
Figure 18. An entry for Alice

With that, you're done. You've completed your first data entry using ApacheDS!
Whenever you want to store a Java object in a directory, you first need to convert your Java object to its byte representation. This conversion process is called serialization. The output of the serialization process is a stream of bytes, which can travel across a network and over to ApacheDS, where it can be stored as a byte representation of your Java object.
Remote Method Invocation (RMI) employs the serialization process in a special manner. Before I discuss the particulars of storing Java objects in ApacheDS, let's make sure you understand the conceptual basis of what's involved.
The Java language has a specification called Java Object Serialization Specification version 1.5, which defines the process of converting a Java object to a stream of bytes (see Resources). According to the Java Object Serialization specification, the process of serializing a Java object is already implemented in the JRE in the form of a serialization runtime that handles serialization and deserialization of Java objects.
The serialization runtime contains a couple of methods, writeObject() and readObject(), which it uses to serialize and
deserialize Java objects according to the Java Object
Serialization specification. The Java object that you want to
serialize just needs to implement an interface named java.io.Serializable. The Serializable interface does not contain any
methods: it exists only to tell the serialization runtime that your
object is serializable.
Note that the serialization runtime serializes the data members of
your Java objects during the serialization process. If some of the
data member is itself another Java object, you should serialize that
member along with the main object that you want to serialize.
Therefore, such data members should also implement the Serializable interface.
In the second half of this article, I demonstrate how to use the default serialization support in Java to store Java objects in ApacheDS.
In addition to serializing your objects, you may want to apply some specific encoding to the byte representation before sending it across a network. This encoding process is called marshalling, and it is an important element of the Java RMI Specification. The RMI framework allows your Java applications to use remote objects. A remote object resides outside the scope of your Java application, such as elsewhere on the Internet.
Using RMI, you can call methods of remote objects just like you call methods of local objects. To do this, you need a stub class of the remote object. The stub class contains method signatures of the remote object. Your application instantiates the stub class and calls its methods locally. The RMI framework then manages communication with the remote object, which results in remote invocation of the required methods. As a result, the application doesn't need to know whether the object is actually local or remote.
The details of the RMI framework are beyond the scope of this article, although you can learn more about it by studying references in the Resources section. What is important to this discussion, as you've probably guessed, is that the RMI framework allows Java objects to travel across a network to invoke methods of remote objects. Therefore, RMI needs to serialize Java objects. The RMI specification specifies a marshalling algorithm, which is applied to the serialized form of Java objects. The algorithm inserts special flags in serialized objects.
The RMI specification is already implemented in J2SE, so you don't need to worry about the low-level details of object marshalling. You can simply use RMI classes to marshall your Java objects. LDAP allows you to store marshalled Java objects in an LDAP directory. In the second half of this article, I demonstrate how to marshall and unmarshall Java objects, as well as how to store and retrieve them in ApacheDS.
Storing Java objects in ApacheDS
For the remainder of this article, I'll walk you through a simple application of the concepts you've learned so far. I'll show you how to represent a serialized Java object, use different object classes, represent a marshalled Java object, and store a reference of a Java object in ApacheDS. In Part 2, I'll take these simple exercises much further; for now, just focus on the basic steps involved.
To start, you need a set of object classes to work with. RFC 2713
(see Resources) defines object
classes and attribute types to represent Java objects in an LDAP
directory. ApacheDS provides complete support for these attribute types
and object classes. I use four object classes for this exercise and
the ones in Part 2: javaContainer, javaObject, javaSerializedObject and javaNamingReference. Let's take a look at the
first two object classes and their attributes.
javaContainer (shown in
Figure 19) is a structural class that contains just one attribute: cn. The purpose of this object class is to name the
data entry that contains the Java object. LDAP allows you to use other
structural object classes to name your Java object. For example, you can
also use the person object class to store
your Java object.
Figure 19. The javaContainer class
javaObject is an abstract class. The
purpose of this object class is to define some helping attributes that
are not directly used in storing the data of a Java object but are
rather helpful in search operations to find or retrieve the object from
the directory. Figure 20 shows the javaObject class:
Figure 20. The javaObject class

The attribute types in the javaObject
class shown in Figure 20 are as follows:
- A mandatory attribute type named
javaClassNameholds the name of the class whose instance is stored in ApacheDS. You normally use this attribute type to find instances of a particular class stored in ApacheDS. - Another attribute type named
javaClassNamesholds names of all the super classes of the Java object as well as the names of all the interfaces that the object implements. This attribute is supposed to hold a number of values, so it is a multivalued attribute type. LDAP allows multivalued attributes to hold multiple values. You use thejavaClassNamesattribute type while searching for objects that have implemented a particular interface or objects extending a particular class. - The
javaCodebaseattribute type shown in Figure 20 stores the location where a class definition for the stored Java object can be found. It is an optional attribute, which you use if your application requires loading class definitions by reading their location from ApacheDS. - The
javaDocattribute type is also optional and carries a URL that points to the Java documentation of the class whose instance is stored in ApacheDS.
As you can likely guess, the description attribute type stores a textual description of the class.
Representing a serialized Java object
Notice that none of the attribute types in javaObject stores the actual string of octets that
represents the object being stored. That's why the javaObject class is kept abstract and why you cannot
use it directly to create a data entry. LDAP has defined the
javaObject class this way because LDAP allows
you to store Java objects in different forms (for example, objects in serialized
or marshalled forms). Each form of object representation has its own
object class that extends the javaObject
class.
An object class named javaSerializedObject (shown in Figure 21)
extends the javaObject class by adding just
one attribute called javaSerializedData. The
javaSerializedData attribute contains the
actual serialized form of your Java object.
The javaSerializedObject class shown
in Figure 21 is an auxilliary object class, for reasons I'll shortly explain:
Figure 21. The javaSerializedObject class
Now look at Figure 22, which is a serialized Java object called MessagingPreferences stored in ApacheDS,
as shown on the JXplorer screen:
Figure 22. Alice's MessagingPreferences object stored in ApacheDS

The MessagingPreferences object in Figure
22 represents the preferences that your user, Alice, intends to use.
That's why the MessagingPreferences
object appears as a child object of Alice's data entry object,
which you created earlier in this article.
Using different object classes
As shown in Figure 22, the MessagingPreferences data entry object uses four
object classes: javaSerializedObject,
javaObject, javaContainer, and top.
Can you guess why the MessagingPreferences
object needs these four classes?
The MessagingPreferences data entry
object needs the javaSerializedObject class
because you are storing the serialized form of the MessagingPreferences object.
It needs the javaObject class because the
javaSerializedObject class extends the javaObject class. This means that whenever a data entry
object uses the javaSerializedObject class,
it is also using the javaObject class.
It needs the javaContainer class because
none of the other three object classes (javaSerializedObject, javaObject, and top) is
a structural class. Every data entry object in ApacheDS needs to use a
structural class. Your Java objects can use either javaContainer or any other structural class (such
as the person object class). LDAP wants you
to mix your Java object entries with structural classes (like javaContainer or the person object classes ), so the LDAP specification
has defined the javaSerializedObject class as
auxiliary.
Finally, the MessagingPreferences data
entry object needs the top class because all object classes
extend from the top class, as I previously explained.
Representing a marshalled Java object
Now look at Figure 23, which shows a marshalled Java object stored in ApacheDS:
Figure 23. A marshalled object stored in ApacheDS
You can compare Figure 23 with Figure 22
(which shows a serialized object on the JXplorer screen). The javaClassName attribute in Figure 23 shows that the
entry contains an instance of the java.rmi.MarshalledObject class. I use this
class in the second half of this article to demonstrate Java-object
marshalling.
Storing a reference of a Java object
Finally, LDAP also allows you to store a reference of a Java object in a directory instead of storing the actual object. In this case, you store the address of your Java object in ApacheDS. While de-referencing the address to fetch the instance of your object, you need a factory object. The factory object implements your de-referencing logic.
The primary advantage of storing a reference is to share the object among different users. For example, consider the MessagingPreferences class that I introduced earlier in the discussion accompanying Listing 1. If several users share common messaging preferences, you might find it beneficial to store one MessagingPreferences instance representing the common preferences and store its reference for each person using them.
RFC 2713 has an
object class named javaNamingReference (shown
in Figure 24) that extends the javaObject class and defines two new attribute
types, namely javaReferenceAddress and javaFactory. The javaReferenceAddress attribute type stores the
reference (or address) of the Java object and the javaFactory attribute type stores the name of the
factory object.
Figure 24. The javaNamingReference class
In this first half of my introduction to storing Java objects in ApacheDS, you have learned quite a bit about the pluggable protocol support of ApacheDS. You've also learned about core LDAP concepts and terminology, including distinguished names, object classes, attribute types, and LDAP syntax. Finally, you've learned how these LDAP concepts can be used to represent and store Java objects in ApacheDS.
In the second half of this article, you will put these concepts to the test. I include several sample Java applications along with lots of Java code to demonstrate how to store, search, and retrieve Java objects in ApacheDS. The sample applications implement various aspects of the data management scenario introduced here. Before concluding the second part of this article, I also wrap up the concepts in the form of a reusable Java class that you can use in your own applications. Go to Part 2 now.
| Description | Name | Size | Download method |
|---|---|---|---|
| Source code | j-apachedssource.zip | 40KB | HTTP |
Information about download methods
Learn
- "Introduction to LDAP, Part 1: Installation and simple Java LDAP Programming" (Fred
Simmons and Jeng Yoong Tan, developerWorks, April 2005): Introduces the concept of search filters in LDAP.
- Lightweight Directory Access Protocol, v3 (RFC 2251): Read the official LDAP specification.
- Schema for Representing
Java Objects in an LDAP Directory (RFC 2713): Defines the schema for representing Java objects in an LDAP directory.
- The Internet
Engineering Task Force hosts the complete RFC's of the
LDAP family of specifications, as follows:
- RFC 2256 details the user's schema for LDAPv3.
- RFC 2798 elaborates attribute syntax definitions for LDAP entries.
- RFC 2253 describes UTF-8 string representation for distinguished names in LDAP.
- RFC 2254 describes representation of search filters in LDAP.
- The RMI tutorial trail (Ann Wollrath and Jim Waldo, Java.sun.com): A step-by-step introduction to many aspects of RMI.
- The JNDI tutorial: A good place to get started with JNDI.
- Java Object
Serialization and RMI specifications: Get the information directly from the source.
- CS 696 Emerging Technologies: Distributed Objects (Course notes, San Diego State University, April 1998): A student's guide to serialization and marshalling.
- The Java technology zone: Hundreds of articles about every aspect of Java programming.
Get products and technologies
- Apache Directory Server: Download it from Apache.org.
- JXplorer:
The Java-based, open-source LDAP client used extensively in this
article.
- The Internet Assigned Numbers Authority: Get a free OID for your enterprise.
- Softerra LDAP Browser: A free LDAP browser.
Discuss
- Open Group forums: Discuss directory interoperability issues.
- developerWorks
blogs: Get involved in the developerWorks community.
Bilal Siddiqui is an electronics engineer, an XML consultant, and the co-founder of WaxSys, a company focused on simplifying e-business. After graduating in 1995 with a degree in electronics engineering from the University of Engineering and Technology, Lahore, he began designing software solutions for industrial control systems. Later, he turned to XML and used his experience programming in C++ to build Web- and Wap-based XML processing tools, server-side parsing solutions, and service applications. Bilal is a technology evangelist and a frequently-published technical author.
Comments (Undergoing maintenance)





