Skip to Content
author's profile photo Former Member
Former Member

Transactional behavior in JMS

On WAS 6.40 I have a problem trying to get the following behavior when using JMS:

A message is sent from a session bean method (TX_REQUIRED) and then we mark the transaction for rollbackonly, i.e. aborting the transaction. Expected behaviour is that the message should not be sent. This works for a number of application servers however it fails on WebAS.

I am using XAQueueConnectionFactory configured in VisualAdmin. I tried several scenarios for session creation as well as using XA interfaces explicitely:

XAQueueConnectionFactory factory = (XAQueueConnectionFactory) ctx.lookup( JNDIUtils.Q_CONFAC );

XAQueueConnection _queueConnection = factory.createXAQueueConnection();

_queueConnection.createXAQueueSession();

So is there a way in netweaver to achieve this behavior without using explicit transactional attributes for sessions? We rely heavily on using container managed transactions.

Any help is appreciated!

Add a comment
10|10000 characters needed characters exceeded

Related questions

2 Answers

  • author's profile photo Former Member
    Former Member
    Posted on Feb 23, 2005 at 11:00 AM

    Hi Mikhail,

    Can you post the sources you are testing with? I mean the original ones, i.e. these that do not use explicitly the XA interfaces and that work correctly with the other application servers?

    Best regards,

    Stoyan

    Message was edited by: Stoyan Vellev

    Add a comment
    10|10000 characters needed characters exceeded

    • Former Member

      Hi Stoyan,

      Basically the code is distributed in a number of classes, however I stripped away some code to show the idea (please let me know if this is enough).

      Generally the scenario is the following:

      A junit test sends two messages to a sendTestQueue through a call to a sessionbean method (transaction required). One call purposefully aborts the transaction inside the session bean method, which should prevent message to be sent. The other one does not.

      A message driven bean listener takes any message that comes from sendTestQueue and sends it back to another queue (sendBackTestQueue). Then in the junit test we recieve messages from the sendBackTestQueue. Assertion is made that we must only recieve the successful message (not the failed message).

      Here is the test code:

      public void testSendMessageInFailedTransaction() throws Exception {
      		String fail = "This message should not be received as a reply.";
      		String success = "This message should be the only messaged returned in a reply.";
              String successCorrleationId = "MDBTest.testSendMessageInTransaction.SUCCESS_MSG";
              String failCorrleationId = "MDBTest.testSendMessageInTransaction.FAIL_MSG";
      
      		assertNull("The reply queue is supposed to be empty", queueReceiver.receiveNoWait());
      
      		// Send a message with a forced exception.  There should not be a reply to this message.		
      		try {
      
      			sessionEJB.sendMessage(fail, failCorrleationId, true);
      		} catch (Exception e) {
      			handleForcedException(e);
      		}
      
      		// Send a second message without an exception.  We should receive this message in a reply.		
      		sessionEJB.sendMessage(success, successCorrleationId, false);
      
      		TextMessage replyMsg = (TextMessage) queueReceiver.receive(5000);
      
      		if (replyMsg == null)
      			fail("A reply message was not received within a 5 second timeout.");
      		else
      			assertEquals("The reply message ID should equal the success message ID. Reply ID=" + replyMsg.getJMSCorrelationID() + ", success ID=" + successCorrleationId, successCorrleationId, replyMsg.getJMSCorrelationID());
      
      		assertNull("The reply queue is supposed to be empty after receiving", queueReceiver.receiveNoWait());
      	}
      

      The body of the session bean method that we use to send an receive messages

      public void sendMessage( String message, String correlationId, boolean forceException )
          {                
              // code for the next 2 methods is listed below 
              Message jmsMsg = base.buildMessage( message );
              Queue replyQueue = base.getQueue( JMSMessageApplicationInterface.JMS_TEST_BACK_QUEUE );
              try
              {
                  jmsMsg.setJMSCorrelationID( correlationId );
                  jmsMsg.setJMSReplyTo( replyQueue );
              }
              catch( JMSException jex )
              {
                  throw new EJBException( jex );
              }
              
              Queue requestQueue = base.getQueue( JMSMessageApplicationInterface.JMS_TEST_QUEUE );
              base.sendMessage( requestQueue, jmsMsg );
              if( forceException ) {
                  try {
                      // setRollbackOnly
                      // in this case the message should not be sent
                      abort(new BasicBOBeanException(10000, JMSMessageApplicationInterface.FORCED_EXCEPTION_MSG));
                  } catch (BasicBOBeanException e) {
                      // do nothing  it is planned
                      e.printStackTrace();  
                  }
                  throw new EJBException( JMSMessageApplicationInterface.FORCED_EXCEPTION_MSG );
              }
          }
      
      

      MDB listener method:

      public void onMessage( Message message )
          {
              JMSMessageApplicationInterface messageApp = 
                  (JMSMessageApplicationInterface) super.getEJB( "JMSMessageApplication" );
              try
              {
                  TextMessage receivedMessage = (TextMessage) message;
                  
                  logMessage( "Message received with the following properties:", receivedMessage );                                                                                
      Queue replyQueue = (Queue) message.getJMSReplyTo();
                  if( replyQueue != null )
                  {            
                      // Since the message is requesting a reply, create a message producer and 
                      // send a reply to the reply test queue.  Copy the message content and 
                      // correlation ID to the reply message so that the original sender can correlate
                      // the reply with the original message.
                      InitialContext ctx = JNDIUtils.getInitialContext();
                      QueueConnectionFactory queueConFact = (QueueConnectionFactory) ctx.lookup( JNDIUtils.Q_CONFAC );
                      QueueConnection queueCon = queueConFact.createQueueConnection();
                      QueueSession queueSession = queueCon.createQueueSession( false, Session.AUTO_ACKNOWLEDGE );                
                      QueueSender replySender = queueSession.createSender( replyQueue );
                      queueCon.start();                        
          
                      TextMessage replyMessage = queueSession.createTextMessage( receivedMessage.getText() );                
                      replyMessage.setJMSCorrelationID( receivedMessage.getJMSCorrelationID() );
                      replySender.send( replyMessage );
                                                                                      logMessage( "Message sent with the following properties:", replyMessage );
                  }                
              }
              catch( JMSException e )
              {                
                  _logger.error( e );
                  throw new javax.ejb.EJBException( e );
              }
              catch( NamingException e )
              {
                  _logger.error( e );
                  throw new javax.ejb.EJBException( e );
              }
          }

      Base methods to obtain queues and build messages

        public void sendMessage( Queue queue, Message msg )
          {
              try
              {
                  if ( Utils.isTraceEnabled( Utils.JMS ) )
                  {
                      String destName = queue.getQueueName();
                      doMessageTrace( destName, msg );
                  }
                  QueueSender sender = getQueueSender();
                  sender.send( queue, msg );
              }
              catch ( JMSException je )
              {
                  throw new EJBException( je );
              }
              catch ( NamingException ne )
              {
                  throw new EJBException( ne );
              }
          }
      
          private QueueSender getQueueSender() throws JMSException, NamingException
          {
              // open up JMS channel if not already done
              if ( _sender == null )
              {
                  QueueSession session = getQueueSession();
                  _sender = session.createSender( null );
              }
              return _sender;
          }
      
      
         private QueueSession getQueueSession() throws JMSException, NamingException
          {
              if ( _queueSession == null )
              {
                  Context ctx = getInitialContext();
                  QueueConnectionFactory factory = (QueueConnectionFactory) ctx.lookup( JNDIUtils.Q_CONFAC );
                  _queueConnection = factory.createQueueConnection();
                  _queueSession  = _queueConnection.createQueueSession( false, Session.AUTO_ACKNOWLEDGE );
              }
              return _queueSession;
          }
      

      Regards,

      Mikhail

  • author's profile photo Former Member
    Former Member
    Posted on Feb 24, 2005 at 11:14 AM

    Hello Mikhail,

    You are creating the JMS session with transacted flag false, because of this flag the session will not be enlisted in the EJB transaction.

    As a workaround you can update your code to use a true flag :

    _queueSession = queueConnection.createQueueSession( true, Session.AUTOACKNOWLEDGE );

    Best Regards

    Peter Peshev

    Add a comment
    10|10000 characters needed characters exceeded

Before answering

You should only submit an answer when you are proposing a solution to the poster's problem. If you want the poster to clarify the question or provide more information, please leave a comment instead, requesting additional details. When answering, please include specifics, such as step-by-step instructions, context for the solution, and links to useful resources. Also, please make sure that you answer complies with our Rules of Engagement.
You must be Logged in to submit an answer.

Up to 10 attachments (including images) can be used with a maximum of 1.0 MB each and 10.5 MB total.