users@jms-spec.java.net

[jms-spec users] Re: Digest for list users_at_jms-spec.java.net

From: Werner Keil <werner.keil_at_gmail.com>
Date: Thu, 3 Sep 2015 16:51:38 +0200

Hi,

This is currently working from JMS 1 on:
@MessageDriven(name = "AQueue", activationConfig = {
@ActivationConfigProperty(propertyName = "messageSelector", propertyValue =
"JMSCorrelationID='12345'")

Making the messageSelector property a first class annotation should make it
a little more intuitive, but I don't see how get it to understand
properties, values or expressions like "JMSCorrelationID='12345'" or
"ticker='ORCL'" at compile time. If you say mis-spell
it "JMSCorelationID='12345'" that won't be noticed at compile time. Not
sure, if there was a solution here that would already notice such things
before running/debugging your apps.

At most properly written tests should catch that kind of problem ;-)

Werner

On Thu, Sep 3, 2015 at 3:13 AM, <users-request_at_jms-spec.java.net> wrote:

> Table of contents:
>
> 1. [jms-spec users] Re: JMS_SPEC-134: Declarative Annotation Based JMS
> Listeners - Nigel Deakin <nigel.deakin_at_oracle.com>
> 2. [jms-spec users] Re: JMS_SPEC-134: Declarative Annotation Based JMS
> Listeners - Nigel Deakin <nigel.deakin_at_oracle.com>
>
>
>
> ---------- Forwarded message ----------
> From: Nigel Deakin <nigel.deakin_at_oracle.com>
> To: users_at_jms-spec.java.net
> Cc:
> Date: Wed, 2 Sep 2015 15:24:13 +0100
> Subject: [jms-spec users] Re: JMS_SPEC-134: Declarative Annotation Based
> JMS Listeners
> Evans,
>
> Thanks. That's helpful.
>
> I can see how that might work, and see how it offers a way to plug a
> callback method directly into the @MessageSelector annotation. We'd not
> want to lose the ability to specify the message selector directly, so we'd
> need to define the @MessageSelector annotation to allow both, perhaps using
>
> @MessageSelector("ticker='ORCL'") <== using the "value" attribute
>
> @MessageSelector(expression="method=#{selectorProvider.tickerSelector}")
> <== using the "expression" attribute
>
> However I'm still unenthusiastic about the use of EL. It's not Java. It's
> a script inside a Java program, and a typo would not be detected at compile
> time. And it's something new for the JMS developer to learn about. I'd like
> to keep looking for something better.
>
> I'm recording all these suggestions in a wiki page. I've captured the
> various comments on runtime customisation at
>
> https://java.net/projects/jms-spec/pages/CDIListenerBeanComments#Runtime_customisation
>
> Nigel
>
> On 01/09/2015 14:32, Evans Armitage wrote:
>
> Hi Nigel,
>
> The EL evaluation can be done using javax.el.CompositeELResolver which can
> be created with beanManager.getELResolver.
>
> @Named is not limited to JSF and JSP pages hence the unification of EL.
> You can use @Named to qualify any beans and @Inject the one with the right
> @Named at the right injection point. It's not refactoring friendly but is
> all CDI and has nothing to do with Web pages.
>
> It is clearer to have the message selector definition as part of the
> activation configs on the listener method rather than being located
> elsewhere in the class definition. Whether it should be restricted to only
> be inside the class that has the listener method is also another issue. The
> EL approach eliminates the need to have the selector method in the same
> class (or module) as the listener method and removes the complexity that
> could arise with choosing the selector method when multiple listener
> methods are in the same class.
> A 'caveat' of the EL approach is that the latest EL spec allows
> expressions like "#{bean.methodName ('someValue')" where methodName takes a
> String but this would be transparent to the JMS implementor as they simply
> pass the EL to the ELResolver.
>
> A lambda expression could indeed be better but I think it would need to
> allow instance::instanceMethodName which means the instance needs to be
> created somewhere and I don't think that will work in an annotation. Just
> allowing the static ClassName::methodName option would be limiting IMO. My
> lambdas are not the best though.
>
> Regards
>
> Evans
> On 01 Sep 2015 1:36 PM, "Nigel Deakin" <nigel.deakin_at_oracle.com> wrote:
>
>> On 28/08/2015 17:03, Evans Armitage wrote:
>>
>>> 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}")
>>>
>>>
>>>
>> Currently when the listener bean is initialised (using code plugged in by
>> the portable extension), it can use reflection to discover what message
>> selector to use for the callback method as follows:
>>
>> MessageSelector messageSelectorAnnotation
>> method.getAnnotation(MessageSelector.class);
>> String messageSelector = messageSelectorAnnotation.getValue();
>> ...
>> JMSContext jmsContext = ...
>> Destination destination = ...
>> JMSConsumer consumer =
>> jmsContext.createConsumer(destination,messageSelector);
>> ...
>>
>> If the message selector is "method=#{selectorProvider.tickerSelector}"
>> then how does this code need to change to evaluate the expression?
>>
>> I'm not sure EL is the best way to specify a callback method which should
>> be called to obtain the message selector: EL is intended for use in
>> non-Java code such as a JSF or JSP pages, whereas we're in Java code here
>> and have the full power of Java available to us. Perhaps a lambda
>> expression is more appropriate.
>>
>> Nigel
>>
>> Evans
>>>
>>> On Fri, Aug 28, 2015 at 5:30 PM, Nigel Deakin <
>>> <nigel.deakin_at_oracle.com>nigel.deakin_at_oracle.com <mailto:
>>> 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_at_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>nigel.deakin_at_oracle.com <mailto:
>>>> 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>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
>>>>>
>>>>>
>>>>
>>>>
>>>
>>>
>
>
> ---------- Forwarded message ----------
> From: Nigel Deakin <nigel.deakin_at_oracle.com>
> To: users_at_jms-spec.java.net
> Cc:
> Date: Wed, 2 Sep 2015 15:30:08 +0100
> Subject: [jms-spec users] Re: JMS_SPEC-134: Declarative Annotation Based
> JMS Listeners
> On 24/08/2015 15:51, Nigel Deakin wrote:
>
>>
>> I've written down some proposals which you can read at
>> https://java.net/projects/jms-spec/pages/CDIBeansAsJMSListeners
>>
>
> Thank you for the feedback so far. I've also received some very helpful
> comments from the CDI spec community, and from colleagues within Oracle.
> I've attempted to record all the comments made so far on a wiki page. This
> is at
> https://java.net/projects/jms-spec/pages/CDIListenerBeanComments
>
> Here's a summary of the comments so far:
>
> * Is there a way to avoid the application having to inject and instantiate
> the listener bean?
> See
> https://java.net/projects/jms-spec/pages/CDIListenerBeanComments#Creating_listener_beans_automatically
>
> * Is there a way for the queue, message selector etc to be specified at
> runtime rather than hardcoded as an annotation?
> See
> https://java.net/projects/jms-spec/pages/CDIListenerBeanComments#Runtime_customisation
>
> * It might be desirable to allow JMS listener beans to listen to temporary
> queues and topics.
> See
> https://java.net/projects/jms-spec/pages/CDIListenerBeanComments#Listening_to_temporary_queues_and_topics
>
> * It's important that my application deploys even if the JMS provider
> isn't fully available yet
> See
> https://java.net/projects/jms-spec/pages/CDIListenerBeanComments#Handling_failures
>
> * What scopes are active when the callback method is invoked?
> See
> https://java.net/projects/jms-spec/pages/CDIListenerBeanComments#What_scopes_are_active_when_the_callback_method_is_invoked
> ?
>
> * I think we should leverage the existing CDI event/observer functionality
> instead of introducing a completely new delivery mechanism
> See
> https://java.net/projects/jms-spec/pages/CDIListenerBeanComments#Are_CDI_events_better
> ?
>
> Please feel free to make comments on those comments, or to raise new
> comments.
>
> Nigel
>
>
>
> End of digest for list users_at_jms-spec.java.net - Thu, 03 Sep 2015
>
>