Arch2Arch Tab BEA.com
Syndicate this blog (XML)

JMS messaging with Spring...nice but there is no magic

Bookmark Blog Post

del.icio.us del.icio.us
Digg Digg
DZone DZone
Furl Furl
Reddit Reddit

Dmitri Maximovich's Blog | October 19, 2005   4:56 PM | Comments (2)


I came across the recent article, published on IBM developerWorks website, about using Spring framework to simplify JMS interaction with IBM WebSphere MQ. Being backbone of any integration system Message-Oriented Middleware (MOM) is used widely in corporate projects and quite often in heterogeneous environment where J2EE server vendor (for example WebLogic) is different from MOM vendor (for example IBM MQ).

While article by itself can serve as reasonably good introduction to JMS support in Spring, there are some important moments which author didn't cover. The fact that Spring being positioned as 'J2EE framework' combined with recent announcement of BEA official support of Spring in WebLogic may lead some developers to believe that code from the article could be transfered without changes into your J2EE application running in WebLogic (probably instead of file-based JDNI most would prefer to use WebLogic startup class to map MQ ConnectionFactories and queues into WebLogic JNDI namespace or map it through support for Foreign JMS providers).

So what we would get if we transfer code from the article as is into J2EE application running in WebLogic? Well, as expected it's going to work - messages getting send and delivered, no exceptions flying around so everything is good at first sight. Until you try to use it in CMT or BMT transactions, say like in the code below, from a session bean:

/**
 * @ejb.bean
 *   type="Stateless"
 *   name="SpringTest"
 *   view-type="local"
 *   transaction-type="Container"
 *
 * @ejb.transaction
 *   type="RequiresNew"
 */
public class SpringTestBean implements SessionBean {
...
  /** @ejb.interface-method */
  public void sendMessage() throws Exception {
    JmsSender jmsSender =  
      (JmsSender)springContext.getBean("jmsSender");
    jmsSender.sendMesage("test");
    // rollback CMT transaction
    sessionContext.setRollbackOnly();
  }
...  
}

One would expect that after transaction rollback message won't be in the MQ but it will. The reason for this is pretty simple - WebLogic need to use special wrappers around MQ ConnectionFactory object to ensure proper resource enlistment into XA transaction context. Just putting object into WebLogic JNDI is not enough. Developer should declare ConnectionFactory via resource-ref element in EJB deployment descriptors:

<resource-ref>
  <res-ref-name>myQcf</res-ref-name>
  <res-type>javax.jms.QueueConnectionFactory</res-type>
  <res-auth>Container</res-auth>
  <res-sharing-scope>Shareable</res-sharing-scope>
</resource-ref>
...
<resource-description>
  <res-ref-name>myQcf</res-ref-name>
  <jndi-name>mq.qcf</jndi-name>
</resource-description>

And than, in Spring context definition, QueueConnectionFactory should refer to name mapped via resource-ref:

    <bean id="jmsQueueConnectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean">
        <property name="jndiName" value="java:comp/env/myQcf"/>
    </bean>

Note that factory looked up in java:comp/env namespace and not in the global JNDI scope. This will ensure that WebLogic uses properly wrapped ConnectionFactory object which is going to participate in global transaction and our example above would work as expected.

Although our example now works this is not very nice, because now all your operations with Spring's JMS objects should be originated from some EJB with properly defined resource-ref. This means that for example developer should be careful not to inject JMSSender as dependency into some class which could be executed not as a part of EJB call sequence (for example scheduler of some sort) or when access to more than one ConnectionFactory is needed. Alternative approach would be to extend Spring's JndiObjectFactoryBean class to enable creation of required wrapper. The problem with this is the wrapper API is not documented as far as I know.

I guess the conclusion is that it's best not just assume that framework would do 'magic' stuff for you and expect everything to work, but always test to make sure it actually works.


Comments

Comments are listed in date ascending order (oldest first) | Post Comment

  • Thanks for pointing out these issues; it's good to be aware of them. Indeed, there is no magic: Even within a Spring-based application, resource references need to be defined correctly, just like they would for a plain J2EE application talking to the same resources.

    Of course, "resource-ref" elements can be declared in "web.xml" as well, so the exact same functionality should be available to plain web applications (WAR deployment units) - not just to EJBs. This is probably the most typical place for Spring applications to tap directly into the application server's services: using Spring-driven transactions with JtaTransactionManager as backend, plus JndiObjectFactoryBean definitions pointing to "resource-ref" JNDI locations (be it a JDBC DataSource or a JMS ConnectionFactory).

    Posted by: juergen.hoeller on October 20, 2005 at 1:59 PM

  • Juergen,

    That's true, you can use the same resource-ref in WAR as well, it will work and it's little bit better in that case because you can specify resource-ref on a global level while in case of EJB it's per bean if I'm not mistaken. Annouing part is that (at least in case of EJB) that EJB has do define these attributes even if it is getting used somewhere deep down the call stack.

    Have to be careful as well if there are multiple ConnectionFactories defined because common practice is to define them under the same 'logical' name in different EJBs, and they can call the same shared components.

    Do you think it would be beneficial to provide special implementation of JndiObjectFactoryBean to auto-wrap ConnectionFactoris in the case of WebLogic (along the lines of WebLogicJTATransactionManager class)?

    Posted by: maximdim on October 20, 2005 at 2:33 PM



Only logged in users may post comments. Login Here.

Powered by
Movable Type 3.31