12 Replies Latest reply on May 26, 2010 11:08 PM by rebody

    start a process within another process in jbpm 4.3

    matrixpooh

      Hi,

       

      Trying to port existing 3.2 workflow implementation into 4.3

       

      My requirement is to be able to calculate a number of sub-processes to start at a certain step of the main process. Since I haven't found the way to do this in jpdl/bpmn, I'm doing this programmatically:

      When a main process is instantiated via

       

      ProcessInstance processInstance = WorkflowTest.processEngine.getExecutionService().startProcessInstanceByKey("rmc", variables);

       

      it proceeds through a few java tasks and stops at the wait state. One of those java tasks runs a few calculations and decides to create 2-3 processes (i'm calling them sub-processes for separation of concerns) via:

       

      ProcessInstance processInstance = WorkflowTest.processEngine.getExecutionService().startProcessInstanceByKey("9.any");

       

      The main process stops at the state task and flushes hibernate session.

       

      The hibernate does the following:

      inserts records into jbpm4_execution for main process

      inserts records into jbpm4_execution for sub-processes

      /** does some inserts into history tables */

      updates ID_ in jbpm4_execution for main process

      updates ID_ in jbpm4_execution for sub-processes   ---- The Exception is throw right here

       

      The exception is thrown due to the ID_ field having a unique constrain. Upon insert, ID_ is null, then it's updated with key_+"."+dbid_ value. So if my dbid is 1090015 and process definition key is "rmc", the ID_ is "rms.109001"

      Since hibernate first inserts then updates, it fails to insert the second row that also has ID_=null at that moment.

       

      I can think of only two solutions:

      (a) drop unique constrain

      (b) add 1 line to ExecutionImpl.java::save() right before saving:

      this.id = this.dbid;

      if (dbSession!=null) {
            dbSession.save(this);

      }

       

      Both of those solutions don't really look apealing. Any suggestions would be greatly appreciated.

        • 1. Re: start a process within another process in jbpm 4.3
          matrixpooh

          After a little more investigation,

           

          public class RmExecutionImpl extends ExecutionImpl{

           

              private static final long serialVersionUID = 7281196660125907487L;

           

              @Override
                protected void save() {             
                  this.dbid = DbidGenerator.getDbidGenerator().getNextId();
                  /**
                   * this is the line that makes the diff: set JBPM4_EXECUTION::ID_ to
                   * unique value upon INSERT. It affects creating a process within
                   * another just created and not yet persisted process.
                   */
                  super.id = new Long(super.dbid).toString();
                  super.save();
              }
          }

           

          and assuming you follow examples setup, in jbpm.execution.hbm.xml and jbpm.task.execution.xml substitute all occurrences of ExecutionImpl with RMExecutionImpl, i.e.

           

          <class name="RMExecutionImpl"  table="JBPM4_EXECUTION" discriminator-value="pvm">

           

          The only thing is: had to keep package name org.jbpm.pvm.internal.model

           

          Would still appreciate any other suggestions

          • 2. Re: start a process within another process in jbpm 4.3
            matrixpooh
            • 3. Re: start a process within another process in jbpm 4.3
              rebody

              Hi Al,

               

              Could you provide a testcase that can reproduce this scenario?  Actually, I am not very clear for what you did, so I don't know how to reproduce it.

               

              Thank you very much.

              • 4. Re: start a process within another process in jbpm 4.3
                matrixpooh

                In short, I start a process that happily follows a few steps before it hits a 'wait' state where it's persisted to db. At some point, i have to derive by the rules if any other sub-processes have to be created. Since jbpm provides an option to create only 1 subprocess at a given step, I'm openning subprocesses programmatically, i.e. in CreateSubprocesses activity handler:

                 

                        {code}

                       //calculate groups to assign to a swimlane

                         taskAssignees = ...;
                           
                          assigneeGroups.put(SharedConstants.KEY_SWIMLANE_CANDIDATE_GROUPS, taskAssignees);
                           
                           ProcessInstance processInstance = executionService.startProcessInstanceByKey("subprocess_1", assigneeGroups);   

                {/code}

                Again, all of the above is done in an activity handler of the process that has just been instantiated and hasn't been saved to db yet.

                 

                Here's a shortened version of my jpdl:

                 

                {code:xml}

                <process key="main" name="main" xmlns="http://jbpm.org/4.3/jpdl">
                  
                   <start g="5,23,48,48" name="start">
                      <transition g="141,46:-88,-15" name="open.case" to="Create sub-process"/>
                   </start>


                   <state g="306,193,148,52" name="Wait For Update">
                      <transition g="-23,-24" name="end" to="end1"/>
                   </state>
                  
                   <custom g="239,26,138,52" name="Create sub-process" class="CreateSubprocesses">
                      <transition g="484,52:-108,-17" name="to-split-paths" to="Wait For Update"/>
                   </custom>
                  <end g="566,493,48,48" name="end1"/>


                </process>

                {/code:xml}

                 

                and one of possible sub-processes (simplified):

                 

                {code:xml}

                <?xml version="1.0" encoding="UTF-8"?>

                 

                <process name="test" key="test" xmlns="http://jbpm.org/4.3/jpdl">

                 

                   <swimlane candidate-groups="#{assigned.responsibilities}" name="assigned-group"/>

                   <start name="start1" g="16,21,48,48">
                      <transition name="to task1" to="task1" g="-17,-20"/>
                   </start>
                  
                   <end name="end1" g="219,17,48,48"/>
                  
                   <task name="task1" g="96,16,92,52" swimlane="assigned-group">
                      <transition name="to end1" to="end1" g="-20,-19"/>
                   </task>
                  
                </process>

                {/code:xml}

                 

                 

                • 5. Re: start a process within another process in jbpm 4.3
                  rebody

                  Hi Al,

                   

                  I  create a testcase using your code and xml, but still cannot reproduce this problem, neither on jBPM-4.4-SNAPHOT nor jBPM-4.3.  So please have a look at attach and show me more details about this problem.  Otherwise I will close the issue as 'cannot reproduce'.  Thank you very much.

                  • 6. Re: start a process within another process in jbpm 4.3
                    matrixpooh

                    Hi HiuSheng,

                     

                    Thanks for the test, it seems to be proper.

                     

                    What is the repository for the unit test? If it's an in-memory db, please try with a real database. I'm using db2.

                    • 7. Re: start a process within another process in jbpm 4.3
                      rebody

                      Hi Al,

                       

                      I changed hsqldb to mysql,  and the testcase could still pass.  I didn't know anything about db2 and there is no qa environment for db2 on jbpm project. so if we couldn't find more details,  I am afraid that I must left this issue to others who can handle db2.

                       

                      Attached the testcase with mysql database configuration.

                      • 8. Re: start a process within another process in jbpm 4.3
                        matrixpooh

                        Hi HiuSheng,

                         

                        Your help is grately appreciated.

                         

                        I think I've got to the bottom of it: I'm failing with ConstraintViolationException running against the code included into jbpm-4.4-SNAPSHOT. I checked out the code base from http://anonsvn.jboss.org/repos/jbpm (rev. 6169).

                        • 9. Re: start a process within another process in jbpm 4.3
                          rebody

                          Hi Al,

                           

                          Could you use my testcase to reproduce the problem?  If you can reproduce it with my testcase, please show me the whole exception stack trace.  Maybe I could find something on it.  Thank you very much.

                          • 10. Re: start a process within another process in jbpm 4.3
                            matrixpooh

                            org.hibernate.exception.ConstraintViolationException: could not insert: [org.jbpm.pvm.internal.model.ExecutionImpl]

                            at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:94)

                            at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66)

                            at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2285)

                            at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2678)

                            at org.hibernate.action.EntityInsertAction.execute(EntityInsertAction.java:79)

                            at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:279)

                            at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:263)

                            at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:167)

                            at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321)

                            at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:50)

                            at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1028)

                            at org.jbpm.pvm.internal.tx.HibernateSessionResource.prepare(HibernateSessionResource.java:56)

                            at org.jbpm.pvm.internal.tx.StandardTransaction.commit(StandardTransaction.java:107)

                            at org.jbpm.pvm.internal.tx.StandardTransaction.complete(StandardTransaction.java:64)

                            at org.jbpm.pvm.internal.tx.StandardTransactionInterceptor.execute(StandardTransactionInterceptor.java:61)

                            at org.jbpm.pvm.internal.svc.EnvironmentInterceptor.executeInNewEnvironment(EnvironmentInterceptor.java:53)

                            at org.jbpm.pvm.internal.svc.EnvironmentInterceptor.execute(EnvironmentInterceptor.java:40)

                            at org.jbpm.pvm.internal.svc.RetryInterceptor.execute(RetryInterceptor.java:56)

                            at org.jbpm.pvm.internal.svc.SkipInterceptor.execute(SkipInterceptor.java:43)

                            at org.jbpm.pvm.internal.svc.ExecutionServiceImpl.startProcessInstanceByKey(ExecutionServiceImpl.java:66)

                            at com.gs.crd.requestmanager.workflow.test.OpenProcessWithinProcessTest.testDefault(OpenProcessWithinProcessTest.java:79)

                            at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)

                            at java.lang.reflect.Method.invoke(Method.java:597) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)

                            at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)

                            at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)

                            at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)

                            at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)

                            at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:31)

                            at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:76)

                            at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)

                            at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)

                            at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184) at org.junit.runners.ParentRunner.run(ParentRunner.java:236) at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:46) at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197) Caused by: com.ibm.db2.jcc.b.SqlException: DB2 SQL error: SQLCODE: -803, SQLSTATE: 23505, SQLERRMC: 3;REQUESTMANAGER_WF_DEV.JBPM4_EXECUTION at com.ibm.db2.jcc.b.hh.b(hh.java:1369) at com.ibm.db2.jcc.b.hh.c(hh.java:1356) at com.ibm.db2.jcc.c.db.k(db.java:352) at com.ibm.db2.jcc.c.db.a(db.java:60) at com.ibm.db2.jcc.c.t.a(t.java:52) at com.ibm.db2.jcc.c.tb.b(tb.java:202) at com.ibm.db2.jcc.b.ih.ab(ih.java:1898) at com.ibm.db2.jcc.b.ih.d(ih.java:2467) at com.ibm.db2.jcc.b.ih.W(ih.java:525) at com.ibm.db2.jcc.b.ih.executeUpdate(ih.java:508) at org.apache.commons.dbcp.DelegatingPreparedStatement.executeUpdate(DelegatingPreparedStatement.java:102) at org.apache.commons.dbcp.DelegatingPreparedStatement.executeUpdate(DelegatingPreparedStatement.java:102) at org.hibernate.jdbc.NonBatchingBatcher.addToBatch(NonBatchingBatcher.java:46) at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2265) ... 42 more

                            • 11. Re: start a process within another process in jbpm 4.3
                              rebody

                              Hi Al,

                               

                              I read your post again, and find out you had already point out the key of this problem.  I am sorry for not look at this before.

                               

                              Because hibernate will insert null for id_ column then update it to the related value, seems DB2 didn't allow unique column with multiple column which value is null, as well as sql server.  So I think maybe your solution is right.  I will go back and have a try.  Thank you for your patient.

                              • 12. Re: start a process within another process in jbpm 4.3
                                rebody

                                Hi Al,

                                 

                                I update a patch for this issue.  But I cannot test it by myself,  because of no db2 environment.  Maybe I can commit it and you could check out the latest version of svn and test it?