io.vertx.tp.workflow.refine.WfFlow Maven / Gradle / Ivy
The newest version!
package io.vertx.tp.workflow.refine;
import cn.vertxup.workflow.cv.em.PassWay;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;
import io.vertx.tp.workflow.init.WfPin;
import io.vertx.up.eon.KName;
import io.vertx.up.util.Ut;
import org.camunda.bpm.engine.RepositoryService;
import org.camunda.bpm.engine.repository.ProcessDefinition;
import org.camunda.bpm.engine.task.Task;
import org.camunda.bpm.model.bpmn.Bpmn;
import org.camunda.bpm.model.bpmn.BpmnModelInstance;
import org.camunda.bpm.model.bpmn.impl.instance.Outgoing;
import org.camunda.bpm.model.bpmn.instance.FlowNode;
import org.camunda.bpm.model.bpmn.instance.SequenceFlow;
import org.camunda.bpm.model.bpmn.instance.UserTask;
import org.camunda.bpm.model.xml.instance.ModelElementInstance;
import java.util.*;
import java.util.stream.Collectors;
import static io.vertx.tp.workflow.refine.Wf.LOG;
/**
* @author Lang
*/
class WfFlow {
// ------------------- Other Output ------------------------
static JsonObject outBpmn(final ProcessDefinition definition) {
final RepositoryService service = WfPin.camundaRepository();
// Content Definition
final BpmnModelInstance instance = service.getBpmnModelInstance(definition.getId());
Objects.requireNonNull(instance);
final String xml = Bpmn.convertToString(instance);
// Response Json
final JsonObject workflow = new JsonObject();
workflow.put(KName.Flow.DEFINITION_ID, definition.getId());
workflow.put(KName.Flow.DEFINITION_KEY, definition.getKey());
workflow.put(KName.Flow.BPMN, xml);
workflow.put(KName.NAME, definition.getName());
return workflow;
}
static JsonObject outLinkage(final JsonObject linkageJ) {
final JsonObject parsed = new JsonObject();
linkageJ.fieldNames().forEach(field -> {
final Object value = linkageJ.getValue(field);
/*
* Secondary format for
* field1: path1
* field1: path2
*/
JsonObject json = null;
if (value instanceof String) {
json = Ut.ioJObject(value.toString());
} else if (value instanceof JsonObject) {
json = (JsonObject) value;
}
if (Ut.isNotNil(json)) {
assert json != null;
parsed.put(field, json.copy());
}
});
return parsed;
}
// ------------------- Gateway Type Analyzing ------------------------
/*
* PassWay Input Data
* 1: 1
* {
* "toUser": "user1"
* }
*
* n: 1
* {
* "toUser": {
* "type1": "user1",
* "type2": "user2",
* "type3": "user3",
* "...": "...",
* "typeN": "userN"
* }
* }
*
* 1: n
* {
* "toUser": [
* "user1",
* "user2",
* "user3",
* "...",
* "userN"
* ]
* }
*
* n: n
* {
* "toUser": {
* "type1": [
* "user1",
* "user2",
* "..."
* ],
* "type2": [
* "user3",
* "user4",
* "...",
* "userY"
* ],
* "...": [
* "...",
* "userN"
* ],
* "typeN": [
* "user2",
* "user3",
* "...",
* "userX"
* ],
* }
* }
*/
static PassWay inGateway(final JsonObject requestJ) {
// toUser field extraction
final JsonObject requestData = Ut.valueJObject(requestJ);
final Object toUser = requestData.getValue(KName.Auditor.TO_USER);
if (toUser instanceof String) {
// String
return PassWay.Standard;
} else if (toUser instanceof JsonArray) {
// JsonArray
return PassWay.Multi;
} else if (toUser instanceof JsonObject) {
// JsonObject
/*
* - Fork/Join: All String
* - Grid: All JsonObject
*/
final JsonObject toUserJ = ((JsonObject) toUser);
final Set typeSet = toUserJ.fieldNames();
final long strCount = typeSet.stream()
.filter(field -> (toUserJ.getValue(field) instanceof String))
.count();
if (typeSet.size() == strCount) {
// Fork/Join
return PassWay.Fork;
} else {
// Grid
return PassWay.Grid;
}
} else {
// Undermine
return null;
}
}
// ------------------- Name Event ------------------------
static String nameEvent(final Task task) {
if (Objects.isNull(task)) {
return null;
}
final RepositoryService service = WfPin.camundaRepository();
final BpmnModelInstance instance = service.getBpmnModelInstance(task.getProcessDefinitionId());
final ModelElementInstance node = instance.getModelElementById(task.getTaskDefinitionKey());
return node.getElementType().getTypeName();
}
static List taskNext(final Task task, final List source) {
Objects.requireNonNull(task);
final RepositoryService service = WfPin.camundaRepository();
final BpmnModelInstance instance = service.getBpmnModelInstance(task.getProcessDefinitionId());
final ModelElementInstance node = instance.getModelElementById(task.getTaskDefinitionKey());
final Set nextKeys = taskSearch(node, instance);
LOG.Move.info(WfFlow.class, "[Outgoing] Keys = {0}", Ut.fromJoin(nextKeys));
return source.stream()
.filter(taskNext -> nextKeys.contains(taskNext.getTaskDefinitionKey()))
.collect(Collectors.toList());
}
/*
* The method is recursion calling on BPMN, here are some situations
* 1. The objective will be: Find the next all UserTask
* 2. When the system met gateway node, continue to find the task here
*/
private static Set taskSearch(final ModelElementInstance nodeTask, final BpmnModelInstance instance) {
// Find all `outgoing` that belong to `nodeTask`
final Collection outgoing = nodeTask.getChildElementsByType(Outgoing.class);
final Set keys = new HashSet<>();
outgoing.forEach(child -> {
final ModelElementInstance sequence = instance.getModelElementById(child.getTextContent());
// SequenceFlow
if (sequence instanceof SequenceFlow) {
final FlowNode target = ((SequenceFlow) sequence).getTarget();
final ModelElementInstance found = instance.getModelElementById(target.getId());
if (found instanceof UserTask) {
// Task -> Task
keys.add(target.getId());
} else {
// Task -> Gateway -> Task
final Set continueSearch = taskSearch(found, instance);
keys.addAll(continueSearch);
}
}
});
return keys;
}
}