Java Code Examples for org.flowable.bpmn.model.Process#getFlowElement()

The following examples show how to use org.flowable.bpmn.model.Process#getFlowElement() . You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example 1
Source File: PoolsConverterTest.java    From flowable-engine with Apache License 2.0 6 votes vote down vote up
private void validateModel(BpmnModel model) {
    assertThat(model.getPools())
            .extracting(Pool::getId, Pool::getName)
            .containsExactly(tuple("pool1", "Pool"));
    Pool pool = model.getPools().get(0);
    Process process = model.getProcess(pool.getId());
    assertThat(process.getLanes())
            .extracting(Lane::getId, Lane::getName)
            .containsExactly(
                    tuple("lane1", "Lane 1"),
                    tuple("lane2", "Lane 2")
            );
    assertThat(process.getLanes().get(0).getFlowReferences()).hasSize(2);
    assertThat(process.getLanes().get(1).getFlowReferences()).hasSize(2);

    FlowElement flowElement = process.getFlowElement("flow1");
    assertThat(flowElement).isInstanceOf(SequenceFlow.class);
}
 
Example 2
Source File: SyncopeFormHandlerHelper.java    From syncope with Apache License 2.0 6 votes vote down vote up
@Override
public TaskFormHandler getTaskFormHandlder(final String procDefId, final String taskId) {
    Process process = ProcessDefinitionUtil.getProcess(procDefId);
    FlowElement flowElement = process.getFlowElement(taskId, true);
    if (flowElement instanceof UserTask) {
        UserTask userTask = (UserTask) flowElement;

        ProcessDefinition processDefinitionEntity = ProcessDefinitionUtil.getProcessDefinition(procDefId);
        DeploymentEntity deploymentEntity = CommandContextUtil.getProcessEngineConfiguration().
                getDeploymentEntityManager().findById(processDefinitionEntity.getDeploymentId());

        TaskFormHandler taskFormHandler = new SyncopeTaskFormHandler();
        taskFormHandler.parseConfiguration(
                userTask.getFormProperties(), userTask.getFormKey(), deploymentEntity, processDefinitionEntity);
        return taskFormHandler;
    }

    return null;
}
 
Example 3
Source File: ExecutionGraphUtil.java    From flowable-engine with Apache License 2.0 5 votes vote down vote up
/**
 * Verifies if the element with the given source identifier can reach the element with the target identifier through following sequence flow.
 */
public static boolean isReachable(String processDefinitionId, String sourceElementId, String targetElementId) {

    // Fetch source and target elements
    Process process = ProcessDefinitionUtil.getProcess(processDefinitionId);

    FlowElement sourceFlowElement = process.getFlowElement(sourceElementId, true);
    FlowNode sourceElement = null;
    if (sourceFlowElement instanceof FlowNode) {
        sourceElement = (FlowNode) sourceFlowElement;
    } else if (sourceFlowElement instanceof SequenceFlow) {
        sourceElement = (FlowNode) ((SequenceFlow) sourceFlowElement).getTargetFlowElement();
    }

    FlowElement targetFlowElement = process.getFlowElement(targetElementId, true);
    FlowNode targetElement = null;
    if (targetFlowElement instanceof FlowNode) {
        targetElement = (FlowNode) targetFlowElement;
    } else if (targetFlowElement instanceof SequenceFlow) {
        targetElement = (FlowNode) ((SequenceFlow) targetFlowElement).getTargetFlowElement();
    }

    if (sourceElement == null) {
        throw new FlowableException("Invalid sourceElementId '" + sourceElementId + "': no element found for this id n process definition '" + processDefinitionId + "'");
    }
    if (targetElement == null) {
        throw new FlowableException("Invalid targetElementId '" + targetElementId + "': no element found for this id n process definition '" + processDefinitionId + "'");
    }

    Set<String> visitedElements = new HashSet<>();
    return isReachable(process, sourceElement, targetElement, visitedElements);
}
 
Example 4
Source File: BaseDynamicSubProcessInjectUtil.java    From flowable-engine with Apache License 2.0 5 votes vote down vote up
protected static void processSubProcessFlowElements(CommandContext commandContext, String prefix, Process process, BpmnModel bpmnModel, 
                SubProcess subProcess, BpmnModel subProcessBpmnModel, ProcessDefinition originalProcessDefinition, 
                DeploymentEntity newDeploymentEntity, Map<String, FlowElement> generatedIds, boolean includeDiInfo) {
    
    Collection<FlowElement> flowElementsOfSubProcess = subProcess.getFlowElementMap().values(); 
    for (FlowElement flowElement : flowElementsOfSubProcess) {

        if (process.getFlowElement(flowElement.getId(), true) != null) {
            generateIdForDuplicateFlowElement(prefix, process, bpmnModel, subProcessBpmnModel, flowElement, generatedIds, includeDiInfo);
        } else {
            if (includeDiInfo) {
                if (flowElement instanceof SequenceFlow) {
                    List<GraphicInfo> wayPoints = subProcessBpmnModel.getFlowLocationGraphicInfo(flowElement.getId());
                    if (wayPoints != null) {
                        bpmnModel.addFlowGraphicInfoList(flowElement.getId(), wayPoints);
                    }
                    
                } else {
                    GraphicInfo graphicInfo = subProcessBpmnModel.getGraphicInfo(flowElement.getId());
                    if (graphicInfo != null) {
                        bpmnModel.addGraphicInfo(flowElement.getId(), subProcessBpmnModel.getGraphicInfo(flowElement.getId()));
                    }
                }
            }
        }
        
        processUserTask(flowElement, originalProcessDefinition, newDeploymentEntity, commandContext);
        processDecisionTask(flowElement, originalProcessDefinition, newDeploymentEntity, commandContext);

        if (flowElement instanceof SubProcess) {
            processSubProcessFlowElements(commandContext, prefix, process, bpmnModel, (SubProcess) flowElement, 
                    subProcessBpmnModel, originalProcessDefinition, newDeploymentEntity, generatedIds, includeDiInfo);
        }
    }
}
 
Example 5
Source File: ProcessDefinitionPersistenceTest.java    From flowable-engine with Apache License 2.0 5 votes vote down vote up
@Test
public void testProcessDefinitionIntrospection() {
    String deploymentId = repositoryService.createDeployment().addClasspathResource("org/flowable/engine/test/db/processOne.bpmn20.xml").deploy().getId();

    String procDefId = repositoryService.createProcessDefinitionQuery().singleResult().getId();
    ProcessDefinition processDefinition = ((RepositoryServiceImpl) repositoryService).getDeployedProcessDefinition(procDefId);

    assertThat(processDefinition.getId()).isEqualTo(procDefId);
    assertThat(processDefinition.getName()).isEqualTo("Process One");

    Process process = repositoryService.getBpmnModel(processDefinition.getId()).getMainProcess();
    StartEvent startElement = (StartEvent) process.getFlowElement("start");
    assertThat(startElement).isNotNull();
    assertThat(startElement.getId()).isEqualTo("start");
    assertThat(startElement.getName()).isEqualTo("S t a r t");
    assertThat(startElement.getDocumentation()).isEqualTo("the start event");
    List<SequenceFlow> outgoingFlows = startElement.getOutgoingFlows();
    assertThat(outgoingFlows)
            .extracting(SequenceFlow::getConditionExpression)
            .containsExactly("${a == b}");

    EndEvent endElement = (EndEvent) process.getFlowElement("end");
    assertThat(endElement).isNotNull();
    assertThat(endElement.getId()).isEqualTo("end");

    assertThat(outgoingFlows.get(0).getId()).isEqualTo("flow1");
    assertThat(outgoingFlows.get(0).getName()).isEqualTo("Flow One");
    assertThat(outgoingFlows.get(0).getDocumentation()).isEqualTo("The only transitions in the process");
    assertThat(outgoingFlows.get(0).getSourceFlowElement()).isSameAs(startElement);
    assertThat(outgoingFlows.get(0).getTargetFlowElement()).isSameAs(endElement);

    repositoryService.deleteDeployment(deploymentId);
}
 
Example 6
Source File: BpmnParseTest.java    From flowable-engine with Apache License 2.0 5 votes vote down vote up
@Test
@Deployment
public void testParseNamespaceInConditionExpressionType() {

    BpmnModel bpmnModel = repositoryService.getBpmnModel(repositoryService.createProcessDefinitionQuery().singleResult().getId());
    Process process = bpmnModel.getProcesses().get(0);
    assertNotNull(process);

    SequenceFlow sequenceFlow = (SequenceFlow) process.getFlowElement("SequenceFlow_3");
    assertEquals("#{approved}", sequenceFlow.getConditionExpression());

    sequenceFlow = (SequenceFlow) process.getFlowElement("SequenceFlow_4");
    assertEquals("#{!approved}", sequenceFlow.getConditionExpression());

}
 
Example 7
Source File: EventGatewayValidator.java    From flowable-engine with Apache License 2.0 5 votes vote down vote up
@Override
protected void executeValidation(BpmnModel bpmnModel, Process process, List<ValidationError> errors) {
    List<EventGateway> eventGateways = process.findFlowElementsOfType(EventGateway.class);
    for (EventGateway eventGateway : eventGateways) {
        for (SequenceFlow sequenceFlow : eventGateway.getOutgoingFlows()) {
            FlowElement flowElement = process.getFlowElement(sequenceFlow.getTargetRef(), true);
            if (flowElement != null && !(flowElement instanceof IntermediateCatchEvent)) {
                addError(errors, Problems.EVENT_GATEWAY_ONLY_CONNECTED_TO_INTERMEDIATE_EVENTS, process, eventGateway, "Event based gateway can only be connected to elements of type intermediateCatchEvent");
            }
        }
    }
}
 
Example 8
Source File: EventValidator.java    From flowable-engine with Apache License 2.0 5 votes vote down vote up
protected void handleCompensationEventDefinition(BpmnModel bpmnModel, Process process, Event event, EventDefinition eventDefinition, List<ValidationError> errors) {
    CompensateEventDefinition compensateEventDefinition = (CompensateEventDefinition) eventDefinition;

    // Check activityRef
    if ((StringUtils.isNotEmpty(compensateEventDefinition.getActivityRef()) && process.getFlowElement(compensateEventDefinition.getActivityRef(), true) == null)) {
        addError(errors, Problems.COMPENSATE_EVENT_INVALID_ACTIVITY_REF, process, event, "Invalid attribute value for 'activityRef': no activity with the given id");
    }
}
 
Example 9
Source File: CompensationEventHandler.java    From flowable-engine with Apache License 2.0 4 votes vote down vote up
@Override
public void handleEvent(EventSubscriptionEntity eventSubscription, Object payload, CommandContext commandContext) {

    String configuration = eventSubscription.getConfiguration();
    if (configuration == null) {
        throw new FlowableException("Compensating execution not set for compensate event subscription with id " + eventSubscription.getId());
    }

    ExecutionEntity compensatingExecution = CommandContextUtil.getExecutionEntityManager(commandContext).findById(configuration);

    String processDefinitionId = compensatingExecution.getProcessDefinitionId();
    Process process = ProcessDefinitionUtil.getProcess(processDefinitionId);
    if (process == null) {
        throw new FlowableException("Cannot start process instance. Process model (id = " + processDefinitionId + ") could not be found");
    }

    FlowElement flowElement = process.getFlowElement(eventSubscription.getActivityId(), true);

    if (flowElement instanceof SubProcess && !((SubProcess) flowElement).isForCompensation()) {

        // descend into scope:
        compensatingExecution.setScope(true);
        List<CompensateEventSubscriptionEntity> eventsForThisScope = CommandContextUtil.getEventSubscriptionService(commandContext).findCompensateEventSubscriptionsByExecutionId(compensatingExecution.getId());
        ScopeUtil.throwCompensationEvent(eventsForThisScope, compensatingExecution, false);

    } else {

        try {

            FlowableEventDispatcher eventDispatcher = CommandContextUtil.getProcessEngineConfiguration(commandContext).getEventDispatcher();
            if (eventDispatcher != null && eventDispatcher.isEnabled()) {
                eventDispatcher.dispatchEvent(
                        FlowableEventBuilder.createActivityEvent(FlowableEngineEventType.ACTIVITY_COMPENSATE, flowElement.getId(), flowElement.getName(),
                                compensatingExecution.getId(), compensatingExecution.getProcessInstanceId(), compensatingExecution.getProcessDefinitionId(), flowElement));
            }
            
            Activity compensationActivity = null;
            Activity activity = (Activity) flowElement;
            if (!activity.isForCompensation() && activity.getBoundaryEvents().size() > 0) {
                for (BoundaryEvent boundaryEvent : activity.getBoundaryEvents()) {
                    if (boundaryEvent.getEventDefinitions().size() > 0 && boundaryEvent.getEventDefinitions().get(0) instanceof CompensateEventDefinition) {
                        List<Association> associations = process.findAssociationsWithSourceRefRecursive(boundaryEvent.getId());
                        for (Association association : associations) {
                            FlowElement targetElement = process.getFlowElement(association.getTargetRef(), true);
                            if (targetElement instanceof Activity) {
                                Activity targetActivity = (Activity) targetElement;
                                if (targetActivity.isForCompensation()) {
                                    compensationActivity = targetActivity;
                                    break;
                                }
                            }
                        }
                    }
                }
            }
            
            if (compensationActivity != null) {
                flowElement = compensationActivity;
            }
            
            compensatingExecution.setCurrentFlowElement(flowElement);
            CommandContextUtil.getAgenda().planContinueProcessInCompensation(compensatingExecution);

        } catch (Exception e) {
            throw new FlowableException("Error while handling compensation event " + eventSubscription, e);
        }

    }
}
 
Example 10
Source File: ExecutionGraphUtil.java    From flowable-engine with Apache License 2.0 4 votes vote down vote up
public static boolean isReachable(Process process, FlowNode sourceElement, FlowNode targetElement, Set<String> visitedElements) {
    
    // Special case: start events in an event subprocess might exist as an execution and are most likely be able to reach the target
    // when the target is in the event subprocess, but should be ignored as they are not 'real' runtime executions (but rather waiting for a trigger)
    if (sourceElement instanceof StartEvent && isInEventSubprocess(sourceElement)) {
        return false;
    }

    // No outgoing seq flow: could be the end of eg . the process or an embedded subprocess
    if (sourceElement.getOutgoingFlows().size() == 0) {
        visitedElements.add(sourceElement.getId());

        FlowElementsContainer parentElement = process.findParent(sourceElement);
        if (parentElement instanceof SubProcess) {
            sourceElement = (SubProcess) parentElement;
        } else {
            return false;
        }
    }

    if (sourceElement.getId().equals(targetElement.getId())) {
        return true;
    }

    // To avoid infinite looping, we must capture every node we visit
    // and check before going further in the graph if we have already
    // visited the node.
    visitedElements.add(sourceElement.getId());

    List<SequenceFlow> sequenceFlows = sourceElement.getOutgoingFlows();
    if (sequenceFlows != null && sequenceFlows.size() > 0) {
        for (SequenceFlow sequenceFlow : sequenceFlows) {
            String targetRef = sequenceFlow.getTargetRef();
            FlowNode sequenceFlowTarget = (FlowNode) process.getFlowElement(targetRef, true);
            if (sequenceFlowTarget != null && !visitedElements.contains(sequenceFlowTarget.getId())) {
                boolean reachable = isReachable(process, sequenceFlowTarget, targetElement, visitedElements);

                if (reachable) {
                    return true;
                }
            }
        }
    }

    return false;
}
 
Example 11
Source File: GetTaskFormModelCmd.java    From flowable-engine with Apache License 2.0 4 votes vote down vote up
@Override
public FormInfo execute(CommandContext commandContext) {
    boolean historic = false;

    ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(commandContext);
    FormService formService = CommandContextUtil.getFormService();
    if (formService == null) {
        throw new FlowableIllegalArgumentException("Form engine is not initialized");
    }

    TaskInfo task = CommandContextUtil.getTaskService(commandContext).getTask(taskId);
    Date endTime = null;
    if (task == null) {
        historic = true;
        task = CommandContextUtil.getHistoricTaskService(commandContext).getHistoricTask(taskId);
        if (task != null) {
            endTime = ((HistoricTaskInstance) task).getEndTime();
        }
    }

    if (task == null) {
        throw new FlowableObjectNotFoundException("Task not found with id " + taskId);
    }

    Map<String, Object> variables = new HashMap<>();
    if (!ignoreVariables && task.getProcessInstanceId() != null) {

        if (!historic) {
            processEngineConfiguration.getTaskService()
                    .getVariableInstances(taskId).values()
                    .stream()
                    .forEach(variableInstance -> variables.putIfAbsent(variableInstance.getName(), variableInstance.getValue()));

            processEngineConfiguration.getRuntimeService().getVariableInstances(task.getProcessInstanceId()).values()
                    .stream()
                    .forEach(variableInstance -> variables.putIfAbsent(variableInstance.getName(), variableInstance.getValue()));


        } else {

            processEngineConfiguration.getHistoryService()
                    .createHistoricVariableInstanceQuery().taskId(taskId).list()
                    .stream()
                    .forEach(variableInstance -> variables.putIfAbsent(variableInstance.getVariableName(), variableInstance.getValue()));

            processEngineConfiguration.getHistoryService()
                    .createHistoricVariableInstanceQuery().processInstanceId(task.getProcessInstanceId()).list()
                    .stream()
                    .forEach(variableInstance -> variables.putIfAbsent(variableInstance.getVariableName(), variableInstance.getValue()));

        }
    }

    String parentDeploymentId = null;
    if (StringUtils.isNotEmpty(task.getProcessDefinitionId())) {
        Process process = ProcessDefinitionUtil.getProcess(task.getProcessDefinitionId());
        FlowElement element = process.getFlowElement(task.getTaskDefinitionKey(), true);
        boolean sameDeployment = true;
        if (element instanceof UserTask) {
            sameDeployment = ((UserTask) element).isSameDeployment();
        }
        if (sameDeployment) {
            // If it is not same deployment then there is no need to search for parent deployment
            parentDeploymentId = ProcessDefinitionUtil.getDefinitionDeploymentId(task.getProcessDefinitionId(), processEngineConfiguration);
        }
    }

    FormInfo formInfo = null;
    if (ignoreVariables) {
        FormRepositoryService formRepositoryService = CommandContextUtil.getFormRepositoryService();
        formInfo = formRepositoryService.getFormModelByKeyAndParentDeploymentId(task.getFormKey(), parentDeploymentId,
                task.getTenantId(), processEngineConfiguration.isFallbackToDefaultTenant());

    } else if (endTime != null) {
        formInfo = formService.getFormInstanceModelByKeyAndParentDeploymentId(task.getFormKey(), parentDeploymentId,
                taskId, task.getProcessInstanceId(), variables, task.getTenantId(), processEngineConfiguration.isFallbackToDefaultTenant());

    } else {
        formInfo = formService.getFormModelWithVariablesByKeyAndParentDeploymentId(task.getFormKey(), parentDeploymentId,
                taskId, variables, task.getTenantId(), processEngineConfiguration.isFallbackToDefaultTenant());
    }

    // If form does not exists, we don't want to leak out this info to just anyone
    if (formInfo == null) {
        throw new FlowableObjectNotFoundException("Form model for task " + task.getTaskDefinitionKey() + " cannot be found for form key " + task.getFormKey());
    }

    FormFieldHandler formFieldHandler = CommandContextUtil.getProcessEngineConfiguration(commandContext).getFormFieldHandler();
    formFieldHandler.enrichFormFields(formInfo);

    return formInfo;
}
 
Example 12
Source File: BoundaryCompensateEventActivityBehavior.java    From flowable-engine with Apache License 2.0 4 votes vote down vote up
@Override
public void execute(DelegateExecution execution) {
    ExecutionEntity executionEntity = (ExecutionEntity) execution;
    BoundaryEvent boundaryEvent = (BoundaryEvent) execution.getCurrentFlowElement();

    Process process = ProcessDefinitionUtil.getProcess(execution.getProcessDefinitionId());
    if (process == null) {
        throw new FlowableException("Process model (id = " + execution.getId() + ") could not be found");
    }

    Activity sourceActivity = null;
    Activity compensationActivity = null;
    List<Association> associations = process.findAssociationsWithSourceRefRecursive(boundaryEvent.getId());
    for (Association association : associations) {
        sourceActivity = boundaryEvent.getAttachedToRef();
        FlowElement targetElement = process.getFlowElement(association.getTargetRef(), true);
        if (targetElement instanceof Activity) {
            Activity activity = (Activity) targetElement;
            if (activity.isForCompensation()) {
                compensationActivity = activity;
                break;
            }
        }
    }
    
    if (sourceActivity == null) {
        throw new FlowableException("Parent activity for boundary compensation event could not be found");
    }

    if (compensationActivity == null) {
        throw new FlowableException("Compensation activity could not be found (or it is missing 'isForCompensation=\"true\"'");
    }

    // find SubProcess or Process instance execution
    ExecutionEntity scopeExecution = null;
    ExecutionEntity parentExecution = executionEntity.getParent();
    while (scopeExecution == null && parentExecution != null) {
        if (parentExecution.getCurrentFlowElement() instanceof SubProcess) {
            scopeExecution = parentExecution;

        } else if (parentExecution.isProcessInstanceType()) {
            scopeExecution = parentExecution;
        } else {
            parentExecution = parentExecution.getParent();
        }
    }

    if (scopeExecution == null) {
        throw new FlowableException("Could not find a scope execution for compensation boundary event " + boundaryEvent.getId());
    }

    EventSubscriptionEntity eventSubscription = (EventSubscriptionEntity) CommandContextUtil.getEventSubscriptionService().createEventSubscriptionBuilder()
                    .eventType(CompensateEventSubscriptionEntity.EVENT_TYPE)
                    .executionId(scopeExecution.getId())
                    .processInstanceId(scopeExecution.getProcessInstanceId())
                    .activityId(sourceActivity.getId())
                    .tenantId(scopeExecution.getTenantId())
                    .create();
    
    CountingEntityUtil.handleInsertEventSubscriptionEntityCount(eventSubscription);
}
 
Example 13
Source File: SequenceflowValidator.java    From flowable-engine with Apache License 2.0 4 votes vote down vote up
@Override
protected void executeValidation(BpmnModel bpmnModel, Process process, List<ValidationError> errors) {
    List<SequenceFlow> sequenceFlows = process.findFlowElementsOfType(SequenceFlow.class);
    for (SequenceFlow sequenceFlow : sequenceFlows) {

        String sourceRef = sequenceFlow.getSourceRef();
        String targetRef = sequenceFlow.getTargetRef();

        if (StringUtils.isEmpty(sourceRef)) {
            addError(errors, Problems.SEQ_FLOW_INVALID_SRC, process, sequenceFlow, "Invalid source for sequenceflow");
        }
        if (StringUtils.isEmpty(targetRef)) {
            addError(errors, Problems.SEQ_FLOW_INVALID_TARGET, process, sequenceFlow, "Invalid target for sequenceflow");
        }

        // Implicit check: sequence flow cannot cross (sub) process boundaries, hence we check the parent and not the process
        // (could be subprocess for example)
        FlowElement source = process.getFlowElement(sourceRef, true);
        FlowElement target = process.getFlowElement(targetRef, true);
        
        // Src and target validation
        if (source == null) {
            addError(errors, Problems.SEQ_FLOW_INVALID_SRC, process, sequenceFlow, "Invalid source for sequenceflow");
        }
        
        if (target == null) {
            addError(errors, Problems.SEQ_FLOW_INVALID_TARGET, process, sequenceFlow, "Invalid target for sequenceflow");
        }

        if (source != null && target != null) {
            FlowElementsContainer sourceContainer = process.getFlowElementsContainer(source.getId());
            FlowElementsContainer targetContainer = process.getFlowElementsContainer(target.getId());
            
            if (sourceContainer == null) {
                addError(errors, Problems.SEQ_FLOW_INVALID_SRC, process, sequenceFlow, "Invalid source for sequenceflow");
            }
            
            if (targetContainer == null) {
                addError(errors, Problems.SEQ_FLOW_INVALID_TARGET, process, sequenceFlow, "Invalid target for sequenceflow");
            }
            
            if (sourceContainer != null && targetContainer != null && !sourceContainer.equals(targetContainer)) {
                addError(errors, Problems.SEQ_FLOW_INVALID_TARGET, process, sequenceFlow, "Invalid target for sequenceflow, the target isn't defined in the same scope as the source");
            }
        }
    }
}
 
Example 14
Source File: SubProcessMultiDiagramConverterTest.java    From flowable-engine with Apache License 2.0 4 votes vote down vote up
private void validateModel(BpmnModel model) {
    Process process = model.getMainProcess();
    Collection<Artifact> artifacts = process.getArtifacts();
    List<ValuedDataObject> dataObjects = process.getDataObjects();

    // verify main process
    assertThat(process.getFlowElements()).hasSize(13);
    assertThat(artifacts).hasSize(2);
    assertThat(dataObjects).hasSize(6);

    Artifact artifact = artifacts.iterator().next();
    assertThat(artifact)
            .isInstanceOfSatisfying(TextAnnotation.class, art -> {
                assertThat(art.getId()).isEqualTo("textannotation1");
                assertThat(art.getText()).isEqualTo("Test Annotation");
            });

    FlowElement flowElement = process.getFlowElement("start1");
    assertThat(flowElement)
            .isInstanceOfSatisfying(StartEvent.class, startEvent -> {
                assertThat(startEvent.getId()).isEqualTo("start1");
            });

    flowElement = process.getFlowElement("userTask1");
    assertThat(flowElement)
            .isInstanceOfSatisfying(UserTask.class, userTask -> {
                assertThat(userTask.getName()).isEqualTo("User task 1");
                assertThat(userTask.getCandidateUsers()).hasSize(1);
                assertThat(userTask.getCandidateGroups()).hasSize(1);
            });

    flowElement = process.getFlowElement("subprocess1");
    assertThat(flowElement)
            .isInstanceOfSatisfying(SubProcess.class, subProcess -> {
                assertThat(subProcess.getId()).isEqualTo("subprocess1");
                assertThat(subProcess.getFlowElements()).hasSize(11);

                // verify subprocess
                assertThat(subProcess.getArtifacts()).hasSize(2);
                assertThat(subProcess.getDataObjects()).hasSize(6);

                assertThat(subProcess.getArtifacts().iterator().next())
                        .isInstanceOfSatisfying(TextAnnotation.class, art -> {
                            assertThat(art.getId()).isEqualTo("textannotation2");
                            assertThat(art.getText()).isEqualTo("Sub Test Annotation");
                        });

                assertThat(subProcess.getFlowElement("subStartEvent"))
                        .isInstanceOfSatisfying(StartEvent.class, startEvent -> {
                            assertThat(startEvent.getId()).isEqualTo("subStartEvent");
                        });

                assertThat(subProcess.getFlowElement("subUserTask1"))
                        .isInstanceOfSatisfying(UserTask.class, userTask -> {
                            assertThat(userTask.getName()).isEqualTo("User task 2");
                            assertThat(userTask.getCandidateUsers()).isEmpty();
                            assertThat(userTask.getCandidateGroups()).isEmpty();
                        });
            });
}