6 Replies Latest reply on Dec 18, 2006 9:02 AM by jviolette123

    SuperState DB tests

    jviolette123

      We are having some difficulty loading a process definition with a SuperState from an Oracle database.

      We looked in the jbpm-3.1 src/java.jbpm.test packages and did not see any database tests that included a super state. The closest was org.jbpm.graph.def.SuperStateTest, but that built a process definition from an XML string.

      Is there a reason why the super states are not unit tested against the database ?

      Our process is the following:
      milestoneProcess
      - pending (superstate)
      --- due (state)
      --- tbd (state)
      --- forecasted (state)
      - complete (state)


      We successfully ran our own JUnit superstate test using an XML file.
      We successfully saved the superstate to the database. (all the records that should have been there were there)

      When we loaded the process definition, using the graphSession.loadProcessDefinition method, the process definition did not include the superstate. This broke our JUnit tests because we use the superstate in our token path name. So 'pending/due' reverted to just 'due'.

        • 1. Re: SuperState DB tests
          jviolette123

          We have isolated this bug to the following:
          When a process node list is loaded, only the nodes where superstate==null should be added via the query. However, the default behavior is to add all nodes to the query.

          We have not tested nested superstates, so there still may be a similar issue there.

          In the example, (details to follow), Hibernate has the following data:
          process definition milestone (pid=1)

          node start id=2, pid=1, superstateid=null, index=0
          node pending id=3, pid=1, superstateid =null, index=1
          node due id=4, pid=1, superstateid=3, index=0
          node tbd id=5, pid=1, superstateid=3, index=1
          node forecasted id=6, pid=1, superstateid=3, index=2
          node completed id=7, pid=1, superstateid=null, index=2
          node end id=8, pid=1, superstateid=null, index=3


          With the production 3.1 jbpm, the process defintion oracle query is:
          select nodes0_.PROCESSDEFINITION_ as PROCESSD4_1_, nodes0_.ID_ as ID1_1_, nodes0_.NODECOLLECTIONINDEX_ as NODECOL14_1_, nodes0_.ID_ as ID1_2_0_, nodes0_.NAME_ as NAME3_2_0_, nodes0_.PROCESSDEFINITION_ as PROCESSD4_2_0_, nodes0_.ISASYNC_ as ISASYNC5_2_0_, nodes0_.ACTION_ as ACTION6_2_0_, nodes0_.SUPERSTATE_ as SUPERSTATE7_2_0_, nodes0_.SUBPROCESSDEFINITION_ as SUBPROCE8_2_0_, nodes0_.DECISIONEXPRESSION_ as DECISION9_2_0_, nodes0_.DECISIONDELEGATION as DECISIO10_2_0_, nodes0_.SIGNAL_ as SIGNAL11_2_0_, nodes0_.CREATETASKS_ as CREATET12_2_0_, nodes0_.ENDTASKS_ as ENDTASKS13_2_0_, nodes0_.CLASS_ as CLASS2_2_0_ from JBPM_NODE nodes0_ where nodes0_.PROCESSDEFINITION_=1

          This returns all 7 rows.

          However, the process definition node list is built incorrectly. The node list at index 0 uses the second index 0 (due) node, which is a substate of pending. Similarly, index 1 is also corrupted:
          node due id=4, pid=1, superstateid=3, index=0
          node tbd id=5, pid=1, superstateid=3, index=1
          node completed id=7, pid=1, superstateid=null, index=2
          node end id=8, pid=1, superstateid=null, index=3

          The correct query from the process defintion should only include those nodes that have a superstateid==null.



          select nodes0_.PROCESSDEFINITION_ as PROCESSD4_1_, nodes0_.ID_ as ID1_1_, nodes0_.NODECOLLECTIONINDEX_ as NODECOL14_1_, nodes0_.ID_ as ID1_2_0_, nodes0_.NAME_ as NAME3_2_0_, nodes0_.PROCESSDEFINITION_ as PROCESSD4_2_0_, nodes0_.ISASYNC_ as ISASYNC5_2_0_, nodes0_.ACTION_ as ACTION6_2_0_, nodes0_.SUPERSTATE_ as SUPERSTATE7_2_0_, nodes0_.SUBPROCESSDEFINITION_ as SUBPROCE8_2_0_, nodes0_.DECISIONEXPRESSION_ as DECISION9_2_0_, nodes0_.DECISIONDELEGATION as DECISIO10_2_0_, nodes0_.SIGNAL_ as SIGNAL11_2_0_, nodes0_.CREATETASKS_ as CREATET12_2_0_, nodes0_.ENDTASKS_ as ENDTASKS13_2_0_, nodes0_.CLASS_ as CLASS2_2_0_ from JBPM_NODE nodes0_ where nodes0_.PROCESSDEFINITION_=1 and nodes0_.SUPERSTATE_ is null

          Here is the XML file for this process definition Note that the xml brackets did not show up correctly, so I replaced them with the html version:
          <process-definition name="milestone">
          <start-state name='start'>
          <transition name="create" to='pending' />
          </start-state>
          <super-state name='pending'>
          <state name='due'>
          <transition name="late" to="tbd">
          </transition>
          </state>
          <state name='forecasted'>
          <transition name="late" to="tbd">
          </transition>
          </state>
          <state name='tbd'>
          </state>
          <transition name="reset" to='pending' />
          <transition name="complete" to='completed' />
          <transition name="forecast" to='/pending/forecasted' />
          </super-state>
          <state name="completed">
          <transition name="reset" to="pending" />
          <transition name="update" to="completed" />
          </state>
          <end-state name='end'>
          </end-state>
          </process-definition>

          Here is the JUnit test method that runs this file, within a TestCase that extends AbstractDbTestCase:

          public void testMsNodeSuperState() throws Exception {
          // create a process definition
          FileInputStream fis = new FileInputStream(MilestoneDefinitionPgd.XML_FILE);
          ProcessDefinition processDefinition = ProcessDefinition.parseXmlInputStream(fis);

          processDefinition = saveAndReload(processDefinition);

          SuperState superState = (SuperState) processDefinition.getNode("pending");
          assertNotNull(superState); // fails
          Node node = superState.getNode("due");
          assertNotNull(node);
          assertNotNull(superState);
          assertSame(node, superState.getNode("due"));
          }

          • 2. Re: SuperState DB tests
            jviolette123

            This issue can be fixed by adding in the following where clause to the nodes list property mapping definition in the ProcessDefinition.hbm.xml file:

            <list name="nodes"
            cascade="all"
            where="nodes0_.SUPERSTATE_ is null"
            >
            ...

            </list>

            • 3. Re: SuperState DB tests
              tom.baeyens

              this looks like a great suggestion. i'll try to examine the fix that you propose asap. that might take a couple of days, though.

              • 4. Re: SuperState DB tests - the fix throws Exception when one

                I applied the above fix but then undeploying a process definion throws Excpetions.

                The test case broken is:

                public void testUndeploy() {
                 ProcessDefinition procDef = new ProcessDefinition("testUndeploy");
                 State s = new State("testnode");
                 procDef.addNode(s);
                 jbpmContext.deployProcessDefinition(procDef);
                 newTransaction();
                 ProcessDefinition pd = jbpmContext.getGraphSession().findLatestProcessDefinition("testUndeploy");
                 jbpmContext.getGraphSession().deleteProcessDefinition(pd);
                 newTransaction();
                 }
                


                The hibernate query that creates the problem is:

                Hibernate:
                 update
                 JBPM_NODE
                 set
                 PROCESSDEFINITION_=null,
                 NODECOLLECTIONINDEX_=null
                 where
                 PROCESSDEFINITION_=?
                 and (
                 nodes0_.SUPERSTATE_ is null
                 )
                


                Finally the exception thrown is:

                12:55:04,534 [main] WARN JDBCExceptionReporter - SQL Error: 904, SQLState: 42000
                12:55:04,534 [main] ERROR JDBCExceptionReporter - ORA-00904: "NODES0_"."SUPERSTATE_": invalid identifier
                
                12:55:04,534 [main] WARN JDBCExceptionReporter - SQL Error: 904, SQLState: 42000
                12:55:04,550 [main] ERROR JDBCExceptionReporter - ORA-00904: "NODES0_"."SUPERSTATE_": invalid identifier
                
                12:55:04,550 [main] ERROR AbstractFlushingEventListener - Could not synchronize database state with session
                org.hibernate.exception.SQLGrammarException: Could not execute JDBC batch update
                 at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:67)
                 at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)
                 at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:249)
                 at org.hibernate.jdbc.AbstractBatcher.prepareStatement(AbstractBatcher.java:92)
                 at org.hibernate.jdbc.AbstractBatcher.prepareStatement(AbstractBatcher.java:87)
                 at org.hibernate.jdbc.AbstractBatcher.prepareBatchStatement(AbstractBatcher.java:218)
                 at org.hibernate.persister.collection.AbstractCollectionPersister.remove(AbstractCollectionPersister.java:1030)
                 at org.hibernate.action.CollectionRemoveAction.execute(CollectionRemoveAction.java:28)
                 at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:248)
                 at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:232)
                 at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:141)
                 at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:298)
                 at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:27)
                 at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1000)
                 at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:338)
                 at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:106)
                 at org.jbpm.persistence.db.DbPersistenceService.close(DbPersistenceService.java:162)
                 at org.jbpm.svc.Services.close(Services.java:211)
                 at org.jbpm.JbpmContext.close(JbpmContext.java:139)
                 ....
                Caused by: java.sql.BatchUpdateException: ORA-00904: "NODES0_"."SUPERSTATE_": invalid identifier
                
                 at oracle.jdbc.driver.DatabaseError.throwBatchUpdateException(DatabaseError.java:367)
                 at oracle.jdbc.driver.OraclePreparedStatement.executeBatch(OraclePreparedStatement.java:8739)
                 at com.mchange.v2.c3p0.impl.NewProxyPreparedStatement.executeBatch(NewProxyPreparedStatement.java:1723)
                 at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:48)
                 at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:242)
                


                • 5. Re: SuperState DB tests

                  It seems that having

                  where="SUPERSTATE_ is null"
                  


                  instead of

                  where="nodes0_.SUPERSTATE_ is null"


                  fixes the latest problem with undeploy.
                  I dont know if this is correct but so my test cases run.


                  • 6. Re: SuperState DB tests
                    jviolette123

                    Thank you for finding this better syntax.