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
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import io.cloudevents.CloudEvent;
import io.cloudevents.CloudEventData;
import java.time.OffsetDateTime;
import java.util.Base64;
import java.util.Map;
import java.util.Optional;

Expand All @@ -41,6 +42,10 @@ public interface WorkflowModelFactory extends ServicePriority<WorkflowModelFacto

WorkflowModel from(Map<String, Object> map);

default WorkflowModel from(byte[] bytes) {
return from(new String(Base64.getEncoder().encode(bytes)));
}

WorkflowModel fromNull();

default WorkflowModel fromOther(Object obj) {
Expand All @@ -63,6 +68,7 @@ default WorkflowModel fromAny(Object obj) {
case CloudEventData value -> from(value);
case OffsetDateTime value -> from(value);
case Map map -> from(map);
case byte[] bytes -> from(bytes);
case WorkflowModel model -> model;
default -> fromOther(obj);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
import org.openworkflow.sdk.impl.WorkflowApplication;
import org.openworkflow.sdk.impl.WorkflowContext;
import org.openworkflow.sdk.impl.http.WorkflowHttpContentType;
import org.openworkflow.sdk.impl.http.WorkflowHttpRequestHelper;
import org.openworkflow.sdk.impl.http.WorkflowHttpHelper;
import org.openworkflow.sdk.impl.http.WorkflowHttpRequestInfo;

class AccessTokenProvider {
Expand All @@ -48,7 +48,7 @@ public CompletableFuture<JWT> validateAndGet(WorkflowContext workflow, TaskConte
WorkflowHttpRequestInfo httpRequestInfo =
buildHttpRequestInfo(workflow, context, authRequestInfo);
CompletableFuture<JWT> future =
WorkflowHttpRequestHelper.executeRequest(httpRequestInfo, app, workflow, context)
WorkflowHttpHelper.executeRequest(httpRequestInfo, app, workflow, context)
.thenApply(bytes -> jwtConverter.fromToken(bytes));
List<String> issuers = authRequestInfo.issuers();
if (!issuers.isEmpty()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ private String processResponse(
WorkflowHttpResponse r, URI uri, String method, WorkflowContext workflow, TaskContext task) {
int responseCode = r.status();
if (responseCode == 401) {
DigestServerInfo serverInfo = DigestServerInfo.from((String) r.getHeader("WWW-Authenticate"));
DigestServerInfo serverInfo = DigestServerInfo.from(r.getHeader("WWW-Authenticate"));
String userName = userFilter.apply(workflow, task);
String path = uri.getPath();
String nonceCount;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,15 @@

import static org.openworkflow.sdk.impl.WorkflowUtils.buildMapResolver;

import java.net.URI;
import org.openworkflow.sdk.api.types.CallHTTP;
import org.openworkflow.sdk.api.types.Endpoint;
import org.openworkflow.sdk.api.types.HTTPArguments;
import org.openworkflow.sdk.api.types.TaskBase;
import org.openworkflow.sdk.impl.WorkflowDefinition;
import org.openworkflow.sdk.impl.WorkflowMutablePosition;
import org.openworkflow.sdk.impl.WorkflowValueResolver;
import org.openworkflow.sdk.impl.executors.CallableTaskBuilder;
import org.openworkflow.sdk.impl.executors.CallableTaskFactory;
import org.openworkflow.sdk.impl.http.WorkflowHttpHelper;
import org.openworkflow.sdk.impl.http.WorkflowHttpRequestInfoBuilderFactory;

public class CallableTaskHttpExecutorBuilder implements CallableTaskBuilder<CallHTTP> {
Expand All @@ -41,10 +40,6 @@ public CallableTaskFactory init(
.withBody(httpArgs.getBody())
.withMethod(httpArgs.getMethod().toUpperCase())
.redirect(httpArgs.isRedirect());
final Endpoint endpoint = httpArgs.getEndpoint();
if (endpoint.getEndpointConfiguration() != null) {
builder.withAuth(endpoint.getEndpointConfiguration().getAuthentication());
}
if (httpArgs.getHeaders() != null) {
builder.withHeaders(
buildMapResolver(
Expand All @@ -63,9 +58,25 @@ public CallableTaskFactory init(
? httpArgs.getQuery().getHTTPQuery().getAdditionalProperties()
: null));
}
final WorkflowValueResolver<URI> uriSupplier =
definition.resourceLoader().uriSupplier(endpoint);
return () -> new HttpExecutor(builder, uriSupplier);
final Endpoint endpoint = httpArgs.getEndpoint();
if (endpoint.getEndpointConfiguration() != null) {
builder.withAuth(endpoint.getEndpointConfiguration().getAuthentication());
}
return () ->
new HttpExecutor(
builder,
definition.resourceLoader().uriSupplier(endpoint),
buildOutputFunction(httpArgs));
}

private WorkflowHttpHelper.WorkflowHttpOutputFunction buildOutputFunction(
HTTPArguments httpArgs) {
return switch (httpArgs.getOutput()) {
case null -> WorkflowHttpHelper.contentFunction;
case CONTENT -> WorkflowHttpHelper.contentFunction;
case RESPONSE -> WorkflowHttpHelper.responseFunction;
case RAW -> WorkflowHttpHelper.rawFunction;
};
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,27 +22,32 @@
import org.openworkflow.sdk.impl.WorkflowModel;
import org.openworkflow.sdk.impl.WorkflowValueResolver;
import org.openworkflow.sdk.impl.executors.CallableTask;
import org.openworkflow.sdk.impl.http.WorkflowHttpRequestHelper;
import org.openworkflow.sdk.impl.http.WorkflowHttpHelper;
import org.openworkflow.sdk.impl.http.WorkflowHttpRequestInfoBuilderFactory;

public class HttpExecutor implements CallableTask {

private final WorkflowHttpRequestInfoBuilderFactory builder;
private final WorkflowValueResolver<URI> uriSupplier;
WorkflowHttpHelper.WorkflowHttpOutputFunction outputFunction;

public HttpExecutor(
WorkflowHttpRequestInfoBuilderFactory builder, WorkflowValueResolver<URI> uriSupplier) {
WorkflowHttpRequestInfoBuilderFactory builder,
WorkflowValueResolver<URI> uriSupplier,
WorkflowHttpHelper.WorkflowHttpOutputFunction outputFunction) {
this.builder = builder;
this.uriSupplier = uriSupplier;
this.outputFunction = outputFunction;
}

public CompletableFuture<WorkflowModel> apply(
WorkflowContext workflow, TaskContext taskContext, WorkflowModel input) {
return WorkflowHttpRequestHelper.executeRequest(
return WorkflowHttpHelper.executeRequest(
builder
.build(workflow, taskContext, input)
.build(uriSupplier.apply(workflow, taskContext, input)),
workflow,
taskContext);
taskContext,
outputFunction);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
import org.openworkflow.sdk.impl.WorkflowContext;
import org.openworkflow.sdk.impl.WorkflowModel;
import org.openworkflow.sdk.impl.executors.CallableTask;
import org.openworkflow.sdk.impl.http.WorkflowHttpRequestHelper;
import org.openworkflow.sdk.impl.http.WorkflowHttpHelper;
import org.openworkflow.sdk.impl.http.WorkflowHttpRequestInfo.Builder;
import org.openworkflow.sdk.impl.http.WorkflowHttpRequestInfoBuilderFactory;

Expand Down Expand Up @@ -72,13 +72,13 @@ public CompletableFuture<WorkflowModel> apply(
"List of servers is empty for schema " + resource.getName());
}
CompletableFuture<WorkflowModel> future =
WorkflowHttpRequestHelper.executeRequest(
WorkflowHttpHelper.executeRequest(
httpInfoBuilder.build(URI.create(iter.next())), workflowContext, taskContext);
while (iter.hasNext()) {
final String uri = iter.next();
future =
future.exceptionallyCompose(i ->
WorkflowHttpRequestHelper.executeRequest(
WorkflowHttpHelper.executeRequest(
httpInfoBuilder.build(URI.create(uri)), workflowContext, taskContext));
}
return future;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,9 @@

public class DefaultHttpRequest implements WorkflowHttpRequest {

private final WorkflowHttpRequestInfo httpInfo;
protected final WorkflowHttpRequestInfo httpInfo;
protected final WorkflowApplication app;
private final HttpClient client;
private final WorkflowApplication app;

public DefaultHttpRequest(
WorkflowApplication app, HttpClient client, WorkflowHttpRequestInfo httpInfo) {
Expand All @@ -62,14 +62,13 @@ public CompletableFuture<WorkflowHttpResponse> invoke(
builder.uri(uri);
String ifModifiedSince = httpInfo.ifModifiedSince();
if (ifModifiedSince != null) {
builder.header(WorkflowHttpRequestHelper.IF_MODIFIED_SINCE_HEADER, ifModifiedSince);
builder.header(WorkflowHttpHelper.IF_MODIFIED_SINCE_HEADER, ifModifiedSince);
}
return WorkflowHttpRequestHelper.processAuth(
httpInfo, builder::header, workflowContext, taskContext)
return WorkflowHttpHelper.processAuth(httpInfo, builder::header, workflowContext, taskContext)
.thenCompose(
__ -> client.sendAsync(builder.build(), HttpResponse.BodyHandlers.ofByteArray()))
.exceptionallyCompose(ex ->
CompletableFuture.failedFuture(WorkflowHttpRequestHelper.fromError(ex, taskContext)))
.exceptionallyCompose(
ex -> CompletableFuture.failedFuture(WorkflowHttpHelper.fromError(ex, taskContext)))
.thenApply(response -> new DefaultHttpResponse(app, taskContext, response));
}

Expand All @@ -81,29 +80,58 @@ private URI addQueryParams(URI uri, Map<String, Object> queryParams) {
.build();
}

private BodyPublisher buildBody() {
protected BodyPublisher buildBody() {
WorkflowModel body = httpInfo.body();
WorkflowHttpContentType contentType = httpInfo.contentType();
if (body == null || body.isNull()) {
return HttpRequest.BodyPublishers.noBody();
}
return switch (httpInfo.contentType()) {
case WorkflowHttpContentType.APPLICATION_JSON ->
HttpRequest.BodyPublishers.ofByteArray(
body.asJson()
if (contentType == WorkflowHttpContentType.APPLICATION_JSON) {
return buildJsonBody();
} else if (contentType == WorkflowHttpContentType.APPLICATION_X_WWW_FORM_URLENCODED) {
return HttpRequest.BodyPublishers.ofString(
encodeMap(
httpInfo
.body()
.asMap()
.orElseThrow(() ->
new IllegalStateException(
"Underlying model needs to support json in order to use application-json content type")));
case WorkflowHttpContentType.APPLICATION_X_WWW_FORM_URLENCODED ->
HttpRequest.BodyPublishers.ofString(
encodeMap(
httpInfo
.body()
.asMap()
.orElseThrow(() ->
new IllegalStateException(
"Underlying model needs to support asMap in order to use form urlencoded content type")),
DefaultHttpRequest::encodeForm));
};
"Underlying model needs to support asMap in order to use form urlencoded content type")),
DefaultHttpRequest::encodeForm));
} else if (isTextMediaType(contentType)) {
return HttpRequest.BodyPublishers.ofString(
body.asText()
Comment on lines +102 to +103
.orElseThrow(() ->
new IllegalStateException(
"Undelying model needs to support as text to use content type "
+ contentType)));
} else {
return fallbackBuildBody();
}
}

/*
* User might override this to change which is considered a text media type
*/
protected boolean isTextMediaType(WorkflowHttpContentType contentType) {
return WorkflowHttpHelper.isTextMediaType(contentType);
}

/*
* Users might override this to provide different behavior for additional content types
*/
protected BodyPublisher fallbackBuildBody() {
return buildJsonBody();
}

private BodyPublisher buildJsonBody() {
return HttpRequest.BodyPublishers.ofByteArray(
httpInfo
.body()
.asJson()
.orElseThrow(() ->
new IllegalStateException(
"Underlying model needs to support json in order to use application-json content type")));
}

private String encodeMap(Map<String, Object> map, Function<Object, String> decoder) {
Expand Down
Loading
Loading