Java Naming and Directory Interface: Lesson 1

1. NAMING CONCEPTS

Naming is a fundamental concept used in almost every system of the world. Our computing systems are not exceptions. It allows us to associate (called binding) names with objects and to find (called lookup) those objects later by their names. Names are some people-friendly identifiers. An object in the naming system is a nameable/referenceable entity such as an object in a program, an IP address, a file etc. A naming service maps these names to objects. The examples of such naming systems are Domain Name System (DNS), File system, Java’s rmiregistry, Java IDL’s tnameserv and orbd etc. The DNS is a naming system since it maps host names to IP addresses.

www.google.com-74.124.24.104

A file system is also a naming system since it maps a file name to some h/w specific address.

D:\progs\test.java -sector, track and cylinder number

A naming server typically provides services such as binding, unbinding, and looking up objects by their names. It is also important to note that all name servers do not function in the same way. However, in order to be a naming service, it must at the very least support the facility to bind objects with names and to look up objects by name.

Apart from functional differences, the visible difference is the way each naming service requires names to be specified—its naming convention.

1.1. Naming Convention

A name is formed by one or more name components. The syntax of names, also called naming convention, is specified by the naming system.

For example, in the DNS, a name (e.g. www.googie.com) is an ordered sequence of name components (www, google and com) separated by dots (‘.’). Here, google is a subdomain under com domain (written as googie.com) and www is a name under googie.com.

A file name in windows (say D:\progs\test.java), on the other hand, starts with a drive name (d: ) and uses \ (back slash) as the name component separator.

Unix like OS uses / (forwards slash) in the file path names.

A name (e.g. ou=it,o=ju,c=in) in LDAP (Lightweight Directory Access Protocol) compliant server is a comma (,) separated ordered sequence of name components, each of which is a name and value pair separated by equality sign (=). This refers to the organizational unit (ou) IT under organization (o) JU (for Jadavpur University ) in the country (c) IN (for India).

1.2. Naming Context

A naming context [Figure 24.1:] is a collection of zero or more name-to-object bindings. For example, a directory in a file system, that contains a set of (file name, file) bindings, is a context. A subcontext is child context of a parent context. For example, a sub directory is a subcontext. A subcontext like its parent can also contain a list of bindings. Contexts and their subcontexts together form a general tree. The root of the context tree is referred to as initial context or root context.

Each context is identified by a name unique within its parent context. The fully qualified name of a context starts from the root context and ends with its own name.

Note that not all naming servers allow creating subcontexts. For example, Java’s rmiregistry does not permit to create sub contexts.

1.3. Binding

The process of associating a name to an object is called binding. For example, a DNS name is bound to an IP address; a file name is bound to a file and so on.

Many naming systems don’t store objects directly. Instead, they store references to objects. For example, in DNS, the address 207.69.175.36 is a reference to a computer’s location on the Internet, not the computer itself.

2. DIRECTORY CONCEPTS

A directory service extends the idea of naming service. In addition to associating names with objects, a directory service allows objects to have attributes. Directory service also allows to perform attribute-related operations such as reading, modifying, removing attributes, searching object based- on attributes etc.

For example, an organization will not only have a name, but it will have a (mandatory and optional) set of attributes such as its postal code, street address, telephone number, web link etc. Objects stored in a directory server are called directory objects. Virtually, any entity may be represented as a directory object. Attributes describe the entity the directory object represents. An attribute has a name (called identifier) and one or more values. For example, postalCode attribute of an organization has only one value, but telephone number can have many values.

Examples of directory servers include, Novell Directory Service (NDS), Network Information Service (NIS) etc. There are also general directory services that use standard protocols such as X.500 and Lightweight Directory Access Protocol (LDAP).

As mentioned earlier, we can search objects based on their attributes. In that case, we supply query, called search filter, consisting of a logical expression in which we specify the attributes that the object or objects must have. This type of searching is known as content based searching or reverse lookup. For example, we can search all educational institutions situated in Kolkata.

2.1. Directory Context

Note that in a name tree, objects can only be bound under a context, not under another object. However, unlike name tree, every node in a directory tree is a context. Consequently, objects can be bound under other objects as well. A directory server, does not distinguish an object and context.

3. JAVA NAMING AND DIRECTORY INTERFACE

The Java Naming and Directory Interface (JNDI) allows Java application to use naming and directory. It is not an implementation; rather an interface which has been defined to be independent of any specific service implementation. That’s the way, it works virtually for all implementation seamlessly. However, it also provides implementations for three common name service, LDAP, RMI’s rmiregistry and CORBA’s COS (Common Object Services ) name service.

The JNDI architecture [Figure 24.2:] consists of an Application Programming Interface (API) and a Service Provider Interface (SPI). The SPI helps to plug-in various service providers, whereas API allows applications to use them. The API has two parts: one used to access naming service and the other is used for directory service.

4. AN EXAMPLE

In this section, we shall show how to write a simple Java application using JNDI. We shall rewrite our calculator RMI application that will use JNDI. The rmiregistry will be used as the name server. If you have JDK installed, you also have rmiregistry installed. So, you don’t have to look for another name server. Since it is an RMI application, the server side includes an interface (Caicuiator.java) and an implementation (simpieCaicuiator.java) as follows:

//Calculator.java

import java.rmi.*;

public interface Calculator extends Remote {

public int add(int a, int b) throws RemoteException;

}

//SimpleCalculator.java

public class SimpleCalculator implements Calculator {

public int add(int a, int b) {

return a + b;

}

}

4.1. Writing the Server

To use JNDI interfaces and classes, it imports the naming package:

import javax.naming.*;

The server, as usual, creates an instance of servant and obtains a stub as follows:

SimpleCalculator cal = new SimpleCalculator();

Calculator stub = (Calculator)UnicastRemoteObject.exportObject(cal,0);

The next task of the server is to upload this stub to a name server. To work with naming service, we must have a reference to a context in the name tree. The simplest way to create such an object is as follows:

Context ctx = new InitiaiContext();

This ctx basically refers to a node (context) in the name tree [see Figure 24.1:] maintained by a name server. To work with that name tree, we simply refer to this ctx object which, on behalf of us, communicates with the name server. So, this Context object behaves like a proxy. The constructor of the InitiaiContext class does not actually create a Context object; instead it looks for a provider specific factory class that can manufacture such a proxy instance. However, we have not yet provided any information (such as port number, IP address) about the name server; nor have we specified the factory class.

There are different ways to specify the required information. In our example, we shall provide them as command line arguments. Anyway, the server can add a binding using bind() method as follows:

ctx.bind(args[0], stub);

This essentially binds the object s tub to the context ctx with a name specified as the first command line argument. The complete source code (CaicuiatorServerJNDI.java) is shown below:

//CalculatorServerJNDI

import java.rmi.server.*;

import javax.naming.*;

public class CalculatorServerJNDI {

public static void main(String args[]) {

try {

SimpleCalculator cal = new SimpleCalculator();

Calculator stub = (Calculator)UnicastRemoteObject.exportObject(cal,0);

Context ctx = new InitialContext();

ctx.bind(args[0], stub);

System.out.println(“Calculator server ready…”);

}catch (Exception e) { e.printStackTrace(); }

}

}

The relevant modification is shown with bold face.

4.2. Writing the Client

A client, like server, also creates a Context object as follows:

Context ctx = new InitialContext();

It then looks up the object supplying the name in the command line using iookup() method:

Calculator cal = (Calculator)ctx.lookup(args[0]);

Since, the type of the object we bound earlier was a Calculator type, we can cast the result of lookup() to its target class. The complete source code (CalculatorClientJNDI.java) is shown below:

//CalculatorClientJNDI.java import javax.naming.*;

public class CalculatorClientJNDI {

public static void main(String args[]) {

try {

Context ctx = new InitialContext();

Calculator cal = (Calculator)ctx.lookup(args[0]);

int x = 4, y = 3;

int result = cal.add(x,y);

System.out.println(”Sent: ” + x +” and ”+y);

System.out.print(”Received(”+x+”+”+y+”=): ” + result);

}catch (Exception e) { e.printStackTrace(); }

}

}

The relevant modification is shown with bold face.

4.3. Running Application

Place server related files (Calculator.java, SimpleCalculator.java and CalculatorServerJNDI. java) in a directory, say E:\ajp\jndi\rmi\server. Compile all the classes normally. Open a terminal, go to this directory and use the following command to start rmiregistry on port 6789

start rmiregistry 6789

To start the server, we have to specify the values of two primary properties java.naming.factory. initial and java.naming.provider.url. The former one specifies the fully qualified name of the factory class, to be used to create a Context object, to communicate with the name server. The latter holds location information (port, IP address etc.) of the JNDI provider. The InitialContext’s constructor uses this information to create a Context object and to connect to the naming server. For rmiregistry running on port 67 8 9 in host 172.16.5.81, the values of these properties are com. sun.jndi.rmi.registry.RegistryContextFactory and rmi://172.16.5.81:6789 respectively. For other name servers, the values of these two properties can be found in Table 24.1: Note that by only changing these two values, we can talk to any name server. Use the following command to start the server:

java –

Djava.naming.factory.initial=com.sun.jndi.rmi.registry.RegistryContextFactory –

Djava.naming.provider.url=rmi://172.16.5.81:6789 CalculatorServerJNDI

calculator

If everything goes fine, the following message appears:

Calculator server ready…

Now, place client related files (Caicuiator.java, and CaicuiatorClientJNDl.java) in a directory, say E:\ajp\jndi\rmi\ciient, probably in a different host. Compile all the classes normally. Open a terminal, go to this directory and use the following command to start the client:

java –

Djava.naming.factory.initial=com.sun.jndi.rmi.registry.RegistryContextFactory- Djava.naming.provider.url=rmi://172.16.5.81:6789 CalculatorClientJNDI

calculator

If everything goes fine, the following message appears:

Sent: 4 and 3

Received(4+3=): 7

Source: Uttam Kumar Roy (2015), Advanced Java programming, Oxford University Press.

Leave a Reply

Your email address will not be published. Required fields are marked *