/* * JBoss, Home of Professional Open Source * Copyright 2005, JBoss Inc., and individual contributors as indicated * by the @authors tag. See the copyright.txt in the distribution for a * full listing of individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.jbpm.graph.node; import org.hibernate.criterion.Order; import org.jbpm.context.exe.ContextInstance; import org.jbpm.db.AbstractDbTestCase; import org.jbpm.graph.def.ProcessDefinition; import org.jbpm.graph.exe.ProcessInstance; import org.jbpm.graph.exe.Token; import org.jbpm.graph.log.ProcessStateLog; public class ProcessStateDbTest extends AbstractDbTestCase { public void testProcessStateName() { ProcessDefinition processDefinition = ProcessDefinition.parseXmlString("<process-definition>" + " <process-state name='subprocess' />" + "</process-definition>"); processDefinition = saveAndReload(processDefinition); ProcessState processState = (ProcessState) processDefinition.getNode("subprocess"); assertEquals("subprocess", processState.getName()); } public void testRecursiveProcessDefinition() { ProcessDefinition processDefinition = ProcessDefinition.parseXmlString("<process-definition name='recursive process'>" + " <start-state>" + " <transition to='first wait' />" + " </start-state>" + " <state name='first wait'>" + " <transition to='subprocessnode' />" + " <transition name='done' to='end' />" + " </state>" + " <process-state name='subprocessnode'>" + " <sub-process name='recursive process' />" + " <transition to='end' />" + " </process-state>" + " <end-state name='end' />" + "</process-definition>"); deployProcessDefinition(processDefinition); ProcessInstance superProcessInstance = jbpmContext.newProcessInstanceForUpdate("recursive process"); superProcessInstance.signal(); superProcessInstance.signal(); processJobs(); superProcessInstance = jbpmContext.loadProcessInstance(superProcessInstance.getId()); Token superToken = superProcessInstance.getRootToken(); assertEquals("subprocessnode", superToken.getNode().getName()); ProcessInstance subProcessInstance = superToken.getSubProcessInstance(); assertEquals("recursive process", subProcessInstance.getProcessDefinition().getName()); Token subToken = subProcessInstance.getRootToken(); assertEquals("first wait", subToken.getNode().getName()); subProcessInstance.signal("done"); jbpmContext.save(subProcessInstance); processJobs(); superProcessInstance = graphSession.loadProcessInstance(superProcessInstance.getId()); assertTrue(subProcessInstance.hasEnded()); assertTrue(superProcessInstance.hasEnded()); } public void testMultipleRecursiveProcessDefinitions() { for (int i = 0; i < 10; i++) { testRecursiveProcessDefinition(); newTransaction(); } } public void testProcessStateSubProcessDefinition() { // create the subprocess ProcessDefinition subProcessDefinition = new ProcessDefinition("sub"); // store the subprocess in the database deployProcessDefinition(subProcessDefinition); // create the super process ProcessDefinition superProcessDefinition = ProcessDefinition.parseXmlString("<process-definition name='super'>" + " <process-state name='subprocess' />" + "</process-definition>"); // resolve the reference to the subprocess ProcessState processState = (ProcessState) superProcessDefinition.getNode("subprocess"); processState.setSubProcessDefinition(subProcessDefinition); // save and reload the superprocess superProcessDefinition = saveAndReload(superProcessDefinition); processState = (ProcessState) superProcessDefinition.getNode("subprocess"); assertNotNull("sub", processState.getSubProcessDefinition().getName()); } public void testProcessStateStartVariableMappings() { ProcessDefinition processDefinition = ProcessDefinition.parseXmlString("<process-definition>" + " <process-state name='subprocess'>" + " <variable name='startsuperone' access='read,write' mapped-name='startsubone' />" + " <variable name='startsupertwo' access='read,write' mapped-name='startsubtwo' />" + " <variable name='startsuperthree' access='read,write' mapped-name='startsubthree' />" + " </process-state>" + "</process-definition>"); processDefinition = saveAndReload(processDefinition); ProcessState processState = (ProcessState) processDefinition.getNode("subprocess"); assertEquals(3, processState.variableAccesses.size()); } public void testSubProcessBindingWithLatestVersion() { final int versionCount = 3; for (int i = 0; i < versionCount; i++) { deployProcessDefinition(new ProcessDefinition("the multiversion subprocess")); } ProcessDefinition processDefinitionTwo = ProcessDefinition.parseXmlString("<process-definition>" + " <process-state name='the sub process state'>" + " <sub-process name='the multiversion subprocess'/>" + " </process-state>" + "</process-definition>"); processDefinitionTwo = saveAndReload(processDefinitionTwo); ProcessState processState = (ProcessState) processDefinitionTwo.getNode("the sub process state"); assertEquals("the multiversion subprocess", processState.getSubProcessDefinition() .getName()); assertEquals(3, processState.getSubProcessDefinition().getVersion()); } public void testAverageSubProcess() { ProcessDefinition subProcessDefinition = ProcessDefinition.parseXmlString("<process-definition name='subprocess'>" + " <start-state name='start'>" + " <transition to='wait' />" + " </start-state>" + " <state name='wait'>" + " <transition to='end' />" + " </state>" + " <end-state name='end' />" + "</process-definition>"); deployProcessDefinition(subProcessDefinition); ProcessDefinition superProcessDefinition = ProcessDefinition.parseXmlString("<process-definition name='superprocess'>" + " <start-state name='start'>" + " <transition to='sub process state' />" + " </start-state>" + " <process-state name='sub process state'>" + " <sub-process name='subprocess' />" + " <variable name='a' access='read' mapped-name='A' />" + " <variable name='b' mapped-name='B' />" + " <variable name='c' access='write' mapped-name='C' />" + " <transition to='wait' />" + " </process-state>" + " <state name='wait' />" + "</process-definition>"); deployProcessDefinition(superProcessDefinition); ProcessInstance processInstance = jbpmContext.newProcessInstanceForUpdate("superprocess"); ContextInstance contextInstance = processInstance.getContextInstance(); contextInstance.setVariable("a", "1"); contextInstance.setVariable("b", "1"); contextInstance.setVariable("c", "1"); processInstance.signal(); processJobs(); long processInstanceId = processInstance.getId(); long subProcessInstanceId = processInstance.getRootToken().getSubProcessInstance().getId(); processInstance = jbpmContext.loadProcessInstance(processInstanceId); assertNotNull(processInstance.getRootToken().getSubProcessInstance()); assertEquals("sub process state", processInstance.getRootToken().getNode().getName()); contextInstance = processInstance.getContextInstance(); assertEquals("1", contextInstance.getVariable("a")); assertEquals("1", contextInstance.getVariable("b")); assertEquals("1", contextInstance.getVariable("c")); ProcessInstance subProcessInstance = jbpmContext.loadProcessInstance(subProcessInstanceId); assertEquals("wait", subProcessInstance.getRootToken().getNode().getName()); ContextInstance subContextInstance = subProcessInstance.getContextInstance(); assertEquals("1", subContextInstance.getVariable("A")); assertEquals("1", subContextInstance.getVariable("B")); assertNull(subContextInstance.getVariable("C")); subContextInstance.setVariable("A", "2"); subContextInstance.setVariable("B", "2"); subContextInstance.setVariable("C", "2"); subProcessInstance.signal(); jbpmContext.save(subProcessInstance); processJobs(); assertTrue(jbpmContext.loadProcessInstance(subProcessInstanceId).hasEnded()); processInstance = jbpmContext.loadProcessInstance(processInstanceId); assertEquals("wait", processInstance.getRootToken().getNode().getName()); contextInstance = processInstance.getContextInstance(); assertEquals("1", contextInstance.getVariable("a")); assertEquals("2", contextInstance.getVariable("b")); assertEquals("2", contextInstance.getVariable("c")); } public void testSubProcessBindingByVersion() { ProcessDefinition processDefinitionOne = new ProcessDefinition("the ultimate subprocess"); deployProcessDefinition(processDefinitionOne); ProcessDefinition processDefinitionTwo = ProcessDefinition.parseXmlString("<process-definition name='other'>" + " <process-state name='the sub process state'>" + " <sub-process name='the ultimate subprocess' version='1' />" + " </process-state>" + "</process-definition>"); processDefinitionTwo = saveAndReload(processDefinitionTwo); ProcessState processState = (ProcessState) processDefinitionTwo.getNode("the sub process state"); assertEquals("the ultimate subprocess", processState.getSubProcessDefinition().getName()); assertEquals(1, processState.getSubProcessDefinition().getVersion()); } public void testSubProcessLogs() { ProcessDefinition subProcessDefinition = ProcessDefinition.parseXmlString("<process-definition name='subprocess'>" + " <start-state name='start'>" + " <transition to='wait' />" + " </start-state>" + " <state name='wait'>" + " <transition to='end' />" + " </state>" + " <end-state name='end' />" + "</process-definition>"); deployProcessDefinition(subProcessDefinition); ProcessDefinition superProcessDefinition = ProcessDefinition.parseXmlString("<process-definition name='superprocess'>" + " <start-state name='start'>" + " <transition to='sub process state' />" + " </start-state>" + " <process-state name='sub process state'>" + " <sub-process name='subprocess' />" + " <transition to='wait' />" + " </process-state>" + " <state name='wait' />" + "</process-definition>"); deployProcessDefinition(superProcessDefinition); ProcessInstance superProcessInstance = jbpmContext.newProcessInstanceForUpdate("superprocess"); superProcessInstance.signal(); processJobs(); long subProcessInstanceId = superProcessInstance.getRootToken() .getSubProcessInstance() .getId(); ProcessInstance subProcessInstance = jbpmContext.loadProcessInstance(subProcessInstanceId); subProcessInstance.signal(); jbpmContext.save(subProcessInstance); processJobs(); ProcessStateLog processStateLog = (ProcessStateLog) session.createCriteria(ProcessStateLog.class) .addOrder(Order.desc("enter")) .setMaxResults(1) .uniqueResult(); assertEquals(subProcessInstanceId, processStateLog.getSubProcessInstance().getId()); assertEquals(superProcessInstance.getId(), processStateLog.getToken() .getProcessInstance() .getId()); } public void testDynamicProcessBinding() { ProcessDefinition processDefinitionOne = ProcessDefinition.parseXmlString("<process-definition name='subprocess1'>" + " <start-state name='start'>" + " <transition to='wait subprocess 1' />" + " </start-state>" + " <state name='wait subprocess 1'>" + " <transition to='end' />" + " </state>" + " <end-state name='end' />" + "</process-definition>"); deployProcessDefinition(processDefinitionOne); ProcessDefinition processDefinitionTwo = ProcessDefinition.parseXmlString("<process-definition name='subprocess2'>" + " <start-state name='start'>" + " <transition to='wait subprocess 2' />" + " </start-state>" + " <state name='wait subprocess 2'>" + " <transition to='end' />" + " </state>" + " <end-state name='end' />" + "</process-definition>"); deployProcessDefinition(processDefinitionTwo); ProcessDefinition processDefinitionThree = ProcessDefinition.parseXmlString("<process-definition name='superprocess'>" + " <start-state name='start'>" + " <transition to='sub process state' />" + " </start-state>" + " <process-state name='sub process state'>" + " <sub-process name='#{mySubProcess}' binding='late'/>" + " <transition to='wait' />" + " </process-state>" + " <state name='wait' />" + "</process-definition>"); deployProcessDefinition(processDefinitionThree); ProcessInstance processInstance1 = jbpmContext.newProcessInstanceForUpdate("superprocess"); processInstance1.getContextInstance().setVariable("mySubProcess", "subprocess1"); processInstance1.signal(); processJobs(); long processInstanceId = processInstance1.getId(); long subProcessInstanceId = processInstance1.getRootToken().getSubProcessInstance().getId(); processInstance1 = jbpmContext.loadProcessInstance(processInstanceId); assertNotNull(processInstance1.getRootToken().getSubProcessInstance()); assertEquals("sub process state", processInstance1.getRootToken().getNode().getName()); assertEquals("subprocess1", processInstance1.getContextInstance().getVariable("mySubProcess")); ProcessInstance subProcessInstance1 = jbpmContext.loadProcessInstance(subProcessInstanceId); assertEquals("subprocess1", subProcessInstance1.getProcessDefinition().getName()); assertEquals("wait subprocess 1", subProcessInstance1.getRootToken().getNode().getName()); subProcessInstance1.signal(); jbpmContext.save(subProcessInstance1); processJobs(); assertTrue(jbpmContext.loadProcessInstance(subProcessInstanceId).hasEnded()); processInstance1 = jbpmContext.loadProcessInstance(processInstanceId); assertEquals("wait", processInstance1.getRootToken().getNode().getName()); ProcessInstance processInstance2 = jbpmContext.newProcessInstanceForUpdate("superprocess"); processInstance2.getContextInstance().setVariable("mySubProcess", "subprocess2"); processInstance2.signal(); processJobs(); long processInstanceId2 = processInstance2.getId(); long subProcessInstanceId2 = processInstance2.getRootToken() .getSubProcessInstance() .getId(); processInstance2 = jbpmContext.loadProcessInstance(processInstanceId2); assertNotNull(processInstance2.getRootToken().getSubProcessInstance()); assertEquals("sub process state", processInstance2.getRootToken().getNode().getName()); assertEquals("subprocess2", processInstance2.getContextInstance().getVariable("mySubProcess")); ProcessInstance subProcessInstance2 = jbpmContext.loadProcessInstance(subProcessInstanceId2); assertEquals("subprocess2", subProcessInstance2.getProcessDefinition().getName()); assertEquals("wait subprocess 2", subProcessInstance2.getRootToken().getNode().getName()); subProcessInstance2.signal(); jbpmContext.save(subProcessInstance2); processJobs(); assertTrue(jbpmContext.loadProcessInstance(subProcessInstanceId2).hasEnded()); processInstance2 = jbpmContext.loadProcessInstance(processInstanceId2); assertEquals("wait", processInstance2.getRootToken().getNode().getName()); } public void testUnboundSubProcess() { ProcessDefinition processDefinition = ProcessDefinition.parseXmlString("<process-definition name='superprocess'>" + " <start-state name='start'>" + " <transition to='sub process state' />" + " </start-state>" + " <process-state name='sub process state'>" + " <sub-process name='subprocess' binding='late' />" + " <transition to='wait' />" + " </process-state>" + " <state name='wait' />" + "</process-definition>"); deployProcessDefinition(processDefinition); ProcessInstance processInstance = jbpmContext.newProcessInstance("superprocess"); try { processInstance.signal(); fail("expected exception"); } catch (IllegalArgumentException e) { // expected jbpmContext.setRollbackOnly(); } } }