users@jms-spec.java.net

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

From: Evans Armitage <evans.armitage_at_gmail.com>
Date: Fri, 28 Aug 2015 18:03:35 +0200

Hi Nigel, the EL use could look like below

import javax.inject.Named;
@Named
public class SelectorProvider {
public String tickerSelector() {
return "ticker='ORCL'";
}
}

Here CDI will make the SelectorProvider bean available using the name
#{selectorProvider}


Then the listener method would have

@MessageSelector("method=#{selectorProvider.tickerSelector}")


Evans

On Fri, Aug 28, 2015 at 5:30 PM, Nigel Deakin <nigel.deakin_at_oracle.com>
wrote:

> Evans,
>
> On 28/08/2015 16:03, Evans Armitage wrote:
>
> Hi Nigel,
>
> For the problem of how to specify the message selector when there are
> multiple callback methods, an approach could be using the unified
> expression language @MessageSelector(method="#{someBean.method}") which
> allows selectors to be reused in other listeners. The evaluation of the EL
> expression would be delegated to the CDI container.
>
>
> I'm not familiar with that. Can you give a more detailed example of what
> you are suggesting?
>
> The listener bean connects to the JMS provider and creates the JMS
> consumer during its @PostConstruct phase, using code plugged in by the
> portable extension. What code would this use to discover what message
> selector to use and (say) save it in a local variable?
>
> Making the injecting application decide the selector might not be feasible
> because depending on the scope e.g @ApplicationScoped and @SessionScoped
> the listener instance might already have been created and receiving
> messages before it is injected at any injection point. This is assuming
> that @Eager like behavior gets implemented as default.
>
> This is a problem even if the instance has not already been eagerly
> created. As I mentioned in my example below:
>
> Inject Instance<MyDepScopeListenerBean> listenerProvider;
> MyDepScopeJMSListener jmsListener1 = listenerProvider.get();
>
> since the consumer is created during the bean's @PostConstruct stage then
> we need a way for the application to specify the message selector etc
> before CDI actually creates the bean. Once the bean has been created it's
> too late. CDI allows qualifiers to be specified before calling get(), but
> these annotations (@MessageSelector etc) are not qualifiers (i.e. they're
> not used to determined which bean class to use).
>
> Nigel
>
>
> Kind regards
> Evans Armitage
>
> On Fri, Aug 28, 2015 at 12:41 PM, Nigel Deakin <nigel.deakin_at_oracle.com>
> wrote:
>
>> 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> 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
>>>
>>>
>>
>
>