Skip to content
Open
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
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* 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 static io.serverlessworkflow.impl.executors.http.HttpExecutor.client;

import io.serverlessworkflow.impl.TaskContext;
import io.serverlessworkflow.impl.WorkflowContext;
import io.serverlessworkflow.impl.WorkflowModel;
import io.serverlessworkflow.impl.WorkflowValueResolver;
import jakarta.ws.rs.client.WebTarget;

public class ExpressionURISupplier implements TargetSupplier {
private WorkflowValueResolver<String> expr;

public ExpressionURISupplier(WorkflowValueResolver<String> expr) {
this.expr = expr;
}

@Override
public WebTarget apply(WorkflowContext workflow, TaskContext task, WorkflowModel node) {
return client.target(expr.apply(workflow, task, node));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@

public class HttpExecutor implements CallableTask<CallHTTP> {

private static final Client client = ClientBuilder.newClient();
public static final Client client = ClientBuilder.newClient();

private TargetSupplier targetSupplier;
private Optional<WorkflowValueResolver<Map<String, Object>>> headersMap;
Expand All @@ -56,11 +56,6 @@ public class HttpExecutor implements CallableTask<CallHTTP> {
private RequestSupplier requestFunction;
private HttpModelConverter converter = new HttpModelConverter() {};

@FunctionalInterface
private interface TargetSupplier {
WebTarget apply(WorkflowContext workflow, TaskContext task, WorkflowModel node);
}

@FunctionalInterface
private interface RequestSupplier {
WorkflowModel apply(
Expand Down Expand Up @@ -172,7 +167,7 @@ public boolean accept(Class<? extends TaskBase> clazz) {
return clazz.equals(CallHTTP.class);
}

private static TargetSupplier getTargetSupplier(
public static TargetSupplier getTargetSupplier(
Endpoint endpoint, ExpressionFactory expressionFactory) {
if (endpoint.getEndpointConfiguration() != null) {
EndpointUri uri = endpoint.getEndpointConfiguration().getUri();
Expand All @@ -193,7 +188,7 @@ private static TargetSupplier getTargetSupplier(
throw new IllegalArgumentException("Invalid endpoint definition " + endpoint);
}

private static TargetSupplier getURISupplier(UriTemplate template) {
public static TargetSupplier getURISupplier(UriTemplate template) {
if (template.getLiteralUri() != null) {
return (w, t, n) -> client.target(template.getLiteralUri());
} else if (template.getLiteralUriTemplate() != null) {
Expand All @@ -202,17 +197,4 @@ private static TargetSupplier getURISupplier(UriTemplate template) {
}
throw new IllegalArgumentException("Invalid uritemplate definition " + template);
}

private static class ExpressionURISupplier implements TargetSupplier {
private WorkflowValueResolver<String> expr;

public ExpressionURISupplier(WorkflowValueResolver<String> expr) {
this.expr = expr;
}

@Override
public WebTarget apply(WorkflowContext workflow, TaskContext task, WorkflowModel node) {
return client.target(expr.apply(workflow, task, node));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* 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.WebTarget;

public interface TargetSupplier {
WebTarget apply(WorkflowContext workflow, TaskContext task, WorkflowModel node);
}
30 changes: 30 additions & 0 deletions impl/openapi/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>io.serverlessworkflow</groupId>
<artifactId>serverlessworkflow-impl</artifactId>
<version>8.0.0-SNAPSHOT</version>
</parent>
<artifactId>serverlessworkflow-impl-openapi</artifactId>
<name>Serverless Workflow :: Impl :: OpenAPI</name>
<dependencies>
<dependency>
<groupId>jakarta.ws.rs</groupId>
<artifactId>jakarta.ws.rs-api</artifactId>
</dependency>
<dependency>
<groupId>io.serverlessworkflow</groupId>
<artifactId>serverlessworkflow-impl-core</artifactId>
</dependency>
<dependency>
<groupId>io.serverlessworkflow</groupId>
<artifactId>serverlessworkflow-impl-http</artifactId>
</dependency>
<dependency>
<groupId>io.swagger.parser.v3</groupId>
<artifactId>swagger-parser</artifactId>
<version>${version.io.swagger.parser.v3}</version>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
/*
* 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.openapi;

import io.serverlessworkflow.api.types.CallHTTP;
import io.serverlessworkflow.api.types.Endpoint;
import io.serverlessworkflow.api.types.EndpointConfiguration;
import io.serverlessworkflow.api.types.HTTPArguments;
import io.serverlessworkflow.api.types.HTTPHeaders;
import io.serverlessworkflow.api.types.HTTPQuery;
import io.serverlessworkflow.api.types.Headers;
import io.serverlessworkflow.api.types.Query;
import io.serverlessworkflow.api.types.ReferenceableAuthenticationPolicy;
import io.serverlessworkflow.api.types.TaskTimeout;
import io.serverlessworkflow.api.types.Timeout;
import io.serverlessworkflow.api.types.TimeoutAfter;
import io.serverlessworkflow.api.types.UriTemplate;
import io.swagger.v3.oas.models.media.Schema;
import io.swagger.v3.oas.models.parameters.Parameter;
import java.net.URI;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;

@SuppressWarnings("rawtypes")
class HttpCallAdapter {

private ReferenceableAuthenticationPolicy auth;
private Map<String, Schema> body;
private String contentType;
private Collection<Parameter> headers;
private String method;
private Collection<Parameter> query;
private boolean redirect;
private URI server;
private URI target;
private Map<String, Object> workflowParams;

HttpCallAdapter auth(ReferenceableAuthenticationPolicy policy) {
if (policy != null) {
this.auth = policy;
}
return this;
}

HttpCallAdapter body(Map<String, Schema> body) {
this.body = body;
return this;
}

CallHTTP build() {
CallHTTP callHTTP = new CallHTTP();

HTTPArguments httpArgs = new HTTPArguments();
callHTTP.withWith(httpArgs);

Endpoint endpoint = new Endpoint();
httpArgs.withEndpoint(endpoint);

if (this.auth != null) {
EndpointConfiguration endPointConfig = new EndpointConfiguration();
endPointConfig.setAuthentication(this.auth);
endpoint.setEndpointConfiguration(endPointConfig);
}

httpArgs.setRedirect(this.redirect);
httpArgs.setMethod(this.method);

addHttpHeaders(httpArgs);
addQueryParams(httpArgs);
addBody(httpArgs);

addTarget(endpoint);

TaskTimeout taskTimeout = new TaskTimeout();
Timeout timeout = new Timeout();
taskTimeout.withTaskTimeoutDefinition(timeout);
TimeoutAfter timeoutAfter = new TimeoutAfter();
timeout.setAfter(timeoutAfter);
timeoutAfter.withDurationExpression("PT30S");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be configurable (or deleted)

callHTTP.setTimeout(taskTimeout);

return callHTTP;
}

HttpCallAdapter contentType(String contentType) {
this.contentType = contentType;
return this;
}

HttpCallAdapter headers(Collection<io.swagger.v3.oas.models.parameters.Parameter> headers) {
this.headers = headers;
return this;
}

HttpCallAdapter method(String method) {
this.method = method;
return this;
}

HttpCallAdapter query(Collection<io.swagger.v3.oas.models.parameters.Parameter> query) {
this.query = query;
return this;
}

HttpCallAdapter redirect(boolean redirect) {
this.redirect = redirect;
return this;
}

HttpCallAdapter server(String server) {
this.server = URI.create(server);
return this;
}

HttpCallAdapter target(URI target) {
this.target = target;
return this;
}

HttpCallAdapter workflowParams(Map<String, Object> workflowParams) {
this.workflowParams = workflowParams;
return this;
}

private void addBody(HTTPArguments httpArgs) {
Map<String, Object> bodyContent = new LinkedHashMap<>();
if (!(body == null || body.isEmpty())) {
for (Map.Entry<String, Schema> entry : body.entrySet()) {
String name = entry.getKey();
if (workflowParams.containsKey(name)) {
Object value = workflowParams.get(name);
bodyContent.put(name, value);
}
}
if (!bodyContent.isEmpty()) {
httpArgs.setBody(bodyContent);
}
}
}

private void addHttpHeaders(HTTPArguments httpArgs) {
if (!(headers == null || headers.isEmpty())) {
Headers hdrs = new Headers();
HTTPHeaders httpHeaders = new HTTPHeaders();
hdrs.setHTTPHeaders(httpHeaders);
httpArgs.setHeaders(hdrs);

for (Parameter p : headers) {
String name = p.getName();
if (workflowParams.containsKey(name)) {
Object value = workflowParams.get(name);
if (value instanceof String asString) {
httpHeaders.setAdditionalProperty(name, asString);
} else {
throw new IllegalArgumentException("Header parameter " + name + " must be a String");
}
}
}
}
}

private void addQueryParams(HTTPArguments httpArgs) {
if (!(query == null || query.isEmpty())) {
Query queryParams = new Query();
httpArgs.setQuery(queryParams);
HTTPQuery httpQuery = new HTTPQuery();
queryParams.setHTTPQuery(httpQuery);

for (Parameter p : query) {
String name = p.getName();
if (workflowParams.containsKey(name)) {
Object value = workflowParams.get(name);
if (value instanceof String asString) {
httpQuery.setAdditionalProperty(name, asString);
} else if (value instanceof Number asNumber) {
httpQuery.setAdditionalProperty(name, asNumber.toString());
} else if (value instanceof Boolean asBoolean) {
httpQuery.setAdditionalProperty(name, asBoolean.toString());
} else if (value instanceof Character asCharacter) {
httpQuery.setAdditionalProperty(name, asCharacter.toString());
} else {
httpQuery.setAdditionalProperty(name, value.toString());
}
}
}
}
}

private void addTarget(Endpoint endpoint) {
if (this.target == null) {
throw new IllegalArgumentException("No Server defined for the OpenAPI operation");
}
UriTemplate uriTemplate = new UriTemplate();
uriTemplate.withLiteralUri(this.server.resolve(this.target.getPath()));
endpoint.setUriTemplate(uriTemplate);
}
}
Loading