Skip to content

Commit

Permalink
Add base sample native example
Browse files Browse the repository at this point in the history
The example is from https://github.com/spring-tips/flowable-processes

Co-Authored-By: Joram Barrez <[email protected]>
  • Loading branch information
joshlong and jbarrez committed Feb 7, 2024
1 parent d14c893 commit 5a31cf8
Show file tree
Hide file tree
Showing 10 changed files with 394 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/usr/bin/env bash
rm -rf target
mvn -DskipTests -Pnative native:compile
./target/flowable
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>org.flowable</groupId>
<artifactId>flowable-spring-boot-samples</artifactId>
<version>7.1.0-SNAPSHOT</version>
</parent>

<artifactId>flowable-spring-boot-sample-native</artifactId>

<dependencies>
<dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.graalvm.buildtools</groupId>
<artifactId>native-maven-plugin</artifactId>
<configuration>
<buildArgs>
--enable-url-protocols=https
</buildArgs>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>

<configuration>
<jvmArguments>
-agentlib:native-image-agent=config-output-dir=target/native-image
</jvmArguments>
</configuration>
</plugin>
</plugins>
</build>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.flowable;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

import org.flowable.cmmn.api.delegate.DelegatePlanItemInstance;
import org.flowable.cmmn.api.delegate.PlanItemJavaDelegate;
import org.flowable.common.engine.api.variable.VariableContainer;
import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.delegate.JavaDelegate;
import org.springframework.stereotype.Service;

@Service
public class EmailService implements JavaDelegate, PlanItemJavaDelegate {

protected final ConcurrentHashMap<String, AtomicInteger> sends = new ConcurrentHashMap<>();

protected AtomicInteger getSendCount(String key) {
return this.sends.get(key);
}

@Override
public void execute(DelegateExecution execution) {
internalExecute(execution);
}

@Override
public void execute(DelegatePlanItemInstance planItemInstance) {
internalExecute(planItemInstance);
}

protected void internalExecute(VariableContainer variableContainer) {
String customerId = (String) variableContainer.getVariable("customerId");
String email = (String) variableContainer.getVariable("email");
System.out.println("sending welcome email for " + customerId + " to " + email);
sends.computeIfAbsent(email, e -> new AtomicInteger());
sends.get(email).incrementAndGet();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
/* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.flowable;

import java.util.List;
import java.util.Map;

import org.flowable.cmmn.api.CmmnRuntimeService;
import org.flowable.cmmn.api.CmmnTaskService;
import org.flowable.cmmn.engine.CmmnEngine;
import org.flowable.dmn.engine.DmnEngine;
import org.flowable.engine.ProcessEngine;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.task.api.Task;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.util.Assert;

@SpringBootApplication
public class FlowableApplication {

public static void main(String[] args) {
SpringApplication.run(FlowableApplication.class, args);
}

@Bean
ApplicationRunner demo(ProcessEngine processEngine, CmmnEngine cmmnEngine, DmnEngine dmnEngine, EmailService emailService) {
return args -> {
startProcessInstance(processEngine, emailService);
startCaseInstance(cmmnEngine, emailService);
executeRule(dmnEngine);
};
}

protected void startProcessInstance(ProcessEngine processEngine, EmailService emailService) {
String customerId = "1";
String email = "[email protected]";

RuntimeService runtimeService = processEngine.getRuntimeService();
TaskService taskService = processEngine.getTaskService();

Map<String, Object> vars = Map.of("customerId", customerId, "email", email);
String processInstanceId = runtimeService.startProcessInstanceByKey("signup-process", vars).getId();

System.out.println("process instance ID: " + processInstanceId);
Assert.notNull(processInstanceId, "the process instance ID should not be null");
List<Task> tasks = taskService
.createTaskQuery()
.taskName("confirm-email-task")
.includeProcessVariables()
.processVariableValueEquals("customerId", customerId)
.list();
Assert.state(!tasks.isEmpty(), "there should be one outstanding task");
tasks.forEach(task -> {
taskService.claim(task.getId(), "jlong");
taskService.complete(task.getId());
});
Assert.isTrue(emailService.getSendCount(email).get() == 1, "there should be 1 email sent");
}

protected void startCaseInstance(CmmnEngine cmmnEngine, EmailService emailService) {
String customerId = "2";
String email = "[email protected]";

CmmnRuntimeService cmmnRuntimeService = cmmnEngine.getCmmnRuntimeService();
CmmnTaskService cmmnTaskService = cmmnEngine.getCmmnTaskService();

String caseInstanceId = cmmnRuntimeService.createCaseInstanceBuilder()
.caseDefinitionKey("signupCase")
.variable("customerId", customerId)
.variable("email", email)
.start()
.getId();

System.out.println("case instance ID: " + caseInstanceId);
Assert.notNull(caseInstanceId, "the case instance ID should not be null");
List<Task> tasks = cmmnTaskService
.createTaskQuery()
.taskName("Confirm email task")
.includeProcessVariables()
.caseVariableValueEquals("customerId", customerId)
.list();
Assert.state(!tasks.isEmpty(), "there should be one outstanding task");
tasks.forEach(task -> {
cmmnTaskService.claim(task.getId(), "jbarrez");
cmmnTaskService.complete(task.getId());
});
Assert.isTrue(emailService.getSendCount(email).get() == 2, "there should be 2 emails sent");
}

protected void executeRule(DmnEngine dmnEngine) {
Map<String, Object> result = dmnEngine.getDmnDecisionService().createExecuteDecisionBuilder()
.decisionKey("myDecisionTable")
.variable("customerTotalOrderPrice", 99999)
.executeWithSingleResult();

Assert.isTrue(result.size() == 1, "Expected one result");
Object tier = result.get("tier");
Assert.isTrue(tier.equals("SILVER"), "Expected SILVER as output, but was " + tier);
System.out.println("Executed DMN rule correctly");
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#spring.threads.virtual.enabled=true

logging.level.root=INFO

spring.sql.init.mode=always

flowable.eventregistry.enabled=false
flowable.idm.enabled=false
flowable.jpa-enabled=false
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/CMMN/20151109/MODEL" xmlns:flowable="http://flowable.org/cmmn"
xmlns:cmmndi="http://www.omg.org/spec/CMMN/20151109/CMMNDI" xmlns:dc="http://www.omg.org/spec/CMMN/20151109/DC"
xmlns:di="http://www.omg.org/spec/CMMN/20151109/DI" xmlns:design="http://flowable.org/design" targetNamespace="http://flowable.org/cmmn"
design:palette="flowable-core-case-palette">
<case id="signupCase" name="SignupCase" flowable:initiatorVariableName="initiator" flowable:candidateStarterGroups="flowableUser">
<casePlanModel id="onecaseplanmodel1" name="Case plan model">
<extensionElements>
<design:stencilid><![CDATA[CasePlanModel]]></design:stencilid>
</extensionElements>
<planItem id="planItemcmmnTask_1" name="Confirm email task" definitionRef="cmmnTask_1"></planItem>
<planItem id="planItemcmmnTask_2" name="Send welcome email" definitionRef="cmmnTask_2">
<entryCriterion id="cmmnEntrySentry_3" sentryRef="sentrycmmnEntrySentry_3"></entryCriterion>
</planItem>
<sentry id="sentrycmmnEntrySentry_3">
<extensionElements>
<design:stencilid><![CDATA[EntryCriterion]]></design:stencilid>
</extensionElements>
<planItemOnPart id="sentryOnPartcmmnEntrySentry_3" sourceRef="planItemcmmnTask_1">
<standardEvent>complete</standardEvent>
</planItemOnPart>
</sentry>
<humanTask id="cmmnTask_1" name="Confirm email task" flowable:assignee="${initiator}">
<extensionElements>
<design:stencilid><![CDATA[HumanTask]]></design:stencilid>
<design:stencilsuperid><![CDATA[Task]]></design:stencilsuperid>
</extensionElements>
</humanTask>
<task id="cmmnTask_2" name="Send welcome email" flowable:type="java" flowable:delegateExpression="${emailService}">
<extensionElements>
<design:stencilid><![CDATA[ServiceTask]]></design:stencilid>
<design:stencilsuperid><![CDATA[Task]]></design:stencilsuperid>
</extensionElements>
</task>
</casePlanModel>
</case>
<cmmndi:CMMNDI>
<cmmndi:CMMNDiagram id="CMMNDiagram_signupCase">
<cmmndi:CMMNShape id="CMMNShape_onecaseplanmodel1" cmmnElementRef="onecaseplanmodel1">
<dc:Bounds height="679.0" width="830.0" x="270.0" y="120.0"></dc:Bounds>
<cmmndi:CMMNLabel></cmmndi:CMMNLabel>
</cmmndi:CMMNShape>
<cmmndi:CMMNShape id="CMMNShape_planItemcmmnTask_1" cmmnElementRef="planItemcmmnTask_1">
<dc:Bounds height="80.0" width="100.0" x="331.0" y="229.0"></dc:Bounds>
<cmmndi:CMMNLabel></cmmndi:CMMNLabel>
</cmmndi:CMMNShape>
<cmmndi:CMMNShape id="CMMNShape_planItemcmmnTask_2" cmmnElementRef="planItemcmmnTask_2">
<dc:Bounds height="80.0" width="100.0" x="622.0" y="229.0"></dc:Bounds>
<cmmndi:CMMNLabel></cmmndi:CMMNLabel>
</cmmndi:CMMNShape>
<cmmndi:CMMNShape id="CMMNShape_cmmnEntrySentry_3" cmmnElementRef="cmmnEntrySentry_3">
<dc:Bounds height="28.0" width="18.0" x="613.0" y="255.0"></dc:Bounds>
<cmmndi:CMMNLabel></cmmndi:CMMNLabel>
</cmmndi:CMMNShape>
<cmmndi:CMMNEdge id="CMMNEdge_cmmnConnector_4" cmmnElementRef="planItemcmmnTask_1" targetCMMNElementRef="cmmnEntrySentry_3">
<di:extension>
<flowable:docker type="source" x="50.0" y="40.0"></flowable:docker>
<flowable:docker type="target" x="9.0" y="14.0"></flowable:docker>
</di:extension>
<di:waypoint x="431.0" y="269.0"></di:waypoint>
<di:waypoint x="613.0" y="269.0"></di:waypoint>
<cmmndi:CMMNLabel></cmmndi:CMMNLabel>
</cmmndi:CMMNEdge>
</cmmndi:CMMNDiagram>
</cmmndi:CMMNDI>
</definitions>
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<definitions xmlns="https://www.omg.org/spec/DMN/20191111/MODEL/" xmlns:dmndi="https://www.omg.org/spec/DMN/20191111/DMNDI/" id="definition_myDecisionTable"
name="MyDecisionTable" namespace="http://www.flowable.org/dmn">
<decision id="myDecisionTable" name="MyDecisionTable">
<decisionTable id="decisionTable_myDecisionTable" hitPolicy="FIRST">
<input label="Order">
<inputExpression id="inputExpression_1" typeRef="number">
<text>customerTotalOrderPrice</text>
</inputExpression>
</input>
<output id="outputExpression_2" label="Tier" name="tier" typeRef="string"></output>
<rule>
<inputEntry id="inputEntry_1_1">
<text><![CDATA[> 100000]]></text>
</inputEntry>
<outputEntry id="outputEntry_2_1">
<text><![CDATA["GOLD"]]></text>
</outputEntry>
</rule>
<rule>
<inputEntry id="inputEntry_1_2">
<text><![CDATA[> 10000]]></text>
</inputEntry>
<outputEntry id="outputEntry_2_2">
<text><![CDATA["SILVER"]]></text>
</outputEntry>
</rule>
<rule>
<inputEntry id="inputEntry_1_3">
<text><![CDATA[> 1000]]></text>
</inputEntry>
<outputEntry id="outputEntry_2_3">
<text><![CDATA["BRONZE"]]></text>
</outputEntry>
</rule>
</decisionTable>
</decision>
<dmndi:DMNDI></dmndi:DMNDI>
</definitions>
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<definitions
xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
xmlns:flowable="http://flowable.org/bpmn"
targetNamespace="Examples">

<!--
we expect a ${customerId} and ${email} process variable
-->
<process id="signup-process" name="signup-process">

<startEvent id="start" flowable:initiator="initiator"/>

<sequenceFlow sourceRef="start" targetRef="confirm-email-task"/>

<userTask id="confirm-email-task" name="confirm-email-task"
flowable:assignee="${initiator}"/>

<sequenceFlow sourceRef="confirm-email-task"
targetRef="send-welcome-email-task"/>

<serviceTask id="send-welcome-email-task"
flowable:delegateExpression="#{emailService}" />

<sequenceFlow sourceRef="send-welcome-email-task" targetRef="end"/>

<endEvent id="end"/>

</process>

</definitions>
Loading

0 comments on commit 5a31cf8

Please sign in to comment.