users@jms-spec.java.net

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

From: Reza Rahman <reza_rahman_at_lycos.com>
Date: Wed, 11 Apr 2012 12:48:18 -0400

My responses:

 

Question 1: Should the injection of JMSContext be tied to CDI or should we
simply define the injection behaviour we require?

- I think it’s best to stick with CDI-style syntax to keep things
consistent across the Java EE platform going forward. However, this is a
tricky issue and I could go either way.

 

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 either way is fine. My inclination is to keep the
instances completely separate.

 

Question 3: Even if the session and connection are shared, should the
producer properties listed above still have dependent scope?

- I don’t think the instances should be shared, but if it is, the
producer properties should be separate.

 

Question 4: Should the scope of the injected JMSContext be (A) request or
(B) extended to cover any transaction as well?

- The scope should be a combination of request and transaction,
whichever one is longer.

 

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)

- I prefer smaller annotations. If they are CDI “qualifiers” they
could be grouped together in a “stereotype” when needed. I used the double
quotes because these facilities could be modified to meet our needs or we
could use a similar concept (perhaps defined at the Java EE level in the
future).

 

Hope this helps.

 

From: Nigel Deakin [mailto:nigel.deakin_at_oracle.com]
Sent: Thursday, April 05, 2012 11:40 AM
To: jsr343-experts_at_jms-spec.java.net
Subject: [jsr343-experts] Re: (JMS_SPEC-70) Define annotations for injecting
MessagingContext objects

 

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