users@jms-spec.java.net

[jms-spec users] Re: JMS_SPEC-134: Declarative Annotation Based JMS Listeners

From: Nigel Deakin <nigel.deakin_at_oracle.com>
Date: Fri, 28 Aug 2015 11:41:32 +0100

Evans,

Agreed. The current proposals is that the listener bean class specifies the destination, connection factory, destination
type, acknowledge mode, subscription durability, clientId, subscription name and message selector using annotations,
which means these are set at compile time.

It would be desirable to allow these to be specified at runtime, for each listener bean instance separately.

I like your suggestion of allowing the listener bean itself to have callbacks which return these values.

  @SessionScoped
  public class MyCDIBean21 {
  
    @JMSListener(lookup="java:global/java:global/Trades",type=JMSListener.Type.TOPIC )
    @JMSConnectionFactory("java:global/MyCF")
    @MessageSelector("ticker='ORCL'")
    public void processNewsItem(String newsItem) {
      ...
    }

    @GetMessageSelector
    public void returnMessageSelector(){
      // some logic to work out message selector
      return ...
  }

This would allow the bean initialisation code to find out what message selector to use. However what only works if
there is a single callback method. The current proposals suggest that a bean can have multiple callbacks, each listening
to different destinations or using different message selectors. To handle that we'd need something like:

    @GetMessageSelector
    public void returnMessageSelector(Method m){
      // some logic to work out message selector for the specified method
      return ...

It would be simpler overall if we allowed these beans to define just a single callback method. (The same issue applies
to the new-style MDBs).

There's a second, and more important, issue with these callback methods. Although it allows the listen bean itself to
decide (say) the message selector, it doesn't provide a way for the application which is injecting it to decide the
message selector. I think that's probably a bigger requirement, but I'm not sure the best way to achieve that.

CDI provides a way to programmatically obtain an instance of the listener bean. I describe this here:
https://java.net/projects/jms-spec/pages/CDIBeansAsJMSListeners#JMS_listener_bean_with_dependent_scope_and_explicit_lifecycle_management

    Inject Instance<MyDepScopeListenerBean> listenerProvider;
    MyDepScopeJMSListener jmsListener1 = listenerProvider.get();

However since the consumer is created during the bean's @postCreate stage then we need a way for the application to
specify the message selector etc before we actually create the bean. CDI allows qualifiers to be specified before
calling get(), but these annotations are not qualifiers. Ideas welcome.

Nigel


On 26/08/2015 12:36, Evans Armitage wrote:
>
> Hi Nigel,
> I was asking more around the definition of the destinations themselves. Currently those properties are static and thus
> do not allow the developer to decide at runtime which messages get delivered. In the @SessionScoped scenario it is
> likely that if a developer needs a listener to be @SessionScoped then they intend for the messages to be delivered to
> the current session user only. They would thus likely appreciate some customization on their activation config
> (especially for message selector) to allow them to specify the selector dynamically through a call back method to
> select messages for, say, the current user principal.
> It's just a thought triggered by your suggested addition. If the targets for delivery are now going to be dynamic
> would it also be feasible to make the message selector dynamic?
>
> Evans
>
> On 26 Aug 2015 12:34 PM, "Nigel Deakin" <nigel.deakin_at_oracle.com <mailto:nigel.deakin_at_oracle.com>> wrote:
>
> Evans,
>
> On 26/08/2015 05:44, Evans Armitage wrote:
>
> I take it container discovery and validation still happens at startup even for these CDI listeners?
>
>
> My proposal was that "JMS listener beans" would be completely ordinary CDI managed beans, created in the same way.
> The new portable extension would simply extend their postCreate behaviour to create a JMS consumer, and extend
> their preDestroy behaviour to close that consumer. I'm not familiar with those specific events, but I'm not
> proposing anything to interfere with them working as normal.
>
> Is there anything that can be added to allow an @SessionScoped listener that only delivers messages for the
> current
> session? I think that will be a more common reason to use a @SessionScoped jms listener (i.e only deliver
> when user
> session exists AND only messages intended for the current user).
>
>
> A JMS listener bean could have any scope, including @SessionScoped. So once it was injected and created by the
> application it would listen for messages until the scope ends and the bean was destroyed.
>
> Over on the cdi-dev list people have suggested we provide some way of automatically creating a listener bean
> whenever a new scope starts, so that the application wouldn't have to inject it. If that were the case then an
> instance of the listener would be automatically created whenever a new SessionScope starts. (I'm still thinking
> about this).
>
> Would adding a message selector callback approach be too much work for container developers for too little gain?
>
>
> I don't understand your question. Can you explain it a bit more?
>
> Nigel
>