3 Replies Latest reply on Feb 14, 2007 1:16 AM by mrudulam

    JTA inside jBPM

    joshua_hj

      Dear community,

      I have a two-phase commit operation that i want to modify to integrate jBPM in it. Obviously, the operation starts with a tx.begin and ends with a tx.commit. Inside the two-phase commit operation i want to instantiate a jbpm process that makes a couple of transactions inside nodes/actions. The thing is, is the two-phase commit operation awareness of the transaction made inside the jBPM process states? Will those transactions made inside jbpm be rolled back in case of failure? Will they be considered by the main two-phase commit transaction?

      Thanks joshua

        • 1. Re: JTA inside jBPM
          ralfoeldi

          Hi Joshua,

          two-phase or not doesn't make any difference here. You usually don't handle the prepare / commit stuff manually or do you?

          There are no nested transactions in Java. So there are two scenarios:

          a) Everything happens and is commited or rolled back in the one enclosing tx, i.e. no new transactions. This would be the standard straight forward approach.

          b) You start new transactions in your action handlers. (Is this what you are describing?) These will however be totally independent. Your jbpm-transaction (the outer transaction) will be able to react to the failure of the inner transactions but not the other way around.

          or

          c) you roll your own, i.e. you coordinate the inner transactions and the outer transaction by your own means. There are a fews comments on that in this forum. But this is definately non trivial (believe me, I just built one of these)

          Is this of any help?

          Greeting

          Rainer

          • 2. Re: JTA inside jBPM
            joshua_hj

            Thanks for the help,

            There is nothing better then trying it :). It works fine. All the transactions made inside jBPM are within the main JTA transaction. And that means that if something goes wrong inside the jBPM all the transactions are rolledback. (cool)


            Joshua

            • 3. Rollback of a process using JTA inside jBPM - help
              mrudulam

              The situation I am breaking my head over is this - Assume there is a simple 3 node process. Each node has its own action handler. In the second action handler, I have an update to another database (other than the jbpm). In the 3rd action handler, there is an exception. I am trying to combine nodes 2 and 3 as part of one transaction. [I am **not** having code to leave the nodes withing action handler for testing purposes]

              I am using a servlet/stand alone program to instantiate the process, and using the javax.transaction.UserTransaction.begin() and commit() to demarcate transaction as show below and I am testing this out in WSAD.

              The transaction is managed beautifully - commits to jbpm database and the external database works fine, if there is no exception. However, if there is an exception (in the third actionhandler), the rollback of hte jbpm process takes place only by one node. It does not seem to conform to the begin/commit demarcations. The other rollback is fine.

              Can anyone tell me what is wrong with the code? Is there a wrong usage of save jbpmContext or close or anything else?

              Thanks for all your help

              package com.excercise.jbpm;
              
              public class JBPMTestServlet extends HttpServlet implements Servlet {
               private static JbpmConfiguration jbpmConfiguration =
               JbpmConfiguration.getInstance();
               private static final String USER_TRANSACTION_JNDI_NAME = "UserTransaction";
               private static long pid = 0L;
               private PrintWriter out = null;
               private Context ctx = null;
               private DataSource ds = null;
               private UserTransaction utx= null;
              
               public void doPost(HttpServletRequest req, HttpServletResponse resp)
               throws ServletException, IOException {
              
               resp.setContentType("text/html");
               out = resp.getWriter();
               ProcessInstance pInstance = null;
               ProcessDefinition pmpd = null;
               Token token = null;
               try {
               ctx = new InitialContext();
               } catch (NamingException e) {
               out.println("ERROR! Could not get Initial Context.");
               out.println("<br>" + e.getMessage() + "<br><pre>");
               e.printStackTrace(new PrintWriter(out));
               out.println("</pre>");
               }
              
               try
               {
               utx = (UserTransaction)
               ctx.lookup("java:comp/UserTransaction");
               System.out.println(utx);
               }
               catch (NamingException e) {
               out.println("ERROR! Could not get UserTransaction");
               out.println("<br>" + e.getMessage() + "<br><pre>");
               e.printStackTrace(new PrintWriter(out));
               out.println("</pre>");
               }
               if (ctx != null) {
               try {
               ds = (DataSource) ctx.lookup("jdbc/jbpm");
               } catch (NamingException e) {
               out.println("ERROR! Could not find DSN.");
               out.println("<br>" + e.getMessage() + "<br><pre>");
               e.printStackTrace(new PrintWriter(out));
               out.println("</pre>");
               }
               }
              
              // **************************** Creating Process Instance and signalling to node1 **************************** //
               JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
               Connection conn = null;
               try {
               utx.begin();
               conn = ds.getConnection();
               conn.setAutoCommit(true);
               jbpmContext.setConnection(conn);
               pmpd =
               jbpmContext.getGraphSession().findLatestProcessDefinition(
               "JustNodesProcess");
               pInstance = new ProcessInstance(pmpd);
               pid = pInstance.getId();
               token = pInstance.getRootToken();
               out.println(
               "Before signalling, the token is now at " + token.getNode() + "\n");
               token.signal();
               out.println(
               "After signalling, the token is now at " + token.getNode() + "\n");
               jbpmContext.save(pInstance);
               out.println("After saving...\n");
               utx.commit();
               } catch (Exception e) {
               e.printStackTrace();
               out.println(e.getMessage());
               try
               {
               utx.rollback();
               }
               catch (Exception ex)
               {
               ex.printStackTrace();
               }
               } finally {
               jbpmContext.getSession().flush();
               out.println("After flushin...\n");
               jbpmContext.close();
               out.println("After closing...\n");
              
               }
               // **************************** Signalling to node2 and node3 **************************** //
               /**
               * Note that node2 and node3 have been combined into one transaction.
               * Here we can give an exception in node3 and check if it rolls back to node2
               */
               jbpmContext = jbpmConfiguration.createJbpmContext();
               try {
               utx.begin();
               conn = ds.getConnection();
               jbpmContext.setConnection(conn);
               conn.setAutoCommit(true);
               GraphSession graphSession = jbpmContext.getGraphSession();
               pInstance = graphSession.loadProcessInstance(pid);
               pInstance.signal();
               pInstance.signal();
               jbpmContext.save(pInstance);
               utx.commit();
               } catch (Exception e) {
               e.printStackTrace();
               out.println(e.getMessage());
               try
               {
               utx.rollback();
               }
               catch (Exception ex)
               {
               ex.printStackTrace();
               }
               out.println("pInstance.hasEnded()" + pInstance.hasEnded());
               List list = pInstance.findAllTokens();
               out.println(
               "pInstance tokens size is "
               + list.size()
               + " token is "
               + ((Token) list.get(0)).getNode());
               return;
               } finally {
               jbpmContext.getSession().flush();
               jbpmContext.close();
               }
               // **************************** Signalling to End state **************************** //
               jbpmContext = jbpmConfiguration.createJbpmContext();
               try {
               utx.begin();
               conn = ds.getConnection();
               conn.setAutoCommit(true);
               jbpmContext.setConnection(conn);
               GraphSession graphSession = jbpmContext.getGraphSession();
               pInstance = graphSession.loadProcessInstance(pid);
               pInstance.signal();
               jbpmContext.save(pInstance);
               utx.commit();
               } catch (Exception e) {
               e.printStackTrace();
               out.println(e.getMessage());
               try
               {
               utx.rollback();
               }
               catch (Exception ex)
               {
               ex.printStackTrace();
               }
               return;
               } finally {
               jbpmContext.getSession().flush();
               jbpmContext.close();
               }
               return;
               }
              }
              


              And the jbpm configuration is as shown below

              <jbpm-configuration>
              
               <jbpm-context>
               <!-- <service name="persistence" factory="org.jbpm.persistence.db.DbPersistenceServiceFactory" /> -->
               <service name="persistence">
               <factory>
               <bean name="org.jbpm.persistence.db.DbPersistenceServiceFactory" class="org.jbpm.persistence.db.DbPersistenceServiceFactory">
               <field name="isTransactionEnabled"><false /></field>
               </bean>
               </factory>
               </service>
               <service name="message" factory="org.jbpm.msg.db.DbMessageServiceFactory" />
               <service name="scheduler" factory="org.jbpm.scheduler.db.DbSchedulerServiceFactory" />
               <service name="logging" factory="org.jbpm.logging.db.DbLoggingServiceFactory" />
               <service name="authentication" factory="org.jbpm.security.authentication.DefaultAuthenticationServiceFactory" />
               </jbpm-context>
              
               <!-- configuration resource files pointing to default configuration files in jbpm-{version}.jar -->
               <string name="resource.hibernate.cfg.xml" value="hibernate.cfg.xml" />
               <!-- <string name="resource.hibernate.properties" value="hibernate.properties" /> -->
               <string name="resource.business.calendar" value="org/jbpm/calendar/jbpm.business.calendar.properties" />
               <string name="resource.default.modules" value="org/jbpm/graph/def/jbpm.default.modules.properties" />
               <string name="resource.converter" value="org/jbpm/db/hibernate/jbpm.converter.properties" />
               <string name="resource.action.types" value="org/jbpm/graph/action/action.types.xml" />
               <string name="resource.node.types" value="org/jbpm/graph/node/node.types.xml" />
               <string name="resource.parsers" value="org/jbpm/jpdl/par/jbpm.parsers.xml" />
               <string name="resource.varmapping" value="org/jbpm/context/exe/jbpm.varmapping.xml" />
              
               <bean name="jbpm.task.instance.factory" class="org.jbpm.taskmgmt.impl.DefaultTaskInstanceFactoryImpl" singleton="true" />
               <bean name="jbpm.variable.resolver" class="org.jbpm.jpdl.el.impl.JbpmVariableResolver" singleton="true" />
               <long name="jbpm.msg.wait.timout" value="5000" singleton="true" />
              
              </jbpm-configuration>