The only way how to send a JMS message that participates in the current transaction from a meesage driven bean is to use transactional connection factory which is bound in JNDI unde java:/QpidJMSXA. The problematic code is: @Resource(mappedName = "java:/QpidJMSXA") private ConnectionFactory connectionFactory; @Resource(mappedName = "queue/mrg_mrg_jca_mdb_transactions_out") private Destination queue; private MessageProducer sender; private Connection connection; private Session session; @PostConstruct public void init() throws Exception { connection = connectionFactory.createConnection(); session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE); sender = session.createProducer(queue); } @Override public void onMessage(Message message) { ... TextMessage response = session.createTextMessage("performance01 " + time + " ACK"); <<-- PROBLEMATIC LINE sender.send(response); ... } On the marked line, the following exception is thrown: Caused by: java.lang.NullPointerException at org.apache.qpid.ra.QpidRASession.createTextMessage(QpidRASession.java:319) at org.jboss.test.mdb.MRGJCAMessageBean.onMessage(MRGJCAMessageBean.java:84) at sun.reflect.GeneratedMethodAccessor295.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at org.jboss.aop.joinpoint.MethodInvocation.invokeTarget(MethodInvocation.java:122) at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:111) at org.jboss.ejb3.interceptors.container.ContainerMethodInvocationWrapper.invokeNext(ContainerMethodInvocationWrapper.java:72) at org.jboss.ejb3.interceptors.aop.InterceptorSequencer.invoke(InterceptorSequencer.java:76) at org.jboss.ejb3.interceptors.aop.InterceptorSequencer.aroundInvoke(InterceptorSequencer.java:62) at sun.reflect.GeneratedMethodAccessor290.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at org.jboss.aop.advice.PerJoinpointAdvice.invoke(PerJoinpointAdvice.java:174) at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102) at org.jboss.ejb3.interceptors.aop.InvocationContextInterceptor.fillMethod(InvocationContextInterceptor.java:72) at org.jboss.aop.advice.org.jboss.ejb3.interceptors.aop.InvocationContextInterceptor_z_fillMethod_28985350.invoke(InvocationContextInterceptor_z_fillMethod_28985350.java) at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102) at org.jboss.ejb3.interceptors.aop.InvocationContextInterceptor.setup(InvocationContextInterceptor.java:88) at org.jboss.aop.advice.org.jboss.ejb3.interceptors.aop.InvocationContextInterceptor_z_setup_28985350.invoke(InvocationContextInterceptor_z_setup_28985350.java) at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102) at org.jboss.ejb3.connectionmanager.CachedConnectionInterceptor.invoke(CachedConnectionInterceptor.java:62) at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102) at org.jboss.ejb3.entity.TransactionScopedEntityManagerInterceptor.invoke(TransactionScopedEntityManagerInterceptor.java:56) at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102) at org.jboss.ejb3.AllowedOperationsInterceptor.invoke(AllowedOperationsInterceptor.java:47) at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102) at org.jboss.ejb3.tx.NullInterceptor.invoke(NullInterceptor.java:42) at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102) at org.jboss.ejb3.stateless.StatelessInstanceInterceptor.invoke(StatelessInstanceInterceptor.java:68) at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102) at org.jboss.aspects.tx.TxPolicy.invokeInCallerTx(TxPolicy.java:126) ... 31 more Unfortunately, this problem blocks MRG-EAP integration and performance test development.
The NPE comes from a line where QpidRASession gets its internal session which is null. But now I realized from my server log, that sometimes it works. I have 15 instances of the same MDB in a pool. First, all 15 failed to send the message. Then after redelivery and 12 failures, one of them succeeded. Maybe it won a battle for a valid session? From other exceptions I saw, I have a feeling that there is an internal limit in JCA adapter to have a single session per connection factory and not per connection. But this is just a wild guess.
You should not construct your connection, session and producer in a PostConstruct method. Sessions are pooled by the underlying JCA layer and as such need to be opened and closed on each use rather than trying to maintain them over successive message deliveries. Example: //Remove @PostContruct public void onMessage(Message message) { Connection conn = null; Session sess = null; Producer p = null; try { conn = connectionFactory.createConnection //Create session, producer here is in your @PostConstruct method } catch(Exception e) { } finally { try { if(p != null) p.close(); }catch(Exception ignore){} try { if(sess != null) sess.close(); }catch(Exception ignore){} try { if(conn != null) conn.close(); }catch(Exception ignore){} }
According to J2EE tutorial, at least creating Connection should be possible in @PostConstruct method http://download.oracle.com/javaee/5/tutorial/doc/bncgw.html Do you have any reference that forbids creating session?
Connection is ok, but you really don't want to do this. Session is not. Sessions are pooled and as such you cannot hold them over message delivery. This is common knowledge in general EE development and is tantamount to using a JDBC/JCA DataSource.
I fully understand your point of view. It is very sane not to chache pooled resources. However, I'm looking for a specification that forbids it for a simple purpose - what if a customer used JCA adapter in that way? We need more than "common knowledge" to explain them that this is not a valid use case...
Please read: http://community.jboss.org/wiki/ShouldICacheJMSConnectionsAndJMSSessions and close this issue.
Hmmm, nice. I already said that I understand this. I know that there is cache for connections and sessions in JCA adapter. However, there is nothing that forbids my approach in the specification. This means that a customer might want us to support this. So we need to document this. How could I rise a documentation type issue/bug for MRG JCA adapter?
'However, there is nothing that forbids my approach in the specification. ' There is nothing to forbid you from caching JDBC connections either, you simply don't do this if you want your application to work correctly. This is well known in the industry and is simply a error on the part of the developer. 'This means that a customer might want us to support this.' There is no 'support' for this as it makes no sense and does not work for Stateless components (i.e. Stateless Session Beans and MessageDrivenBeans). If you want this behavior, use a STATEFUL Session bean, not an SLSB or an MDB. Again, this is NOT a defect.
Note, the 'caching' part of this is provided by JCA is the form of a connection pool. THIS is why you don't cache JCA resources since it's already provided!
And for something more definitive, from the JCA specification Section 6.4.1 6. After the component finishes with the connection, it closes the connection using the close method on the Connection interface. cx.close(); 7. If an application component fails to close an allocated connection after its use, that connection is considered an unused connection. The application server manages the cleanup of unused connections. When a container terminates a component instance, the container cleans up all connections used by that component instance. Refer section Section 6.5.4 “ManagedConnection” and Section 6.8.3 “Scenario: Connection Event Notifications and Connection Close” for details on the cleanup of connections. Note, don't misread this. The JCA infrastructure will close the connection/session for you, but since you are keeping this as a state variable in your MDB instance, you are never getting a new one from the pool and as such, your connection/session handle is invalid at this point. Now please, close this issue.
Strange thing is, that getting a Connection and preserving it in an instance variable is fine works. This is even used in J2EE Tutorial. And according to Comment 11, my connection ahdnle should be invalid as well, which isn't. Even storing JMS Session works with JBoss Messaging. Once obtained Session should not just vanish. It should not be given to another requester while I hold it. The only problem I can think of is that it stores something in a ThreadLocal variable... However, I do not see any point in this argument and I'm closing the issue. There is only a little chance it would cause a trouble later and I gave it a shot...