10 Replies Latest reply on Jan 24, 2007 4:30 AM by hoigh

    MDB and connection to a remote queue with transaction

    hoigh

      Hi,

      I have got an MDB that has to resend the message received by the onMessage() method to another queue. Additionally, I want to use a container managed transaction for this send operation.

      Using the following code, everything works fine if I try to send to a local queue on the same JBoss:

      public void onMessage(Message message) {
      ...
       Context ctx = new InitialContext();
       Queue queue = (Queue)ctx.lookup("QueueName");
       QueueConnectionFactory queueFactory = (QueueConnectionFactory)ctx.lookup("java:/JmsXA");
       QueueConnection connection = queueFactory.createQueueConnection("username", "password");
       QueueSession session = connection.createQueueSession(true, -1);
       QueueSender sender = session.createSender(queue);
       sender.send(queue, message);
      ...
      }
      


      If I try to connect to a remote queue everything seems to be OK for the MDB and it exits without any exception.
      However, the message never reaches the remote queue because the send operation managed by the container fails. From the log files I could see that my JBoss tried to resend the message many times until I stopped it.
      The code for the remote case looks like this:
      public void onMessage(Message message) {
      ...
       Properties env = new Properties();
       env.put(Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory");
       env.put(Context.URL_PKG_PREFIXES, "org.jboss.naming:org.jnp.interfaces");
       env.put(Context.PROVIDER_URL, "jnp://remotehost:1299");
      
       Context remoteCtx = new InitialContext(env);
       Queue queue = (Queue)remoteCtx.lookup("QueueName");
       QueueConnectionFactory queueFactory = (QueueConnectionFactory)remoteCtx.lookup("java:/JmsXA");
       QueueConnection connection = queueFactory.createQueueConnection("username", "password");
       QueueSession session = connection.createQueueSession(true, -1);
       QueueSender sender = session.createSender(queue);
       sender.send(queue, message);
      ...
      }
      


      If I switch off transaction by
       QueueSession session = connection.createQueueSession(false, QueueSession.AUTO_ACKNOWLEDGE);
      

      message sending works as expected. But I have no transaction handling this way.

      I also tested an XAConnectionFactory instead of JmsXA which makes no difference and does not work, too.

      Has anybody an idea or perhaps a better running solution?


      Thanks in advance!



        • 1. Re: MDB and connection to a remote queue with transaction
          weston.price

          Hi,

          The 'java:/' namespace is not available remotely change your lookup to be

           Context remoteCtx = new InitialContext(env);
           Queue queue = (Queue)remoteCtx.lookup("QueueName");
           QueueConnectionFactory queueFactory = (QueueConnectionFactory)
          
          //Change
          remoteCtx.lookup("ConnectionFactory");
          
          
          //Or
          
          remoteCtx.lookup("XAConnectionFactory");
          
          





          • 2. Re: MDB and connection to a remote queue with transaction
            hoigh

            Omitting "java:/" to use the other namespace is a good point. If I use the XAConnectionFactory from global JNDI on the remote JBoss then the resending phenomenon is gone. However, there is still the problem that the message seems to be correctly sent but neither reaches the remote destination nor any local queue, e.g. the DLQ or the queue the message was consumed from.

            • 3. Re: MDB and connection to a remote queue with transaction
              weston.price

              What version of JBoss?

              • 4. Re: MDB and connection to a remote queue with transaction
                hoigh

                My JBoss-Version is 4.0.2.

                • 5. Re: MDB and connection to a remote queue with transaction
                  weston.price

                  Though you code doesn't show it, I would assume that you are closing the sender, session and connection. Is this correct?

                  Also, make sure the transactional attributes in you ejb-jar.xml file are correct.


                  • 6. Re: MDB and connection to a remote queue with transaction
                    hoigh

                    Yes, sender, session, and connection are closed after the send call.

                    Here are the XML fragments for transaction handling in my ejb-jar.xml:

                    
                     ...
                    
                     <transaction-type>Container</transaction-type>
                     <message-driven-destination>
                     <destination-type>javax.jms.Queue</destination-type>
                     </message-driven-destination>
                    
                     ....
                    
                     <container-transaction >
                     <method >
                     <ejb-name>RemoteResenderMDB</ejb-name>
                     <method-name>*</method-name>
                     </method>
                     <trans-attribute>Required</trans-attribute>
                     </container-transaction>
                    
                     ....
                    
                    





                    • 7. Re: MDB and connection to a remote queue with transaction
                      weston.price

                      Can you extract the send part from the MDB example and put it in a standalone client (you will obviously want to use 'ConnectionFactory') for the example?

                      I just want to verify that you can post to the Queue at all. Also, any log sippets would be helpful as well.



                      • 8. Re: MDB and connection to a remote queue with transaction
                        hoigh

                        As already stated, posting to the remote queue works fine if I use

                        QueueSession session = connection.createQueueSession(false, QueueSession.AUTO_ACKNOWLEDGE);
                        

                        instead of
                        QueueSession session = connection.createQueueSession(true, -1);
                        

                        It makes no difference whether I use ConnectionFactory or XAConnectionFactory.

                        To find more details on the problem I examined the server logs and switched the logger for org.jboss.qm to DEBUG level.

                        Astonishingly, there seems to be no difference in the log if I use the transacted session instead of the normal one.
                        Here are some extracted snippets:

                        Sending within MDB.onMessage() on local host:
                        2006-09-29 11:22:30,036 DEBUG [org.jboss.mq.referenceable.SpyDestinationObjectFactory] SpyDestinationObjectFactory->getObjectInstance()
                        2006-09-29 11:22:30,040 DEBUG [org.jboss.mq.referenceable.SpyConnectionFactoryObjectFactory] Extracting SpyConnectionFactory from reference
                        2006-09-29 11:22:30,045 DEBUG [org.jboss.mq.referenceable.SpyConnectionFactoryObjectFactory] The GenericConnectionFactory is: GenericConnectionFactory[server=org.jboss.mq.il.uil2.UILServerIL@4ff8413a connectionProperties={UIL_PORT_KEY=8293, ClientILService=org.jboss.mq.il.uil2.UILClientILService, UIL_ADDRESS_KEY=172.23.4.115, UIL_TCPNODELAY_KEY=yes, PingPeriod=60000, UIL_CHUNKSIZE_KEY=1000000, UIL_RECEIVE_REPLIES_KEY=No, UIL_BUFFERSIZE_KEY=2048}]
                        2006-09-29 11:22:30,047 DEBUG [org.jboss.mq.il.uil2.SocketManager] Begin ReadTask.run
                        2006-09-29 11:22:30,047 DEBUG [org.jboss.mq.il.uil2.SocketManager] Begin WriteTask.run
                        2006-09-29 11:22:30,047 DEBUG [org.jboss.mq.il.uil2.SocketManager] Created ObjectOutputStream
                        2006-09-29 11:22:30,049 DEBUG [org.jboss.mq.il.uil2.SocketManager] Created ObjectInputStream
                        2006-09-29 11:22:30,091 DEBUG [org.jboss.mq.il.uil2.UILClientILService] Starting
                        2006-09-29 11:22:30,106 DEBUG [org.jboss.mq.il.uil2.UILClientILService] Stopping
                        2006-09-29 11:22:30,107 DEBUG [org.jboss.mq.il.uil2.SocketManager] End ReadTask.run
                        2006-09-29 11:22:30,108 DEBUG [org.jboss.mq.il.uil2.SocketManager] End WriteTask.run
                        


                        The receiver on the remote host 172.23.4.115 logs something like:
                        2006-09-29 15:31:02,052 DEBUG [org.jboss.mq.referenceable.SpyDestinationObjectFactory] SpyDestinationObjectFactory->getObjectInstance()
                        2006-09-29 15:31:02,292 DEBUG [org.jboss.mq.referenceable.SpyConnectionFactoryObjectFactory] Extracting SpyConnectionFactory from reference
                        2006-09-29 15:31:02,293 DEBUG [org.jboss.mq.referenceable.SpyConnectionFactoryObjectFactory] The GenericConnectionFactory is: GenericConnectionFactory[server=org.jboss.mq.il.uil2.UILServerIL@b77a46 connectionProperties={UIL_PORT_KEY=8293, ClientILService=org.jboss.mq.il.uil2.UILClientILService, UIL_ADDRESS_KEY=172.23.4.115, UIL_TCPNODELAY_KEY=yes, PingPeriod=60000, UIL_CHUNKSIZE_KEY=1000000, UIL_RECEIVE_REPLIES_KEY=No, UIL_BUFFERSIZE_KEY=2048}]
                        2006-09-29 15:31:02,295 DEBUG [org.jboss.mq.il.uil2.SocketManager] Begin ReadTask.run
                        2006-09-29 15:31:02,295 DEBUG [org.jboss.mq.il.uil2.SocketManager] Begin ReadTask.run
                        2006-09-29 15:31:02,296 DEBUG [org.jboss.mq.il.uil2.SocketManager] Begin WriteTask.run
                        2006-09-29 15:31:02,296 DEBUG [org.jboss.mq.il.uil2.SocketManager] Begin WriteTask.run
                        2006-09-29 15:31:02,296 DEBUG [org.jboss.mq.il.uil2.SocketManager] Created ObjectOutputStream
                        2006-09-29 15:31:02,296 DEBUG [org.jboss.mq.il.uil2.SocketManager] Created ObjectOutputStream
                        2006-09-29 15:31:02,297 DEBUG [org.jboss.mq.il.uil2.SocketManager] Created ObjectInputStream
                        2006-09-29 15:31:02,298 DEBUG [org.jboss.mq.il.uil2.SocketManager] Created ObjectInputStream
                        2006-09-29 15:31:02,302 DEBUG [org.jboss.mq.il.uil2.UILClientILService] Starting
                        2006-09-29 15:31:02,303 DEBUG [org.jboss.mq.il.uil2.ServerSocketManagerHandler] Setting up the UILClientIL Connection
                        2006-09-29 15:31:02,303 DEBUG [org.jboss.mq.il.uil2.ServerSocketManagerHandler] The UILClientIL Connection is set up
                        2006-09-29 15:31:02,307 DEBUG [org.jboss.mq.referenceable.SpyDestinationObjectFactory] SpyDestinationObjectFactory->getObjectInstance()
                        2006-09-29 15:31:02,310 DEBUG [org.jboss.mq.il.uil2.SocketManager] End WriteTask.run
                        2006-09-29 15:31:02,310 DEBUG [org.jboss.mq.il.uil2.ServerSocketManagerHandler] Exiting on IOE
                        java.net.SocketException: Socket closed
                         at java.net.SocketInputStream.read(SocketInputStream.java:162)
                         at java.io.BufferedInputStream.fill(BufferedInputStream.java:218)
                         at java.io.BufferedInputStream.read(BufferedInputStream.java:235)
                         at org.jboss.util.stream.NotifyingBufferedInputStream.read(NotifyingBufferedInputStream.java:67)
                         at java.io.ObjectInputStream$PeekInputStream.peek(ObjectInputStream.java:2196)
                         at java.io.ObjectInputStream$BlockDataInputStream.readBlockHeader(ObjectInputStream.java:2376)
                         at java.io.ObjectInputStream$BlockDataInputStream.refill(ObjectInputStream.java:2443)
                         at java.io.ObjectInputStream$BlockDataInputStream.read(ObjectInputStream.java:2515)
                         at java.io.ObjectInputStream$BlockDataInputStream.readByte(ObjectInputStream.java:2664)
                         at java.io.ObjectInputStream.readByte(ObjectInputStream.java:875)
                         at org.jboss.mq.il.uil2.SocketManager$ReadTask.run(SocketManager.java:290)
                         at java.lang.Thread.run(Thread.java:595)
                        2006-09-29 15:31:02,371 DEBUG [org.jboss.mq.il.uil2.UILClientILService] Stopping
                        2006-09-29 15:31:02,373 DEBUG [org.jboss.mq.il.uil2.SocketManager] End ReadTask.run
                        2006-09-29 15:31:02,311 DEBUG [org.jboss.mq.il.uil2.SocketManager] End WriteTask.run
                        2006-09-29 15:31:02,310 DEBUG [org.jboss.mq.il.uil2.SocketManager] End ReadTask.run
                        


                        The strange exception causing the ServerSocketManagerHandler to exit on IOE seems to be independent of my original problem and is always there: no difference between successful send and failure.
                        Sometimes there is also an
                        java.io.EOFException
                         at java.io.ObjectInputStream$BlockDataInputStream.readByte(ObjectInputStream.java:2666)
                         at java.io.ObjectInputStream.readByte(ObjectInputStream.java:875)
                         at org.jboss.mq.il.uil2.SocketManager$ReadTask.run(SocketManager.java:290)
                         at java.lang.Thread.run(Thread.java:595)
                        

                        instead of the SocketException. But it seems to make no difference, too. Whether the one or the other exception occurs is undetermined.

                        I hope that the snippets could help a little. Perhaps there is also another log setting to find a clue on the problem?











                        • 9. Re: MDB and connection to a remote queue with transaction
                          germanbalbastro

                          The solution is in ths page

                          http://www.odi.ch/prog/jms-tx.php

                          • 10. Re: MDB and connection to a remote queue with transaction
                            hoigh

                            Thanks for the answer. I don't know if the article actually helps. However, I have found my own solution. If you want to send a message in a container managed transaction to a remote destination, the nuts and bolts is to care about the XAConnection, i.e., the usage of XA classes is mandatory.

                            This is some code exctracted from my application that works fine now:

                            public void sendMessage(Message message, String providerUrl, String queueName, String user, String password) {
                             Context context = null;
                            
                             XAQueueConnectionFactory remoteQueueFactoryXA = null;
                             XAQueueConnection connectionXA = null;
                            
                             Queue queue = null;
                             QueueSession session = null;
                             QueueSender sender = null;
                            
                             try {
                             Properties env = new Properties();
                             env.put(Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory");
                             env.put(Context.URL_PKG_PREFIXES, "org.jboss.naming:org.jnp.interfaces");
                             env.put(Context.PROVIDER_URL, providerUrl);
                             context = new InitialContext(env);
                            
                             remoteQueueFactoryXA = (XAQueueConnectionFactory)context.lookup("XAConnectionFactory");
                             connectionXA = remoteQueueFactoryXA.createXAQueueConnection(user, password);
                             session = connectionXA.createQueueSession(true, -1);
                             queue = (Queue)context.lookup(queueName);
                             sender = session.createSender(queue);
                             sender.send(queue, message);
                             }
                             catch(Exception excep) {
                             ...
                             }
                             finally {
                             if(sender != null) {
                             try {
                             sender.close();
                             } catch(Exception excep) {
                             ...
                             }
                             }
                             if(session != null) {
                             try {
                             session.close();
                             } catch(Exception excep) {
                             ...
                             }
                             }
                             if(connectionXA != null) {
                             try {
                             connectionXA.close();
                             } catch(Exception excep) {
                             ...
                             }
                             }
                             }
                            }