This is an automated email from the ASF dual-hosted git repository.
fjtiradosarti pushed a commit to branch main
in repository
https://gitbox.apache.org/repos/asf/incubator-kie-kogito-examples.git
The following commit(s) were added to refs/heads/main by this push:
new eeb187b96 [KOGITO-9454] Adding Java embedded flows to examples (#1895)
eeb187b96 is described below
commit eeb187b96e1d3526959459ca0c9e0d618eeede46
Author: Francisco Javier Tirado Sarti
<[email protected]>
AuthorDate: Mon Mar 18 22:19:06 2024 +0100
[KOGITO-9454] Adding Java embedded flows to examples (#1895)
* [KOGITO-9454] Adding Java embedded flows to examples
* [KOGITO-9454] nice pom
* [KOGITO-9454] Improve readability of division
* Update serverless-workflow-examples/sonata-workflow-fluent/pom.xml
Co-authored-by: Ricardo Zanini
<[email protected]>
* Update serverless-workflow-examples/sonata-workflow-fluent/pom.xml
Co-authored-by: Ricardo Zanini
<[email protected]>
---------
Co-authored-by: Ricardo Zanini
<[email protected]>
---
serverless-workflow-examples/pom.xml | 1 +
.../sonata-workflow-fluent/README.md | 16 ++++
.../sonata-workflow-fluent/pom.xml | 49 ++++++++++
.../workflow/examples/Concatenation.java | 67 ++++++++++++++
.../serverless/workflow/examples/ForEachJava.java | 81 ++++++++++++++++
.../serverless/workflow/examples/HelloWorld.java | 50 ++++++++++
.../workflow/examples/JQInterpolation.java | 51 +++++++++++
.../serverless/workflow/examples/ParallelRest.java | 102 +++++++++++++++++++++
.../src/main/resources/division.sw.json | 26 ++++++
.../src/main/resources/expression.sw.json | 73 +++++++++++++++
.../src/main/resources/message.txt | 1 +
.../src/main/resources/schema/complex.json | 12 +++
.../src/main/resources/schema/expression.json | 15 +++
.../src/main/resources/schema/result.json | 13 +++
.../examples/WorkflowFluentExamplesTest.java | 100 ++++++++++++++++++++
15 files changed, 657 insertions(+)
diff --git a/serverless-workflow-examples/pom.xml
b/serverless-workflow-examples/pom.xml
index 098044315..add587faf 100644
--- a/serverless-workflow-examples/pom.xml
+++ b/serverless-workflow-examples/pom.xml
@@ -78,6 +78,7 @@
<module>serverless-workflow-timeouts-showcase-extended</module>
<module>serverless-workflow-timeouts-showcase-operator-devprofile</module>
<module>serverless-workflow-python-quarkus</module>
+ <module>sonata-workflow-fluent</module>
</modules>
</profile>
diff --git a/serverless-workflow-examples/sonata-workflow-fluent/README.md
b/serverless-workflow-examples/sonata-workflow-fluent/README.md
new file mode 100644
index 000000000..cdd38688d
--- /dev/null
+++ b/serverless-workflow-examples/sonata-workflow-fluent/README.md
@@ -0,0 +1,16 @@
+## Sonata Workflow Embedded examples
+
+Contains several examples of serverless workflow embedded execution, located
at package `org.kie.kogito.serverless.workflow.examples`.
+
+Each example consist of a commented Java class that can be run using its main
method.
+
+The recommend order of execution is
+
+* HelloWorld
+* Concatenation
+* JQInterpolation
+* ForEachJava
+* ParallelRest
+
+Read comments, run and enjoy!
+
\ No newline at end of file
diff --git a/serverless-workflow-examples/sonata-workflow-fluent/pom.xml
b/serverless-workflow-examples/sonata-workflow-fluent/pom.xml
new file mode 100644
index 000000000..2f46974af
--- /dev/null
+++ b/serverless-workflow-examples/sonata-workflow-fluent/pom.xml
@@ -0,0 +1,49 @@
+<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
https://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.kie.kogito.examples</groupId>
+ <artifactId>serverless-workflow-examples</artifactId>
+ <version>999-SNAPSHOT</version>
+ </parent>
+ <artifactId>sonata-workflow-fluent</artifactId>
+ <name>Kogito Example :: SonataFlow :: Java Embedded examples</name>
+ <properties>
+ <kogito.bom.group-id>org.kie.kogito</kogito.bom.group-id>
+ <kogito.bom.artifact-id>kogito-bom</kogito.bom.artifact-id>
+ <kogito.bom.version>999-SNAPSHOT</kogito.bom.version>
+ <maven.compiler.release>17</maven.compiler.release>
+ <java.module.name>SonataFlowFluent</java.module.name>
+ </properties>
+ <dependencyManagement>
+ <dependencies>
+ <dependency>
+ <groupId>${kogito.bom.group-id}</groupId>
+ <artifactId>${kogito.bom.artifact-id}</artifactId>
+ <version>${kogito.bom.version}</version>
+ <type>pom</type>
+ <scope>import</scope>
+ </dependency>
+ </dependencies>
+ </dependencyManagement>
+ <dependencies>
+ <dependency>
+ <groupId>org.kie.kogito</groupId>
+ <artifactId>kogito-serverless-workflow-executor</artifactId>
+ <type>pom</type>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-simple</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.assertj</groupId>
+ <artifactId>assertj-core</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.junit.jupiter</groupId>
+ <artifactId>junit-jupiter-engine</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+</project>
diff --git
a/serverless-workflow-examples/sonata-workflow-fluent/src/main/java/org/kie/kogito/serverless/workflow/examples/Concatenation.java
b/serverless-workflow-examples/sonata-workflow-fluent/src/main/java/org/kie/kogito/serverless/workflow/examples/Concatenation.java
new file mode 100644
index 000000000..a10a515c2
--- /dev/null
+++
b/serverless-workflow-examples/sonata-workflow-fluent/src/main/java/org/kie/kogito/serverless/workflow/examples/Concatenation.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.kie.kogito.serverless.workflow.examples;
+
+import java.util.Map;
+
+import org.kie.kogito.process.Process;
+import org.kie.kogito.serverless.workflow.actions.WorkflowLogLevel;
+import org.kie.kogito.serverless.workflow.executor.StaticWorkflowApplication;
+import org.kie.kogito.serverless.workflow.models.JsonNodeModel;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import io.serverlessworkflow.api.Workflow;
+
+import static org.kie.kogito.serverless.workflow.fluent.ActionBuilder.call;
+import static org.kie.kogito.serverless.workflow.fluent.ActionBuilder.log;
+import static org.kie.kogito.serverless.workflow.fluent.FunctionBuilder.expr;
+import static org.kie.kogito.serverless.workflow.fluent.StateBuilder.operation;
+import static
org.kie.kogito.serverless.workflow.fluent.WorkflowBuilder.workflow;
+
+public class Concatenation {
+
+ private static final Logger logger =
LoggerFactory.getLogger(Concatenation.class);
+
+ public static void main(String[] args) {
+ try (StaticWorkflowApplication application =
StaticWorkflowApplication.create()) {
+ // This flow illustrate the usage of two consecutive function calls
+ // create a reusable process for several executions
+ Process<JsonNodeModel> process =
application.process(getWorkflow());
+ // execute it with one person name
+ logger.info(application.execute(process, Map.of("name", "Javier",
"surname", "Tirado")).getWorkflowdata().toPrettyString());
+ // execute it with other person name
+ logger.info(application.execute(process, Map.of("name", "Mark",
"surname", "Proctor")).getWorkflowdata().toPrettyString());
+ }
+ }
+
+ static Workflow getWorkflow() {
+ return workflow("ExpressionExample")
+ // concatenate name
+ .start(operation()
+ .action(call(expr("name", "\"My name is \"+.name")))
+ // you can add several sequential actions into an
operation
+ .action(log(WorkflowLogLevel.DEBUG, "\"Response
is\"+.response")))
+ // concatenate surname
+ .next(operation()
+ .action(call(expr("surname", ".response+\" and my
surname is \"+.surname")))
+ .outputFilter(".response"))
+ .end().build();
+ }
+}
diff --git
a/serverless-workflow-examples/sonata-workflow-fluent/src/main/java/org/kie/kogito/serverless/workflow/examples/ForEachJava.java
b/serverless-workflow-examples/sonata-workflow-fluent/src/main/java/org/kie/kogito/serverless/workflow/examples/ForEachJava.java
new file mode 100644
index 000000000..52c74e5cf
--- /dev/null
+++
b/serverless-workflow-examples/sonata-workflow-fluent/src/main/java/org/kie/kogito/serverless/workflow/examples/ForEachJava.java
@@ -0,0 +1,81 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.kie.kogito.serverless.workflow.examples;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Map;
+
+import org.kie.kogito.serverless.workflow.executor.StaticWorkflowApplication;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import io.serverlessworkflow.api.Workflow;
+
+import static org.kie.kogito.serverless.workflow.fluent.ActionBuilder.call;
+import static org.kie.kogito.serverless.workflow.fluent.FunctionBuilder.expr;
+import static org.kie.kogito.serverless.workflow.fluent.FunctionBuilder.java;
+import static org.kie.kogito.serverless.workflow.fluent.StateBuilder.forEach;
+import static org.kie.kogito.serverless.workflow.fluent.StateBuilder.operation;
+import static
org.kie.kogito.serverless.workflow.fluent.WorkflowBuilder.workflow;
+
+public class ForEachJava {
+
+ private static final Logger logger =
LoggerFactory.getLogger(ForEachJava.class);
+
+ public static void main(String[] args) {
+ try (StaticWorkflowApplication application =
StaticWorkflowApplication.create()) {
+ // execute the flow passing the list of names and the file name
+ logger.info(application.execute(getWorkflow(), Map.of("names",
Arrays.asList("Javi", "Mark", "Kris", "Alessandro"), "fileName",
"message.txt")).getWorkflowdata().toPrettyString());
+ }
+ }
+
+ static Workflow getWorkflow() {
+ // this flow illustrate the usage of foreach and how to use java to
perform task that are not part of sw spec.
+ // The flow accepts a list of names and suffix them with a message
read from a file
+ return workflow("ForEachExample")
+ // first load the message from the file and store it in
message property
+ .start(operation().action(call(java("getMessage",
ForEachJava::addAdvice), ".fileName")))
+ // then for each element in input names concatenate it with
that message
+
.next(forEach(".names").loopVar("name").outputCollection(".messages")
+ // jq expression that suffix each name with the
message retrieved from the file
+ .action(call(expr("concat", ".name+.adviceMessage")))
+ // only return messages list as result of the flow
+ .outputFilter("{messages}"))
+ .end().build();
+ }
+
+ // Java method invoked from workflow accepts one parameter, which might be
a Map or a primitive/wrapper type, depending on the args provided in the flow
+ // In this case, we are passing the name of a file in the classpath, so
the argument is a string
+ // Java method return type is always a Map<String,Object> (if not
output,it should return an empty map). In this case,
+ // we are adding an advice message to the flow model read from the file.
If the file cannot be read, we return empty map.
+ private static Map<String, Object> addAdvice(String fileName) {
+ try (InputStream is = ClassLoader.getSystemResourceAsStream(fileName))
{
+ if (is != null) {
+ return Collections.singletonMap("adviceMessage", new
String(is.readAllBytes()));
+ }
+ } catch (IOException io) {
+ logger.warn("Error reading file " + fileName + " from classpath",
io);
+ }
+ return Collections.emptyMap();
+ }
+
+}
diff --git
a/serverless-workflow-examples/sonata-workflow-fluent/src/main/java/org/kie/kogito/serverless/workflow/examples/HelloWorld.java
b/serverless-workflow-examples/sonata-workflow-fluent/src/main/java/org/kie/kogito/serverless/workflow/examples/HelloWorld.java
new file mode 100644
index 000000000..3d8648e93
--- /dev/null
+++
b/serverless-workflow-examples/sonata-workflow-fluent/src/main/java/org/kie/kogito/serverless/workflow/examples/HelloWorld.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.kie.kogito.serverless.workflow.examples;
+
+import java.util.Collections;
+
+import org.kie.kogito.serverless.workflow.executor.StaticWorkflowApplication;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import io.serverlessworkflow.api.Workflow;
+
+import static org.kie.kogito.serverless.workflow.fluent.StateBuilder.inject;
+import static
org.kie.kogito.serverless.workflow.fluent.WorkflowBuilder.jsonObject;
+import static
org.kie.kogito.serverless.workflow.fluent.WorkflowBuilder.workflow;
+
+public class HelloWorld {
+
+ private static final Logger logger =
LoggerFactory.getLogger(HelloWorld.class);
+
+ public static void main(String[] args) {
+ try (StaticWorkflowApplication application =
StaticWorkflowApplication.create()) {
+ logger.info("Workflow execution result is {}",
application.execute(getWorkflow(), Collections.emptyMap()).getWorkflowdata());
+ }
+ }
+
+ static Workflow getWorkflow() {
+ return workflow("HelloWorld").start(
+ inject(
+ jsonObject().put("greeting", "Hello
World").put("mantra", "Serverless Workflow is awesome!")))
+ .end()
+ .build();
+ }
+}
diff --git
a/serverless-workflow-examples/sonata-workflow-fluent/src/main/java/org/kie/kogito/serverless/workflow/examples/JQInterpolation.java
b/serverless-workflow-examples/sonata-workflow-fluent/src/main/java/org/kie/kogito/serverless/workflow/examples/JQInterpolation.java
new file mode 100644
index 000000000..b090d23d2
--- /dev/null
+++
b/serverless-workflow-examples/sonata-workflow-fluent/src/main/java/org/kie/kogito/serverless/workflow/examples/JQInterpolation.java
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.kie.kogito.serverless.workflow.examples;
+
+import java.io.IOException;
+
+import org.kie.kogito.jackson.utils.ObjectMapperFactory;
+import org.kie.kogito.serverless.workflow.executor.StaticWorkflowApplication;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import io.serverlessworkflow.api.Workflow;
+
+import static org.kie.kogito.serverless.workflow.fluent.ActionBuilder.call;
+import static org.kie.kogito.serverless.workflow.fluent.FunctionBuilder.expr;
+import static org.kie.kogito.serverless.workflow.fluent.StateBuilder.operation;
+import static
org.kie.kogito.serverless.workflow.fluent.WorkflowBuilder.workflow;
+
+public class JQInterpolation {
+
+ private static final Logger logger =
LoggerFactory.getLogger(JQInterpolation.class);
+
+ public static void main(String[] args) throws IOException {
+ try (StaticWorkflowApplication application =
StaticWorkflowApplication.create()) {
+ logger.info(application.execute(getWorkflow(),
ObjectMapperFactory.get().createObjectNode().put("name",
"Javierito").put("language", "Spanish")).getWorkflowdata().toPrettyString());
+
+ }
+ }
+
+ static Workflow getWorkflow() {
+ final String INTERPOLATION = "interpolation";
+ return workflow("PlayingWithExpression").function(expr(INTERPOLATION,
"{greeting: \"My name is \\(.name). My language is \\(.language)\"}"))
+ .start(operation().action(call(INTERPOLATION))).end().build();
+ }
+}
diff --git
a/serverless-workflow-examples/sonata-workflow-fluent/src/main/java/org/kie/kogito/serverless/workflow/examples/ParallelRest.java
b/serverless-workflow-examples/sonata-workflow-fluent/src/main/java/org/kie/kogito/serverless/workflow/examples/ParallelRest.java
new file mode 100644
index 000000000..58a5d3871
--- /dev/null
+++
b/serverless-workflow-examples/sonata-workflow-fluent/src/main/java/org/kie/kogito/serverless/workflow/examples/ParallelRest.java
@@ -0,0 +1,102 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.kie.kogito.serverless.workflow.examples;
+
+import java.util.Map;
+
+import org.kie.kogito.process.Process;
+import org.kie.kogito.serverless.workflow.actions.WorkflowLogLevel;
+import org.kie.kogito.serverless.workflow.executor.StaticWorkflowApplication;
+import org.kie.kogito.serverless.workflow.fluent.FunctionBuilder.HttpMethod;
+import org.kie.kogito.serverless.workflow.models.JsonNodeModel;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+import io.serverlessworkflow.api.Workflow;
+
+import static org.kie.kogito.serverless.workflow.fluent.ActionBuilder.call;
+import static org.kie.kogito.serverless.workflow.fluent.ActionBuilder.log;
+import static
org.kie.kogito.serverless.workflow.fluent.ActionBuilder.subprocess;
+import static org.kie.kogito.serverless.workflow.fluent.FunctionBuilder.rest;
+import static org.kie.kogito.serverless.workflow.fluent.StateBuilder.operation;
+import static org.kie.kogito.serverless.workflow.fluent.StateBuilder.parallel;
+import static
org.kie.kogito.serverless.workflow.fluent.WorkflowBuilder.jsonObject;
+import static
org.kie.kogito.serverless.workflow.fluent.WorkflowBuilder.workflow;
+
+public class ParallelRest {
+
+ private static final Logger logger =
LoggerFactory.getLogger(ParallelRest.class);
+
+ public static void main(String[] args) {
+ try (StaticWorkflowApplication application =
StaticWorkflowApplication.create()) {
+ // create a reusable process for several executions
+ Process<JsonNodeModel> process =
application.process(getWorkflow(application));
+ // execute it with one person name
+ logger.info(application.execute(process, Map.of("name",
"Javier")).getWorkflowdata().toPrettyString());
+ // execute it with another person name
+ logger.info(application.execute(process, Map.of("name",
"Alba")).getWorkflowdata().toPrettyString());
+ }
+ }
+
+ static Workflow getWorkflow(StaticWorkflowApplication application) {
+ ObjectNode nameArgs = jsonObject().put("name", ".name");
+
+ // Define a subflow process that retrieve country information from the
given name
+ Workflow subflow = workflow("GetCountry")
+ // subflow consist of just one state with two sequential
actions
+ .start(operation()
+ // call rest function to retrieve country id
+ .action(call(rest("getCountryId", HttpMethod.get,
"https://api.nationalize.io:/?name={name}"), nameArgs)
+ // extract relevant information from the
response using JQ expression
+
.resultFilter(".country[0].country_id").outputFilter(".id"))
+ // call rest function to retrieve country information
from country id
+ .action(call(rest("getCountryInfo", HttpMethod.get,
"https://restcountries.com/v3.1/alpha/{id}"), jsonObject().put("id", ".id"))
+ // we are only interested in country name,
longitude and latitude
+ .resultFilter("{country:
{name:.[].name.common, latitude: .[].latlng[0], longitude: .[].latlng[1] }}"))
+ // return only country field to parent flow
+ .outputFilter("{country}"))
+ .end().build();
+
+ Process<JsonNodeModel> subprocess = application.process(subflow);
+ // This is the main flow, it invokes two services (one for retrieving
the age and another to get the gender of the given name )and one subprocess
(the country one defined above) in parallel
+ // Once the three of them has been executed, if age is greater than
50, it retrieve the weather information for the retrieved country,
+ // Else, it gets the list of universities for that country.
+ return workflow("FullExample")
+ // Api key to be used in getting weather call
+ .constant("apiKey", "2482c1d33308a7cffedff5764e9ef203")
+ // Starts performing retrieval of gender, country and age from
the given name on parallel
+ .start(parallel()
+ .newBranch().action(call(rest("getAge",
HttpMethod.get, "https://api.agify.io/?name={name}"),
nameArgs).resultFilter("{age}")).endBranch()
+ .newBranch().action(subprocess(subprocess)).endBranch()
+ .newBranch().action(call(rest("getGender",
HttpMethod.get, "https://api.genderize.io/?name={name}"),
nameArgs).resultFilter("{gender}")).endBranch())
+ // once done, logs the age (using Jq string interpolation)
+ .next(operation().action(log(WorkflowLogLevel.INFO, "\"Age is
\\(.age)\"")))
+ // If age is less that fifty, retrieve the list of
universities (the parameters object is built using jq expressions)
+
.when(".age<50").next(operation().action(call(rest("getUniversities",
HttpMethod.get, "http://universities.hipolabs.com/search?country={country}"),
+ jsonObject().put("country",
".country.name")).resultFilter(".[].name").outputFilter(".universities")))
+ // Else retrieve the weather for that country capital latitude
and longitude (note how parameters are build from model info)
+ .end().or()
+ .next(operation().action(call(rest("getWeather",
HttpMethod.get,
"https://api.openweathermap.org/data/2.5/weather?lat={lat}&lon={lon}&appid={appid}"),
+ jsonObject().put("lat",
".country.latitude").put("lon", ".country.longitude").put("appid",
"$CONST.apiKey"))
+ .resultFilter("{weather:.main}")))
+ .end().build();
+ }
+}
diff --git
a/serverless-workflow-examples/sonata-workflow-fluent/src/main/resources/division.sw.json
b/serverless-workflow-examples/sonata-workflow-fluent/src/main/resources/division.sw.json
new file mode 100644
index 000000000..73b996035
--- /dev/null
+++
b/serverless-workflow-examples/sonata-workflow-fluent/src/main/resources/division.sw.json
@@ -0,0 +1,26 @@
+{
+ "id": "division",
+ "version": "1.0",
+ "name": "division",
+ "start": "divide",
+ "functions": [
+ {
+ "name": "divide",
+ "type": "expression",
+ "operation": ".numerator / .denominator"
+ }
+ ],
+ "states": [
+ {
+ "name": "divide",
+ "type": "operation",
+ "actions": [
+ {
+ "name": "divide",
+ "functionRef": "divide"
+ }
+ ],
+ "end": true
+ }
+ ]
+}
diff --git
a/serverless-workflow-examples/sonata-workflow-fluent/src/main/resources/expression.sw.json
b/serverless-workflow-examples/sonata-workflow-fluent/src/main/resources/expression.sw.json
new file mode 100644
index 000000000..dcf80ae8c
--- /dev/null
+++
b/serverless-workflow-examples/sonata-workflow-fluent/src/main/resources/expression.sw.json
@@ -0,0 +1,73 @@
+{
+ "id": "expression",
+ "version": "1.0",
+ "name": "Workflow Expression example",
+ "constants" : {
+ "Dog" : {
+ "castellano" : "perro",
+ "leones": "perru",
+ "gallego" : "can",
+ "aragones" : "cocho",
+ "catalan" : "gos",
+ "vasco": "txakurra"
+ }
+ },
+ "dataInputSchema" : "schema/expression.json",
+ "description": "An example of how to use a JQ expression assignment",
+ "start": "squareState",
+ "extensions" : [ {
+ "extensionid": "workflow-output-schema",
+ "outputSchema": "schema/result.json"
+ }
+ ],
+ "functions": [
+ {
+ "name": "max",
+ "type": "expression",
+ "operation": "{max: .numbers | max_by(.x), min: .numbers | min_by(.y)}"
+ },
+ {
+ "name": "printMessage",
+ "type": "custom",
+ "operation": "sysout"
+ }
+ ],
+ "states": [
+ {
+ "name": "squareState",
+ "type": "operation",
+ "actions": [
+ {
+ "name": "maxAction",
+ "functionRef": {
+ "refName": "max"
+ },
+ "actionDataFilter": {
+ "results" : ".max.x",
+ "toStateData" : ".number"
+ }
+ }
+ ],
+ "transition": "finish"
+ },
+ {
+ "name": "finish",
+ "type": "operation",
+ "stateDataFilter": {
+ "input": "{result: .number}"
+ },
+ "actions": [
+ {
+ "name": "printAction",
+ "functionRef": {
+ "refName": "printMessage",
+ "arguments": {
+ "message": ".result"
+ }
+ }
+ }
+ ],
+ "end": true
+ }
+ ]
+}
diff --git
a/serverless-workflow-examples/sonata-workflow-fluent/src/main/resources/message.txt
b/serverless-workflow-examples/sonata-workflow-fluent/src/main/resources/message.txt
new file mode 100644
index 000000000..01b797e5b
--- /dev/null
+++
b/serverless-workflow-examples/sonata-workflow-fluent/src/main/resources/message.txt
@@ -0,0 +1 @@
+ , congratulations, you are a happy user of serverless workflow
\ No newline at end of file
diff --git
a/serverless-workflow-examples/sonata-workflow-fluent/src/main/resources/schema/complex.json
b/serverless-workflow-examples/sonata-workflow-fluent/src/main/resources/schema/complex.json
new file mode 100644
index 000000000..7a4e0728f
--- /dev/null
+++
b/serverless-workflow-examples/sonata-workflow-fluent/src/main/resources/schema/complex.json
@@ -0,0 +1,12 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "title": "Complex",
+ "description": "Complex number",
+ "type": "object",
+ "properties": {
+ "x" : {"type":"number"},
+ "y" : {"type":"number"}
+
+ },
+ "required": ["x","y"]
+}
\ No newline at end of file
diff --git
a/serverless-workflow-examples/sonata-workflow-fluent/src/main/resources/schema/expression.json
b/serverless-workflow-examples/sonata-workflow-fluent/src/main/resources/schema/expression.json
new file mode 100644
index 000000000..3633e4e54
--- /dev/null
+++
b/serverless-workflow-examples/sonata-workflow-fluent/src/main/resources/schema/expression.json
@@ -0,0 +1,15 @@
+{
+ "$id": "classpath:/schema/expression.json",
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "title": "Expression",
+ "description": "Schema for expression test",
+ "type": "object",
+ "properties": {
+ "numbers": {
+ "description": "The array of numbers to be operated with",
+ "type": "array",
+ "items": {"$ref" : "complex.json"}
+ }
+ },
+ "required": ["numbers"]
+}
\ No newline at end of file
diff --git
a/serverless-workflow-examples/sonata-workflow-fluent/src/main/resources/schema/result.json
b/serverless-workflow-examples/sonata-workflow-fluent/src/main/resources/schema/result.json
new file mode 100644
index 000000000..c5a55d1d5
--- /dev/null
+++
b/serverless-workflow-examples/sonata-workflow-fluent/src/main/resources/schema/result.json
@@ -0,0 +1,13 @@
+{
+ "$schema": "http://json-schema.org/draft-04/schema#",
+ "title": "Expression Output",
+ "description": "Output schema for expression example",
+ "type": "object",
+ "properties": {
+ "result": {
+ "type" : "number",
+ "description": "Maximum value on x"
+ }
+ },
+ "required": ["result"]
+}
\ No newline at end of file
diff --git
a/serverless-workflow-examples/sonata-workflow-fluent/src/test/java/org/kie/kogito/serverless/workflow/examples/WorkflowFluentExamplesTest.java
b/serverless-workflow-examples/sonata-workflow-fluent/src/test/java/org/kie/kogito/serverless/workflow/examples/WorkflowFluentExamplesTest.java
new file mode 100644
index 000000000..11fe8b473
--- /dev/null
+++
b/serverless-workflow-examples/sonata-workflow-fluent/src/test/java/org/kie/kogito/serverless/workflow/examples/WorkflowFluentExamplesTest.java
@@ -0,0 +1,100 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.kie.kogito.serverless.workflow.examples;
+
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Map;
+
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.kie.kogito.serverless.workflow.executor.StaticWorkflowApplication;
+import org.kie.kogito.serverless.workflow.utils.ServerlessWorkflowUtils;
+import org.kie.kogito.serverless.workflow.utils.WorkflowFormat;
+
+import com.fasterxml.jackson.databind.node.IntNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.fasterxml.jackson.databind.node.TextNode;
+
+import io.serverlessworkflow.api.Workflow;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static
org.kie.kogito.serverless.workflow.fluent.WorkflowBuilder.jsonObject;
+
+public class WorkflowFluentExamplesTest {
+
+ private static StaticWorkflowApplication application;
+
+ @BeforeAll
+ static void init() {
+ application = StaticWorkflowApplication.create();
+ }
+
+ @AfterAll
+ static void cleanUp() {
+ application.close();
+ }
+
+ @Test
+ void testHelloWorldDefinition() {
+ ObjectNode expected = jsonObject().put("greeting", "Hello
World").put("mantra", "Serverless Workflow is awesome!");
+ assertThat(application.execute(HelloWorld.getWorkflow(),
Collections.emptyMap()).getWorkflowdata()).isEqualTo(expected);
+ }
+
+ @Test
+ void testForEachJavaDefinition() {
+ assertThat(application.execute(ForEachJava.getWorkflow(),
Map.of("names", Arrays.asList("Javi", "Mark"), "fileName",
"message.txt")).getWorkflowdata().get("messages"))
+ .containsExactly(new TextNode("Javi , congratulations, you are
a happy user of serverless workflow"),
+ new TextNode("Mark , congratulations, you are a happy
user of serverless workflow"));
+ }
+
+ @Test
+ void testJQInterpolation() {
+ assertThat(application.execute(JQInterpolation.getWorkflow(),
Map.of("name", "Javierito", "language",
"Spanish")).getWorkflowdata().get("greeting"))
+ .isEqualTo(new TextNode("My name is Javierito. My language is
Spanish"));
+ }
+
+ @Test
+ void testConcatenationDefinition() {
+ assertThat(application.execute(Concatenation.getWorkflow(),
Map.of("name", "Javier", "surname", "Tirado")).getWorkflowdata())
+ .isEqualTo(new TextNode("My name is Javier and my surname is
Tirado"));
+ }
+
+ @Test
+ void testDivisionDefinition() throws IOException {
+ assertThat(application.execute(
+ getWorkflow("division.sw.json"), Map.of("numerator", 4,
"denominator", 2)).getWorkflowdata().get("response")).isEqualTo(new IntNode(2));
+ }
+
+ @Test
+ void testExpressionDefinition() throws IOException {
+ assertThat(application.execute(
+ getWorkflow("expression.sw.json"), Map.of("numbers",
Arrays.asList(Map.of("x", 3, "y", 4), Map.of("x", 5, "y",
7)))).getWorkflowdata().get("result")).isEqualTo(new IntNode(5));
+ }
+
+ private Workflow getWorkflow(String filename) throws IOException {
+ try (Reader in = new
InputStreamReader(ClassLoader.getSystemResourceAsStream(filename))) {
+ return ServerlessWorkflowUtils.getWorkflow(in,
WorkflowFormat.JSON);
+ }
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]