1 2 Previous Next 20 Replies Latest reply on May 9, 2011 6:46 AM by michal.warecki

    jboss as 5 jbpm 5.1 persistence

    michal.warecki

      Hi,

       

      I have problem while creating stateful knowledge session using jpa, jboss as 5.1 and jbpm 5.1. I'm trying to create session in statefull EJB.

      While creating session thread just suspends and after 3-4 minutes in console I've got xa transaction timeout's.

      Am I missing something while creating Environment ? Should I set conteiner transaction manager into Environment ?

      Maybe jbpm 5.1 doesn't work with XA datasources ? Help me please. There is a code :

       

      datasources:

       

      <datasources>
          <xa-datasource>
              <jndi-name>jdbc/dbDS</jndi-name>
              <use-java-context>true</use-java-context>
              <isSameRM-override-value>false</isSameRM-override-value> 
              <xa-datasource-class>oracle.jdbc.xa.client.OracleXADataSource</xa-datasource-class>
              <xa-datasource-property name="URL">${ds.connection.url}</xa-datasource-property> 
              <xa-datasource-property name="User">${ds.user.name}</xa-datasource-property> 
              <xa-datasource-property name="Password">${ds.password}</xa-datasource-property> 
              <exception-sorter-class-name>org.jboss.resource.adapter.jdbc.vendor.OracleExceptionSorter</exception-sorter-class-name> 
              <no-tx-separate-pools/> 
          </xa-datasource>
          <xa-datasource>
              <jndi-name>jdbc/processInstanceDS</jndi-name>
              <use-java-context>true</use-java-context>
              <isSameRM-override-value>false</isSameRM-override-value> 
              <xa-datasource-class>oracle.jdbc.xa.client.OracleXADataSource</xa-datasource-class>
              <xa-datasource-property name="URL">${ds.connection.url}</xa-datasource-property> 
              <xa-datasource-property name="User">${ds.user.name}</xa-datasource-property> 
              <xa-datasource-property name="Password">${ds.password}</xa-datasource-property> 
              <exception-sorter-class-name>org.jboss.resource.adapter.jdbc.vendor.OracleExceptionSorter</exception-sorter-class-name> 
              <no-tx-separate-pools/> 
          </xa-datasource>
          <xa-datasource>
              <jndi-name>jdbc/taskDS</jndi-name>
              <use-java-context>true</use-java-context>
              <isSameRM-override-value>false</isSameRM-override-value> 
              <xa-datasource-class>oracle.jdbc.xa.client.OracleXADataSource</xa-datasource-class>
              <xa-datasource-property name="URL">${ds.connection.url}</xa-datasource-property>
              <xa-datasource-property name="User">${ds.user.name}</xa-datasource-property> 
              <xa-datasource-property name="Password">${ds.password}</xa-datasource-property> 
              <exception-sorter-class-name>org.jboss.resource.adapter.jdbc.vendor.OracleExceptionSorter</exception-sorter-class-name> 
              <no-tx-separate-pools/> 
          </xa-datasource>
      </datasources>
      

       

       

      persistence.xml:

       

      <persistence-unit name="${pu.name}" transaction-type="JTA">
              <provider>org.hibernate.ejb.HibernatePersistence</provider>
              <jta-data-source>${pu.jta.data.source}</jta-data-source>
              <!-- <non-jta-data-source>${pu.jta.data.source}Unmanaged</non-jta-data-source> -->
      
              <properties>
                  <property name="hibernate.dialect" value="${pu.hibernate.dialect}" />
                  <property name="hibernate.hbm2ddl.auto" value="${pu.hibernate.hbm2ddl.auto}" />
                  <property name="hibernate.default_batch_fetch_size" value="${pu.hibernate.default_batch_fetch_size}" />
                  <property name="hibernate.show_sql" value="${pu.hibernate.show_sql}" />
                  <property name="hibernate.format_sql" value="true" />
      
                  <!-- Encoding -->
                  <property name="hibernate.connection.useUnicode" value="true" />
                  <property name="hibernate.connection.characterEncoding"
                      value="UTF-8" />
      
                  <!-- These are the default for JBoss EJB3, but not for HEM: -->
                  <property name="hibernate.cache.provider_class" value="org.hibernate.cache.HashtableCacheProvider" />
                  <property name="hibernate.transaction.manager_lookup_class"
                      value="${pu.hibernate.transaction.manager_lookup_class}" />
      
                  <!-- Binds the EntityManagerFactory to JNDI where Seam can look it up. 
                      This is only relevant when the container automatically loads the persistence 
                      unit, as is the case in JBoss AS 5. -->
                  <property name="jboss.entity.manager.factory.jndi.name"
                      value="${pu.jboss.entity.manager.factory.jndi.name}" />
              </properties>
      
              <!-- If the persistence.xml file is not under the same root directory or 
                  jar than your domain model then use the <jar-file> element to point to the 
                  jar containing your domain model. <jar-file>../../vehicles.jar</jar-file> -->
          </persistence-unit>
      
          <persistence-unit name="org.jbpm.persistence.jpa" transaction-type="JTA">
              <provider>org.hibernate.ejb.HibernatePersistence</provider>
              <jta-data-source>java:jdbc/processInstanceDS</jta-data-source>
              <class>org.drools.persistence.info.SessionInfo</class>
              <class>org.jbpm.persistence.processinstance.ProcessInstanceInfo</class>
              <class>org.jbpm.persistence.processinstance.ProcessInstanceEventInfo</class>
              <class>org.drools.persistence.info.WorkItemInfo</class>
      
              <properties>
                  <property name="hibernate.dialect" value="${pu.hibernate.dialect}" />
                      <property name="hibernate.hbm2ddl.auto" value="${pu.hibernate.hbm2ddl.auto}" />
                      <property name="hibernate.default_batch_fetch_size" value="${pu.hibernate.default_batch_fetch_size}" />
                      <property name="hibernate.show_sql" value="${pu.hibernate.show_sql}" />
                      <property name="hibernate.format_sql" value="true" />
      
                      <!-- Encoding -->
                      <property name="hibernate.connection.useUnicode" value="true" />
                      <property name="hibernate.connection.characterEncoding"
                          value="UTF-8" />
      
                      <!-- These are the default for JBoss EJB3, but not for HEM: -->
                      <property name="hibernate.cache.provider_class" value="org.hibernate.cache.HashtableCacheProvider" />
                      <property name="hibernate.transaction.manager_lookup_class"
                          value="${pu.hibernate.transaction.manager_lookup_class}" />
              </properties>
      
          </persistence-unit>
      
          <persistence-unit name="org.drools.task" transaction-type="JTA">
              <provider>org.hibernate.ejb.HibernatePersistence</provider>
              <jta-data-source>java:jdbc/taskDS</jta-data-source>
              <mapping-file>META-INF/taskOrm.xml</mapping-file>
      
              <class>org.jbpm.task.Attachment</class>
              <class>org.jbpm.task.Content</class>
              <class>org.jbpm.task.BooleanExpression</class>
              <class>org.jbpm.task.Comment</class>
              <class>org.jbpm.task.Deadline</class>
              <class>org.jbpm.task.Comment</class>
              <class>org.jbpm.task.Deadline</class>
              <class>org.jbpm.task.Delegation</class>
              <class>org.jbpm.task.Escalation</class>
              <class>org.jbpm.task.Group</class>
              <class>org.jbpm.task.I18NText</class>
              <class>org.jbpm.task.Notification</class>
              <class>org.jbpm.task.EmailNotification</class>
              <class>org.jbpm.task.EmailNotificationHeader</class>
              <class>org.jbpm.task.PeopleAssignments</class>
              <class>org.jbpm.task.Reassignment</class>
              <class>org.jbpm.task.Status</class>
              <class>org.jbpm.task.Task</class>
              <class>org.jbpm.task.TaskData</class>
              <class>org.jbpm.task.SubTasksStrategy</class>
              <class>org.jbpm.task.OnParentAbortAllSubTasksEndStrategy</class>
              <class>org.jbpm.task.OnAllSubTasksEndParentEndStrategy</class>
              <class>org.jbpm.task.User</class>
      
              <properties>
                  <property name="hibernate.dialect" value="${pu.hibernate.dialect}" />
                      <property name="hibernate.hbm2ddl.auto" value="${pu.hibernate.hbm2ddl.auto}" />
                      <property name="hibernate.default_batch_fetch_size" value="${pu.hibernate.default_batch_fetch_size}" />
                      <property name="hibernate.show_sql" value="${pu.hibernate.show_sql}" />
                      <property name="hibernate.format_sql" value="true" />
      
                      <!-- Encoding -->
                      <property name="hibernate.connection.useUnicode" value="true" />
                      <property name="hibernate.connection.characterEncoding"
                          value="UTF-8" />
      
                      <!-- These are the default for JBoss EJB3, but not for HEM: -->
                      <property name="hibernate.cache.provider_class" value="org.hibernate.cache.HashtableCacheProvider" />
                      <property name="hibernate.transaction.manager_lookup_class"
                          value="${pu.hibernate.transaction.manager_lookup_class}" />
              </properties>
      
          </persistence-unit>
      

       

      Bean:

       

      @Stateful
      @Name("register")
      public class RegistationBean implements Registration {
      
          @Out(scope = ScopeType.CONVERSATION)
          private User registerUser;
      
          @In(value="userRepository", create=true)
          private UserRepository userRepository;
      
          @Logger
          private Log log;
      
      
          private KnowledgeBase knowledgeBase;
      
          private Environment environment;
      
          @PersistenceUnit(unitName = "org.jbpm.persistence.jpa")
          private EntityManagerFactory emf;
      
      
          @Factory(value = "registerUser")
          public void createRegisterUser() {
              registerUser = new User();
          }
      
          public String register() {
      
              sendRegistrationEmail();
              userRepository.persist(registerUser);
      
              KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
              kbuilder.add(ResourceFactory.newClassPathResource("process/registration.bpmn"), ResourceType.BPMN2);
              knowledgeBase = kbuilder.newKnowledgeBase();
      
              environment = KnowledgeBaseFactory.newEnvironment();
              environment.set(EnvironmentName.ENTITY_MANAGER_FACTORY, emf);
      
              //AT THIS LINE THREAD HANGS AND SUSPENDS.
              StatefulKnowledgeSession ksession = JPAKnowledgeService.newStatefulKnowledgeSession(knowledgeBase, null, environment );
      
              log.info("#{registerUser.username} has been registered.");
      
              return "registred";
          }
      }
      

       

       

      I'm trying to run this very simple code for over one week and I'm frustrated at this moment :-)

      Anyone know how to solve my problem ?

      Maybe someone has some example how to configure jbpm 5.1 persistence using CMT ?

        • 1. jboss as 5 jbpm 5.1 persistence
          michal.warecki

          And one more thing : after 4-5 minutes there is OutOfMemory exception but I think it is caused by the memory leak while creating knowledge session.

          • 2. Re: jboss as 5 jbpm 5.1 persistence
            michal.warecki

            I have changed register() method to BMT but this time thread suspends on retrieving bitronix transaction manager and after 4 minutes there is java.lang.OutOfMemory exception. Is is possible that I just don't have enought memory to run this ? I set 512M ...

             

            Changed code:

             

            KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
            kbuilder.add(ResourceFactory.newClassPathResource("process/registration.bpmn"), ResourceType.BPMN2);
            knowledgeBase = kbuilder.newKnowledgeBase();
            
            environment = KnowledgeBaseFactory.newEnvironment();
            environment.set(EnvironmentName.ENTITY_MANAGER_FACTORY, Persistence.createEntityManagerFactory("org.jbpm.persistence.jpa"));
            environment.set(EnvironmentName.GLOBALS, new MapGlobalResolver());
            
                    //APPLICATION SUSPENDS HERE THIS TIME...
                    environment.set(EnvironmentName.TRANSACTION_MANAGER, TransactionManagerServices.getTransactionManager());
            
            StatefulKnowledgeSession ksession = JPAKnowledgeService.newStatefulKnowledgeSession(knowledgeBase, null, environment );
            
            UserTransaction ut = sc.getUserTransaction();
            
            ut.begin();
            ksession.startProcess("registration");
            ut.commit();
            

             

             

            Any suggestions ?

            • 3. Re: jboss as 5 jbpm 5.1 persistence
              salaboy21

              I think that the first option was right. If you are running inside a container you should use the container mechanisms to handle transactions.

              If the application stops at the ksession creations I supose that means that your transaction manager is failing in some way. Are you sure that it's not logging any failures in the container?

              Greetings.

              • 4. Re: jboss as 5 jbpm 5.1 persistence
                michal.warecki

                Yes, there are no errors. How drools interact with container transaction manager ? Should I set transaction manager in drools Environment ?

                Is there any example how to use jbpm persistence in container ? I'm using jboss as 5.1.0.GA.

                • 5. Re: jboss as 5 jbpm 5.1 persistence
                  salaboy21

                  Can you debug your application using the JBoss Transaction Manager and put a break point in:

                   

                  environment.set(EnvironmentName.TRANSACTION_MANAGER, TransactionManagerServices.getTransactionManager());

                  To see what it's being registered?

                  Greetings.

                  • 6. Re: jboss as 5 jbpm 5.1 persistence
                    michal.warecki

                    Isn't TransactionManagerServices.getTransactionManager() a Bitronix class and method ?

                    I'll debug this after I finish my work and I will let you know.

                     

                    Thanks for your help.

                    • 7. Re: jboss as 5 jbpm 5.1 persistence
                      michal.warecki

                      When I'm using Jboss Transaction Manager it suspends on this line ...

                      When I change to Bitronix Transaction ( in persistence.xml ) it is beign registered BitronixTransactionManager and suspends on line :

                              StatefulKnowledgeSession ksession = JPAKnowledgeService.newStatefulKnowledgeSession(knowledgeBase, null, environment );

                       

                      Exacly in KnowledgeStoreServiceImpl.java on line 116 ( when creating SingleSessionCommandService using reflection ).

                       

                      Any ideas ?

                      • 8. jboss as 5 jbpm 5.1 persistence
                        michal.warecki

                        Problem is solved !

                        There was slf4j-api.jar included in lib. Shame... Interesting why there were no errors :-)

                        Anyway thanks for help!

                        • 9. Re: jboss as 5 jbpm 5.1 persistence
                          mariemm

                          Michal, I can see that you use task persistence unit with transaction typ JTA. Did you manage to make it work?

                          <persistence-unit name="org.drools.task" transaction-type="JTA">

                          When I tried it, it end on:

                          java.lang.IllegalStateException: A JTA EntityManager cannot use getTransaction()

                                  at org.hibernate.ejb.AbstractEntityManagerImpl.getTransaction(AbstractEntityManagerImpl.java:324)

                                  at org.jbpm.task.service.TaskServiceSession.doOperationInTransaction(TaskServiceSession.java:707)

                                  at org.jbpm.task.service.TaskServiceSession.addTask(TaskServiceSession.java:134)

                                  ...

                          • 10. Re: jboss as 5 jbpm 5.1 persistence
                            michal.warecki

                            You can not use JTA in task PU. You have to use RESOURCE_LOCAL.

                             

                            PS. I don't know why drools tasks use BMT only.

                            • 11. Re: jboss as 5 jbpm 5.1 persistence
                              mariemm

                              Thanks for reply. That is what I thought.

                               

                              What do you mean 'BMT only'?

                               

                              I am trying to run jBPM on jBoss server and I am getting following exception always when something related to task is persisted (in this case TaskServiceSession.addTask()) inside of JTA transaction (new process starts in this transaction):

                               

                              2011-05-04 14:32:19,234 ERROR [org.hibernate.transaction.JDBCTransaction] (http-127.0.0.1-8080-3) JDBC commit failed

                              java.sql.SQLException: You cannot commit during a managed transaction!

                                  at org.jboss.resource.adapter.jdbc.BaseWrapperManagedConnection.jdbcCommit(BaseWrapperManagedConnection.java:659)

                                  at org.jboss.resource.adapter.jdbc.WrappedConnection.commit(WrappedConnection.java:486)

                                  at org.hibernate.transaction.JDBCTransaction.commitAndResetAutoCommit(JDBCTransaction.java:170)

                                  at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:146)

                                  at org.hibernate.ejb.TransactionImpl.commit(TransactionImpl.java:54)

                                  at org.jbpm.task.service.TaskServiceSession.doOperationInTransaction(TaskServiceSession.java:716)

                                  at org.jbpm.task.service.TaskServiceSession.addTask(TaskServiceSession.java:134)

                                  at com.company.wfe.impl.jbpm.GeneralTaskHandler.executeWorkItem(GeneralTaskHandler.java:165)

                                  at org.drools.persistence.jpa.processinstance.JPAWorkItemManager.internalExecuteWorkItem(JPAWorkItemManager.java:53)

                                  at org.jbpm.workflow.instance.node.WorkItemNodeInstance.internalTrigger(WorkItemNodeInstance.java:101)

                                  at org.jbpm.workflow.instance.impl.NodeInstanceImpl.trigger(NodeInstanceImpl.java:122)

                              ...

                               

                               

                              try {

                                       UserTransaction ut = (UserTransaction) new InitialContext().lookup("java:comp/UserTransaction");

                                       ut.begin();

                               

                                       processInstance = (WorkflowProcessInstance) ksession.startProcess(processId, params);

                               

                                       ut.commit();

                                   } catch (Throwable t) {

                                       t.printStackTrace();

                                   }

                               

                              Didn't you by any chance get similar problem?

                              • 12. Re: jboss as 5 jbpm 5.1 persistence
                                michal.warecki

                                You have to use tasks without JTA transactions.

                                ie.:

                                 

                                public ProcessInstance createRegistrationProcess(User user) {
                                          UserTransaction userTransaction = sessionContext.getUserTransaction();
                                          
                                          taskSession.addUser(new org.jbpm.task.User(user.getEmail()));
                                          
                                          try {
                                               userTransaction.begin();
                                               
                                               Map<String, Object> parameters = new HashMap<String, Object>();
                                               parameters.put("User", user);
                                               ProcessInstance processInstance = ksession.startProcess("com.clouddata.registration", parameters);
                                               KnowledgeRuntimeLogger logger = KnowledgeRuntimeLoggerFactory.newFileLogger(ksession, "registerLog");
                                               logger.close();
                                               
                                               userTransaction.commit();
                                               return processInstance;
                                          } catch (Exception e) {
                                               try {
                                                    userTransaction.rollback();
                                               } catch (Exception re) {
                                                    //do nothing
                                               }
                                          }
                                          
                                          return null;
                                     }

                                 

                                public ProcessInstance createRegistrationProcess(User user) {
                                          UserTransaction userTransaction = sessionContext.getUserTransaction();
                                          
                                          taskSession.addUser(new org.jbpm.task.User(user.getEmail()));
                                          
                                          try {
                                               userTransaction.begin();
                                               
                                               Map<String, Object> parameters = new HashMap<String, Object>();
                                               parameters.put("User", user);
                                               ProcessInstance processInstance = ksession.startProcess("com.clouddata.registration", parameters);
                                               KnowledgeRuntimeLogger logger = KnowledgeRuntimeLoggerFactory.newFileLogger(ksession, "registerLog");
                                               logger.close();
                                               
                                               userTransaction.commit();
                                               return processInstance;
                                          } catch (Exception e) {
                                               try {
                                                    userTransaction.rollback();
                                               } catch (Exception re) {
                                                    //do nothing
                                               } 
                                          } 
                                          
                                          return null;
                                     }
                                
                                
                                • 13. Re: jboss as 5 jbpm 5.1 persistence
                                  mariemm

                                  Thanks.

                                   

                                  I can avoid using tasks without JTA transactions in some cases, but not always.

                                  Eg. after start the process moves to first node -> it goes to my WorkItemHandler where I want to handle task (create new task .addTask()).

                                  This is still done within userTransaction.begin() and userTransaction.end() and ends with exception

                                  You cannot commit during a managed transaction!

                                   

                                  If you can give me another hint, it would be great.

                                  marie

                                  • 14. jboss as 5 jbpm 5.1 persistence
                                    zorin

                                    Note sure if you find any hints here, but this is the way we currently handle similar situations, I mean bringing together EJB Session transaction management and JBPM5.

                                     

                                    What we found is that the major issue with JBPM StatefulKnowledgeSession is that it does not attach itself to CMP transaction during the startProcess(...) or signal(...). Playing with Bitronix Transaction manager did bring much help.

                                     

                                    However, any subsequent calls from the workflow to EJB Session methods work as they should (i.e. JBoss's transaction manager attaches itself well to a transaction that is started from process instance). For example, transaction is executed properly when making a call from Script node to local or remote interface of an EJB session.

                                     

                                    So, without breaking the framework, and until a proper fix or better workaround is found, we use the following approach to transaction management:

                                     

                                    When invoking ksession.startProcess(...) or signal(...) from within CMP Session, mark relevant EJB session method as @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED), and do manual transaction management of your records, while making sure that ksession methods are invoked without the transaction, eg.:

                                     

                                    @Stateless

                                    public class InstanceManager implements InstanceManagerRemote,

                                            InstanceManagerLocal {

                                    ...

                                    @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED

                                    public long createLicenseManagementProcess(String procId, ...)

                                    {

                                         ...

                                         // create workflow instance, WITHOUT TX!!!!

                                        ProcessInstance inst = ksession.startProcess(procId);

                                     

                                        // handle your own EJB Entity records

                                        UserTransaction tx = (UserTransaction) new InitialContext().lookup("java:comp/UserTransaction");

                                        logger.info("have UserTransaction " + tx.toString());

                                        tx.begin();

                                        LicenseEntity entity = new LicenseEntity();

                                        entity.setWorkflowInstanceId(inst.getId());

                                        ...

                                        em.persist();

                                        tx.commit();

                                    }

                                     

                                     

                                    // this is the method which is called from ProcessEventListener

                                    public void callbackProcessCompleted(long workflowId)

                                    {

                                      // no need to do manual transaction handling

                                      ... update your own record status using EntityManager directly

                                    }

                                     

                                    // this is the method which is called from BPMN Script via Local interface

                                    public void paymentMade(long workflowId, ....)

                                    {

                                      // no need to do manual transaction handling

                                      ... create payment record status using EntityManager directly

                                    }

                                     

                                    } // end of stateless session bean

                                     

                                    Here is an important bit.

                                    If the first node of a workflow tries to get back to EJB Session, make sure that your data is already there and commited to the database.

                                    Have a look again at createLicenseManagementProcess(...) method.

                                    - First step: we create a process, by calling startProcess(...).

                                    - Second step: we create own record by storing the workflow Id of a created process.

                                    - If the first node in a workflow is a Script which tries to get back to and call any method, such as paymentMade(long workflowId), transaction will work properly, but data will not be there yet.

                                     

                                    One of the solutions/tricks, is breaking the transaction by breaking the workflow via making a first node to be an Event Node waiting for 'start' event. See extended code below:

                                     

                                        // create workflow instance, WITHOUT TX!!!!

                                        // but now this workflow will stop on first Event Node waiting for 'start' signal

                                        ProcessInstance inst = ksession.startProcess(procId);

                                     

                                        // handle your own EJB Entity records

                                        ...

                                        tx.commit();

                                     

                                        // all data is commited, now we can kick-start the workflow

                                        ksession.signalEvent("start", null, inst.getId());

                                        // this is the end of startPrtocess method

                                    }

                                     

                                    [Disclaimer: We did not have a lot of time to do deep investigation why things do not work as we think they should, so we had to quickly come up with own approach to persistence, transaction handling, clustering and safe restarts of JBoss AS. This approach may limit the use of BPMN and JBPM API, but can not bend the rules. So when a better solution is found, system would remain backward compatible.]

                                    1 2 Previous Next