Foreword
The model has been highly abstracted above, and this article will further explain the model behavior. Here begins with a question:
How to let the process go from the start node to the end node according to the arrow point?
StartModel(start)->TaskModel(apply)->TaskModel(deptApprove)->EndModel(end)
Execution process analysis
Object graph:
Timing diagram:
Description of execution process:
- The start node calls the execution method of the output edge t1
- The output side of t1 calls the execution method of the leave application node
- The leave node calls the execution method of the output edge t2
- The t2 output side invokes the execution method of the department leader’s approval
- The department leader approves and calls the execution method of the output edge t3
- t3 calls the execution method of the end node
Code Implementation Steps
The execute method of the node model is added to print the code and name of the current object.
public abstract class NodeModel extends BaseModel implements Action {<!-- --> private String layout;// layout attributes (x,y,w,h) // input edge set private List<TransitionModel> inputs = new ArrayList<TransitionModel>(); // output edge set private List<TransitionModel> outputs = new ArrayList<TransitionModel>(); private String preInterceptors; // Node pre-interceptors private String postInterceptors; // node post interceptor /** * Customized execution method by subclass * @param execution */ abstract void exec(Execution execution); @Override public void execute(Execution execution) {<!-- --> // 1. Call the pre-interceptor // 2. Call the exec method of the subclass // 3. Call post interceptor System.out.println(StrUtil.format("model:{},name:{},displayName:{}", this.getClass().getSimpleName(), getName(),getDisplayName())); exec(execution); } }
The process model adds the method of getting the start node
public class ProcessModel extends BaseModel {<!-- --> private String type; // Process definition classification private String instanceUrl; // The form key to be filled in to start the instance private String expireTime; // expected completion time variable key private String instanceNoClass; // instance number generator implementation class // All nodes of the process definition private List<NodeModel> nodes = new ArrayList<NodeModel>(); // All task nodes defined by the process private List<TaskModel> tasks = new ArrayList<TaskModel>(); /** * get start node * @return */ public StartModel getStart() {<!-- --> StartModel startModel = null; for (int i = 0; i < nodes. size(); i ++ ) {<!-- --> NodeModel nodeModel = nodes. get(i); if(nodeModel instanceof StartModel) {<!-- --> startModel = (StartModel) nodeModel; break; } } return startModel; } }
The process model gets the start node object and calls the execution method
processModel.getStart().execute(new Execution());
At this time, only the start node information is printed
model:StartModel,name:start,displayName:start
The execute method of the node model object adds traversal to call the execution method of the next node
public abstract class NodeModel extends BaseModel implements Action {<!-- --> private String layout;// layout attributes (x,y,w,h) // input edge set private List<TransitionModel> inputs = new ArrayList<TransitionModel>(); // output edge set private List<TransitionModel> outputs = new ArrayList<TransitionModel>(); private String preInterceptors; // Node pre-interceptors private String postInterceptors; // node post interceptor /** * Customized execution method by subclass * @param execution */ abstract void exec(Execution execution); @Override public void execute(Execution execution) {<!-- --> // 1. Call the pre-interceptor // 2. Call the exec method of the subclass // 3. Call post interceptor System.out.println(StrUtil.format("model:{},name:{},displayName:{}", this.getClass().getSimpleName(), getName(),getDisplayName())); outputs.forEach(tr->{<!-- --> tr.getTarget().execute(execution); }); exec(execution); } }
result:
model:StartModel,name:start,displayName:start model:TaskModel,name:apply,displayName:leave application model:TaskModel,name:deptApprove,displayName:dept leader approval model:EndModel,name:end,displayName:end
In order to highlight the role of the edge, we can implement the execution method of the edge:
public class TransitionModel extends BaseModel implements Action {<!-- --> private NodeModel source; // edge source node reference private NodeModel target; // edge target node reference private String to; // target node name private String expr; // edge expression private String g; // set of edge point coordinates (x1, y1; x2, y2, x3, y3...) start, corner, end private boolean enabled; // Whether it can be executed @Override public void execute(Execution execution) {<!-- --> if(!enabled) return; target. execute(execution); } }
Then transform the node model and add the runOutTransition method
public abstract class NodeModel extends BaseModel implements Action {<!-- --> private String layout;// layout attributes (x,y,w,h) // input edge set private List<TransitionModel> inputs = new ArrayList<TransitionModel>(); // output edge set private List<TransitionModel> outputs = new ArrayList<TransitionModel>(); private String preInterceptors; // Node pre-interceptors private String postInterceptors; // node post interceptor /** * Customized execution method by subclass * @param execution */ abstract void exec(Execution execution); @Override public void execute(Execution execution) {<!-- --> // 1. Call the pre-interceptor // 2. Call the exec method of the subclass // 3. Call post interceptor System.out.println(StrUtil.format("model:{},name:{},displayName:{}", this.getClass().getSimpleName(), getName(),getDisplayName())); // Execute output edge runOutTransition(execution); exec(execution); } /** * Execute output edge */ protected void runOutTransition(Execution execution) {<!-- --> outputs.forEach(tr->{<!-- --> tr.setEnabled(true); tr. execute(execution); }); } }
The final effect is:
model:StartModel,name:start,displayName:start model:TaskModel,name:apply,displayName:leave application model:TaskModel,name:deptApprove,displayName:dept leader approval model:EndModel,name:end,displayName:end
How to block the process?
The execution process of the above example is too smooth. In the real workflow scene, there will be some blocking tasks. Blocking means that the execution method of the node is called. If the conditions are not met, the process cannot be driven to the next node. So how do we use programs to simulate this process?
First transform the node model
Not every node executes in the same way, we need to perform different output processing on different nodes, so here
- Temporarily remove the print statement of the original node model and the method of calling the execution edge
- Override the toString() method
public abstract class NodeModel extends BaseModel implements Action {<!-- --> private String layout;// layout attributes (x,y,w,h) // input edge set private List<TransitionModel> inputs = new ArrayList<TransitionModel>(); // output edge set private List<TransitionModel> outputs = new ArrayList<TransitionModel>(); private String preInterceptors; // Node pre-interceptors private String postInterceptors; // node post interceptor /** * Customized execution method by subclass * @param execution */ abstract void exec(Execution execution); @Override public void execute(Execution execution) {<!-- --> // 1. Call the pre-interceptor // 2. Call the exec method of the subclass // 3. Call post interceptor exec(execution); } /** * Execute output edge */ protected void runOutTransition(Execution execution) {<!-- --> outputs.forEach(tr->{<!-- --> tr.setEnabled(true); tr. execute(execution); }); } @Override public String toString() {<!-- --> return StrUtil.format("model:{},name:{},displayName:{},time:{}", this.getClass().getSimpleName(), getName(),getDisplayName(), DateUtil.dateSecond ()); } }
Implement the exec method of the start node
The exec of the start node mainly executes the following logic:
- output super.toString()
- call runOutTransition
public class StartModel extends NodeModel {<!-- --> @Override void exec(Execution execution) {<!-- --> System.out.println(super.toString()); runOutTransition(execution); } }
Implement the exec method of the end node
The end node has no output edge, so only super.toString() is output
public class EndModel extends NodeModel {<!-- --> @Override public void exec(Execution execution) {<!-- --> System.out.println(super.toString()); } }
Implement the exec method of the task node
Task nodes are special, we can do the following to make them temporarily blocked:
public class TaskModel extends NodeModel {<!-- --> private String form; // Form ID private String assignee; // participant private String assignmentHandler; // participant processing class private TaskTypeEnum taskType; // task type (host/co-organizer) private TaskPerformTypeEnum performType; // Participation type (normal participation/countersigned participation) private String reminderTime; // reminder time private String reminderRepeat; // Repeat reminder interval private String expireTime; // Expect task completion time variable key private String autoExecute; // Whether to automatically execute Y/N upon expiration private String callback; // automatically execute the callback class private Dict ext = Dict.create(); // custom extension attributes @Override public void exec(Execution execution) {<!-- --> // Execute task node custom execution logic try {<!-- --> Thread. sleep(3000); } catch (InterruptedException e) {<!-- --> e.printStackTrace(); } System.out.println(super.toString()); runOutTransition(execution); } }
At this time, the printed results are as follows:
model:StartModel,name:start,displayName:start,time:2023-04-25 22:27:45 model: TaskModel, name: apply, displayName: leave application, time: 2023-04-25 22:27:48 model:TaskModel,name:deptApprove,displayName:dept Approve,time:2023-04-25 22:27:51 model:EndModel,name:end,displayName:end,time:2023-04-25 22:27:51
Join an organization
Please open in WeChat:
“Lidong and His Friends”
Related source code
mldong-flow-demo-02
Process Designer
online experience