jsr343-experts@jms-spec.java.net

[jsr343-experts] Re: (JMS_SPEC-33) Improving the JMS API with API simplifications, annotations and CDI

From: Reza Rahman <reza_rahman_at_lycos.com>
Date: Fri, 29 Jul 2011 15:48:29 -0400

Nigel,

Responses below:

* Providing a new way of performing asynchromous callbacks in a Java EE
container (and I'm still unsure what the case is for that) would be more
intrusive as it would need to plug in more explicitly to the transaction
manager, JCA adapter etc.
- Yep, this is mostly what I meant. Depending on the final design, send
and synchronous receive may not be that cut-and-dry either. The issue is
that it might need sophisticated container integration beyond what the
CDI SPI allows, especially for a custom scope. Also, a functional
implementation can probably be fairly portable, but might not be the
most optimal production-ready solution (and I do like the fact that
GlassFish is a production-ready implementation). All in all, this is
probably just a nitpick - we can probably re-use most of the code for
Resin, JBoss, etc.

* I suppose that's the critical issue: what aspects of the JMS API are
simply artifacts of the API, and what are fundamental concepts?
- I think the answer to this becomes more obvious when you consider the
other approaches to solving this problem. If none of those folks respond
to this thread now, I and John can probably try to synthesize the gist
of those approaches and come up with a list of strength and weaknesses
for each of them.

* No doubt if the EJB spec replaces CMT with something different then
whatever we do will fit in with that, but since any change would affect
all resources, not just JMS, I would expect the initiative for such a
change to come from the EJB EG (which I know you are on).
- It's difficult to say much of anything given the current velocity of
the EJB 3.2 EG, but I am fairly certain this is one of the changes that
actually will happen in a timely fashion. If not, we can simply assume
that a JTA transaction happens somehow. In our examples, we can use the
UserTransaction API, which I see no real reason to change.

* I don't know. I can definitely see the attraction, and certainly don't
think we should rule it out without more discussion.
- Sounds good - I hope the other folks do provide their feedback on this
soon. If not, this might be something to engage the broader community on
as I've suggested in the past?

* By "JMS pluggability contract" do you mean (JMS_SPEC-25) Standardize
the interface between a JMS provider and a Java EE application server ?
- Yes

* I've read your comments on that proposal (in the Java EE EG). Do you
think this would address the issues you mention?
- Sort of, but I figured I'll leave it alone for now. It still feels a
bit too high level for me. I would have expected settings more in line
with data sources. For example, here are some configuration examples for
ActiveMQ: http://activemq.apache.org/connection-factory-properties.html.

* Whilst I'm not trying to rule anything out, I see this as being a much
bigger piece of work, and one which would involve both the platform and
EJB EGs.
- Would it make it easier if we discussed it on those EGs right now?
That way, we'll have some kind of "green light". Alternatively, we can
wait until we sort out the "simpler" send and synchronous receive cases?

* I wonder whether a good way forward might be for Reza or John or both
jointly, to come up with a detailed proposal.
- Sounds like a good idea. John and I can actually arrange face-to-face
meetings if he is up for it. It's up to you if you want to stay involved
right now. I think its a good idea to have a conference call to
bootstrap things. After that, John and I can work out the details and
keep you involved as it makes sense. I imagine we should be able to come
up with something in a week or two...

Cheers,
Reza


On 7/29/2011 1:15 PM, Nigel Deakin wrote:
> Reza, (John),
>
> On 25/07/2011 22:57, Reza Rahman wrote:
>> Nigel,
>>
>> Good points worth discussing - specific comments below.
>>
>> I am happy to help with anything. If I had the code handy, I could
>> have donated that to the Java.net project, but we did
>> not go further than the design phase with this with all the other
>> things we need to juggle. I can most certainly help by
>> committing code to the reference implementation - ideally it would be
>> good if it was independent of GlassFish, but I
>> don't think that's really practical because of the deep resource
>> dependencies.
>
> What do you mean by "deep resource dependencies"?
>
> At least some of what you have suggested (the injection of
> connections, sessions etc) sounds like a layer on top of the
> "ordinary" JMS API and it ought to be able to implement it in a way
> which works with any JMS provider.
>
> Providing a new way of performing asynchromous callbacks in a Java EE
> container (and I'm still unsure what the case is for that) would be
> more intrusive as it would need to plug in more explicitly to the
> transaction manager, JCA adapter etc.
>
>>
>> * We've reduced the number of lines of code, but have we actually
>> made the API easier to understand?
>> - One of the fundamental assumptions for us approaching this is that
>> we were not out to replace the JMS API, we just
>> wanted to remove the the boilerplate code. In my mind, using these
>> abstractions should not excuse you from not
>> understanding what might be going on behind the scenes - at least at
>> the conceptual level.
>
> I suppose that's the critical issue: what aspects of the JMS API are
> simply artifacts of the API, and what are fundamental concepts?
>
>>
>> That being said, I think that you can indeed use these abstractions
>> without understanding all that is going on behind
>> the scenes. Because of the way the underlying scopes for these are
>> managed, it would actually be fairly difficult to
>> break anything. The basic principle is that you decide what JMS APIs
>> you actually need for your code and simply inject
>> them, specifying an underlying "originating resource" where needed,
>> with the implementation trying to do it's best to do
>> the "right thing" for you - more details on that below.
>
>>
>> Now, that being said, we can certainly get developer feedback on this
>> as well as the perspectives of the other folks on
>> the EG. Getting different perspectives is why we are here, right :-)?
>> We did evaluate other approaches while designing
>> this. The issue was all other approaches had arbitrary abstraction
>> points that inevitably reduced flexibility in
>> addition to reducing boilerplate code.
>>
>> * I presume @Transactional means a local transaction. When is the
>> session being committed?
>> - @Transactional is actually what I envision EJB transactions
>> decoupled from the component model to look like. I was
>> thinking of JTA transactions in a pure Java EE environment for all of
>> this.
>
> JTA transactions in a Java EE environment are currently handled by the
> transation manager, with the transaction demarcation performed either
> by the container (for CMT) or by the application (for UserTrsansaction).
>
> No doubt if the EJB spec replaces CMT with something different then
> whatever we do will fit in with that, but since any change would
> affect all resources, not just JMS, I would expect the initiative for
> such a change to come from the EJB EG (which I know you are on).
>
> As for the UserTransaction API, are you suggesting that this will change?
>
> My hope is that we can make progress in presenting an improved API to
> JMS developers without being dependent on major changes at the EJB or
> platform level.
>
>>
>> I think the only way to make this abstraction work/scale is by making
>> everything scoped to the transaction/thread/method
>> invocation. What this would mean is that no JMS object is actually
>> created on injection. What is injected is really just
>> a proxy. The actual JMS objects are created when the underlying
>> transaction starts and are destroyed when the
>> transactions ends. What this would mean is that the actual JMS
>> resources would enlist with the underlying JTA
>> transaction and commit with it. The implementation would know what
>> interdependent objects it needs and would try it's
>> best to resolve them by looking at the objects in the current scope.
>> For example, if a message sender is being used, we
>> will need to see if we already have usable session in the current
>> scope. How intelligent this automatic resolution need
>> be we can certainly debate that.
>>
>> In my simple example here is what would happen:
>>
>> @Inject @JmsConnectionFactory("jms/MyConnectionFactory") Session
>> session; // Inject proxy, making sure that the resource
>> actually exists in JNDI.
>> @Inject @JmsDestination("jms/MyQueue") MessageProducer producer; //
>> Inject proxy, making sure that the resource actually
>> exists in JNDI.
>>
>> @Transactional
>> private void send(String messageText) { // JTA transaction started.
>> Message message = session.createTextMessage(messageText); // Actually
>> create the session and store it in the transaction
>> scope. Since we need the connection factory, etc create and store
>> those in the transaction scope too. The metadata would
>> be inherited for any newly created objects.
>> producer.send(message); // Actually create the producer. Since we
>> need a session, see if a suitable one already exists
>> in the transaction as intelligently as possible. In this case, just
>> pick the session that we just stored in the
>> transaction since it doesn't conflict with any meta-data specified
>> for the producer. If a suitable existing resource
>> does not exist, create a new one and store that in the transaction as
>> well. If there are ambiguities, raise an exception.
>> } // JTA transaction will end. Properly close everything that is in
>> the transaction scope when the transaction ends.
>>
>> We could make dependencies more explicit like this:
>>
>> @Inject @JmsConnectionFactory("jms/MyConnectionFactory") Session
>> session;
>> @Inject @JmsConnectionFactory("jms/MyConnectionFactory")
>> @JmsDestination("jms/MyQueue") MessageProducer producer;
>>
>> In a Java EE environment where there is a notion of default
>> resources, we could leave some or all implicit:
>>
>> @Inject Session session;
>> @Inject MessageProducer producer;
>>
>> We could group together resources using qualifiers if needed (rare
>> case in my mind):
>>
>> @Inject @JmsConnectionFactory("jms/MyConnectionFactory") @Group1
>> Session session;
>> @Inject @JmsDestination("jms/MyQueue") @Group1 MessageProducer producer;
>>
>> The alternative to resolving required dependencies in the current
>> scope would be to make all JMS object creation
>> completely orthogonal. I'm not sure this is even desirable let alone
>> necessary or practical. It defeats the entire
>> reason for having connections and sessions in favor of making
>> everything "connectionless". If we need to do that anyways
>> for other reasons (e.g. cloud support) I suppose we could use that
>> API instead.
>>
>> * I think the goal should be to allow a Message to be injected
>> without the need to define a connection factory.
>> - You could. One would be created from the default connection factory
>> -- there is such a notion for MDB already. It
>> would look like this:
>>
>> @Inject TextMessage message;
>> @Inject @JmsDestination("jms/MyQueue") MessageProducer producer;
>>
>> * I'm not sure what scope we have to remove checked exceptions from
>> the existing JMS API without introducing an
>> incompatible change.
>> - Would it really be that difficult to change JMSException from a
>> checked exception to an unchecked exception by having
>> it's parent be RuntimeException? I think it would be a more
>> troublesome change if we needed to change an unchecked
>> exception to a checked exception. I know that it would be
>> unprecedented in the JCP, but as far as I can see, wouldn't
>> this be almost 100% backwards compatible? The only issue would be
>> that people that currently catch runtime exceptions
>> would now get JMS exceptions too, but that kind of code is usually
>> pretty generic anyway.
>
> I don't know. I can definitely see the attraction, and certainly don't
> think we should rule it out without more discussion.
>
> As you say, I don't think it would require applications to change
> their code (unless I've missed something) and JMS providers or
> applications which need to catch this particular exception (or its
> subclasses) can continue to do so.
>
> Since this is such a major issue I'll raise a separate JIRA for it and
> we can consider it directly.
>
>>
>> * We couldn't offer this in a Java EE application without changing
>> the platform restrictions that prevent applications
>> creating async listeners.
>> - In our case, we would have simply continued to do what we do for
>> MDBs today. In a more generic sense, yes - you would
>> have to remove that restriction. I think it's somewhat an artificial
>> restriction anyway since I can't see the actual
>> technical reasoning behind it other than maybe trying to have very
>> tight control over the application server thread pool.
>
> I suspect another reason is that if a MessageListener was registered
> directly then
>
> (1) the inbound message could not particpate in a global transaction.
>
> (2) code in the onMessage method would not be running in a proper Java
> EE environment. Neither CMT or BMT transactions would work, for example.
>
>> * Can you say a bit more about what you see as the problem here?
>> - The basic issue is portability across Java EE containers. Since
>> there isn't a standard way to define these resources,
>> you have to do it in a vendor-specific manner. As a side effect, you
>> have to re-learn exactly how each container defines
>> JMS resources. If we get the JMS pluggability contract nailed down,
>> we can actually define @DataSourceDefinition style
>> annotations/metadata to make things far more portable/usable.
>
> By "JMS pluggability contract" do you mean
> (JMS_SPEC-25) Standardise the interface between a JMS provider and a
> Java EE application server ?
>
> On the subject of resource definition, I spent some time with the Java
> EE spec leads (Linda and Bill) discussing how an application could
> define enough information to allow the container to create the JMS
> (and other) resources (destinations and connection facxtories) it needed.
>
> For those who haven't seen this, it's here:
> http://java.net/attachments/lists/javaee-spec/jsr342-experts/2011-07/36/ResourceConfiguration.pdf
>
>
> I've read your comments on that proposal (in the Java EE EG). Do you
> think this would address the issue syou mention?
>
> OK. Now what next?
>
> I think the greatest consensus is for annotations (probably, but not
> necessarily, using CDI) which would hide the boilerplate code (and
> perhaps some of the intermediate objects) for sending messages and for
> synchronously receiving messages. You've given some examples, and I
> know that John has some something similar.
>
> From what I've heard so far, it would be possible to define something
> which would essentially sit on top of the existing JMS API and,
> because it was non-intrusive (or only requising monor new features),
> would work in a Java EE container and make use of all its services
> (including resource injection).
>
> Anything involving async message consumption would be much more
> intrusive as we would need to work out how to integrate it with the
> JCA adapter and TM, and tackle to question of whether how this related
> to MDBs and their future. Whilst I'm not trying to rule anything out,
> I see this as being a much bigger piece of work, and one which would
> involve both the platform and EJB EGs.
>
> Therefore, I wonder whether a good way forward might be for Reza or
> John or both jointly, to come up with a detailed proposal for
> sending/sync receive case, but not the async case, which the EG could
> then discuss in detail. What do you think? I'm happy to stay
> involved. If it would help, the three of us could arrange a conference
> call next week to discuss getting a proposal together...
>
> Nigel
>
>
>
>>
>> Now, as an aside we can actually do almost all of this using just JSR
>> 330 annotations and no CDI at all. The only actual
>> CDI annotation in this design is @Observes. If we are so inclined, we
>> define something like @Receives:
>>
>> public void listenToSomeMessage(@Receives
>> @JmsDestination("jms/SomeQueue") Message someMessage)
>>
>> This would enable people that don't want to implement CDI to still
>> implement this API. Technically, that is possible
>> albeit most of this is easiest to implement using CDI and CDI is
>> already part of Java EE.
>>
>> Let me know if I missed something. I tried to be complete without
>> being overly verbose.
>>
>> Cheers,
>> Reza
>>
>>
>> On 7/25/2011 3:46 PM, Nigel Deakin wrote:
>>> Reza,
>>>
>>> Thank you for your helpful reply. I'd welcome any other responses to
>>> my initial message - as I said I don't want to
>>> lose sight of what problems we're trying to solve.
>>>
>>> But I do have some questions about your suggestions below - most of
>>> them still high-level, along the lines of "what
>>> problems are we trying to solve, and to what extent does this help
>>> us solve them".
>>>
>>> I'd like to work towards getting some proposals together for the EG
>>> to consider. Can you help me with this? I'll
>>> contact you directly.
>>>
>>> Nigel
>>>
>>>
>>> On 22/07/2011 00:04, Reza Rahman wrote:
>>>> Nigel,
>>>>
>>>> Firstly, I'm glad we are finally getting to this. You initial
>>>> analysis/approach looks very sound I think.
>>>>
>>>> Below are specific responses. I am trying to be brief on purpose to
>>>> try to respect readers' time. So if anything
>>>> requires further explanation, please let me know and I am more than
>>>> happy to follow-up as needed. With all due respect,
>>>> I'll also ignore some of the questions you posed because I do not
>>>> think they require a direct answer at this point. If I
>>>> am mistaken, please do tell me so.
>>>>
>>>> I do not think it is necessary to change the semantics of the
>>>> existing JMS API too much. It is a compact, successful,
>>>> good general purpose API. It is also possible to solve all the
>>>> issues you pointed out simply via CDI because CDI is
>>>> designed to solve the exact problems we are talking about -- namely
>>>> eliminating boilerplate code while still maintaining
>>>> a high degree of flexibility.
>>>>
>>>> The best way to see why is unfortunately by diving into the
>>>> details. As an aside, we initially thought the Seam JMS
>>>> Module was very promising in demonstrating how this could be done
>>>> but seemed to have gotten a bit hazy somewhere along
>>>> the road (granted the module is still being actively evolved). That
>>>> is what forced us to come up with our own design for
>>>> Resin (that being said perhaps we should have tried to provide
>>>> direct feedback to the Seam JMS Module team as well; in
>>>> addition, I do understand that the project is driven by community
>>>> volunteers and not dedicated commercial engineering
>>>> staff).
>>>>
>>>> Let's take your message send code as an example. With CDI, that
>>>> code could look like the following:
>>>>
>>>> @Inject @JmsConnectionFactory("jms/MyConnectionFactory") Session
>>>> session;
>>>> @Inject @JmsDestination("jms/MyQueue") MessageProducer producer;
>>>>
>>>> @Transactional
>>>> private void send(String messageText) {
>>>> Message message = session.createTextMessage(messageText);
>>>> producer.send(message);
>>>> }
>>>
>>> We're only using the Session object here because it has the factory
>>> methods that create Message objects, even though
>>> the resulting Message objects may be used by any Session. However in
>>> the first @Inject statement, the Session object
>>> is the one which we're using to define the connection factory. This
>>> strikes me as being potentially confusing for
>>> anyone who is not already familiar with the underlying API and who
>>> doesn't already know that the session is, under the
>>> covers, also being used to create a producer, and it is the producer
>>> which is actually linked to the connection
>>> factory. We've reduced the number of lines of code, but have we
>>> actually made the API easier to understand?
>>>
>>> I presume @Transactional means a local transaction. When is the
>>> session being committed?
>>>
>>> In a Java EE application we'd normally not be able to use
>>> @Transactional (which I presume means a local transaction)
>>> but would use the standard CMT/BMT mechanisms to commit the
>>> transaction.
>>>
>>>> If we really wanted to get crazy about it, we could even inject the
>>>> message to be sent. The code would be like this:
>>>>
>>>> @Inject @JmsConnectionFactory("jms/MyConnectionFactory")
>>>> TextMessage message;
>>>> @Inject @JmsDestination("jms/MyQueue") MessageProducer producer;
>>>>
>>>> @Transactional
>>>> private void send(String messageText) {
>>>> message.setText(messageText);
>>>> producer.send(message);
>>>> }
>>>
>>> This hides the factory methods that creates a Message from a
>>> Session, but still expects the application to specify a
>>> connection factory in the declaration of the Message. I know why, of
>>> course, but if we were following this approach I
>>> think the goal should be to allow a Message to be injected without
>>> the need to define a conneciton factory.
>>>
>>>>
>>>> We can make all of this happen with CDI alone. The only change in
>>>> the basic JMS API that would be required would be
>>>> getting rid of the checked exceptions that I don't think add much
>>>> value in the first place.
>>>
>>> As I wrote in my email, the need to handle JMSException everywhere
>>> complicates the API. However I'm not sure what
>>> scope we have to remove checked exceptions from the existing JMS API
>>> without introducing an incompatible change.
>>> (Suggestions welcome).
>>>
>>> > Now, with CDI you could also
>>>> inject any intermediate JMS object that you wish. So you could
>>>> inject connection factories, connections, connection
>>>> meta-data, message consumers, queue browsers, temporary queues,
>>>> temporary topics and so on. The CDI runtime would be
>>>> aware of all of the intermediate objects anyway so it would be
>>>> trivial to make them available for injection/resolve them
>>>> from the correct scope.
>>>
>>> I think the key to the success of this would be whether we are
>>> actually removing the need for the user to see some of
>>> these intermediate objects, or whether we are simply hiding the code
>>> that creates one object from another.
>>>
>>>>
>>>> Things can be just as simple/powerful for asynchronous message
>>>> receipt:
>>>>
>>>> public class SomeBean {
>>>> ...
>>>> public void listenToSomeMessage(@Observes
>>>> @JmsDestination("jms/SomeQueue") Message someMessage)
>>>> ...
>>>> }
>>>>
>>>> Or at an even higher level of abstraction:
>>>>
>>>> public class SomeBean {
>>>> ...
>>>> public void listenToSomeMessage(@Observes
>>>> @JmsDestination("jms/SomeQueue") String messageText)
>>>> ...
>>>> }
>>>
>>> As you know, we couldn't offer this in a Java EE application without
>>> changing the platform restrictions that prevent
>>> applications creating async listeners. Essentially, the JMS API in
>>> an app server doesn't have a method
>>> setMessageListener(). This makes your suggestion here different from
>>> your earlier examples which would you could think
>>> of as just a layer on top of the existing JMS API, and so we should
>>> perhaps consider this separately.
>>>
>>>>
>>>> Again, this would require no changes to the basic JMS API.
>>>>
>>>> If an implementer wants to make the higher level abstractions
>>>> available in Java SE, they can easily do this themselves.
>>>> If we absolutely insist that this is necessary, it would be easy to
>>>> get the CDI EG to provide better support for Java SE
>>>> since they are going in that direction anyway. None of the
>>>> underlying capabilities required to support the abstractions
>>>> are really Java EE specific. For example, we plan on making all of
>>>> this possible in Java SE via our CDI-based embedded
>>>> container. For those familiar with Spring and not embedded
>>>> containers in the CDI/Java EE realm, this is basically the
>>>> same as what Spring does in Java SE.
>>>>
>>>> Not being able to define JMS resources in a standard way is a
>>>> problem. This is especially the case since it is possible
>>>> to do so today for JDBC resources:
>>>> http://blogs.oracle.com/Lance/entry/introducing_the_datasourcedefinition_annotation.
>>>> I imagine we can solve this once the JCA pluggability issue is
>>>> resolved properly. We can have something like
>>>> @QueueDefinition, @TopicDefinition, @ConnectionFactoryDefinition
>>>> and so on similar to @DataSourceDefinition.
>>>
>>> Can you say a bit more about what you see as the problem here?
>>>
>>> I've been having some discussions with the Java EE platform spec
>>> leads about improving the ways that resources are
>>> defined in Java EE applications.
>>>
>>> Nigel
>>>
>>>>
>>>> Again, I am happy to follow up on any of this if it is needed.
>>>>
>>>> Cheers,
>>>> Reza
>>>>
>>>>
>>>> On 7/21/2011 1:00 PM, Nigel Deakin wrote:
>>>>> I logged the following issue:
>>>>> http://java.net/jira/browse/JMS_SPEC-33
>>>>>
>>>>> This is a placeholder for this goal I proposed some time ago for
>>>>> JMS 2.0, and which received support from EG members:
>>>>> "We should provide a modern, easier-to-use API, probably using
>>>>> annotations and CDI. There seemed to be a variety of
>>>>> ideas of how we might do this, and we will need to explore these
>>>>> in detail. Whilst I think we mostly see this as a
>>>>> feature for Java EE containers, there seems to be interest in
>>>>> offering features to those using a Java SE environment
>>>>> as well."
>>>>>
>>>>> There has been some discussion already about this, but I'd like to
>>>>> go back a few steps to discuss what we are trying
>>>>> to achieve, and how we might achieve it, and where technologies
>>>>> like annotations and CDI might fit in.
>>>>>
>>>>> One of the reasons I'm doing this is that although we have some
>>>>> Java language and CDI experts in this EG, I know from
>>>>> talking to individuals that the level of knowledge in this group
>>>>> is variable. I hope the "experts" take this as a hint
>>>>> that they should be prepared to help teach the others...
>>>>>
>>>>> Also, I want to avoid us saying "CDI is the solution, now what's
>>>>> the problem" and, in particular, make sure that we
>>>>> don't simply use CDI as a way to hide the complexities of the JMS
>>>>> API when we could be eliminating those complexities,
>>>>> not hiding them.
>>>>>
>>>>> I also think we need to discuss the extent to which any
>>>>> improvements could be offered to Java SE applications as well
>>>>> as those running Java EE. Although it is tempting to instinctively
>>>>> define our goal as offering the same improvements
>>>>> to both, I think there's much greater scope to offer improvements
>>>>> to Java EE applications, given that Java EE is by
>>>>> definition intended to make application development simpler and
>>>>> already offers a significantly simpler experience of
>>>>> using JMS than Java SE. At the every least, the different nature
>>>>> of the two environments will by definition mean the
>>>>> way that JMS is used will always be different in each.
>>>>>
>>>>> One thing we should bear in mind is that the JMS API wasn't really
>>>>> designed with Java EE in mind. Java EE already
>>>>> imposes significant restrictions on how the API can be used, and
>>>>> we might want to consider whether this offers
>>>>> opportunities to simplify the API for such users.
>>>>>
>>>>> WHAT'S THE PROBLEM WITH THE JMS API?
>>>>> ------------------------------------
>>>>>
>>>>> I'd like to start with discussion of the API and what is wrong
>>>>> with it, before we get on to possible solutions. What
>>>>> are the main problems with the JMS API at present which make it
>>>>> more difficult to use than it should?
>>>>>
>>>>> I think the starting point is that the JMS API is rather more
>>>>> cumbersome than it need to be, with a lot of boilerplate
>>>>> code needed to send or receive a single message. Here is how the
>>>>> existing JMS spec expects you to write a method which
>>>>> sends a String:
>>>>>
>>>>> private void send(String messageText) throws NamingException,
>>>>> JMSException {
>>>>> Properties props = new Properties();
>>>>> InitialContext ic = new InitialContext(props);
>>>>> ConnectionFactory connectionFactory = (ConnectionFactory)
>>>>> ic.lookup("myConnectionFactory");
>>>>> Connection connection = connectionFactory.createConnection();
>>>>> try {
>>>>> Session session = connection.createSession(false,
>>>>> Session.AUTO_ACKNOWLEDGE);
>>>>> Destination destination = (Destination) ic.lookup("MyQueue");
>>>>> MessageProducer producer = session.createProducer(destination);
>>>>> Message message = session.createTextMessage(messageText);
>>>>> producer.send(message);
>>>>> } finally {
>>>>> if (connection!=null) connection.close();
>>>>> }
>>>>> }
>>>>>
>>>>> That is indeed a lot of boilerplate code (i.e. code that has to be
>>>>> included in many places with little or no
>>>>> alteration). It also throws two Exceptions which need to be
>>>>> handled somehow. In addition the administrator is expected
>>>>> to use provider-specific tools to bind suitable Connection and
>>>>> Destination objects in JNDI.
>>>>>
>>>>> In a Java EE container, resource injection allows things to be
>>>>> simplified a little by removing the need to create an
>>>>> InitialContext and replacing the JNDI lookups with @Resource
>>>>> annotations. This means that NamingException no longer
>>>>> needs to be explicitly handled.
>>>>>
>>>>> @Resource(name="myQueue") Destination destination;
>>>>> @Resource(name="myConnectionFactory") ConnectionFactory
>>>>> connectionFactory;
>>>>>
>>>>> private void send(String messageText) throws JMSException {
>>>>> Connection connection = connectionFactory.createConnection();
>>>>> try {
>>>>> Session session = connection.createSession(false,
>>>>> Session.AUTO_ACKNOWLEDGE);
>>>>> MessageProducer producer = session.createProducer(destination);
>>>>> Message message = session.createTextMessage(messageText);
>>>>> producer.send(message);
>>>>> } finally {
>>>>> if (connection!=null) connection.close();
>>>>> }
>>>>> }
>>>>>
>>>>> This still requires a JMSException to be handled, and the
>>>>> administrator is still expected to use provider-specific
>>>>> tools to bind suitable Connection and Destination objects in JNDI.
>>>>>
>>>>> Almost identical issues arise if you write code to synchronously
>>>>> consume a message. Let's leave asynchronously
>>>>> consuming messages (via MessageListeners and MDBs until a little
>>>>> later).
>>>>>
>>>>> So, what are the problems here?
>>>>>
>>>>> PROBLEMS
>>>>> --------
>>>>>
>>>>> 1. The need to create several intermediate objects which we might
>>>>> use only once and not use again. In the above
>>>>> example, the Connection, Session, MessageProducer and TextMessage
>>>>> objects will never be used again after this method
>>>>> returns (though in other scenarious they might).
>>>>>
>>>>> 2. The need to tidy up resources after use. In practice, this
>>>>> means calling Connection.close() after use, ideally in a
>>>>> finally block. Whether this physically releases resources or
>>>>> simply returns the connection to a pool, if we don't call
>>>>> this method we will eventually run out of either resources or
>>>>> connections in the pool.
>>>>>
>>>>> 3. The rather redundant arguments to connection.createSession().
>>>>> In a Java SE container we have two arguments when one
>>>>> would do, and in a Java EE EJB or web container they're ignored.
>>>>>
>>>>> 4. The dependence on JNDI as a means to isolate provider-specific
>>>>> connection factory and destination configuration
>>>>> from the portable application (which is currently a fundamendal
>>>>> fature of JMS, so this dependence is currently by
>>>>> design).
>>>>>
>>>>> EXISTING DIFFERENCES BETWEEN JMS API in SE and EE
>>>>> -------------------------------------------------
>>>>>
>>>>> Although it is desirable to keep the JMS API the same when in a
>>>>> Java SE and a Java EE environment, I think we should
>>>>> recognise that the API within the Java EE EJB or web container is
>>>>> already significantly simpler than the full JMS API
>>>>> and would be easier to simplify further. Here are some of the
>>>>> things that we might be able to simplify in a Java EE
>>>>> environment.
>>>>>
>>>>> (I should point out that I'm just trying to provoke discussion
>>>>> here and not trying to make specific proposals)
>>>>>
>>>>> - Connections (as objects exposed to applications) are of limited
>>>>> use, other than to create a single Session. For
>>>>> example, each Connection is limited to one Session, so there is no
>>>>> point in having separate Connection and Session
>>>>> objects. The methods setClientID(), setExceptionListener() and
>>>>> stop() are forbidden. This leaves start() as just about
>>>>> the only useful method remaining on a Connection (and then only
>>>>> when consuming messages). So do we really need to
>>>>> expose Connections to the application at all? (Note that Java EE
>>>>> connection pooling means the application doesn't need
>>>>> to keep instances around purely to avoid the cost of creating them).
>>>>>
>>>>> - Sessions are also of limited use, other than to create producers
>>>>> and consumers. Transactions are managed by the
>>>>> transaction manager, so we don't need commit() or rollback().
>>>>> Client acknowledgement is forbidden, so we don't need
>>>>> acknowledge(). This mainly leaves createMessage() and the other
>>>>> factory methods for messages, which have no particular
>>>>> need to be on the Session object at all. So if we move these
>>>>> factory methods somewhere else, do we need to expose
>>>>> Sessions to the application at all? Sessions have one further
>>>>> important function in JMS: the resources of a session
>>>>> may only be used by a single thread at a time. Any change to hide
>>>>> the Session from the application should not break
>>>>> this restriction or prevent the application observing it.
>>>>>
>>>>> - MessageProducers are obviously useful for sending messages. But
>>>>> do we need to expose a MessageProducer object to the
>>>>> application, other than to allow us to call send() once? The main
>>>>> purpose of a MessageProducer, other than
>>>>> representing a tuple of <destination, deliveryMode, priority,
>>>>> timeToLive> is that it defines JMS message order. So we
>>>>> can't make this object disappear, though we can perhaps make it
>>>>> invisible to the application by defining some rules
>>>>> such as when the order of repeated calls to send() is honoured by
>>>>> the JMS provider.
>>>>>
>>>>> - MessageConsumers represent the tuple <destination,
>>>>> messageSelector>, and for durable topic subscriptions
>>>>> <subscriptionName, clientId> as well. For a queue there is no
>>>>> particular difference between one MessageConsumer
>>>>> instance and another (for the same <destination,
>>>>> messageSelector>). However for a topic the object identity of the
>>>>> MessageConsumer is significant in that each instance receives a
>>>>> copy of all the messages received on the topic, so we
>>>>> probably need to continue to expose this object to the
>>>>> application, at least for synchronous message consumption
>>>>> (let's talk about async message consumption separately).
>>>>>
>>>>> - Messages (and their subclasses) are essentially wrappers for the
>>>>> message payload which allow the application to
>>>>> define user-defined message properties which can be used by
>>>>> message selectors, and one or two header properties such
>>>>> as JMSReplyTo and JMSCorrelationID. Whilst these continue to be
>>>>> needed, perhaps we could provide an simpler API which
>>>>> allows a payload to to be passed directly for use by applications
>>>>> which don't need them.
>>>>>
>>>>> Note that since most of the simplfications suggested above are
>>>>> only possible in a Java EE EJB or web container, we
>>>>> would be introducing a different API in Java EE as for Java SE.
>>>>> However it could be argued that we *already* have a
>>>>> different API in a Java EE EJB or web container (with resource
>>>>> injection, 1 session per connection, forbidden methods,
>>>>> connection pooling, etc) but just don't explain this in the JMS
>>>>> spec and javadocs, much to the confusion of
>>>>> application developers.
>>>>>
>>>>> ASYNC MESSAGE CONSUMPTION
>>>>> -------------------------
>>>>>
>>>>> Now let's talk about asynchronous message consumption. We need to
>>>>> consider this separately because this is the feature
>>>>> which *already* has a completely different API in a Java SE
>>>>> environment and in a Java EE EJB or web container (even
>>>>> though the JMS spec doesn't mention this at all).
>>>>>
>>>>> In a Java SE environment (or the Java EE application client
>>>>> container), message may be consumed asynchronously by
>>>>> creating a MessageConsumer as described above, and then calling
>>>>> MessageConsumer.setMessageListener() to register a
>>>>> MessageListener with an onMessage() method.
>>>>>
>>>>> In a Java EE EJB or web container, the use of
>>>>> MessageConsumer.setMessageListener() is explicitly forbidden (Java
>>>>> EE 6
>>>>> Platform Spec section EE.6.7). Instead, the only means provided
>>>>> for asynchronous message consumption is the
>>>>> message-driven bean (MDB). Since this was defined in the EJB spec
>>>>> rather than the JMS spec this is defined
>>>>> declaratively, using either deployment descriptors or annotations.
>>>>> Here's a simple example using annotation:
>>>>>
>>>>> @MessageDriven(mappedName = "jms/inboundQueue")
>>>>> public class NewMessageBean implements MessageListener {
>>>>> public void onMessage(Message message) {
>>>>> System.out.println("Received a message");
>>>>> }
>>>>> }
>>>>>
>>>>> Where "jms/inboundQueue" is the JNDI name where the queue object
>>>>> can be obtained. Additional information, such as the
>>>>> message selector, can be specified using the activationConfig
>>>>> element of the MessageDriven annotation:
>>>>>
>>>>> @MessageDriven(mappedName = "jms/inboundQueue", activationConfig = {
>>>>> @ActivationConfigProperty(
>>>>> propertyName = "messageSelector",
>>>>> propertyValue = "JMSType = 'car' AND color = 'blue'"),
>>>>> @ActivationConfigProperty(propertyName = "destinationType",
>>>>> propertyValue = "javax.jms.Queue")
>>>>> })
>>>>>
>>>>> The above examples are for GlassFish, and there does appear to be
>>>>> a problem in that the EJB 3.1 spec is distinctly
>>>>> vague about how a MDB is defined. The relevant sections are
>>>>> 5.4.15, 5.4.16 and 5.4.17.1. The only activation config
>>>>> properties defined are acknowledgeMode (only used when
>>>>> transactions are bean-managed, and which must be either
>>>>> Auto-acknowledge or Dups-ok-acknowledge), messageSelector,
>>>>> destinationType (which must be must be either
>>>>> javax.jms.Queue or javax.jms.Topic) and subscriptionDurability
>>>>> (which must be either Durable or NonDurable). But it
>>>>> doesn't specify how the destination is defined or, when
>>>>> subscriptionDurability is Durable, how the subscription name
>>>>> and clientId are defined.
>>>>>
>>>>> The JCA 1.6 spec has some additional guidance, at least for MDBs
>>>>> that use a resource adapter. Section B2 states thatr
>>>>> providers are "strongly encouraged" to provide the properties
>>>>> mentioned above and also destination, subscriptionName
>>>>> and clientId, with destination and destinationType as "required"
>>>>> properties.
>>>>>
>>>>> Whatever else we do, there seems to be a clear need to make these
>>>>> mandatory for JMS MDBs, whether or not they use JCA,
>>>>> so I've logged this separately as
>>>>> http://java.net/jira/browse/JMS_SPEC-30 and we've alreay started
>>>>> discussing the
>>>>> details separately in the thread for that issue.
>>>>>
>>>>> But it seems to me that the existing MDB feature already addresses
>>>>> a lot of the API problems I listed in the section
>>>>> "PROBLEMS" above.
>>>>>
>>>>> 1. There's no creation of intermediate objects which have no real
>>>>> purpose. Indeed no objects are exposed to the
>>>>> application at all apart from the incoming message itself.
>>>>>
>>>>> 2. There's no need for the application to close or tidy up
>>>>> resources after use.
>>>>>
>>>>> 3. There's no need for the user to use the problematical
>>>>> createSession() method
>>>>>
>>>>> 4. The only potential complexity this leaves, of the four I listed
>>>>> above, is the need to define the queue or topic as
>>>>> an administered object in JNDI - though strictly speaking since
>>>>> the configuration properties are not fully
>>>>> standardised it might be possible to avoid even this, if we think
>>>>> it beneficial.
>>>>>
>>>>> What other "problems" with MDBs does this leave? I can think of a
>>>>> few possible ones:
>>>>>
>>>>> * Reliance on MessageListener interface. You can't simply annotate
>>>>> any arbitrary method as the callback.
>>>>>
>>>>> * You can only have one callback per MDB class
>>>>>
>>>>> * Other types of bean such as stateless session beans and
>>>>> singleton beans can't consume messages asynchronously
>>>>>
>>>>> * MDBs can't be used in a Java SE environment (or the Java EE
>>>>> application client). In those environments you're back
>>>>> to using the raw JMS API.
>>>>>
>>>>> * Any others?
>>>>>
>>>>> We can certainly think of how we might make MDBs easier to use or
>>>>> more flexible. We can also think of how the changes
>>>>> currently being considered in the EJB 3.2 EG offer opportunities
>>>>> for generaising MDBs.
>>>>>
>>>>> However it seems to me that MDBs already go a long way to offering
>>>>> a simple API to applications, and that our real
>>>>> priority is to make it easier and simpler to *send* messages and
>>>>> to consume them *synchronously*.
>>>>>
>>>>> CDI
>>>>> ---
>>>>>
>>>>> So far I've not mentioned CDI (JSR 299). This is part of Java EE 6
>>>>> and is already built-in to a Java EE container, so
>>>>> long as you define a beans.xml file in your application.
>>>>>
>>>>> What does this give us? As I write at the start I'm hoping that
>>>>> other EG members can help share their knowledge on
>>>>> this, but as far as I can see it:
>>>>>
>>>>> 1. Provides a way to offer a simplified API which is simply a
>>>>> wrapper on top of the JMS API, effectively replacing
>>>>> boilerplate factory code with annotations which inject objects.
>>>>>
>>>>> 2. Provides a way to define the "scope" of a object, so that
>>>>> close() can be called automatically when it falls out of
>>>>> scope. Scopes might also allow us to define the circumstances when
>>>>> repeated calls to some new send method use the same
>>>>> MessageProducer, and when they use different MessageProducers
>>>>> (important for message order).
>>>>>
>>>>> 3. Offers an internal async event mechanism which has some
>>>>> similarity with async messages.
>>>>>
>>>>> CDI is not built into Java SE, and the existing CDI spec doesn't
>>>>> require implementations to support Java SE
>>>>> environments, though this may change. However any CDI-based API in
>>>>> Java SE may need to be significantly different from
>>>>> a CDI-based API in Java EE because Java SE does not support
>>>>> resource injection. Also, any API for use in Java SE will
>>>>> need to reflect the additional features available in SE (local
>>>>> transactions, client ack, multiple sessions per
>>>>> connection etc).
>>>>>
>>>>> ANNOTATIONS
>>>>> -----------
>>>>>
>>>>> We shouldn't forget that annotations don't have to use CDI. Just
>>>>> like with MDBs, if we want to pass information to the
>>>>> container using annotations we can simply define the annotations
>>>>> we want.
>>>>>
>>>>> WHAT NEXT?
>>>>> ---------
>>>>>
>>>>> I'm not trying to make any proposals at this stage. The purpose of
>>>>> this email was to raise the issues that I think we
>>>>> need to consider as part of doing that. In particular:
>>>>>
>>>>> 1. What do *you* think needs to be improved in the JMS API?
>>>>>
>>>>> 2. To what extent should we be trying to simplify the plain Java
>>>>> API, especially in a Java EE environment when a
>>>>> significant proportion of it is redundant anyway?
>>>>>
>>>>> 3. How might the use of annotations (not necessarily CDI) make the
>>>>> JMS API simpler?
>>>>>
>>>>> 4. How might CDI make the JMS API simpler?
>>>>>
>>>>> 5. If we do try to hide complexities behind CDI, will users have
>>>>> to be aware of what is happening behind the scenes
>>>>> and occasionally dip into using some of the hidden objects? If so,
>>>>> are we really making this simpler?
>>>>>
>>>>> 6. Is it possible to provide similar benefits to plain Java SE
>>>>> applications as to Java EE applications, or are the
>>>>> environments just too different, bearing in mind the existing
>>>>> differences between JMS in Java EE and Java SE?
>>>>>
>>>>> I look forward to the discussion.
>>>>>
>>>>> Nigel
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>>> -----
>>>>> No virus found in this message.
>>>>> Checked by AVG - www.avg.com
>>>>> Version: 10.0.1390 / Virus Database: 1518/3778 - Release Date:
>>>>> 07/21/11
>>>>>
>>>>>
>>>>
>>>>
>>>
>>>
>>> -----
>>> No virus found in this message.
>>> Checked by AVG - www.avg.com
>>> Version: 10.0.1390 / Virus Database: 1518/3787 - Release Date: 07/25/11
>>>
>>>
>>
>
>
> -----
> No virus found in this message.
> Checked by AVG - www.avg.com
> Version: 10.0.1390 / Virus Database: 1518/3793 - Release Date: 07/28/11
>
>