users@jms-spec.java.net

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

From: Nigel Deakin <nigel.deakin_at_oracle.com>
Date: Tue, 10 Apr 2012 11:22:29 +0100

John,

Thanks for the replies. Follow-ups below...

On 06/04/2012 02:58, John D. Ament wrote:
> Nigel,
>
> At the onset of all this, I assumed this would be simpler than it ended up. I also assumed the answer should be CDI
> from the get-go. My answers below even surprised me.
>
> /Question 1: Should the injection of JMSContext be tied to CDI or should we simply define the injection behaviour we
> require? A=Yes, B=No/
>
> B - At this point I believe that the injection behavior we're looking for is closer to how JPA handles injection
> (within EJB), though we should aim to allow it even in a non-EJB container if CDI is available. I would support this
> even if a jms.xml descriptor were added (for some reason).

If we followed the JPA approach we would be defining our own annotation, say

@MessagingContex(lookup="jms/connectionFactory")
JMSContext context

However would this limit their use to a Java EE container?

>
> /Question 2: Should there be a separate instance for each injection point (answer A), or should normal CDI sharing
> (according to scope) be used? (answer B)/
>
> I think the use case of needing multiple injection points is quite small. Injecting into multple stateless session
> beans, or even stateful session beans, should result in different instances. CDI scopes though behave different
> because the objects are related. CDI injection should use the same instance for same scoped objects that are all
> active together.
I'd like to clarify what you're suggesting. If we had two beans, one of which called the other, and which both injected
a JMSContext using

@Inject
@JMSConnectionFactory(lookup="jms/connectionFactory");
JMSContext context;

(so there are two injection points, in two different beans)

then would the two beans use the "same" injected object?

(If so then this would be the same as a normal CDI scope such as "request")

> /Question 3: Even if the session and connection are shared, should the producer properties listed above still have
> dependent scope? (A=yes, B=no)/
>
> The properties should be set against the instance, not a proxy. Not sure what this has to do with dependent scope.

Rüdiger has responded to this. But I think the issue he is raising is whether, when injecting a JMSContext, the
underlying connection/session should have one scope (request or transaction) and the underlying producer should have
another scope (dependent).

Personally I don't think this is necessary, and all aspects of the injected JMSContext should have the same scope.

>
> /Question 4: Should the scope of the injected JMSContext be (A) request or (B) extended to cover any transaction as well?/
>
> Within an EE application it should match up to a JTA transaction.

OK. Given that we will need to declare exactly that this means (and that it needs to cover the non-transacted case),
what do you think of my proposed definition that the scope would be "a single transaction or a request, whichever is
longer."?
>
> /Question 5: Do you prefer (A) multiple small annotations, similar to qualifiers (/_at_JMSConnectionFactory/,
> /_at_JMSPasswordCredential/, /_at_JMSSessionMode/ and /_at_SessionMode/) or (B) a single annotation with many attributes
> (/_at_JMSContextConfiguration/)/
>
> Is there a reason both cannot be supported simultaneously?

I think we should only offer both if there is a good reason for doing so, not because we can't decide which way to go.
Otherwise we are simply bloating the interface and causing confusion.

Nigel

>
>
> John
>
>
> On Thu, Apr 5, 2012 at 11:40 AM, Nigel Deakin <nigel.deakin_at_oracle.com <mailto:nigel.deakin_at_oracle.com>> wrote:
>
> I'd like to review where I think we are on the issue of injecting JMSContext objects into a JavaEE application.
>
> (JMSContext is the new name for MessagingContext, and to avoid confusion I'll use the new name throughout in this
> email)
>
> I ask a number of questions which are repeated in a single list at the end. If you have a strong view on any of
> them please do express an opinion. However these are not easy questions, there may be options other than the
> alternatives suggested, and we may need to discuss this further before coming to a final conclusion. I plan to
> call a conference call in the near future to discuss this.
>
> *Recap of Early Draft proposal*
>
> The current proposals are as described in section 11.3 "Injection of JMSContext" objects of the Early Draft.
> Here's a concise version of what it says,
>
> /
> This section relates to application classes which run in the Java EE web, EJB or application client containers and
> which support injection. Section EE.5 of the Java EE specification lists the application classes that support
> injection.
>
> Applications may declare a field of type javax.jms.JMSContext and annotate it with the javax.inject.Inject annotation:
>
> The container will inject a JMSContext. It will have request scope and will be automatically closed when the
> request ends. However, unlike a normal CDI request-scoped object, a separate JMSContext instance will be injected
> for every injection point.
>
> @Inject
> private JMSContext context;
>
> The following annotations may be added to specify the injected JMSContext in more detail:
>
> @JMSConnectionFactory("jms/connectionFactory") - used to specify the lookup name of the connection factory
> @JMSPasswordCredential(userName="admin",password="mypassword") - used to specify the user/password passed to
> createConnection
> @JMSSessionMode(JMSContext.AUTO_ACKNOWLEDGE) - used to specify the session mode of the JMSContext (subject to
> existing JavaEE restrictions)
> @JMSAutoStart(false) - used to prevent the connection being started automatically
>
> I have a prototype implementation of the above proposal (created with the help of Pete Muir) which demonstrates
> that it can be implemented reasonably easily./
>
> *Issues*
>
> I believe that, despite my successfully prototyping the proposal above, the following issues are unresolved:
>
> *1. Is this CDI injection or not? *
>
> The existing proposal is that the way in which JMSContext objects are injected should be as consistent with
> standard CDI dependency injection as possible and be implemented by normal CDI mechanisms. This means:
>
> * Injection is defined using @Inject
> * Containers need to "support injection points annotated with the javax.inject.Inject annotation only to the
> extent dictated by CDI" (Java EE 6 Section EE 5.21).
> * It will be optional to support the injection of JMSContext objects in the application client (since CDI
> support in the application client is optional)
> * Injection of JMSContext objects will only be possible in application modules for which CDI is enabled by
> including a META-INF/beans.xml descriptor.
>
> However it is not essential for this to be CDI injection (even if it is implemented using CDI internally). There
> are numerous examples in Java EE of non-CDI injection, including @Resource and @PersistenceContext. By removing
> the connection with CDI, and simply defining the required behaviour and leaving the implementation up to the
> container, some additional options become available:
>
> * Injection could be defined using any annotation we choose rather than @Inject (perhaps @MessagingContext, in
> the manner of @PersistenceContext)
> * JMS would be free to mandate support for the injection of JMSContext objects in the application client, just
> as the Java EE spec mandates support for resource injection using @Resource.
> * JMS could mandate support for the injection of JMSContext objects without the need to include a
> META-INF/beans.xml descriptor.
>
> Personally I can see benefits in making this non-CDI injection. This will avoid the need for applications to
> define a META-INF/beans.xml descriptor. It will make it possible to mandate injection in the Application Client.
> It will be consistent with @PersistenceContext. It will avoid any confusion caused by injection "looking like
> "normal CDI injection but having a special scope and using annotations rather than qualifiers.
>
> Note that defining this as "non-CDI" injection does not prevent CDI being used by the container to actually
> implement it.
>
> /Question 1: should the injection of JMSContext be tied to CDI or should we simply define the injection behaviour
> we require? A=Yes, B=No/
>
> *2. Do we want to create a separate instance for each injection point?*
>
> This relates to what I describe as the "sharing" aspects of the injected object.
>
> The current proposal states "unlike a normal CDI request-scoped object, a separate JMSContext instance will be
> injected for every injection point." An injected JMSContext is never shared between different injection points,
> even within the same request. In this sense it is behaving as if it had dependent scope, though since we are
> closing the injected JMSContext at the end of the request it is also behaving as if it had request scope.
>
> What this means in practice is that two beans, called within the same request, which injected a JMSContext (using
> identical annotations), would use /different /JMSContext instances. The main functional significance of this is
> that since the two JMSContext objects would use different underling sessions, any messages sent by the two beans
> would not necessarily be delivered in the order in which they were sent.
>
> Allowing messages sent within a request to be delivered in order seems a useful feature, which could be easily
> provided by defining that injected JMSContext objects be shared according to the defined scope, just like with
> normal CDI injection. So two beans, called within the same request, which injected a JMSContext (using identical
> annotations), would use the same JMSContext instance. This change would also reduce the number of JMSContext
> instances that need to be exist to service the request and thereby increase scalability.
>
> I think that switching to the normal CDI object sharing model would therefore be a good idea.
>
> However Rüdiger has suggested (to me) that this might be confusing, since calling setPriority, setAutoStart,
> setTimeToLive, setDeliveryMode, setDeliveryDelay, setDisableMessageTimestamp or setDisableMessageID on a
> JMSContext in one bean would then have an effect on a JMSContext in another bean. He has proposed that we share
> the underlying connection and session (in order to preserve message order) but not these properties. One way to
> describe this might be to say that the underlying connection and session are request-scoped, but the underlying
> producer (which holds the properties) is dependent scope. Whilst this might not be too difficult to implement it
> would be rather complicated to describe and might itself be confusing for users. So my inclination is to discount
> this objection and for the whole JMSContext to have the same, request, scope. However I'd welcome further views on
> this.
>
> /Question 2: should there be (A) a separate instance for each injection point , or (B) normal CDI sharing
> (according to scope) used? /
>
> /Question 3: even if the session and connection are shared, should the producer properties listed above still have
> dependent scope? (A=yes, B=no)/
>
> *3. Should the scope be "transaction" rather than "request"?*
>
> One of the most important features offered by the injection of JMSContext objects is removing the need for
> applications to need to close the JMSContext (and thereby the connection) after use. Connections are a limited
> resource and application components should not hold on to a connection when it is not needed, such as when the
> application is not being used. Since connections are pooled by the container there is no need for applications to
> hold on to connections simply to avoid the expense of creating them. For this reasons, application developers are
> currently recommended to create a connection (which will fetch one from the pool), use it to send a message, and
> then close the connection (return it to the pool) as soon as possible.
>
> For this reason, the current proposal states that an injected JMSContext object "will have request scope and will
> be automatically closed when the request ends". Request scope was chosen because it appeared to be the most
> appropriate of the CDI built-scopes (which are "request", "session", "application", "conversation", plus the
> psuedo-scope "dependent" ).
>
> * "Application" or "dependent" scope would keep connections in use even when the application was not being used
> * "Conversation" scope can only be used by applications which explicitly demarcate the start and end of the
> conversation
> * "Session" scope was only briefly considered but appears to be longer than is necessary, and I was unsure
> whether it has any meaning for MDBs and EJBs.
> * "Request" scope seemed the most suitable, especially since the CDI spec defines it as including a MDB
> invocation and an EJB invocation.
>
> However there have been suggestions that the injected objects should have "transaction" scope rather than
> "request". However CDI does not define a transaction scope.
>
> JPA does define something vaguely similar to transaction scope: it defines that when an EntityManager is injected
> using the @PersistenceContext annotation, its "persistence context" is "propagated with the current JTA transaction".
>
> The absence of transaction scope in CDI leaves it to JMS to define what scope we require. As I see it, the main
> benefit of using transaction scope is that it would allow JMSContext objects to be shared, and therefore the order
> of sent messages to be preserved, in the case where the transaction spans multiple requests. This is a possibility
> when an external client is using a stateful session bean, where one business method starts a user transaction and
> another business method commits it. It is unclear just how important it would be to allow message order to be
> preserved in such a case.
>
> However the idea of "transaction" scope raises the question of what happens if a JMSContext is used when there is
> no JTA transaction? Although EJB 3.1 is not particularly explicit about how JMS should work in such a case, it is
> most definitely not an error and needs to work. One answer might be to declare if a JMSContext is used when there
> is no transaction, the scope should be "request".
>
> There is also the question of what happens if the transaction is user-demarcated (bean-managed) and a JMSContext
> is used before the call to userTransaction.begin() and perhaps after it, as in the following rather contrived example:
>
> @Inject
> @JMSConnectionFactory("jms/connectionFactory")
> private JMSContext context;
>
> @Resource(mappedName = "jms/inboundQueue")
> private Queue inboundQueue;
> @Inject UserTransaction ut;
>
> public void sendMessages() {
> context.send(inboundQueue, "Message 1");
> ut.begin();
> context.send(inboundQueue, "Message 2");
> ut.commit();
> }
>
> The important question here is "where are the scope boundaries?". Are the two places where a message is sent
> within the same or different scopes? In other words, does the context variable refer to the same JMSContext in
> both places in the same method? My view is that it would be very confusing to start a new scope in the middle of a
> method, and that instead the scope should defines as "a single transaction or a request, whichever is longer".
>
> The above code would then be identical to the following code which doesn't use injection:
>
> @Resource(lookup=""jms/connectionFactory")
> ConnectionFactory cf;
>
> @Resource(mappedName = "jms/inboundQueue")
> private Queue inboundQueue;
> @Inject UserTransaction ut;
>
> public void sendMessages() {
> try (JMSContext context = connectionFactory.createContext(JMSContext.AUTO_ACKNOWLEDGE)) {
> context.send(inboundQueue, "Message 1");
> ut.begin();
> context.send(inboundQueue, "Message 2");
> ut.commit();
> }
> }
>
> Note that the important thing here is translating the application code into a sequence of JMS API calls in a clear
> and unambiguous manner. It is less important what the actual JMS behaviour is (this is currently undefined but may
> be clarified in the future).
>
> I therefore have suggested an alternative definition of the scope of the injected JMSContext , as follows:
>
> "The container will inject a container-managed JMSContext whose lifetime will be managed by the container and
> which is scoped to a single transaction or a request, whichever is longer. An injected JMSContext with a given set
> of annotations will be propagated by the container to other injection points with the same annotations in the same
> transaction or request, whichever is longer.
>
> /Question 4: Should the scope of the injected JMSContext be (A) request or (B) extended to cover any transaction
> as well?/
>
> *4. Lots of small annotations or one big annotation?*
>
> The final issue that needs to be resolved is what are the most suitable annotations to configure the injected
> JMSContext. The current proposal is to provide several annotations, each of which configures a specific aspect of
> the injected object:
>
> @JMSConnectionFactory("jms/connectionFactory") - used to specify the lookup name of the connection factory
> @JMSPasswordCredential(userName="admin",password="mypassword") - used to specify the user/password passed to
> createConnection
> @JMSSessionMode(JMSContext.AUTO_ACKNOWLEDGE) - used to specify the session mode of the JMSContext (subject to
> existing JavaEE restrictions)
> @JMSAutoStart(false) - used to prevent the connection being started automatically
>
> This was proposed because it is similar to the CDI concept of qualifiers, and was expressly recommended by Pete
> Muir as being consistent with CDI style. However an alternative might be to define a single annotation with
> multiple parameters, something like:
>
> @Inject
> @JMSContextConfiguration(lookup="jms/connectionFactory",
> userName="admin",password="mypassword",
> sessionMode=JMSContext.AUTO_ACKNOWLEDGE,
> autoStart=false)
> JMSContext context;
> /
> Question 5: Do you prefer (A) multiple small annotations, similar to qualifiers (@JMSConnectionFactory,
> @JMSPasswordCredential, @JMSSessionMode and @SessionMode) or (B) a single annotation with many attributes
> (@JMSContextConfiguration)/
>
> *Those questions again*
>
> Here are those questions again in a single list. If you have a strong view on any of them please do express an
> opinion. However these are not easy questions and we may need to discuss this further before coming to a final
> conclusion.
>
> /Question 1: Should the injection of JMSContext be tied to CDI or should we simply define the injection behaviour
> we require? A=Yes, B=No
>
> //Question 2: Should there be a separate instance for each injection point (answer A), or should normal CDI
> sharing (according to scope) be used? (answer B)/
>
> /Question 3: Even if the session and connection are shared, should the producer properties listed above still have
> dependent scope? (A=yes, B=no)
>
> //Question 4: Should the scope of the injected JMSContext be (A) request or (B) extended to cover any transaction
> as well?/
> /
> Question 5: Do you prefer (A) multiple small annotations, similar to qualifiers (@JMSConnectionFactory,
> @JMSPasswordCredential, @JMSSessionMode and @SessionMode) or (B) a single annotation with many attributes
> (@JMSContextConfiguration)/
>
> Nigel
>
>