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..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,9 +24,11 @@ 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; +import java.util.ServiceLoader; import java.util.concurrent.CompletableFuture; public class HttpExecutor implements CallableTask { @@ -36,6 +38,7 @@ public class HttpExecutor implements CallableTask { private final Optional>> headersMap; private final Optional>> queryMap; private final RequestExecutor requestFunction; + private final List requestDecorators; HttpExecutor( WorkflowValueResolver uriSupplier, @@ -48,6 +51,11 @@ public class HttpExecutor implements CallableTask { this.queryMap = queryMap; this.requestFunction = requestFunction; this.pathSupplier = pathSupplier; + this.requestDecorators = + ServiceLoader.load(RequestDecorator.class).stream() + .map(ServiceLoader.Provider::get) + .sorted() + .toList(); } public CompletableFuture apply( @@ -67,6 +75,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..bf7ce631 --- /dev/null +++ b/impl/http/src/main/java/io/serverlessworkflow/impl/executors/http/RequestDecorator.java @@ -0,0 +1,48 @@ +/* + * 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.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 modifications. + * + *

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 extends ServicePriority { + + /** + * 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); +}