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

    Transient variables between process and subprocess

    icyjamie

      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

          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
            aguizar

            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.

            • 3. Re: Transient variables between process and subprocess
              icyjamie
              • 4. Re: Transient variables between process and subprocess
                icyjamie

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

                • 5. Re: Transient variables between process and subprocess
                  admin

                  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
                    icyjamie

                    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
                      icyjamie

                      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
                        nizzy

                        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?