public B condition(String condition) { return condition(null, condition); }
private void addTask(AbstractFlowNodeBuilder<?, ?> builder, final String taskId) { if (createdTasks.contains(taskId)) { builder.connectTo(taskId); } else { final YamlTask task = tasksById.get(taskId); if (task == null) { throw new RuntimeException( String.format( "Expected to add task with id '%s', but no task definition with that id exists", taskId)); } builder = addServiceTask(builder, task); createdTasks.add(taskId); addFlowFromTask(builder, task); } }
protected <T extends FlowNode> T createTarget(Class<T> typeClass, String identifier) { final T target = createSibling(typeClass, identifier); final BpmnShape targetBpmnShape = createBpmnShape(target); setCoordinates(targetBpmnShape); connectTarget(target); resizeSubProcess(targetBpmnShape); return target; }
protected void connectTarget(FlowNode target) { // check if compensation was started if (isBoundaryEventWithStartedCompensation()) { // the target activity should be marked for compensation if (target instanceof Activity) { ((Activity) target).setForCompensation(true); } // connect the target via association instead of sequence flow connectTargetWithAssociation(target); } else if (isCompensationHandler()) { // cannot connect to a compensation handler throw new BpmnModelException( "Only single compensation handler allowed. Call compensationDone() to continue main flow."); } else { // connect as sequence flow by default connectTargetWithSequenceFlow(target); } }
protected void connectTargetWithSequenceFlow(FlowNode target) { getCurrentSequenceFlowBuilder().from(element).to(target); final SequenceFlow sequenceFlow = getCurrentSequenceFlowBuilder().getElement(); createEdge(sequenceFlow); currentSequenceFlowBuilder = null; }
.moveToLastGateway() .connectTo("exclusiveJoin") .sequenceFlowId("joinFlow1") .parallelGateway("join") .moveToNode("fork") .serviceTask("waitState", b -> b.zeebeTaskType("type")) .sequenceFlowId("joinFlow2") .connectTo("join") .endEvent() .done();
@Test public void shouldNotCompleteInstanceAfterIncidentIsRaisedOnExclusiveGateway() { // given testClient.deploy( Bpmn.createExecutableProcess(PROCESS_ID) .startEvent() .parallelGateway() .serviceTask("task", t -> t.zeebeTaskType("task")) .endEvent("end-1") .moveToLastGateway() .exclusiveGateway("gateway") .defaultFlow() .endEvent("end-2") .moveToNode("gateway") .sequenceFlowId("to-end-3") .condition("$.x < 21") .endEvent("end-3") .done()); testClient.createWorkflowInstance(PROCESS_ID); // when final Record<IncidentRecordValue> incident = RecordingExporter.incidentRecords(IncidentIntent.CREATED).getFirst(); testClient.completeJobOfType("task"); testClient.updatePayload(incident.getValue().getElementInstanceKey(), "{'x':123}"); testClient.resolveIncident(incident.getKey()); // then assertThatWorkflowInstanceCompletedAfter("end-2", WorkflowInstanceIntent.EVENT_ACTIVATED); }
private long deployWorkflow(String... taskTypes) { AbstractFlowNodeBuilder<?, ?> builder = Bpmn.createExecutableProcess(PROCESS_ID).startEvent(); for (String taskType : taskTypes) { builder = builder.serviceTask( taskType, b -> b.zeebeTaskType(taskType).zeebeTaskRetries(3).zeebeTaskHeader("model", "true")); } final BpmnModelInstance model = builder.endEvent().done(); return apiRule .createCmdRequest() .partitionId(DEPLOYMENT_PARTITION) .type(ValueType.DEPLOYMENT, DeploymentIntent.CREATE) .command() .put( "resources", Collections.singletonList(deploymentResource(bpmnXml(model), "process.bpmn"))) .done() .sendAndAwait() .getKey(); }
@Test public void shouldMergeAndSplitInOneGateway() { // given final BpmnModelInstance process = Bpmn.createExecutableProcess(PROCESS_ID) .startEvent() .parallelGateway("fork") .parallelGateway("join-fork") .moveToNode("fork") .connectTo("join-fork") .serviceTask("task1", b -> b.zeebeTaskType("type1")) .moveToLastGateway() .serviceTask("task2", b -> b.zeebeTaskType("type2")) .done(); testClient.deploy(process); // when testClient.createWorkflowInstance(PROCESS_ID); // then final List<Record<WorkflowInstanceRecordValue>> elementInstances = testClient .receiveWorkflowInstances() .filter(r -> r.getMetadata().getIntent() == WorkflowInstanceIntent.ELEMENT_ACTIVATED) .limit(3) .collect(Collectors.toList()); assertThat(elementInstances) .extracting(e -> e.getValue().getElementId()) .contains(PROCESS_ID, "task1", "task2"); }
private ServiceTaskBuilder addServiceTask( final AbstractFlowNodeBuilder<?, ?> builder, YamlTask task) { final String id = task.getId(); final String taskType = task.getType(); final Integer taskRetries = task.getRetries(); final ServiceTaskBuilder serviceTaskBuilder = builder.serviceTask(id).zeebeTaskType(taskType).zeebeTaskRetries(taskRetries); for (Entry<String, String> header : task.getHeaders().entrySet()) { serviceTaskBuilder.zeebeTaskHeader(header.getKey(), header.getValue()); } addInputOutputMappingToTask(task, serviceTaskBuilder); return serviceTaskBuilder; }
@Test public void shouldCompleteInstanceAfterParallelJoin() { // given testClient.deploy( Bpmn.createExecutableProcess(PROCESS_ID) .startEvent() .parallelGateway("fork") .serviceTask("task-1", t -> t.zeebeTaskType("task-1")) .parallelGateway("join") .endEvent("end") .moveToNode("fork") .serviceTask("task-2", t -> t.zeebeTaskType("task-2")) .connectTo("join") .done()); testClient.createWorkflowInstance(PROCESS_ID); // when testClient.completeJobOfType("task-1"); testClient.completeJobOfType("task-2"); // then assertThatWorkflowInstanceCompletedAfter("end", WorkflowInstanceIntent.EVENT_ACTIVATED); }
private void addFlowFromTask(final AbstractFlowNodeBuilder<?, ?> builder, final YamlTask task) { if (!task.getCases().isEmpty()) { final String gatewayId = "split-" + task.getId(); final ExclusiveGatewayBuilder gatewayBuilder = builder.exclusiveGateway(gatewayId); for (YamlCase flow : task.getCases()) { if (flow.getDefaultCase() != null) { gatewayBuilder.defaultFlow(); addTask(gatewayBuilder, flow.getDefaultCase()); } else { gatewayBuilder.condition(flow.getCondition()); addTask(gatewayBuilder, flow.getNext()); } } } else if (task.getNext() != null) { addTask(builder, task.getNext()); } else { final YamlTask nextTask = getNextTask(task); if (!task.isEnd() && nextTask != null) { addTask(builder, nextTask.getId()); } else { builder.endEvent(); } } }
@Test public void shouldCompleteScopeWithMultipleTokensOnSamePath() { // given final BpmnModelInstance process = Bpmn.createExecutableProcess(PROCESS_ID) .startEvent() .parallelGateway("fork") .exclusiveGateway("join") .endEvent("end") .moveToNode("fork") .connectTo("join") .done(); testClient.deploy(process); // when testClient.createWorkflowInstance(PROCESS_ID); // then final List<Record<WorkflowInstanceRecordValue>> workflowInstanceEvents = testClient .receiveWorkflowInstances() .limitToWorkflowInstanceCompleted() .collect(Collectors.toList()); assertThat(workflowInstanceEvents) .extracting(e -> e.getValue().getElementId(), e -> e.getMetadata().getIntent()) .containsSubsequence( tuple("end", WorkflowInstanceIntent.EVENT_ACTIVATED), tuple("end", WorkflowInstanceIntent.EVENT_ACTIVATED), tuple(PROCESS_ID, WorkflowInstanceIntent.ELEMENT_COMPLETED)); }
.sequenceFlowId("s2") .connectTo("joinRequest") .endEvent("end") .done();
public B condition(String name, String condition) { if (name != null) { getCurrentSequenceFlowBuilder().name(name); } final ConditionExpression conditionExpression = createInstance(ConditionExpression.class); conditionExpression.setTextContent(condition); getCurrentSequenceFlowBuilder().condition(conditionExpression); return myself; }
protected void connectTargetWithAssociation(FlowNode target) { final Association association = modelInstance.newInstance(Association.class); association.setTarget(target); association.setSource(element); association.setAssociationDirection(AssociationDirection.One); element.getParentElement().addChildElement(association); createEdge(association); }
public AbstractFlowNodeBuilder<?, ?> connectTo(String identifier) { final ModelElementInstance target = modelInstance.getModelElementById(identifier); if (target == null) { throw new BpmnModelException( "Unable to connect " + element.getId() + " to element " + identifier + " cause it not exists."); } else if (!(target instanceof FlowNode)) { throw new BpmnModelException( "Unable to connect " + element.getId() + " to element " + identifier + " cause its not a flow node."); } else { final FlowNode targetNode = (FlowNode) target; connectTarget(targetNode); return targetNode.builder(); } }
.moveToLastGateway() .connectTo("exclusiveJoin") .sequenceFlowId("joinFlow1") .parallelGateway("join") .moveToNode("fork") .serviceTask("waitState", b -> b.zeebeTaskType("type")) .sequenceFlowId("joinFlow2") .connectTo("join") .endEvent() .done();
@Test public void shouldNotCompleteInstanceAfterIncidentIsRaisedOnExclusiveGateway() { // given testClient.deploy( Bpmn.createExecutableProcess(PROCESS_ID) .startEvent() .parallelGateway() .serviceTask("task", t -> t.zeebeTaskType("task")) .endEvent("end-1") .moveToLastGateway() .exclusiveGateway("gateway") .defaultFlow() .endEvent("end-2") .moveToNode("gateway") .sequenceFlowId("to-end-3") .condition("$.x < 21") .endEvent("end-3") .done()); testClient.createWorkflowInstance(PROCESS_ID); // when final Record<IncidentRecordValue> incident = RecordingExporter.incidentRecords(IncidentIntent.CREATED).getFirst(); testClient.completeJobOfType("task"); testClient.updatePayload(incident.getValue().getElementInstanceKey(), "{'x':123}"); testClient.resolveIncident(incident.getKey()); // then assertThatWorkflowInstanceCompletedAfter("end-2", WorkflowInstanceIntent.ELEMENT_COMPLETED); }
protected void connectTarget(FlowNode target) { // check if compensation was started if (isBoundaryEventWithStartedCompensation()) { // the target activity should be marked for compensation if (target instanceof Activity) { ((Activity) target).setForCompensation(true); } // connect the target via association instead of sequence flow connectTargetWithAssociation(target); } else if (isCompensationHandler()) { // cannot connect to a compensation handler throw new BpmnModelException( "Only single compensation handler allowed. Call compensationDone() to continue main flow."); } else { // connect as sequence flow by default connectTargetWithSequenceFlow(target); } }