users@jms-spec.java.net

[jms-spec users] [jsr343-experts] Re: (JMS_SPEC-70) Define annotations for injecting MessagingContext objects

From: Rüdiger zu Dohna <ruediger.dohna_at_1und1.de>
Date: Wed, 11 Apr 2012 09:29:28 +0200

Nigel,

On 2012-04-10, at 12:56, Nigel Deakin wrote:
> On 10/04/2012 08:21, Rüdiger zu Dohna wrote:
>>
>> On 2012-04-05, at 17:40, Nigel Deakin wrote:
>>> Question 2: should there be (A) a separate instance for each injection point , or (B) normal CDI sharing (according to scope) used?
>> A - I strongly think it would be extremely confusing to developers to have different beans change the behavior of each other.
>
> I don't see why. This is exactly what happens now if you inject an object which has a normal scope such as "request" or "application".
>
>> An alternative may be to keep the 1.1 producer objects to have a container for those properties. But a client that only sends messages would then want to have only those injected, so an analogous question would still remain: Are they dependent scope and still share the same connection/session? I think so, and this would additionally provide us with a nice place to add annotations for the producer properties!
>>
>>> Question 3: even if the session and connection are shared, should the producer properties listed above still have dependent scope? (A=yes, B=no)
>>
>> A - I think this is actually just a question of implementation, but "dependent scope with a request scoped session/connection" is easier to explain than "request scope but some properties are not shared".
>
> To give a concrete example of the issues here: if we have two beans, one which calls the other (so they're in the same request), and each of which uses the following code to send a message. if
>
> Bean 1:
>
> @Inject
> @JMSConnectionFactory(lookup="jms/connectionFactory")
> JMSContext context;
>
> @Resource(lookup="jms/inboundQueue") Queue inboundQueue;
>
> public void foo(){
> context.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
> context.send(inboundQueue,"Message 1");
> bean2.bar();
> }
>
> Bean 2:
>
> @Inject
> @JMSConnectionFactory(lookup="jms/connectionFactory")
> JMSContext context;
>
> @Resource(lookup="jms/inboundQueue") Queue inboundQueue;
>
> public void bar(){
> context.send(inboundQueue,"Message 2");
> }
>
> As I see it, both JMSContext objects are in the same scope so the underlying JMSContext is shared. This means that setting deliveryMode in one bean affects the deliveryMode of the other. So in bean 2, message 2 is non-persistent (and is guaranteed to be delivered after message 1)
>
> I agree that for those who haven't encountered dependency injection before this might seem odd, but isn't this just what scoping is all about?
>
> I checked what happens in JPA (by asking Linda, the spec lead). If you have two beans, used within the same JTA transaction, each of which injects an EntityManager using
>
> @PersistenceContext
> EntityManager em;
>
> Then if you call em.setProperty(name,value) on one injected EntityManager, it affects all injected EntityManager objects within the same transaction.

The simplified API has collapsed connection, session, and producer into one context. If you view the context as mainly a connection or session, then the scope for the context should be request (maybe extended to transaction). I tend to regard the context primarily as a message producer, because that's what client code will use it for primarily... but then the "natural" scope (i.e. the scope developers would expect without reading much docs) of the context would be dependent.

I think both perspectives are valid. I assume that if we'd start a poll among developers, the answer would very much be biased by exactly how you ask them. It would be better to clarify the topic, and I can see two alternatives:

A) We could actually go back one step and again have message producers separate from the context objects containing only connections/sessions. Bean 1 of your code example would then look like this:

@Inject
@JMSConnectionFactory(lookup="jms/connectionFactory")
JMSProducer producer;

@Resource(lookup="jms/inboundQueue") Queue inboundQueue;

public void foo(){
   producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
   producer.send(inboundQueue,"Message 1");
   bean2.bar();
}

It then would be very confusing, if this bean affected Bean 2, don't you think?

It would even be possible to set the producer properties in other methods, and they would "stick", even when a new request comes in:

@Inject
@JMSConnectionFactory(lookup="jms/connectionFactory")
JMSProducer producer;

@Resource(lookup="jms/inboundQueue") Queue inboundQueue;

@PostConstruct
public void postConstruct() {
   producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
}

public void foo(){
   producer.send(inboundQueue,"Message 1");
   bean2.bar();
}

B) We could make leave the JMSContext as it is but make it very clear, that the "producer properties" are only the defaults, by naming them setDefaultDeliveryMode, etc. I think this would nicely clarify that this is something that may affect other beans using the same context as well. Note that it still may be confusing that setting these values has "no effect" for the next request... at least the javadoc should clearly state that.

Both alternatives have their pros and cons... I just think that the current suggestion would lead to a lot of head scratching in the long run.


>>> Question 4: Should the scope of the injected JMSContext be (A) request or (B) extended to cover any transaction as well?
>>
>> B - would be something a user might expect, but we have an in-house policy not to depend on message ordering but to do a full request-reply before the next message is sent. This is mainly because of the poison message handling in place. So I don't have a very strong opinion here.
>>
>> Maybe we should leave this extended scope message ordering optional for 2.0, so the user can't rely on it to be portable. If CDI defines transaction scope, we could standardize on this in 2.1 (if this comes too late for 2.0).
>
> So we would mandate request scope, and leave any other scope for 2.1?

As 2.1 could only be more specific than 2.0, we'd have to maybe recommend but leave it up to the JMS providers in 2.0 and require it in 2.1.


Rüdiger