8 Replies Latest reply on Sep 3, 2008 11:21 AM by Alan Nisbet

    Transient variables between process and subprocess

    James Depoorter Novice

      Is it normal that transient variables are not transferred between process and subprocess, or that scoping does not apply to transient variables?

      I had to create a handler that copies the map in between process and subprocess.

      James

        • 1. Re: Transient variables between process and subprocess
          Tom Baeyens Master

          it might be a good idea to add that copy into the process-state node implementation... you can create a jira feature request for that if you want it.

          as an alternative, you could use ThreadLocal's

          regards, tom.

          • 2. Re: Transient variables between process and subprocess
            Alejandro Guizar Master

            How about introducing a transient="true|false" attribute.

            <process-state name="initial interview">
             <variable name="b" access="read" mapped-name="bb" transient="true"/>
            </process-state>

            This is just an addition, not a change to the schema.

            • 4. Re: Transient variables between process and subprocess
              James Depoorter Novice

              nudging to know if it will be done in 3.1 or 3.2.

              • 5. Re: Transient variables between process and subprocess
                Administrator Administrator Novice

                i added the last line to org.jbpm.graph.node.ProcessState:

                // feed the readable variableInstances
                 if ((variableAccesses != null) && (!variableAccesses.isEmpty())) {
                
                 ContextInstance superContextInstance = executionContext.getContextInstance();
                 ContextInstance subContextInstance = subProcessInstance.getContextInstance();
                 subContextInstance.setTransientVariables(superContextInstance.getTransientVariables());


                can you make the same update to the beta3 sources and check if it works. if you could write a simple test case that i could add to our test suite, that would be great.

                please comment on the jira issue if that update works for you: Jira http://jira.jboss.com/jira/browse/JBPM-399

                regards, tom.

                • 6. Re: Transient variables between process and subprocess
                  James Depoorter Novice

                  Without testing it:
                  Does this has to be inside the conditional? This means that you have to have at least one read/read-write mapping.
                  If the contract would state that all current transient variables are transferred, this could be sufficient (I don't think you would have read/read-write issues with transients if they are used in a transient way).

                  I think we miss the reverse as well (but I guess you wanted me to figure this out myself :-))

                  • 7. Re: Transient variables between process and subprocess
                    James Depoorter Novice

                    Testclass: testTransientVariablesOnly will fail if you do the transient bit inside the conditional. Will also prove that you have to do the reverse bit as well.


                    /*
                     * 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 junit.framework.TestCase;
                    
                    import org.jbpm.context.def.ContextDefinition;
                    import org.jbpm.context.exe.ContextInstance;
                    import org.jbpm.graph.def.ProcessDefinition;
                    import org.jbpm.graph.exe.ProcessInstance;
                    import org.jbpm.graph.exe.Token;
                    
                    public class ProcessStateTest extends TestCase {
                    
                     public void testBasicScenario() {
                     ProcessDefinition superProcessDefinition = ProcessDefinition.parseXmlString(
                     "<process-definition>" +
                     " <start-state>" +
                     " <transition to='subprocessnode' />" +
                     " </start-state>" +
                     " <process-state name='subprocessnode'>" +
                     " <transition to='end' />" +
                     " </process-state>" +
                     " <end-state name='end' />" +
                     "</process-definition>"
                     );
                    
                     ProcessDefinition subProcessDefinition = ProcessDefinition.parseXmlString(
                     "<process-definition>" +
                     " <start-state>" +
                     " <transition to='state' />" +
                     " </start-state>" +
                     " <state name='state'>" +
                     " <transition to='end' />" +
                     " </state>" +
                     " <end-state name='end' />" +
                     "</process-definition>"
                     );
                    
                     ProcessState processState = (ProcessState) superProcessDefinition.getNode("subprocessnode");
                     processState.setSubProcessDefinition(subProcessDefinition);
                    
                     ProcessInstance superProcessInstance = new ProcessInstance(superProcessDefinition);
                     superProcessInstance.signal();
                    
                     Token superToken = superProcessInstance.getRootToken();
                     assertSame(processState, superToken.getNode());
                    
                     ProcessInstance subProcessInstance = superToken.getSubProcessInstance();
                     assertSame(subProcessDefinition, subProcessInstance.getProcessDefinition());
                     Token subToken = subProcessInstance.getRootToken();
                    
                     assertSame(subProcessDefinition.getNode("state"), subToken.getNode());
                    
                     subToken.signal();
                    
                     assertSame(subProcessDefinition.getNode("end"), subToken.getNode());
                     assertTrue(subToken.hasEnded());
                     assertTrue(subProcessInstance.hasEnded());
                    
                     assertSame(superProcessDefinition.getNode("end"), superToken.getNode());
                     assertTrue(superToken.hasEnded());
                     assertTrue(superProcessInstance.hasEnded());
                     }
                    
                     public void testTransientVariablesOnly() {
                    
                     ProcessDefinition superProcessDefinition = ProcessDefinition.parseXmlString(
                     "<process-definition>" +
                     " <start-state>" +
                     " <transition to='subprocessnode' />" +
                     " </start-state>" +
                     " <process-state name='subprocessnode'>" +
                     " <transition to='end' />" +
                     " </process-state>" +
                     " <end-state name='end' />" +
                     "</process-definition>"
                     );
                    
                     ProcessDefinition subProcessDefinition = ProcessDefinition.parseXmlString(
                     "<process-definition>" +
                     " <start-state>" +
                     " <transition to='state' />" +
                     " </start-state>" +
                     " <state name='state'>" +
                     " <transition to='end' />" +
                     " </state>" +
                     " <end-state name='end' />" +
                     "</process-definition>"
                     );
                     ProcessState processState = (ProcessState) superProcessDefinition.getNode("subprocessnode");
                     processState.setSubProcessDefinition(subProcessDefinition);
                    
                     ProcessInstance superProcessInstance = new ProcessInstance(superProcessDefinition);
                     ContextInstance superContextInstance = superProcessInstance.getContextInstance();
                     // set a transient variable in the super process
                     superContextInstance.setTransientVariable("transientsuper","valuesuper");
                    
                     superProcessInstance.signal();
                    
                     Token superToken = superProcessInstance.getRootToken();
                     ProcessInstance subProcessInstance = superToken.getSubProcessInstance();
                     ContextInstance subContextInstance = subProcessInstance.getContextInstance();
                     // check the transient variable in the sub process
                     assertNotNull(subContextInstance.getTransientVariable("transientsuper"));
                     assertEquals("valuesuper",subContextInstance.getTransientVariable("transientsuper"));
                    
                     Token subToken = subProcessInstance.getRootToken();
                    
                     // clear the superprocess of transients, to make sure that we are not
                     // make updates to the same transient map
                     superContextInstance.setTransientVariables(null);
                    
                     // set a transient variable in the subprocess
                     subContextInstance.setTransientVariable("transientsub","valuesub");
                     // change the super value
                     subContextInstance.setTransientVariable("transientsuper","changesuper");
                     subToken.signal();
                     // check transient variables
                     assertNotNull(superContextInstance.getTransientVariable("transientsub"));
                     assertEquals("valuesub",superContextInstance.getTransientVariable("transientsub"));
                     assertNotNull(superContextInstance.getTransientVariable("transientsuper"));
                     assertEquals("changesuper",superContextInstance.getTransientVariable("transientsuper"));
                     }
                    
                     public void testScenarioWithVariables() {
                     ProcessDefinition superProcessDefinition = ProcessDefinition.parseXmlString(
                     "<process-definition>" +
                     " <start-state>" +
                     " <transition to='subprocessnode' />" +
                     " </start-state>" +
                     " <process-state name='subprocessnode'>" +
                     " <variable name='a' mapped-name='aa' />" +
                     " <variable name='b' mapped-name='bb' />" +
                     " <transition to='end' />" +
                     " </process-state>" +
                     " <end-state name='end' />" +
                     "</process-definition>"
                     );
                     superProcessDefinition.addDefinition(new ContextDefinition());
                    
                     ProcessDefinition subProcessDefinition = ProcessDefinition.parseXmlString(
                     "<process-definition>" +
                     " <start-state>" +
                     " <transition to='state' />" +
                     " </start-state>" +
                     " <state name='state'>" +
                     " <transition to='end' />" +
                     " </state>" +
                     " <end-state name='end' />" +
                     "</process-definition>"
                     );
                     subProcessDefinition.addDefinition(new ContextDefinition());
                    
                     // bind the sub-process to the super process definition
                     ProcessState processState = (ProcessState) superProcessDefinition.getNode("subprocessnode");
                     processState.setSubProcessDefinition(subProcessDefinition);
                    
                     // create the super process definition
                     ProcessInstance superProcessInstance = new ProcessInstance(superProcessDefinition);
                     Token superToken = superProcessInstance.getRootToken();
                    
                     // set some variableInstances in the super process
                     ContextInstance superContextInstance = superProcessInstance.getContextInstance();
                     superContextInstance.setVariable("a", "hello");
                     superContextInstance.setVariable("b", new Integer(3));
                    
                     // set a transient variable in the super process
                     superContextInstance.setTransientVariable("transientsuper","valuesuper");
                    
                     // start execution of the super process
                     superProcessInstance.signal();
                    
                     // check if the variableInstances have been copied properly into the sub process
                     ProcessInstance subProcessInstance = superToken.getSubProcessInstance();
                     ContextInstance subContextInstance = subProcessInstance.getContextInstance();
                    
                     assertEquals("hello", subContextInstance.getVariable("aa"));
                     assertEquals(new Integer(3), subContextInstance.getVariable("bb"));
                    
                     // check the transient variable in the sub process
                     assertNotNull(subContextInstance.getTransientVariable("transientsuper"));
                     assertEquals("valuesuper",subContextInstance.getTransientVariable("transientsuper"));
                    
                     // update variable aa
                     subContextInstance.setVariable("aa", "new hello");
                    
                     // clear the superprocess of transients, to make sure that we are not
                     // make updates to the same transient map
                     superContextInstance.setTransientVariables(null);
                    
                     // set a transient variable in the subprocess
                     subContextInstance.setTransientVariable("transientsub","valuesub");
                     // change the super value
                     subContextInstance.setTransientVariable("transientsuper","changesuper");
                    
                     // end the subprocess
                     subProcessInstance.signal();
                    
                     // now check if the subprocess variableInstances have been copied into the super process
                     assertEquals("new hello", superContextInstance.getVariable("a"));
                     assertEquals(new Integer(3), superContextInstance.getVariable("b"));
                    
                     // check transient variables
                     assertNotNull(superContextInstance.getTransientVariable("transientsub"));
                     assertEquals("valuesub",superContextInstance.getTransientVariable("transientsub"));
                     assertNotNull(superContextInstance.getTransientVariable("transientsuper"));
                     assertEquals("changesuper",superContextInstance.getTransientVariable("transientsuper"));
                     }
                    }
                    


                    • 8. Re: Transient variables between process and subprocess
                      Alan Nisbet Newbie

                      Hi Guys,

                      I know this was a long time ago, but I'm trying to access a super-process transient variables via a sub-process.

                      In an ActionHandler I extract the transient variable map. When in the super-process the map contains the expected variables, however the sub-process map is null.

                      Is there anything special I need to do, have done, so that the

                      subContextInstance.setTransientVariables(superContextInstance.getTransientVariables());
                      

                      line of code in ProcessState is executed?

                      Currently all I'm doing is using the super-process to find the sub-process and signalling the sub-process.

                      public void signalSubProcess(long processInstanceId, String transitionName) {
                       log.info("Signalling Sub Process");
                      
                       // Find ProcessInstance
                       JbpmContext ctx = JbpmConfiguration.getInstance().createJbpmContext();
                       try {
                       GraphSession gs = ctx.getGraphSession();
                       gs.lockProcessInstance(processInstanceId);
                      
                       ProcessInstance instance = ctx.getProcessInstanceForUpdate(processInstanceId);
                       log.info("Root Token of instance is " + instance.getRootToken().getId());
                      
                       ProcessInstance subInstance = instance.getRootToken().getSubProcessInstance();
                       if (instance.hasEnded()) {
                       log.info("SubProcess Instance has already ended so cannot signal");
                       }
                      
                       if (subInstance != null) {
                       signal(subInstance, transitionName);
                       } else {
                       String msg = "ProcessInstance not found";
                       log.info(msg);
                       throw new RuntimeException(msg);
                       }
                      
                       } finally {
                       ctx.close();
                       }
                       }


                      Am I calling the sub-process incorrectly, and as a result not executing the code included in the ProcessState class?