©1994-2003 Kevin Boone
Home     Section index     K-Zone home Software development

Site search

Glossary
Confused by computer jargon? Look it up!

Shameless plug


Now available!

Articles
- Ten-minute guide to setting up a WAP site

- Talk like your boss: new developments in managerese

More...

Development
File handling in the Linux kernel

Java development for the Sony-Ericsson P800

SunONE Application Server 7 FAQ

More...

Linux
Using Linux with the Treo 600

- Linux on the Tecra M1

- Some notes on openzaurus

More...

Download
Java stuff

Linux stuff

More...

(Please read the download policy)

Home automation
The X10 system

Linux TW723 driver

More...

The K-Zone
K-Zone computing

K-Zone law

K-Zone education and science

K-Zone motorcycles

K-Zone DIY

K-Zone railways

K-Zone martial arts

About the author

K-Zone home page

 
Computing
Java on the P800
J2ME FAQ
Perl for Java programmers
Web Service tutorial
CLASSPATH
EJBs on jBoss
CMP with jBoss
Bean managed persistence
C++ tutorial
Simple Java
JDK setup
Howto-appletviewer
Howto-dosprompt
EJB lifecycles
EJB transactions
Inside the J2EE RI
S1AS7 FAQ
iAS 6.0 FAQ
Integrating JMQ with the iPlanet application server

 

Integrating JMQ with iPlanet Application Server

By Kevin Boone
Last updated September 2001.

Disclaimer

The author is a certified iPlanet instructor, but not a member of the iPlanet organization. I am no more privy to internal information about the iAS product than anyone else. Nothing in this document should be taken to constitute official policy of Sun Microsystems.

Scope

This document describes how to use the Sun/iPlanet messaging product JMQ with the iPlanet Application Server. It assumes that JMQ is already installed. For illustration we will use the JMS servlet example simplequeue, which is provided in the iAS code samples package. This example consists of a single servlet which puts a message in a queue and retrieves it itself.
     This article assumes that the reader is already basically familiar with JMS, messaging and the iPlanet Application Server.

Background

At present, a J2EE-compliant application server is required to provide an interface to a messaging service provider that can be used by applications. It is not required to provide the messaging infrastructure itself. Most products have procedures by which a commercial messaging product -- e.g., IBM MQ Series -- can be integrated into the application server.
     What form does this `integration' take? Well, the developer expects to be able to enter lines of code like this (from the simplequeue example):
QueueConnectionFactory qcf = 
  (QueueConnectionFactory) initialContext.lookup
    ("java:comp/env/jms/SampleFactory");
Queue queue = 
  (Queue) initialContext.lookup
    ("java:comp/env/jms/SampleQueue");
This leaves the application server with three problems:
  • 1. Translation of the `local' names java:comp/env/... into the `real' JNDI names of the queue and connection factory
  • 2. Supporting JNDI name lookups for JMS objects; that is, the lookup method should return an object that implements the appropriate part of the JMS API, and against which the developer can write code exactly the same as outside the application server environment
  • 3. Ideally the application server should be able to pool connections to the messaging provider; clients connecting with the same security credentials should be able to share physical connections.
Problem (1) is straightforward for an application server, as it will already have techniques for doing this for JDBC database connections, for example. Problem (2) is solved by storing references to the service provider's objects in the application server's directory, and making it available by JNDI. Problem (3) requires the use of proxies; that is, the object retrieved by the JNDI lookup is not simply a reference to something provided by the messaging service, but a proxy provided by the application server.
     In what follows we will look at the specific techniques used by the iPlanet Application Server, version 6.0SP2. We will use the Sun/iPlanet JMQ messaging product as the service provider.

Initial setup

iAS is not supplied with a messaging provider. In what follows we will describe how to define JMQ queues and connection factories and register them with iAS, but first the application server must be provided with some basic information about the messaging provider. Specifically the kjs CLASSPATH must be extended so that it can find the classes that will be returned as a result of JNDI lookup operations. For JMQ, the required classes are in the two JAR files jmq.jar and jmqadmin.jar. If you did a default installation of JMQ, these classes will be in /opt/SUNWjmq/lib. You could make the CLASSPATH changes manually, but iAS is provided with a script that does it:
[iasroot]/ias/jms/bin/jmssetup
This script prompts the operator for additions to the CLASSPATH. It also asks for additions to the LD_LIBRARY_PATH environment variable, so that it can find native-code libraries; JMQ does not require any, so this section can be ignored.
     You will need to restart iAS after making these changes.
     JMQ uses Java security policies files to dictate who can do what on the messaging system; for ordinary operations (posting and retrieving messages) these policies should not need to be changed. However, to add queues and topics using command-line tools, you may need to modify /opt/SUNWjmq/security/jmqadmin.policy. Adding this line will work:
grant { permission java.security.AllPermission; };

Name mapping

This section describes how iAS maps the `java:comp/env' name onto a real JNDI name. This should be familiar to developers who have used similar techniques for JDBC.
     As we have seen, the Java code in the servlet contains these instructions:
QueueConnectionFactory qcf =
  (QueueConnectionFactory) initialContext.lookup
    ("java:comp/env/jms/SampleFactory");
Queue queue =
  (Queue) initialContext.lookup
    ("java:comp/env/jms/SampleQueue");
These lookups do not correspond to real JNDI names, but to names local to the servlet (strictly, to the WAR module). `java:comp/env' is not part of the name, but an indication to the JNDI subsystem to make a local name lookup. The part of the string after `java:comp/env' is referred to as the coded name. When we create the deployment descriptor web.xml for the servlet we indicate the coded name and the type of resource to which it provides access. So we have:
 <resource-ref>
    <res-ref-name>jms/SampleQueue</res-ref-name>
    <res-type>javax.jms.Queue</res-type>
    <res-auth>Container</res-auth>
  </resource-ref>
  <resource-ref>
    <res-ref-name>jms/SampleFactory</res-ref-name>
    <res-type>javax.jms.QueueConnectionFactory</res-type>
    <res-auth>Container</res-auth>
  </resource-ref>
This XML indicates the coded name of the resource, the type of the resource, and who is to provide authentication information (container). It does not indicate the real name of the resource, nor the security credentials themselves. So, where does this information go? This is vendor-specific. With iAS, it goes into the iAS-specific deployment descriptor which, for a WAR file, is ias-web.xml. In that file we see the rest of the information:
 <resource-ref>
    <res-ref-name>jms/SampleFactory</res-ref-name>
    <jndi-name>jms/theFactory</jndi-name>
  </resource-ref>
  <resource-ref>
    <res-ref-name>jms/SampleQueue</res-ref-name>
    <jndi-name>jms/theQueue</jndi-name>
  </resource-ref>
That is, the local name java:comp/env/jms/SampleFactory maps onto the JNDI name jms/theFactory, while java:comp/env/jms/SampleQueue maps onto the JNDI name jms/theQueue.
     Although it isn't strictly necessary to know this, it can be helpful for debugging to understand that the JMS information from both web.xml and ias-web.xml end up in the same place in the iAS registry, under the J2EE-Module branch:
J2EE-Module
  jms-simplequeue 
    resource-ref
      jms/SampleFactory
        jndi-name=jms/theFactory
        res-auth=container
        res-type=javax.jms.QueueConnectionFactory
      jms/SampleQueue
        jndi-name=jms/theQueue
        res-auth=container
        res-type=javax.jms.Queue
This is all very well, but all we have done is translate one unknown name into another unknown name. What exactly are jms/theFactory and jms/theQueue? The answer is that theQueue is the JNDI name of a queue that will be registered with iAS, while theFactory is the JNDI name for a proxy that will stand for the real queue connection factory. This proxy will be created using an iAS utility called jmspadm, as described later; first we must create and register the queue and connection factory.

Creating the queue

In JMS a Queue object is really something that describes the logical properties of a message queue; it does not represent a connection to anything. Therefore there is no need to pool Queue objects or to provide proxies for them. What we must do, however, is create the queue definition within the messaging service itself, and assign it a JNDI name with iAS. We must do the same with the connection factory, although its JNDI name won't be used by applications (they will use its proxy).
     Creating the Queue is an operation on the messaging service provider; however, it is the application server that will need access to the created object. With Sun JMQ the approach taken is to ask the service provider to create the queue, and provide a JNDI context to which the service provider can add its own reference. JMQ provides a utility called jmqconfig for this; if you wanted to run this command at the prompt to create the queue for the SimpleQueue servlet, you would need to do something like this (but don't; there is a better way: see below):
/opt/SUNWjmq/bin/jmqconfig \
  -a \
  -t q \
  -n theQueue \ 
  -o name=SampleQueue \
  -i com.netscape.server.jms.RefFSContextFactory \
  -u /jms 
In this example, `-a' means `add the object'. `-t q' indicates that the object required is a Queue. `-n theQueue' indicates the JNDI name by which the queue will be referenced. `-o name=SampleQueue' sets the internal name of the queue (this is not a JNDI name, and won't be used by applications). `-i' indicates a JNDI naming context class. This is not provided by JMQ, but by iAS. JMQ will use this class to do a JNDI bind() operation to map the JNDI name onto the queue reference. This is how JMQ can add queues and other objects to the namespace of any application server, even one that it knows nothing about; the real work in this case is done by the RefFSContextFactory class, which is part of iAS. Finally, `-u /jms' sets the system property java.naming.provider.url before carrying out the JNDI bind(). This is so that the RefFSContextFactory class, which may not be specific to JMS lookups, knows where in the directory to insert the new name.
     The problem with running the jmqconfig command manually is that it requires an immense CLASSPATH, which would have to be set beforehand. Happily, iAS provides a script to run it with the correct classpath. This script is [iasroot]/ias/ias-samples/jms/docs/jmsjmqadm.sh. You may need to tweak this script before running it, as its references to the iAS installation directory won't be correct unless you installed the product with defaults. If you do this, then the same effect as the jmqconfig command above can be gained by doing:
jmsjmqadm.sh q theQueue SampleQueue
Please note that SampleQueue is the internal name of the queue, and need not be the same as the name used in the Java code, or as the JNDI name. However, theQueue is a name that will be used by the application; it corresponds to the resource reference that we put in ias-web.xml.
     Although not strictly necessary, it may be helpful to see how the queue creation operation is reflected in the iAS registry:
Application Server
  6.0
    JMSObjects
      theQueue
        ClassName=com.sun.messaging.Queue
        ...
        RA1=S#destName#SampleQueue
Note the `RA1' entry that provides the link to the internal (JMQ) name of the queue.

Creating the factory

The application will not use the connection factory directly, but it still has to exist. If you followed the discussion of creating a queue above, then creating the connection factory should present no additional problems:
jmsjmqadm.sh qf providerFactory SampleFactory
SampleFactory is the internal name of the object, and doesn't have to correspond to any name used in the application. providerFactory is a JNDI name, but this won't be used by applications either: they will use the proxy. After running this command, you will be able to see a new branch in the iAS registry in the same branch as the queue object created earlier. This new branch will be called providerFactory.

Proxy generation

iAS uses proxies for database connections as well as for messaging services, but the difference for the developer and administrator is that, for JMS, the proxy generation process is exposed. For JDBC, it is handled internally. In the previous step we created the connection factory, with JNDI name jms/providerFactory and JMQ interal name SampleFactory. Now we must create the iAS proxy for this object.
     To do this, we use the script jmspadm, which is provided in the directory [iasroot]/ias/jms/bin. The script requires the JNDI name of the factory, and the (new) JNDI name of the proxy. The name of the proxy must match the name of the reference in ias-web.xml, as this is what will get looked up when the servlet runs. So we need:
jmspadm theFactory providerFactory
This creates the following entries in the registry:
Application Server
  6.0
    JMSObjects
      theFactory
        ClassName=com.netscape.server.jms.QueueConnectionFactoryProxy
        ...
        RA0=S#connFactoryName#jms/providerFactory
        ...
Note that the class name is com.netscape..., not com.sun.messaging...; that is, the servlet will get a reference to a proxy provided by the application server, not a class that is part of Sun JMQ. Note also the reference to the real JNDI name of the JMQ object jms/providerFactory.

Summary

A large number of name mapping steps are involved between the servlet's JNDI lookup and the JMQ object itself. The diagram below summarizes these steps for the connection factory.
Servlet  java:comp/env/jms/SampleFactory (servlet's name for factory)


iAS      jms/theFactory (JNDI name of proxy for factory) 


iAS      jms/providerFactory (JNDI name of factory)
 

JMQ      SampleFactory (internal name of factory in JMQ)
The steps to instantiating, registering and creating proxies for a publish-subscribe messaging system (Topic and TopicConnectionFactory) are almost exactly the same as for queues.