Skip to main content

By clicking Submit, you agree to the developerWorks terms of use.

The first time you sign into developerWorks, a profile is created for you. Select information in your profile (name, country/region, and company) is displayed to the public and will accompany any content you post. You may update your IBM account at any time.

All information submitted is secure.

  • Close [x]

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerworks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

By clicking Submit, you agree to the developerWorks terms of use.

All information submitted is secure.

  • Close [x]

Storing Java objects in Apache Directory Server, Part 1

Inside the Apache Directory Server

Bilal Siddiqui (xml4java@yahoo.co.uk), Freelance consultant, WaxSys
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.

Summary:  This two-part article walks you through all the steps of storing Java™ objects in Apache Directory Server (ApacheDS). In this first half, author Bilal Siddiqui introduces you to ApacheDS and provides an overview of its core architecture. Because you primarily use ApacheDS as an LDAP server for storing Java objects, Bilal offers a quick overview of LDAP concepts and terminology. He also shows you how to use JXplorer to view LDAP schema components, such as attribute types and object classes, and how to enter a data object in ApacheDS. The article wraps up with an overview of Java object serialization and Remote Method Invocation as they apply to storing Java objects in ApacheDS, in preparation for the more hands-on approach in Part 2.

Date:  02 May 2006
Level:  Intermediate
Also available in:   Russian  Japanese

Activity:  17429 views
Comments:  

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.

ApacheDS implements JNDI

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.


Pluggable protocol support

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.

How MINA works

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's service framework

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.


Overview of LDAP

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.

An application to learn from

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
    } 

Data management with ApacheDS

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.

A note about terminology

You can also think about DN as a named context in the directory service. A user such as Alice's data entry is written at the named context defined by her DN. In fact, you'll often find that the terms DN and named context are used interchangeably. JNDI documentation typically talks in terms of named (or naming) contexts, and LDAP documentation uses the term DN. If you are working with both LDAP and JNDI, you can assume the terms have the same meaning.

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.

Getting started with ApacheDS

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.

Connecting to ApacheDS

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

Default data in 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.

A note about attribute types

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.


Object classes in ApacheDS

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

Defining an 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
DESCProvides 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).
MAYSpecifies 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.
MUSTSpecifies 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.
NAMESpecifies the name of the object class.
OIDSpecifies 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.
SUPSpecifies 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

Types of object classes

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.


Attribute types 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
EQUALITYSpecifies 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.
SUBSTRIs 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.


LDAP syntax in ApacheDS

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.


Entering data in 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 ou component 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 uid component provides a user identifier for the entry. Normally, you use this attribute to identify the users (for example, Alice) of ApacheDS.

  • The cn component 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).

Creating an RDN entry

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.

Using object classes

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

Applying attribute values

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!


Java serialization and RMI

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.

Serializing a Java object

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.

Custom serialization

If your application architecture doesn't allow your data members to be serializable (for example, one of the data members belongs to an existing non-serializable class), you need to implement your own customized serializing and deserializing logic in the Java class you want to serialize. Custom serialization is beyond the scope of this article; refer to the Resources section for more details on custom serialization.

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.

RMI

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 javaClassName holds 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 javaClassNames holds 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 the javaClassNames attribute type while searching for objects that have implemented a particular interface or objects extending a particular class.

  • The javaCodebase attribute 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 javaDoc attribute 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


Conclusion to Part 1

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.



Download

DescriptionNameSizeDownload method
Source codej-apachedssource.zip40KB HTTP

Information about download methods


Resources

Learn

Get products and technologies

Discuss

About the author

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.

Report abuse help

Report abuse

Thank you. This entry has been flagged for moderator attention.


Report abuse help

Report abuse

Report abuse submission failed. Please try again later.


developerWorks: Sign in


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Select information in your profile (name, country/region, and company) is displayed to the public and will accompany any content you post. You may update your IBM account at any time.

Choose your display name

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


Rate this article

Comments

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Java technology, Open source
ArticleID=109894
ArticleTitle=Storing Java objects in Apache Directory Server, Part 1
publish-date=05022006
author1-email=xml4java@yahoo.co.uk
author1-email-cc=