4 Replies Latest reply on Aug 27, 2001 7:59 AM by Jim Downing

    Another transaction problem

    Jim Downing Newbie

      Hi,
      I'm afraid that despite all the posts and the documentation on this subject I'm still at sea with a problem with transactions in an MDB.

      I have an MDB that connects to an external socket server. Since the socket server is not a jboss managed resource do the bean need to manage it's own transaction with the socket server?

      When the transaction code runs, I suspect I'm not getting the right transaction - a java.rmi.RemoteException is thrown with the message "Application error: BMT stateless bean LoggingMDB should complete transactions before returning". I thought I had completed the transaction...

      LoggingMDB.java

      package com.paribus.hemlatta.beans.messagedriven;
      
      import java.net.Socket;
      import java.io.ObjectOutputStream;
      
      import javax.ejb.MessageDrivenBean;
      import javax.ejb.MessageDrivenContext;
      import javax.ejb.EJBException;
      
      import javax.jms.MessageListener;
      import javax.jms.Message;
      
      import javax.transaction.UserTransaction;
      
      import org.jboss.tm.TxManager;
      
      import javax.naming.Context;
      import javax.naming.InitialContext;
      import javax.naming.NamingException;
      
      import org.apache.log4j.spi.LoggingEvent;
      import org.apache.log4j.Category;
      import org.apache.log4j.Priority;
      
      public class LoggingMDB implements MessageDrivenBean, MessageListener
      {
       private MessageDrivenContext ctx = null;
      
       public LoggingMDB () { ; }
      
       public void setMessageDrivenContext(MessageDrivenContext ctx) throws EJBException
       {
       this.ctx = ctx;
       }
      
       public void ejbCreate() { ; }
       public void ejbRemove() { ; }
      
       public void onMessage(Message msg)
       {
       System.out.println("Logger got message "+ msg.toString());
      
       try
       {
       Context ic = new InitialContext();
       UserTransaction xa = (UserTransaction)ic.lookup("java:comp/UserTransaction");
      
       String classname = "com.paribus.hemlatta.beans.messagedriven.LoggingMDB";
      
       xa.begin();
       try
       {
       LoggingEvent l = new LoggingEvent(
       classname,
       Category.getInstance(classname),
       Priority.INFO,
       msg,
       null);
       Socket socket = new Socket("localhost",2469);
       ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream());
       out.writeObject(l);
       out.close();
       socket.close();
       xa.commit();
       }
       catch (Exception e)
       {
       xa.rollback();
       e.printStackTrace();
       }
       }
       catch (javax.transaction.NotSupportedException e)
       {
       e.printStackTrace();
       }
       catch (javax.transaction.SystemException e)
       {
       e.printStackTrace();
       }
       catch (NamingException e)
       {
       e.printStackTrace();
       }
       }
      }
      


      Stack Trace
      [LoggingMDB] Logger got message TextMessage@Fri Aug 24 14:32:58 GMT+01:00 2001 #1
      [LoggingMDB] Application error: BMT stateless bean LoggingMDB should complete transactions before returning (ejb1.1 spec, 11.6.1)
      [Container factory] Exception in JMSCI message listener: : java.rmi.RemoteException: Application error: BMT stateless bean LoggingMDB should complete transactions before returning (ejb1.1 spec, 11.6.1)
      [Container factory] java.rmi.RemoteException: Application error: BMT stateless bean LoggingMDB should complete transactions before returning (ejb1.1 spec, 11.6.1)
      [Container factory] at org.jboss.ejb.plugins.MessageDrivenTxInterceptorBMT.invoke(MessageDrivenTxInterceptorBMT.java:161)
      [Container factory] at org.jboss.ejb.plugins.MessageDrivenInstanceInterceptor.invoke(MessageDrivenInstanceInterceptor.java:58)
      [Container factory] at org.jboss.ejb.plugins.SecurityInterceptor.invoke(SecurityInterceptor.java:190)
      [Container factory] at org.jboss.ejb.plugins.LogInterceptor.invoke(LogInterceptor.java:195)
      [Container factory] at org.jboss.ejb.MessageDrivenContainer.invoke(MessageDrivenContainer.java:264)
      [Container factory] at org.jboss.ejb.plugins.jms.JMSContainerInvoker.invoke(JMSContainerInvoker.java:151)
      [Container factory] at org.jboss.ejb.plugins.jms.JMSContainerInvoker$MessageListenerImpl.onMessage(JMSContainerInvoker.java:448)
      [Container factory] at org.jbossmq.SpyMessageConsumer.deliverMessage(SpyMessageConsumer.java:294)
      [Container factory] at org.jbossmq.SpySession.run(SpySession.java:236)
      [Container factory] at org.jboss.jms.asf.StdServerSession.run(StdServerSession.java:131)
      [Container factory] at org.jboss.jms.asf.ThreadPool$Worker.run(ThreadPool.java:128)

      ejb-jar.xml
      <?xml version="1.0"?>
      <!DOCTYPE ejb-jar>
      <ejb-jar>
       <enterprise-beans>
       <message-driven>
       <ejb-name>LoggingMDB</ejb-name>
       <ejb-class>com.paribus.hemlatta.beans.messagedriven.LoggingMDB</ejb-class>
       <message-selector/>
       <transaction-type>Bean</transaction-type>
       <acknowledge-mode>Auto-acknowledge</acknowledge-mode>
       <message-driven-destination>
       <destination-type>javax.jms.Queue</destination-type>
       </message-driven-destination>
       </message-driven>
       </enterprise-beans>
      </ejb-jar>
      


      thanks,
      jim

        • 1. Re: Another transaction problem
          Scott Stark Master

          That error msg only occurs if the container caught an Error thrown from the onMessage() method. Do you know that onMessage() is getting to the point where xa.commit() is called?

          • 2. Re: Another transaction problem
            Peter Antman Expert

            I am not to shure about that, since it is actually the AbstractTXInterceptorBMT that throws the exception, since it falls into the following code block:

            case Status.STATUS_PREPARED:
            String msg = "Application error: BMT stateless bean " +
            container.getBeanMetaData().getEjbName() +
            " should complete transactions before" +
            " returning (ejb1.1 spec, 11.6.1)";
            Logger.error(msg);

            // the instance interceptor will discard the instance
            throw new RemoteException(msg);

            This might be the effect of two things:

            - a bug in the bean we are discussing
            - a bug in the BMT transaction handling.

            I am no transaction expert, but to me it seems strange to start a user transaction, access no transacted resource and making a commit on it, since there will be no transacted resource that will act on the started user transaction. But I do not really know what happend in these situation.

            The other possible problem would be that the JMS message receipt transaction in some way plays trick here. It ought not to do it since I have used BMT:s several time, but I have never started a user transaction.

            //Peter

            • 3. Re: Another transaction problem
              Peter Antman Expert

              I am not really shure if this is the way to do it. One way you will NOT get in this is that the outcome of your socket action should have any effect of the message receipt. In BMT all messages are acknowledge at receipt (or at least you will have to code your bean under that assumption to be portable).

              Instead, if what you want is that your message receipt ack should have anytging to do with the outcome of the socket actions, I would have coded the bean as container managed TX and used setRollbackOnly in the catch clause of your socket action.

              If you get an exception, then your message receipt ack will be rolled back.

              //Peter

              • 4. Re: Another transaction problem
                Jim Downing Newbie

                Hi Guys,
                thanks for the help. Unsurprisingly it was my code at fault - switching to CMT gave me a more helpful stack trace. The constructor of the LoggingEvent object doesn't work in the MDB but does in a stand alone client.

                Thanks again,
                jim