1 Reply Latest reply on Nov 18, 2005 6:34 AM by tpaterson

    Container managed transactions not working for MDB

    shaileshjboss

      Hi,
      I have a message driven bean(CmtMdb) which updates the database(MS SQL server) & sends the JMS message to another queue(TestMDB2). Another MDB(CmtMdbReceiver) listens to this queue.I am using Container managed transactions & for JMS, JBOSSMQ server is used. As per the spec., you are not needed to commit on jms session or sql Connection when using CMP. In my example, it works only for sql Connection but not for jms Session. For database connection, <local-tx-datasource> is used. The code in the MDB is given below. As the session is not committed, the message is not send to next queue. Can anybody please help me??

      MDB code is as follows :

      private static final String DB_NAME = "java:comp/env/jdbc/test1";
      private static final String INSERT_QUERY = "insert into table1(name, val) values(?,?)";
      private static final String Q2 = "java:comp/env/jms/TestMDB2";
      private MessageDrivenContext m_context = null;

      public void setMessageDrivenContext(MessageDrivenContext context) {
      m_context = context;
      }

      public void onMessage(Message message) {
      try {
      InitialContext initialContext = new InitialContext();
      persistDBData(message, initialContext);
      sendJMSMessage(message, initialContext);
      throwException(message);
      } catch (Throwable t) {
      m_context.setRollbackOnly();
      System.out.println("Transaction will be rolled back...");
      t.printStackTrace();
      }
      }

      private void persistDBData(Message message, Context jndiContext) throws SQLException, NamingException {
      Connection conn = null;
      PreparedStatement stmt = null;

      try {
      conn = getConnection(jndiContext);
      stmt = conn.prepareStatement(INSERT_QUERY);
      stmt.setString(1,"Hello");
      stmt.setInt(2, 100);
      stmt.executeUpdate();
      } finally {
      try {
      stmt.close();
      conn.close();
      } catch(Exception ex) { ex.printStackTrace(); }
      }
      }

      private void sendJMSMessage(Message message, Context jndiContext)
      throws JMSException, NamingException {
      QueueConnection conn = null;
      QueueSession session = null;
      try {
      conn = getQueueConnection(jndiContext);
      Queue q2 = getQueue(Q2, jndiContext);
      session = conn.createQueueSession(true, 0);
      QueueSender sender = session.createSender(q2);
      sender.send(message);
      } finally {
      try { conn.close(); } catch (Exception exc) {exc.printStackTrace();}
      }
      }

      private void throwException(Message message) throws Exception {
      TextMessage textMessage = (TextMessage) message;
      String text = textMessage.getText();
      if ( !(text != null && text.equalsIgnoreCase("success")) ) {
      throw new Exception("Application Exception");
      }
      }

      private Connection getConnection(Context ctx) throws SQLException, NamingException {
      DataSource dataSource = (DataSource)ctx.lookup(DB_NAME);
      Connection conn = dataSource.getConnection();
      return conn;
      }

      private QueueConnection getQueueConnection(Context ctx) throws JMSException, NamingException {
      QueueConnectionFactory qcf = (QueueConnectionFactory)ctx.lookup("java:comp/env/jms/QueueConnectionFactory");
      return qcf.createQueueConnection();
      }

      private Queue getQueue(String queueName, Context ctx) throws JMSException, NamingException {
      Queue queue = (Queue)ctx.lookup(queueName);
      return queue;
      }


      The ejb-jar.xml file is as follows :

      <ejb-jar>
      <enterprise-beans>
      <message-driven>
      <ejb-name>CmtMdb</ejb-name>
      <ejb-class>com.cmt.CmtMdb</ejb-class>
      <transaction-type>Container</transaction-type>
      <message-driven-destination>
      <destination-type>javax.jms.Queue</destination-type>
      </message-driven-destination>
      <resource-ref>
      <res-ref-name>jms/QueueConnectionFactory</res-ref-name>
      <res-type>javax.jms.QueueConnectionFactory</res-type>
      <res-auth>Container</res-auth>
      </resource-ref>
      <resource-env-ref>
      <resource-env-ref-name>jms/TestMDB2</resource-env-ref-name>
      <resource-env-ref-type>javax.jms.Queue</resource-env-ref-type>
      </resource-env-ref>
      <resource-ref>
      <res-ref-name>jdbc/test1</res-ref-name>
      <res-type>javax.sql.DataSource</res-type>
      <res-auth>Container</res-auth>
      </resource-ref>
      </message-driven>

      <message-driven>
      <ejb-name>CmtMdbReceiver</ejb-name>
      <ejb-class>com.cmt.CmtMdbReceiver</ejb-class>
      <transaction-type>Container</transaction-type>
      <message-driven-destination>
      <destination-type>javax.jms.Queue</destination-type>
      </message-driven-destination>
      <resource-ref>
      <res-ref-name>jms/QueueConnectionFactory</res-ref-name>
      <res-type>javax.jms.QueueConnectionFactory</res-type>
      <res-auth>Container</res-auth>
      </resource-ref>
      <resource-ref>
      <res-ref-name>jdbc/test1</res-ref-name>
      <res-type>javax.sql.DataSource</res-type>
      <res-auth>Container</res-auth>
      </resource-ref>
      </message-driven>
      </enterprise-beans>

      <assembly-descriptor>
      <container-transaction>

      <ejb-name>CmtMdb</ejb-name>
      <method-name>*</method-name>

      <trans-attribute>Required</trans-attribute>
      </container-transaction>

      <container-transaction>

      <ejb-name>CmtMdbReceiver</ejb-name>
      <method-name>*</method-name>

      <trans-attribute>Required</trans-attribute>
      </container-transaction>

      </assembly-descriptor>
      </ejb-jar>

      The jboss.xml file is as follows :


      <enterprise-beans>
      <message-driven>
      <ejb-name>CmtMdb</ejb-name>
      <destination-jndi-name>TestMDB1</destination-jndi-name>
      <resource-ref>
      <res-ref-name>jms/QueueConnectionFactory</res-ref-name>
      <jndi-name>java:/ConnectionFactory</jndi-name>
      </resource-ref>
      <resource-ref>
      <res-ref-name>jdbc/test1</res-ref-name>
      <jndi-name>java:/test1</jndi-name>
      </resource-ref>
      <resource-env-ref>
      <resource-env-ref-name>jms/TestMDB2</resource-env-ref-name>
      <jndi-name>queue/TestMDB2</jndi-name>
      </resource-env-ref>
      </message-driven>

      <message-driven>
      <ejb-name>CmtMdbReceiver</ejb-name>
      <destination-jndi-name>TestMDB2</destination-jndi-name>
      <resource-ref>
      <res-ref-name>jms/QueueConnectionFactory</res-ref-name>
      <jndi-name>QueueConnectionFactory</jndi-name>
      </resource-ref>
      <resource-ref>
      <res-ref-name>jdbc/test1</res-ref-name>
      <jndi-name>java:/test1</jndi-name>
      </resource-ref>
      </message-driven>

      </enterprise-beans>

        • 1. Re: Container managed transactions not working for MDB

          If I understand your post and your code correctly -- the problem seems to be to do with the ConnectionFactory you are using..

          if you want your JMS message to be commited(send)/rolled-back as part of the CMP transaction -- you need to use the XA connection factory : java:/JmsXA ..

          otherwise the JMS message will be sent regardless of the outcome of the CMP transaction.