How to roll back a transaction

classic Classic list List threaded Threaded
14 messages Options
Reply | Threaded
Open this post in threaded view
|

How to roll back a transaction

David CHAU
Hello,
I am using swiftMQ for a J2EE application using JOnAS.
Actually, I have a EJB which transactions are bean managed transactions. this EJB call a service that provides some processes including sending messages to a queue. My process is as follow:
First, I make an access to a database.
Then, I send a message to a queue.
and finally, I make another access to the database.

This process throws a runtime exception if there are problems with database operations or jms operations.
In my EJB, I have set the property rollbackonly when catching an runtime exception. So, my database transactions are well roll backed but the JMS transaction are not.

To send a message to a queue, I get the initial context, create the connection factory  and create a session. Then I get the sender and send the message. Finally, I close all the sender, session and connection and context.

regards,
Reply | Threaded
Open this post in threaded view
|

Re: How to roll back a transaction

IIT Software
Administrator
Are you using JMS with XA? Do you use our JCA 1.5 resource adapter? Which version of SwiftMQ are you using?

-- Andreas
Reply | Threaded
Open this post in threaded view
|

Re: How to roll back a transaction

David CHAU
i am using JMS with XA/ASF.
I did not succeed to use the JCA 1.5 resource adapter with JOnAS 4.1.4. I made JOnAS 4.3.4 using resource adapter but not with JOnAS 4.1.4. Actually, I cannot migrate my application in another version of JOnAS.
I am using swiftMQ 6.0.1
Reply | Threaded
Open this post in threaded view
|

Re: How to roll back a transaction

IIT Software
Administrator
How do you access SwiftMQ? Do you use our JNDI context or Jonas' one? It's important to follow these instructions to ensure that the JMS connection/session is enlisted in the current XA transaction from Jonas. Otherwise a rollback (implicit or explicit) doesn't have effect.
Reply | Threaded
Open this post in threaded view
|

Re: How to roll back a transaction

David CHAU
My JOnAS configuration is as follow:

###################### JOnAS JMS service configuration
#
#  Set the name of the implementation class of the jms service
jonas.service.jms.class org.objectweb.jonas.jms.JmsServiceImpl

#  Indicates the Jms service must be started with this class for administering the mom
#jonas.service.jms.mom org.objectweb.jonas_jms.JmsAdminForJoram
jonas.service.jms.mom com.swiftmq.appserver.jonas.JmsAdminForSwiftMQ

#  Set the Jms Server launching mode
#  If set to 'true'  it is launched in the same JVM as Application Server
#  If set to 'false' Jms Server is launched in a separate JVM
#jonas.service.jms.collocated true
jonas.service.jms.collocated false

#  Set to the url connexion when the Jms server is not collocated
#jonas.service.jms.url joram://localhost:16010
jonas.service.jms.url smqp://localhost:4001/timeout=1000


We use swiftMQ JNDI context.
Which part do I have to look?

I did not modify the a3servers.xml file and did not add the resource-ref, resource_ref-env and jonas-resource-env parts.

thanks
Reply | Threaded
Open this post in threaded view
|

Re: How to roll back a transaction

IIT Software
Administrator
If you use SwiftMQ's JNDI then you are using JMS like a plain JMS client without transaction interception from Jonas. That's why the JMS session isn't rolled back.

You must use "Resource-Ref" to specify the connection factory to use and then use Jonas's JNDI to look them up. That way, Jonas provides you a proxy which does the tx handling under the covers. Jonas should get our connection factories from the service class "JmsAdminForSwiftMQ" you are using.

Please check the Jonas docs how to specify the resource-refs and where it stores the JMS connection factories in Jonas JNDI.
Reply | Threaded
Open this post in threaded view
|

Re: How to roll back a transaction

David CHAU
this is my jonas configuration

jonas.services    registry,jmx,jtm,db,dbm,jms,security,resource,ejb,web,ear

#
###################### JOnAS JMS service configuration
#
#  Set the name of the implementation class of the jms service
jonas.service.jms.class        org.objectweb.jonas.jms.JmsServiceImpl

#  Indicates the Jms service must be started with this class for administering the mom
#jonas.service.jms.mom        org.objectweb.jonas_jms.JmsAdminForJoram
jonas.service.jms.mom        com.swiftmq.appserver.jonas.JmsAdminForSwiftMQ

#  Set the Jms Server launching mode
#  If set to 'true'  it is launched in the same JVM as Application Server
#  If set to 'false' Jms Server is launched in a separate JVM
#jonas.service.jms.collocated    true
jonas.service.jms.collocated    false

#  Set to the url connexion when the Jms server is not collocated
#jonas.service.jms.url        joram://localhost:16010
jonas.service.jms.url        smqp://55.2.10.155:4001/timeout=1000


my Session Bean configuration:
- in the ejb-jar.xml :
     
     <session >
        <description>
<![CDATA[]]>
</description>

        <ejb-name>JmsService</ejb-name>

        <local-home>test.JmsServiceHome</local-home>
        <local>test.JmsServiceLocal</local>
        <ejb-class>test.JmsServiceBean</ejb-class>
        <session-type>Stateless</session-type>
        <transaction-type>Container</transaction-type>
        <resource-ref >
           <res-ref-name>jms/connectionFactory</res-ref-name>
           <res-type>javax.jms.ConnectionFactory</res-type>
           <res-auth>Container</res-auth>
        </resource-ref>
        <resource-env-ref>
           <resource-env-ref-name>jms/valorisationQueue</resource-env-ref-name>
           <resource-env-ref-type>javax.jms.Queue</resource-env-ref-type>
        </resource-env-ref>
     </session>
- in jonas-ejb-jar.xml :
 
 <jonas-session>

   <ejb-name>JmsService</ejb-name>

   <jndi-name>***/JmsService</jndi-name>

   <jonas-resource>
     <res-ref-name>jms/connectionFactory</res-ref-name>
     <jndi-name>ConnectionFactory</jndi-name>
   </jonas-resource>

   <jonas-resource-env>              <resource-env-ref-name>jms/valorisationQueue</resource-env-ref-name>
     <jndi-name>myQueue</jndi-name>
   </jonas-resource-env>

 </jonas-session>


the code of the EJB service:
       String xml = getMessage();
       if (xml != null)
       {
           String urlJms = properties.getProperty("swiftmq.url");
           Context context = null;
           Queue valorisationQueue = null;
           QueueConnectionFactory tcf = null;
           try
           {
               // Get an InitialContext
               Properties h = new Properties();
               h.put(Context.INITIAL_CONTEXT_FACTORY, "com.swiftmq.jndi.InitialContextFactoryImpl");
               h.put(Context.PROVIDER_URL, urlJms);
               context = new InitialContext(h);
               valorisationQueue = (Queue) context.lookup("java:comp/env/jms/valorisationQueue");
               tcf = (QueueConnectionFactory) context.lookup("java:comp/env/jms/connectionFactory");
           }
           catch (NamingException ne)
           {
               log.error(ne);
               throw new RuntimeException("jndi.naming", ne);
           }
           sendMessage(valorisationQueue, xml, tcf);
     }


the sendMessage method:
   private void sendMessage (Queue queue, String msg, QueueConnectionFactory tcf) {
       QueueConnection tc = null;
       QueueSession session = null;
       MessageProducer producer = null;
       try
       {
           tc = (QueueConnection) tcf.createQueueConnection();
           session = (QueueSession) tc.createQueueSession(true, 0);
           producer = session.createProducer(queue);
       }
       catch (JMSException jmse)
       {
           throw new RuntimeException("jms.connexion", jmse);
       }
       // publish A message to the queue
       try
       {
           TextMessage message;
           message = (TextMessage) session.createTextMessage();
           message.setText(msg);
           producer.send(message);
           session.close();
           tc.close();
       }
       catch (JMSException jmse)
       {
           throw new JmsRuntimeException("jms.envoie", jmse);
       }
   }

when deploying we have this exception when we do a lookup for the JNDI name "java:comp/env/jms/valorisationQueue":
javax.naming.NamingException: javax.naming.NamingException: javax.naming.NameNotFoundException: myQueue
Caused by: javax.naming.NameNotFoundException: myQueue
   at org.objectweb.carol.jndi.spi.JRMPLocalContext.lookup(JRMPLocalContext.java:185)
   at org.objectweb.carol.jndi.spi.JRMPLocalContext.lookup(JRMPLocalContext.java:195)
   at javax.naming.InitialContext.lookup(InitialContext.java:347)
   at org.objectweb.carol.jndi.spi.MultiContext.lookup(MultiContext.java:96)
   at org.objectweb.carol.jndi.spi.ContextWrapper.lookup(ContextWrapper.java:112)
   at javax.naming.InitialContext.lookup(InitialContext.java:347)
   at org.objectweb.jonas.naming.CompNamingContext.lookup(CompNamingContext.java:162)
   at org.objectweb.jonas.naming.CompNamingContext.lookup(CompNamingContext.java:185)
   at org.objectweb.jonas.naming.CompNamingContext.lookup(CompNamingContext.java:185)
   at org.objectweb.jonas.naming.CompNamingContext.lookup(CompNamingContext.java:185)
   at org.objectweb.jonas.naming.java.javaURLContext.lookup(javaURLContext.java:176)
   at javax.naming.InitialContext.lookup(InitialContext.java:347)
   at test.JmsServiceImpl.envoyerMessageValorisation(JmsServiceImpl.java:121)

I think that my JNDI context is not well initialised but I do not know what to do after that.
Reply | Threaded
Open this post in threaded view
|

Re: How to roll back a transaction

IIT Software
Administrator
David CHAU wrote
               // Get an InitialContext
               Properties h = new Properties();
               h.put(Context.INITIAL_CONTEXT_FACTORY, "com.swiftmq.jndi.InitialContextFactoryImpl");
               h.put(Context.PROVIDER_URL, urlJms);
               context = new InitialContext(h);
               valorisationQueue = (Queue) context.lookup("java:comp/env/jms/valorisationQueue");
               tcf = (QueueConnectionFactory) context.lookup("java:comp/env/jms/connectionFactory");
 
You are still using SwiftMQ's JNDI. You must use Jonas' JNDI. It's just

ctx = new InitalContext();

without any environment settings. If you get a NameNotFoundException, you need to figure out (e.g. by listing JNDI) where the object is located. Usually this is "java:comp/env/jms".
Reply | Threaded
Open this post in threaded view
|

Re: How to roll back a transaction

David CHAU
when doing
IIT Software wrote
ctx = new InitalContext();
then
 valorisationQueue = (Queue) context.lookup("java:comp/env/jms/valorisationQueue");
returns null.
Reply | Threaded
Open this post in threaded view
|

Re: How to roll back a transaction

IIT Software
Administrator
Look here how queues and topics were defined in Jonas 2.6.

In jonas.preoperties there must be an entry:

     jonas.service.jms.queues valorisationQueue

SwiftMQ must have the following configration:

Queue Manager Swiftlet:

        <queues>
          <queue name="valorisationQueue"/>
        </queues>

JNDI Swiftlet:

        <aliases>
          <alias name="valorisationQueue" map-to="valorisationQueue@router1"/>
         </aliases>

That should actually work. If not, check the Jonas docs whether they changed that.

The definition in jonas.properties actually leads to a call "getQueue" on our service class which does an internal lookup on our JNDI and returns the queue object.
Reply | Threaded
Open this post in threaded view
|

Re: How to roll back a transaction

David CHAU
Ok, the queues are found in the conteext, but not the connection factory.
Reply | Threaded
Open this post in threaded view
|

Re: How to roll back a transaction

IIT Software
Administrator
Well, that's really something you have to ask the Jonas guys. All we provide in our service class is a method

  public XAQueueConnectionFactory getXAQueueConnectionFactory()

which is called from Jonas and they do the binding stuff. I thought it might go via the resource-refs. Can't you just list and print the whole JNDI tree of Jonas and figure out whether the cf is stored there? In the past they had a little program for JNDI view.

In any case you need the cf from Jonas JNDI, otherwise you will not have the tx stuff.
Reply | Threaded
Open this post in threaded view
|

Re: How to roll back a transaction

David CHAU
Ok
I found the JNDI name QCF in jonas that is mapped to "QueueConnectionFactory".

thanks a lot for your aswers!
Reply | Threaded
Open this post in threaded view
|

Re: How to roll back a transaction

IIT Software
Administrator
I don't think that it's the proper one. Our service class registers a "JTCF" and a "QTCF" in Jonas's JNDI. However, these are connection factories for Jonas's clients (non-EJB) to use Jonas's JNDI only to connect to SwiftMQ. If you use them, you still have no tx handling. You have to find the other ones...