From a61e5c5f59d5a3dfb7d14cd7d8f47116f924d6c4 Mon Sep 17 00:00:00 2001 From: Maciej Swiderski Date: Sat, 10 Aug 2024 14:51:57 +0200 Subject: [PATCH] small adjustements for workflow dsl to allow to pass data object init expressions as lambda, otherwise for split as default path, errorOn as exception class --- .../workflow/builder/ServiceNodeBuilder.java | 14 ++ .../workflow/builder/SplitNodeBuilder.java | 13 ++ .../workflow/builder/WorkflowBuilder.java | 121 +++++++++++++++++- 3 files changed, 147 insertions(+), 1 deletion(-) diff --git a/workflow/automatiko-workflow-core/src/main/java/io/automatiko/engine/workflow/builder/ServiceNodeBuilder.java b/workflow/automatiko-workflow-core/src/main/java/io/automatiko/engine/workflow/builder/ServiceNodeBuilder.java index 01523e378..12cd57a3a 100644 --- a/workflow/automatiko-workflow-core/src/main/java/io/automatiko/engine/workflow/builder/ServiceNodeBuilder.java +++ b/workflow/automatiko-workflow-core/src/main/java/io/automatiko/engine/workflow/builder/ServiceNodeBuilder.java @@ -298,6 +298,20 @@ public ErrorNodeBuilder onError(String... errorCodes) { .errorCodes(errorCodes); } + /** + * Adds error handling node that allows to move to different path in case of an error + * + * @param errorCodes list of codes to listen on + * @return the builder + */ + @SuppressWarnings("unchecked") + public ErrorNodeBuilder onError(Class... exceptions) { + workflowBuilder.putOnContext(getNode()); + workflowBuilder.putBuilderOnContext(null); + return new ErrorNodeBuilder("error on " + node.getName(), (String) this.node.getMetaData("UniqueId"), workflowBuilder) + .errorCodes(Stream.of(exceptions).map(c -> c.getName()).toArray(String[]::new)); + } + /** * Configures the maximum amount of time the node will wait to get response from the service. * In case it is not successfully within that time it will abort the operation and throw error with 408 error diff --git a/workflow/automatiko-workflow-core/src/main/java/io/automatiko/engine/workflow/builder/SplitNodeBuilder.java b/workflow/automatiko-workflow-core/src/main/java/io/automatiko/engine/workflow/builder/SplitNodeBuilder.java index 019a70fef..4d17b5c0f 100644 --- a/workflow/automatiko-workflow-core/src/main/java/io/automatiko/engine/workflow/builder/SplitNodeBuilder.java +++ b/workflow/automatiko-workflow-core/src/main/java/io/automatiko/engine/workflow/builder/SplitNodeBuilder.java @@ -47,6 +47,19 @@ public WorkflowBuilder when(String expression) { return workflowBuilder; } + public WorkflowBuilder otherwise() { + workflowBuilder.putOnContext(getNode()); + workflowBuilder.putBuilderOnContext(this); + + this.returnValueConstraint = new ReturnValueConstraintEvaluator(); + returnValueConstraint.setDialect("java"); + returnValueConstraint.setName(""); + returnValueConstraint.setPriority(1); + returnValueConstraint.setDefault(true); + + return workflowBuilder; + } + @Override protected void apply(Connection connection) { node.setConstraint(connection, returnValueConstraint); diff --git a/workflow/automatiko-workflow-core/src/main/java/io/automatiko/engine/workflow/builder/WorkflowBuilder.java b/workflow/automatiko-workflow-core/src/main/java/io/automatiko/engine/workflow/builder/WorkflowBuilder.java index f8f701f3f..e363941af 100644 --- a/workflow/automatiko-workflow-core/src/main/java/io/automatiko/engine/workflow/builder/WorkflowBuilder.java +++ b/workflow/automatiko-workflow-core/src/main/java/io/automatiko/engine/workflow/builder/WorkflowBuilder.java @@ -8,6 +8,7 @@ import java.util.Map; import java.util.Objects; import java.util.concurrent.atomic.AtomicLong; +import java.util.function.Supplier; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -298,6 +299,75 @@ public WorkflowBuilder listDataObject(String name, Class type, String... tags return this; } + /** + * Adds list data object to the workflow definition and returns it so it can be used in expressions + * + * @param name name of the data object + * @param valueExpression expression to initialize the data object with + * @param type type of the list elements + * @param tags optional tags + * @return the builder + */ + public WorkflowBuilder listDataObject(String name, Supplier valueExpression, Class type, String... tags) { + Variable variable = new Variable(); + variable.setId(name); + variable.setName(name); + variable.setType(new ObjectDataType(List.class, List.class.getCanonicalName() + "<" + type.getCanonicalName() + ">")); + variable.setMetaData("type", type.getCanonicalName()); + + if (tags != null && tags.length > 0) { + String variableTags = Stream.of(tags).collect(Collectors.joining(",")); + variable.setMetaData("tags", variableTags); + + if (variableTags.contains(Variable.BUSINESS_RELEVANT_TAG)) { + this.tags("#{" + name + "}"); + } + } + if (valueExpression != null) { + variable.setMetaData(Variable.DEFAULT_VALUE, + "#{" + BuilderContext.get(Thread.currentThread().getStackTrace()[2].getMethodName()) + "}"); + } + process.getVariableScope().getVariables().add(variable); + return this; + } + + /** + * Adds list data object to the workflow definition and returns it so it can be used in expressions + * + * @param name name of the data object + * @param valueExpression expression to initialize the data object with + * @param type type of the list elements + * @param tags optional tags + * @return the builder + */ + public WorkflowBuilder listDataObject(String name, String valueExpression, Class type, String... tags) { + Variable variable = new Variable(); + variable.setId(name); + variable.setName(name); + variable.setType(new ObjectDataType(List.class, List.class.getCanonicalName() + "<" + type.getCanonicalName() + ">")); + variable.setMetaData("type", type.getCanonicalName()); + + if (tags != null && tags.length > 0) { + String variableTags = Stream.of(tags).collect(Collectors.joining(",")); + variable.setMetaData("tags", variableTags); + + if (variableTags.contains(Variable.BUSINESS_RELEVANT_TAG)) { + this.tags("#{" + name + "}"); + } + } + if (valueExpression != null) { + variable.setMetaData("value", + "#{" + valueExpression + "}"); + } + process.getVariableScope().getVariables().add(variable); + return this; + } + + public List listDataObject(Class type, String name, Supplier valueExpression, String... tags) { + listDataObject(name, valueExpression, type, tags); + return null; + } + /** * Adds parameterized data object to the workflow definition and returns it so it can be used in expressions * @@ -373,6 +443,7 @@ public WorkflowBuilder dataObject(String name, Class type, String... tags) { * Adds data object to the workflow definition * * @param name name of the data object that can be later on referenced by + * @param valueExpression expression to initialize the data object with * @param type type of the data object * @param tags optional (non null tags) to be assigned to the data object e.g. output, input, required, etc * @return the builder @@ -393,13 +464,61 @@ public WorkflowBuilder dataObject(String name, String valueExpression, Class } if (valueExpression != null) { - variable.setMetaData("value", "#{" + valueExpression + "}"); + variable.setMetaData(Variable.DEFAULT_VALUE, "#{" + valueExpression + "}"); + } + + process.getVariableScope().getVariables().add(variable); + return this; + } + + /** + * Adds data object to the workflow definition + * + * @param name name of the data object that can be later on referenced by + * @param valueExpression expression to initialize the data object with + * @param type type of the data object + * @param tags optional (non null tags) to be assigned to the data object e.g. output, input, required, etc + * @return the builder + */ + public WorkflowBuilder dataObject(String name, Supplier valueExpression, Class type, String... tags) { + Variable variable = new Variable(); + variable.setId(name); + variable.setName(name); + variable.setType(new ObjectDataType(type)); + + if (tags != null && tags.length > 0) { + String variableTags = Stream.of(tags).collect(Collectors.joining(",")); + variable.setMetaData("tags", variableTags); + + if (variableTags.contains(Variable.BUSINESS_RELEVANT_TAG)) { + this.tags("#{" + name + "}"); + } + } + + if (valueExpression != null) { + variable.setMetaData(Variable.DEFAULT_VALUE, + "#{" + BuilderContext.get(Thread.currentThread().getStackTrace()[2].getMethodName()) + "}"); } process.getVariableScope().getVariables().add(variable); return this; } + /** + * Adds parameterized data object to the workflow definition and returns it so it can be used in expressions + * + * @param data type + * @param type type of the data objects + * @param name name of the data object + * @param valueExpression expression to initialize the data object with + * @param tags optional tags + * @return return null as it only records the definition + */ + public T dataObject(Class type, String name, Supplier valueExpression, String... tags) { + dataObject(name, valueExpression, type, tags); + return null; + } + /** * Adds a starting node *