Skip to content

Commit 21909cd

Browse files
committed
[Fix #1507] Loading HttpRequestDecorator from WorkflowAdditionaObject
1 parent b0d9e6a commit 21909cd

4 files changed

Lines changed: 134 additions & 8 deletions

File tree

impl/core/src/main/java/io/serverlessworkflow/impl/WorkflowApplication.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@
6868
import java.util.ServiceLoader.Provider;
6969
import java.util.concurrent.ConcurrentHashMap;
7070
import java.util.concurrent.ExecutorService;
71+
import java.util.function.Supplier;
7172
import java.util.stream.Collectors;
7273

7374
public class WorkflowApplication implements AutoCloseable {
@@ -91,6 +92,7 @@ public class WorkflowApplication implements AutoCloseable {
9192
private final WorkflowModelFactory contextFactory;
9293
private final WorkflowScheduler scheduler;
9394
private final Map<String, WorkflowAdditionalObject<?>> additionalObjects;
95+
private final Map<String, Supplier<?>> additionalObjectSuppliers;
9496
private final AuthProviderFactory authProviderFactory;
9597
private final ConfigManager configManager;
9698
private final SecretManager secretManager;
@@ -123,6 +125,7 @@ private WorkflowApplication(Builder builder) {
123125
this.scheduler = builder.scheduler;
124126
this.schedulerListener = builder.schedulerListener;
125127
this.additionalObjects = builder.additionalObjects;
128+
this.additionalObjectSuppliers = builder.additionalObjectSuppliers;
126129
this.authProviderFactory = builder.authProviderFactory;
127130
this.configManager = builder.configManager;
128131
this.secretManager = builder.secretManager;
@@ -245,6 +248,7 @@ public SchemaValidator getValidator(SchemaInline inline) {
245248
private WorkflowModelFactory modelFactory;
246249
private WorkflowModelFactory contextFactory;
247250
private Map<String, WorkflowAdditionalObject<?>> additionalObjects = new HashMap<>();
251+
private Map<String, Supplier<?>> additionalObjectSuppliers = new HashMap<>();
248252
private AuthProviderFactory authProviderFactory;
249253
private SecretManager secretManager;
250254
private ConfigManager configManager;
@@ -362,6 +366,11 @@ public <T> Builder withAdditionalObject(
362366
return this;
363367
}
364368

369+
public <T> Builder withAdditionalObject(String name, Supplier<T> additionalObject) {
370+
additionalObjectSuppliers.put(name, additionalObject);
371+
return this;
372+
}
373+
365374
public Builder withAuthProviderFactory(AuthProviderFactory authProviderFactory) {
366375
this.authProviderFactory = authProviderFactory;
367376
return this;
@@ -594,6 +603,10 @@ public String id() {
594603
return id;
595604
}
596605

606+
public <T> Optional<T> additionalObject(String name) {
607+
return Optional.ofNullable(additionalObjectSuppliers.get(name)).map(v -> (T) v.get());
608+
}
609+
597610
public <T> Optional<T> additionalObject(
598611
String name, WorkflowContext workflowContext, TaskContext taskContext) {
599612
return Optional.ofNullable(additionalObjects.get(name))
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
/*
2+
* Copyright 2020-Present The Serverless Workflow Specification Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package io.serverlessworkflow.impl;
17+
18+
import static org.assertj.core.api.Assertions.assertThat;
19+
20+
import io.serverlessworkflow.impl.additional.WorkflowAdditionalObject;
21+
import io.serverlessworkflow.impl.lifecycle.WorkflowExecutionCompletableListener;
22+
import java.util.ArrayList;
23+
import java.util.Collections;
24+
import java.util.List;
25+
import java.util.function.Supplier;
26+
import org.junit.jupiter.api.BeforeEach;
27+
import org.junit.jupiter.api.Test;
28+
import org.mockito.Mockito;
29+
30+
public class WorkflowAdditionalObjectTest {
31+
32+
private WorkflowExecutionCompletableListener mediumPrio = new MediumPriorityListener("javi");
33+
private WorkflowExecutionCompletableListener lowestPrio = new LowestPriorityListener();
34+
private WorkflowExecutionCompletableListener topPrio = new TopPriorityListener();
35+
private WorkflowModelFactory modelFactory;
36+
37+
@BeforeEach
38+
void setup() {
39+
modelFactory = Mockito.mock(WorkflowModelFactory.class);
40+
}
41+
42+
private static class DummyAdditionalObjectBiFunction
43+
implements WorkflowAdditionalObject<Integer> {
44+
@Override
45+
public Integer apply(WorkflowContextData workflowContext, TaskContextData taskContext) {
46+
return workflowContext.hashCode() + taskContext.hashCode();
47+
}
48+
}
49+
50+
private class DummyAdditionalObjectSupplier implements Supplier<List<ServicePriority>> {
51+
@Override
52+
public List<ServicePriority> get() {
53+
return List.of(mediumPrio, lowestPrio, topPrio);
54+
}
55+
}
56+
57+
@Test
58+
void testAdditionalObjectBiFunction() {
59+
WorkflowContext workflowContext = Mockito.mock(WorkflowContext.class);
60+
TaskContext taskContext = Mockito.mock(TaskContext.class);
61+
final String key = "Dummy_Bifactory";
62+
try (WorkflowApplication appl =
63+
WorkflowApplication.builder()
64+
.withAdditionalObject(key, new DummyAdditionalObjectBiFunction())
65+
.withModelFactory(modelFactory)
66+
.build()) {
67+
assertThat(appl.<Integer>additionalObject(key, workflowContext, taskContext).orElse(0))
68+
.isNotEqualTo(0);
69+
}
70+
}
71+
72+
@Test
73+
void testAdditionalObjectSupplier() {
74+
final String key = "Dummy_supplier";
75+
try (WorkflowApplication appl =
76+
WorkflowApplication.builder()
77+
.withModelFactory(modelFactory)
78+
.withAdditionalObject(key, new DummyAdditionalObjectSupplier())
79+
.build()) {
80+
List<ServicePriority> priorities = new ArrayList<>();
81+
WorkflowExecutionCompletableListener anotherMediumPrio =
82+
new MediumPriorityListener("javierito");
83+
priorities.add(anotherMediumPrio);
84+
priorities.addAll(appl.<List<ServicePriority>>additionalObject(key).orElse(List.of()));
85+
Collections.sort(priorities);
86+
assertThat(priorities).isEqualTo(List.of(topPrio, anotherMediumPrio, mediumPrio, lowestPrio));
87+
}
88+
}
89+
90+
@Test
91+
void testAdditionalObjectSupplierNull() {
92+
final String key = "Null_supplier";
93+
try (WorkflowApplication appl =
94+
WorkflowApplication.builder()
95+
.withModelFactory(modelFactory)
96+
.withAdditionalObject(key, () -> null)
97+
.build()) {
98+
assertThat(appl.additionalObject(key)).isEmpty();
99+
}
100+
}
101+
}

impl/http/src/main/java/io/serverlessworkflow/impl/executors/http/HttpExecutor.java

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828
import java.util.Map;
2929
import java.util.Map.Entry;
3030
import java.util.Optional;
31-
import java.util.ServiceLoader;
3231
import java.util.concurrent.CompletableFuture;
3332

3433
public class HttpExecutor implements CallableTask {
@@ -45,17 +44,14 @@ public class HttpExecutor implements CallableTask {
4544
Optional<WorkflowValueResolver<Map<String, Object>>> headersMap,
4645
Optional<WorkflowValueResolver<Map<String, Object>>> queryMap,
4746
RequestExecutor requestFunction,
48-
Optional<WorkflowValueResolver<URI>> pathSupplier) {
47+
Optional<WorkflowValueResolver<URI>> pathSupplier,
48+
Collection<HttpRequestDecorator> requestDecorators) {
4949
this.uriSupplier = uriSupplier;
5050
this.headersMap = headersMap;
5151
this.queryMap = queryMap;
5252
this.requestFunction = requestFunction;
5353
this.pathSupplier = pathSupplier;
54-
this.requestDecorators =
55-
ServiceLoader.load(HttpRequestDecorator.class).stream()
56-
.map(ServiceLoader.Provider::get)
57-
.sorted()
58-
.toList();
54+
this.requestDecorators = requestDecorators;
5955
}
6056

6157
public CompletableFuture<WorkflowModel> apply(

impl/http/src/main/java/io/serverlessworkflow/impl/executors/http/HttpExecutorBuilder.java

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,19 @@
2424
import io.serverlessworkflow.impl.auth.AuthProvider;
2525
import jakarta.ws.rs.HttpMethod;
2626
import java.net.URI;
27+
import java.util.ArrayList;
28+
import java.util.Collection;
29+
import java.util.Collections;
30+
import java.util.List;
2731
import java.util.Map;
2832
import java.util.Optional;
33+
import java.util.ServiceLoader;
2934

3035
public class HttpExecutorBuilder {
3136

37+
public static final String HTTP_REQUEST_DECORATOR_KEY = "HttpRequestDecorator";
3238
private final WorkflowDefinition definition;
39+
private final List<HttpRequestDecorator> requestDecorators;
3340
private WorkflowValueResolver<URI> pathSupplier;
3441
private Object body;
3542
private String method = HttpMethod.GET;
@@ -40,6 +47,14 @@ public class HttpExecutorBuilder {
4047

4148
private HttpExecutorBuilder(WorkflowDefinition definition) {
4249
this.definition = definition;
50+
this.requestDecorators = new ArrayList<>();
51+
requestDecorators.addAll(
52+
definition
53+
.application()
54+
.<Collection<HttpRequestDecorator>>additionalObject(HTTP_REQUEST_DECORATOR_KEY)
55+
.orElse(List.of()));
56+
ServiceLoader.load(HttpRequestDecorator.class).forEach(requestDecorators::add);
57+
Collections.sort(requestDecorators);
4358
}
4459

4560
public HttpExecutorBuilder withAuth(ReferenceableAuthenticationPolicy policy) {
@@ -110,7 +125,8 @@ public HttpExecutor build(WorkflowValueResolver<URI> uriSupplier) {
110125
Optional.ofNullable(headersMap),
111126
Optional.ofNullable(queryMap),
112127
buildRequestExecutor(),
113-
Optional.ofNullable(pathSupplier));
128+
Optional.ofNullable(pathSupplier),
129+
requestDecorators);
114130
}
115131

116132
public static HttpExecutorBuilder builder(WorkflowDefinition definition) {

0 commit comments

Comments
 (0)