Java Message Service: Using JNDI

JMS has not defined any address syntax by which clients communicate with the broker. Instead, JMS utilizes Java Naming & Directory Interface (JNDI), that provides the following advantages:

  • Hides provider-specific details from JMS clients.
  • Abstracts JMS configuration information into Java objects that are easily administrated and organized from a common management console.
  • Since, there exists JNDI providers for all popular naming services, JMS providers can provide single implementation of administered objects that will run everywhere, thereby eliminating complicated deployment and configuration issues.

Using JNDI, administered objects are created and configured by the MQ administrator and placed on a publicly accessible naming service. These objects can then be used by JMS clients using JNDI interface. This makes client code provider independent and becomes portable from one JMS provider to another. The client can also avoid complicated task for creating and configuring administered objects.

However, for testing purpose or in the early stages of the application, it is more convenient to insert a few lines of code in the client program to connect to the JMS provider directly, instead of using a long procedure needed by JNDI. In the previous sections, we have seen how a client can connect to the JMD provider directly. In this section, we shall discuss the same using JNDI.

So, a client, instead of creating administered object itself, can also look up predefined administered objects such as ConnectionFactory and Destination using the Java Naming and Directory Interface (JNDI). In this case, the administered objects are created and configured by the MQ administrator and placed in a naming service such as file system, LDAP, rmiregistry etc.

It is expected that JMS providers will provide the tools an administrator needs to create and configure administered objects in a JNDI namespace. Accordingly, MQ provides a utility imqadmin for this purpose. A Java program may also be written to create such administered objects. The following is a sample example that uses JNDI:

import javax.naming.*;

import javax.jms.*;

//import com.sun.messaging.*;

public class CreateAO {

public static void main(String[] args) {

try {

Context ctx = new InitialContext();

ConnectionFactory cf = new com.sun.messaging.ConnectionFactory();

((com.sun.messaging.ConnectionFactory)cf).setProperty(com.sun.messaging.

ConnectionConfiguration.imqAddressList,”172.16.4.248:7676”);

ctx.rebind(args[0], cf);

ctx.rebind(args[1], new com.sun.messaging.Queue());

ctx.rebind(args[2], new com.sun.messaging.Topic());

System.out.println(”Created and registered three administered objects”);

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

}

}

This creates ConnectionFactory a Queue and a Topic objects and binds them to a naming server with names specified as command lines arguments. The ConnectionFactory factory object encapsulates the information of a broker running in a host 172.16.4.248 on port 7676 and hence, when used later, is capable of establishing connection with this broker. If your broker runs on a different host, use it in the setProperty() method. Note that this program configures administered objects minimally. For other sophisticated configurations such as performance tuning, use imqadmin utility that provides a GUI instead. Compile the program as follows:

javac -cp imq.jar CreateAO.java

Note that the above program is capable of binding administered objects to any naming service, provided that information of the name server is provided as JNDI command line arguments. For example, to register these objects to the (local) file system naming service with base fiie:///D:/openmq4_5_2/adminObjects , use the following command:

java -cp imq.jar;fscontext.jar;. –

Djava.naming.factory.initial=com.sun.jndi.fscontext.RefFSContextFactory – Djava.naming.provider.url=file:///D:/openmq4_5_2/adminObjects CreateAO ACF

AQueue ATopic

The names of the connection factory, queue and topic are specified as ACF, AQueue and ATopic Respectively. This essentially creates a file .bindings that contains necessary information to establish a connection to the broker running in 172.16.4.248 on port 7676 in the directory file:///D:/openmq4_5_2/adminObjects.

Similarly, to register them to the rmiregistry on port 6789, use the following command:

java -cp imq.jar;. –

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

Djava.naming.provider.url=rmi://localhost:6789 CreateAO ACF

AQueue ATopic

Start rmiregistery as follows:

rmiregistry 6789

Note that rmiregistry must be started in the local machine, as it does not allow us to register objects created in a different machine. This problem may be avoided using an LDAP naming service. We started Apache Directory Server in a machine 172.16.4.248 on port 10389. The administered object can be registered to this LDAP server from any remote computer as follows:

java -cp imq.jar;. –

Djava.naming.factory.initial=com.sun.jndi.ldap.LdapCtxFactory –

Djava.naming.provider.url=ldap://172.16.4.248:10389/dc=example,dc=com CreateAO

cn=ACF cn=AQueue cn=ATopic

Apache directory sever has two default partitions dc=example,dc=com and ou=system. We used the former one. A client can then get a reference to ConnectionFactory and Destination objects, using JNDI as follows:

Context ctx = new InitialContext();

ConnectionFactory cf = (ConnectionFactory) ctx.lookup(args[0]);

Destination dest = (Destination)ctx.lookup(args[1]);

The complete source code (ProducerJNDI.java) of the producer that used JNDI is shown below:

import javax.jms.*; import javax.naming.*; public class ProducerJNDI {

public static void main(String[] args) {

try {

Context ctx = new InitialContext();

ConnectionFactory cf = (ConnectionFactory) ctx.lookup(args[0]);

Destination dest = (Destination)ctx.lookup(args[1]);

Connection con = cf.createConnection();

Session sn = con.createSession(false, Session.AUTO_ACKNOWLEDGE);

MessageProducer mp = sn.createProducer(dest);

TextMessage tm = sn.createTextMessage();

tm.setText(”A test message”);

mp.send(tm);

System.out.println(”Message sent:”);

sn.close();

con.close();

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

}

}

}

Compile this program using the following:

javac -cp jms.jar ProducerJNDI.java

Note that this program does not use any provider specific code and hence is capable of working with any JMS provider, provided that JNDI parameters are passed to this program as follows:

java -cp jms.jar;imq.jar;fscontext.jar;. –

Djava.naming.factory.initial=com.sun.jndi.fscontext.RefFSContextFactory –

Djava.naming.provider.url=file:///D:/openmq4_5_2/adminObjects ProducerJNDI ACF AQueue

For file system naming service, a JAR file fscontext.jar that contains necessary classes for file system JNDI is needed. This file can be found in <MQ_TOP>/iib directory. Make also sure that the MQ broker is running on a machine, 172.16.4.248 on port 7676 since the ConnectionFactory corresponds to such a broker. For rmiregistry naming service running on a computer 172.16.5.1 on port 6789, use the following command:

java -cp jms.jar;imq.jar;. –

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

Djava.naming.provider.url=rmi://172.16.5.81:6789 ProducerJNDI ACF AQueue

For LDAP service, use the following command:

java -cp jms.jar;imq.jar;. –

Djava.naming.factory.initial=com.sun.jndi.ldap.LdapCtxFactory – Djava.naming.provider.url=ldap://172.16.4.248:10389/dc=example,dc=com

ProducerJNDI cn=ACFcn=AQueue

The JNDI properties may be specified directly in the program. For file system, it looks like this:

java.util.Hashtable env = new java.util.Hashtable();

env.put(Context.INITIAL_CONTEXT_FACTORY,

“com.sun.jndi.fscontext.RefFSContextFactory”);

env.put(Context.PROVIDER_URL, “file:///D:/openmq4_5_2/adminObjects”);

Context ctx = new InitialContext(env);

And run the program simply as follows:

java -cp imq.jar;fscontext.jar;. ProducerJNDI ACF AQueue

Note that for a file system JNDI, the file system must be local to the JMS client. If it is created by the MQ administrator in a different computer, transfer the .bindings file to the JMS client’s machine and put it in any directory say D:/openmq4_5_2/remoteObjects and specify the directory in the Djava.naming.provider.url property as follows:

env.put(Context.PROVIDER_URL, “file:///D:/openmq4_5_2/remoteObjects”);.

Or as a command line argument as

-Djava.naming.provider.url=file:///D:/openmq4_5_2/remoteObjects

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 *