7 Replies Latest reply on Apr 16, 2009 7:44 AM by tom.baeyens

    introducing process instance ?

    tom.baeyens

      i'm thinking to introduce ProcessInstance:

      interface ProcessInstance extends Execution {
      }
      


      advantage is that with this interface we can indicate more precisely what the ExecutionService methods are returning: a real ProcessInstance (one execution of a full process) or an Execution (one path of execution in a process instance)

      sidenote: in the PVM implementation class, we cannot make that distinction. cause if concrete process languages like jPDL want to introduce JpdlProcessInstance as a concrete subclass, that would lead to multiple inheritence.

      disadvantage is that the ProcessInstance interface doesn't contain any extra methods. that might be strange. but i don't think it will cause confusion. and it will reduce the confusion in understanding the ExecutionService

      public interface ExecutionService {
      
       ProcessInstance startProcessInstanceById(String processDefinitionId);
      
       ProcessInstance startProcessInstanceById(String processDefinitionId, String processInstanceKey);
      
       ProcessInstance startProcessInstanceById(String processDefinitionId, Map<String, Object> variables);
      
       ProcessInstance startProcessInstanceById(String processDefinitionId, Map<String, Object> variables, String processInstanceKey);
      
       ProcessInstance startProcessInstanceByKey(String processDefinitionKey);
      
       ProcessInstance startProcessInstanceByKey(String processDefinitionKey, String processInstanceKey);
      
       ProcessInstance startProcessInstanceByKey(String processDefinitionKey, Map<String, Object> variables);
      
       ProcessInstance startProcessInstanceByKey(String processDefinitionKey, Map<String, Object> variables, String processInstanceKey);
      
       Execution findExecutionById(String executionId);
      
       List<Execution> findExecutionsById(String processDefinitionId);
      
       ProcessInstance signalExecutionById(String executionId);
      
       ProcessInstance signalExecutionById(String executionId, String signalName);
      
       ProcessInstance signalExecutionById(String executionId, String signalName, Map<String, Object> parameters);
      
       ProcessInstance signalExecutionById(String executionId, Map<String, Object> parameters);
      
      
       ExecutionQuery createExecutionQuery();
      
       ExecutionQuery createProcessInstanceQuery();
      
       void setVariable(String executionId, String name, Object value);
      
       void setVariables(String executionId, Map<String, Object> variables);
      
       Object getVariable(String executionId, String variableName);
      
       Set<String> getVariableNames(String executionId);
      
       Map<String, Object> getVariables(String executionId, Set<String> variableNames);
      
       void endProcessInstance(String processInstanceId, String state);
      
       void deleteProcessInstance(String processInstanceId);
      }
      



      i also think that the return value for signal should be the process instance and not the execution on which the signal occurs. that will force users to use the right way of getting the executionId's that are in a wait state. in the context of timers, each activity is potentially a scope, resulting in a child-execution and hence you cannot assume that it is the same execution that will be waiting in the wait state. that is why users will have to do something like this in case of a wait state:

      Execution processInstance = executionService.startProcessInstanceByKey("TimerTransition");
      
       String executionId = processInstance.findActiveExecutionIn("guardedWait").getId();
      
       executionService.signalExecutionById(executionId, "go on");
      


        • 1. Re: introducing process instance ?
          jbarrez

          Tom,

          I agree that it makes the executionService more user-friendly.
          After all, when you signal an execution and he forks in 5 paths, the following 5 waitstates should be returned to make the code more easier to understand.

          The only alternative for the ProcessInstance I'm seeing is a Set/Map/... of curent wait states of the 'root execution'. (or return nothing and let the user make a query ... but then we're back at jbpm 3, which was flawed in that perspective)

          But I don't agree that the ProcessInstance should be an interface.
          Why not make it an extension of the ExecutionImpl? After all, the ProcessInstance is just another name of a very specific execution (ie the root execution). You could add some specifc stuff to the process instance (eg business key? as it was in jbpm3 or getAllWaitStates())

          • 2. Re: introducing process instance ?
            ainze

            Doesn't processInstance.findActiveExecutionIn only make sense when your execution is a processInstance?
            So we could add this method to the processInstance interface/class and remove it from the execution.

            • 3. Re: introducing process instance ?
              jbarrez

              Executions are structured as a tree, so calling findActiveExecutionIn() will produce results if somewhere down the road there's a fork.

              So, for most of the use cases you are right. It makes the most sense on the process instance for end-users.

              However, perhaps power-users could find a usage for querying a subtree of the executions (for performance or something)

              • 4. Re: introducing process instance ?
                tom.baeyens

                 

                "jbarrez" wrote:
                But I don't agree that the ProcessInstance should be an interface.
                Why not make it an extension of the ExecutionImpl? After all, the ProcessInstance is just another name of a very specific execution (ie the root execution). You could add some specifc stuff to the process instance (eg business key? as it was in jbpm3 or getAllWaitStates())


                the ProcessInstance interface that I propose is in the api.

                i can't make the same distinction in the implementation classes. but the api user will not notice that.

                suppose that we have

                class ProcessInstanceImpl extends ExecutionImpl {
                ...
                }


                in the implementation. And then suppose that jPDL wants to add a property to all executions... then you end up in multiple inheritence.

                and besides, i think it is best that all executions (incl process instances) are stored in only 1 single table.


                • 5. Re: introducing process instance ?
                  tom.baeyens

                   

                  "jbarrez" wrote:
                  Executions are structured as a tree, so calling findActiveExecutionIn() will produce results if somewhere down the road there's a fork.

                  So, for most of the use cases you are right. It makes the most sense on the process instance for end-users.

                  However, perhaps power-users could find a usage for querying a subtree of the executions (for performance or something)


                  still, Andries' point might still be valid in the api. as the power users can always cast to the implementation class if they want.

                  • 6. Re: introducing process instance ?
                    jbarrez

                     

                    in the implementation. And then suppose that jPDL wants to add a property to all executions... then you end up in multiple inheritence.



                    I understand.
                    Extending implementation classes is indeed a no-go when the process instance implementation must be extendable.

                    So how do you see the inheritance?

                    ProcessInstance (interface) extends Execution
                    ExecutionImpl implements ProcessInstance, Execution
                    


                    -> This could lead to castings of executions to ProcessInstances, which aren't process instances (ie no root execution). But for the compiler, nothing is wrong since they are exactly the same...

                    I don't know, I get a funy feeling about it when I think about it like that... This leads back to the question if processInstance == Execution? (I know we already discussed this, but perhaps I'm seeing this in the wrong perspective here)


                    and besides, i think it is best that all executions (incl process instances) are stored in only 1 single table.


                    Definitely

                    • 7. Re: introducing process instance ?
                      tom.baeyens

                       

                      "jbarrez" wrote:
                      -> This could lead to castings of executions to ProcessInstances, which aren't process instances (ie no root execution). But for the compiler, nothing is wrong since they are exactly the same...


                      i don't see the need for those casts. first, the api returns process instances where appropriate.

                      secondly, process instance doesn't add any methods, so there will be no reason to cast :-)


                      the thing that i'm mostly in doubt about is the return value of the signal methods. previously we returned the execution in which the signal was given. but in the context of this thread it looks to me more logically that we return the process instance. that could lead to confusion, but if we introduce the ProcessInstance interface, it becomes clear that the process instance is returned. so on balance i am in favour of introducing ProcessInstance and changing the return value of the signal methods to ProcessInstance