Skip to content

Commit

Permalink
[Fix #461] alternative approach
Browse files Browse the repository at this point in the history
Signed-off-by: Francisco Javier Tirado Sarti <[email protected]>
  • Loading branch information
fjtirado committed Nov 12, 2024
1 parent c72cfe5 commit a345386
Show file tree
Hide file tree
Showing 15 changed files with 369 additions and 89 deletions.
15 changes: 15 additions & 0 deletions api/src/main/java/io/serverlessworkflow/api/WorkflowReader.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,12 @@
package io.serverlessworkflow.api;

import io.serverlessworkflow.api.types.Workflow;
import java.io.ByteArrayInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.io.StringReader;
import java.nio.file.Files;
import java.nio.file.Path;

Expand All @@ -37,6 +39,19 @@ public static Workflow readWorkflow(Path path, WorkflowFormat format) throws IOE
return format.mapper().readValue(Files.readAllBytes(path), Workflow.class);
}

public static Workflow readWorkflow(byte[] content, WorkflowFormat format) throws IOException {
try (InputStream input = new ByteArrayInputStream(content)) {
return readWorkflow(input, format);
}
}

public static Workflow readWorkflowFromString(String content, WorkflowFormat format)
throws IOException {
try (Reader reader = new StringReader(content)) {
return readWorkflow(reader, format);
}
}

public static Workflow readWorkflowFromClasspath(String classpath) throws IOException {
return readWorkflowFromClasspath(
classpath,
Expand Down
18 changes: 18 additions & 0 deletions api/src/main/java/io/serverlessworkflow/api/WorkflowWriter.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@
package io.serverlessworkflow.api;

import io.serverlessworkflow.api.types.Workflow;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.StringWriter;
import java.io.Writer;
import java.nio.file.Files;
import java.nio.file.Path;
Expand Down Expand Up @@ -45,5 +47,21 @@ public static void writeWorkflow(Path output, Workflow workflow, WorkflowFormat
}
}

public static String workflowAsString(Workflow workflow, WorkflowFormat format)
throws IOException {
try (Writer writer = new StringWriter()) {
writeWorkflow(writer, workflow, format);
return writer.toString();
}
}

public static byte[] workflowAsBytes(Workflow workflow, WorkflowFormat format)
throws IOException {
try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
writeWorkflow(out, workflow, format);
return out.toByteArray();
}
}

private WorkflowWriter() {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,24 +21,58 @@
import com.fasterxml.jackson.databind.JsonMappingException;
import jakarta.validation.ConstraintViolationException;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;

public class DeserializeHelper {

public static <T> T deserializeOneOf(
JsonParser p, Class<T> targetClass, Collection<Class<?>> unionTypes) throws IOException {
JsonParser p, Class<T> targetClass, Collection<Class<?>> oneOfTypes) throws IOException {
TreeNode node = p.readValueAsTree();
JsonProcessingException ex =
new JsonMappingException(p, "Problem deserializing " + targetClass);
for (Class<?> unionType : unionTypes) {
try {
Object object = p.getCodec().treeToValue(node, unionType);
return targetClass.getConstructor(unionType).newInstance(object);
} catch (IOException | ReflectiveOperationException | ConstraintViolationException io) {
ex.addSuppressed(io);
try {
T result = targetClass.getDeclaredConstructor().newInstance();
Collection<Exception> exceptions = new ArrayList<>();
for (Class<?> oneOfType : oneOfTypes) {
try {
assingIt(p, result, node, targetClass, oneOfType);
break;
} catch (IOException | ConstraintViolationException | InvocationTargetException ex) {
exceptions.add(ex);
}
}
if (exceptions.size() == oneOfTypes.size()) {
JsonMappingException ex =
new JsonMappingException(
p,
String.format(
"Error deserializing class %s, all oneOf alternatives %s has failed ",
targetClass, oneOfTypes));
exceptions.forEach(ex::addSuppressed);
throw ex;
}

return result;
} catch (ReflectiveOperationException ex) {
throw new IllegalStateException(ex);
}
}

private static <T> void assingIt(
JsonParser p, T result, TreeNode node, Class<T> targetClass, Class<?> type)
throws JsonProcessingException, ReflectiveOperationException {
findSetMethod(targetClass, type).invoke(result, p.getCodec().treeToValue(node, type));
}

private static Method findSetMethod(Class<?> targetClass, Class<?> type) {
for (Method method : targetClass.getMethods()) {
OneOfSetter oneOfSetter = method.getAnnotation(OneOfSetter.class);
if (oneOfSetter != null && type.equals(oneOfSetter.value())) {
return method;
}
}
throw ex;
throw new IllegalStateException("Cannot find a setter for type " + type);
}

public static <T> T deserializeItem(JsonParser p, Class<T> targetClass, Class<?> valueClass)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* 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.serialization;

import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Retention;
import java.lang.annotation.Target;

@Retention(RUNTIME)
@Target(METHOD)
public @interface OneOfSetter {
Class<?> value();
}
19 changes: 18 additions & 1 deletion api/src/test/java/io/serverlessworkflow/api/FeaturesTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@

import static io.serverlessworkflow.api.WorkflowReader.readWorkflow;
import static io.serverlessworkflow.api.WorkflowReader.readWorkflowFromClasspath;
import static io.serverlessworkflow.api.WorkflowWriter.workflowAsBytes;
import static io.serverlessworkflow.api.WorkflowWriter.workflowAsString;
import static io.serverlessworkflow.api.WorkflowWriter.writeWorkflow;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertNotNull;

import io.serverlessworkflow.api.types.Workflow;
Expand All @@ -32,6 +35,13 @@ public class FeaturesTest {
@ParameterizedTest
@ValueSource(
strings = {
"features/authentication-bearer.yaml",
"features/authentication-bearer-uri-format.yaml",
"features/authentication-oauth2.yaml",
"features/authentication-oauth2-secret.yaml",
"features/authentication-oidc.yaml",
"features/authentication-oidc-secret.yaml",
"features/authentication-reusable.yaml",
"features/callHttp.yaml",
"features/callOpenAPI.yaml",
"features/composite.yaml",
Expand All @@ -51,7 +61,7 @@ public class FeaturesTest {
public void testSpecFeaturesParsing(String workflowLocation) throws IOException {
Workflow workflow = readWorkflowFromClasspath(workflowLocation);
assertWorkflow(workflow);
assertWorkflow(writeAndReadInMemory(workflow));
assertWorkflowEquals(workflow, writeAndReadInMemory(workflow));
}

private static Workflow writeAndReadInMemory(Workflow workflow) throws IOException {
Expand All @@ -70,4 +80,11 @@ private static void assertWorkflow(Workflow workflow) {
assertNotNull(workflow.getDocument());
assertNotNull(workflow.getDo());
}

private static void assertWorkflowEquals(Workflow workflow, Workflow other) throws IOException {
assertThat(workflowAsString(workflow, WorkflowFormat.YAML))
.isEqualTo(workflowAsString(other, WorkflowFormat.YAML));
assertThat(workflowAsBytes(workflow, WorkflowFormat.JSON))
.isEqualTo(workflowAsBytes(other, WorkflowFormat.JSON));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
document:
dsl: '1.0.0-alpha5'
namespace: examples
name: bearer-auth
version: '0.1.0'
do:
- getPet:
call: http
with:
method: get
endpoint:
uri: https://petstore.swagger.io/v2/pet/{petId}
authentication:
bearer:
token: ${ .token }
15 changes: 15 additions & 0 deletions api/src/test/resources/features/authentication-bearer.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
document:
dsl: '1.0.0-alpha5'
namespace: examples
name: bearer-auth-uri-format
version: '0.1.0'
do:
- getPet:
call: http
with:
method: get
endpoint:
uri: https://petstore.swagger.io/v2/pet/1
authentication:
bearer:
token: ${ .token }
18 changes: 18 additions & 0 deletions api/src/test/resources/features/authentication-oauth2-secret.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
document:
dsl: 1.0.0-alpha1
namespace: examples
name: oauth2-authentication
version: 1.0.0-alpha1
use:
secrets:
- mySecret
do:
- getPet:
call: http
with:
method: get
endpoint:
uri: https://petstore.swagger.io/v2/pet/{petId}
authentication:
oauth2:
use: mySecret
22 changes: 22 additions & 0 deletions api/src/test/resources/features/authentication-oauth2.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
document:
dsl: '1.0.0-alpha5'
namespace: examples
name: oauth2-authentication
version: '0.1.0'
do:
- getPet:
call: http
with:
method: get
endpoint:
uri: https://petstore.swagger.io/v2/pet/{petId}
authentication:
oauth2:
authority: http://keycloak/realms/fake-authority
endpoints: #optional
token: /auth/token #defaults to /oauth2/token
introspection: /auth/introspect #defaults to /oauth2/introspect
grant: client_credentials
client:
id: workflow-runtime-id
secret: workflow-runtime-secret
18 changes: 18 additions & 0 deletions api/src/test/resources/features/authentication-oidc-secret.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
document:
dsl: 1.0.0-alpha1
namespace: examples
name: oidc-authentication
version: 1.0.0-alpha1
use:
secrets:
- mySecret
do:
- getPet:
call: http
with:
method: get
endpoint:
uri: https://petstore.swagger.io/v2/pet/{petId}
authentication:
oidc:
use: mySecret
19 changes: 19 additions & 0 deletions api/src/test/resources/features/authentication-oidc.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
document:
dsl: '1.0.0-alpha5'
namespace: examples
name: oidc-authentication
version: '0.1.0'
do:
- getPet:
call: http
with:
method: get
endpoint:
uri: https://petstore.swagger.io/v2/pet/{petId}
authentication:
oidc:
authority: http://keycloak/realms/fake-authority #endpoints are resolved using the OIDC configuration located at '/.well-known/openid-configuration'
grant: client_credentials
client:
id: workflow-runtime-id
secret: workflow-runtime-secret
19 changes: 19 additions & 0 deletions api/src/test/resources/features/authentication-reusable.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
document:
dsl: '1.0.0-alpha5'
namespace: examples
name: bearer-auth
version: '0.1.0'
use:
authentications:
petStoreAuth:
bearer:
token: ${ .token }
do:
- getPet:
call: http
with:
method: get
endpoint:
uri: https://petstore.swagger.io/v2/pet/{petId}
authentication:
use: petStoreAuth
Loading

0 comments on commit a345386

Please sign in to comment.