Billy Newport has written about restrictions that J2EE developers face when working with JMS. He explains that when you lookup a JMS provider that was declared in your application server, your code gets back a wrapped version (wrapped connection, wrapper sessions, wrapped everything).
- Posted by: Dion Almaer
- Posted on: November 13 2003 11:26 EST
This wrapper does good stuff (XA, pooling, and policing), but also restricts us:
"Thus, if you want to call the restricted methods such as JMSConnection.setExceptionListener or APIs to do with ConnectionConsumer then these will fail with a compliance exception. Basically, the J2EE spec says you can't call these. When J2EE 1.4 comes along, then JMS providers will have to implement this 'forbidden API' support when they run in a JCA connector.
There is also a restriction of a single JMS session per connection and you can't call Session.setMessageListener. This basically means an application can't do async receiving of messages at all except using MDBs and MDBs are typically too static for the kinds of customers/applications I'm alluding to here."
To get around the problem now, Bill says that you can decouple pulling in messages from processing them, and use a WorkManager to do the processing:
"If you're using WebSphere Enterprise then when a message listener is called on an unmanaged JMS session thread then you should use a WorkManager to process the message on a managed thread before accessing any WebSphere APIs. The pattern here is basically, use one or two sessions to pull the messages in and then execute them on a WorkManager using a pool, i.e. decouple the pulling of the messages from the message processing."
Hopefully J2EE CA 1.5 will solve this problem by getting rid of the need for the wrapper classes.
Read Billy Newport's articles: Why are JMS APIs restricted in J2EE and how to workaround it.
Async Beans Introduction
Are there any other workarounds that you have had to use in practice?
- Opinion: Working around restricted JMS APIs in J2EE by Billy Newport on November 13 2003 12:09 EST
- Opinion: Working around restricted JMS APIs in J2EE by Tom Barnes on November 13 2003 18:05 EST
- Opinion: Working around restricted JMS APIs in J2EE by Billy Newport on November 13 2003 21:27 EST
JCA 1.5 won't solve this 'problem', the wrapper isn't the problem. JCA 1.5 will be cleaner in terms of the contract for XA between the server and the JMS provider. JCA 1.0 and JMS just don't work well together (mismatch between JCA requiring connections to know about XA for transaction affinity but with JMS it's the sessions that know about XA not the connection so oops) but thats another story...
The JMS provider will still enforce these restrictions directly in any case so even with 1.5, it's still the same.
While I agree that some of the concepts in the article are useful, I think the "BUT" below overstates the case a bit:
<snip> But, nevertheless. Some times, a developer wants to do this. The only workaround available to customers is to load the JMS provider directly, i.e. configure some properties in your application for "InitialContextFactory", "URL", "JNDI Name", "UserID", "Password" and directly create a TopicConnectionFactory or QueueConnectionFactory. This basically gives you a unwrapped/altered JMS provider which will allow you to make the forbidden calls. BUT, you will lose XA support and pooling if you do this... </snip>
(1) With any XA capable JMS vendor, one does not lose XA support when loading the JMS provider directly - but what does happen is that the application now has to go through the extra programming step of enlisting the JMS XA resource (obtained via javax.jms.XASession.getXAResource()) with the app server's transaction manager. This is what the pooling wrapper mentioned in the article does for you. (2) The loss of pooling capability due to direct loading is not hard to work-around - there are many ways for apps to set up their own custom pooling. (3) BEA WebLogic specifically provides a configurable JMS "foreign destination wrapper" feature to simplify this type of app, by, for instance, moving the URL into an administratively configured mbean rather than forcing the app to hard-code it somewhere (this feature does not prevent access to "forbidden" APIs).
Tom Barnes, BEA
Of course, the right people can reproduce anything we do as vendors, it's all just code in the end. A better way of stating my point below is that you lose access to the vendor supplied plumbing, XA, pooling etc.
The bottom line and one we're would both happily agree with, is that once you step out of this box, you're dependent on vendor specific APIs/features(as both you and I have pointed out, i.e. your TM and MBean and our WorkManager feature) until the spec catches up and fully supports this kind of application.