Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

import io.serverlessworkflow.api.types.SchemaInline;
import io.serverlessworkflow.api.types.Workflow;
import io.serverlessworkflow.impl.additional.NamedWorkflowAdditionalObject;
import io.serverlessworkflow.impl.additional.WorkflowAdditionalObject;
import io.serverlessworkflow.impl.config.ConfigManager;
import io.serverlessworkflow.impl.config.ConfigSecretManager;
Expand Down Expand Up @@ -172,13 +173,16 @@ public SchemaValidator getValidator(SchemaInline inline) {
() -> new RuntimeDescriptor("reference impl", "1.0.0_alpha", Collections.emptyMap());
private boolean lifeCycleCEPublishingEnabled = true;
private WorkflowModelFactory modelFactory;
private Map<String, WorkflowAdditionalObject<?>> additionalObjects;
private Map<String, WorkflowAdditionalObject<?>> additionalObjects = new HashMap<>();
private SecretManager secretManager;
private ConfigManager configManager;
private SchedulerListener schedulerListener;
private Optional<URITemplateResolver> templateResolver;

private Builder() {}
private Builder() {
ServiceLoader.load(NamedWorkflowAdditionalObject.class)
.forEach(a -> additionalObjects.put(a.name(), a));
}

public Builder withListener(WorkflowExecutionListener listener) {
listeners.add(listener);
Expand Down Expand Up @@ -257,9 +261,6 @@ public Builder withConfigManager(ConfigManager configManager) {

public <T> Builder withAdditionalObject(
String name, WorkflowAdditionalObject<T> additionalObject) {
if (additionalObjects == null) {
additionalObjects = new HashMap<>();
}
additionalObjects.put(name, additionalObject);
return this;
}
Expand Down Expand Up @@ -314,9 +315,7 @@ public WorkflowApplication build() {
}
schedulerListener = new SchedulerListener(scheduler);
listeners.add(schedulerListener);
if (additionalObjects == null) {
additionalObjects = Collections.emptyMap();
}

if (configManager == null) {
configManager =
ServiceLoader.load(ConfigManager.class)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
* 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.additional;

public interface NamedWorkflowAdditionalObject<T> extends WorkflowAdditionalObject<T> {
String name();
}
Original file line number Diff line number Diff line change
@@ -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.impl.executors.http;

import io.serverlessworkflow.impl.TaskContext;
import io.serverlessworkflow.impl.WorkflowContext;

public class HttpConverterResolver {

public static final String HTTP_MODEL_CONVERTER = "httpModelConverter";

private static class DefaultHolder {
private static final HttpModelConverter converter =
new HttpModelConverter() {
@Override
public Class<?> responseType() {
return Object.class;
}
};
}

public static HttpModelConverter converter(
WorkflowContext workflowContext, TaskContext taskContext) {
return workflowContext
.definition()
.application()
.<HttpModelConverter>additionalObject(HTTP_MODEL_CONVERTER, workflowContext, taskContext)
.orElseGet(() -> DefaultHolder.converter);
}

private HttpConverterResolver() {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,6 @@

public class HttpExecutor implements CallableTask<CallHTTP> {

// TODO allow changing default converter
private static final HttpModelConverter defaultConverter = new HttpModelConverter() {};

private WorkflowValueResolver<WebTarget> targetSupplier;
private Optional<WorkflowValueResolver<Map<String, Object>>> headersMap;
private Optional<WorkflowValueResolver<Map<String, Object>>> queryMap;
Expand Down Expand Up @@ -124,8 +121,7 @@ public HttpExecutor build(WorkflowValueResolver<URI> uriSupplier) {
? getTargetSupplier(uriSupplier)
: getTargetSupplier(uriSupplier, pathSupplier);
executor.authProvider = AuthProviderFactory.getAuth(definition, authPolicy);
executor.requestFunction =
buildRequestSupplier(method, body, definition.application(), defaultConverter);
executor.requestFunction = buildRequestSupplier(method, body, definition.application());
executor.headersMap = Optional.ofNullable(headersMap);
executor.queryMap = Optional.ofNullable(queryMap);
return executor;
Expand Down Expand Up @@ -176,27 +172,31 @@ public void init(CallHTTP task, WorkflowDefinition definition) {
: Optional.empty();
this.requestFunction =
buildRequestSupplier(
httpArgs.getMethod().toUpperCase(),
httpArgs.getBody(),
definition.application(),
defaultConverter);
httpArgs.getMethod().toUpperCase(), httpArgs.getBody(), definition.application());
}

private static RequestSupplier buildRequestSupplier(
String method, Object body, WorkflowApplication application, HttpModelConverter converter) {
String method, Object body, WorkflowApplication application) {

switch (method.toUpperCase()) {
case HttpMethod.POST:
WorkflowFilter bodyFilter = WorkflowUtils.buildWorkflowFilter(application, body);
return (request, w, context, node) ->
converter.toModel(
application.modelFactory(),
node,
request.post(
converter.toEntity(bodyFilter.apply(w, context, node)), node.objectClass()));
return (request, w, t, node) -> {
HttpModelConverter converter = HttpConverterResolver.converter(w, t);
return w.definition()
.application()
.modelFactory()
.fromAny(
request.post(
converter.toEntity(bodyFilter.apply(w, t, node)), converter.responseType()));
};
case HttpMethod.GET:
default:
return (request, w, t, n) ->
converter.toModel(application.modelFactory(), n, request.get(n.objectClass()));
w.definition()
.application()
.modelFactory()
.fromAny(request.get(HttpConverterResolver.converter(w, t).responseType()));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,13 @@
package io.serverlessworkflow.impl.executors.http;

import io.serverlessworkflow.impl.WorkflowModel;
import io.serverlessworkflow.impl.WorkflowModelFactory;
import jakarta.ws.rs.client.Entity;

public interface HttpModelConverter {

default WorkflowModel toModel(WorkflowModelFactory factory, WorkflowModel model, Object entity) {
return factory.fromAny(model, entity);
}

default Entity toEntity(WorkflowModel model) {
default Entity<?> toEntity(WorkflowModel model) {
return Entity.json(model.as(model.objectClass()).orElseThrow());
}

Class<?> responseType();
}
Original file line number Diff line number Diff line change
@@ -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.jackson;

import com.fasterxml.jackson.databind.JsonNode;
import io.serverlessworkflow.impl.TaskContextData;
import io.serverlessworkflow.impl.WorkflowContextData;
import io.serverlessworkflow.impl.additional.NamedWorkflowAdditionalObject;
import io.serverlessworkflow.impl.executors.http.HttpConverterResolver;
import io.serverlessworkflow.impl.executors.http.HttpModelConverter;

public class JacksonModelConverterFactory
implements NamedWorkflowAdditionalObject<HttpModelConverter> {

private static class JacksonModelConverterHolder {

private static HttpModelConverter converter =
new HttpModelConverter() {
@Override
public Class<?> responseType() {
return JsonNode.class;
}
};
}

@Override
public HttpModelConverter apply(WorkflowContextData t, TaskContextData u) {
return JacksonModelConverterHolder.converter;
}

@Override
public String name() {
return HttpConverterResolver.HTTP_MODEL_CONVERTER;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
io.serverlessworkflow.impl.executors.http.jackson.JacksonModelConverterFactory
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,10 @@ private static Stream<Arguments> provideParameters() {
"workflows-samples/call-http-endpoint-interpolation.yaml", petInput, petCondition),
Arguments.of(
"workflows-samples/call-http-query-parameters.yaml", starTrekInput, starTrekCondition),
Arguments.of(
"workflows-samples/callFindByStatusHttp.yaml",
Map.of(),
new Condition<WorkflowModel>(o -> !o.asCollection().isEmpty(), "HasElementCondition")),
Arguments.of(
"workflows-samples/call-http-query-parameters-external-schema.yaml",
starTrekInput,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
document:
dsl: 1.0.0-alpha1
namespace: test
name: http-call-find-by-status
version: 1.0.0
do:
- tryGetPet:
try:
- getPet:
call: http
with:
headers:
content-type: application/json
method: get
endpoint:
uri: https://petstore.swagger.io/v2/pet/findByStatus?status=sold
catch:
errors:
with:
type: https://serverlessworkflow.io/spec/1.0.0/errors/communication
status: 404