Using the Java Naming and Directory Interface (JNDI) (Part 2)

In my last post, I discussed directory servers and a quick example of how to query them. To read part one click here. JNDI can be used to store whole objects into a LDAP server. In this entry, a java object will be stored on the server directly.

First example uses a mechanism that Java has had since the beginning, serialization. I need to define a user class. The following class is from User.java:

public class User implements Serializable {

private static final long serialVersionUID = 3999866113934116781L;

private String name;

private String userid;

private String email;


public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public String getUserid() {

return userid;

}

public void setUserid(String userid) {

this.userid = userid;

}

public String getEmail() {

return email;

}

public void setEmail(String email) {

this.email = email;

}

}

It is just a number of setters and getters for a name, user id and email. It does implement java.io.Serializable to make it work for storage. Here is the class that uses User.java.

public class JavaObjectLookup {

static Hashtable<String, String> getEnv() {

Hashtable<String, String> env = new Hashtable<String, String>();

env.put(Context.INITIAL_CONTEXT_FACTORY, “com.sun.jndi.ldap.LdapCtxFactory”);

env.put(Context.PROVIDER_URL, “ldap://localhost:10389/ou=java,dc=example,dc=com”);

return env;

}

public static void main(String[] args) {

DirContext ctx = null;

try {

ctx = new InitialDirContext(getEnv());

// first bind an object to the Directory

User user = new User();

user.setName(“Joey”);

user.setUserid(“joey”);

user.setEmail(“joey@example.com”);


ctx.bind(“cn=joey”, user);


User u = (User)ctx.lookup(“cn=joey”);


System.out.println( “User’s email is “ + u.getEmail());

} catch (NamingException e) {

e.printStackTrace();

}

finally {

try {

ctx.close();

} catch (Exception e) {

e.printStackTrace();

}

}

}

}


Notice that the connection URL has been changed to “ou=java,dc=example,dc=com” so the object will be put into the java organizational unit. On the LDAP server, the entry looks like the following:

dn: cn=joey,ou=java,dc=example,dc=com

objectClass: javaSerializedObject

objectClass: javaObject

objectClass: javaContainer

objectClass: top

cn: joey

javaClassName: org.mathison.example.jndi.User

javaSerializedData:: rO0ABXNyAB5vcmcubWF0aGlzb24uZXhhbXBsZS5qbmRpLlVzZXI3gmE

J1ipHrQIAA0wABWVtYWlsdAASTGphdmEvbGFuZy9TdHJpbmc7TAAEbmFtZXEAfgABTAAGdXNlcm

lkcQB+AAF4cHQAEGpvZXlAZXhhbXBsZS5jb210AARKb2V5dAAEam9leQ==

javaClassNames: org.mathison.example.jndi.User

javaClassNames: java.lang.Object

javaClassNames: java.io.Serializable

The instance is stored as a base-64 encoded string. This is good for storing an instance that a lot of different java processes will access such as a printer driver. But what if a service wants to register its services on a LDAP server? It is no good to store a copy of a service on a directory server because a service is only useful if it can serve. It would be better if the entry just “referred” at the service rather being a copy of it. This is the rational for using javax.naming.Reference. To store a reference, a developer can have the class implement java.naming.Referenceable and call bind on the object or create a reference and bind the reference. On retrieving the reference, a developer can create an object from the information in the reference instance. If an object factory is used, the lookup returns an instance of your class. The following example has ReferUser that implements Referencable and uses an object factory.

Example code:

public class JavaObjectRefLookup {


static Hashtable<String, String> getEnv() {

Hashtable<String, String> env = new Hashtable<String, String>();


env.put(Context.INITIAL_CONTEXT_FACTORY, “com.sun.jndi.ldap.LdapCtxFactory”);

env.put(Context.PROVIDER_URL, “ldap://localhost:10389/ou=java,dc=example,dc=com”);


return env;

}

/**

* @param args

*/

public static void main(String[] args) {

DirContext ctx = null;

try {

ctx = new InitialDirContext(getEnv());


// first bind an object to the Directory

ReferUser user = new ReferUser();

user.setName(“Joey”);

user.setUserid(“joey”);

user.setEmail(“joey@example.com”);


ctx.rebind(“cn=joey”, user);


ReferUser u = (ReferUser)ctx.lookup(“cn=joey”);


System.out.println( “User’s email is “ + u.getEmail());

} catch (NamingException e) {

e.printStackTrace();

}

finally{

try {

ctx.close();

} catch (Exception e) {

e.printStackTrace();

}

}

}

}

import org.mathison.jndi.example2.User;

public class ReferUser extends User implements Referenceable {

public Reference getReference() throws NamingException {

Reference ref = new Reference(this.getClass().getName(),

ReferUserFactory.class.getName(), null);

ref.add(new StringRefAddr(“name”, getName()));

ref.add(new StringRefAddr(“mail”, getEmail()));

ref.add(new StringRefAddr(“uid”, getUserid()));

return ref;

}

}

import javax.naming.directory.Attributes;

import javax.naming.spi.DirObjectFactory;

public class ReferUserFactory implements DirObjectFactory {

@Override

public Object getObjectInstance(Object arg0, Name arg1, Context arg2, Hashtable arg3, Attributes arg4) throws Exception {

return getObjectInstance(arg0, arg1, arg2, arg3);

}

@Override

public Object getObjectInstance(Object arg0, Name arg1, Context arg2, Hashtable arg3) throws Exception {

ReferUser user = null;

if (arg0 instanceof Reference){

Reference ref = (Reference)arg0;

if(ref.getClassName().equals(ReferUser.class.getName())) {

RefAddr name = ref.get(“name”);

RefAddr uid = ref.get(“uid”);

RefAddr email = ref.get(“mail”);


user = new ReferUser();

user.setName(name.getContent().toString());

user.setEmail(email.getContent().toString());

user.setUserid(uid.getContent().toString());

}

}

return user;

}

}

Here is what you will find if you take a look at the Directory Server:

dn: cn=joey,ou=java,dc=example,dc=com

objectClass: javaContainer

objectClass: javaNamingReference

objectClass: javaObject

objectClass: top

cn: joey

javaClassName: org.mathison.example.jndi.ReferUser

javaFactory: org.mathison.example.jndi.ReferUserFactory

javaReferenceAddress: #0#name#Joey

javaReferenceAddress: #1#mail#joey@example.com

javaReferenceAddress: #2#uid#joey

Notice that the object’s attributes are now stored in javaReferenceAddress attributes. Also notice how each of these techniques used special java storage attributes to the job done. Well, the next part of this blog series will tackle creating a object without special java structures. All of this code can be downloaded from https://github.com/darylmathison/jndi-example via subversion or your browser.

Advertisement

1 thought on “Using the Java Naming and Directory Interface (JNDI) (Part 2)

Comments are closed.