users@jms-spec.java.net

[jms-spec users] [jsr343-experts] Re: (JMS_SPEC-90) Provide simpler mechanism to refer to queues and topics in a portable way

From: Nigel Deakin <nigel.deakin_at_oracle.com>
Date: Fri, 20 Apr 2012 14:16:16 +0100

My earlier proposals for some new API to create Queue and Topic objects didn't gain much support from this EG. I've
thought about this more, discussed it with colleagues, and come up with a new proposal.

What am I trying to achieve here is to allow any application (including Java SE or Java EE applications, a Java EE
container, a resource adapter, and tools) to create a Queue or Topic object in a portable way without the need to obtain
a connection factory, connection or session first.

I did consider adding new API to connection factory, but this introduces a dependency on a vendor's JMS implementation
which is actually not necessary. JMS already defines a Queue or Topic object to be simply a wrapper around a
provider-specific queue or topic name, and I think we should keep it as that.

I also considered whether we should make the use of Queue and Topic objects unnecessary by adding new methods to JMS
which simply took a String name instead of a Queue and Topic. I decided this was undesirable for two reasons: it would
bloat the API with yet more methods, but more importantly because the concept of a Queue and Topic object remains a
useful one in JMS (and Java EE) because by allowing Queue and Topic objects to be bound in JNDI it allows application
code to be separated from queue and topic names.

Below are two separate proposals: a new feature in JMS, and a tentative proposal for Java EE which exploits this
feature. (We would need to discuss the latter in detail with the Java EE platform spec EG).

Please give your comments or questions on both (A) and (B).

A: JMS Proposal
---------------

I propose that JMS defines two classes: javax.jms.QueueImpl (which implements the javax.jms.Queue interface) and
javax.jms.TopicImpl (which implements the javax.jms.Topic interface). These are classes, whose implementation is
provided by JMS.

Here is what javax.jms.QueueImpl would look like:

public final class QueueImpl implements Queue {
    String queueName;
    public QueueImpl(String queueName) {
       this.queueName = queueName;
    }
    public String getQueueName() throws JMSException {
     return queueName;
    }
}

javax.jms.TopicImpl would be similar.

So an application could create a Queue by calling

    Queue queue = new QueueImpl("myQueue");

We would then define that any existing JMS API call which accepted a javax.jms.Destination must be able to accept a
QueueImpl or TopicImpl, any existing JMS API call which accepted a javax.jms.Queue must be able to accept a QueueImpl,
and any existing JMS API call which accepted a javax.jms.Topic must be able to accept a TopicImpl.

This would be very simple for vendors to implement, since they can simply use the existing createQueue/createTopic
methods on Session (which they already implement) to convert the queue or topic name to whatever provider-specific class
they currently use to implement Queue and Topic.

For example, the implementation of Session.createConsumer would need to be modified as follows:

Existing implementation:

    public MessageConsumer createConsumer(Destination destination) throws JMSException {
       return someProprietaryCodeToCreateConsumer(destination);
    }

New implementation:

    public MessageConsumer createConsumer(Destination destination) throws JMSException {
       if (destination instanceof QueueImpl){
          return someProprietaryCodeToCreateConsumer(createQueue(destination.getQueueName());
       } else if (destination instanceof TopicImpl){
          return someProprietaryCodeToCreateConsumer(createTopic(destination.getTopicName());
       } else {
          return someProprietaryCodeToCreateConsumer(destination);
       }
    }

Some minor details:

* We would need to define that it was valid to pass a QueueImpl or TopicImpl into Message.setJMSReplyTo, though
Message.getJMSReplyTo would be free to return a proprietary implementation.

* We would clarify that implementations of Session.createQueue/createTopic and Message.getJMSReployTo would be free to
return a proprietary implementation of Queue or Topic in all cases, or they could return a QueueImpl or TopicImpl.

B: Java EE Proposal
-------------------

The above change would make it possible to consider some new features for Java EE. This is because for the first time it
would be possible for a Java EE container to inject a Queue or Topic object without the need to use JMS provider code.

It is proposed that we define some default behaviour when injecting a Queue or Topic object into a Java EE application.

An application can currently inject a Queue object as follows:

@Resource(name="myQueueName")
Queue myQueue;

Java EE states that the name attribute is used to specify a "destination reference name". The application deployer is
responsible for creating a Queue object, binding it to some location of JNDI, and providing a <message-destination-ref>
element which maps the specified name to the JNDI name of the Queue object. If there is no such mapping, or if there is
no such JNDI object, a deployment error occurs.

We could propose that if the specified destination reference name is not mapped to a JNDI name then the container will
automatically instantiate a QueueImpl, using the specified destination reference name as the queue name, and inject it
into the application.

This would offer a much simpler way to configure destinations for applications, whilst leaving unchanged the ability of
a deployer to override this behaviour by defining a <message-destination-ref> element in the normal way.

Note that the Java EE 7 Early Draft already proposes a way for a container to inject a "platform default connection
factory". These two features together will significantly simply the use of JMS for smaller or less complex applications.

There are a few details related to this Java EE proposal that would need to be considered:

* We may want to define some similar default behaviour for MDBs.

* We would need to check whether there were any restrictions on valid characters in @Resource(name="..."), since this
would limit the queue or topic names that could be specified in this way.

* This wouldn't be possible the application injected a Destination rather than a Queue or Topic, since the container
wouldn't know whether to create a QueueImpl or a TopicImpl.

Nigel