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: Wed, 25 Apr 2012 12:20:05 +0100

Rüdiger,

Your comments are as always interesting and welcome...

On 25/04/2012 08:48, Rüdiger zu Dohna wrote:
> 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.

I don't follow what you mean. If a destination is automatically-created when used then by definition it doesn't need to
be configured by an administrator. (Though I want to stress that nothing I propose relies on JMS providers supporting
auto-creation of destinations).

> 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.

If the destination is on a different host, then the ConnectionFactory will define how to connect to the JMS server, and
the Destination (however it is created) will define what the name of the queue or topic is.

> 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.

But I'm not proposing anything different from the current behaviour: an existing application can either specify the
destination name explicitly (using createQueue) or they can specify a logical name (destination reference name) which
the deployer maps to the real destination. In both cases the destination is only completely specified when used in
conjunction with a connection factory. I'm not proposing to change this.

>
> 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.

Ah, I think you're using a different meaning of "bind" to me. Can you clarify how the administrator would "bind" an
"endpoint" (which seems to be another way of referring to the destination) to a physical destination?

Can you clarify what you mean by an "endpoint", as you seem to be introducing a new concept?

>
>
>>> 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.

I don't mind discussing this for a little longer.

>
> 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.

Yes, and we don't know yet whether the Java EE folks would approve of it.

> 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).

This looks like an alternative way of injecting Destination objects into the application, where @DestinationAddress is
used to specify the physical queue or topic name.

The problem I see with this is that it adds a completely new mechanism for injecting Destination objects, and a
completely new mechanism for allowing the deployer to configure or override the mapping to a physical queue or topic
name, that would be an alternative to the way currently defined in Java EE 6. I was trying to avoid doing that.

I concede that I've done that to some extent by allowing JMSContext objects to be injected directly, though they don't
change the administered object itself (it's still a ConnectionFactory) and it is my intention that the connection
factory can be specified both in terms of a JNDI name and a resource reference name that can be overridden in the
deployment descriptor.

You've also added an anotation @QueueLength(1024) which suggests that you're expecting the container to use this to
create the physical destination.

We could start defining annotations for creating a physical destination, but, for better or worse, Java EE 7 has got
there first and proposed a @JMSDestinationDefinition annotation for this purpose (see EE.5.17.5 of the Java EE 7 Early
Draft).

>
> To sum it all up: Having a fully fledged destination object instead of a simple string is only useful for
> auto-creation.

If you're referring to the existing Destination object, then I disagree. It's useful (in Java EE 6) because it's an
object you can bind into JNDI and use as a way to keep a physical destination name separate from the application. This
applies irrespective of how the physical destination itself is created.

A Destination object *is* really just a simple string, but one which also contains the destination type. My proposal
for a QueueImpl class are intended to recognise this.

> 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

Nigel