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: Wed, 25 Apr 2012 09:48:01 +0200

Nigel,

On 2012-04-24, at 18:12, Nigel Deakin wrote:
> I don't really follow what you are suggesting here.
>
>> Auto-create a destinations to hold messages before they are bound, so
>> the binding happens *after* the method runs and calls some send method.
>
> In my proposal B I'm not suggesting that anything is actually bound into JNDI. I'm proposing that a Queue or Topic
> administered object is created on-the-fly (by instantiating the class supplied with JMS) and injected into the application.
>
> If the JMS provider supports auto-creation of physical destinations, and the administrator has enabled this feature,
> then I would expect any such auto-creation to take place when the JMS API is first used to access the destination, such
> as when sending a message or it, or perhaps creating a producer or consumer on it. Not when the Queue or Topic is looked up or instantiated.

Agreed, but that auto-created destination would remain (except for that logical name) unconfigured until some admin does so. This is okay, when the same logical name is used by a consumer on the same JMS server. But when the messaging is used to store-and-forward to a different host, the routing has to be configured somewhere... not to mention all the other options that may have to be configured.

Developers would have to be very careful with the logical name, or different applications using, say, the name "order-queue" would start to receive orders from a different application domain! So it's not only a logical destination name, it's a logical destination address. Sender and receiver would have to agree on one address, and it would have to be (more or less) globally unique.

At least the tenant id would *have* to qualify the name. To communicate between tenants, a routing would have to be configured by some arbitration body... I assume digital signatures allow this to be done automatically; but there's still quite some way to standardize on that.

>> Throw an exception if the endpoint is not bound
>
> You mean that if the application or deployed descriptor specifies the JNDI name of a Queue or Topic object in JNDI but
> no such object has been bound in the location specified? This will cause an error now, and I'm not suggesting this
> should change.

I was thinking to get along without any JNDI whatsoever... the application just defines the endpoint, and the container injects whatever is necessary. In this alternative, when an application uses an endpoint before an administrator binds it to a physical destination, an exception is thrown.


>> If we are willing to go further down that road, another option would be to invert even more... I'm aware that this
>> would be a huge change to the already proposed simplified API and would require a lot of rethinking again. The code
>> could look like this:
>>
>> @JMSEndpoint @ConnectionFactory(...) public JMSDestination destination;
>>
>> public void sendMessage(String payload) { destination.send(payload); }
>>
>> The injection point would by default be identified by the application name, module name, bean name, and field name.
>> The last three could be overridden by annotation attributes.
>>
>> Deployment tools could scan the annotations and ask the deployer to create and bind the destinations required. This
>> also could be automated in a cloud environment by adding some destination deployment descriptor that include the
>> provider-specific destination address, destination type, queue length, etc. And to finish the round trip, these could
>> also be set by annotations like @DestinationAddress("hostname/appname"), @DestinationType(QUEUE),
>> @DestinationOption("queue-length", "1024").
>
> I'd need to ask lots of questions before I can give a sensible comment on this. Do you really want me to devote time to
> this?

I seriously think that we could proceed on this to make it a viable solution that could turn out to be superior to the current one. But it's a suggestion that would require a significant amount of work and time, which may not be available any more.


Returning to your suggestion:

> My proposal is that if the application specifies @Resource("name=logicalQueueName"), and there is no
> <message-destination-ref> element in the deployment descriptor that maps that name to a Queue or Topic object in JNDI, then the container should instantiate a Queue or Topic object, set it to refer to a queue or topic named
> "logicalQueueName" and inject it into the application. Currently this would cause a deployment error.

I understand that this would require a change to the @Resource injection mechanism and/or JNDI. The smallest change to other specs, yet most powerful approach that I can think of, would be to use CDI directly. Other properties describing the destination could be added as well, but they would have useful defaults. The code could look something like this:

@Inject
@DestinationType(TOPIC) // default: QUEUE
@DestinationAddress("provider-specific-destination-name") // default: unrouted
@QueueLength(1024) // default: provider-specific
public Destination logicalQueueName; // could be overridden with @Named

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

The annotations could be overridden, probably even by CDI Alternatives (I'm not CDI savvy enough to be sure), or some other deployment descriptor (i.e., an jms.xml).

To sum it all up: Having a fully fledged destination object instead of a simple string is only useful for auto-creation. If we don't standardize on auto-creation, let's stick with a simple string for the logical name. And using a logical destination name (String) that hasn't yet been created throws an exception. But if we actually do standardize auto-creation, it should be done -- cloud-enabled -- automatically at application startup, not semi-manually at deployment time.

The implementation of this CDI extension would be provider-specific, of course, as it has to use internal APIs to turn the annotations into actual physical queues.


Rüdiger