users@jms-spec.java.net

[jms-spec users] Re: JMS_SPEC-116: Take advantage of EJB 3.2's RA improvement for MDBs

From: Nigel Deakin <nigel.deakin_at_oracle.com>
Date: Tue, 30 Jun 2015 17:23:36 +0100

On 17/06/2015 10:06, Rüdiger zu Dohna wrote:
> sorry for taking so long to reply... the proposal is a lot to consider and these are busy times... as always ;)

Many thanks. It's not too late to send in comments: this is a big feature and we need to get it right, and as
future-proof as possible. I also realise we're also getting into the vacation season (for me as well).

> • Issue I2: I agree with your colleague that the return type should be defined to be void. Anything else would be
> non-portable now and maybe could be specified in the future.

I think we're all agreed on this. When I update the proposals they will require the return type to be void.


> • Issue I3: "The EJB specification does not define a standard way to associate a MDB with a resource adapter.” Is
> this about different RAs existing in the container and associating an MDB with one of them? If so, it would be more
> clear to have the word ‘specific’ before ‘resource adapter’. I think this is a separate issue that could be discussed
> independently.

The use case I had in mind was when the application wanted to specify a particular resource adapter, either because the
application server used a different resource adapter by default or did not use a resource adapter at all.

I agree this is a separate issue, which exists in Java EE 7 currently. I've logged this as
https://java.net/jira/browse/JMS_SPEC-174 but since it's actually an EJB issue I'll take it up separately with the EJB
maintenance lead.

>
> • Issue I4: It would be _very_ helpful to have more than one callback method, e.g. to receive different types of
> messages. We would have to specify the selection algorithm, though. Annotations could be placed on the method _or_
> the class, with the usual logic that method level annotations overwrite class level annotations.

I agree in principle, but avoided it because of the extra complexity it would involve in specifying it. We already have
lots of issues to consider: this would gives us many more. I'm tempted to put this to one side and come back to it a bit
later in the development of JMS 2.1, purely for project management reasons, to allow us to focus on the basics. (We also
need to come back and look at batch delivery, which we deferred from JMS 2.0 because the API was getting too
complicated). I'd welcome more views on this.

The EJB spec currently assumes a MDB has only a single destination (e.g. <message-driven> has a sub-element
<message-destination-link>) though I suspect we can simply ignore that.

I can't see anything in the JCA spec that would prevent a MDB having multiple destinations (or multiple message selectors).

If a single MDB had multiple listener methods, each could have its own JMS consumer. That would be the simplest way to
define the "selection algorithm" semantics.

> And the RA can
> decide whether it needs different consumers for different methods (e.g. only when they have different destinations).

That's up to the RA now, so long as it conforms to the requirement that each MDB instance is called from one thread at a
time.

The RA calls MessageEndpointFactory#createEndpoint whenever it wants a new instance of the MDB object, and
MessageEndpoint#release when it has finished with it. MDB instances can be pooled by the either the RA or the EJB
container, or by both.

>
> • Issue I6: I don’t understand, why the RA cannot access the onMessage method to fetch annotations. This should be
> just some interface for the RA, shouldn’t it? And ignoring them may be confusing. I’d prefer if they either where an
> error, or be allowed. Maybe I should take a look at the RI code ;-)

I think this is an error on my part. I was confusing the special behaviour defined in EJB 3.2 section "Message-Driven
Bean with No-Methods Listener Interface" (which describes the class of the proxy returned by
MessageEndpointFactory#createEndpoint) with the general behaviour of MessageEndpointFactory#getEndpointClass().

On re-reading this, it's clear that the RA should be able to call MessageEndpointFactory#getEndpointClass() and use it
to discover any annotations on onMessage.

So yes, it should be possible for these annotations to be applied to the onMessage method of a MessageListener. I'll
update my next draft accordingly.

I haven't prototyped this, but will do so.

A few lines above this I discussed allowing MDB to have more than one callback method, perhaps as a later feature. When
we do this, should we also allow a MDB that implements javax.jms.MessageListener to also have additional callback
methods, or would this be confusing? For example, should we allow

  @MessageDriven
  public class MyMessageBean implements MessageListener, JMSMessageDrivenBean {

    @Override // required by MessageListener interface
    @JMSListener(lookup="java:global/Trades1", type=JMSListener.Type.QUEUE)
    public void onMessage(TextMessage tradeMessage){
      ...
    }

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

  }


>
> • Issue I11: The destination name is generally simpler than the JNDI name. It can be used to specify the destination
> on a more abstract, business-oriented level, e.g. ‘trades’. So, objecting to your colleague, I think it would be
> desirable to use that, yes... portable or not.

Specifying a destination by anything other than JNDI name is a can of worms which I would like to keep separate from
this work. You will remember we discussed this in JMS 2.0 but got rather bogged down.

As things stand, destination name is not considered portable (in at least one JMS provider it includes deployment
information such as the name of the JMS server). The javadocs for Session#createQueue state that this is a
"provider-specific queue name" and states that "Portable applications are recommended to not use this method but instead
look up an administratively-defined Queue object using JNDI." Because of this, there are no CTS tests for this method.

If we can't think of anything better we could allow the existing queue and topic name to be specified, but I would
rather we define a new, portable, non-JNDI name and use that instead.

>
> • Issue I13: We can assume that the destination already exits in the container. The RA then can simply look it up to
> see if it’s a queue or a topic. Then it would even be possible to swap one for the other without changing the
> application. The queue topology shouldn’t be relevant for an application, should it? This is why I prefer
> @JMSListener to @JMSQueue/TopicListener.

The RA does not have any way to discover whether a Destination object is a Queue or Topic. You can't rely on using
"instanceof": in a well-known JMS provider (oh, alright, I mean Weblogic), queue or topic objects implement both
javax.jms.Queue and javax.jms.Topic at the same time. Which appears to me to be perfectly legal.

However we could certainly add a method Destination#getType if we wanted to.

I disagree that a MDB could be swapped from a queue to a topic without changing the application. For a start, you might
need to specify the subscription name and clientID. But more importantly, I think that the semantics for the two are so
different that this would rarely make any sense except for trivial applications.

>
> • Specify the connection factory: I think it’s worth to note that there is a default connection factory, so this
> annotation is optional.

Good point.

>
> • Issue I14: I think it would be more consistent to have separate annotations even here.

So I think you're endorsing my proposal which uses separate annotations for SubscriptionDurability, SubscriptionName and
ClientId

>
> • Parameters for message body: It should be an error to have more than one method parameter for the message body,
> i.e. the container should report and fail to load an application with MDBs that has methods with more than one
> parameter without a @MessageHeader or @MessageProperty annotation. Annotation processors could mark this error even
> in the IDE.

Possibly, though a callback method which had multiple method parameters of different types could be used to receive JMS
messages of different types.

I think it depends on how we handle mis-matched message bodies (for example if the callback method has a parameter of
type byte[], but the message is a ObjectMessage). Currently I am proposing simply setting it to null, but I am far from
sure that this is the right thing to do. I'd be interested to hear what you think about that.

If we decide that a mis-matched message body needs to be treated as an error then it follows naturally that having more
than one method parameter for the message body should be treated as an error, at least if they were of different type.

>
> • Message properties: Should we make the value of the @MessageProperty annotation optional in Java 8?

I think you mean that if the @MessageProperty annotation is omitted, the property name is inferred from the variable name.

> Even though the
> default is not to include the parameter names in the class file (which I consider a bad decision, as it reduces
> adoption, which already has effectively killed the assert keyword), it can really reduce repetition of the name.

I like this in principle, though how would we then distinguish between a parameter which we want to contain the message
body, and a parameter which we want to contain a message property?

I'm also worried that we could be making such a MDB dependent on being compiled with the special option to include the
parameter names in the class file. In the real world it would mean that every MDB would end up being compiled with this
option, to avoid the possibility of a runtime error. Do we really want to inflict this on users?

>
> • Issue I16: I also agree with you colleague that we should consider to finally specify DLQs. They are one of the
> fundamental messaging patterns, and official support is overdue. Routing messages that can’t be converted are just
> one use case; they also should be usable for messages that can’t be delivered due to technical as well as application
> problems in the consumer.

As I mentioned, I think how we handle conversion errors is the biggest issue I am unsure about.

Does anyone know how Spring handles conversion errors? I can't see any mention of this in the docs.

>
> • Question 1: Will it be possible to use @Stereotypes for all the annotations?

This is javax.enterprise.inject.Stereotype, which is part of Java EE 7.

I didn't propose it, but it sounds a good idea, if there aren't any technical obstacles. I'd like to ask David Blevins
about that...

>
> • Question 2: If the container sets method parameters to message headers and message parameters, wouldn’t it be
> useful to have it also set method parameters to message fields of a MapMessage?

I left this out for simplicity, but agree it might be nice, so long as we can define it neatly and simply. This is the
kind of thing we could easily add in a later iteration of this feature.

Nigel