From e22186e1906683d1cc06e02ae8035002e8a560d4 Mon Sep 17 00:00:00 2001 From: Matheus Cruz Date: Thu, 15 Jan 2026 15:12:18 -0300 Subject: [PATCH 1/2] Add RequestDecorator to allow SDK clients to modify the request Signed-off-by: Matheus Cruz --- .../impl/executors/http/HttpExecutor.java | 8 ++++ .../impl/executors/http/RequestDecorator.java | 43 +++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 impl/http/src/main/java/io/serverlessworkflow/impl/executors/http/RequestDecorator.java diff --git a/impl/http/src/main/java/io/serverlessworkflow/impl/executors/http/HttpExecutor.java b/impl/http/src/main/java/io/serverlessworkflow/impl/executors/http/HttpExecutor.java index 7ca9230e..0644c90b 100644 --- a/impl/http/src/main/java/io/serverlessworkflow/impl/executors/http/HttpExecutor.java +++ b/impl/http/src/main/java/io/serverlessworkflow/impl/executors/http/HttpExecutor.java @@ -27,6 +27,7 @@ import java.util.Map; import java.util.Map.Entry; import java.util.Optional; +import java.util.ServiceLoader; import java.util.concurrent.CompletableFuture; public class HttpExecutor implements CallableTask { @@ -36,6 +37,7 @@ public class HttpExecutor implements CallableTask { private final Optional>> headersMap; private final Optional>> queryMap; private final RequestExecutor requestFunction; + private final ServiceLoader requestDecorators; HttpExecutor( WorkflowValueResolver uriSupplier, @@ -48,6 +50,7 @@ public class HttpExecutor implements CallableTask { this.queryMap = queryMap; this.requestFunction = requestFunction; this.pathSupplier = pathSupplier; + this.requestDecorators = ServiceLoader.load(RequestDecorator.class); } public CompletableFuture apply( @@ -67,6 +70,11 @@ public CompletableFuture apply( target = target.queryParam(entry.getKey(), entry.getValue()); } Builder request = target.request(); + + for (RequestDecorator requestDecorator : requestDecorators) { + requestDecorator.decorate(request, workflow, taskContext, input); + } + headersMap.ifPresent( h -> h.apply(workflow, taskContext, input).forEach((k, v) -> request.header(k, v))); return CompletableFuture.supplyAsync( diff --git a/impl/http/src/main/java/io/serverlessworkflow/impl/executors/http/RequestDecorator.java b/impl/http/src/main/java/io/serverlessworkflow/impl/executors/http/RequestDecorator.java new file mode 100644 index 00000000..d9770ea8 --- /dev/null +++ b/impl/http/src/main/java/io/serverlessworkflow/impl/executors/http/RequestDecorator.java @@ -0,0 +1,43 @@ +/* + * 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.impl.executors.http; + +import io.serverlessworkflow.impl.TaskContext; +import io.serverlessworkflow.impl.WorkflowContext; +import io.serverlessworkflow.impl.WorkflowModel; +import jakarta.ws.rs.client.Invocation; + +/** + * Interface for decorating HTTP requests with additional headers or modifications. + * + *

Implementations should be loaded via ServiceLoader. + */ +public interface RequestDecorator { + + /** + * Decorate the HTTP request builder with additional headers or modifications. + * + * @param requestBuilder the request builder to decorate + * @param workflowContext the workflow context + * @param taskContext the task context + * @param workflowModel the input data + */ + void decorate( + Invocation.Builder requestBuilder, + WorkflowContext workflowContext, + TaskContext taskContext, + WorkflowModel workflowModel); +} From 99b2c22971aa41d29463f147060a7ac669ce396e Mon Sep 17 00:00:00 2001 From: Matheus Cruz Date: Thu, 15 Jan 2026 15:45:26 -0300 Subject: [PATCH 2/2] Apply @fjtirado suggestion Signed-off-by: Matheus Cruz --- .../impl/executors/http/HttpExecutor.java | 9 +++++++-- .../impl/executors/http/RequestDecorator.java | 11 ++++++++--- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/impl/http/src/main/java/io/serverlessworkflow/impl/executors/http/HttpExecutor.java b/impl/http/src/main/java/io/serverlessworkflow/impl/executors/http/HttpExecutor.java index 0644c90b..b237393f 100644 --- a/impl/http/src/main/java/io/serverlessworkflow/impl/executors/http/HttpExecutor.java +++ b/impl/http/src/main/java/io/serverlessworkflow/impl/executors/http/HttpExecutor.java @@ -24,6 +24,7 @@ import jakarta.ws.rs.client.Invocation.Builder; import jakarta.ws.rs.client.WebTarget; import java.net.URI; +import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Optional; @@ -37,7 +38,7 @@ public class HttpExecutor implements CallableTask { private final Optional>> headersMap; private final Optional>> queryMap; private final RequestExecutor requestFunction; - private final ServiceLoader requestDecorators; + private final List requestDecorators; HttpExecutor( WorkflowValueResolver uriSupplier, @@ -50,7 +51,11 @@ public class HttpExecutor implements CallableTask { this.queryMap = queryMap; this.requestFunction = requestFunction; this.pathSupplier = pathSupplier; - this.requestDecorators = ServiceLoader.load(RequestDecorator.class); + this.requestDecorators = + ServiceLoader.load(RequestDecorator.class).stream() + .map(ServiceLoader.Provider::get) + .sorted() + .toList(); } public CompletableFuture apply( diff --git a/impl/http/src/main/java/io/serverlessworkflow/impl/executors/http/RequestDecorator.java b/impl/http/src/main/java/io/serverlessworkflow/impl/executors/http/RequestDecorator.java index d9770ea8..bf7ce631 100644 --- a/impl/http/src/main/java/io/serverlessworkflow/impl/executors/http/RequestDecorator.java +++ b/impl/http/src/main/java/io/serverlessworkflow/impl/executors/http/RequestDecorator.java @@ -15,17 +15,22 @@ */ package io.serverlessworkflow.impl.executors.http; +import io.serverlessworkflow.impl.ServicePriority; import io.serverlessworkflow.impl.TaskContext; import io.serverlessworkflow.impl.WorkflowContext; import io.serverlessworkflow.impl.WorkflowModel; import jakarta.ws.rs.client.Invocation; /** - * Interface for decorating HTTP requests with additional headers or modifications. + * Interface for decorating HTTP requests with additional modifications. * - *

Implementations should be loaded via ServiceLoader. + *

Implementations should be loaded via ServiceLoader and are sorted by priority in ascending + * order (lower priority numbers executed first). Decorators are applied in sequence, where later + * decorators can override headers set by earlier decorators with the same header name. + * + * @see ServicePriority */ -public interface RequestDecorator { +public interface RequestDecorator extends ServicePriority { /** * Decorate the HTTP request builder with additional headers or modifications.