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