diff --git a/fluent/pom.xml b/fluent/pom.xml
new file mode 100644
index 00000000..71d54a64
--- /dev/null
+++ b/fluent/pom.xml
@@ -0,0 +1,35 @@
+
+
+ 4.0.0
+
+ io.serverlessworkflow
+ serverlessworkflow-parent
+ 8.0.0-SNAPSHOT
+
+ Serverless Workflow :: Fluent
+ serverlessworkflow-fluent
+ pom
+
+
+ 17
+ 17
+ UTF-8
+
+
+
+
+
+ io.serverlessworkflow
+ serverlessworkflow-types
+ ${project.version}
+
+
+
+
+
+ standard
+
+
+
\ No newline at end of file
diff --git a/fluent/standard/pom.xml b/fluent/standard/pom.xml
new file mode 100644
index 00000000..570d9665
--- /dev/null
+++ b/fluent/standard/pom.xml
@@ -0,0 +1,32 @@
+
+
+ 4.0.0
+
+ io.serverlessworkflow
+ serverlessworkflow-fluent
+ 8.0.0-SNAPSHOT
+
+ Serverless Workflow :: Fluent :: Standard
+ serverlessworkflow-fluent-standard
+
+
+ 17
+ 17
+ UTF-8
+
+
+
+
+ io.serverlessworkflow
+ serverlessworkflow-types
+
+
+ org.junit.jupiter
+ junit-jupiter-api
+ test
+
+
+
+
\ No newline at end of file
diff --git a/fluent/standard/src/main/java/io/serverlessworkflow/fluent/standard/AuthenticationPolicyUnionBuilder.java b/fluent/standard/src/main/java/io/serverlessworkflow/fluent/standard/AuthenticationPolicyUnionBuilder.java
new file mode 100644
index 00000000..2699c809
--- /dev/null
+++ b/fluent/standard/src/main/java/io/serverlessworkflow/fluent/standard/AuthenticationPolicyUnionBuilder.java
@@ -0,0 +1,80 @@
+/*
+ * 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.standard;
+
+import io.serverlessworkflow.api.types.AuthenticationPolicyUnion;
+import java.util.function.Consumer;
+
+public class AuthenticationPolicyUnionBuilder {
+ final AuthenticationPolicyUnion authenticationPolicy;
+
+ AuthenticationPolicyUnionBuilder() {
+ this.authenticationPolicy = new AuthenticationPolicyUnion();
+ }
+
+ public AuthenticationPolicyUnionBuilder basic(
+ Consumer basicConsumer) {
+ final BasicAuthenticationPolicyBuilder basicAuthenticationPolicyBuilder =
+ new BasicAuthenticationPolicyBuilder();
+ basicConsumer.accept(basicAuthenticationPolicyBuilder);
+ this.authenticationPolicy.setBasicAuthenticationPolicy(
+ basicAuthenticationPolicyBuilder.build());
+ return this;
+ }
+
+ public AuthenticationPolicyUnionBuilder bearer(
+ Consumer bearerConsumer) {
+ final BearerAuthenticationPolicyBuilder bearerAuthenticationPolicyBuilder =
+ new BearerAuthenticationPolicyBuilder();
+ bearerConsumer.accept(bearerAuthenticationPolicyBuilder);
+ this.authenticationPolicy.setBearerAuthenticationPolicy(
+ bearerAuthenticationPolicyBuilder.build());
+ return this;
+ }
+
+ public AuthenticationPolicyUnionBuilder digest(
+ Consumer digestConsumer) {
+ final DigestAuthenticationPolicyBuilder digestAuthenticationPolicyBuilder =
+ new DigestAuthenticationPolicyBuilder();
+ digestConsumer.accept(digestAuthenticationPolicyBuilder);
+ this.authenticationPolicy.setDigestAuthenticationPolicy(
+ digestAuthenticationPolicyBuilder.build());
+ return this;
+ }
+
+ public AuthenticationPolicyUnionBuilder oauth2(
+ Consumer oauth2Consumer) {
+ final OAuth2AuthenticationPolicyBuilder oauth2AuthenticationPolicyBuilder =
+ new OAuth2AuthenticationPolicyBuilder();
+ oauth2Consumer.accept(oauth2AuthenticationPolicyBuilder);
+ this.authenticationPolicy.setOAuth2AuthenticationPolicy(
+ oauth2AuthenticationPolicyBuilder.build());
+ return this;
+ }
+
+ public AuthenticationPolicyUnionBuilder openIDConnect(
+ Consumer openIdConnectConsumer) {
+ final OpenIdConnectAuthenticationPolicyBuilder builder =
+ new OpenIdConnectAuthenticationPolicyBuilder();
+ openIdConnectConsumer.accept(builder);
+ this.authenticationPolicy.setOpenIdConnectAuthenticationPolicy(builder.build());
+ return this;
+ }
+
+ public AuthenticationPolicyUnion build() {
+ return authenticationPolicy;
+ }
+}
diff --git a/fluent/standard/src/main/java/io/serverlessworkflow/fluent/standard/BasicAuthenticationPolicyBuilder.java b/fluent/standard/src/main/java/io/serverlessworkflow/fluent/standard/BasicAuthenticationPolicyBuilder.java
new file mode 100644
index 00000000..c121f18f
--- /dev/null
+++ b/fluent/standard/src/main/java/io/serverlessworkflow/fluent/standard/BasicAuthenticationPolicyBuilder.java
@@ -0,0 +1,46 @@
+/*
+ * 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.standard;
+
+import io.serverlessworkflow.api.types.BasicAuthenticationPolicy;
+import io.serverlessworkflow.api.types.BasicAuthenticationPolicyConfiguration;
+import io.serverlessworkflow.api.types.BasicAuthenticationProperties;
+
+public final class BasicAuthenticationPolicyBuilder {
+
+ private final BasicAuthenticationProperties basicAuthenticationProperties;
+
+ BasicAuthenticationPolicyBuilder() {
+ this.basicAuthenticationProperties = new BasicAuthenticationProperties();
+ }
+
+ public BasicAuthenticationPolicyBuilder username(String username) {
+ this.basicAuthenticationProperties.setUsername(username);
+ return this;
+ }
+
+ public BasicAuthenticationPolicyBuilder password(String password) {
+ this.basicAuthenticationProperties.setPassword(password);
+ return this;
+ }
+
+ public BasicAuthenticationPolicy build() {
+ final BasicAuthenticationPolicyConfiguration configuration =
+ new BasicAuthenticationPolicyConfiguration();
+ configuration.setBasicAuthenticationProperties(basicAuthenticationProperties);
+ return new BasicAuthenticationPolicy(configuration);
+ }
+}
diff --git a/fluent/standard/src/main/java/io/serverlessworkflow/fluent/standard/BearerAuthenticationPolicyBuilder.java b/fluent/standard/src/main/java/io/serverlessworkflow/fluent/standard/BearerAuthenticationPolicyBuilder.java
new file mode 100644
index 00000000..08e52522
--- /dev/null
+++ b/fluent/standard/src/main/java/io/serverlessworkflow/fluent/standard/BearerAuthenticationPolicyBuilder.java
@@ -0,0 +1,40 @@
+/*
+ * 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.standard;
+
+import io.serverlessworkflow.api.types.BearerAuthenticationPolicy;
+import io.serverlessworkflow.api.types.BearerAuthenticationPolicyConfiguration;
+import io.serverlessworkflow.api.types.BearerAuthenticationProperties;
+
+public final class BearerAuthenticationPolicyBuilder {
+ private final BearerAuthenticationProperties bearerAuthenticationProperties;
+
+ BearerAuthenticationPolicyBuilder() {
+ this.bearerAuthenticationProperties = new BearerAuthenticationProperties();
+ }
+
+ public BearerAuthenticationPolicyBuilder token(final String token) {
+ this.bearerAuthenticationProperties.setToken(token);
+ return this;
+ }
+
+ public BearerAuthenticationPolicy build() {
+ final BearerAuthenticationPolicyConfiguration configuration =
+ new BearerAuthenticationPolicyConfiguration();
+ configuration.setBearerAuthenticationProperties(bearerAuthenticationProperties);
+ return new BearerAuthenticationPolicy(configuration);
+ }
+}
diff --git a/fluent/standard/src/main/java/io/serverlessworkflow/fluent/standard/CallHTTPTaskBuilder.java b/fluent/standard/src/main/java/io/serverlessworkflow/fluent/standard/CallHTTPTaskBuilder.java
new file mode 100644
index 00000000..f2603903
--- /dev/null
+++ b/fluent/standard/src/main/java/io/serverlessworkflow/fluent/standard/CallHTTPTaskBuilder.java
@@ -0,0 +1,157 @@
+/*
+ * 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.standard;
+
+import io.serverlessworkflow.api.types.CallHTTP;
+import io.serverlessworkflow.api.types.Endpoint;
+import io.serverlessworkflow.api.types.HTTPArguments;
+import io.serverlessworkflow.api.types.HTTPHeaders;
+import io.serverlessworkflow.api.types.HTTPQuery;
+import io.serverlessworkflow.api.types.Headers;
+import io.serverlessworkflow.api.types.Query;
+import io.serverlessworkflow.api.types.UriTemplate;
+import java.net.URI;
+import java.util.Map;
+import java.util.function.Consumer;
+
+public class CallHTTPTaskBuilder extends TaskBaseBuilder {
+
+ private final CallHTTP callHTTP;
+
+ CallHTTPTaskBuilder() {
+ callHTTP = new CallHTTP();
+ callHTTP.setWith(new HTTPArguments());
+ callHTTP.getWith().setOutput(HTTPArguments.HTTPOutput.CONTENT);
+ super.setTask(this.callHTTP);
+ }
+
+ @Override
+ protected CallHTTPTaskBuilder self() {
+ return this;
+ }
+
+ public CallHTTPTaskBuilder method(String method) {
+ this.callHTTP.getWith().setMethod(method);
+ return this;
+ }
+
+ public CallHTTPTaskBuilder endpoint(URI endpoint) {
+ this.callHTTP
+ .getWith()
+ .setEndpoint(new Endpoint().withUriTemplate(new UriTemplate().withLiteralUri(endpoint)));
+ return this;
+ }
+
+ public CallHTTPTaskBuilder endpoint(String expr) {
+ this.callHTTP.getWith().setEndpoint(new Endpoint().withRuntimeExpression(expr));
+ return this;
+ }
+
+ // TODO: add endpoint configuration to support authentication
+
+ public CallHTTPTaskBuilder headers(String expr) {
+ this.callHTTP.getWith().setHeaders(new Headers().withRuntimeExpression(expr));
+ return this;
+ }
+
+ public CallHTTPTaskBuilder headers(Consumer consumer) {
+ HTTPHeadersBuilder hb = new HTTPHeadersBuilder();
+ consumer.accept(hb);
+ callHTTP.getWith().setHeaders(hb.build());
+ return this;
+ }
+
+ public CallHTTPTaskBuilder headers(Map headers) {
+ HTTPHeadersBuilder hb = new HTTPHeadersBuilder();
+ hb.headers(headers);
+ callHTTP.getWith().setHeaders(hb.build());
+ return this;
+ }
+
+ public CallHTTPTaskBuilder body(Object body) {
+ this.callHTTP.getWith().setBody(body);
+ return this;
+ }
+
+ public CallHTTPTaskBuilder query(String expr) {
+ this.callHTTP.getWith().setQuery(new Query().withRuntimeExpression(expr));
+ return this;
+ }
+
+ public CallHTTPTaskBuilder query(Consumer consumer) {
+ HTTPQueryBuilder queryBuilder = new HTTPQueryBuilder();
+ consumer.accept(queryBuilder);
+ callHTTP.getWith().setQuery(queryBuilder.build());
+ return this;
+ }
+
+ public CallHTTPTaskBuilder query(Map query) {
+ HTTPQueryBuilder httpQueryBuilder = new HTTPQueryBuilder();
+ httpQueryBuilder.queries(query);
+ callHTTP.getWith().setQuery(httpQueryBuilder.build());
+ return this;
+ }
+
+ public CallHTTPTaskBuilder redirect(boolean redirect) {
+ callHTTP.getWith().setRedirect(redirect);
+ return this;
+ }
+
+ public CallHTTPTaskBuilder output(HTTPArguments.HTTPOutput output) {
+ callHTTP.getWith().setOutput(output);
+ return this;
+ }
+
+ public CallHTTP build() {
+ return callHTTP;
+ }
+
+ public static class HTTPQueryBuilder {
+ private final HTTPQuery httpQuery = new HTTPQuery();
+
+ public HTTPQueryBuilder query(String name, String value) {
+ httpQuery.setAdditionalProperty(name, value);
+ return this;
+ }
+
+ public HTTPQueryBuilder queries(Map headers) {
+ headers.forEach(httpQuery::setAdditionalProperty);
+ return this;
+ }
+
+ public Query build() {
+ return new Query().withHTTPQuery(httpQuery);
+ }
+ }
+
+ public static class HTTPHeadersBuilder {
+ private final HTTPHeaders httpHeaders = new HTTPHeaders();
+
+ public HTTPHeadersBuilder header(String name, String value) {
+ httpHeaders.setAdditionalProperty(name, value);
+ return this;
+ }
+
+ public HTTPHeadersBuilder headers(Map headers) {
+ headers.forEach(httpHeaders::setAdditionalProperty);
+ return this;
+ }
+
+ public Headers build() {
+ return new Headers().withHTTPHeaders(httpHeaders);
+ }
+ }
+}
diff --git a/fluent/standard/src/main/java/io/serverlessworkflow/fluent/standard/DigestAuthenticationPolicyBuilder.java b/fluent/standard/src/main/java/io/serverlessworkflow/fluent/standard/DigestAuthenticationPolicyBuilder.java
new file mode 100644
index 00000000..8405a48b
--- /dev/null
+++ b/fluent/standard/src/main/java/io/serverlessworkflow/fluent/standard/DigestAuthenticationPolicyBuilder.java
@@ -0,0 +1,45 @@
+/*
+ * 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.standard;
+
+import io.serverlessworkflow.api.types.DigestAuthenticationPolicy;
+import io.serverlessworkflow.api.types.DigestAuthenticationPolicyConfiguration;
+import io.serverlessworkflow.api.types.DigestAuthenticationProperties;
+
+public final class DigestAuthenticationPolicyBuilder {
+ private final DigestAuthenticationProperties digestAuthenticationProperties;
+
+ DigestAuthenticationPolicyBuilder() {
+ this.digestAuthenticationProperties = new DigestAuthenticationProperties();
+ }
+
+ public DigestAuthenticationPolicyBuilder username(String username) {
+ this.digestAuthenticationProperties.setUsername(username);
+ return this;
+ }
+
+ public DigestAuthenticationPolicyBuilder password(String password) {
+ this.digestAuthenticationProperties.setPassword(password);
+ return this;
+ }
+
+ public DigestAuthenticationPolicy build() {
+ final DigestAuthenticationPolicyConfiguration configuration =
+ new DigestAuthenticationPolicyConfiguration();
+ configuration.setDigestAuthenticationProperties(digestAuthenticationProperties);
+ return new DigestAuthenticationPolicy(configuration);
+ }
+}
diff --git a/fluent/standard/src/main/java/io/serverlessworkflow/fluent/standard/DoTaskBuilder.java b/fluent/standard/src/main/java/io/serverlessworkflow/fluent/standard/DoTaskBuilder.java
new file mode 100644
index 00000000..3de5cfe7
--- /dev/null
+++ b/fluent/standard/src/main/java/io/serverlessworkflow/fluent/standard/DoTaskBuilder.java
@@ -0,0 +1,156 @@
+/*
+ * 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.standard;
+
+import io.serverlessworkflow.api.types.CallTask;
+import io.serverlessworkflow.api.types.DoTask;
+import io.serverlessworkflow.api.types.Task;
+import io.serverlessworkflow.api.types.TaskItem;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+import java.util.function.Consumer;
+
+public class DoTaskBuilder extends TaskBaseBuilder {
+
+ private final DoTask doTask;
+ private final List list;
+
+ DoTaskBuilder() {
+ this.doTask = new DoTask();
+ this.list = new ArrayList<>();
+ this.setTask(doTask);
+ }
+
+ @Override
+ protected DoTaskBuilder self() {
+ return this;
+ }
+
+ public DoTaskBuilder set(String name, Consumer itemsConfigurer) {
+ final SetTaskBuilder setBuilder = new SetTaskBuilder();
+ itemsConfigurer.accept(setBuilder);
+ this.list.add(new TaskItem(name, new Task().withSetTask(setBuilder.build())));
+ return this;
+ }
+
+ public DoTaskBuilder set(Consumer itemsConfigurer) {
+ return this.set(UUID.randomUUID().toString(), itemsConfigurer);
+ }
+
+ public DoTaskBuilder set(String name, final String expr) {
+ return this.set(name, s -> s.expr(expr));
+ }
+
+ public DoTaskBuilder set(final String expr) {
+ return this.set(UUID.randomUUID().toString(), s -> s.expr(expr));
+ }
+
+ public DoTaskBuilder forEach(String name, Consumer itemsConfigurer) {
+ final ForTaskBuilder forBuilder = new ForTaskBuilder();
+ itemsConfigurer.accept(forBuilder);
+ this.list.add(new TaskItem(name, new Task().withForTask(forBuilder.build())));
+ return this;
+ }
+
+ public DoTaskBuilder forEach(Consumer itemsConfigurer) {
+ return this.forEach(UUID.randomUUID().toString(), itemsConfigurer);
+ }
+
+ public DoTaskBuilder switchTask(String name, Consumer itemsConfigurer) {
+ final SwitchTaskBuilder switchBuilder = new SwitchTaskBuilder();
+ itemsConfigurer.accept(switchBuilder);
+ this.list.add(new TaskItem(name, new Task().withSwitchTask(switchBuilder.build())));
+ return this;
+ }
+
+ public DoTaskBuilder switchTask(Consumer itemsConfigurer) {
+ return this.switchTask(UUID.randomUUID().toString(), itemsConfigurer);
+ }
+
+ public DoTaskBuilder raise(String name, Consumer itemsConfigurer) {
+ final RaiseTaskBuilder raiseBuilder = new RaiseTaskBuilder();
+ itemsConfigurer.accept(raiseBuilder);
+ this.list.add(new TaskItem(name, new Task().withRaiseTask(raiseBuilder.build())));
+ return this;
+ }
+
+ public DoTaskBuilder raise(Consumer itemsConfigurer) {
+ return this.raise(UUID.randomUUID().toString(), itemsConfigurer);
+ }
+
+ public DoTaskBuilder fork(String name, Consumer itemsConfigurer) {
+ final ForkTaskBuilder forkBuilder = new ForkTaskBuilder();
+ itemsConfigurer.accept(forkBuilder);
+ this.list.add(new TaskItem(name, new Task().withForkTask(forkBuilder.build())));
+ return this;
+ }
+
+ public DoTaskBuilder fork(Consumer itemsConfigurer) {
+ return this.fork(UUID.randomUUID().toString(), itemsConfigurer);
+ }
+
+ public DoTaskBuilder listen(String name, Consumer itemsConfigurer) {
+ final ListenTaskBuilder listenBuilder = new ListenTaskBuilder();
+ itemsConfigurer.accept(listenBuilder);
+ this.list.add(new TaskItem(name, new Task().withListenTask(listenBuilder.build())));
+ return this;
+ }
+
+ public DoTaskBuilder listen(Consumer itemsConfigurer) {
+ return this.listen(UUID.randomUUID().toString(), itemsConfigurer);
+ }
+
+ public DoTaskBuilder emit(String name, Consumer itemsConfigurer) {
+ final EmitTaskBuilder emitBuilder = new EmitTaskBuilder();
+ itemsConfigurer.accept(emitBuilder);
+ this.list.add(new TaskItem(name, new Task().withEmitTask(emitBuilder.build())));
+ return this;
+ }
+
+ public DoTaskBuilder emit(Consumer itemsConfigurer) {
+ return this.emit(UUID.randomUUID().toString(), itemsConfigurer);
+ }
+
+ public DoTaskBuilder tryTask(String name, Consumer itemsConfigurer) {
+ final TryTaskBuilder tryBuilder = new TryTaskBuilder();
+ itemsConfigurer.accept(tryBuilder);
+ this.list.add(new TaskItem(name, new Task().withTryTask(tryBuilder.build())));
+ return this;
+ }
+
+ public DoTaskBuilder tryTask(Consumer itemsConfigurer) {
+ return this.tryTask(UUID.randomUUID().toString(), itemsConfigurer);
+ }
+
+ public DoTaskBuilder callHTTP(String name, Consumer itemsConfigurer) {
+ final CallHTTPTaskBuilder callHTTPBuilder = new CallHTTPTaskBuilder();
+ itemsConfigurer.accept(callHTTPBuilder);
+ this.list.add(
+ new TaskItem(
+ name, new Task().withCallTask(new CallTask().withCallHTTP(callHTTPBuilder.build()))));
+ return this;
+ }
+
+ public DoTaskBuilder callHTTP(Consumer itemsConfigurer) {
+ return this.callHTTP(UUID.randomUUID().toString(), itemsConfigurer);
+ }
+
+ public DoTask build() {
+ this.doTask.setDo(this.list);
+ return this.doTask;
+ }
+}
diff --git a/fluent/standard/src/main/java/io/serverlessworkflow/fluent/standard/DocumentBuilder.java b/fluent/standard/src/main/java/io/serverlessworkflow/fluent/standard/DocumentBuilder.java
new file mode 100644
index 00000000..de6d9ee3
--- /dev/null
+++ b/fluent/standard/src/main/java/io/serverlessworkflow/fluent/standard/DocumentBuilder.java
@@ -0,0 +1,108 @@
+/*
+ * 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.standard;
+
+import io.serverlessworkflow.api.types.Document;
+import io.serverlessworkflow.api.types.WorkflowMetadata;
+import io.serverlessworkflow.api.types.WorkflowTags;
+import java.util.function.Consumer;
+
+public class DocumentBuilder {
+
+ private final Document document;
+
+ DocumentBuilder(final Document document) {
+ this.document = document;
+ }
+
+ public DocumentBuilder dsl(final String dsl) {
+ this.document.setDsl(dsl);
+ return this;
+ }
+
+ public DocumentBuilder name(final String name) {
+ this.document.setName(name);
+ return this;
+ }
+
+ public DocumentBuilder namespace(final String namespace) {
+ this.document.setNamespace(namespace);
+ return this;
+ }
+
+ public DocumentBuilder version(final String version) {
+ this.document.setVersion(version);
+ return this;
+ }
+
+ public DocumentBuilder title(final String title) {
+ this.document.setTitle(title);
+ return this;
+ }
+
+ public DocumentBuilder summary(final String summary) {
+ this.document.setSummary(summary);
+ return this;
+ }
+
+ public DocumentBuilder tags(Consumer tagsBuilderConsumer) {
+ final WorkflowTagsBuilder tagsBuilder = new WorkflowTagsBuilder();
+ tagsBuilderConsumer.accept(tagsBuilder);
+ this.document.setTags(tagsBuilder.build());
+ return this;
+ }
+
+ public DocumentBuilder metadata(Consumer metadataBuilderConsumer) {
+ final WorkflowMetadataBuilder metadataBuilder = new WorkflowMetadataBuilder();
+ metadataBuilderConsumer.accept(metadataBuilder);
+ this.document.setMetadata(metadataBuilder.build());
+ return this;
+ }
+
+ public static final class WorkflowTagsBuilder {
+ private final WorkflowTags tags;
+
+ WorkflowTagsBuilder() {
+ this.tags = new WorkflowTags();
+ }
+
+ public WorkflowTagsBuilder tag(final String key, final String value) {
+ this.tags.withAdditionalProperty(key, value);
+ return this;
+ }
+
+ public WorkflowTags build() {
+ return this.tags;
+ }
+ }
+
+ public static final class WorkflowMetadataBuilder {
+ private final WorkflowMetadata workflowMetadata;
+
+ WorkflowMetadataBuilder() {
+ this.workflowMetadata = new WorkflowMetadata();
+ }
+
+ public WorkflowMetadataBuilder metadata(final String key, final Object value) {
+ this.workflowMetadata.withAdditionalProperty(key, value);
+ return this;
+ }
+
+ public WorkflowMetadata build() {
+ return this.workflowMetadata;
+ }
+ }
+}
diff --git a/fluent/standard/src/main/java/io/serverlessworkflow/fluent/standard/DurationInlineBuilder.java b/fluent/standard/src/main/java/io/serverlessworkflow/fluent/standard/DurationInlineBuilder.java
new file mode 100644
index 00000000..23730731
--- /dev/null
+++ b/fluent/standard/src/main/java/io/serverlessworkflow/fluent/standard/DurationInlineBuilder.java
@@ -0,0 +1,56 @@
+/*
+ * 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.standard;
+
+import io.serverlessworkflow.api.types.DurationInline;
+
+public class DurationInlineBuilder {
+
+ private final DurationInline duration;
+
+ DurationInlineBuilder() {
+ duration = new DurationInline();
+ }
+
+ public DurationInlineBuilder days(int days) {
+ duration.setDays(days);
+ return this;
+ }
+
+ public DurationInlineBuilder hours(int hours) {
+ duration.setHours(hours);
+ return this;
+ }
+
+ public DurationInlineBuilder minutes(int minutes) {
+ duration.setMinutes(minutes);
+ return this;
+ }
+
+ public DurationInlineBuilder seconds(int seconds) {
+ duration.setSeconds(seconds);
+ return this;
+ }
+
+ public DurationInlineBuilder milliseconds(int milliseconds) {
+ duration.setMilliseconds(milliseconds);
+ return this;
+ }
+
+ public DurationInline build() {
+ return duration;
+ }
+}
diff --git a/fluent/standard/src/main/java/io/serverlessworkflow/fluent/standard/EmitTaskBuilder.java b/fluent/standard/src/main/java/io/serverlessworkflow/fluent/standard/EmitTaskBuilder.java
new file mode 100644
index 00000000..77ea9d98
--- /dev/null
+++ b/fluent/standard/src/main/java/io/serverlessworkflow/fluent/standard/EmitTaskBuilder.java
@@ -0,0 +1,49 @@
+/*
+ * 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.standard;
+
+import io.serverlessworkflow.api.types.EmitEventDefinition;
+import io.serverlessworkflow.api.types.EmitTask;
+import io.serverlessworkflow.api.types.EmitTaskConfiguration;
+import java.util.function.Consumer;
+
+public class EmitTaskBuilder extends TaskBaseBuilder {
+
+ private final EmitTask emitTask;
+
+ EmitTaskBuilder() {
+ this.emitTask = new EmitTask();
+ super.setTask(emitTask);
+ }
+
+ public EmitTaskBuilder event(Consumer consumer) {
+ final EventPropertiesBuilder eventPropertiesBuilder = new EventPropertiesBuilder();
+ consumer.accept(eventPropertiesBuilder);
+ this.emitTask.setEmit(
+ new EmitTaskConfiguration()
+ .withEvent(new EmitEventDefinition().withWith(eventPropertiesBuilder.build())));
+ return this;
+ }
+
+ public EmitTask build() {
+ return emitTask;
+ }
+
+ @Override
+ protected EmitTaskBuilder self() {
+ return this;
+ }
+}
diff --git a/fluent/standard/src/main/java/io/serverlessworkflow/fluent/standard/EventPropertiesBuilder.java b/fluent/standard/src/main/java/io/serverlessworkflow/fluent/standard/EventPropertiesBuilder.java
new file mode 100644
index 00000000..86863804
--- /dev/null
+++ b/fluent/standard/src/main/java/io/serverlessworkflow/fluent/standard/EventPropertiesBuilder.java
@@ -0,0 +1,78 @@
+/*
+ * 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.standard;
+
+import io.serverlessworkflow.api.types.EventData;
+import io.serverlessworkflow.api.types.EventProperties;
+import io.serverlessworkflow.api.types.EventSource;
+import io.serverlessworkflow.api.types.EventTime;
+import io.serverlessworkflow.api.types.UriTemplate;
+import java.net.URI;
+import java.util.Date;
+
+public final class EventPropertiesBuilder {
+ private final EventProperties properties = new EventProperties();
+
+ public EventPropertiesBuilder id(String id) {
+ properties.setId(id);
+ return this;
+ }
+
+ public EventPropertiesBuilder source(String expr) {
+
+ properties.setSource(new EventSource().withRuntimeExpression(expr));
+ return this;
+ }
+
+ public EventPropertiesBuilder source(URI uri) {
+ properties.setSource(new EventSource().withUriTemplate(new UriTemplate().withLiteralUri(uri)));
+ return this;
+ }
+
+ public EventPropertiesBuilder type(String type) {
+ properties.setType(type);
+ return this;
+ }
+
+ public EventPropertiesBuilder time(Date time) {
+ properties.setTime(new EventTime().withLiteralTime(time));
+ return this;
+ }
+
+ public EventPropertiesBuilder subject(String subject) {
+ properties.setSubject(subject);
+ return this;
+ }
+
+ public EventPropertiesBuilder dataContentType(String ct) {
+ properties.setDatacontenttype(ct);
+ return this;
+ }
+
+ public EventPropertiesBuilder data(String expr) {
+ properties.setData(new EventData().withRuntimeExpression(expr));
+ return this;
+ }
+
+ public EventPropertiesBuilder data(Object obj) {
+ properties.setData(new EventData().withObject(obj));
+ return this;
+ }
+
+ public EventProperties build() {
+ return properties;
+ }
+}
diff --git a/fluent/standard/src/main/java/io/serverlessworkflow/fluent/standard/ForTaskBuilder.java b/fluent/standard/src/main/java/io/serverlessworkflow/fluent/standard/ForTaskBuilder.java
new file mode 100644
index 00000000..e755eebd
--- /dev/null
+++ b/fluent/standard/src/main/java/io/serverlessworkflow/fluent/standard/ForTaskBuilder.java
@@ -0,0 +1,69 @@
+/*
+ * 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.standard;
+
+import io.serverlessworkflow.api.types.ForTask;
+import io.serverlessworkflow.api.types.ForTaskConfiguration;
+import java.util.function.Consumer;
+
+public class ForTaskBuilder extends TaskBaseBuilder {
+
+ private final ForTask forTask;
+ private final ForTaskConfiguration forTaskConfiguration;
+
+ ForTaskBuilder() {
+ super();
+ forTask = new ForTask();
+ forTaskConfiguration = new ForTaskConfiguration();
+ super.setTask(forTask);
+ }
+
+ protected ForTaskBuilder self() {
+ return this;
+ }
+
+ public ForTaskBuilder each(String each) {
+ forTaskConfiguration.setEach(each);
+ return this;
+ }
+
+ public ForTaskBuilder in(String in) {
+ this.forTaskConfiguration.setIn(in);
+ return this;
+ }
+
+ public ForTaskBuilder at(String at) {
+ this.forTaskConfiguration.setAt(at);
+ return this;
+ }
+
+ public ForTaskBuilder whileCondition(final String expression) {
+ this.forTask.setWhile(expression);
+ return this;
+ }
+
+ public ForTaskBuilder doTasks(Consumer doBuilderConsumer) {
+ final DoTaskBuilder doTaskBuilder = new DoTaskBuilder();
+ doBuilderConsumer.accept(doTaskBuilder);
+ this.forTask.setDo(doTaskBuilder.build().getDo());
+ return this;
+ }
+
+ public ForTask build() {
+ this.forTask.setFor(this.forTaskConfiguration);
+ return this.forTask;
+ }
+}
diff --git a/fluent/standard/src/main/java/io/serverlessworkflow/fluent/standard/ForkTaskBuilder.java b/fluent/standard/src/main/java/io/serverlessworkflow/fluent/standard/ForkTaskBuilder.java
new file mode 100644
index 00000000..59754ed8
--- /dev/null
+++ b/fluent/standard/src/main/java/io/serverlessworkflow/fluent/standard/ForkTaskBuilder.java
@@ -0,0 +1,53 @@
+/*
+ * 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.standard;
+
+import io.serverlessworkflow.api.types.ForkTask;
+import io.serverlessworkflow.api.types.ForkTaskConfiguration;
+import java.util.function.Consumer;
+
+public class ForkTaskBuilder extends TaskBaseBuilder {
+
+ private final ForkTask forkTask;
+ private final ForkTaskConfiguration forkTaskConfiguration;
+
+ @Override
+ protected ForkTaskBuilder self() {
+ return this;
+ }
+
+ ForkTaskBuilder() {
+ this.forkTask = new ForkTask();
+ this.forkTaskConfiguration = new ForkTaskConfiguration();
+ super.setTask(this.forkTask);
+ }
+
+ public ForkTaskBuilder compete(final Boolean compete) {
+ this.forkTaskConfiguration.setCompete(compete);
+ return this;
+ }
+
+ public ForkTaskBuilder branches(Consumer branchesConsumer) {
+ final DoTaskBuilder doTaskBuilder = new DoTaskBuilder();
+ branchesConsumer.accept(doTaskBuilder);
+ this.forkTaskConfiguration.setBranches(doTaskBuilder.build().getDo());
+ return this;
+ }
+
+ public ForkTask build() {
+ return this.forkTask.withFork(this.forkTaskConfiguration);
+ }
+}
diff --git a/fluent/standard/src/main/java/io/serverlessworkflow/fluent/standard/InputBuilder.java b/fluent/standard/src/main/java/io/serverlessworkflow/fluent/standard/InputBuilder.java
new file mode 100644
index 00000000..81ebfcc0
--- /dev/null
+++ b/fluent/standard/src/main/java/io/serverlessworkflow/fluent/standard/InputBuilder.java
@@ -0,0 +1,67 @@
+/*
+ * 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.standard;
+
+import io.serverlessworkflow.api.types.Endpoint;
+import io.serverlessworkflow.api.types.ExternalResource;
+import io.serverlessworkflow.api.types.Input;
+import io.serverlessworkflow.api.types.InputFrom;
+import io.serverlessworkflow.api.types.SchemaExternal;
+import io.serverlessworkflow.api.types.SchemaInline;
+import io.serverlessworkflow.api.types.SchemaUnion;
+
+public class InputBuilder {
+
+ private final Input input;
+
+ InputBuilder() {
+ this.input = new Input();
+ this.input.setFrom(new InputFrom());
+ this.input.setSchema(new SchemaUnion());
+ }
+
+ public InputBuilder from(String expr) {
+ this.input.getFrom().setString(expr);
+ return this;
+ }
+
+ public InputBuilder from(Object object) {
+ this.input.getFrom().setObject(object);
+ return this;
+ }
+
+ public InputBuilder schema(Object schema) {
+ this.input.getSchema().setSchemaInline(new SchemaInline(schema));
+ return this;
+ }
+
+ public InputBuilder schema(String schema) {
+ this.input
+ .getSchema()
+ .setSchemaExternal(
+ new SchemaExternal()
+ .withResource(
+ new ExternalResource()
+ .withEndpoint(
+ new Endpoint()
+ .withUriTemplate(UriTemplateBuilder.newUriTemplate(schema)))));
+ return this;
+ }
+
+ public Input build() {
+ return this.input;
+ }
+}
diff --git a/fluent/standard/src/main/java/io/serverlessworkflow/fluent/standard/ListenTaskBuilder.java b/fluent/standard/src/main/java/io/serverlessworkflow/fluent/standard/ListenTaskBuilder.java
new file mode 100644
index 00000000..16791cab
--- /dev/null
+++ b/fluent/standard/src/main/java/io/serverlessworkflow/fluent/standard/ListenTaskBuilder.java
@@ -0,0 +1,149 @@
+/*
+ * 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.standard;
+
+import io.serverlessworkflow.api.types.AllEventConsumptionStrategy;
+import io.serverlessworkflow.api.types.AnyEventConsumptionStrategy;
+import io.serverlessworkflow.api.types.CorrelateProperty;
+import io.serverlessworkflow.api.types.EventFilter;
+import io.serverlessworkflow.api.types.EventFilterCorrelate;
+import io.serverlessworkflow.api.types.ListenTask;
+import io.serverlessworkflow.api.types.ListenTaskConfiguration;
+import io.serverlessworkflow.api.types.ListenTo;
+import io.serverlessworkflow.api.types.OneEventConsumptionStrategy;
+import java.util.List;
+import java.util.function.Consumer;
+
+/**
+ * Fluent builder for a "listen" task in a Serverless Workflow. Enforces exactly one consumption
+ * strategy: one, all, or any.
+ */
+public class ListenTaskBuilder extends TaskBaseBuilder {
+
+ private final ListenTask listenTask;
+ private final ListenTaskConfiguration config;
+ private boolean oneSet, allSet, anySet;
+
+ public ListenTaskBuilder() {
+ super();
+ this.listenTask = new ListenTask();
+ this.config = new ListenTaskConfiguration();
+ this.config.setTo(new ListenTo());
+ this.listenTask.setListen(config);
+ super.setTask(listenTask);
+ }
+
+ @Override
+ protected ListenTaskBuilder self() {
+ return this;
+ }
+
+ /** Consume exactly one matching event. */
+ public ListenTaskBuilder one(Consumer c) {
+ ensureNoneSet();
+ oneSet = true;
+ EventFilterBuilder fb = new EventFilterBuilder();
+ c.accept(fb);
+ OneEventConsumptionStrategy strat = new OneEventConsumptionStrategy();
+ strat.setOne(fb.build());
+ config.getTo().withOneEventConsumptionStrategy(strat);
+ return this;
+ }
+
+ /** Consume events only when *all* filters match. */
+ public ListenTaskBuilder all(Consumer c) {
+ ensureNoneSet();
+ allSet = true;
+ EventFilterBuilder fb = new EventFilterBuilder();
+ c.accept(fb);
+ AllEventConsumptionStrategy strat = new AllEventConsumptionStrategy();
+ strat.setAll(List.of(fb.build()));
+ config.getTo().withAllEventConsumptionStrategy(strat);
+ return this;
+ }
+
+ /** Consume events when *any* filter matches. */
+ public ListenTaskBuilder any(Consumer c) {
+ ensureNoneSet();
+ anySet = true;
+ EventFilterBuilder fb = new EventFilterBuilder();
+ c.accept(fb);
+ AnyEventConsumptionStrategy strat = new AnyEventConsumptionStrategy();
+ strat.setAny(List.of(fb.build()));
+ config.getTo().withAnyEventConsumptionStrategy(strat);
+ return this;
+ }
+
+ private void ensureNoneSet() {
+ if (oneSet || allSet || anySet) {
+ throw new IllegalStateException("Only one consumption strategy can be configured");
+ }
+ }
+
+ /** Validate and return the built ListenTask. */
+ public ListenTask build() {
+ if (!(oneSet || allSet || anySet)) {
+ throw new IllegalStateException(
+ "A consumption strategy (one, all, or any) must be configured");
+ }
+ return listenTask;
+ }
+
+ /** Builder for event filters used in consumption strategies. */
+ public static final class EventFilterBuilder {
+ private final EventFilter filter = new EventFilter();
+ private final EventFilterCorrelate correlate = new EventFilterCorrelate();
+
+ /** Predicate to match event properties. */
+ public EventFilterBuilder with(Consumer c) {
+ EventPropertiesBuilder pb = new EventPropertiesBuilder();
+ c.accept(pb);
+ filter.setWith(pb.build());
+ return this;
+ }
+
+ /** Correlation property for the filter. */
+ public EventFilterBuilder correlate(String key, Consumer c) {
+ CorrelatePropertyBuilder cpb = new CorrelatePropertyBuilder();
+ c.accept(cpb);
+ correlate.withAdditionalProperty(key, cpb.build());
+ return this;
+ }
+
+ public EventFilter build() {
+ filter.setCorrelate(correlate);
+ return filter;
+ }
+ }
+
+ public static final class CorrelatePropertyBuilder {
+ private final CorrelateProperty prop = new CorrelateProperty();
+
+ public CorrelatePropertyBuilder from(String expr) {
+ prop.setFrom(expr);
+ return this;
+ }
+
+ public CorrelatePropertyBuilder expect(String val) {
+ prop.setExpect(val);
+ return this;
+ }
+
+ public CorrelateProperty build() {
+ return prop;
+ }
+ }
+}
diff --git a/fluent/standard/src/main/java/io/serverlessworkflow/fluent/standard/OAuth2AuthenticationPolicyBuilder.java b/fluent/standard/src/main/java/io/serverlessworkflow/fluent/standard/OAuth2AuthenticationPolicyBuilder.java
new file mode 100644
index 00000000..7eac31b4
--- /dev/null
+++ b/fluent/standard/src/main/java/io/serverlessworkflow/fluent/standard/OAuth2AuthenticationPolicyBuilder.java
@@ -0,0 +1,57 @@
+/*
+ * 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.standard;
+
+import io.serverlessworkflow.api.types.OAuth2AuthenticationPolicy;
+import io.serverlessworkflow.api.types.OAuth2AuthenticationPolicyConfiguration;
+import io.serverlessworkflow.api.types.OAuth2ConnectAuthenticationProperties;
+import io.serverlessworkflow.api.types.Oauth2;
+import java.util.function.Consumer;
+
+public final class OAuth2AuthenticationPolicyBuilder
+ extends OIDCBuilder {
+
+ private final OAuth2ConnectAuthenticationProperties properties;
+
+ OAuth2AuthenticationPolicyBuilder() {
+ super();
+ this.properties = new OAuth2ConnectAuthenticationProperties();
+ }
+
+ public OAuth2AuthenticationPolicyBuilder endpoints(
+ Consumer endpointsConsumer) {
+ final OAuth2AuthenticationPropertiesEndpointsBuilder builder =
+ new OAuth2AuthenticationPropertiesEndpointsBuilder();
+ endpointsConsumer.accept(builder);
+ this.properties.setEndpoints(builder.build());
+ return this;
+ }
+
+ public OAuth2AuthenticationPolicy build() {
+ final OAuth2AuthenticationPolicyConfiguration configuration =
+ new OAuth2AuthenticationPolicyConfiguration();
+ configuration.setOAuth2AutenthicationData(this.getAuthenticationData());
+ configuration.setOAuth2ConnectAuthenticationProperties(this.properties);
+
+ final Oauth2 oauth2 = new Oauth2();
+ oauth2.setOAuth2ConnectAuthenticationProperties(configuration);
+
+ final OAuth2AuthenticationPolicy policy = new OAuth2AuthenticationPolicy();
+ policy.setOauth2(oauth2);
+
+ return policy;
+ }
+}
diff --git a/fluent/standard/src/main/java/io/serverlessworkflow/fluent/standard/OIDCBuilder.java b/fluent/standard/src/main/java/io/serverlessworkflow/fluent/standard/OIDCBuilder.java
new file mode 100644
index 00000000..e757de8f
--- /dev/null
+++ b/fluent/standard/src/main/java/io/serverlessworkflow/fluent/standard/OIDCBuilder.java
@@ -0,0 +1,190 @@
+/*
+ * 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.standard;
+
+import io.serverlessworkflow.api.types.AuthenticationPolicy;
+import io.serverlessworkflow.api.types.OAuth2AutenthicationData;
+import io.serverlessworkflow.api.types.OAuth2AutenthicationDataClient;
+import io.serverlessworkflow.api.types.OAuth2AuthenticationPropertiesEndpoints;
+import io.serverlessworkflow.api.types.OAuth2TokenDefinition;
+import io.serverlessworkflow.api.types.OAuth2TokenRequest;
+import java.util.List;
+import java.util.function.Consumer;
+
+public abstract class OIDCBuilder {
+ private final OAuth2AutenthicationData authenticationData;
+
+ OIDCBuilder() {
+ this.authenticationData = new OAuth2AutenthicationData();
+ this.authenticationData.setRequest(new OAuth2TokenRequest());
+ }
+
+ public OIDCBuilder authority(String authority) {
+ this.authenticationData.setAuthority(UriTemplateBuilder.newUriTemplate(authority));
+ return this;
+ }
+
+ public OIDCBuilder grant(OAuth2AutenthicationData.OAuth2AutenthicationDataGrant grant) {
+ this.authenticationData.setGrant(grant);
+ return this;
+ }
+
+ public OIDCBuilder issuers(String... issuers) {
+ if (issuers != null) {
+ this.authenticationData.setIssuers(List.of(issuers));
+ }
+ return this;
+ }
+
+ public OIDCBuilder scopes(String... scopes) {
+ if (scopes != null) {
+ this.authenticationData.setScopes(List.of(scopes));
+ }
+ return this;
+ }
+
+ public OIDCBuilder audiences(String... audiences) {
+ if (audiences != null) {
+ this.authenticationData.setAudiences(List.of(audiences));
+ }
+ return this;
+ }
+
+ public OIDCBuilder username(String username) {
+ this.authenticationData.setUsername(username);
+ return this;
+ }
+
+ public OIDCBuilder password(String password) {
+ this.authenticationData.setPassword(password);
+ return this;
+ }
+
+ public OIDCBuilder requestEncoding(OAuth2TokenRequest.Oauth2TokenRequestEncoding encoding) {
+ this.authenticationData.setRequest(new OAuth2TokenRequest().withEncoding(encoding));
+ return this;
+ }
+
+ public OIDCBuilder subject(Consumer subjectConsumer) {
+ final OAuth2TokenDefinitionBuilder builder = new OAuth2TokenDefinitionBuilder();
+ subjectConsumer.accept(builder);
+ this.authenticationData.setSubject(builder.build());
+ return this;
+ }
+
+ public OIDCBuilder actor(Consumer actorConsumer) {
+ final OAuth2TokenDefinitionBuilder builder = new OAuth2TokenDefinitionBuilder();
+ actorConsumer.accept(builder);
+ this.authenticationData.setActor(builder.build());
+ return this;
+ }
+
+ public OIDCBuilder client(Consumer clientConsumer) {
+ final OAuth2AuthenticationDataClientBuilder builder =
+ new OAuth2AuthenticationDataClientBuilder();
+ clientConsumer.accept(builder);
+ this.authenticationData.setClient(builder.build());
+ return this;
+ }
+
+ protected final OAuth2AutenthicationData getAuthenticationData() {
+ return authenticationData;
+ }
+
+ public abstract T build();
+
+ public static final class OAuth2TokenDefinitionBuilder {
+ private final OAuth2TokenDefinition oauth2TokenDefinition;
+
+ OAuth2TokenDefinitionBuilder() {
+ this.oauth2TokenDefinition = new OAuth2TokenDefinition();
+ }
+
+ public OAuth2TokenDefinitionBuilder token(String token) {
+ this.oauth2TokenDefinition.setToken(token);
+ return this;
+ }
+
+ public OAuth2TokenDefinitionBuilder type(String type) {
+ this.oauth2TokenDefinition.setType(type);
+ return this;
+ }
+
+ public OAuth2TokenDefinition build() {
+ return this.oauth2TokenDefinition;
+ }
+ }
+
+ public static final class OAuth2AuthenticationDataClientBuilder {
+ private final OAuth2AutenthicationDataClient client;
+
+ OAuth2AuthenticationDataClientBuilder() {
+ this.client = new OAuth2AutenthicationDataClient();
+ }
+
+ public OAuth2AuthenticationDataClientBuilder id(String id) {
+ this.client.setId(id);
+ return this;
+ }
+
+ public OAuth2AuthenticationDataClientBuilder secret(String secret) {
+ this.client.setSecret(secret);
+ return this;
+ }
+
+ public OAuth2AuthenticationDataClientBuilder assertion(String assertion) {
+ this.client.setAssertion(assertion);
+ return this;
+ }
+
+ public OAuth2AuthenticationDataClientBuilder authentication(
+ OAuth2AutenthicationDataClient.ClientAuthentication authentication) {
+ this.client.setAuthentication(authentication);
+ return this;
+ }
+
+ public OAuth2AutenthicationDataClient build() {
+ return this.client;
+ }
+ }
+
+ public static final class OAuth2AuthenticationPropertiesEndpointsBuilder {
+ private final OAuth2AuthenticationPropertiesEndpoints endpoints;
+
+ OAuth2AuthenticationPropertiesEndpointsBuilder() {
+ endpoints = new OAuth2AuthenticationPropertiesEndpoints();
+ }
+
+ public OAuth2AuthenticationPropertiesEndpointsBuilder token(String token) {
+ this.endpoints.setToken(token);
+ return this;
+ }
+
+ public OAuth2AuthenticationPropertiesEndpointsBuilder revocation(String revocation) {
+ this.endpoints.setRevocation(revocation);
+ return this;
+ }
+
+ public OAuth2AuthenticationPropertiesEndpointsBuilder introspection(String introspection) {
+ this.endpoints.setIntrospection(introspection);
+ return this;
+ }
+
+ public OAuth2AuthenticationPropertiesEndpoints build() {
+ return this.endpoints;
+ }
+ }
+}
diff --git a/fluent/standard/src/main/java/io/serverlessworkflow/fluent/standard/OpenIdConnectAuthenticationPolicyBuilder.java b/fluent/standard/src/main/java/io/serverlessworkflow/fluent/standard/OpenIdConnectAuthenticationPolicyBuilder.java
new file mode 100644
index 00000000..98b9152b
--- /dev/null
+++ b/fluent/standard/src/main/java/io/serverlessworkflow/fluent/standard/OpenIdConnectAuthenticationPolicyBuilder.java
@@ -0,0 +1,36 @@
+/*
+ * 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.standard;
+
+import io.serverlessworkflow.api.types.OpenIdConnectAuthenticationPolicy;
+import io.serverlessworkflow.api.types.OpenIdConnectAuthenticationPolicyConfiguration;
+
+public final class OpenIdConnectAuthenticationPolicyBuilder
+ extends OIDCBuilder {
+
+ OpenIdConnectAuthenticationPolicyBuilder() {
+ super();
+ }
+
+ public OpenIdConnectAuthenticationPolicy build() {
+ final OpenIdConnectAuthenticationPolicyConfiguration configuration =
+ new OpenIdConnectAuthenticationPolicyConfiguration();
+ configuration.setOpenIdConnectAuthenticationProperties(this.getAuthenticationData());
+ final OpenIdConnectAuthenticationPolicy policy = new OpenIdConnectAuthenticationPolicy();
+ policy.setOidc(configuration);
+ return policy;
+ }
+}
diff --git a/fluent/standard/src/main/java/io/serverlessworkflow/fluent/standard/OutputBuilder.java b/fluent/standard/src/main/java/io/serverlessworkflow/fluent/standard/OutputBuilder.java
new file mode 100644
index 00000000..797f8872
--- /dev/null
+++ b/fluent/standard/src/main/java/io/serverlessworkflow/fluent/standard/OutputBuilder.java
@@ -0,0 +1,67 @@
+/*
+ * 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.standard;
+
+import io.serverlessworkflow.api.types.Endpoint;
+import io.serverlessworkflow.api.types.ExternalResource;
+import io.serverlessworkflow.api.types.Output;
+import io.serverlessworkflow.api.types.OutputAs;
+import io.serverlessworkflow.api.types.SchemaExternal;
+import io.serverlessworkflow.api.types.SchemaInline;
+import io.serverlessworkflow.api.types.SchemaUnion;
+
+public class OutputBuilder {
+
+ private final Output output;
+
+ OutputBuilder() {
+ this.output = new Output();
+ this.output.setAs(new OutputAs());
+ this.output.setSchema(new SchemaUnion());
+ }
+
+ public OutputBuilder as(final String expr) {
+ this.output.getAs().setString(expr);
+ return this;
+ }
+
+ public OutputBuilder as(final Object object) {
+ this.output.getAs().setObject(object);
+ return this;
+ }
+
+ public OutputBuilder schema(final String schema) {
+ this.output
+ .getSchema()
+ .setSchemaExternal(
+ new SchemaExternal()
+ .withResource(
+ new ExternalResource()
+ .withEndpoint(
+ new Endpoint()
+ .withUriTemplate(UriTemplateBuilder.newUriTemplate(schema)))));
+ return this;
+ }
+
+ public OutputBuilder schema(final Object schema) {
+ this.output.getSchema().setSchemaInline(new SchemaInline(schema));
+ return this;
+ }
+
+ public Output build() {
+ return this.output;
+ }
+}
diff --git a/fluent/standard/src/main/java/io/serverlessworkflow/fluent/standard/RaiseTaskBuilder.java b/fluent/standard/src/main/java/io/serverlessworkflow/fluent/standard/RaiseTaskBuilder.java
new file mode 100644
index 00000000..f2d370e9
--- /dev/null
+++ b/fluent/standard/src/main/java/io/serverlessworkflow/fluent/standard/RaiseTaskBuilder.java
@@ -0,0 +1,101 @@
+/*
+ * 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.standard;
+
+import io.serverlessworkflow.api.types.ErrorDetails;
+import io.serverlessworkflow.api.types.ErrorTitle;
+import io.serverlessworkflow.api.types.ErrorType;
+import io.serverlessworkflow.api.types.RaiseTask;
+import io.serverlessworkflow.api.types.RaiseTaskConfiguration;
+import io.serverlessworkflow.api.types.RaiseTaskError;
+import io.serverlessworkflow.api.types.UriTemplate;
+import java.net.URI;
+import java.util.function.Consumer;
+
+public class RaiseTaskBuilder extends TaskBaseBuilder {
+
+ private final RaiseTask raiseTask;
+
+ RaiseTaskBuilder() {
+ this.raiseTask = new RaiseTask();
+ setTask(raiseTask);
+ }
+
+ @Override
+ protected RaiseTaskBuilder self() {
+ return this;
+ }
+
+ public RaiseTaskBuilder error(Consumer consumer) {
+ final RaiseTaskErrorBuilder raiseTaskErrorBuilder = new RaiseTaskErrorBuilder();
+ consumer.accept(raiseTaskErrorBuilder);
+ this.raiseTask.setRaise(new RaiseTaskConfiguration().withError(raiseTaskErrorBuilder.build()));
+ return this;
+ }
+
+ // TODO: validation, one or the other
+
+ public RaiseTaskBuilder error(String errorReference) {
+ this.raiseTask.setRaise(
+ new RaiseTaskConfiguration()
+ .withError(new RaiseTaskError().withRaiseErrorReference(errorReference)));
+ return this;
+ }
+
+ public RaiseTask build() {
+ return this.raiseTask;
+ }
+
+ public static final class RaiseTaskErrorBuilder {
+ private final io.serverlessworkflow.api.types.Error error;
+
+ private RaiseTaskErrorBuilder() {
+ this.error = new io.serverlessworkflow.api.types.Error();
+ }
+
+ public RaiseTaskErrorBuilder type(String expression) {
+ this.error.setType(new ErrorType().withExpressionErrorType(expression));
+ return this;
+ }
+
+ public RaiseTaskErrorBuilder type(URI errorType) {
+ this.error.setType(
+ new ErrorType().withLiteralErrorType(new UriTemplate().withLiteralUri(errorType)));
+ return this;
+ }
+
+ public RaiseTaskErrorBuilder status(int status) {
+ this.error.setStatus(status);
+ return this;
+ }
+
+ // TODO: change signature to Expression interface since literal and expressions are String
+
+ public RaiseTaskErrorBuilder title(String expression) {
+ this.error.setTitle(new ErrorTitle().withExpressionErrorTitle(expression));
+ return this;
+ }
+
+ public RaiseTaskErrorBuilder detail(String expression) {
+ this.error.setDetail(new ErrorDetails().withExpressionErrorDetails(expression));
+ return this;
+ }
+
+ public RaiseTaskError build() {
+ return new RaiseTaskError().withRaiseErrorDefinition(this.error);
+ }
+ }
+}
diff --git a/fluent/standard/src/main/java/io/serverlessworkflow/fluent/standard/SetTaskBuilder.java b/fluent/standard/src/main/java/io/serverlessworkflow/fluent/standard/SetTaskBuilder.java
new file mode 100644
index 00000000..6c43ddfc
--- /dev/null
+++ b/fluent/standard/src/main/java/io/serverlessworkflow/fluent/standard/SetTaskBuilder.java
@@ -0,0 +1,55 @@
+/*
+ * 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.standard;
+
+import io.serverlessworkflow.api.types.Set;
+import io.serverlessworkflow.api.types.SetTask;
+import io.serverlessworkflow.api.types.SetTaskConfiguration;
+
+public class SetTaskBuilder extends TaskBaseBuilder {
+
+ private final SetTask setTask;
+ private final SetTaskConfiguration setTaskConfiguration;
+
+ SetTaskBuilder() {
+ this.setTask = new SetTask();
+ this.setTaskConfiguration = new SetTaskConfiguration();
+ this.setTask(setTask);
+ }
+
+ @Override
+ protected SetTaskBuilder self() {
+ return this;
+ }
+
+ public SetTaskBuilder expr(String expression) {
+ this.setTask.setSet(new Set().withString(expression));
+ return this;
+ }
+
+ public SetTaskBuilder put(String key, String value) {
+ setTaskConfiguration.withAdditionalProperty(key, value);
+ return this;
+ }
+
+ public SetTask build() {
+ if (this.setTask.getSet() == null) {
+ this.setTask.setSet(new Set().withSetTaskConfiguration(setTaskConfiguration));
+ }
+
+ return setTask;
+ }
+}
diff --git a/fluent/standard/src/main/java/io/serverlessworkflow/fluent/standard/SwitchTaskBuilder.java b/fluent/standard/src/main/java/io/serverlessworkflow/fluent/standard/SwitchTaskBuilder.java
new file mode 100644
index 00000000..12e027ee
--- /dev/null
+++ b/fluent/standard/src/main/java/io/serverlessworkflow/fluent/standard/SwitchTaskBuilder.java
@@ -0,0 +1,76 @@
+/*
+ * 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.standard;
+
+import io.serverlessworkflow.api.types.SwitchCase;
+import io.serverlessworkflow.api.types.SwitchItem;
+import io.serverlessworkflow.api.types.SwitchTask;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Consumer;
+
+public class SwitchTaskBuilder extends TaskBaseBuilder {
+
+ private final SwitchTask switchTask;
+ private final List switchItems;
+
+ SwitchTaskBuilder() {
+ super();
+ this.switchTask = new SwitchTask();
+ this.switchItems = new ArrayList<>();
+ this.setTask(switchTask);
+ }
+
+ @Override
+ protected SwitchTaskBuilder self() {
+ return this;
+ }
+
+ public SwitchTaskBuilder switchTask(
+ final String name, Consumer switchCaseConsumer) {
+ final SwitchCaseBuilder switchCaseBuilder = new SwitchCaseBuilder();
+ switchCaseConsumer.accept(switchCaseBuilder);
+ this.switchItems.add(new SwitchItem(name, switchCaseBuilder.build()));
+ return this;
+ }
+
+ public SwitchTask build() {
+ this.switchTask.setSwitch(this.switchItems);
+ return this.switchTask;
+ }
+
+ public static final class SwitchCaseBuilder {
+ private final SwitchCase switchCase;
+
+ SwitchCaseBuilder() {
+ this.switchCase = new SwitchCase();
+ }
+
+ public SwitchCaseBuilder when(String when) {
+ this.switchCase.setWhen(when);
+ return this;
+ }
+
+ public SwitchCaseBuilder then(String then) {
+ this.switchCase.setWhen(then);
+ return this;
+ }
+
+ public SwitchCase build() {
+ return this.switchCase;
+ }
+ }
+}
diff --git a/fluent/standard/src/main/java/io/serverlessworkflow/fluent/standard/TaskBaseBuilder.java b/fluent/standard/src/main/java/io/serverlessworkflow/fluent/standard/TaskBaseBuilder.java
new file mode 100644
index 00000000..31d30b3f
--- /dev/null
+++ b/fluent/standard/src/main/java/io/serverlessworkflow/fluent/standard/TaskBaseBuilder.java
@@ -0,0 +1,120 @@
+/*
+ * 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.standard;
+
+import io.serverlessworkflow.api.types.Endpoint;
+import io.serverlessworkflow.api.types.Export;
+import io.serverlessworkflow.api.types.ExportAs;
+import io.serverlessworkflow.api.types.ExternalResource;
+import io.serverlessworkflow.api.types.FlowDirective;
+import io.serverlessworkflow.api.types.FlowDirectiveEnum;
+import io.serverlessworkflow.api.types.SchemaExternal;
+import io.serverlessworkflow.api.types.SchemaInline;
+import io.serverlessworkflow.api.types.SchemaUnion;
+import io.serverlessworkflow.api.types.TaskBase;
+import java.util.function.Consumer;
+
+public abstract class TaskBaseBuilder> {
+ protected abstract T self();
+
+ private TaskBase task;
+
+ protected TaskBaseBuilder() {}
+
+ protected void setTask(TaskBase task) {
+ this.task = task;
+ }
+
+ public T _if(String id) {
+ this.task.setIf(id);
+ return self();
+ }
+
+ public T then(FlowDirectiveEnum then) {
+ this.task.setThen(new FlowDirective().withFlowDirectiveEnum(then));
+ return self();
+ }
+
+ public T exportAs(Object exportAs) {
+ this.task.setExport(new ExportBuilder().as(exportAs).build());
+ return self();
+ }
+
+ public T export(Consumer exportConsumer) {
+ final ExportBuilder exportBuilder = new ExportBuilder();
+ exportConsumer.accept(exportBuilder);
+ this.task.setExport(exportBuilder.build());
+ return self();
+ }
+
+ public T input(Consumer inputConsumer) {
+ final InputBuilder inputBuilder = new InputBuilder();
+ inputConsumer.accept(inputBuilder);
+ this.task.setInput(inputBuilder.build());
+ return self();
+ }
+
+ public T output(Consumer outputConsumer) {
+ final OutputBuilder outputBuilder = new OutputBuilder();
+ outputConsumer.accept(outputBuilder);
+ this.task.setOutput(outputBuilder.build());
+ return self();
+ }
+
+ // TODO: add timeout, metadata
+
+ public static final class ExportBuilder {
+ private final Export export;
+
+ public ExportBuilder() {
+ this.export = new Export();
+ this.export.setAs(new ExportAs());
+ this.export.setSchema(new SchemaUnion());
+ }
+
+ public ExportBuilder as(Object as) {
+ this.export.getAs().withObject(as);
+ return this;
+ }
+
+ public ExportBuilder as(String as) {
+ this.export.getAs().withString(as);
+ return this;
+ }
+
+ public ExportBuilder schema(String schema) {
+ this.export
+ .getSchema()
+ .setSchemaExternal(
+ new SchemaExternal()
+ .withResource(
+ new ExternalResource()
+ .withEndpoint(
+ new Endpoint()
+ .withUriTemplate(UriTemplateBuilder.newUriTemplate(schema)))));
+ return this;
+ }
+
+ public ExportBuilder schema(Object schema) {
+ this.export.getSchema().setSchemaInline(new SchemaInline(schema));
+ return this;
+ }
+
+ public Export build() {
+ return this.export;
+ }
+ }
+}
diff --git a/fluent/standard/src/main/java/io/serverlessworkflow/fluent/standard/TryTaskBuilder.java b/fluent/standard/src/main/java/io/serverlessworkflow/fluent/standard/TryTaskBuilder.java
new file mode 100644
index 00000000..2e022503
--- /dev/null
+++ b/fluent/standard/src/main/java/io/serverlessworkflow/fluent/standard/TryTaskBuilder.java
@@ -0,0 +1,338 @@
+/*
+ * 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.standard;
+
+import io.serverlessworkflow.api.types.CatchErrors;
+import io.serverlessworkflow.api.types.Constant;
+import io.serverlessworkflow.api.types.ConstantBackoff;
+import io.serverlessworkflow.api.types.ErrorFilter;
+import io.serverlessworkflow.api.types.Exponential;
+import io.serverlessworkflow.api.types.ExponentialBackOff;
+import io.serverlessworkflow.api.types.Linear;
+import io.serverlessworkflow.api.types.LinearBackoff;
+import io.serverlessworkflow.api.types.Retry;
+import io.serverlessworkflow.api.types.RetryBackoff;
+import io.serverlessworkflow.api.types.RetryLimit;
+import io.serverlessworkflow.api.types.RetryLimitAttempt;
+import io.serverlessworkflow.api.types.RetryPolicy;
+import io.serverlessworkflow.api.types.RetryPolicyJitter;
+import io.serverlessworkflow.api.types.TimeoutAfter;
+import io.serverlessworkflow.api.types.TryTask;
+import io.serverlessworkflow.api.types.TryTaskCatch;
+import java.util.function.Consumer;
+
+public class TryTaskBuilder extends TaskBaseBuilder {
+
+ private final TryTask tryTask;
+
+ TryTaskBuilder() {
+ this.tryTask = new TryTask();
+ }
+
+ @Override
+ protected TryTaskBuilder self() {
+ return this;
+ }
+
+ public TryTaskBuilder tryHandler(Consumer consumer) {
+ final DoTaskBuilder doTaskBuilder = new DoTaskBuilder();
+ consumer.accept(doTaskBuilder);
+ this.tryTask.setTry(doTaskBuilder.build().getDo());
+ return this;
+ }
+
+ public TryTaskBuilder catchHandler(Consumer consumer) {
+ final TryTaskCatchBuilder catchBuilder = new TryTaskCatchBuilder();
+ consumer.accept(catchBuilder);
+ this.tryTask.setCatch(catchBuilder.build());
+ return this;
+ }
+
+ public TryTask build() {
+ return tryTask;
+ }
+
+ public static final class TryTaskCatchBuilder {
+ private final TryTaskCatch tryTaskCatch;
+
+ TryTaskCatchBuilder() {
+ this.tryTaskCatch = new TryTaskCatch();
+ }
+
+ public TryTaskCatchBuilder as(final String as) {
+ this.tryTaskCatch.setAs(as);
+ return this;
+ }
+
+ public TryTaskCatchBuilder when(final String when) {
+ this.tryTaskCatch.setWhen(when);
+ return this;
+ }
+
+ public TryTaskCatchBuilder exceptWhen(final String exceptWhen) {
+ this.tryTaskCatch.setExceptWhen(exceptWhen);
+ return this;
+ }
+
+ public TryTaskCatchBuilder retry(Consumer consumer) {
+ final RetryPolicyBuilder retryPolicyBuilder = new RetryPolicyBuilder();
+ consumer.accept(retryPolicyBuilder);
+ this.tryTaskCatch.setRetry(new Retry().withRetryPolicyDefinition(retryPolicyBuilder.build()));
+ return this;
+ }
+
+ public TryTaskCatchBuilder errorsWith(Consumer consumer) {
+ final CatchErrorsBuilder catchErrorsBuilder = new CatchErrorsBuilder();
+ consumer.accept(catchErrorsBuilder);
+ this.tryTaskCatch.setErrors(catchErrorsBuilder.build());
+ return this;
+ }
+
+ public TryTaskCatch build() {
+ return tryTaskCatch;
+ }
+ }
+
+ public static final class CatchErrorsBuilder {
+ private final ErrorFilter errorFilter;
+
+ CatchErrorsBuilder() {
+ this.errorFilter = new ErrorFilter();
+ }
+
+ public CatchErrorsBuilder type(final String type) {
+ this.errorFilter.setType(type);
+ return this;
+ }
+
+ public CatchErrorsBuilder status(final int status) {
+ this.errorFilter.setStatus(status);
+ return this;
+ }
+
+ public CatchErrorsBuilder instance(final String instance) {
+ this.errorFilter.setInstance(instance);
+ return this;
+ }
+
+ public CatchErrorsBuilder title(final String title) {
+ this.errorFilter.setTitle(title);
+ return this;
+ }
+
+ public CatchErrorsBuilder details(final String details) {
+ this.errorFilter.setDetails(details);
+ return this;
+ }
+
+ public CatchErrors build() {
+ return new CatchErrors().withWith(this.errorFilter);
+ }
+ }
+
+ public static final class RetryPolicyJitterBuilder {
+ private final RetryPolicyJitter retryPolicyJitter;
+
+ RetryPolicyJitterBuilder() {
+ this.retryPolicyJitter = new RetryPolicyJitter();
+ }
+
+ public RetryPolicyJitter to(Consumer consumer) {
+ final DurationInlineBuilder durationInlineBuilder = new DurationInlineBuilder();
+ consumer.accept(durationInlineBuilder);
+ this.retryPolicyJitter.setTo(
+ new TimeoutAfter().withDurationInline(durationInlineBuilder.build()));
+ return retryPolicyJitter;
+ }
+
+ public RetryPolicyJitter to(String expression) {
+ this.retryPolicyJitter.setTo(new TimeoutAfter().withDurationExpression(expression));
+ return retryPolicyJitter;
+ }
+
+ public RetryPolicyJitter from(Consumer consumer) {
+ final DurationInlineBuilder durationInlineBuilder = new DurationInlineBuilder();
+ consumer.accept(durationInlineBuilder);
+ this.retryPolicyJitter.setFrom(
+ new TimeoutAfter().withDurationInline(durationInlineBuilder.build()));
+ return retryPolicyJitter;
+ }
+
+ public RetryPolicyJitter from(String expression) {
+ this.retryPolicyJitter.setFrom(new TimeoutAfter().withDurationExpression(expression));
+ return retryPolicyJitter;
+ }
+
+ public RetryPolicyJitter build() {
+ return retryPolicyJitter;
+ }
+ }
+
+ public static final class RetryPolicyBuilder {
+ private final RetryPolicy retryPolicy;
+
+ RetryPolicyBuilder() {
+ this.retryPolicy = new RetryPolicy();
+ }
+
+ public RetryPolicyBuilder when(final String when) {
+ this.retryPolicy.setWhen(when);
+ return this;
+ }
+
+ public RetryPolicyBuilder exceptWhen(final String exceptWhen) {
+ this.retryPolicy.setExceptWhen(exceptWhen);
+ return this;
+ }
+
+ public RetryPolicyBuilder backoff(Consumer consumer) {
+ final BackoffBuilder backoffBuilder = new BackoffBuilder();
+ consumer.accept(backoffBuilder);
+ this.retryPolicy.setBackoff(backoffBuilder.build());
+ return this;
+ }
+
+ public RetryPolicyBuilder delay(Consumer consumer) {
+ final DurationInlineBuilder builder = new DurationInlineBuilder();
+ consumer.accept(builder);
+ this.retryPolicy.setDelay(new TimeoutAfter().withDurationInline(builder.build()));
+ return this;
+ }
+
+ public RetryPolicyBuilder delay(String expression) {
+ this.retryPolicy.setDelay(new TimeoutAfter().withDurationExpression(expression));
+ return this;
+ }
+
+ public RetryPolicyBuilder limit(Consumer consumer) {
+ final RetryLimitBuilder limitBuilder = new RetryLimitBuilder();
+ consumer.accept(limitBuilder);
+ this.retryPolicy.setLimit(limitBuilder.build());
+ return this;
+ }
+
+ public RetryPolicyBuilder jitter(Consumer consumer) {
+ final RetryPolicyJitterBuilder jitterBuilder = new RetryPolicyJitterBuilder();
+ consumer.accept(jitterBuilder);
+ this.retryPolicy.setJitter(jitterBuilder.build());
+ return this;
+ }
+
+ public RetryPolicy build() {
+ return this.retryPolicy;
+ }
+ }
+
+ public static final class RetryLimitBuilder {
+ private final RetryLimit retryLimit;
+
+ RetryLimitBuilder() {
+ this.retryLimit = new RetryLimit();
+ }
+
+ public RetryLimitBuilder duration(Consumer consumer) {
+ final DurationInlineBuilder builder = new DurationInlineBuilder();
+ consumer.accept(builder);
+ this.retryLimit.setDuration(new TimeoutAfter().withDurationInline(builder.build()));
+ return this;
+ }
+
+ public RetryLimitBuilder duration(String expression) {
+ this.retryLimit.setDuration(new TimeoutAfter().withDurationExpression(expression));
+ return this;
+ }
+
+ public RetryLimitBuilder attempt(Consumer consumer) {
+ final RetryLimitAttemptBuilder retryLimitAttemptBuilder = new RetryLimitAttemptBuilder();
+ consumer.accept(retryLimitAttemptBuilder);
+ this.retryLimit.setAttempt(retryLimitAttemptBuilder.build());
+ return this;
+ }
+
+ public RetryLimit build() {
+ return this.retryLimit;
+ }
+ }
+
+ public static final class RetryLimitAttemptBuilder {
+ private final RetryLimitAttempt retryLimitAttempt;
+
+ RetryLimitAttemptBuilder() {
+ this.retryLimitAttempt = new RetryLimitAttempt();
+ }
+
+ public RetryLimitAttemptBuilder count(int count) {
+ this.retryLimitAttempt.setCount(count);
+ return this;
+ }
+
+ public RetryLimitAttemptBuilder duration(Consumer consumer) {
+ final DurationInlineBuilder builder = new DurationInlineBuilder();
+ consumer.accept(builder);
+ this.retryLimitAttempt.setDuration(new TimeoutAfter().withDurationInline(builder.build()));
+ return this;
+ }
+
+ public RetryLimitAttemptBuilder duration(String expression) {
+ this.retryLimitAttempt.setDuration(new TimeoutAfter().withDurationExpression(expression));
+ return this;
+ }
+
+ public RetryLimitAttempt build() {
+ return this.retryLimitAttempt;
+ }
+ }
+
+ public static final class BackoffBuilder {
+ private final RetryBackoff retryBackoff;
+ private final ConstantBackoff constantBackoff;
+ private final ExponentialBackOff exponentialBackOff;
+ private final LinearBackoff linearBackoff;
+
+ BackoffBuilder() {
+ this.retryBackoff = new RetryBackoff();
+
+ this.constantBackoff = new ConstantBackoff();
+ this.constantBackoff.setConstant(new Constant());
+ this.exponentialBackOff = new ExponentialBackOff();
+ this.exponentialBackOff.setExponential(new Exponential());
+ this.linearBackoff = new LinearBackoff();
+ this.linearBackoff.setLinear(new Linear());
+ }
+
+ public BackoffBuilder constant(String key, String value) {
+ this.constantBackoff.getConstant().withAdditionalProperty(key, value);
+ return this;
+ }
+
+ public BackoffBuilder exponential(String key, String value) {
+ this.exponentialBackOff.getExponential().withAdditionalProperty(key, value);
+ return this;
+ }
+
+ public BackoffBuilder linear(String key, String value) {
+ this.linearBackoff.getLinear().withAdditionalProperty(key, value);
+ return this;
+ }
+
+ public RetryBackoff build() {
+ this.retryBackoff.setConstantBackoff(constantBackoff);
+ this.retryBackoff.setExponentialBackOff(exponentialBackOff);
+ this.retryBackoff.setLinearBackoff(linearBackoff);
+ return this.retryBackoff;
+ }
+ }
+}
diff --git a/fluent/standard/src/main/java/io/serverlessworkflow/fluent/standard/UriTemplateBuilder.java b/fluent/standard/src/main/java/io/serverlessworkflow/fluent/standard/UriTemplateBuilder.java
new file mode 100644
index 00000000..da95f6b7
--- /dev/null
+++ b/fluent/standard/src/main/java/io/serverlessworkflow/fluent/standard/UriTemplateBuilder.java
@@ -0,0 +1,31 @@
+/*
+ * 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.standard;
+
+import io.serverlessworkflow.api.types.UriTemplate;
+import java.net.URI;
+import java.net.URISyntaxException;
+
+public final class UriTemplateBuilder {
+
+ public static UriTemplate newUriTemplate(String uri) {
+ try {
+ return new UriTemplate().withLiteralUri(new URI(uri));
+ } catch (URISyntaxException e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/fluent/standard/src/main/java/io/serverlessworkflow/fluent/standard/UseAuthenticationsBuilder.java b/fluent/standard/src/main/java/io/serverlessworkflow/fluent/standard/UseAuthenticationsBuilder.java
new file mode 100644
index 00000000..f24fec2f
--- /dev/null
+++ b/fluent/standard/src/main/java/io/serverlessworkflow/fluent/standard/UseAuthenticationsBuilder.java
@@ -0,0 +1,40 @@
+/*
+ * 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.standard;
+
+import io.serverlessworkflow.api.types.UseAuthentications;
+import java.util.function.Consumer;
+
+public class UseAuthenticationsBuilder {
+
+ private final UseAuthentications authentication;
+
+ UseAuthenticationsBuilder() {
+ this.authentication = new UseAuthentications();
+ }
+
+ public UseAuthenticationsBuilder authentication(
+ String name, Consumer authenticationConsumer) {
+ final AuthenticationPolicyUnionBuilder builder = new AuthenticationPolicyUnionBuilder();
+ authenticationConsumer.accept(builder);
+ this.authentication.setAdditionalProperty(name, builder.build());
+ return this;
+ }
+
+ public UseAuthentications build() {
+ return authentication;
+ }
+}
diff --git a/fluent/standard/src/main/java/io/serverlessworkflow/fluent/standard/UseBuilder.java b/fluent/standard/src/main/java/io/serverlessworkflow/fluent/standard/UseBuilder.java
new file mode 100644
index 00000000..5b4dd836
--- /dev/null
+++ b/fluent/standard/src/main/java/io/serverlessworkflow/fluent/standard/UseBuilder.java
@@ -0,0 +1,49 @@
+/*
+ * 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.standard;
+
+import io.serverlessworkflow.api.types.Use;
+import java.util.List;
+import java.util.function.Consumer;
+
+public class UseBuilder {
+
+ private final Use use;
+
+ UseBuilder() {
+ this.use = new Use();
+ }
+
+ public UseBuilder secrets(final String... secrets) {
+ if (secrets != null) {
+ this.use.setSecrets(List.of(secrets));
+ }
+ return this;
+ }
+
+ public UseBuilder authentications(Consumer authenticationsConsumer) {
+ final UseAuthenticationsBuilder builder = new UseAuthenticationsBuilder();
+ authenticationsConsumer.accept(builder);
+ this.use.setAuthentications(builder.build());
+ return this;
+ }
+
+ // TODO: implement the remaining `use` attributes
+
+ public Use build() {
+ return use;
+ }
+}
diff --git a/fluent/standard/src/main/java/io/serverlessworkflow/fluent/standard/WorkflowBuilder.java b/fluent/standard/src/main/java/io/serverlessworkflow/fluent/standard/WorkflowBuilder.java
new file mode 100644
index 00000000..742b5761
--- /dev/null
+++ b/fluent/standard/src/main/java/io/serverlessworkflow/fluent/standard/WorkflowBuilder.java
@@ -0,0 +1,96 @@
+/*
+ * 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.standard;
+
+import io.serverlessworkflow.api.types.Document;
+import io.serverlessworkflow.api.types.Workflow;
+import java.util.UUID;
+import java.util.function.Consumer;
+
+public class WorkflowBuilder {
+
+ private static final String DSL = "1.0.0";
+ private static final String DEFAULT_VERSION = "0.0.1";
+ private static final String DEFAULT_NAMESPACE = "org.acme";
+
+ private final Workflow workflow;
+ private final Document document;
+
+ private WorkflowBuilder(final String name, final String namespace, final String version) {
+ this.document = new Document();
+ this.document.setName(name);
+ this.document.setNamespace(namespace);
+ this.document.setVersion(version);
+ this.document.setDsl(DSL);
+ this.workflow = new Workflow();
+ this.workflow.setDocument(this.document);
+ }
+
+ public static WorkflowBuilder workflow(
+ final String name, final String namespace, final String version) {
+ return new WorkflowBuilder(name, namespace, version);
+ }
+
+ public static WorkflowBuilder workflow(final String name, final String namespace) {
+ return new WorkflowBuilder(name, namespace, DEFAULT_VERSION);
+ }
+
+ public static WorkflowBuilder workflow(final String name) {
+ return new WorkflowBuilder(name, DEFAULT_NAMESPACE, DEFAULT_VERSION);
+ }
+
+ public static WorkflowBuilder workflow() {
+ return new WorkflowBuilder(UUID.randomUUID().toString(), DEFAULT_NAMESPACE, DEFAULT_VERSION);
+ }
+
+ public WorkflowBuilder document(Consumer documentBuilderConsumer) {
+ final DocumentBuilder documentBuilder = new DocumentBuilder(this.document);
+ documentBuilderConsumer.accept(documentBuilder);
+ return this;
+ }
+
+ public WorkflowBuilder use(Consumer useBuilderConsumer) {
+ final UseBuilder builder = new UseBuilder();
+ useBuilderConsumer.accept(builder);
+ this.workflow.setUse(builder.build());
+ return this;
+ }
+
+ public WorkflowBuilder doTasks(Consumer doTaskConsumer) {
+ final DoTaskBuilder doTaskBuilder = new DoTaskBuilder();
+ doTaskConsumer.accept(doTaskBuilder);
+ this.workflow.setDo(doTaskBuilder.build().getDo());
+ return this;
+ }
+
+ public WorkflowBuilder input(Consumer inputBuilderConsumer) {
+ final InputBuilder inputBuilder = new InputBuilder();
+ inputBuilderConsumer.accept(inputBuilder);
+ this.workflow.setInput(inputBuilder.build());
+ return this;
+ }
+
+ public WorkflowBuilder output(Consumer outputBuilderConsumer) {
+ final OutputBuilder outputBuilder = new OutputBuilder();
+ outputBuilderConsumer.accept(outputBuilder);
+ this.workflow.setOutput(outputBuilder.build());
+ return this;
+ }
+
+ public Workflow build() {
+ return this.workflow;
+ }
+}
diff --git a/fluent/standard/src/main/java/io/serverlessworkflow/fluent/standard/WorkflowBuilderConsumers.java b/fluent/standard/src/main/java/io/serverlessworkflow/fluent/standard/WorkflowBuilderConsumers.java
new file mode 100644
index 00000000..28652c5f
--- /dev/null
+++ b/fluent/standard/src/main/java/io/serverlessworkflow/fluent/standard/WorkflowBuilderConsumers.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.standard;
+
+import java.util.function.Consumer;
+
+public final class WorkflowBuilderConsumers {
+
+ private WorkflowBuilderConsumers() {}
+
+ public static Consumer authBasic(
+ final String username, final String password) {
+ return auth -> auth.basic(b -> b.username(username).password(password));
+ }
+
+ public static Consumer authBearer(final String token) {
+ return auth -> auth.bearer(b -> b.token(token));
+ }
+
+ public static Consumer authDigest(
+ final String username, final String password) {
+ return auth -> auth.digest(d -> d.username(username).password(password));
+ }
+}
diff --git a/fluent/standard/src/test/java/io/serverlessworkflow/fluent/standard/WorkflowBuilderTest.java b/fluent/standard/src/test/java/io/serverlessworkflow/fluent/standard/WorkflowBuilderTest.java
new file mode 100644
index 00000000..e29a27b9
--- /dev/null
+++ b/fluent/standard/src/test/java/io/serverlessworkflow/fluent/standard/WorkflowBuilderTest.java
@@ -0,0 +1,518 @@
+/*
+ * 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.standard;
+
+import static io.serverlessworkflow.fluent.standard.WorkflowBuilderConsumers.authBasic;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertInstanceOf;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import io.serverlessworkflow.api.types.AuthenticationPolicyUnion;
+import io.serverlessworkflow.api.types.CallHTTP;
+import io.serverlessworkflow.api.types.CatchErrors;
+import io.serverlessworkflow.api.types.Document;
+import io.serverlessworkflow.api.types.ErrorFilter;
+import io.serverlessworkflow.api.types.EventFilter;
+import io.serverlessworkflow.api.types.HTTPArguments;
+import io.serverlessworkflow.api.types.HTTPHeaders;
+import io.serverlessworkflow.api.types.HTTPQuery;
+import io.serverlessworkflow.api.types.ListenTask;
+import io.serverlessworkflow.api.types.OneEventConsumptionStrategy;
+import io.serverlessworkflow.api.types.RetryLimitAttempt;
+import io.serverlessworkflow.api.types.RetryPolicy;
+import io.serverlessworkflow.api.types.SetTask;
+import io.serverlessworkflow.api.types.TaskItem;
+import io.serverlessworkflow.api.types.TryTask;
+import io.serverlessworkflow.api.types.TryTaskCatch;
+import io.serverlessworkflow.api.types.Use;
+import io.serverlessworkflow.api.types.UseAuthentications;
+import io.serverlessworkflow.api.types.Workflow;
+import java.net.URI;
+import java.util.List;
+import java.util.Map;
+import org.junit.jupiter.api.Test;
+
+/** Unit tests for the fluent WorkflowBuilder API (using static consumers). */
+public class WorkflowBuilderTest {
+
+ @Test
+ void testWorkflowDocumentDefaults() {
+ // Use default name, namespace, version
+ Workflow wf = WorkflowBuilder.workflow().build();
+ assertNotNull(wf, "Workflow should not be null");
+ Document doc = wf.getDocument();
+ assertNotNull(doc, "Document should not be null");
+ assertEquals("org.acme", doc.getNamespace(), "Default namespace should be org.acme");
+ assertEquals("0.0.1", doc.getVersion(), "Default version should be 0.0.1");
+ assertEquals("1.0.0", doc.getDsl(), "DSL version should be set to 1.0.0");
+ assertNotNull(doc.getName(), "Name should be auto-generated");
+ }
+
+ @Test
+ void testWorkflowDocumentExplicit() {
+ Workflow wf =
+ WorkflowBuilder.workflow("myFlow", "myNs", "1.2.3")
+ .document(d -> d.dsl("1.0.0").namespace("myNs").name("myFlow").version("1.2.3"))
+ .build();
+
+ Document doc = wf.getDocument();
+ assertEquals("1.0.0", doc.getDsl());
+ assertEquals("myNs", doc.getNamespace());
+ assertEquals("myFlow", doc.getName());
+ assertEquals("1.2.3", doc.getVersion());
+ }
+
+ @Test
+ void testUseAuthenticationsBasic() {
+ Workflow wf =
+ WorkflowBuilder.workflow("flowAuth")
+ .use(
+ u ->
+ u.authentications(
+ a -> a.authentication("basicAuth", authBasic("admin", "pass"))))
+ .build();
+
+ Use use = wf.getUse();
+ assertNotNull(use, "Use must not be null");
+ UseAuthentications auths = use.getAuthentications();
+ assertNotNull(auths, "Authentications map must not be null");
+ AuthenticationPolicyUnion union = auths.getAdditionalProperties().get("basicAuth");
+ assertNotNull(union, "basicAuth policy should be present");
+ assertNotNull(union.getBasicAuthenticationPolicy(), "BasicAuthenticationPolicy should be set");
+ }
+
+ @Test
+ void testDoTaskSetAndForEach() {
+ Workflow wf =
+ WorkflowBuilder.workflow("flowDo")
+ .doTasks(
+ d ->
+ d.set("initCtx", "$.foo = 'bar'")
+ .forEach("item", f -> f.each("item").at("$.list")))
+ .build();
+
+ List items = wf.getDo();
+ assertNotNull(items, "Do list must not be null");
+ assertEquals(2, items.size(), "There should be two tasks");
+
+ TaskItem setItem = items.get(0);
+ assertEquals("initCtx", setItem.getName());
+ SetTask st = setItem.getTask().getSetTask();
+ assertNotNull(st, "SetTask should be present");
+ assertEquals("$.foo = 'bar'", st.getSet().getString());
+
+ TaskItem forItem = items.get(1);
+ assertEquals("item", forItem.getName());
+ assertNotNull(forItem.getTask().getForTask(), "ForTask should be present");
+ }
+
+ @Test
+ void testDoTaskMultipleTypes() {
+ Workflow wf =
+ WorkflowBuilder.workflow("flowMixed")
+ .doTasks(
+ d ->
+ d.set("init", s -> s.expr("$.init = true"))
+ .forEach("items", f -> f.each("item").in("$.list"))
+ .switchTask(
+ "choice",
+ sw -> {
+ // no-op configuration
+ })
+ .raise(
+ "alert",
+ r -> {
+ // no-op configuration
+ })
+ .fork(
+ "parallel",
+ f -> {
+ // no-op configuration
+ }))
+ .build();
+
+ List items = wf.getDo();
+ assertNotNull(items, "Do list must not be null");
+ assertEquals(5, items.size(), "There should be five tasks");
+
+ // set task
+ TaskItem setItem = items.get(0);
+ assertEquals("init", setItem.getName());
+ assertNotNull(setItem.getTask().getSetTask(), "SetTask should be present");
+
+ // forEach task
+ TaskItem forItem = items.get(1);
+ assertEquals("items", forItem.getName());
+ assertNotNull(forItem.getTask().getForTask(), "ForTask should be present");
+
+ // switchTask
+ TaskItem switchItem = items.get(2);
+ assertEquals("choice", switchItem.getName());
+ assertNotNull(switchItem.getTask().getSwitchTask(), "SwitchTask should be present");
+
+ // raise task
+ TaskItem raiseItem = items.get(3);
+ assertEquals("alert", raiseItem.getName());
+ assertNotNull(raiseItem.getTask().getRaiseTask(), "RaiseTask should be present");
+
+ // fork task
+ TaskItem forkItem = items.get(4);
+ assertEquals("parallel", forkItem.getName());
+ assertNotNull(forkItem.getTask().getForkTask(), "ForkTask should be present");
+ }
+
+ @Test
+ void testDoTaskListenOne() {
+ Workflow wf =
+ WorkflowBuilder.workflow("flowListen")
+ .doTasks(
+ d ->
+ d.listen(
+ "waitCheck",
+ l -> l.one(f -> f.with(p -> p.type("com.fake.pet").source("mySource")))))
+ .build();
+
+ List items = wf.getDo();
+ assertNotNull(items, "Do list must not be null");
+ assertEquals(1, items.size(), "There should be one task");
+
+ TaskItem item = items.get(0);
+ assertEquals("waitCheck", item.getName());
+ ListenTask lt = item.getTask().getListenTask();
+ assertNotNull(lt, "ListenTask should be present");
+ OneEventConsumptionStrategy one = lt.getListen().getTo().getOneEventConsumptionStrategy();
+ assertNotNull(one, "One consumption strategy should be set");
+ EventFilter filter = one.getOne();
+ assertNotNull(filter, "EventFilter should be present");
+ assertEquals("com.fake.pet", filter.getWith().getType(), "Filter type should match");
+ }
+
+ @Test
+ void testDoTaskEmitEvent() {
+ Workflow wf =
+ WorkflowBuilder.workflow("flowEmit")
+ .doTasks(
+ d ->
+ d.emit(
+ "emitEvent",
+ e ->
+ e.event(
+ p ->
+ p.source(URI.create("https://petstore.com"))
+ .type("com.petstore.order.placed.v1")
+ .data(
+ Map.of(
+ "client",
+ Map.of(
+ "firstName", "Cruella", "lastName", "de Vil"),
+ "items",
+ List.of(
+ Map.of(
+ "breed", "dalmatian", "quantity", 101)))))))
+ .build();
+
+ List items = wf.getDo();
+ assertNotNull(items, "Do list must not be null");
+ assertEquals(1, items.size(), "There should be one emit task");
+
+ TaskItem item = items.get(0);
+ assertEquals("emitEvent", item.getName(), "TaskItem name should match");
+ io.serverlessworkflow.api.types.EmitTask et = item.getTask().getEmitTask();
+ assertNotNull(et, "EmitTask should be present");
+
+ io.serverlessworkflow.api.types.EmitEventDefinition ed = et.getEmit().getEvent();
+ assertNotNull(ed, "EmitEventDefinition should be present");
+ io.serverlessworkflow.api.types.EventProperties props = ed.getWith();
+ assertEquals(
+ "https://petstore.com",
+ props.getSource().getUriTemplate().getLiteralUri().toString(),
+ "Source URI should match");
+ assertEquals("com.petstore.order.placed.v1", props.getType(), "Event type should match");
+
+ Object dataObj = props.getData().getObject();
+ assertNotNull(dataObj, "Data object should be present");
+ assertInstanceOf(Map.class, dataObj, "Data should be a Map");
+ @SuppressWarnings("unchecked")
+ Map dataMap = (Map) dataObj;
+ assertTrue(dataMap.containsKey("client"), "Data should contain 'client'");
+ assertTrue(dataMap.containsKey("items"), "Data should contain 'items'");
+ }
+
+ @Test
+ void testDoTaskTryCatchWithRetry() {
+ Workflow wf =
+ WorkflowBuilder.workflow("flowTry")
+ .doTasks(
+ d ->
+ d.tryTask(
+ "tryBlock",
+ t ->
+ t.tryHandler(tb -> tb.set("init", s -> s.expr("$.start = true")))
+ .catchHandler(
+ c ->
+ c.when("$.errorType == 'TEMP' ")
+ .retry(
+ r ->
+ r.when("$.retryCount < 3")
+ .limit(
+ l -> l.attempt(at -> at.count(3)))))))
+ .build();
+
+ List items = wf.getDo();
+ assertEquals(1, items.size(), "There should be one try task");
+ TaskItem item = items.get(0);
+ assertEquals("tryBlock", item.getName());
+
+ // Verify TryTask
+ TryTask tryTask = item.getTask().getTryTask();
+ assertNotNull(tryTask, "TryTask should be present");
+
+ // Verify try handler tasks
+ List tryItems = tryTask.getTry();
+ assertEquals(1, tryItems.size(), "Try handler should contain one task");
+ TaskItem initItem = tryItems.get(0);
+ assertEquals("init", initItem.getName());
+ assertNotNull(initItem.getTask().getSetTask(), "SetTask in try handler should be present");
+
+ // Verify catch configuration
+ TryTaskCatch catchCfg = tryTask.getCatch();
+ assertNotNull(catchCfg, "Catch configuration should be present");
+ assertEquals("$.errorType == 'TEMP' ", catchCfg.getWhen());
+
+ RetryPolicy retry = catchCfg.getRetry().getRetryPolicyDefinition();
+ assertNotNull(retry, "RetryPolicy should be defined");
+ assertEquals("$.retryCount < 3", retry.getWhen());
+ RetryLimitAttempt attempt = retry.getLimit().getAttempt();
+ assertEquals(3, attempt.getCount());
+ }
+
+ @Test
+ void testDoTaskTryCatchErrorsFiltering() {
+ Workflow wf =
+ WorkflowBuilder.workflow("flowCatch")
+ .doTasks(
+ d ->
+ d.tryTask(
+ "tryBlock",
+ t ->
+ t.tryHandler(tb -> tb.set("foo", s -> s.expr("$.foo = 'bar'")))
+ .catchHandler(
+ c ->
+ c.exceptWhen("$.status == 500")
+ .errorsWith(
+ eb ->
+ eb.type("ServerError")
+ .status(500)
+ .instance("http://errors/5xx")))))
+ .build();
+
+ TaskItem item = wf.getDo().get(0);
+ TryTask tryTask = item.getTask().getTryTask();
+ TryTaskCatch catchCfg = tryTask.getCatch();
+
+ // exceptWhen should match
+ assertEquals("$.status == 500", catchCfg.getExceptWhen());
+
+ CatchErrors errors = catchCfg.getErrors();
+ assertNotNull(errors, "CatchErrors should be present");
+ ErrorFilter filter = errors.getWith();
+ assertEquals("ServerError", filter.getType());
+ assertEquals(500, filter.getStatus());
+ assertEquals("http://errors/5xx", filter.getInstance());
+ }
+
+ @Test
+ void testWorkflowInputExternalSchema() {
+ String uri = "http://example.com/schema";
+ Workflow wf =
+ WorkflowBuilder.workflow("wfInput").input(i -> i.from("$.data").schema(uri)).build();
+
+ assertNotNull(wf.getInput(), "Input must be set");
+ assertEquals("$.data", wf.getInput().getFrom().getString());
+ assertNotNull(wf.getInput().getSchema().getSchemaExternal(), "External schema must be set");
+ String resolved =
+ wf.getInput()
+ .getSchema()
+ .getSchemaExternal()
+ .getResource()
+ .getEndpoint()
+ .getUriTemplate()
+ .getLiteralUri()
+ .toString();
+ assertEquals(uri, resolved, "Schema URI should match");
+ }
+
+ @Test
+ void testWorkflowOutputExternalSchemaAndAs() {
+ String uri = "http://example.org/output-schema";
+ Workflow wf =
+ WorkflowBuilder.workflow("wfOutput").output(o -> o.as("$.result").schema(uri)).build();
+
+ assertNotNull(wf.getOutput(), "Output must be set");
+ assertEquals("$.result", wf.getOutput().getAs().getString());
+ assertNotNull(wf.getOutput().getSchema().getSchemaExternal(), "External schema must be set");
+ String resolved =
+ wf.getOutput()
+ .getSchema()
+ .getSchemaExternal()
+ .getResource()
+ .getEndpoint()
+ .getUriTemplate()
+ .getLiteralUri()
+ .toString();
+ assertEquals(uri, resolved, "Schema URI should match");
+ }
+
+ @Test
+ void testWorkflowOutputInlineSchemaAndAsObject() {
+ Map inline = Map.of("foo", "bar");
+ Workflow wf =
+ WorkflowBuilder.workflow().output(o -> o.as(Map.of("ok", true)).schema(inline)).build();
+
+ assertNotNull(wf.getOutput(), "Output must be set");
+ assertInstanceOf(Map.class, wf.getOutput().getAs().getObject(), "As object must be a Map");
+ assertNotNull(wf.getOutput().getSchema().getSchemaInline(), "Inline schema must be set");
+ }
+
+ @Test
+ void testWorkflowInputInlineSchemaAndFromObject() {
+ Map inline = Map.of("nested", List.of(1, 2, 3));
+ Workflow wf = WorkflowBuilder.workflow().input(i -> i.from(inline).schema(inline)).build();
+
+ assertNotNull(wf.getInput(), "Input must be set");
+ assertInstanceOf(Map.class, wf.getInput().getFrom().getObject(), "From object must be a Map");
+ assertNotNull(wf.getInput().getSchema().getSchemaInline(), "Inline schema must be set");
+ }
+
+ @Test
+ void testDoTaskCallHTTPBasic() {
+ Workflow wf =
+ WorkflowBuilder.workflow("flowCallBasic")
+ .doTasks(
+ d ->
+ d.callHTTP(
+ "basicCall",
+ c ->
+ c.method("POST")
+ .endpoint(URI.create("http://example.com/api"))
+ .body(Map.of("foo", "bar"))))
+ .build();
+ List items = wf.getDo();
+ assertEquals(1, items.size(), "Should have one HTTP call task");
+ TaskItem ti = items.get(0);
+ assertEquals("basicCall", ti.getName());
+ CallHTTP call = ti.getTask().getCallTask().getCallHTTP();
+ assertNotNull(call, "CallHTTP should be present");
+ assertEquals("POST", call.getWith().getMethod());
+ assertEquals(
+ URI.create("http://example.com/api"),
+ call.getWith().getEndpoint().getUriTemplate().getLiteralUri());
+ assertInstanceOf(Map.class, call.getWith().getBody(), "Body should be the Map provided");
+ }
+
+ @Test
+ void testDoTaskCallHTTPHeadersConsumerAndMap() {
+ Workflow wf =
+ WorkflowBuilder.workflow("flowCallHeaders")
+ .doTasks(
+ d ->
+ d.callHTTP(
+ "hdrCall",
+ c ->
+ c.method("GET")
+ .endpoint("${uriExpr}")
+ .headers(h -> h.header("A", "1").header("B", "2"))))
+ .build();
+ CallHTTP call = wf.getDo().get(0).getTask().getCallTask().getCallHTTP();
+ HTTPHeaders hh = call.getWith().getHeaders().getHTTPHeaders();
+ assertEquals("1", hh.getAdditionalProperties().get("A"));
+ assertEquals("2", hh.getAdditionalProperties().get("B"));
+
+ Workflow wf2 =
+ WorkflowBuilder.workflow()
+ .doTasks(
+ d ->
+ d.callHTTP(
+ c ->
+ c.method("GET").endpoint("expr").headers(Map.of("X", "10", "Y", "20"))))
+ .build();
+ CallHTTP call2 = wf2.getDo().get(0).getTask().getCallTask().getCallHTTP();
+ HTTPHeaders hh2 = call2.getWith().getHeaders().getHTTPHeaders();
+ assertEquals("10", hh2.getAdditionalProperties().get("X"));
+ assertEquals("20", hh2.getAdditionalProperties().get("Y"));
+ }
+
+ @Test
+ void testDoTaskCallHTTPQueryConsumerAndMap() {
+ Workflow wf =
+ WorkflowBuilder.workflow("flowCallQuery")
+ .doTasks(
+ d ->
+ d.callHTTP(
+ "qryCall",
+ c ->
+ c.method("GET")
+ .endpoint("exprUri")
+ .query(q -> q.query("k1", "v1").query("k2", "v2"))))
+ .build();
+ HTTPQuery hq =
+ wf.getDo().get(0).getTask().getCallTask().getCallHTTP().getWith().getQuery().getHTTPQuery();
+ assertEquals("v1", hq.getAdditionalProperties().get("k1"));
+ assertEquals("v2", hq.getAdditionalProperties().get("k2"));
+
+ Workflow wf2 =
+ WorkflowBuilder.workflow()
+ .doTasks(
+ d ->
+ d.callHTTP(
+ c -> c.method("GET").endpoint("uri").query(Map.of("q1", "x", "q2", "y"))))
+ .build();
+ HTTPQuery hq2 =
+ wf2.getDo()
+ .get(0)
+ .getTask()
+ .getCallTask()
+ .getCallHTTP()
+ .getWith()
+ .getQuery()
+ .getHTTPQuery();
+ assertEquals("x", hq2.getAdditionalProperties().get("q1"));
+ assertEquals("y", hq2.getAdditionalProperties().get("q2"));
+ }
+
+ @Test
+ void testDoTaskCallHTTPRedirectAndOutput() {
+ Workflow wf =
+ WorkflowBuilder.workflow("flowCallOpts")
+ .doTasks(
+ d ->
+ d.callHTTP(
+ "optCall",
+ c ->
+ c.method("DELETE")
+ .endpoint("expr")
+ .redirect(true)
+ .output(HTTPArguments.HTTPOutput.RESPONSE)))
+ .build();
+ CallHTTP call = wf.getDo().get(0).getTask().getCallTask().getCallHTTP();
+ assertTrue(call.getWith().isRedirect(), "Redirect should be true");
+ assertEquals(
+ HTTPArguments.HTTPOutput.RESPONSE,
+ call.getWith().getOutput(),
+ "Output should be overridden");
+ }
+}
diff --git a/pom.xml b/pom.xml
index b0a57369..f6d140e8 100644
--- a/pom.xml
+++ b/pom.xml
@@ -45,6 +45,7 @@
serialization
examples
experimental
+ fluent