Skip to content

Commit

Permalink
[KOGITO-9454] Adding Java embedded flows to examples (#1895)
Browse files Browse the repository at this point in the history
* [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 <1538000+ricardozanini@users.noreply.github.com>

* Update serverless-workflow-examples/sonata-workflow-fluent/pom.xml

Co-authored-by: Ricardo Zanini <1538000+ricardozanini@users.noreply.github.com>

---------

Co-authored-by: Ricardo Zanini <1538000+ricardozanini@users.noreply.github.com>
  • Loading branch information
fjtirado and ricardozanini committed Mar 18, 2024
1 parent 9f7cf81 commit eeb187b
Show file tree
Hide file tree
Showing 15 changed files with 657 additions and 0 deletions.
1 change: 1 addition & 0 deletions serverless-workflow-examples/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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>

Expand Down
16 changes: 16 additions & 0 deletions serverless-workflow-examples/sonata-workflow-fluent/README.md
Original file line number Diff line number Diff line change
@@ -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!

49 changes: 49 additions & 0 deletions serverless-workflow-examples/sonata-workflow-fluent/pom.xml
Original file line number Diff line number Diff line change
@@ -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>
Original file line number Diff line number Diff line change
@@ -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();
}
}
Original file line number Diff line number Diff line change
@@ -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();
}

}
Original file line number Diff line number Diff line change
@@ -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();
}
}
Original file line number Diff line number Diff line change
@@ -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();
}
}

0 comments on commit eeb187b

Please sign in to comment.