jsr343-experts@jms-spec.java.net

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

From: Rüdiger zu Dohna <ruediger.dohna_at_1und1.de>
Date: Sun, 22 Apr 2012 00:18:54 +0200

Since JMS 1.1, hardly any code has to care about the type of the Destination it sends messages to. My code generally looks something like this:

@Resource(mappedName = "myQueue")
private Destination destination;

public void sendMessage(String payload) {
    context.send(destination, payload);
}

I can also write code like this:

public void sendMessage(String payload) {
    Destination destination = context.createQueue("myQueue");
    context.send(destination, payload);
}

I would like to replace both options with code like this:

public void sendMessageNew(String payload) {
    context.send("myQueue", payload);
}

I'm very well aware that there is a huge difference between a JNDI name and the provider-specific destination name passed into createQueue/Topic and returned by Queue.getQueueName/Topic.getTopicName. But I don't care! This distinction gives me no benefit, it only makes my life harder.

I'm also aware that they have different name spaces: In the first example, the String is obviously unique within JNDI; in the second, it must be unique to the JMS provider and destination type (actually, you can regard the type to be part of the address); in the third, it would have to be unique to the JMS provider. But that's not really a problem, is it? We're talking about new methods, so there's not legacy code we have to consider.

The destination name that I put into my code should be purely business driven, i.e., it should not have to adhere to the JNDI naming conventions (i.e., prefixes), nor to the addressing scheme the JMS provider might use. It actually sort of identifies the logical endpoint of the sender, not the physical destination where the messages go to... so when a physical queue is created, this endpoint has to be bound to that queue... conventions may even allow to do this on demand... but creating physical destinations is a completely different topic.


Rüdiger

On 2012-04-20, at 17:21, Nigel Deakin wrote:

> John,
>
> Thanks for the quick response.
>
> The aim of this feature is to avoid the need to use vendor-specific code (such as a connection factory) to create a Queue or Topic object., given that it is really nothing more than a wrapper around a provider-specific queue or topic name.
>
> An alternative would be to use just String objects (as suggested by Rüdiger in his email "Why are Destinations resources and not Strings?") However, we still need to support the idea of administered objects, bound into JNDI, allow the deployer to configure or override the specific destination used by the application. Although it would be possible to bind String objects into JNDI instead of Queue or Topic objects these don't contain quite enough information as they don't specify the destination type. In any case, we're stuck with Queue and Topic as administered objects forever and I'd rather focus on making them easier to create and use.
>
> I gave some other reasons for not wanting a method on connection factory (e.g. assisting the development of generic JMS resource adapters) in a previous email on this his thread. But the proposal for B (allowing Queue or Topic objects to be generated automatically by the Java EE container) introduces a new reason, since since they require the container to be able to create Queue and Topic objects without using any provider-implemented code (and without knowing what JMS provider would be used).
>
> I agree that defining an implementation in an API definition is a bit unusual - though it wouldn't be the first such class in JMS.
>
> The QueueImpl/TopicImpl proposal is ultimately a way to achieve a portable javax.jms.Queue or javax.jms.Topic without breaking existing non-portable implementations of those interfaces. There might be other ways to achieve this, but I can't think of one as simple as this. Suggestions welcome.
>
> Nigel
>
> On 20/04/2012 14:46, John D. Ament wrote:
>>
>> Nigel,
>>
>> I'm not a fan of either approach (EE is maybe doable). Defining a standard implementation as a part of the JMS API seems awkward. You're forcing the implementers to write code in a fashion that is mandated by JMS.
>>
>> I'm not sure I follow why keying it off connection factory is poor, or even having a static method available in some class?
>>
>> John
>>
>> On Fri, Apr 20, 2012 at 9:16 AM, Nigel Deakin <nigel.deakin_at_oracle.com> wrote:
>> 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
>>
>>