Skip to content

Commit b409915

Browse files
committed
[Fix #498] Adding possibility to validate before parsing
Fix #498 Signed-off-by: Francisco Javier Tirado Sarti <ftirados@redhat.com>
1 parent 0939916 commit b409915

File tree

12 files changed

+255
-63
lines changed

12 files changed

+255
-63
lines changed

api/pom.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@
2121
<groupId>com.fasterxml.jackson.core</groupId>
2222
<artifactId>jackson-core</artifactId>
2323
</dependency>
24+
<dependency>
25+
<groupId>com.networknt</groupId>
26+
<artifactId>json-schema-validator</artifactId>
27+
</dependency>
2428
<dependency>
2529
<groupId>com.fasterxml.jackson.core</groupId>
2630
<artifactId>jackson-databind</artifactId>
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* Copyright 2020-Present The Serverless Workflow Specification Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package io.serverlessworkflow.api;
17+
18+
import io.serverlessworkflow.api.types.Workflow;
19+
import java.io.IOException;
20+
import java.io.InputStream;
21+
import java.io.Reader;
22+
23+
class DirectReader implements WorkflowReaderOperations {
24+
25+
@Override
26+
public Workflow read(InputStream input, WorkflowFormat format) throws IOException {
27+
return format.mapper().readValue(input, Workflow.class);
28+
}
29+
30+
@Override
31+
public Workflow read(Reader input, WorkflowFormat format) throws IOException {
32+
return format.mapper().readValue(input, Workflow.class);
33+
}
34+
35+
@Override
36+
public Workflow read(byte[] input, WorkflowFormat format) throws IOException {
37+
return format.mapper().readValue(input, Workflow.class);
38+
}
39+
40+
@Override
41+
public Workflow read(String input, WorkflowFormat format) throws IOException {
42+
return format.mapper().readValue(input, Workflow.class);
43+
}
44+
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/*
2+
* Copyright 2020-Present The Serverless Workflow Specification Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package io.serverlessworkflow.api;
17+
18+
import com.fasterxml.jackson.databind.JsonNode;
19+
import com.networknt.schema.InputFormat;
20+
import com.networknt.schema.JsonSchema;
21+
import com.networknt.schema.JsonSchemaFactory;
22+
import com.networknt.schema.SchemaValidatorsConfig;
23+
import com.networknt.schema.SpecVersion.VersionFlag;
24+
import com.networknt.schema.ValidationMessage;
25+
import io.serverlessworkflow.api.types.Workflow;
26+
import java.io.IOException;
27+
import java.io.InputStream;
28+
import java.io.Reader;
29+
import java.util.Set;
30+
import java.util.stream.Collectors;
31+
32+
class ValidationReader implements WorkflowReaderOperations {
33+
private final JsonSchema schemaObject;
34+
35+
ValidationReader() {
36+
this.schemaObject =
37+
JsonSchemaFactory.getInstance(VersionFlag.V7)
38+
.getSchema(
39+
Thread.currentThread()
40+
.getContextClassLoader()
41+
.getResourceAsStream("schema/workflow.yaml"),
42+
InputFormat.YAML,
43+
SchemaValidatorsConfig.builder().build());
44+
}
45+
46+
@Override
47+
public Workflow read(InputStream input, WorkflowFormat format) throws IOException {
48+
return validate(format.mapper().readValue(input, JsonNode.class), format);
49+
}
50+
51+
@Override
52+
public Workflow read(Reader input, WorkflowFormat format) throws IOException {
53+
return validate(format.mapper().readValue(input, JsonNode.class), format);
54+
}
55+
56+
@Override
57+
public Workflow read(byte[] input, WorkflowFormat format) throws IOException {
58+
return validate(format.mapper().readValue(input, JsonNode.class), format);
59+
}
60+
61+
@Override
62+
public Workflow read(String input, WorkflowFormat format) throws IOException {
63+
return validate(format.mapper().readValue(input, JsonNode.class), format);
64+
}
65+
66+
private Workflow validate(JsonNode value, WorkflowFormat format) {
67+
Set<ValidationMessage> validationErrors = schemaObject.validate(value);
68+
if (!validationErrors.isEmpty()) {
69+
throw new IllegalArgumentException(
70+
validationErrors.stream()
71+
.map(ValidationMessage::toString)
72+
.collect(Collectors.joining("\n")));
73+
}
74+
return format.mapper().convertValue(value, Workflow.class);
75+
}
76+
}

api/src/main/java/io/serverlessworkflow/api/WorkflowReader.java

Lines changed: 56 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -16,58 +16,98 @@
1616
package io.serverlessworkflow.api;
1717

1818
import io.serverlessworkflow.api.types.Workflow;
19-
import java.io.ByteArrayInputStream;
2019
import java.io.FileNotFoundException;
2120
import java.io.IOException;
2221
import java.io.InputStream;
2322
import java.io.Reader;
24-
import java.io.StringReader;
2523
import java.nio.file.Files;
2624
import java.nio.file.Path;
2725

2826
public class WorkflowReader {
2927

3028
public static Workflow readWorkflow(InputStream input, WorkflowFormat format) throws IOException {
31-
return format.mapper().readValue(input, Workflow.class);
29+
return defaultReader().read(input, format);
3230
}
3331

3432
public static Workflow readWorkflow(Reader input, WorkflowFormat format) throws IOException {
35-
return format.mapper().readValue(input, Workflow.class);
33+
return defaultReader().read(input, format);
3634
}
3735

38-
public static Workflow readWorkflow(Path path, WorkflowFormat format) throws IOException {
39-
return format.mapper().readValue(Files.readAllBytes(path), Workflow.class);
36+
public static Workflow readWorkflow(byte[] input, WorkflowFormat format) throws IOException {
37+
return defaultReader().read(input, format);
4038
}
4139

42-
public static Workflow readWorkflow(byte[] content, WorkflowFormat format) throws IOException {
43-
try (InputStream input = new ByteArrayInputStream(content)) {
44-
return readWorkflow(input, format);
45-
}
40+
public static Workflow readWorkflow(Path path) throws IOException {
41+
return readWorkflow(defaultReader(), path, WorkflowFormat.fromPath(path));
42+
}
43+
44+
public static Workflow readWorkflow(Path path, WorkflowFormat format) throws IOException {
45+
return readWorkflow(defaultReader(), path, format);
4646
}
4747

48-
public static Workflow readWorkflowFromString(String content, WorkflowFormat format)
48+
public static Workflow readWorkflowFromString(String input, WorkflowFormat format)
4949
throws IOException {
50-
try (Reader reader = new StringReader(content)) {
51-
return readWorkflow(reader, format);
52-
}
50+
return defaultReader().read(input, format);
5351
}
5452

5553
public static Workflow readWorkflowFromClasspath(String classpath) throws IOException {
54+
return readWorkflowFromClasspath(defaultReader(), classpath);
55+
}
56+
57+
public static Workflow readWorkflowFromClasspath(
58+
String classpath, ClassLoader cl, WorkflowFormat format) throws IOException {
59+
return readWorkflowFromClasspath(defaultReader(), classpath);
60+
}
61+
62+
public static Workflow readWorkflow(WorkflowReaderOperations reader, Path path)
63+
throws IOException {
64+
return readWorkflow(reader, path, WorkflowFormat.fromPath(path));
65+
}
66+
67+
public static Workflow readWorkflow(
68+
WorkflowReaderOperations reader, Path path, WorkflowFormat format) throws IOException {
69+
return reader.read(Files.readAllBytes(path), format);
70+
}
71+
72+
public static Workflow readWorkflowFromClasspath(
73+
WorkflowReaderOperations reader, String classpath) throws IOException {
5674
return readWorkflowFromClasspath(
75+
reader,
5776
classpath,
5877
Thread.currentThread().getContextClassLoader(),
5978
WorkflowFormat.fromFileName(classpath));
6079
}
6180

6281
public static Workflow readWorkflowFromClasspath(
63-
String classpath, ClassLoader cl, WorkflowFormat format) throws IOException {
82+
WorkflowReaderOperations reader, String classpath, ClassLoader cl, WorkflowFormat format)
83+
throws IOException {
6484
try (InputStream in = cl.getResourceAsStream(classpath)) {
6585
if (in == null) {
6686
throw new FileNotFoundException(classpath);
6787
}
68-
return readWorkflow(in, format);
88+
return reader.read(in, format);
6989
}
7090
}
7191

92+
public static WorkflowReaderOperations noValidation() {
93+
return NoValidationHolder.instance;
94+
}
95+
96+
public static WorkflowReaderOperations validation() {
97+
return ValidationHolder.instance;
98+
}
99+
100+
private static class NoValidationHolder {
101+
private static final WorkflowReaderOperations instance = new DirectReader();
102+
}
103+
104+
private static class ValidationHolder {
105+
private static final WorkflowReaderOperations instance = new ValidationReader();
106+
}
107+
108+
private static WorkflowReaderOperations defaultReader() {
109+
return NoValidationHolder.instance;
110+
}
111+
72112
private WorkflowReader() {}
73113
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/*
2+
* Copyright 2020-Present The Serverless Workflow Specification Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package io.serverlessworkflow.api;
17+
18+
import io.serverlessworkflow.api.types.Workflow;
19+
import java.io.IOException;
20+
import java.io.InputStream;
21+
import java.io.Reader;
22+
23+
public interface WorkflowReaderOperations {
24+
Workflow read(InputStream input, WorkflowFormat format) throws IOException;
25+
26+
Workflow read(Reader input, WorkflowFormat format) throws IOException;
27+
28+
Workflow read(byte[] input, WorkflowFormat format) throws IOException;
29+
30+
Workflow read(String input, WorkflowFormat format) throws IOException;
31+
}

api/src/main/java/io/serverlessworkflow/api/WorkflowWriter.java

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
import java.io.ByteArrayOutputStream;
2020
import java.io.IOException;
2121
import java.io.OutputStream;
22-
import java.io.StringWriter;
2322
import java.io.Writer;
2423
import java.nio.file.Files;
2524
import java.nio.file.Path;
@@ -49,10 +48,7 @@ public static void writeWorkflow(Path output, Workflow workflow, WorkflowFormat
4948

5049
public static String workflowAsString(Workflow workflow, WorkflowFormat format)
5150
throws IOException {
52-
try (Writer writer = new StringWriter()) {
53-
writeWorkflow(writer, workflow, format);
54-
return writer.toString();
55-
}
51+
return format.mapper().writeValueAsString(workflow);
5652
}
5753

5854
public static byte[] workflowAsBytes(Workflow workflow, WorkflowFormat format)

api/src/test/java/io/serverlessworkflow/api/FeaturesTest.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
import static io.serverlessworkflow.api.WorkflowReader.readWorkflow;
1919
import static io.serverlessworkflow.api.WorkflowReader.readWorkflowFromClasspath;
20+
import static io.serverlessworkflow.api.WorkflowReader.validation;
2021
import static io.serverlessworkflow.api.WorkflowWriter.workflowAsBytes;
2122
import static io.serverlessworkflow.api.WorkflowWriter.workflowAsString;
2223
import static io.serverlessworkflow.api.WorkflowWriter.writeWorkflow;
@@ -53,13 +54,13 @@ public class FeaturesTest {
5354
"features/set.yaml",
5455
"features/switch.yaml",
5556
"features/try.yaml",
56-
"features/listen.yaml",
57+
"features/listen-to-any.yaml",
5758
"features/callFunction.yaml",
5859
"features/callCustomFunction.yaml",
5960
"features/call-http-query-parameters.yaml"
6061
})
6162
public void testSpecFeaturesParsing(String workflowLocation) throws IOException {
62-
Workflow workflow = readWorkflowFromClasspath(workflowLocation);
63+
Workflow workflow = readWorkflowFromClasspath(validation(), workflowLocation);
6364
assertWorkflow(workflow);
6465
assertWorkflowEquals(workflow, writeAndReadInMemory(workflow));
6566
}
Lines changed: 23 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,25 @@
11
document:
2-
dsl: 1.0.0-alpha5
3-
namespace: test
4-
name: call-example
5-
version: 0.1.0
6-
schedule:
7-
cron: 0 8 * * *
2+
dsl: '1.0.0-alpha5'
3+
namespace: samples
4+
name: call-custom-function-inline
5+
version: '0.1.0'
6+
use:
7+
functions:
8+
getPetById:
9+
input:
10+
schema:
11+
document:
12+
type: object
13+
properties:
14+
petId:
15+
type: string
16+
required: [ petId ]
17+
call: http
18+
with:
19+
method: get
20+
endpoint: https://petstore.swagger.io/v2/pet/{petId}
821
do:
9-
- getData:
10-
call: http
11-
with:
12-
method: get
13-
endpoint: https://api.agify.io?name=meelad
14-
output:
15-
as: ".data.reading"
16-
- filterData:
17-
for:
18-
in: ".data.reading"
19-
each: reading
20-
do:
21-
- log:
22-
call: https://raw.githubusercontent.com/serverlessworkflow/catalog/main/functions/log/1.0.0/function.yaml
23-
with:
24-
level: information
25-
format: "{TIMESTAMP} [{LEVEL}] ({CONTEXT}): {MESSAGE}"
26-
message: Hello, world!
27-
timestamp: true
22+
- getPet:
23+
call: getPetById
24+
with:
25+
petId: 69

api/src/test/resources/features/callOpenAPI.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ do:
88
call: openapi
99
with:
1010
document:
11-
uri: "https://petstore.swagger.io/v2/swagger.json"
11+
endpoint: "https://petstore.swagger.io/v2/swagger.json"
1212
operationId: findPetsByStatus
1313
parameters:
1414
status: ${ .status }

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy