diff --git a/experimental/lambda/src/test/java/io/serverless/workflow/impl/FluentDSLCallTest.java b/experimental/lambda/src/test/java/io/serverless/workflow/impl/FluentDSLCallTest.java index 9706be4f..dcad95d8 100644 --- a/experimental/lambda/src/test/java/io/serverless/workflow/impl/FluentDSLCallTest.java +++ b/experimental/lambda/src/test/java/io/serverless/workflow/impl/FluentDSLCallTest.java @@ -34,7 +34,7 @@ void testJavaFunction() throws InterruptedException, ExecutionException { try (WorkflowApplication app = WorkflowApplication.builder().build()) { final Workflow workflow = FuncWorkflowBuilder.workflow("testJavaCall") - .tasks(tasks -> tasks.callFn(f -> f.fn(JavaFunctions::getName))) + .tasks(tasks -> tasks.callFn(f -> f.function(JavaFunctions::getName))) .build(); assertThat( app.workflowDefinition(workflow) @@ -85,7 +85,7 @@ void testSwitch() throws InterruptedException, ExecutionException { switchOdd.items( item -> item.when(CallTest::isOdd).then(FlowDirectiveEnum.END))) - .callFn(callJava -> callJava.fn(CallTest::zero))) + .callFn(callJava -> callJava.function(CallTest::zero))) .build(); WorkflowDefinition definition = app.workflowDefinition(workflow); diff --git a/fluent/func/src/main/java/io/serverlessworkflow/fluent/func/DelegatingFuncDoTaskFluent.java b/fluent/func/src/main/java/io/serverlessworkflow/fluent/func/DelegatingFuncDoTaskFluent.java new file mode 100644 index 00000000..131330fa --- /dev/null +++ b/fluent/func/src/main/java/io/serverlessworkflow/fluent/func/DelegatingFuncDoTaskFluent.java @@ -0,0 +1,86 @@ +/* + * Copyright 2020-Present The Serverless Workflow Specification Authors + * + * 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 io.serverlessworkflow.fluent.func; + +import io.serverlessworkflow.fluent.spec.HasDelegate; +import java.util.function.Consumer; + +/** + * Mixin that implements {@link FuncDoTaskFluent} by forwarding to another instance. + * + * @param concrete builder type + */ +public interface DelegatingFuncDoTaskFluent> + extends FuncDoTaskFluent, HasDelegate { + + @SuppressWarnings("unchecked") + default SELF self() { + return (SELF) this; + } + + @SuppressWarnings("unchecked") + private FuncDoTaskFluent d() { + return (FuncDoTaskFluent) this.delegate(); + } + + @Override + default SELF callFn(String name, Consumer cfg) { + d().callFn(name, cfg); + return self(); + } + + @Override + default SELF callFn(Consumer cfg) { + d().callFn(cfg); + return self(); + } + + @Override + default SELF forFn(String name, Consumer cfg) { + d().forFn(name, cfg); + return self(); + } + + @Override + default SELF forFn(Consumer cfg) { + d().forFn(cfg); + return self(); + } + + @Override + default SELF switchFn(String name, Consumer cfg) { + d().switchFn(name, cfg); + return self(); + } + + @Override + default SELF switchFn(Consumer cfg) { + d().switchFn(cfg); + return self(); + } + + @Override + default SELF forkFn(String name, Consumer cfg) { + d().forkFn(name, cfg); + return self(); + } + + @Override + default SELF forkFn(Consumer cfg) { + d().forkFn(cfg); + return self(); + } +} diff --git a/fluent/func/src/main/java/io/serverlessworkflow/fluent/func/FuncCallTaskBuilder.java b/fluent/func/src/main/java/io/serverlessworkflow/fluent/func/FuncCallTaskBuilder.java index a8bcf08b..6c4c524d 100644 --- a/fluent/func/src/main/java/io/serverlessworkflow/fluent/func/FuncCallTaskBuilder.java +++ b/fluent/func/src/main/java/io/serverlessworkflow/fluent/func/FuncCallTaskBuilder.java @@ -35,7 +35,7 @@ protected FuncCallTaskBuilder self() { return this; } - public FuncCallTaskBuilder fn(Function function) { + public FuncCallTaskBuilder function(Function function) { this.callTaskJava = new CallTaskJava(CallJava.function(function)); super.setTask(this.callTaskJava.getCallJava()); return this; diff --git a/fluent/func/src/main/java/io/serverlessworkflow/fluent/func/FuncDoTaskBuilder.java b/fluent/func/src/main/java/io/serverlessworkflow/fluent/func/FuncDoTaskBuilder.java index ec721c1e..deefa099 100644 --- a/fluent/func/src/main/java/io/serverlessworkflow/fluent/func/FuncDoTaskBuilder.java +++ b/fluent/func/src/main/java/io/serverlessworkflow/fluent/func/FuncDoTaskBuilder.java @@ -16,47 +16,17 @@ package io.serverlessworkflow.fluent.func; import io.serverlessworkflow.fluent.spec.BaseDoTaskBuilder; -import java.util.function.Consumer; public class FuncDoTaskBuilder extends BaseDoTaskBuilder - implements FuncTransformations { + implements FuncTransformations, + DelegatingFuncDoTaskFluent { - FuncDoTaskBuilder() { + public FuncDoTaskBuilder() { super(new FuncTaskItemListBuilder()); } @Override - protected FuncDoTaskBuilder self() { - return this; - } - - public FuncDoTaskBuilder callFn(String name, Consumer consumer) { - this.innerListBuilder().callJava(name, consumer); - return this; - } - - public FuncDoTaskBuilder callFn(Consumer consumer) { - this.innerListBuilder().callJava(consumer); - return this; - } - - public FuncDoTaskBuilder forFn(String name, Consumer consumer) { - this.innerListBuilder().forFn(name, consumer); - return this; - } - - public FuncDoTaskBuilder forFn(Consumer consumer) { - this.innerListBuilder().forFn(consumer); - return this; - } - - public FuncDoTaskBuilder switchFn(String name, Consumer consumer) { - this.innerListBuilder().switchFn(name, consumer); - return this; - } - - public FuncDoTaskBuilder switchFn(Consumer consumer) { - this.innerListBuilder().switchFn(consumer); + public FuncDoTaskBuilder self() { return this; } } diff --git a/fluent/func/src/main/java/io/serverlessworkflow/fluent/func/FuncDoTaskFluent.java b/fluent/func/src/main/java/io/serverlessworkflow/fluent/func/FuncDoTaskFluent.java new file mode 100644 index 00000000..9ec0cb39 --- /dev/null +++ b/fluent/func/src/main/java/io/serverlessworkflow/fluent/func/FuncDoTaskFluent.java @@ -0,0 +1,37 @@ +/* + * Copyright 2020-Present The Serverless Workflow Specification Authors + * + * 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 io.serverlessworkflow.fluent.func; + +import java.util.function.Consumer; + +public interface FuncDoTaskFluent> { + + SELF callFn(String name, Consumer cfg); + + SELF callFn(Consumer cfg); + + SELF forFn(String name, Consumer cfg); + + SELF forFn(Consumer cfg); + + SELF switchFn(String name, Consumer cfg); + + SELF switchFn(Consumer cfg); + + SELF forkFn(String name, Consumer cfg); + + SELF forkFn(Consumer cfg); +} diff --git a/fluent/func/src/main/java/io/serverlessworkflow/fluent/func/FuncForkTaskBuilder.java b/fluent/func/src/main/java/io/serverlessworkflow/fluent/func/FuncForkTaskBuilder.java new file mode 100644 index 00000000..7df66fab --- /dev/null +++ b/fluent/func/src/main/java/io/serverlessworkflow/fluent/func/FuncForkTaskBuilder.java @@ -0,0 +1,74 @@ +/* + * Copyright 2020-Present The Serverless Workflow Specification Authors + * + * 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 io.serverlessworkflow.fluent.func; + +import io.serverlessworkflow.api.types.ForkTask; +import io.serverlessworkflow.api.types.ForkTaskConfiguration; +import io.serverlessworkflow.api.types.Task; +import io.serverlessworkflow.api.types.TaskItem; +import io.serverlessworkflow.api.types.func.CallJava; +import io.serverlessworkflow.api.types.func.CallTaskJava; +import io.serverlessworkflow.fluent.spec.TaskBaseBuilder; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import java.util.function.Consumer; +import java.util.function.Function; + +public class FuncForkTaskBuilder extends TaskBaseBuilder + implements FuncTransformations { + + private final ForkTask forkTask; + private final List items; + + FuncForkTaskBuilder() { + this.forkTask = new ForkTask(); + this.forkTask.setFork(new ForkTaskConfiguration()); + this.items = new ArrayList<>(); + } + + @Override + protected FuncForkTaskBuilder self() { + return this; + } + + public FuncForkTaskBuilder branch(String name, Function function) { + this.items.add( + new TaskItem(name, new Task().withCallTask(new CallTaskJava(CallJava.function(function))))); + return this; + } + + public FuncForkTaskBuilder branch(Function function) { + return this.branch(UUID.randomUUID().toString(), function); + } + + public FuncForkTaskBuilder branches(Consumer consumer) { + final FuncTaskItemListBuilder builder = new FuncTaskItemListBuilder(); + consumer.accept(builder); + this.items.addAll(builder.build()); + return this; + } + + public FuncForkTaskBuilder compete(boolean compete) { + this.forkTask.getFork().setCompete(compete); + return this; + } + + public ForkTask build() { + this.forkTask.getFork().setBranches(this.items); + return forkTask; + } +} diff --git a/fluent/func/src/main/java/io/serverlessworkflow/fluent/func/FuncTaskItemListBuilder.java b/fluent/func/src/main/java/io/serverlessworkflow/fluent/func/FuncTaskItemListBuilder.java index e11063da..13ce0c29 100644 --- a/fluent/func/src/main/java/io/serverlessworkflow/fluent/func/FuncTaskItemListBuilder.java +++ b/fluent/func/src/main/java/io/serverlessworkflow/fluent/func/FuncTaskItemListBuilder.java @@ -18,15 +18,21 @@ import io.serverlessworkflow.api.types.Task; import io.serverlessworkflow.api.types.TaskItem; import io.serverlessworkflow.fluent.spec.BaseTaskItemListBuilder; +import java.util.List; import java.util.UUID; import java.util.function.Consumer; -public class FuncTaskItemListBuilder extends BaseTaskItemListBuilder { +public class FuncTaskItemListBuilder extends BaseTaskItemListBuilder + implements FuncDoTaskFluent { - FuncTaskItemListBuilder() { + public FuncTaskItemListBuilder() { super(); } + public FuncTaskItemListBuilder(final List list) { + super(list); + } + @Override protected FuncTaskItemListBuilder self() { return this; @@ -37,17 +43,20 @@ protected FuncTaskItemListBuilder newItemListBuilder() { return new FuncTaskItemListBuilder(); } - public FuncTaskItemListBuilder callJava(String name, Consumer consumer) { + @Override + public FuncTaskItemListBuilder callFn(String name, Consumer consumer) { this.requireNameAndConfig(name, consumer); final FuncCallTaskBuilder callTaskJavaBuilder = new FuncCallTaskBuilder(); consumer.accept(callTaskJavaBuilder); return addTaskItem(new TaskItem(name, new Task().withCallTask(callTaskJavaBuilder.build()))); } - public FuncTaskItemListBuilder callJava(Consumer consumer) { - return this.callJava(UUID.randomUUID().toString(), consumer); + @Override + public FuncTaskItemListBuilder callFn(Consumer consumer) { + return this.callFn(UUID.randomUUID().toString(), consumer); } + @Override public FuncTaskItemListBuilder forFn(String name, Consumer consumer) { this.requireNameAndConfig(name, consumer); final FuncForTaskBuilder forTaskJavaBuilder = new FuncForTaskBuilder(); @@ -55,10 +64,12 @@ public FuncTaskItemListBuilder forFn(String name, Consumer c return this.addTaskItem(new TaskItem(name, new Task().withForTask(forTaskJavaBuilder.build()))); } + @Override public FuncTaskItemListBuilder forFn(Consumer consumer) { return this.forFn(UUID.randomUUID().toString(), consumer); } + @Override public FuncTaskItemListBuilder switchFn(String name, Consumer consumer) { this.requireNameAndConfig(name, consumer); final FuncSwitchTaskBuilder funcSwitchTaskBuilder = new FuncSwitchTaskBuilder(); @@ -67,7 +78,22 @@ public FuncTaskItemListBuilder switchFn(String name, Consumer consumer) { return this.switchFn(UUID.randomUUID().toString(), consumer); } + + @Override + public FuncTaskItemListBuilder forkFn(Consumer cfg) { + return this.forkFn(UUID.randomUUID().toString(), cfg); + } + + @Override + public FuncTaskItemListBuilder forkFn(String name, Consumer cfg) { + this.requireNameAndConfig(name, cfg); + final FuncForkTaskBuilder forkTaskJavaBuilder = new FuncForkTaskBuilder(); + cfg.accept(forkTaskJavaBuilder); + return this.addTaskItem( + new TaskItem(name, new Task().withForkTask(forkTaskJavaBuilder.build()))); + } } diff --git a/fluent/func/src/main/java/io/serverlessworkflow/fluent/func/FuncWorkflowBuilder.java b/fluent/func/src/main/java/io/serverlessworkflow/fluent/func/FuncWorkflowBuilder.java index aad21591..686b1773 100644 --- a/fluent/func/src/main/java/io/serverlessworkflow/fluent/func/FuncWorkflowBuilder.java +++ b/fluent/func/src/main/java/io/serverlessworkflow/fluent/func/FuncWorkflowBuilder.java @@ -22,7 +22,7 @@ public class FuncWorkflowBuilder extends BaseWorkflowBuilder implements FuncTransformations { - private FuncWorkflowBuilder(final String name, final String namespace, final String version) { + protected FuncWorkflowBuilder(final String name, final String namespace, final String version) { super(name, namespace, version); } diff --git a/fluent/func/src/test/java/io/serverlessworkflow/fluent/func/JavaWorkflowBuilderTest.java b/fluent/func/src/test/java/io/serverlessworkflow/fluent/func/JavaWorkflowBuilderTest.java index 529a9b8d..72cf6a68 100644 --- a/fluent/func/src/test/java/io/serverlessworkflow/fluent/func/JavaWorkflowBuilderTest.java +++ b/fluent/func/src/test/java/io/serverlessworkflow/fluent/func/JavaWorkflowBuilderTest.java @@ -27,7 +27,6 @@ import io.serverlessworkflow.api.types.Workflow; import io.serverlessworkflow.api.types.func.*; import io.serverlessworkflow.fluent.spec.BaseWorkflowBuilder; -// if you reuse anything import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicBoolean; @@ -166,7 +165,7 @@ void testJavaFunctionalIO() { ForTaskFunction fn = (ForTaskFunction) forTaskFnHolder.getForTask(); assertNotNull(fn); - // Inspect nested tasks inside the function loop + // Inspect nested branche inside the function loop List nested = fn.getDo(); assertEquals(1, nested.size()); TaskBase nestedTask = nested.get(0).getTask().getSetTask(); @@ -194,7 +193,7 @@ void testJavaFunctionalIO() { } @Test - @DisplayName("callJava task added and retains name + CallTask union") + @DisplayName("callFn task added and retains name + CallTask union") void testCallJavaTask() { Workflow wf = FuncWorkflowBuilder.workflow("callJavaFlow") @@ -214,20 +213,20 @@ void testCallJavaTask() { assertEquals("invokeHandler", ti.getName()); Task task = ti.getTask(); - assertNotNull(task.getCallTask(), "CallTask should be present for callJava"); + assertNotNull(task.getCallTask(), "CallTask should be present for callFn"); // Additional assertions if FuncCallTaskBuilder populates fields // e.g., assertEquals("com.acme.Handler", task.getCallTask().getCallJava().getClassName()); } @Test - @DisplayName("switchCaseFn (Java variant) coexists with spec tasks") + @DisplayName("switchCaseFn (Java variant) coexists with spec branche") void testSwitchCaseJava() { Workflow wf = FuncWorkflowBuilder.workflow("switchJava") .tasks( d -> d.set("prepare", s -> s.expr("$.ready = true")) - .switchC( + .switchCase( sw -> { // configure Java switch builder (cases / predicates) })) @@ -244,7 +243,7 @@ void testSwitchCaseJava() { } @Test - @DisplayName("Combined: spec set + java forE + callJava inside nested do") + @DisplayName("Combined: spec set + java forE + callFn inside nested do") void testCompositeScenario() { Workflow wf = FuncWorkflowBuilder.workflow("composite") @@ -257,7 +256,7 @@ void testCompositeScenario() { .tasks( inner -> inner - .callJava( + .callFn( cj -> { // customizing Java call }) diff --git a/fluent/pom.xml b/fluent/pom.xml index ff19f4d5..4d056c48 100644 --- a/fluent/pom.xml +++ b/fluent/pom.xml @@ -35,6 +35,11 @@ serverlessworkflow-fluent-spec ${project.version} + + io.serverlessworkflow + serverlessworkflow-fluent-func + ${project.version} + diff --git a/fluent/spec/src/main/java/io/serverlessworkflow/fluent/spec/BaseDoTaskBuilder.java b/fluent/spec/src/main/java/io/serverlessworkflow/fluent/spec/BaseDoTaskBuilder.java index d4c70aec..8e6a2410 100644 --- a/fluent/spec/src/main/java/io/serverlessworkflow/fluent/spec/BaseDoTaskBuilder.java +++ b/fluent/spec/src/main/java/io/serverlessworkflow/fluent/spec/BaseDoTaskBuilder.java @@ -16,128 +16,31 @@ package io.serverlessworkflow.fluent.spec; import io.serverlessworkflow.api.types.DoTask; -import java.util.function.Consumer; public abstract class BaseDoTaskBuilder< - TASK extends TaskBaseBuilder, LIST extends BaseTaskItemListBuilder> - extends TaskBaseBuilder { - private final DoTask doTask; - private final BaseTaskItemListBuilder taskItemListBuilder; + SELF extends BaseDoTaskBuilder, LIST extends BaseTaskItemListBuilder> + extends TaskBaseBuilder implements DelegatingDoTaskFluent { - protected BaseDoTaskBuilder(BaseTaskItemListBuilder taskItemListBuilder) { - this.doTask = new DoTask(); - this.taskItemListBuilder = taskItemListBuilder; - this.setTask(doTask); - } - - protected abstract TASK self(); - - protected LIST innerListBuilder() { - return (LIST) taskItemListBuilder; - } - - public TASK set(String name, Consumer itemsConfigurer) { - taskItemListBuilder.set(name, itemsConfigurer); - return self(); - } - - public TASK set(Consumer itemsConfigurer) { - taskItemListBuilder.set(itemsConfigurer); - return self(); - } - - public TASK set(String name, final String expr) { - taskItemListBuilder.set(name, s -> s.expr(expr)); - return self(); - } - - public TASK set(final String expr) { - taskItemListBuilder.set(expr); - return self(); - } - - public TASK forEach(String name, Consumer> itemsConfigurer) { - taskItemListBuilder.forEach(name, itemsConfigurer); - return self(); - } - - public TASK forEach(Consumer> itemsConfigurer) { - taskItemListBuilder.forEach(itemsConfigurer); - return self(); - } - - public TASK switchC(String name, Consumer itemsConfigurer) { - taskItemListBuilder.switchC(name, itemsConfigurer); - return self(); - } - - public TASK switchC(Consumer itemsConfigurer) { - taskItemListBuilder.switchC(itemsConfigurer); - return self(); - } - - public TASK raise(String name, Consumer itemsConfigurer) { - taskItemListBuilder.raise(name, itemsConfigurer); - return self(); - } - - public TASK raise(Consumer itemsConfigurer) { - taskItemListBuilder.raise(itemsConfigurer); - return self(); - } - - public TASK fork(String name, Consumer itemsConfigurer) { - taskItemListBuilder.fork(name, itemsConfigurer); - return self(); - } - - public TASK fork(Consumer itemsConfigurer) { - taskItemListBuilder.fork(itemsConfigurer); - return self(); - } - - public TASK listen(String name, Consumer itemsConfigurer) { - taskItemListBuilder.listen(name, itemsConfigurer); - return self(); - } - - public TASK listen(Consumer itemsConfigurer) { - taskItemListBuilder.listen(itemsConfigurer); - return self(); - } - - public TASK emit(String name, Consumer itemsConfigurer) { - taskItemListBuilder.emit(name, itemsConfigurer); - return self(); - } - - public TASK emit(Consumer itemsConfigurer) { - taskItemListBuilder.emit(itemsConfigurer); - return self(); - } - - public TASK tryC(String name, Consumer> itemsConfigurer) { - taskItemListBuilder.tryC(name, itemsConfigurer); - return self(); - } + private final DoTask doTask = new DoTask(); + private final BaseTaskItemListBuilder itemsListBuilder; - public TASK tryC(Consumer> itemsConfigurer) { - taskItemListBuilder.tryC(itemsConfigurer); - return self(); + protected BaseDoTaskBuilder(BaseTaskItemListBuilder itemsListBuilder) { + this.itemsListBuilder = itemsListBuilder; + setTask(doTask); } - public TASK callHTTP(String name, Consumer itemsConfigurer) { - taskItemListBuilder.callHTTP(name, itemsConfigurer); - return self(); + @SuppressWarnings("unchecked") + @Override + public LIST delegate() { + return (LIST) itemsListBuilder; } - public TASK callHTTP(Consumer itemsConfigurer) { - taskItemListBuilder.callHTTP(itemsConfigurer); - return self(); + public LIST list() { + return (LIST) itemsListBuilder; } public DoTask build() { - this.doTask.setDo(this.taskItemListBuilder.build()); - return this.doTask; + doTask.setDo(itemsListBuilder.build()); + return doTask; } } diff --git a/fluent/spec/src/main/java/io/serverlessworkflow/fluent/spec/BaseTaskItemListBuilder.java b/fluent/spec/src/main/java/io/serverlessworkflow/fluent/spec/BaseTaskItemListBuilder.java index bb2a34dc..2233a418 100644 --- a/fluent/spec/src/main/java/io/serverlessworkflow/fluent/spec/BaseTaskItemListBuilder.java +++ b/fluent/spec/src/main/java/io/serverlessworkflow/fluent/spec/BaseTaskItemListBuilder.java @@ -35,7 +35,8 @@ * * @param the concrete builder type */ -public abstract class BaseTaskItemListBuilder> { +public abstract class BaseTaskItemListBuilder> + implements DoTaskFluent { private final List list; @@ -43,21 +44,30 @@ public BaseTaskItemListBuilder() { this.list = new ArrayList<>(); } + public BaseTaskItemListBuilder(final List list) { + this.list = list; + } + protected abstract SELF self(); protected abstract SELF newItemListBuilder(); - protected SELF addTaskItem(TaskItem taskItem) { + protected final List mutableList() { + return this.list; + } + + protected final SELF addTaskItem(TaskItem taskItem) { Objects.requireNonNull(taskItem, "taskItem must not be null"); list.add(taskItem); return self(); } - protected void requireNameAndConfig(String name, Consumer cfg) { + protected final void requireNameAndConfig(String name, Consumer cfg) { Objects.requireNonNull(name, "Task name must not be null"); Objects.requireNonNull(cfg, "Configurer must not be null"); } + @Override public SELF set(String name, Consumer itemsConfigurer) { requireNameAndConfig(name, itemsConfigurer); final SetTaskBuilder setBuilder = new SetTaskBuilder(); @@ -65,18 +75,22 @@ public SELF set(String name, Consumer itemsConfigurer) { return addTaskItem(new TaskItem(name, new Task().withSetTask(setBuilder.build()))); } + @Override public SELF set(Consumer itemsConfigurer) { return this.set(UUID.randomUUID().toString(), itemsConfigurer); } + @Override public SELF set(String name, final String expr) { return this.set(name, s -> s.expr(expr)); } + @Override public SELF set(final String expr) { return this.set(UUID.randomUUID().toString(), s -> s.expr(expr)); } + @Override public SELF forEach(String name, Consumer> itemsConfigurer) { requireNameAndConfig(name, itemsConfigurer); final ForTaskBuilder forBuilder = new ForTaskBuilder<>(newItemListBuilder()); @@ -84,21 +98,25 @@ public SELF forEach(String name, Consumer> itemsConfigurer) return addTaskItem(new TaskItem(name, new Task().withForTask(forBuilder.build()))); } + @Override public SELF forEach(Consumer> itemsConfigurer) { return this.forEach(UUID.randomUUID().toString(), itemsConfigurer); } - public SELF switchC(String name, Consumer itemsConfigurer) { + @Override + public SELF switchCase(String name, Consumer itemsConfigurer) { requireNameAndConfig(name, itemsConfigurer); final SwitchTaskBuilder switchBuilder = new SwitchTaskBuilder(); itemsConfigurer.accept(switchBuilder); return addTaskItem(new TaskItem(name, new Task().withSwitchTask(switchBuilder.build()))); } - public SELF switchC(Consumer itemsConfigurer) { - return this.switchC(UUID.randomUUID().toString(), itemsConfigurer); + @Override + public SELF switchCase(Consumer itemsConfigurer) { + return this.switchCase(UUID.randomUUID().toString(), itemsConfigurer); } + @Override public SELF raise(String name, Consumer itemsConfigurer) { requireNameAndConfig(name, itemsConfigurer); final RaiseTaskBuilder raiseBuilder = new RaiseTaskBuilder(); @@ -106,10 +124,12 @@ public SELF raise(String name, Consumer itemsConfigurer) { return addTaskItem(new TaskItem(name, new Task().withRaiseTask(raiseBuilder.build()))); } + @Override public SELF raise(Consumer itemsConfigurer) { return this.raise(UUID.randomUUID().toString(), itemsConfigurer); } + @Override public SELF fork(String name, Consumer itemsConfigurer) { requireNameAndConfig(name, itemsConfigurer); final ForkTaskBuilder forkBuilder = new ForkTaskBuilder(); @@ -117,10 +137,12 @@ public SELF fork(String name, Consumer itemsConfigurer) { return addTaskItem(new TaskItem(name, new Task().withForkTask(forkBuilder.build()))); } + @Override public SELF fork(Consumer itemsConfigurer) { return this.fork(UUID.randomUUID().toString(), itemsConfigurer); } + @Override public SELF listen(String name, Consumer itemsConfigurer) { requireNameAndConfig(name, itemsConfigurer); final ListenTaskBuilder listenBuilder = new ListenTaskBuilder(); @@ -128,10 +150,12 @@ public SELF listen(String name, Consumer itemsConfigurer) { return addTaskItem(new TaskItem(name, new Task().withListenTask(listenBuilder.build()))); } + @Override public SELF listen(Consumer itemsConfigurer) { return this.listen(UUID.randomUUID().toString(), itemsConfigurer); } + @Override public SELF emit(String name, Consumer itemsConfigurer) { requireNameAndConfig(name, itemsConfigurer); final EmitTaskBuilder emitBuilder = new EmitTaskBuilder(); @@ -139,21 +163,25 @@ public SELF emit(String name, Consumer itemsConfigurer) { return addTaskItem(new TaskItem(name, new Task().withEmitTask(emitBuilder.build()))); } + @Override public SELF emit(Consumer itemsConfigurer) { return this.emit(UUID.randomUUID().toString(), itemsConfigurer); } - public SELF tryC(String name, Consumer> itemsConfigurer) { + @Override + public SELF tryCatch(String name, Consumer> itemsConfigurer) { requireNameAndConfig(name, itemsConfigurer); final TryTaskBuilder tryBuilder = new TryTaskBuilder<>(this.newItemListBuilder()); itemsConfigurer.accept(tryBuilder); return addTaskItem(new TaskItem(name, new Task().withTryTask(tryBuilder.build()))); } - public SELF tryC(Consumer> itemsConfigurer) { - return this.tryC(UUID.randomUUID().toString(), itemsConfigurer); + @Override + public SELF tryCatch(Consumer> itemsConfigurer) { + return this.tryCatch(UUID.randomUUID().toString(), itemsConfigurer); } + @Override public SELF callHTTP(String name, Consumer itemsConfigurer) { requireNameAndConfig(name, itemsConfigurer); final CallHTTPTaskBuilder callHTTPBuilder = new CallHTTPTaskBuilder(); @@ -163,6 +191,7 @@ public SELF callHTTP(String name, Consumer itemsConfigurer) name, new Task().withCallTask(new CallTask().withCallHTTP(callHTTPBuilder.build())))); } + @Override public SELF callHTTP(Consumer itemsConfigurer) { return this.callHTTP(UUID.randomUUID().toString(), itemsConfigurer); } diff --git a/fluent/spec/src/main/java/io/serverlessworkflow/fluent/spec/DelegatingDoTaskFluent.java b/fluent/spec/src/main/java/io/serverlessworkflow/fluent/spec/DelegatingDoTaskFluent.java new file mode 100644 index 00000000..bfaa6817 --- /dev/null +++ b/fluent/spec/src/main/java/io/serverlessworkflow/fluent/spec/DelegatingDoTaskFluent.java @@ -0,0 +1,163 @@ +/* + * Copyright 2020-Present The Serverless Workflow Specification Authors + * + * 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 io.serverlessworkflow.fluent.spec; + +import java.util.function.Consumer; + +/** + * Mixin that implements {@link DoTaskFluent} by delegating to another instance. + * + * @param the concrete delegating type + * @param the list-builder type used by nested constructs like for/try + */ +public interface DelegatingDoTaskFluent< + SELF extends DelegatingDoTaskFluent, LIST extends BaseTaskItemListBuilder> + extends DoTaskFluent, HasDelegate { + + @SuppressWarnings("unchecked") + default SELF self() { + return (SELF) this; + } + + LIST list(); + + @SuppressWarnings("unchecked") + private DoTaskFluent d() { + return (DoTaskFluent) this.delegate(); + } + + /* ---------- Forwarders ---------- */ + + @Override + default SELF set(String name, Consumer cfg) { + d().set(name, cfg); + return self(); + } + + @Override + default SELF set(Consumer cfg) { + d().set(cfg); + return self(); + } + + @Override + default SELF set(String name, String expr) { + d().set(name, expr); + return self(); + } + + @Override + default SELF set(String expr) { + d().set(expr); + return self(); + } + + @Override + default SELF forEach(String name, Consumer> cfg) { + d().forEach(name, cfg); + return self(); + } + + @Override + default SELF forEach(Consumer> cfg) { + d().forEach(cfg); + return self(); + } + + @Override + default SELF switchCase(String name, Consumer cfg) { + d().switchCase(name, cfg); + return self(); + } + + @Override + default SELF switchCase(Consumer cfg) { + d().switchCase(cfg); + return self(); + } + + @Override + default SELF raise(String name, Consumer cfg) { + d().raise(name, cfg); + return self(); + } + + @Override + default SELF raise(Consumer cfg) { + d().raise(cfg); + return self(); + } + + @Override + default SELF fork(String name, Consumer cfg) { + d().fork(name, cfg); + return self(); + } + + @Override + default SELF fork(Consumer cfg) { + d().fork(cfg); + return self(); + } + + @Override + default SELF listen(String name, Consumer cfg) { + d().listen(name, cfg); + return self(); + } + + @Override + default SELF listen(Consumer cfg) { + d().listen(cfg); + return self(); + } + + @Override + default SELF emit(String name, Consumer cfg) { + d().emit(name, cfg); + return self(); + } + + @Override + default SELF emit(Consumer cfg) { + d().emit(cfg); + return self(); + } + + @Override + default SELF tryCatch(String name, Consumer> cfg) { + d().tryCatch(name, cfg); + return self(); + } + + @Override + default SELF tryCatch(Consumer> cfg) { + d().tryCatch(cfg); + return self(); + } + + @Override + default SELF callHTTP(String name, Consumer cfg) { + d().callHTTP(name, cfg); + return self(); + } + + @Override + default SELF callHTTP(Consumer cfg) { + d().callHTTP(cfg); + return self(); + } +} diff --git a/fluent/spec/src/main/java/io/serverlessworkflow/fluent/spec/DoTaskBuilder.java b/fluent/spec/src/main/java/io/serverlessworkflow/fluent/spec/DoTaskBuilder.java index a9d4f6cb..3b1a768c 100644 --- a/fluent/spec/src/main/java/io/serverlessworkflow/fluent/spec/DoTaskBuilder.java +++ b/fluent/spec/src/main/java/io/serverlessworkflow/fluent/spec/DoTaskBuilder.java @@ -22,7 +22,7 @@ public class DoTaskBuilder extends BaseDoTaskBuilderCNCF + * DSL Reference - Do + * @param The TaskBaseBuilder constructor that sub-tasks will build + * @param The specialized BaseTaskItemListBuilder for sub-tasks that require a list of + * sub-tasks, such as `for`. + */ +public interface DoTaskFluent< + SELF extends DoTaskFluent, LIST extends BaseTaskItemListBuilder> { + + SELF set(String name, Consumer itemsConfigurer); + + SELF set(Consumer itemsConfigurer); + + SELF set(String name, final String expr); + + SELF set(final String expr); + + SELF forEach(String name, Consumer> itemsConfigurer); + + SELF forEach(Consumer> itemsConfigurer); + + SELF switchCase(String name, Consumer itemsConfigurer); + + SELF switchCase(Consumer itemsConfigurer); + + SELF raise(String name, Consumer itemsConfigurer); + + SELF raise(Consumer itemsConfigurer); + + SELF fork(String name, Consumer itemsConfigurer); + + SELF fork(Consumer itemsConfigurer); + + SELF listen(String name, Consumer itemsConfigurer); + + SELF listen(Consumer itemsConfigurer); + + SELF emit(String name, Consumer itemsConfigurer); + + SELF emit(Consumer itemsConfigurer); + + SELF tryCatch(String name, Consumer> itemsConfigurer); + + SELF tryCatch(Consumer> itemsConfigurer); + + SELF callHTTP(String name, Consumer itemsConfigurer); + + SELF callHTTP(Consumer itemsConfigurer); + + // ----- shortcuts/aliases + + default SELF sc(String name, Consumer cfg) { + return switchCase(name, cfg); + } + + default SELF sc(Consumer cfg) { + return switchCase(cfg); + } + + default SELF tc(String name, Consumer> cfg) { + return tryCatch(name, cfg); + } + + default SELF tc(Consumer> cfg) { + return tryCatch(cfg); + } +} diff --git a/fluent/spec/src/main/java/io/serverlessworkflow/fluent/spec/HasDelegate.java b/fluent/spec/src/main/java/io/serverlessworkflow/fluent/spec/HasDelegate.java new file mode 100644 index 00000000..f0b1e0b9 --- /dev/null +++ b/fluent/spec/src/main/java/io/serverlessworkflow/fluent/spec/HasDelegate.java @@ -0,0 +1,21 @@ +/* + * Copyright 2020-Present The Serverless Workflow Specification Authors + * + * 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 io.serverlessworkflow.fluent.spec; + +public interface HasDelegate { + + Object delegate(); +} diff --git a/fluent/spec/src/test/java/io/serverlessworkflow/fluent/spec/WorkflowBuilderTest.java b/fluent/spec/src/test/java/io/serverlessworkflow/fluent/spec/WorkflowBuilderTest.java index 49d41dbb..dbb9f1d3 100644 --- a/fluent/spec/src/test/java/io/serverlessworkflow/fluent/spec/WorkflowBuilderTest.java +++ b/fluent/spec/src/test/java/io/serverlessworkflow/fluent/spec/WorkflowBuilderTest.java @@ -128,7 +128,7 @@ void testDoTaskMultipleTypes() { d -> d.set("init", s -> s.expr("$.init = true")) .forEach("items", f -> f.each("item").in("$.list")) - .switchC( + .switchCase( "choice", sw -> { // no-op configuration @@ -258,7 +258,7 @@ void testDoTaskTryCatchWithRetry() { WorkflowBuilder.workflow("flowTry") .tasks( d -> - d.tryC( + d.tryCatch( "tryBlock", t -> t.tryHandler(tb -> tb.set("init", s -> s.expr("$.start = true"))) @@ -306,7 +306,7 @@ void testDoTaskTryCatchErrorsFiltering() { WorkflowBuilder.workflow("flowCatch") .tasks( d -> - d.tryC( + d.tryCatch( "tryBlock", t -> t.tryHandler(tb -> tb.set("foo", s -> s.expr("$.foo = 'bar'"))) diff --git a/pom.xml b/pom.xml index b456e6a4..428e82bb 100644 --- a/pom.xml +++ b/pom.xml @@ -150,6 +150,11 @@ slf4j-api ${version.org.slf4j} + + org.slf4j + slf4j-simple + ${version.org.slf4j} + io.serverlessworkflow serverlessworkflow-api