users@jms-spec.java.net

[jms-spec users] Re: Issue I18: Legacy MessageListener and @JMSListener compatibility

From: Nigel Deakin <nigel.deakin_at_oracle.com>
Date: Wed, 05 Aug 2015 11:38:23 +0100

David (and everyone else),

On 05/08/2015 04:54, David Blevins wrote:
> Pretty clear I'm never going to have time to address the entire manifesto of discussion points in one shot. Here's
> me attempting to address them one at a time as time permits. I see little feedback in general, so hopefully smaller
> chunks of digestible bits is easier for others as well. I hope I can give at least more consistent feedback in
> chunks.

Sending comments on individual issues is just fine!

I appreciate there's a lot here. Is there anything more I can do to help people understand these proposals and get
involved?

> Now on point...

More below...

>
> This may be the wrong time to come to decision, but I'm looking through the API and options and wondering if it is a
> good idea to mix the legacy MDB API and new annotation approach.
>
> The specific concern is the duplication and potential for conflict between the activation config and the annotations
> themselves.
>
> - Conflict: What to do if they disagree on destination name or destination type?
>
> - Precedence: If we set defaults in the annotation a user applies to onMessage and there is an explicit value in the
> activation config, which wins?
>
> I realize of course, this possibility exists for the new MDB API regardless as the ActivationConfigProperty[] bucket
> of the @MessageDriven annotation still exists and the user might fill it in creating the potential for conflict even
> though MessageListener is not implemented.
>
> Seems we have just a few choices:
>
> 1. Use of Annotations and ActivationConfig are either/or
>
> a. only JMSMessageDrivenBean can use the annotation approach
>
> b. either JMSMessageDrivenBean or MessageListener can use the annotations as long as it is done without
> ActivationConfig use
>
> 2. Define a clear rule for mixed use. This rule could be:
>
> a. Annotations, including annotation defaults, always win
>
> b. Activation Config Properties always win (we'd never do that, but presented for completeness)
>
> c. Deployment error on conflict
>
> If you had asked me 4 years ago which was my preference, I might have said 2.a.
>
> However, now as an employer I question the cost involved in writing TCK tests to cover the mixed cases for something
> like 2.a especially considering it is effectively a stop-gap. The benefit will be short-term, however the weight on
> compliance and the TCK will be long-term.
>
> What thoughts do others have?
>

This is a good summary of the options here.

My current proposal (and I should stress this is just a proposal, definitely open for debate) is that we do allow users
to mix both activation properties and the new JMS 2.1 method annotations in the same MDB, and that if the *same
property* is defined in both ways, then the value defined in the activation property "wins"

This looks like 2b in your list above, which you describe as "we'd never do that". That's interesting. Let me explain
why I suggested this.

To keep things as simple as possible, at least at this stage in discussions, there is a direct correspondence between
the proposed new JMS 2.1 method annotations and the existing JMS activation properties defined in EJB 3.2.

@JMSListener corresponds to destinationLookup and destinationType
@JMSConnectionFactory corresponds to clientId
@SubscriptionDurability corresponds to subscriptionDurability
@ClientId corresponds to clientId
@SubscriptionName corresponds to subscriptionName
@MessageSelector corresponds to messageSelector
@Acknowledge corresponds to acknowledgeMode

So this override rule would apply only to these eight properties (since these are the only ones you can define using the
new annotations).

There are only eight properties here, so I didn't think this would be too onerous to define and test. There's a wider
issue of whether non-standard properties could be used to override JMS annotations, but that's undefined with MDBs now
and I wasn't trying to address it.

So, why did I propose that activation properties should "win"? For two reasons.

1. The main reason was that it provides a way for the deployer to configure the XML deployment descriptor to override
values set in the Java code. So the developer could write:

    @JMSListener(lookup="java:global/Trades", type=JMSListener.Type.QUEUE)
    public void processTrade(TextMessage tradeMessage){
      ...
    }

and the deployer could configure ejb-jar.xml to override the destination specified:

<message-driven>
    ...
     <activation-config>
         <activation-config-property>
             <activation-config-property-name>
                 destinationLookup
             </activation-config-property-name>
             <activation-config-property-value>
                 java:global/Orders
             </activation-config-property-value>
         </activation-config-property>
         ...

You can do this now with MDBs: you can specify an activation property in the Java code using annotations
(@ActivationConfigProperty etc) and override it in ejb-jar.xml.

I've been told that this is a useful facility, but we could decide it isn't. That would definitely simplify things.

An alternative way to offer an override facility would be to define some new JMS-specific XML elements corresponding to
the new JMS-specific annotations. I mentioned this as issue I8.

What do others think on this? Is there a need to allow deployers to override the code using the deployment descriptor,
or is this an unwanted EJB legacy feature which we can abandon?

2. The other reason I suggested allowing activation properties to be used was because it offers a way of passing
arbitrary vendor-specific properties in addition to the standard ones. However we do have the option of defining other
ways of achieving this, such as by defining a generic annotation something like:

    @JMSListenerProperty(name="foo1", value="bar1") // uses Java 8 repeatable annotations
    @JMSListenerProperty(name="foo2", value="bar2")
    @JMSListener(lookup="java:global/Trades", type=JMSListener.Type.QUEUE)
    public void processTrade(TextMessage tradeMessage){
      ...
    }

I don't mention that in the proposals, so I'll it as an issue.

As David says, what do others think?

Nigel