diff --git a/impl/core/pom.xml b/impl/core/pom.xml
index 53fb5a656..00c34df8c 100644
--- a/impl/core/pom.xml
+++ b/impl/core/pom.xml
@@ -33,5 +33,10 @@
junit-jupiter-engine
test
+
+ org.assertj
+ assertj-core
+ test
+
diff --git a/impl/core/src/main/java/io/serverlessworkflow/impl/FunctionReader.java b/impl/core/src/main/java/io/serverlessworkflow/impl/FunctionReader.java
index 755a98c1e..0b7066359 100644
--- a/impl/core/src/main/java/io/serverlessworkflow/impl/FunctionReader.java
+++ b/impl/core/src/main/java/io/serverlessworkflow/impl/FunctionReader.java
@@ -19,4 +19,4 @@
import io.serverlessworkflow.impl.resources.ExternalResourceHandler;
import java.util.function.Function;
-public interface FunctionReader extends Function {}
+public interface FunctionReader extends Function, ServicePriority {}
diff --git a/impl/core/src/main/java/io/serverlessworkflow/impl/WorkflowApplication.java b/impl/core/src/main/java/io/serverlessworkflow/impl/WorkflowApplication.java
index cd70f881a..550cddb2f 100644
--- a/impl/core/src/main/java/io/serverlessworkflow/impl/WorkflowApplication.java
+++ b/impl/core/src/main/java/io/serverlessworkflow/impl/WorkflowApplication.java
@@ -15,6 +15,7 @@
*/
package io.serverlessworkflow.impl;
+import static io.serverlessworkflow.impl.WorkflowUtils.loadFirst;
import static io.serverlessworkflow.impl.WorkflowUtils.safeClose;
import io.serverlessworkflow.api.types.SchemaInline;
@@ -305,8 +306,7 @@ public Builder withDefaultCatalogURI(URI defaultCatalogURI) {
public WorkflowApplication build() {
if (modelFactory == null) {
modelFactory =
- ServiceLoader.load(WorkflowModelFactory.class)
- .findFirst()
+ loadFirst(WorkflowModelFactory.class)
.orElseThrow(
() ->
new IllegalStateException(
@@ -318,21 +318,17 @@ public WorkflowApplication build() {
ServiceLoader.load(ExpressionFactory.class).forEach(exprFactories::add);
if (schemaValidatorFactory == null) {
schemaValidatorFactory =
- ServiceLoader.load(SchemaValidatorFactory.class)
- .findFirst()
+ loadFirst(SchemaValidatorFactory.class)
.orElseGet(() -> EmptySchemaValidatorHolder.instance);
}
if (taskFactory == null) {
taskFactory =
- ServiceLoader.load(TaskExecutorFactory.class)
- .findFirst()
- .orElseGet(() -> DefaultTaskExecutorFactory.get());
+ loadFirst(TaskExecutorFactory.class).orElseGet(() -> DefaultTaskExecutorFactory.get());
}
ServiceLoader.load(EventPublisher.class).forEach(e -> eventPublishers.add(e));
if (eventConsumer == null) {
eventConsumer =
- ServiceLoader.load(EventConsumer.class)
- .findFirst()
+ loadFirst(EventConsumer.class)
.orElseGet(
() -> {
InMemoryEvents inMemory = new InMemoryEvents(executorFactory);
@@ -353,18 +349,14 @@ public WorkflowApplication build() {
if (configManager == null) {
configManager =
- ServiceLoader.load(ConfigManager.class)
- .findFirst()
- .orElseGet(() -> new SystemPropertyConfigManager());
+ loadFirst(ConfigManager.class).orElseGet(() -> new SystemPropertyConfigManager());
}
if (secretManager == null) {
secretManager =
- ServiceLoader.load(SecretManager.class)
- .findFirst()
- .orElseGet(() -> new ConfigSecretManager(configManager));
+ loadFirst(SecretManager.class).orElseGet(() -> new ConfigSecretManager(configManager));
}
- templateResolver = ServiceLoader.load(URITemplateResolver.class).findFirst();
- functionReader = ServiceLoader.load(FunctionReader.class).findFirst();
+ templateResolver = loadFirst(URITemplateResolver.class);
+ functionReader = loadFirst(FunctionReader.class);
if (defaultCatalogURI == null) {
defaultCatalogURI = URI.create("https://github.com/serverlessworkflow/catalog");
}
diff --git a/impl/core/src/main/java/io/serverlessworkflow/impl/WorkflowUtils.java b/impl/core/src/main/java/io/serverlessworkflow/impl/WorkflowUtils.java
index 75fcf8910..16979fc1f 100644
--- a/impl/core/src/main/java/io/serverlessworkflow/impl/WorkflowUtils.java
+++ b/impl/core/src/main/java/io/serverlessworkflow/impl/WorkflowUtils.java
@@ -39,6 +39,7 @@
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
+import java.util.ServiceLoader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -304,4 +305,11 @@ public static WorkflowValueResolver getURISupplier(
}
throw new IllegalArgumentException("Invalid uritemplate definition " + template);
}
+
+ public static Optional loadFirst(Class serviceClass) {
+ return ServiceLoader.load(serviceClass).stream()
+ .map(ServiceLoader.Provider::get)
+ .sorted()
+ .findFirst();
+ }
}
diff --git a/impl/core/src/main/java/io/serverlessworkflow/impl/auth/AccessTokenProviderFactory.java b/impl/core/src/main/java/io/serverlessworkflow/impl/auth/AccessTokenProviderFactory.java
index 4aed1fa2c..c18f69f4c 100644
--- a/impl/core/src/main/java/io/serverlessworkflow/impl/auth/AccessTokenProviderFactory.java
+++ b/impl/core/src/main/java/io/serverlessworkflow/impl/auth/AccessTokenProviderFactory.java
@@ -15,9 +15,10 @@
*/
package io.serverlessworkflow.impl.auth;
+import io.serverlessworkflow.impl.ServicePriority;
import java.util.List;
-public interface AccessTokenProviderFactory {
+public interface AccessTokenProviderFactory extends ServicePriority {
AccessTokenProvider build(
HttpRequestInfo requestInfo, List issuers, JWTConverter converter);
diff --git a/impl/core/src/main/java/io/serverlessworkflow/impl/auth/CommonOAuthProvider.java b/impl/core/src/main/java/io/serverlessworkflow/impl/auth/CommonOAuthProvider.java
index 9ead4c59a..73c0e45f7 100644
--- a/impl/core/src/main/java/io/serverlessworkflow/impl/auth/CommonOAuthProvider.java
+++ b/impl/core/src/main/java/io/serverlessworkflow/impl/auth/CommonOAuthProvider.java
@@ -16,6 +16,7 @@
package io.serverlessworkflow.impl.auth;
import static io.serverlessworkflow.impl.WorkflowUtils.checkSecret;
+import static io.serverlessworkflow.impl.WorkflowUtils.loadFirst;
import static io.serverlessworkflow.impl.WorkflowUtils.secret;
import io.serverlessworkflow.api.types.OAuth2AuthenticationData;
@@ -28,20 +29,17 @@
import java.net.URI;
import java.util.Arrays;
import java.util.Map;
-import java.util.ServiceLoader;
abstract class CommonOAuthProvider implements AuthProvider {
private final WorkflowValueResolver tokenProvider;
private static JWTConverter jwtConverter =
- ServiceLoader.load(JWTConverter.class)
- .findFirst()
+ loadFirst(JWTConverter.class)
.orElseThrow(() -> new IllegalStateException("No JWTConverter implementation found"));
private static AccessTokenProviderFactory accessTokenProviderFactory =
- ServiceLoader.load(AccessTokenProviderFactory.class)
- .findFirst()
+ loadFirst(AccessTokenProviderFactory.class)
.orElseThrow(() -> new IllegalStateException("No JWTConverter implementation found"));
protected CommonOAuthProvider(WorkflowValueResolver tokenProvider) {
diff --git a/impl/core/src/main/java/io/serverlessworkflow/impl/auth/JWTConverter.java b/impl/core/src/main/java/io/serverlessworkflow/impl/auth/JWTConverter.java
index 85338e5fc..90580d214 100644
--- a/impl/core/src/main/java/io/serverlessworkflow/impl/auth/JWTConverter.java
+++ b/impl/core/src/main/java/io/serverlessworkflow/impl/auth/JWTConverter.java
@@ -15,7 +15,9 @@
*/
package io.serverlessworkflow.impl.auth;
-public interface JWTConverter {
+import io.serverlessworkflow.impl.ServicePriority;
+
+public interface JWTConverter extends ServicePriority {
/**
* Converts a JWT token string into a JWT object.
diff --git a/impl/core/src/main/java/io/serverlessworkflow/impl/events/EventConsumer.java b/impl/core/src/main/java/io/serverlessworkflow/impl/events/EventConsumer.java
index 1c94ed497..68ac9a009 100644
--- a/impl/core/src/main/java/io/serverlessworkflow/impl/events/EventConsumer.java
+++ b/impl/core/src/main/java/io/serverlessworkflow/impl/events/EventConsumer.java
@@ -17,12 +17,13 @@
import io.cloudevents.CloudEvent;
import io.serverlessworkflow.api.types.EventFilter;
+import io.serverlessworkflow.impl.ServicePriority;
import io.serverlessworkflow.impl.WorkflowApplication;
import java.util.Collection;
import java.util.function.Consumer;
public interface EventConsumer
- extends AutoCloseable {
+ extends AutoCloseable, ServicePriority {
V listen(EventFilter filter, WorkflowApplication workflowApplication);
diff --git a/impl/core/src/main/java/io/serverlessworkflow/impl/executors/RunScriptExecutorBuilder.java b/impl/core/src/main/java/io/serverlessworkflow/impl/executors/RunScriptExecutorBuilder.java
index f51850903..87198d540 100644
--- a/impl/core/src/main/java/io/serverlessworkflow/impl/executors/RunScriptExecutorBuilder.java
+++ b/impl/core/src/main/java/io/serverlessworkflow/impl/executors/RunScriptExecutorBuilder.java
@@ -68,6 +68,7 @@ public CallableTask build(RunScript taskConfiguration, WorkflowDefinition defini
ServiceLoader.load(ScriptRunner.class).stream()
.map(ServiceLoader.Provider::get)
.filter(s -> s.identifier().equals(language))
+ .sorted()
.findFirst()
.orElseThrow(
() ->
diff --git a/impl/core/src/main/java/io/serverlessworkflow/impl/executors/RunTaskExecutor.java b/impl/core/src/main/java/io/serverlessworkflow/impl/executors/RunTaskExecutor.java
index 5bd26a1bc..af2a414d5 100644
--- a/impl/core/src/main/java/io/serverlessworkflow/impl/executors/RunTaskExecutor.java
+++ b/impl/core/src/main/java/io/serverlessworkflow/impl/executors/RunTaskExecutor.java
@@ -44,6 +44,7 @@ protected RunTaskExecutorBuilder(
runnables.stream()
.map(Provider::get)
.filter(r -> r.accept(config.getClass()))
+ .sorted()
.findFirst()
.map(r -> r.build(config, definition))
.orElseThrow(
diff --git a/impl/core/src/main/java/io/serverlessworkflow/impl/executors/RunnableTaskBuilder.java b/impl/core/src/main/java/io/serverlessworkflow/impl/executors/RunnableTaskBuilder.java
index eb0f4ba09..e0bc9b0b4 100644
--- a/impl/core/src/main/java/io/serverlessworkflow/impl/executors/RunnableTaskBuilder.java
+++ b/impl/core/src/main/java/io/serverlessworkflow/impl/executors/RunnableTaskBuilder.java
@@ -16,9 +16,10 @@
package io.serverlessworkflow.impl.executors;
import io.serverlessworkflow.api.types.RunTaskConfiguration;
+import io.serverlessworkflow.impl.ServicePriority;
import io.serverlessworkflow.impl.WorkflowDefinition;
-public interface RunnableTaskBuilder {
+public interface RunnableTaskBuilder extends ServicePriority {
boolean accept(Class extends RunTaskConfiguration> clazz);
CallableTask build(T taskConfiguration, WorkflowDefinition definition);
diff --git a/impl/core/src/main/java/io/serverlessworkflow/impl/resources/URITemplateResolver.java b/impl/core/src/main/java/io/serverlessworkflow/impl/resources/URITemplateResolver.java
index 72e4255c8..97bb62360 100644
--- a/impl/core/src/main/java/io/serverlessworkflow/impl/resources/URITemplateResolver.java
+++ b/impl/core/src/main/java/io/serverlessworkflow/impl/resources/URITemplateResolver.java
@@ -15,12 +15,13 @@
*/
package io.serverlessworkflow.impl.resources;
+import io.serverlessworkflow.impl.ServicePriority;
import io.serverlessworkflow.impl.TaskContext;
import io.serverlessworkflow.impl.WorkflowContext;
import io.serverlessworkflow.impl.WorkflowModel;
import java.net.URI;
-public interface URITemplateResolver {
+public interface URITemplateResolver extends ServicePriority {
URI resolveTemplates(
String uri, WorkflowContext workflowContext, TaskContext taskContext, WorkflowModel model);
}
diff --git a/impl/core/src/test/java/io/serverlessworkflow/impl/LowestPriority.java b/impl/core/src/test/java/io/serverlessworkflow/impl/LowestPriority.java
new file mode 100644
index 000000000..b4410e198
--- /dev/null
+++ b/impl/core/src/test/java/io/serverlessworkflow/impl/LowestPriority.java
@@ -0,0 +1,22 @@
+/*
+ * 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;
+
+public class LowestPriority implements ServicePriority {
+ public int priority() {
+ return DEFAULT_PRIORITY + 1;
+ }
+}
diff --git a/impl/core/src/test/java/io/serverlessworkflow/impl/MediumPriority.java b/impl/core/src/test/java/io/serverlessworkflow/impl/MediumPriority.java
new file mode 100644
index 000000000..2963409f8
--- /dev/null
+++ b/impl/core/src/test/java/io/serverlessworkflow/impl/MediumPriority.java
@@ -0,0 +1,18 @@
+/*
+ * 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;
+
+public class MediumPriority implements ServicePriority {}
diff --git a/impl/core/src/test/java/io/serverlessworkflow/impl/ServicePriorityTest.java b/impl/core/src/test/java/io/serverlessworkflow/impl/ServicePriorityTest.java
new file mode 100644
index 000000000..f58af79df
--- /dev/null
+++ b/impl/core/src/test/java/io/serverlessworkflow/impl/ServicePriorityTest.java
@@ -0,0 +1,29 @@
+/*
+ * 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;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.junit.jupiter.api.Test;
+
+class ServicePriorityTest {
+
+ @Test
+ void testRightOrder() {
+ assertThat(WorkflowUtils.loadFirst(ServicePriority.class).orElseThrow())
+ .isInstanceOf(TopPriority.class);
+ }
+}
diff --git a/impl/core/src/test/java/io/serverlessworkflow/impl/TopPriority.java b/impl/core/src/test/java/io/serverlessworkflow/impl/TopPriority.java
new file mode 100644
index 000000000..ce7bd88ff
--- /dev/null
+++ b/impl/core/src/test/java/io/serverlessworkflow/impl/TopPriority.java
@@ -0,0 +1,22 @@
+/*
+ * 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;
+
+public class TopPriority implements ServicePriority {
+ public int priority() {
+ return DEFAULT_PRIORITY - 1;
+ }
+}
diff --git a/impl/core/src/test/resources/META-INF/services/io.serverlessworkflow.impl.ServicePriority b/impl/core/src/test/resources/META-INF/services/io.serverlessworkflow.impl.ServicePriority
new file mode 100644
index 000000000..0c5166da3
--- /dev/null
+++ b/impl/core/src/test/resources/META-INF/services/io.serverlessworkflow.impl.ServicePriority
@@ -0,0 +1,3 @@
+io.serverlessworkflow.impl.LowestPriority
+io.serverlessworkflow.impl.TopPriority
+io.serverlessworkflow.impl.MediumPriority
diff --git a/impl/jq/src/test/java/io/serverlessworkflow/impl/expressions/jq/JQExpressionFactoryTest.java b/impl/jq/src/test/java/io/serverlessworkflow/impl/expressions/jq/JQExpressionFactoryTest.java
index 784de6885..aa9bcc8b2 100644
--- a/impl/jq/src/test/java/io/serverlessworkflow/impl/expressions/jq/JQExpressionFactoryTest.java
+++ b/impl/jq/src/test/java/io/serverlessworkflow/impl/expressions/jq/JQExpressionFactoryTest.java
@@ -15,6 +15,7 @@
*/
package io.serverlessworkflow.impl.expressions.jq;
+import static io.serverlessworkflow.impl.WorkflowUtils.loadFirst;
import static org.assertj.core.api.Assertions.assertThat;
import io.serverlessworkflow.impl.WorkflowContext;
@@ -26,7 +27,6 @@
import java.util.Iterator;
import java.util.List;
import java.util.Map;
-import java.util.ServiceLoader;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
@@ -41,7 +41,7 @@ class JQExpressionFactoryTest {
void setup() {
workflowContext = Mockito.mock(WorkflowContext.class);
factory = new JQExpressionFactory();
- modelFactory = ServiceLoader.load(WorkflowModelFactory.class).findFirst().orElseThrow();
+ modelFactory = loadFirst(WorkflowModelFactory.class).orElseThrow();
}
@Test
diff --git a/impl/json-utils/src/main/java/io/serverlessworkflow/impl/jackson/ObjectMapperFactory.java b/impl/json-utils/src/main/java/io/serverlessworkflow/impl/jackson/ObjectMapperFactory.java
index 684a60a61..6cc04cf24 100644
--- a/impl/json-utils/src/main/java/io/serverlessworkflow/impl/jackson/ObjectMapperFactory.java
+++ b/impl/json-utils/src/main/java/io/serverlessworkflow/impl/jackson/ObjectMapperFactory.java
@@ -16,6 +16,7 @@
package io.serverlessworkflow.impl.jackson;
import com.fasterxml.jackson.databind.ObjectMapper;
+import io.serverlessworkflow.impl.ServicePriority;
import java.util.function.Supplier;
-public interface ObjectMapperFactory extends Supplier {}
+public interface ObjectMapperFactory extends Supplier, ServicePriority {}
diff --git a/impl/json-utils/src/main/java/io/serverlessworkflow/impl/jackson/ObjectMapperFactoryProvider.java b/impl/json-utils/src/main/java/io/serverlessworkflow/impl/jackson/ObjectMapperFactoryProvider.java
index df6d8a91e..3a12ea3d9 100644
--- a/impl/json-utils/src/main/java/io/serverlessworkflow/impl/jackson/ObjectMapperFactoryProvider.java
+++ b/impl/json-utils/src/main/java/io/serverlessworkflow/impl/jackson/ObjectMapperFactoryProvider.java
@@ -15,9 +15,10 @@
*/
package io.serverlessworkflow.impl.jackson;
+import static io.serverlessworkflow.impl.WorkflowUtils.loadFirst;
+
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.Objects;
-import java.util.ServiceLoader;
import java.util.function.Supplier;
public class ObjectMapperFactoryProvider implements Supplier {
@@ -40,8 +41,7 @@ public void setFactory(ObjectMapperFactory objectMapperFactory) {
public ObjectMapperFactory get() {
return objectMapperFactory != null
? objectMapperFactory
- : ServiceLoader.load(ObjectMapperFactory.class)
- .findFirst()
+ : loadFirst(ObjectMapperFactory.class)
.orElseGet(() -> () -> new ObjectMapper().findAndRegisterModules());
}
}
diff --git a/impl/persistence/api/src/main/java/io/serverlessworkflow/impl/marshaller/CustomObjectMarshaller.java b/impl/persistence/api/src/main/java/io/serverlessworkflow/impl/marshaller/CustomObjectMarshaller.java
index b96283b64..23fbe1bb1 100644
--- a/impl/persistence/api/src/main/java/io/serverlessworkflow/impl/marshaller/CustomObjectMarshaller.java
+++ b/impl/persistence/api/src/main/java/io/serverlessworkflow/impl/marshaller/CustomObjectMarshaller.java
@@ -15,7 +15,9 @@
*/
package io.serverlessworkflow.impl.marshaller;
-public interface CustomObjectMarshaller {
+import io.serverlessworkflow.impl.ServicePriority;
+
+public interface CustomObjectMarshaller extends ServicePriority {
void write(WorkflowOutputBuffer buffer, T object);
T read(WorkflowInputBuffer buffer);