diff --git a/.gitignore b/.gitignore
index f69c781754..64c2050c0c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -114,6 +114,7 @@ Migrations/
/core-tests/client-java/distance-heuristics/target/
/em.toml
+/core-extra/arazzo-parser/target/
/core-extra/solver/target/
/em.yaml
/core-tests/e2e-tests/spring/spring-rest-openapi-v2/em.yaml
diff --git a/core-extra/arazzo-parser/pom.xml b/core-extra/arazzo-parser/pom.xml
new file mode 100644
index 0000000000..dcd2fe6d21
--- /dev/null
+++ b/core-extra/arazzo-parser/pom.xml
@@ -0,0 +1,68 @@
+
+
+ 4.0.0
+
+ org.evomaster
+ evomaster-core-extra
+ 6.0.1-SNAPSHOT
+
+
+ arazzo-parser
+
+
+
+ io.swagger.core.v3
+ swagger-models
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+
+
+ com.fasterxml.jackson.dataformat
+ jackson-dataformat-yaml
+
+
+ io.swagger.core.v3
+ swagger-core
+
+
+ org.junit.jupiter
+ junit-jupiter
+ test
+
+
+ io.swagger.parser.v3
+ swagger-parser-v3
+ 2.1.33
+ test
+
+
+ com.graphql-java
+ java-dataloader
+ test
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+ 8
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+
+ @{argLine} -ea -Xms512m -Xmx1536m -Xss2m -Dfile.encoding=UTF-8 -Duser.language=en -Duser.country=GB
+
+
+
+
+
+
\ No newline at end of file
diff --git a/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/access/ArazzoAccess.java b/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/access/ArazzoAccess.java
new file mode 100644
index 0000000000..dec839e303
--- /dev/null
+++ b/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/access/ArazzoAccess.java
@@ -0,0 +1,43 @@
+package com.webfuzzing.arazzo.access;
+
+import java.net.URI;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+/**
+ * Read Arrazzo documents
+ */
+public class ArazzoAccess {
+
+ /**
+ * Read Arrazzo documents from disk (files in the project)
+ */
+ public static String readFromDisk(String arazzoLocation) {
+ String fileScheme = "file:";
+
+ Path path;
+ try {
+ if (arazzoLocation.toLowerCase().startsWith(fileScheme)) {
+ path = Paths.get(URI.create(arazzoLocation));
+ } else {
+ path = Paths.get(arazzoLocation);
+ }
+ } catch (Exception e) {
+ throw new IllegalArgumentException("The file path provided for the Arazzo Schema " + arazzoLocation + " ended up with the following error: " + e.getMessage());
+ }
+
+ if ((!Files.exists(path))) {
+ throw new IllegalArgumentException("The provided Arazzo file does not exist: " + arazzoLocation);
+ }
+
+ try {
+ byte[] bytes = Files.readAllBytes(path);
+ return new String(bytes, StandardCharsets.UTF_8);
+ } catch (Exception e) {
+ throw new RuntimeException("Error reading the Arazzo file: " + e.getMessage());
+ }
+
+ }
+}
diff --git a/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/deserializer/AnyExpressionDeserializer.java b/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/deserializer/AnyExpressionDeserializer.java
new file mode 100644
index 0000000000..a5cac1a83e
--- /dev/null
+++ b/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/deserializer/AnyExpressionDeserializer.java
@@ -0,0 +1,30 @@
+package com.webfuzzing.arazzo.deserializer;
+
+import com.fasterxml.jackson.core.JacksonException;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.webfuzzing.arazzo.models.domain.AnyExpression;
+
+import java.io.IOException;
+
+/**
+ * Custom Jackson deserializer for {@link AnyExpression}.
+ * It resolves dynamic JSON payloads by mapping plain text to a {@link AnyExpression.Expression},
+ * and any other complex structure to a generic JSON node.
+ */
+public class AnyExpressionDeserializer extends JsonDeserializer {
+
+ @Override
+ public AnyExpression deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JacksonException {
+ JsonNode node = jsonParser.getCodec().readTree(jsonParser);
+
+ if (node.isTextual()) {
+ return new AnyExpression.Expression(node.asText());
+ }
+ JsonNode any = jsonParser.getCodec().treeToValue(node, JsonNode.class);
+ return new AnyExpression.Any(any);
+ }
+
+}
diff --git a/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/deserializer/CriterionTypeDeserializer.java b/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/deserializer/CriterionTypeDeserializer.java
new file mode 100644
index 0000000000..937227e847
--- /dev/null
+++ b/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/deserializer/CriterionTypeDeserializer.java
@@ -0,0 +1,35 @@
+package com.webfuzzing.arazzo.deserializer;
+
+import com.fasterxml.jackson.core.JacksonException;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.webfuzzing.arazzo.models.domain.CriterionExpression;
+import com.webfuzzing.arazzo.models.domain.CriterionType;
+
+import java.io.IOException;
+
+/**
+ * Custom Jackson deserializer for {@link CriterionType}.
+ * It resolves dynamic JSON payloads by mapping plain text to a {@link CriterionType.Simple},
+ * and a JSON object to a {@link CriterionType.Complex}.
+ */
+public class CriterionTypeDeserializer extends JsonDeserializer {
+
+ @Override
+ public CriterionType deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JacksonException {
+ JsonNode node = jsonParser.getCodec().readTree(jsonParser);
+
+ if (node.isTextual()) {
+ return new CriterionType.Simple(node.asText());
+ } else if (node.isObject()) {
+ CriterionExpression complex = jsonParser.getCodec().treeToValue(node, CriterionExpression.class);
+ return new CriterionType.Complex(complex);
+ } else {
+ throw new IllegalArgumentException("Arazzo Parsing Error: Invalid " + node.getNodeType() + ". Expected string or Criterion Expression");
+ }
+
+ }
+
+}
diff --git a/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/deserializer/FailureReusableDeserializer.java b/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/deserializer/FailureReusableDeserializer.java
new file mode 100644
index 0000000000..026a1d0c75
--- /dev/null
+++ b/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/deserializer/FailureReusableDeserializer.java
@@ -0,0 +1,33 @@
+package com.webfuzzing.arazzo.deserializer;
+
+import com.fasterxml.jackson.core.JacksonException;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.webfuzzing.arazzo.models.domain.FailureAction;
+import com.webfuzzing.arazzo.models.domain.FailureReusable;
+import com.webfuzzing.arazzo.models.domain.Reusable;
+
+import java.io.IOException;
+
+/**
+ * Custom Jackson deserializer for {@link FailureReusable}.
+ * It differentiates the incoming JSON payload based on the presence of the "reference" field,
+ * mapping it to a {@link FailureReusable.ReusableObj} if present, or to a {@link FailureReusable.Failure} otherwise.
+ */
+public class FailureReusableDeserializer extends JsonDeserializer {
+
+ @Override
+ public FailureReusable deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JacksonException {
+ JsonNode node = jsonParser.getCodec().readTree(jsonParser);
+
+ if (node.has(Reusable.REFERENCE)) {
+ Reusable reusable = jsonParser.getCodec().treeToValue(node, Reusable.class);
+ return new FailureReusable.ReusableObj(reusable);
+ }
+
+ FailureAction action = jsonParser.getCodec().treeToValue(node, FailureAction.class);
+ return new FailureReusable.Failure(action);
+ }
+}
diff --git a/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/deserializer/ParameterReusableDeserializer.java b/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/deserializer/ParameterReusableDeserializer.java
new file mode 100644
index 0000000000..42cd9c4a20
--- /dev/null
+++ b/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/deserializer/ParameterReusableDeserializer.java
@@ -0,0 +1,34 @@
+package com.webfuzzing.arazzo.deserializer;
+
+import com.fasterxml.jackson.core.JacksonException;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.webfuzzing.arazzo.models.domain.Parameter;
+import com.webfuzzing.arazzo.models.domain.ParameterReusable;
+import com.webfuzzing.arazzo.models.domain.Reusable;
+
+import java.io.IOException;
+
+/**
+ * Custom Jackson deserializer for {@link ParameterReusable}.
+ * It differentiates the incoming JSON payload based on the presence of the "reference" field,
+ * mapping it to a {@link ParameterReusable.ReusableObj} if present, or to a {@link ParameterReusable.Param} otherwise.
+ */
+public class ParameterReusableDeserializer extends JsonDeserializer {
+
+ @Override
+ public ParameterReusable deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JacksonException {
+ JsonNode node = jsonParser.getCodec().readTree(jsonParser);
+
+ if (node.has(Reusable.REFERENCE)) {
+ Reusable reusable = jsonParser.getCodec().treeToValue(node, Reusable.class);
+ return new ParameterReusable.ReusableObj(reusable);
+ }
+
+ Parameter parameter = jsonParser.getCodec().treeToValue(node, Parameter.class);
+ return new ParameterReusable.Param(parameter);
+ }
+
+}
diff --git a/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/deserializer/SuccessReusableDeserializer.java b/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/deserializer/SuccessReusableDeserializer.java
new file mode 100644
index 0000000000..b755f125c7
--- /dev/null
+++ b/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/deserializer/SuccessReusableDeserializer.java
@@ -0,0 +1,34 @@
+package com.webfuzzing.arazzo.deserializer;
+
+import com.fasterxml.jackson.core.JacksonException;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.webfuzzing.arazzo.models.domain.Reusable;
+import com.webfuzzing.arazzo.models.domain.SuccessAction;
+import com.webfuzzing.arazzo.models.domain.SuccessReusable;
+
+import java.io.IOException;
+
+/**
+ * Custom Jackson deserializer for {@link SuccessReusable}.
+ * It differentiates the incoming JSON payload based on the presence of the "reference" field,
+ * mapping it to a {@link SuccessReusable.ReusableObj} if present, or to a {@link SuccessReusable.Success} otherwise.
+ */
+public class SuccessReusableDeserializer extends JsonDeserializer {
+
+ @Override
+ public SuccessReusable deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JacksonException {
+ JsonNode node = jsonParser.getCodec().readTree(jsonParser);
+
+ if (node.has(Reusable.REFERENCE)) {
+ Reusable reusable = jsonParser.getCodec().treeToValue(node, Reusable.class);
+ return new SuccessReusable.ReusableObj(reusable);
+ }
+
+ SuccessAction action = jsonParser.getCodec().treeToValue(node, SuccessAction.class);
+ return new SuccessReusable.Success(action);
+ }
+
+}
diff --git a/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/mapper/ArazzoMapper.java b/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/mapper/ArazzoMapper.java
new file mode 100644
index 0000000000..ebfaef8382
--- /dev/null
+++ b/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/mapper/ArazzoMapper.java
@@ -0,0 +1,102 @@
+package com.webfuzzing.arazzo.mapper;
+
+import com.webfuzzing.arazzo.models.domain.ArazzoSpecifications;
+import com.webfuzzing.arazzo.models.domain.Step;
+import com.webfuzzing.arazzo.models.domain.Workflow;
+import com.webfuzzing.arazzo.models.unresolved.UnresolvedArazzoSpecifications;
+import com.webfuzzing.arazzo.models.unresolved.UnresolvedStep;
+import com.webfuzzing.arazzo.models.unresolved.UnresolvedWorkflow;
+import com.webfuzzing.arazzo.resolver.ArazzoReferenceResolver;
+import io.swagger.v3.oas.models.media.Schema;
+
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * Mapper class responsible for converting unresolved Arazzo Specification models
+ * into their corresponding domain models.
+ */
+public class ArazzoMapper {
+ private ArazzoReferenceResolver resolver;
+
+ public ArazzoMapper(ArazzoReferenceResolver resolver) {
+ this.resolver = resolver;
+ }
+
+ /**
+ * Maps UnresolvedArazzoSpecifications to ArazzoSpecifications
+ */
+ public ArazzoSpecifications toDomain(UnresolvedArazzoSpecifications unresolvedArazzoSpecifications) {
+ return ArazzoSpecifications.builder()
+ .arazzo(unresolvedArazzoSpecifications.getArazzo())
+ .info(unresolvedArazzoSpecifications.getInfo())
+ .sourceDescriptions(unresolvedArazzoSpecifications.getSourceDescriptions())
+ .workflows(unresolvedArazzoSpecifications.getWorkflows().stream()
+ .map(this::toDomain)
+ .collect(Collectors.toList()))
+ .components(unresolvedArazzoSpecifications.getComponents())
+ .build();
+ }
+
+ /**
+ * Maps UnresolvedWorkflow to Workflow
+ */
+ public Workflow toDomain(UnresolvedWorkflow unresolvedWorkflow) {
+ return Workflow.builder()
+ .workflowId(unresolvedWorkflow.getWorkflowId())
+ .summary(unresolvedWorkflow.getSummary())
+ .description(unresolvedWorkflow.getDescription())
+ .inputs(this.toDomain(unresolvedWorkflow.getInputs()))
+ .dependsOn(unresolvedWorkflow.getDependsOn())
+ .steps(unresolvedWorkflow.getSteps().stream()
+ .map(this::toDomain)
+ .collect(Collectors.toList()))
+ .successActions(resolver.resolveSuccessReusable(unresolvedWorkflow.getSuccessActions()))
+ .failureActions(resolver.resolveFailureReusable(unresolvedWorkflow.getFailureActions()))
+ .outputs(unresolvedWorkflow.getOutputs())
+ .parameters(resolver.resolveParametersReusable(unresolvedWorkflow.getParameters()))
+ .build();
+ }
+
+ /**
+ * Maps UnresolvedStep to Step
+ */
+ public Step toDomain(UnresolvedStep unresolvedStep) {
+ return Step.builder()
+ .description(unresolvedStep.getDescription())
+ .stepId(unresolvedStep.getStepId())
+ .operationId(unresolvedStep.getOperationId())
+ .operationPath(unresolvedStep.getOperationPath())
+ .workflowId(unresolvedStep.getWorkflowId())
+ .parameters(resolver.resolveParametersReusable(unresolvedStep.getParameters()))
+ .requestBody(unresolvedStep.getRequestBody())
+ .successCriteria(unresolvedStep.getSuccessCriteria())
+ .onSuccess(resolver.resolveSuccessReusable(unresolvedStep.getOnSuccess()))
+ .onFailure(resolver.resolveFailureReusable(unresolvedStep.getOnFailure()))
+ .outputs(unresolvedStep.getOutputs())
+ .build();
+ }
+
+ /**
+ * Map Schema to Schema with reference resolved
+ */
+ public Schema> toDomain(Schema> schema) {
+ if (schema != null && schema.get$ref() != null && !schema.get$ref().trim().isEmpty()) {
+ Schema> reference = toDomain(resolver.resolveJsonPointer(schema.get$ref()));
+ if (reference != null) {
+ if (reference.getProperties() != null) {
+ Map updatedProperties = reference.getProperties().entrySet().stream()
+ .collect(Collectors.toMap(
+ Map.Entry::getKey, entry -> toDomain(entry.getValue())
+ ));
+
+ reference.setProperties(updatedProperties);
+ }
+
+ return reference;
+ }
+ }
+
+ return schema;
+ }
+}
diff --git a/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/models/domain/AnyExpression.java b/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/models/domain/AnyExpression.java
new file mode 100644
index 0000000000..6c44d7b3c1
--- /dev/null
+++ b/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/models/domain/AnyExpression.java
@@ -0,0 +1,39 @@
+package com.webfuzzing.arazzo.models.domain;
+
+import com.fasterxml.jackson.databind.JsonNode;
+
+/**
+ * Representing the model (Any | {expression})
+ * The value to pass in the parameter.
+ * The value can be a constant or a Runtime Expression to be evaluated
+ * and passed to the referenced operation or workflow
+ */
+public abstract class AnyExpression {
+
+ public AnyExpression() {
+ }
+
+ public static class Any extends AnyExpression {
+ private final JsonNode jsonNode;
+
+ public Any(JsonNode jsonNode) {
+ this.jsonNode = jsonNode;
+ }
+
+ public JsonNode getJsonNode() {
+ return jsonNode;
+ }
+ }
+
+ public static class Expression extends AnyExpression {
+ private final String expression;
+
+ public Expression(String expression) {
+ this.expression = expression;
+ }
+
+ public String getExpression() {
+ return expression;
+ }
+ }
+}
diff --git a/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/models/domain/ArazzoSpecifications.java b/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/models/domain/ArazzoSpecifications.java
new file mode 100644
index 0000000000..7b55748ee1
--- /dev/null
+++ b/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/models/domain/ArazzoSpecifications.java
@@ -0,0 +1,86 @@
+package com.webfuzzing.arazzo.models.domain;
+
+import java.util.List;
+
+/**
+ * Representing the model Arazzo Specification Object
+ * This is the root object of the Arazzo Description
+ * Original info from Arazzo: ...
+ */
+public class ArazzoSpecifications {
+ /**
+ * This string MUST be the version number of the Arazzo Specification that the Arazzo Description uses
+ */
+ private String arazzo;
+
+ /**
+ * Provides metadata about the workflows contain within the Arazzo Description.
+ */
+ private InfoArazzo info;
+
+ /**
+ * A list of source descriptions.
+ */
+ private List sourceDescriptions;
+
+ /**
+ * A list of workflows.
+ */
+ private List workflows;
+
+ /**
+ * An element to hold various schemas for the Arazzo Description.
+ */
+ private Components components;
+
+ private ArazzoSpecifications(Builder builder) {
+ this.arazzo = builder.arazzo;
+ this.info = builder.info;
+ this.sourceDescriptions = builder.sourceDescriptions;
+ this.workflows = builder.workflows;
+ this.components = builder.components;
+ }
+
+ public String getArazzo() {
+ return arazzo;
+ }
+
+ public InfoArazzo getInfo() {
+ return info;
+ }
+
+ public List getSourceDescriptions() {
+ return sourceDescriptions;
+ }
+
+ public List getWorkflows() {
+ return workflows;
+ }
+
+ public Components getComponents() {
+ return components;
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static class Builder {
+ private String arazzo;
+ private InfoArazzo info;
+ private List sourceDescriptions;
+ private List workflows;
+ private Components components;
+
+ public Builder arazzo(String arazzo) { this.arazzo = arazzo; return this; }
+ public Builder info(InfoArazzo info) { this.info = info; return this; }
+ public Builder sourceDescriptions(List sourceDescriptions) { this.sourceDescriptions = sourceDescriptions; return this; }
+ public Builder workflows(List workflows) { this.workflows = workflows; return this; }
+ public Builder components(Components components) { this.components = components; return this; }
+
+ public ArazzoSpecifications build() {
+ return new ArazzoSpecifications(this);
+ }
+
+ }
+}
diff --git a/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/models/domain/Components.java b/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/models/domain/Components.java
new file mode 100644
index 0000000000..209dca466c
--- /dev/null
+++ b/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/models/domain/Components.java
@@ -0,0 +1,67 @@
+package com.webfuzzing.arazzo.models.domain;
+
+import java.util.Map;
+import io.swagger.v3.oas.models.media.Schema;
+
+/**
+ * Representing the model Components Object
+ * Holds a set of reusable objects for different aspects of the Arazzo Specification.
+ * All objects defined within the components object will have no effect on the Arazzo Description
+ * unless they are explicitly referenced from properties outside the components object.
+ */
+public class Components {
+ /**
+ * An object to hold reusable JSON Schema objects to be referenced from workflow inputs.
+ */
+ private Map> inputs;
+
+ /**
+ * An object to hold reusable Parameter Objects
+ */
+ private Map parameters;
+
+ /**
+ * An object to hold reusable Success Actions Objects.
+ */
+ private Map successAction;
+
+ /**
+ * An object to hold reusable Failure Actions Objects.
+ */
+ private Map failureAction;
+
+ public Components() {
+ }
+
+ public Map> getInputs() {
+ return inputs;
+ }
+
+ public void setInputs(Map> inputs) {
+ this.inputs = inputs;
+ }
+
+ public Map getParameters() {
+ return parameters;
+ }
+
+ public void setParameters(Map parameters) {
+ this.parameters = parameters;
+ }
+
+ public Map getSuccessAction() {
+ return successAction;
+ }
+
+ public void setSuccessAction(Map successAction) {
+ this.successAction = successAction;
+ }
+
+ public Map getFailureAction() {
+ return failureAction;
+ }
+
+ public void setFailureAction(Map failureAction) {
+ this.failureAction = failureAction;
+ }
+}
diff --git a/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/models/domain/Criterion.java b/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/models/domain/Criterion.java
new file mode 100644
index 0000000000..962d0c900e
--- /dev/null
+++ b/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/models/domain/Criterion.java
@@ -0,0 +1,54 @@
+package com.webfuzzing.arazzo.models.domain;
+
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.webfuzzing.arazzo.deserializer.CriterionTypeDeserializer;
+
+/**
+ * Representing the model Criterion Object
+ * An object used to specify the context, conditions,
+ * and condition types that can be used to prove or satisfy assertions specified
+ */
+public class Criterion {
+ /**
+ * A Runtime Expression used to set the context for the condition to be applied on.
+ */
+ private String context;
+
+ /**
+ * The condition to apply.
+ */
+ private String condition;
+
+ /**
+ * The type of condition to be applied.
+ */
+ @JsonDeserialize(using = CriterionTypeDeserializer.class)
+ private CriterionType type;
+
+ public Criterion() {
+ }
+
+ public String getContext() {
+ return context;
+ }
+
+ public void setContext(String context) {
+ this.context = context;
+ }
+
+ public String getCondition() {
+ return condition;
+ }
+
+ public void setCondition(String condition) {
+ this.condition = condition;
+ }
+
+ public CriterionType getType() {
+ return type;
+ }
+
+ public void setType(CriterionType type) {
+ this.type = type;
+ }
+}
diff --git a/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/models/domain/CriterionExpression.java b/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/models/domain/CriterionExpression.java
new file mode 100644
index 0000000000..983c3d34dd
--- /dev/null
+++ b/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/models/domain/CriterionExpression.java
@@ -0,0 +1,29 @@
+package com.webfuzzing.arazzo.models.domain;
+
+/**
+ * Representing the model Criterion Expression Type Object
+ * An object used to describe the type and version of an expression used within a Criterion Object
+ */
+public class CriterionExpression {
+ private String type;
+ private String version;
+
+ public CriterionExpression() {
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ public String getVersion() {
+ return version;
+ }
+
+ public void setVersion(String version) {
+ this.version = version;
+ }
+}
diff --git a/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/models/domain/CriterionType.java b/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/models/domain/CriterionType.java
new file mode 100644
index 0000000000..7942bcf4c7
--- /dev/null
+++ b/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/models/domain/CriterionType.java
@@ -0,0 +1,34 @@
+package com.webfuzzing.arazzo.models.domain;
+
+/**
+ * It represents an object that can be a String or a {@link CriterionExpression}.
+ */
+public abstract class CriterionType {
+
+ public CriterionType() {
+ }
+
+ public static class Simple extends CriterionType {
+ private final String value;
+
+ public Simple(String value) {
+ this.value = value;
+ }
+
+ public String getValue() {
+ return value;
+ }
+ }
+
+ public static class Complex extends CriterionType {
+ private final CriterionExpression expression;
+
+ public Complex(CriterionExpression expression) {
+ this.expression = expression;
+ }
+
+ public CriterionExpression getExpression() {
+ return expression;
+ }
+ }
+}
diff --git a/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/models/domain/FailureAction.java b/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/models/domain/FailureAction.java
new file mode 100644
index 0000000000..3ba8217d63
--- /dev/null
+++ b/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/models/domain/FailureAction.java
@@ -0,0 +1,104 @@
+package com.webfuzzing.arazzo.models.domain;
+
+import java.util.List;
+
+/**
+ * Representing the model Failure Action Object
+ * A single failure action which describes an action to take upon failure of a workflow step
+ */
+public class FailureAction {
+
+ /**
+ * The name of the failure action.
+ */
+ private String name;
+
+ /**
+ * The type of action to take.
+ */
+ private String type;
+
+ /**
+ * The workflowId referencing an existing workflow within the Arazzo Description to transfer to upon failure of the step.
+ */
+ private String workflowId;
+
+ /**
+ * The stepId to transfer to upon failure of the step.
+ */
+ private String stepId;
+
+ /**
+ * A non-negative decimal indicating the seconds to delay after the step failure before another attempt SHALL be made.
+ */
+ private Number retryAfter;
+
+ /**
+ * A non-negative integer indicating how many attempts to retry the step MAY be attempted before failing the overall step.
+ */
+ private Integer retryLimit;
+
+ /**
+ * A list of assertions to determine if this action SHALL be executed.
+ */
+ private List criteria;
+
+ public FailureAction() {
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ public String getWorkflowId() {
+ return workflowId;
+ }
+
+ public void setWorkflowId(String workflowId) {
+ this.workflowId = workflowId;
+ }
+
+ public Number getRetryAfter() {
+ return retryAfter;
+ }
+
+ public void setRetryAfter(Number retryAfter) {
+ this.retryAfter = retryAfter;
+ }
+
+ public String getStepId() {
+ return stepId;
+ }
+
+ public void setStepId(String stepId) {
+ this.stepId = stepId;
+ }
+
+ public Integer getRetryLimit() {
+ return retryLimit;
+ }
+
+ public void setRetryLimit(Integer retryLimit) {
+ this.retryLimit = retryLimit;
+ }
+
+ public List getCriteria() {
+ return criteria;
+ }
+
+ public void setCriteria(List criteria) {
+ this.criteria = criteria;
+ }
+}
diff --git a/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/models/domain/FailureReusable.java b/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/models/domain/FailureReusable.java
new file mode 100644
index 0000000000..9b526e4c92
--- /dev/null
+++ b/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/models/domain/FailureReusable.java
@@ -0,0 +1,34 @@
+package com.webfuzzing.arazzo.models.domain;
+
+/**
+ * It represents an object that can be a {@link FailureAction} or a {@link Reusable}.
+ */
+public abstract class FailureReusable {
+
+ public FailureReusable() {
+ }
+
+ public static class Failure extends FailureReusable {
+ private final FailureAction action;
+
+ public Failure(FailureAction action) {
+ this.action = action;
+ }
+
+ public FailureAction getAction() {
+ return action;
+ }
+ }
+
+ public static class ReusableObj extends FailureReusable {
+ private final Reusable reusable;
+
+ public ReusableObj(Reusable reusable) {
+ this.reusable = reusable;
+ }
+
+ public Reusable getReusable() {
+ return reusable;
+ }
+ }
+}
diff --git a/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/models/domain/InfoArazzo.java b/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/models/domain/InfoArazzo.java
new file mode 100644
index 0000000000..4a5718ca6e
--- /dev/null
+++ b/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/models/domain/InfoArazzo.java
@@ -0,0 +1,62 @@
+package com.webfuzzing.arazzo.models.domain;
+
+/**
+ * Representing the model Info Object
+ * This is the root object of the Arazzo Description
+ */
+public class InfoArazzo {
+ /**
+ * A human readable title of the Arazzo Description.
+ */
+ private String title;
+
+ /**
+ * A short summary of the Arazzo Description.
+ */
+ private String summary;
+
+ /**
+ * A description of the purpose of the workflows defined.
+ */
+ private String description;
+
+ /**
+ * The version identifier of the Arazzo document.
+ */
+ private String version;
+
+ public InfoArazzo() {
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ public String getSummary() {
+ return summary;
+ }
+
+ public void setSummary(String summary) {
+ this.summary = summary;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ public String getVersion() {
+ return version;
+ }
+
+ public void setVersion(String version) {
+ this.version = version;
+ }
+}
diff --git a/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/models/domain/Parameter.java b/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/models/domain/Parameter.java
new file mode 100644
index 0000000000..6ab6949a71
--- /dev/null
+++ b/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/models/domain/Parameter.java
@@ -0,0 +1,53 @@
+package com.webfuzzing.arazzo.models.domain;
+
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.webfuzzing.arazzo.deserializer.AnyExpressionDeserializer;
+
+/**
+ * Representing the model Parameter Object
+ * Describes a single step parameter
+ */
+public class Parameter {
+ /**
+ * The name of the parameter.
+ */
+ private String name;
+
+ /**
+ * The location of the parameter.
+ */
+ private String in;
+
+ /**
+ * The value to pass in the parameter.
+ */
+ @JsonDeserialize(using = AnyExpressionDeserializer.class)
+ private AnyExpression value;
+
+ public Parameter() {
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getIn() {
+ return in;
+ }
+
+ public void setIn(String in) {
+ this.in = in;
+ }
+
+ public AnyExpression getValue() {
+ return value;
+ }
+
+ public void setValue(AnyExpression value) {
+ this.value = value;
+ }
+}
diff --git a/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/models/domain/ParameterReusable.java b/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/models/domain/ParameterReusable.java
new file mode 100644
index 0000000000..ed6f49f3c5
--- /dev/null
+++ b/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/models/domain/ParameterReusable.java
@@ -0,0 +1,34 @@
+package com.webfuzzing.arazzo.models.domain;
+
+/**
+ * It represents an object that can be a {@link Parameter} or a {@link Reusable}.
+ */
+public abstract class ParameterReusable {
+
+ public ParameterReusable() {
+ }
+
+ public static class Param extends ParameterReusable {
+ private final Parameter parameter;
+
+ public Param(Parameter parameter) {
+ this.parameter = parameter;
+ }
+
+ public Parameter getParameter() {
+ return parameter;
+ }
+ }
+
+ public static class ReusableObj extends ParameterReusable {
+ private final Reusable reusable;
+
+ public ReusableObj(Reusable reusable) {
+ this.reusable = reusable;
+ }
+
+ public Reusable getReusable() {
+ return reusable;
+ }
+ }
+}
diff --git a/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/models/domain/PayloadReplacement.java b/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/models/domain/PayloadReplacement.java
new file mode 100644
index 0000000000..809970cfcd
--- /dev/null
+++ b/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/models/domain/PayloadReplacement.java
@@ -0,0 +1,41 @@
+package com.webfuzzing.arazzo.models.domain;
+
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.webfuzzing.arazzo.deserializer.AnyExpressionDeserializer;
+
+/**
+ * Representing the model Payload Replacement Object
+ * Describes a location within a payload (e.g., a request body) and a value to set within the location.
+ */
+public class PayloadReplacement {
+
+ /**
+ * A JSON Pointer or XPath Expression which MUST be resolved against the request body. Used to identify the location to inject the value.
+ */
+ private String target;
+
+ /**
+ * The value set within the target location.
+ */
+ @JsonDeserialize(using = AnyExpressionDeserializer.class)
+ private AnyExpression value;
+
+ public PayloadReplacement() {
+ }
+
+ public String getTarget() {
+ return target;
+ }
+
+ public void setTarget(String target) {
+ this.target = target;
+ }
+
+ public AnyExpression getValue() {
+ return value;
+ }
+
+ public void setValue(AnyExpression value) {
+ this.value = value;
+ }
+}
diff --git a/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/models/domain/RequestBody.java b/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/models/domain/RequestBody.java
new file mode 100644
index 0000000000..9eb19a6e99
--- /dev/null
+++ b/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/models/domain/RequestBody.java
@@ -0,0 +1,53 @@
+package com.webfuzzing.arazzo.models.domain;
+
+import com.fasterxml.jackson.databind.JsonNode;
+
+import java.util.List;
+
+/**
+ * Representing the model Request Body Object
+ * A single request body describing the Content-Type and request body content to be passed by a step to an operation.
+ */
+public class RequestBody {
+ /**
+ * The Content-Type for the request content.
+ */
+ private String contentType;
+
+ /**
+ * A value representing the request body payload.
+ */
+ private JsonNode payload;
+
+ /**
+ * A list of locations and values to set within a payload.
+ */
+ private List replacements;
+
+ public RequestBody() {
+ }
+
+ public String getContentType() {
+ return contentType;
+ }
+
+ public void setContentType(String contentType) {
+ this.contentType = contentType;
+ }
+
+ public JsonNode getPayload() {
+ return payload;
+ }
+
+ public void setPayload(JsonNode payload) {
+ this.payload = payload;
+ }
+
+ public List getReplacements() {
+ return replacements;
+ }
+
+ public void setReplacements(List replacements) {
+ this.replacements = replacements;
+ }
+}
diff --git a/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/models/domain/Reusable.java b/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/models/domain/Reusable.java
new file mode 100644
index 0000000000..0ad3dec70d
--- /dev/null
+++ b/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/models/domain/Reusable.java
@@ -0,0 +1,39 @@
+package com.webfuzzing.arazzo.models.domain;
+
+/**
+ * Representing the model Reusable Object
+ * A simple object to allow referencing of objects contained within the {@link Components}
+ */
+public class Reusable {
+
+ public static final String REFERENCE = "reference";
+
+ /**
+ * A Runtime Expression used to reference the desired object.
+ */
+ private String reference;
+
+ /**
+ * Sets a value of the referenced parameter.
+ */
+ private String value;
+
+ public Reusable() {
+ }
+
+ public String getReference() {
+ return reference;
+ }
+
+ public void setReference(String reference) {
+ this.reference = reference;
+ }
+
+ public String getValue() {
+ return value;
+ }
+
+ public void setValue(String value) {
+ this.value = value;
+ }
+}
diff --git a/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/models/domain/SourceDescription.java b/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/models/domain/SourceDescription.java
new file mode 100644
index 0000000000..ae4c87f8e4
--- /dev/null
+++ b/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/models/domain/SourceDescription.java
@@ -0,0 +1,50 @@
+package com.webfuzzing.arazzo.models.domain;
+
+/**
+ * Representing the model Source Description Object
+ * Describes a source description (such as an OpenAPI description)
+ * that will be referenced by one or more workflows described within an Arazzo Description
+ */
+public class SourceDescription {
+ /**
+ * A unique name for the source description.
+ */
+ private String name;
+
+ /**
+ * A URL to a source description to be used by a workflow.
+ */
+ private String url;
+
+ /**
+ * The type of source description. Possible values are "openapi" or "arazzo".
+ */
+ private String type;
+
+ public SourceDescription() {
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getUrl() {
+ return url;
+ }
+
+ public void setUrl(String url) {
+ this.url = url;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+}
diff --git a/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/models/domain/Step.java b/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/models/domain/Step.java
new file mode 100644
index 0000000000..81b75c5370
--- /dev/null
+++ b/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/models/domain/Step.java
@@ -0,0 +1,162 @@
+package com.webfuzzing.arazzo.models.domain;
+
+import com.webfuzzing.arazzo.resolver.ArazzoReferenceResolver;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Representing the model Step Object
+ * Describes a single workflow step which MAY be a call
+ * to an API operation (OpenAPI Operation Object) or another Workflow Object
+ * This model only have SuccessAction, FailureAction and Parameter.
+ * The references are expected to be resolved by {@link ArazzoReferenceResolver}.
+ */
+public class Step {
+ /**
+ * A description of the step.
+ */
+ private String description;
+
+ /**
+ * Unique string to represent the step.
+ */
+ private String stepId;
+
+ /**
+ * The name of an existing, resolvable operation, as defined with a unique operationId and existing within one of the sourceDescriptions.
+ */
+ private String operationId;
+
+ /**
+ * A reference to a Source Description Object combined with a JSON Pointer to reference an operation.
+ */
+ private String operationPath;
+
+ /**
+ * The workflowId referencing an existing workflow within the Arazzo Description.
+ */
+ private String workflowId;
+
+ /**
+ * A list of parameters that MUST be passed to an operation or workflow as referenced by operationId, operationPath, or workflowId.
+ */
+ private List parameters;
+
+ /**
+ * The request body to pass to an operation as referenced by operationId or operationPath.
+ */
+ private RequestBody requestBody;
+
+ /**
+ * A list of assertions to determine the success of the step.
+ */
+ private List successCriteria;
+
+ /**
+ * An array of success action objects that specify what to do upon step success.
+ */
+ private List onSuccess;
+
+ /**
+ * An array of failure action objects that specify what to do upon step failure.
+ */
+ private List onFailure;
+
+ /**
+ * A map between a friendly name and a dynamic output value defined using a Runtime Expression.
+ */
+ private Map outputs;
+
+ public Step(Builder builder) {
+ this.description = builder.description;
+ this.stepId = builder.stepId;
+ this.operationId = builder.operationId;
+ this.operationPath = builder.operationPath;
+ this.workflowId = builder.workflowId;
+ this.parameters = builder.parameters;
+ this.requestBody = builder.requestBody;
+ this.successCriteria = builder.successCriteria;
+ this.onSuccess = builder.onSuccess;
+ this.onFailure = builder.onFailure;
+ this.outputs = builder.outputs;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public String getStepId() {
+ return stepId;
+ }
+
+ public String getOperationId() {
+ return operationId;
+ }
+
+ public String getOperationPath() {
+ return operationPath;
+ }
+
+ public String getWorkflowId() {
+ return workflowId;
+ }
+
+ public List getParameters() {
+ return parameters;
+ }
+
+ public RequestBody getRequestBody() {
+ return requestBody;
+ }
+
+ public List getSuccessCriteria() {
+ return successCriteria;
+ }
+
+ public List getOnSuccess() {
+ return onSuccess;
+ }
+
+ public List getOnFailure() {
+ return onFailure;
+ }
+
+ public Map getOutputs() {
+ return outputs;
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static class Builder {
+ private String description;
+ private String stepId;
+ private String operationId;
+ private String operationPath;
+ private String workflowId;
+ private List parameters;
+ private RequestBody requestBody;
+ private List successCriteria;
+ private List onSuccess;
+ private List onFailure;
+ private Map outputs;
+
+ public Builder description(String description) { this.description = description; return this; }
+ public Builder stepId(String stepId) { this.stepId = stepId; return this; }
+ public Builder operationId(String operationId) { this.operationId = operationId; return this; }
+ public Builder operationPath(String operationPath) { this.operationPath = operationPath; return this; }
+ public Builder workflowId(String workflowId) { this.workflowId = workflowId; return this; }
+ public Builder parameters(List parameters) { this.parameters = parameters; return this; }
+ public Builder requestBody(RequestBody requestBody) { this.requestBody = requestBody; return this; }
+ public Builder successCriteria(List successCriteria) { this.successCriteria = successCriteria; return this; }
+ public Builder onSuccess(List onSuccess) { this.onSuccess = onSuccess; return this; }
+ public Builder onFailure(List onFailure) { this.onFailure = onFailure; return this; }
+ public Builder outputs(Map outputs) { this.outputs = outputs; return this; }
+
+ public Step build() {
+ return new Step(this);
+ }
+ }
+}
\ No newline at end of file
diff --git a/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/models/domain/SuccessAction.java b/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/models/domain/SuccessAction.java
new file mode 100644
index 0000000000..8fc7d331a2
--- /dev/null
+++ b/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/models/domain/SuccessAction.java
@@ -0,0 +1,77 @@
+package com.webfuzzing.arazzo.models.domain;
+
+import java.util.List;
+
+/**
+ * Representing the model Success Action Object
+ * A single success action which describes an action to take upon success of a workflow step
+ */
+public class SuccessAction {
+ /**
+ * The name of the success action.
+ */
+ private String name;
+
+ /**
+ * The type of action to take.
+ */
+ private String type;
+
+ /**
+ * The workflowId referencing an existing workflow within the Arazzo Description to transfer to upon success of the step.
+ */
+ private String workflowId;
+
+ /**
+ * The stepId to transfer to upon success of the step.
+ */
+ private String stepId;
+
+ /**
+ * A list of assertions to determine if this action SHALL be executed.
+ */
+ private List criteria;
+
+ public SuccessAction() {
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ public String getWorkflowId() {
+ return workflowId;
+ }
+
+ public void setWorkflowId(String workflowId) {
+ this.workflowId = workflowId;
+ }
+
+ public String getStepId() {
+ return stepId;
+ }
+
+ public void setStepId(String stepId) {
+ this.stepId = stepId;
+ }
+
+ public List getCriteria() {
+ return criteria;
+ }
+
+ public void setCriteria(List criteria) {
+ this.criteria = criteria;
+ }
+}
diff --git a/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/models/domain/SuccessReusable.java b/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/models/domain/SuccessReusable.java
new file mode 100644
index 0000000000..68520b1918
--- /dev/null
+++ b/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/models/domain/SuccessReusable.java
@@ -0,0 +1,34 @@
+package com.webfuzzing.arazzo.models.domain;
+
+/**
+ * It represents an object that can be a {@link SuccessAction} or a {@link Reusable}.
+ */
+public abstract class SuccessReusable {
+
+ public SuccessReusable() {
+ }
+
+ public static class Success extends SuccessReusable {
+ private final SuccessAction action;
+
+ public Success(SuccessAction action) {
+ this.action = action;
+ }
+
+ public SuccessAction getAction() {
+ return action;
+ }
+ }
+
+ public static class ReusableObj extends SuccessReusable {
+ private final Reusable reusable;
+
+ public ReusableObj(Reusable reusable) {
+ this.reusable = reusable;
+ }
+
+ public Reusable getReusable() {
+ return reusable;
+ }
+ }
+}
diff --git a/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/models/domain/Workflow.java b/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/models/domain/Workflow.java
new file mode 100644
index 0000000000..bcd9c5e82d
--- /dev/null
+++ b/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/models/domain/Workflow.java
@@ -0,0 +1,154 @@
+package com.webfuzzing.arazzo.models.domain;
+
+import io.swagger.v3.oas.models.media.Schema;
+import com.webfuzzing.arazzo.resolver.ArazzoReferenceResolver;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Representing the model Workflow Object
+ * Describes the steps to be taken across one or more APIs to achieve an objective.
+ * The workflow object MAY define inputs needed in order to execute workflow steps,
+ * where the defined steps represent a call to an API operation or another workflow,
+ * and a set of outputs.
+ * This model only have SuccessAction, FailureAction and Parameter.
+ * The references are expected to be resolved by {@link ArazzoReferenceResolver}.
+ */
+public class Workflow {
+ /**
+ * Unique string to represent the workflow.
+ */
+ private String workflowId;
+
+ /**
+ * A summary of the purpose or objective of the workflow.
+ */
+ private String summary;
+
+ /**
+ * A description of the workflow.
+ */
+ private String description;
+
+ /**
+ * A JSON Schema 2020-12 object representing the input parameters used by this workflow.
+ */
+ private Schema> inputs;
+
+ /**
+ * A list of workflows that MUST be completed before this workflow can be processed.
+ */
+ private List dependsOn;
+
+ /**
+ * An ordered list of steps where each step represents a call to an API operation or to another workflow.
+ */
+ private List steps;
+
+ /**
+ * A list of success actions that are applicable for all steps described under this workflow.
+ */
+ private List successActions;
+
+ /**
+ * A list of failure actions that are applicable for all steps described under this workflow.
+ */
+ private List failureActions;
+
+ /**
+ * A map between a friendly name and a dynamic output value.
+ */
+ private Map outputs;
+
+ /**
+ * A list of parameters that are applicable for all steps described under this workflow.
+ */
+ private List parameters;
+
+ private Workflow(Builder builder) {
+ this.workflowId = builder.workflowId;
+ this.summary = builder.summary;
+ this.description = builder.description;
+ this.inputs = builder.inputs;
+ this.dependsOn = builder.dependsOn;
+ this.steps = builder.steps;
+ this.successActions = builder.successActions;
+ this.failureActions = builder.failureActions;
+ this.outputs = builder.outputs;
+ this.parameters = builder.parameters;
+ }
+
+ public String getWorkflowId() {
+ return workflowId;
+ }
+
+ public String getSummary() {
+ return summary;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public Schema> getInputs() {
+ return inputs;
+ }
+
+ public List getDependsOn() {
+ return dependsOn;
+ }
+
+ public List getSteps() {
+ return steps;
+ }
+
+ public List getSuccessActions() {
+ return successActions;
+ }
+
+ public List getFailureActions() {
+ return failureActions;
+ }
+
+ public Map getOutputs() {
+ return outputs;
+ }
+
+ public List getParameters() {
+ return parameters;
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static class Builder {
+ private String workflowId;
+ private String summary;
+ private String description;
+ private Schema> inputs;
+ private List dependsOn;
+ private List steps;
+ private List successActions;
+ private List failureActions;
+ private Map outputs;
+ private List parameters;
+
+ public Builder workflowId(String workflowId) { this.workflowId = workflowId; return this; }
+ public Builder summary(String summary) { this.summary = summary; return this; }
+ public Builder description(String description) { this.description = description; return this; }
+ public Builder inputs(Schema> inputs) { this.inputs = inputs; return this; }
+ public Builder dependsOn(List dependsOn) { this.dependsOn = dependsOn; return this; }
+ public Builder steps(List steps) { this.steps = steps; return this; }
+ public Builder successActions(List successActions) { this.successActions = successActions; return this; }
+ public Builder failureActions(List failureActions) { this.failureActions = failureActions; return this; }
+ public Builder outputs(Map outputs) { this.outputs = outputs; return this; }
+ public Builder parameters(List parameters) { this.parameters = parameters; return this; }
+
+ public Workflow build() {
+ return new Workflow(this);
+ }
+ }
+
+}
diff --git a/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/models/unresolved/UnresolvedArazzoSpecifications.java b/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/models/unresolved/UnresolvedArazzoSpecifications.java
new file mode 100644
index 0000000000..d718f6c986
--- /dev/null
+++ b/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/models/unresolved/UnresolvedArazzoSpecifications.java
@@ -0,0 +1,64 @@
+package com.webfuzzing.arazzo.models.unresolved;
+
+import com.webfuzzing.arazzo.models.domain.Components;
+import com.webfuzzing.arazzo.models.domain.InfoArazzo;
+import com.webfuzzing.arazzo.models.domain.SourceDescription;
+
+import java.util.List;
+
+/**
+ * Jackson-deserializable representation of the root Arazzo Specification Object
+ * with unresolved references. Mutable intermediate model used during parsing;
+ * mapped to the immutable domain {@link com.webfuzzing.arazzo.models.domain.ArazzoSpecifications}
+ * by {@link com.webfuzzing.arazzo.mapper.ArazzoMapper}.
+ */
+public class UnresolvedArazzoSpecifications {
+ private String arazzo;
+ private InfoArazzo info;
+ private List sourceDescriptions;
+ private List workflows;
+ private Components components;
+
+ public UnresolvedArazzoSpecifications() {
+ }
+
+ public String getArazzo() {
+ return arazzo;
+ }
+
+ public void setArazzo(String arazzo) {
+ this.arazzo = arazzo;
+ }
+
+ public InfoArazzo getInfo() {
+ return info;
+ }
+
+ public void setInfo(InfoArazzo info) {
+ this.info = info;
+ }
+
+ public List getSourceDescriptions() {
+ return sourceDescriptions;
+ }
+
+ public void setSourceDescriptions(List sourceDescriptions) {
+ this.sourceDescriptions = sourceDescriptions;
+ }
+
+ public List getWorkflows() {
+ return workflows;
+ }
+
+ public void setWorkflows(List workflows) {
+ this.workflows = workflows;
+ }
+
+ public Components getComponents() {
+ return components;
+ }
+
+ public void setComponents(Components components) {
+ this.components = components;
+ }
+}
diff --git a/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/models/unresolved/UnresolvedStep.java b/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/models/unresolved/UnresolvedStep.java
new file mode 100644
index 0000000000..d53226e616
--- /dev/null
+++ b/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/models/unresolved/UnresolvedStep.java
@@ -0,0 +1,129 @@
+package com.webfuzzing.arazzo.models.unresolved;
+
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.webfuzzing.arazzo.deserializer.FailureReusableDeserializer;
+import com.webfuzzing.arazzo.deserializer.ParameterReusableDeserializer;
+import com.webfuzzing.arazzo.deserializer.SuccessReusableDeserializer;
+import com.webfuzzing.arazzo.models.domain.*;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Jackson-deserializable representation of a Step Object
+ * with unresolved references. Mutable intermediate model used during parsing;
+ * mapped to the immutable domain {@link com.webfuzzing.arazzo.models.domain.Step}
+ * by {@link com.webfuzzing.arazzo.mapper.ArazzoMapper}.
+ * Uses {@link SuccessReusable}, {@link FailureReusable} and {@link ParameterReusable}
+ * for representing (Object | Reusable Object).
+ */
+public class UnresolvedStep {
+ private String description;
+ private String stepId;
+ private String operationId;
+ private String operationPath;
+ private String workflowId;
+ private RequestBody requestBody;
+ private List successCriteria;
+ private Map outputs;
+
+ @JsonDeserialize(contentUsing = ParameterReusableDeserializer.class)
+ private List parameters;
+
+ @JsonDeserialize(contentUsing = SuccessReusableDeserializer.class)
+ private List onSuccess;
+
+ @JsonDeserialize(contentUsing = FailureReusableDeserializer.class)
+ private List onFailure;
+
+ public UnresolvedStep() {
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ public String getStepId() {
+ return stepId;
+ }
+
+ public void setStepId(String stepId) {
+ this.stepId = stepId;
+ }
+
+ public String getOperationId() {
+ return operationId;
+ }
+
+ public void setOperationId(String operationId) {
+ this.operationId = operationId;
+ }
+
+ public String getOperationPath() {
+ return operationPath;
+ }
+
+ public void setOperationPath(String operationPath) {
+ this.operationPath = operationPath;
+ }
+
+ public String getWorkflowId() {
+ return workflowId;
+ }
+
+ public void setWorkflowId(String workflowId) {
+ this.workflowId = workflowId;
+ }
+
+ public RequestBody getRequestBody() {
+ return requestBody;
+ }
+
+ public void setRequestBody(RequestBody requestBody) {
+ this.requestBody = requestBody;
+ }
+
+ public List getSuccessCriteria() {
+ return successCriteria;
+ }
+
+ public void setSuccessCriteria(List successCriteria) {
+ this.successCriteria = successCriteria;
+ }
+
+ public Map getOutputs() {
+ return outputs;
+ }
+
+ public void setOutputs(Map outputs) {
+ this.outputs = outputs;
+ }
+
+ public List getParameters() {
+ return parameters;
+ }
+
+ public void setParameters(List parameters) {
+ this.parameters = parameters;
+ }
+
+ public List getOnSuccess() {
+ return onSuccess;
+ }
+
+ public void setOnSuccess(List onSuccess) {
+ this.onSuccess = onSuccess;
+ }
+
+ public List getOnFailure() {
+ return onFailure;
+ }
+
+ public void setOnFailure(List onFailure) {
+ this.onFailure = onFailure;
+ }
+}
diff --git a/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/models/unresolved/UnresolvedWorkflow.java b/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/models/unresolved/UnresolvedWorkflow.java
new file mode 100644
index 0000000000..099d0e65e1
--- /dev/null
+++ b/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/models/unresolved/UnresolvedWorkflow.java
@@ -0,0 +1,123 @@
+package com.webfuzzing.arazzo.models.unresolved;
+
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.webfuzzing.arazzo.deserializer.FailureReusableDeserializer;
+import com.webfuzzing.arazzo.deserializer.ParameterReusableDeserializer;
+import com.webfuzzing.arazzo.deserializer.SuccessReusableDeserializer;
+import com.webfuzzing.arazzo.models.domain.FailureReusable;
+import com.webfuzzing.arazzo.models.domain.ParameterReusable;
+import com.webfuzzing.arazzo.models.domain.SuccessReusable;
+import io.swagger.v3.oas.models.media.Schema;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Jackson-deserializable representation of a Workflow Object
+ * with unresolved references. Mutable intermediate model used during parsing;
+ * mapped to the immutable domain {@link com.webfuzzing.arazzo.models.domain.Workflow}
+ * by {@link com.webfuzzing.arazzo.mapper.ArazzoMapper}.
+ * Uses {@link SuccessReusable}, {@link FailureReusable} and {@link ParameterReusable}
+ * for representing (Object | Reusable Object).
+ */
+public class UnresolvedWorkflow {
+ private String workflowId;
+ private String summary;
+ private String description;
+ private Schema> inputs;
+ private List dependsOn;
+ private List steps;
+ private Map outputs;
+
+ @JsonDeserialize(contentUsing = SuccessReusableDeserializer.class)
+ private List successActions;
+
+ @JsonDeserialize(contentUsing = FailureReusableDeserializer.class)
+ private List failureActions;
+
+ @JsonDeserialize(contentUsing = ParameterReusableDeserializer.class)
+ private List parameters;
+
+ public UnresolvedWorkflow() {
+ }
+
+ public String getWorkflowId() {
+ return workflowId;
+ }
+
+ public void setWorkflowId(String workflowId) {
+ this.workflowId = workflowId;
+ }
+
+ public String getSummary() {
+ return summary;
+ }
+
+ public void setSummary(String summary) {
+ this.summary = summary;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ public Schema> getInputs() {
+ return inputs;
+ }
+
+ public void setInputs(Schema> inputs) {
+ this.inputs = inputs;
+ }
+
+ public List getDependsOn() {
+ return dependsOn;
+ }
+
+ public void setDependsOn(List dependsOn) {
+ this.dependsOn = dependsOn;
+ }
+
+ public List getSteps() {
+ return steps;
+ }
+
+ public void setSteps(List steps) {
+ this.steps = steps;
+ }
+
+ public Map getOutputs() {
+ return outputs;
+ }
+
+ public void setOutputs(Map outputs) {
+ this.outputs = outputs;
+ }
+
+ public List getSuccessActions() {
+ return successActions;
+ }
+
+ public void setSuccessActions(List successActions) {
+ this.successActions = successActions;
+ }
+
+ public List getFailureActions() {
+ return failureActions;
+ }
+
+ public void setFailureActions(List failureActions) {
+ this.failureActions = failureActions;
+ }
+
+ public List getParameters() {
+ return parameters;
+ }
+
+ public void setParameters(List parameters) {
+ this.parameters = parameters;
+ }
+}
diff --git a/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/parser/ArazzoParser.java b/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/parser/ArazzoParser.java
new file mode 100644
index 0000000000..f3b4e8c4cb
--- /dev/null
+++ b/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/parser/ArazzoParser.java
@@ -0,0 +1,50 @@
+package com.webfuzzing.arazzo.parser;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
+import io.swagger.v3.oas.models.OpenAPI;
+import com.webfuzzing.arazzo.mapper.ArazzoMapper;
+import com.webfuzzing.arazzo.models.domain.ArazzoSpecifications;
+import com.webfuzzing.arazzo.models.unresolved.UnresolvedArazzoSpecifications;
+import com.webfuzzing.arazzo.resolver.ArazzoReferenceResolver;
+import java.util.AbstractMap;
+
+/**
+ * Parse a String containing an Arazzo document into a complete model in ArazzoSpecifications
+ */
+public class ArazzoParser {
+
+ private static final ObjectMapper JSON_MAPPER = new ObjectMapper().findAndRegisterModules();
+ private static final ObjectMapper YAML_MAPPER = new ObjectMapper(new YAMLFactory()).findAndRegisterModules();
+
+ /**
+ * Parses an Arazzo document along with the corresponding OpenAPI document and returns an instance of ArazzoSpecifications.
+ */
+ public static ArazzoSpecifications parse(String schemaText, OpenAPI openAPI) {
+ AbstractMap.SimpleEntry parsed = parseSchemaText(schemaText);
+ ArazzoReferenceResolver resolver = new ArazzoReferenceResolver(parsed.getKey().getComponents(), parsed.getValue(), openAPI);
+ ArazzoMapper mapper = new ArazzoMapper(resolver);
+ return mapper.toDomain(parsed.getKey());
+ }
+
+ private static AbstractMap.SimpleEntry parseSchemaText(String schemaText) {
+ UnresolvedArazzoSpecifications unresolvedArazzoSpecifications;
+ JsonNode arazzoJsonNode;
+
+ try {
+ unresolvedArazzoSpecifications = JSON_MAPPER.readValue(schemaText, UnresolvedArazzoSpecifications.class);
+ arazzoJsonNode = JSON_MAPPER.readTree(schemaText);
+ } catch (JsonProcessingException jsonException) {
+ try {
+ unresolvedArazzoSpecifications = YAML_MAPPER.readValue(schemaText, UnresolvedArazzoSpecifications.class);
+ arazzoJsonNode = YAML_MAPPER.readTree(schemaText);
+ } catch (Exception yamlException) {
+ throw new IllegalArgumentException("Problems parsing the Arazzo document", yamlException);
+ }
+ }
+
+ return new AbstractMap.SimpleEntry<>(unresolvedArazzoSpecifications, arazzoJsonNode);
+ }
+}
diff --git a/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/resolver/ArazzoReferenceResolver.java b/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/resolver/ArazzoReferenceResolver.java
new file mode 100644
index 0000000000..88b1f44439
--- /dev/null
+++ b/core-extra/arazzo-parser/src/main/java/com/webfuzzing/arazzo/resolver/ArazzoReferenceResolver.java
@@ -0,0 +1,189 @@
+package com.webfuzzing.arazzo.resolver;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.webfuzzing.arazzo.models.domain.*;
+import io.swagger.v3.core.util.Json;
+import io.swagger.v3.oas.models.OpenAPI;
+import io.swagger.v3.oas.models.media.Schema;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * Resolver class responsible for resolving Arazzo references.
+ */
+public class ArazzoReferenceResolver {
+ private final String COMPONENTS_PREFIX = "$components.";
+ private final String SUCCESS_ACTIONS = "successActions";
+ private final String FAILURE_ACTIONS = "failureActions";
+ private final String PARAMETERS = "parameters";
+ private final String OPENAPI_SCHEMAS_PREFIX = "/components/schemas/";
+
+ private Components components;
+ private JsonNode arazzoJsonNode;
+ private OpenAPI openApi;
+
+ public ArazzoReferenceResolver(Components components, JsonNode arazzoJsonNode, OpenAPI openAPI) {
+ this.components = components;
+ this.arazzoJsonNode = arazzoJsonNode;
+ this.openApi = openAPI;
+ }
+
+ public void setComponents(Components components) {
+ this.components = components;
+ }
+
+ public void setArazzoJsonNode(JsonNode arazzoJsonNode) {
+ this.arazzoJsonNode = arazzoJsonNode;
+ }
+
+ public void setOpenApi(OpenAPI openApi) {
+ this.openApi = openApi;
+ }
+
+ /**
+ * Resolve the {@link SuccessReusable} references to get a complete list of {@link SuccessAction}
+ */
+ public List resolveSuccessReusable(List items) {
+ if (items == null) {
+ return null;
+ }
+
+ return items.stream().map(item -> {
+ if (item instanceof SuccessReusable.Success) {
+ SuccessReusable.Success action = (SuccessReusable.Success) item;
+ return action.getAction();
+ }
+ SuccessReusable.ReusableObj reusableObj = (SuccessReusable.ReusableObj) item;
+ return (SuccessAction) resolveReusableWithPrefix(reusableObj.getReusable(), this.SUCCESS_ACTIONS);
+ }).collect(Collectors.toList());
+ }
+
+ /**
+ * Resolve the {@link FailureReusable} references to get a complete list of {@link FailureAction}
+ */
+ public List resolveFailureReusable(List items) {
+ if (items == null) {
+ return null;
+ }
+
+ return items.stream().map(item -> {
+ if (item instanceof FailureReusable.Failure) {
+ FailureReusable.Failure action = (FailureReusable.Failure) item;
+ return action.getAction();
+ }
+ FailureReusable.ReusableObj reusableObj = (FailureReusable.ReusableObj) item;
+ return (FailureAction) resolveReusableWithPrefix(reusableObj.getReusable(), this.FAILURE_ACTIONS);
+ }).collect(Collectors.toList());
+ }
+
+ /**
+ * Resolve the {@link ParameterReusable} references to get a complete list of {@link Parameter}
+ */
+ public List resolveParametersReusable(List items) {
+ if (items == null) {
+ return null;
+ }
+
+ return items.stream().map(item -> {
+ if (item instanceof ParameterReusable.Param) {
+ ParameterReusable.Param param = (ParameterReusable.Param) item;
+ return param.getParameter();
+ }
+ ParameterReusable.ReusableObj reusableObj = (ParameterReusable.ReusableObj) item;
+ return (Parameter) resolveReusableWithPrefix(reusableObj.getReusable(), this.PARAMETERS);
+ }).collect(Collectors.toList());
+ }
+
+ private Object resolveReusableWithPrefix(Reusable reusable, String expectedPrefix) {
+ if (components == null) {
+ throw new IllegalArgumentException("Arazzo Parsing Error: Can't reference with no Components");
+ }
+
+ String reference = reusable.getReference();
+ if (!reference.startsWith(this.COMPONENTS_PREFIX)) {
+ throw new IllegalArgumentException("Arazzo Parsing Error: Invalid reference (" + reference + "). Expected to point to '" + this.COMPONENTS_PREFIX + "'");
+ }
+
+ String referenceWithoutComponents = reference.substring(this.COMPONENTS_PREFIX.length());
+ if (!referenceWithoutComponents.startsWith(expectedPrefix)) {
+ throw new IllegalArgumentException("Arazzo Parsing Error: Invalid reference (" + referenceWithoutComponents + "). Expected to point to '" + expectedPrefix +"'");
+ }
+
+ String referenceClean = referenceWithoutComponents.substring((expectedPrefix + ".").length());
+ Object resolve;
+ switch (expectedPrefix) {
+ case SUCCESS_ACTIONS:
+ resolve = (components.getSuccessAction() != null) ? components.getSuccessAction().get(referenceClean) : null;
+ break;
+ case FAILURE_ACTIONS:
+ resolve = (components.getFailureAction() != null) ? components.getFailureAction().get(referenceClean) : null;
+ break;
+ case PARAMETERS:
+ resolve = (components.getParameters() != null) ? components.getParameters().get(referenceClean) : null;
+ break;
+ default:
+ resolve = null;
+ break;
+ }
+
+ if (resolve == null) {
+ throw new IllegalArgumentException("Arazzo Parsing Error: The " + expectedPrefix + ": '" + referenceClean + "' is not in the components.");
+ }
+
+ return resolve;
+
+ }
+
+ public Schema> resolveJsonPointer(String reference) {
+ if (reference.startsWith("#/")) {
+ return resolveJsonPointerLocal(reference);
+ }
+ return resolveJsonPointerExternal(reference);
+ }
+
+ private Schema> resolveJsonPointerLocal(String reference) {
+ if (arazzoJsonNode == null) {
+ throw new IllegalArgumentException("Arazzo Parsing Error: Can't reference with no Arazzo Document");
+ }
+
+ String jsonPointer = reference.substring(1);
+
+ JsonNode result = arazzoJsonNode.at(jsonPointer);
+
+ if (result.isMissingNode()) {
+ throw new IllegalArgumentException("Arazzo Parsing Error: Can't reference '" + reference + "'");
+ }
+
+ return Json.mapper().convertValue(result, Schema.class);
+ }
+
+ private Schema> resolveJsonPointerExternal(String reference) {
+ if (openApi == null) {
+ throw new IllegalArgumentException("Arazzo Parsing Error: Can't reference with no OpenApi Document");
+ }
+
+ String[] tokens = reference.split("#");
+ if (tokens.length < 2) {
+ throw new IllegalArgumentException("Arazzo Parsing Error: Error reference (" + reference + "). '#' Is mandatory");
+ }
+
+ String jsonPointer = tokens[1];
+ if (!jsonPointer.startsWith(this.OPENAPI_SCHEMAS_PREFIX)) {
+ throw new IllegalArgumentException("Arazzo Parsing Error: Error reference (" + reference + "). \"" + this.OPENAPI_SCHEMAS_PREFIX + "\" Is mandatory for references to OpenApi");
+ }
+
+ String schemaName = jsonPointer.substring(this.OPENAPI_SCHEMAS_PREFIX.length());
+ Schema> result = null;
+ if (openApi.getComponents() != null && openApi.getComponents().getSchemas() != null) {
+ result = openApi.getComponents().getSchemas().get(schemaName);
+ }
+
+ if (result == null) {
+ throw new IllegalArgumentException("Arazzo Parsing Error: (" + reference + ") reference does not exist in the OpenApi document");
+ }
+
+ return result;
+ }
+
+}
diff --git a/core-extra/arazzo-parser/src/test/java/com/webfuzzing/arazzo/ArazzoParserTest.java b/core-extra/arazzo-parser/src/test/java/com/webfuzzing/arazzo/ArazzoParserTest.java
new file mode 100644
index 0000000000..11424b5587
--- /dev/null
+++ b/core-extra/arazzo-parser/src/test/java/com/webfuzzing/arazzo/ArazzoParserTest.java
@@ -0,0 +1,39 @@
+package com.webfuzzing.arazzo;
+
+import com.webfuzzing.arazzo.access.ArazzoAccess;
+import com.webfuzzing.arazzo.models.domain.ArazzoSpecifications;
+import com.webfuzzing.arazzo.parser.ArazzoParser;
+import io.swagger.v3.oas.models.OpenAPI;
+import io.swagger.v3.parser.OpenAPIV3Parser;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class ArazzoParserTest {
+
+ private final String BASE_RESOURCE_ARAZZO = "src/test/resources/arazzo";
+ private final String BASE_RESOURCE_OPENAPI = "src/test/resources/openapi";
+
+ @Test
+ public void shouldParseArazzoYamlSuccessfully() {
+ String schemaText = ArazzoAccess.readFromDisk(BASE_RESOURCE_ARAZZO + "/arazzo_pet.yaml");
+ OpenAPI openAPI = new OpenAPIV3Parser().read(BASE_RESOURCE_OPENAPI + "/openapi_pet.json");
+
+ ArazzoSpecifications arazzo = ArazzoParser.parse(schemaText, openAPI);
+
+ assertEquals(3, arazzo.getWorkflows().size());
+ assertEquals("Petstore - Apply Coupons", arazzo.getInfo().getTitle());
+ }
+
+ @Test
+ public void shouldParseArazzoJsonSuccessfully() {
+ String schemaText = ArazzoAccess.readFromDisk(BASE_RESOURCE_ARAZZO + "/arazzo_pet.json");
+ OpenAPI openAPI = new OpenAPIV3Parser().read(BASE_RESOURCE_OPENAPI + "/openapi_pet.json");
+
+ ArazzoSpecifications arazzo = ArazzoParser.parse(schemaText, openAPI);
+
+ assertEquals(3, arazzo.getWorkflows().size());
+ assertEquals("Petstore - Apply Coupons", arazzo.getInfo().getTitle());
+ }
+
+}
diff --git a/core-extra/arazzo-parser/src/test/resources/arazzo/arazzo_pet.json b/core-extra/arazzo-parser/src/test/resources/arazzo/arazzo_pet.json
new file mode 100644
index 0000000000..47b817654c
--- /dev/null
+++ b/core-extra/arazzo-parser/src/test/resources/arazzo/arazzo_pet.json
@@ -0,0 +1,248 @@
+{
+ "arazzo": "1.0.0",
+ "info": {
+ "title": "Petstore - Apply Coupons",
+ "version": "1.0.0",
+ "description": "Illustrates a workflow whereby a client a) finds a pet in the petstore, b) finds coupons for that pet, and finally c) orders the pet while applying the coupons from step b."
+ },
+ "sourceDescriptions": [
+ {
+ "name": "pet-coupons",
+ "url": "./pet-coupons.openapi.yaml",
+ "type": "openapi"
+ }
+ ],
+ "workflows": [
+ {
+ "workflowId": "apply-coupon",
+ "summary": "Apply a coupon to a pet order.",
+ "description": "This is how you can find a pet, find an applicable coupon, and apply that coupon in your order. The workflow concludes by outputting the ID of the placed order.",
+ "inputs": {
+ "$ref": "#/components/inputs/apply_coupon_input"
+ },
+ "steps": [
+ {
+ "stepId": "find-pet",
+ "description": "Find a pet based on the provided tags.",
+ "operationId": "findPetsByTags",
+ "parameters": [
+ {
+ "name": "pet_tags",
+ "in": "query",
+ "value": "$inputs.my_pet_tags"
+ }
+ ],
+ "successCriteria": [
+ {
+ "condition": "$statusCode == 200"
+ }
+ ],
+ "outputs": {
+ "my_pet_id": "$response.body#/0/id"
+ }
+ },
+ {
+ "stepId": "find-coupons",
+ "description": "Find a coupon available for the selected pet.",
+ "operationId": "getPetCoupons",
+ "parameters": [
+ {
+ "name": "pet_id",
+ "in": "path",
+ "value": "$steps.find-pet.outputs.my_pet_id"
+ }
+ ],
+ "successCriteria": [
+ {
+ "condition": "$statusCode == 200"
+ }
+ ],
+ "outputs": {
+ "my_coupon_code": "$response.body#/couponCode"
+ }
+ },
+ {
+ "stepId": "place-order",
+ "description": "Place an order for the pet, applying the coupon.",
+ "workflowId": "place-order",
+ "parameters": [
+ {
+ "name": "pet_id",
+ "value": "$steps.find-pet.outputs.my_pet_id"
+ },
+ {
+ "name": "coupon_code",
+ "value": "$steps.find-coupons.outputs.my_coupon_code"
+ }
+ ],
+ "successCriteria": [
+ {
+ "condition": "$statusCode == 200"
+ }
+ ],
+ "outputs": {
+ "my_order_id": "$outputs.workflow_order_id"
+ }
+ }
+ ],
+ "outputs": {
+ "apply_coupon_pet_order_id": "$steps.place-order.outputs.my_order_id"
+ }
+ },
+ {
+ "workflowId": "buy-available-pet",
+ "summary": "Buy an available pet if one is available.",
+ "description": "This workflow demonstrates a workflow very similar to `apply-coupon`, by intention. It's meant to indicate how to reuse a step (`place-order`) as well as a parameter (`page`, `pageSize`).",
+ "inputs": {
+ "$ref": "#/components/inputs/buy_available_pet_input"
+ },
+ "steps": [
+ {
+ "stepId": "find-pet",
+ "description": "Find a pet that is available for purchase.",
+ "operationId": "findPetsByStatus",
+ "parameters": [
+ {
+ "name": "status",
+ "in": "query",
+ "value": "available"
+ },
+ {
+ "reference": "$components.parameters.page",
+ "value": 1
+ },
+ {
+ "reference": "$components.parameters.pageSize",
+ "value": 10
+ }
+ ],
+ "successCriteria": [
+ {
+ "condition": "$statusCode == 200"
+ }
+ ],
+ "outputs": {
+ "my_pet_id": "$response.body#/0/id"
+ }
+ },
+ {
+ "stepId": "place-order",
+ "description": "Place an order for the pet.",
+ "workflowId": "place-order",
+ "parameters": [
+ {
+ "name": "pet_id",
+ "value": "$steps.find-pet.outputs.my_pet_id"
+ }
+ ],
+ "successCriteria": [
+ {
+ "condition": "$statusCode == 200"
+ }
+ ],
+ "outputs": {
+ "my_order_id": "$outputs.workflow_order_id"
+ }
+ }
+ ],
+ "outputs": {
+ "buy_pet_order_id": "$steps.place-order.outputs.my_order_id"
+ }
+ },
+ {
+ "workflowId": "place-order",
+ "summary": "Place an order for a pet.",
+ "description": "This workflow places an order for a pet. It may be reused by other workflows as the \"final step\" in a purchase.",
+ "inputs": {
+ "type": "object",
+ "properties": {
+ "pet_id": {
+ "type": "integer",
+ "format": "int64",
+ "description": "The ID of the pet to place in the order."
+ },
+ "quantity": {
+ "type": "integer",
+ "format": "int32",
+ "description": "The number of pets to place in the order."
+ },
+ "coupon_code": {
+ "type": "string",
+ "description": "The coupon code to apply to the order."
+ }
+ }
+ },
+ "steps": [
+ {
+ "stepId": "place-order",
+ "description": "Place an order for the pet.",
+ "operationId": "placeOrder",
+ "requestBody": {
+ "contentType": "application/json",
+ "payload": {
+ "petId": "$inputs.pet_id",
+ "quantity": "$inputs.quantity",
+ "couponCode": "$inputs.coupon_code",
+ "status": "placed",
+ "complete": false
+ }
+ },
+ "successCriteria": [
+ {
+ "condition": "$statusCode == 200"
+ }
+ ],
+ "outputs": {
+ "step_order_id": "$response.body#/id"
+ }
+ }
+ ],
+ "outputs": {
+ "workflow_order_id": "$steps.place-order.outputs.step_order_id"
+ }
+ }
+ ],
+ "components": {
+ "inputs": {
+ "apply_coupon_input": {
+ "type": "object",
+ "properties": {
+ "my_pet_tags": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "description": "Desired tags to use when searching for a pet, in CSV format (e.g. \"puppy, dalmatian\")"
+ },
+ "store_id": {
+ "$ref": "#/components/inputs/store_id"
+ }
+ }
+ },
+ "buy_available_pet_input": {
+ "type": "object",
+ "properties": {
+ "store_id": {
+ "$ref": "#/components/inputs/store_id"
+ }
+ }
+ },
+ "store_id": {
+ "type": "string",
+ "description": "Indicates the domain name of the store where the customer is browsing or buying pets, e.g. \"pets.example.com\" or \"pets.example.co.uk\"."
+ }
+ },
+ "parameters": {
+ "page": {
+ "name": "page",
+ "in": "query",
+ "value": 1
+ },
+ "pageSize": {
+ "name": "pageSize",
+ "in": "query",
+ "value": 100
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/core-extra/arazzo-parser/src/test/resources/arazzo/arazzo_pet.yaml b/core-extra/arazzo-parser/src/test/resources/arazzo/arazzo_pet.yaml
new file mode 100644
index 0000000000..8a573b645e
--- /dev/null
+++ b/core-extra/arazzo-parser/src/test/resources/arazzo/arazzo_pet.yaml
@@ -0,0 +1,160 @@
+arazzo: 1.0.0
+info:
+ title: Petstore - Apply Coupons
+ version: 1.0.0
+ description: >-
+ Illustrates a workflow whereby a client a) finds a pet in the petstore,
+ b) finds coupons for that pet, and finally
+ c) orders the pet while applying the coupons from step b.
+sourceDescriptions:
+ - name: pet-coupons
+ url: ./pet-coupons.openapi.yaml
+ type: openapi
+workflows:
+ - workflowId: apply-coupon
+ summary: Apply a coupon to a pet order.
+ description: >-
+ This is how you can find a pet, find an applicable coupon, and apply that coupon in your order.
+ The workflow concludes by outputting the ID of the placed order.
+ inputs:
+ $ref: "#/components/inputs/apply_coupon_input"
+ steps:
+ - stepId: find-pet
+ description: Find a pet based on the provided tags.
+ operationId: findPetsByTags
+ parameters:
+ - name: pet_tags
+ in: query
+ value: $inputs.my_pet_tags
+ successCriteria:
+ - condition: $statusCode == 200
+ outputs:
+ my_pet_id: $response.body#/0/id
+ # there is some implied selection here - findPetsByTags responds with a list of pets,
+ # but the client only wants to choose one, and that's what will be provided to the next step.
+ # not totally sure how to indicate that.
+ - stepId: find-coupons
+ description: Find a coupon available for the selected pet.
+ operationId: getPetCoupons
+ parameters:
+ - name: pet_id
+ in: path
+ value: $steps.find-pet.outputs.my_pet_id
+ successCriteria:
+ - condition: $statusCode == 200
+ outputs:
+ my_coupon_code: $response.body#/couponCode
+ - stepId: place-order
+ description: Place an order for the pet, applying the coupon.
+ workflowId: place-order
+ parameters:
+ - name: pet_id
+ value: $steps.find-pet.outputs.my_pet_id
+ - name: coupon_code
+ value: $steps.find-coupons.outputs.my_coupon_code
+ successCriteria:
+ - condition: $statusCode == 200
+ outputs:
+ my_order_id: $outputs.workflow_order_id
+ outputs:
+ apply_coupon_pet_order_id: $steps.place-order.outputs.my_order_id
+ - workflowId: buy-available-pet
+ summary: Buy an available pet if one is available.
+ description:
+ This workflow demonstrates a workflow very similar to `apply-coupon`, by intention.
+ It's meant to indicate how to reuse a step (`place-order`) as well as a parameter (`page`, `pageSize`).
+ inputs:
+ $ref: "#/components/inputs/buy_available_pet_input"
+ steps:
+ - stepId: find-pet
+ description: Find a pet that is available for purchase.
+ operationId: findPetsByStatus
+ parameters:
+ - name: status
+ in: query
+ value: "available"
+ - reference: $components.parameters.page
+ value: 1
+ - reference: $components.parameters.pageSize
+ value: 10
+ successCriteria:
+ - condition: $statusCode == 200
+ outputs:
+ my_pet_id: $response.body#/0/id
+ - stepId: place-order
+ description: Place an order for the pet.
+ workflowId: place-order
+ parameters:
+ - name: pet_id
+ value: $steps.find-pet.outputs.my_pet_id
+ successCriteria:
+ - condition: $statusCode == 200
+ outputs:
+ my_order_id: $outputs.workflow_order_id
+ outputs:
+ buy_pet_order_id: $steps.place-order.outputs.my_order_id
+ - workflowId: place-order
+ summary: Place an order for a pet.
+ description:
+ This workflow places an order for a pet. It may be reused by other workflows as the "final step" in a purchase.
+ inputs:
+ type: object
+ properties:
+ pet_id:
+ type: integer
+ format: int64
+ description: The ID of the pet to place in the order.
+ quantity:
+ type: integer
+ format: int32
+ description: The number of pets to place in the order.
+ coupon_code:
+ type: string
+ description: The coupon code to apply to the order.
+ steps:
+ - stepId: place-order
+ description: Place an order for the pet.
+ operationId: placeOrder
+ requestBody:
+ contentType: application/json
+ payload:
+ petId: $inputs.pet_id
+ quantity: $inputs.quantity
+ couponCode: $inputs.coupon_code
+ status: placed
+ complete: false
+ successCriteria:
+ - condition: $statusCode == 200
+ outputs:
+ step_order_id: $response.body#/id
+ outputs:
+ workflow_order_id: $steps.place-order.outputs.step_order_id
+components:
+ inputs:
+ apply_coupon_input:
+ type: object
+ properties:
+ my_pet_tags:
+ type: array
+ items:
+ type: string
+ description: Desired tags to use when searching for a pet, in CSV format (e.g. "puppy, dalmatian")
+ store_id:
+ $ref: "#/components/inputs/store_id"
+ buy_available_pet_input:
+ type: object
+ properties:
+ store_id:
+ $ref: "#/components/inputs/store_id"
+ store_id:
+ type: string
+ description: Indicates the domain name of the store where the customer is browsing or buying pets, e.g. "pets.example.com" or "pets.example.co.uk".
+ parameters:
+ page:
+ name: page
+ in: query
+ value: 1
+ pageSize:
+ name: pageSize
+ in: query
+ value: 100
\ No newline at end of file
diff --git a/core-extra/arazzo-parser/src/test/resources/openapi/openapi_pet.json b/core-extra/arazzo-parser/src/test/resources/openapi/openapi_pet.json
new file mode 100644
index 0000000000..1b546da4a4
--- /dev/null
+++ b/core-extra/arazzo-parser/src/test/resources/openapi/openapi_pet.json
@@ -0,0 +1,1225 @@
+{
+ "openapi": "3.0.2",
+ "info": {
+ "title": "Swagger Petstore - OpenAPI 3.0",
+ "description": "This is a sample Pet Store Server based on the OpenAPI 3.0 specification. You can find out more about\nSwagger at [http://swagger.io](http://swagger.io). In the third iteration of the pet store, we've switched to the design first approach!\nYou can now help us improve the API whether it's by making changes to the definition itself or to the code.\nThat way, with time, we can improve the API in general, and expose some of the new features in OAS3.\n\nSome useful links:\n- [The Pet Store repository](https://github.com/swagger-api/swagger-petstore)\n- [The source API definition for the Pet Store](https://github.com/swagger-api/swagger-petstore/blob/master/src/main/resources/openapi.yaml)",
+ "termsOfService": "http://swagger.io/terms/",
+ "contact": {
+ "email": "apiteam@swagger.io"
+ },
+ "license": {
+ "name": "Apache 2.0",
+ "url": "http://www.apache.org/licenses/LICENSE-2.0.html"
+ },
+ "version": "1.0.17"
+ },
+ "externalDocs": {
+ "description": "Find out more about Swagger",
+ "url": "http://swagger.io"
+ },
+ "servers": [
+ {
+ "url": "/api/v3"
+ }
+ ],
+ "tags": [
+ {
+ "name": "pet",
+ "description": "Everything about your Pets",
+ "externalDocs": {
+ "description": "Find out more",
+ "url": "http://swagger.io"
+ }
+ },
+ {
+ "name": "store",
+ "description": "Access to Petstore orders",
+ "externalDocs": {
+ "description": "Find out more about our store",
+ "url": "http://swagger.io"
+ }
+ },
+ {
+ "name": "user",
+ "description": "Operations about user"
+ }
+ ],
+ "paths": {
+ "/pet": {
+ "put": {
+ "tags": [
+ "pet"
+ ],
+ "summary": "Update an existing pet",
+ "description": "Update an existing pet by Id",
+ "operationId": "updatePet",
+ "requestBody": {
+ "description": "Update an existent pet in the store",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/Pet"
+ }
+ },
+ "application/xml": {
+ "schema": {
+ "$ref": "#/components/schemas/Pet"
+ }
+ },
+ "application/x-www-form-urlencoded": {
+ "schema": {
+ "$ref": "#/components/schemas/Pet"
+ }
+ }
+ },
+ "required": true
+ },
+ "responses": {
+ "200": {
+ "description": "Successful operation",
+ "content": {
+ "application/xml": {
+ "schema": {
+ "$ref": "#/components/schemas/Pet"
+ }
+ },
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/Pet"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Invalid ID supplied"
+ },
+ "404": {
+ "description": "Pet not found"
+ },
+ "405": {
+ "description": "Validation exception"
+ }
+ },
+ "security": [
+ {
+ "petstore_auth": [
+ "write:pets",
+ "read:pets"
+ ]
+ }
+ ]
+ },
+ "post": {
+ "tags": [
+ "pet"
+ ],
+ "summary": "Add a new pet to the store",
+ "description": "Add a new pet to the store",
+ "operationId": "addPet",
+ "requestBody": {
+ "description": "Create a new pet in the store",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/Pet"
+ }
+ },
+ "application/xml": {
+ "schema": {
+ "$ref": "#/components/schemas/Pet"
+ }
+ },
+ "application/x-www-form-urlencoded": {
+ "schema": {
+ "$ref": "#/components/schemas/Pet"
+ }
+ }
+ },
+ "required": true
+ },
+ "responses": {
+ "200": {
+ "description": "Successful operation",
+ "content": {
+ "application/xml": {
+ "schema": {
+ "$ref": "#/components/schemas/Pet"
+ }
+ },
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/Pet"
+ }
+ }
+ }
+ },
+ "405": {
+ "description": "Invalid input"
+ }
+ },
+ "security": [
+ {
+ "petstore_auth": [
+ "write:pets",
+ "read:pets"
+ ]
+ }
+ ]
+ }
+ },
+ "/pet/findByStatus": {
+ "get": {
+ "tags": [
+ "pet"
+ ],
+ "summary": "Finds Pets by status",
+ "description": "Multiple status values can be provided with comma separated strings",
+ "operationId": "findPetsByStatus",
+ "parameters": [
+ {
+ "name": "status",
+ "in": "query",
+ "description": "Status values that need to be considered for filter",
+ "required": false,
+ "explode": true,
+ "schema": {
+ "type": "string",
+ "default": "available",
+ "enum": [
+ "available",
+ "pending",
+ "sold"
+ ]
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "successful operation",
+ "content": {
+ "application/xml": {
+ "schema": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/Pet"
+ }
+ }
+ },
+ "application/json": {
+ "schema": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/Pet"
+ }
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Invalid status value"
+ }
+ },
+ "security": [
+ {
+ "petstore_auth": [
+ "write:pets",
+ "read:pets"
+ ]
+ }
+ ]
+ }
+ },
+ "/pet/findByTags": {
+ "get": {
+ "tags": [
+ "pet"
+ ],
+ "summary": "Finds Pets by tags",
+ "description": "Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing.",
+ "operationId": "findPetsByTags",
+ "parameters": [
+ {
+ "name": "tags",
+ "in": "query",
+ "description": "Tags to filter by",
+ "required": false,
+ "explode": true,
+ "schema": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "successful operation",
+ "content": {
+ "application/xml": {
+ "schema": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/Pet"
+ }
+ }
+ },
+ "application/json": {
+ "schema": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/Pet"
+ }
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Invalid tag value"
+ }
+ },
+ "security": [
+ {
+ "petstore_auth": [
+ "write:pets",
+ "read:pets"
+ ]
+ }
+ ]
+ }
+ },
+ "/pet/{petId}": {
+ "get": {
+ "tags": [
+ "pet"
+ ],
+ "summary": "Find pet by ID",
+ "description": "Returns a single pet",
+ "operationId": "getPetById",
+ "parameters": [
+ {
+ "name": "petId",
+ "in": "path",
+ "description": "ID of pet to return",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int64"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "successful operation",
+ "content": {
+ "application/xml": {
+ "schema": {
+ "$ref": "#/components/schemas/Pet"
+ }
+ },
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/Pet"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Invalid ID supplied"
+ },
+ "404": {
+ "description": "Pet not found"
+ }
+ },
+ "security": [
+ {
+ "api_key": []
+ },
+ {
+ "petstore_auth": [
+ "write:pets",
+ "read:pets"
+ ]
+ }
+ ]
+ },
+ "post": {
+ "tags": [
+ "pet"
+ ],
+ "summary": "Updates a pet in the store with form data",
+ "description": "",
+ "operationId": "updatePetWithForm",
+ "parameters": [
+ {
+ "name": "petId",
+ "in": "path",
+ "description": "ID of pet that needs to be updated",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int64"
+ }
+ },
+ {
+ "name": "name",
+ "in": "query",
+ "description": "Name of pet that needs to be updated",
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "status",
+ "in": "query",
+ "description": "Status of pet that needs to be updated",
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "405": {
+ "description": "Invalid input"
+ }
+ },
+ "security": [
+ {
+ "petstore_auth": [
+ "write:pets",
+ "read:pets"
+ ]
+ }
+ ]
+ },
+ "delete": {
+ "tags": [
+ "pet"
+ ],
+ "summary": "Deletes a pet",
+ "description": "",
+ "operationId": "deletePet",
+ "parameters": [
+ {
+ "name": "api_key",
+ "in": "header",
+ "description": "",
+ "required": false,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "petId",
+ "in": "path",
+ "description": "Pet id to delete",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int64"
+ }
+ }
+ ],
+ "responses": {
+ "400": {
+ "description": "Invalid pet value"
+ }
+ },
+ "security": [
+ {
+ "petstore_auth": [
+ "write:pets",
+ "read:pets"
+ ]
+ }
+ ]
+ }
+ },
+ "/pet/{petId}/uploadImage": {
+ "post": {
+ "tags": [
+ "pet"
+ ],
+ "summary": "uploads an image",
+ "description": "",
+ "operationId": "uploadFile",
+ "parameters": [
+ {
+ "name": "petId",
+ "in": "path",
+ "description": "ID of pet to update",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int64"
+ }
+ },
+ {
+ "name": "additionalMetadata",
+ "in": "query",
+ "description": "Additional Metadata",
+ "required": false,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/octet-stream": {
+ "schema": {
+ "type": "string",
+ "format": "binary"
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "successful operation",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ApiResponse"
+ }
+ }
+ }
+ }
+ },
+ "security": [
+ {
+ "petstore_auth": [
+ "write:pets",
+ "read:pets"
+ ]
+ }
+ ]
+ }
+ },
+ "/store/inventory": {
+ "get": {
+ "tags": [
+ "store"
+ ],
+ "summary": "Returns pet inventories by status",
+ "description": "Returns a map of status codes to quantities",
+ "operationId": "getInventory",
+ "responses": {
+ "200": {
+ "description": "successful operation",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "integer",
+ "format": "int32"
+ }
+ }
+ }
+ }
+ }
+ },
+ "security": [
+ {
+ "api_key": []
+ }
+ ]
+ }
+ },
+ "/store/order": {
+ "post": {
+ "tags": [
+ "store"
+ ],
+ "summary": "Place an order for a pet",
+ "description": "Place a new order in the store",
+ "operationId": "placeOrder",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/Order"
+ }
+ },
+ "application/xml": {
+ "schema": {
+ "$ref": "#/components/schemas/Order"
+ }
+ },
+ "application/x-www-form-urlencoded": {
+ "schema": {
+ "$ref": "#/components/schemas/Order"
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "successful operation",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/Order"
+ }
+ }
+ }
+ },
+ "405": {
+ "description": "Invalid input"
+ }
+ }
+ }
+ },
+ "/store/order/{orderId}": {
+ "get": {
+ "tags": [
+ "store"
+ ],
+ "summary": "Find purchase order by ID",
+ "description": "For valid response try integer IDs with value <= 5 or > 10. Other values will generate exceptions.",
+ "operationId": "getOrderById",
+ "parameters": [
+ {
+ "name": "orderId",
+ "in": "path",
+ "description": "ID of order that needs to be fetched",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int64"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "successful operation",
+ "content": {
+ "application/xml": {
+ "schema": {
+ "$ref": "#/components/schemas/Order"
+ }
+ },
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/Order"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Invalid ID supplied"
+ },
+ "404": {
+ "description": "Order not found"
+ }
+ }
+ },
+ "delete": {
+ "tags": [
+ "store"
+ ],
+ "summary": "Delete purchase order by ID",
+ "description": "For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors",
+ "operationId": "deleteOrder",
+ "parameters": [
+ {
+ "name": "orderId",
+ "in": "path",
+ "description": "ID of the order that needs to be deleted",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int64"
+ }
+ }
+ ],
+ "responses": {
+ "400": {
+ "description": "Invalid ID supplied"
+ },
+ "404": {
+ "description": "Order not found"
+ }
+ }
+ }
+ },
+ "/user": {
+ "post": {
+ "tags": [
+ "user"
+ ],
+ "summary": "Create user",
+ "description": "This can only be done by the logged in user.",
+ "operationId": "createUser",
+ "requestBody": {
+ "description": "Created user object",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/User"
+ }
+ },
+ "application/xml": {
+ "schema": {
+ "$ref": "#/components/schemas/User"
+ }
+ },
+ "application/x-www-form-urlencoded": {
+ "schema": {
+ "$ref": "#/components/schemas/User"
+ }
+ }
+ }
+ },
+ "responses": {
+ "default": {
+ "description": "successful operation",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/User"
+ }
+ },
+ "application/xml": {
+ "schema": {
+ "$ref": "#/components/schemas/User"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/user/createWithList": {
+ "post": {
+ "tags": [
+ "user"
+ ],
+ "summary": "Creates list of users with given input array",
+ "description": "Creates list of users with given input array",
+ "operationId": "createUsersWithListInput",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/User"
+ }
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Successful operation",
+ "content": {
+ "application/xml": {
+ "schema": {
+ "$ref": "#/components/schemas/User"
+ }
+ },
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/User"
+ }
+ }
+ }
+ },
+ "default": {
+ "description": "successful operation"
+ }
+ }
+ }
+ },
+ "/user/login": {
+ "get": {
+ "tags": [
+ "user"
+ ],
+ "summary": "Logs user into the system",
+ "description": "",
+ "operationId": "loginUser",
+ "parameters": [
+ {
+ "name": "username",
+ "in": "query",
+ "description": "The user name for login",
+ "required": false,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "password",
+ "in": "query",
+ "description": "The password for login in clear text",
+ "required": false,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "successful operation",
+ "headers": {
+ "X-Rate-Limit": {
+ "description": "calls per hour allowed by the user",
+ "schema": {
+ "type": "integer",
+ "format": "int32"
+ }
+ },
+ "X-Expires-After": {
+ "description": "date in UTC when token expires",
+ "schema": {
+ "type": "string",
+ "format": "date-time"
+ }
+ }
+ },
+ "content": {
+ "application/xml": {
+ "schema": {
+ "type": "string"
+ }
+ },
+ "application/json": {
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Invalid username/password supplied"
+ }
+ }
+ }
+ },
+ "/user/logout": {
+ "get": {
+ "tags": [
+ "user"
+ ],
+ "summary": "Logs out current logged in user session",
+ "description": "",
+ "operationId": "logoutUser",
+ "parameters": [],
+ "responses": {
+ "default": {
+ "description": "successful operation"
+ }
+ }
+ }
+ },
+ "/user/{username}": {
+ "get": {
+ "tags": [
+ "user"
+ ],
+ "summary": "Get user by user name",
+ "description": "",
+ "operationId": "getUserByName",
+ "parameters": [
+ {
+ "name": "username",
+ "in": "path",
+ "description": "The name that needs to be fetched. Use user1 for testing. ",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "successful operation",
+ "content": {
+ "application/xml": {
+ "schema": {
+ "$ref": "#/components/schemas/User"
+ }
+ },
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/User"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Invalid username supplied"
+ },
+ "404": {
+ "description": "User not found"
+ }
+ }
+ },
+ "put": {
+ "tags": [
+ "user"
+ ],
+ "summary": "Update user",
+ "description": "This can only be done by the logged in user.",
+ "operationId": "updateUser",
+ "parameters": [
+ {
+ "name": "username",
+ "in": "path",
+ "description": "name that needs to be updated",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "requestBody": {
+ "description": "Update an existent user in the store",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/User"
+ }
+ },
+ "application/xml": {
+ "schema": {
+ "$ref": "#/components/schemas/User"
+ }
+ },
+ "application/x-www-form-urlencoded": {
+ "schema": {
+ "$ref": "#/components/schemas/User"
+ }
+ }
+ }
+ },
+ "responses": {
+ "default": {
+ "description": "successful operation"
+ }
+ }
+ },
+ "delete": {
+ "tags": [
+ "user"
+ ],
+ "summary": "Delete user",
+ "description": "This can only be done by the logged in user.",
+ "operationId": "deleteUser",
+ "parameters": [
+ {
+ "name": "username",
+ "in": "path",
+ "description": "The name that needs to be deleted",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "400": {
+ "description": "Invalid username supplied"
+ },
+ "404": {
+ "description": "User not found"
+ }
+ }
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "Order": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "integer",
+ "format": "int64",
+ "example": 10
+ },
+ "petId": {
+ "type": "integer",
+ "format": "int64",
+ "example": 198772
+ },
+ "quantity": {
+ "type": "integer",
+ "format": "int32",
+ "example": 7
+ },
+ "shipDate": {
+ "type": "string",
+ "format": "date-time"
+ },
+ "status": {
+ "type": "string",
+ "description": "Order Status",
+ "example": "approved",
+ "enum": [
+ "placed",
+ "approved",
+ "delivered"
+ ]
+ },
+ "complete": {
+ "type": "boolean"
+ }
+ },
+ "xml": {
+ "name": "order"
+ }
+ },
+ "Customer": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "integer",
+ "format": "int64",
+ "example": 100000
+ },
+ "username": {
+ "type": "string",
+ "example": "fehguy"
+ },
+ "address": {
+ "type": "array",
+ "xml": {
+ "name": "addresses",
+ "wrapped": true
+ },
+ "items": {
+ "$ref": "#/components/schemas/Address"
+ }
+ }
+ },
+ "xml": {
+ "name": "customer"
+ }
+ },
+ "Address": {
+ "type": "object",
+ "properties": {
+ "street": {
+ "type": "string",
+ "example": "437 Lytton"
+ },
+ "city": {
+ "type": "string",
+ "example": "Palo Alto"
+ },
+ "state": {
+ "type": "string",
+ "example": "CA"
+ },
+ "zip": {
+ "type": "string",
+ "example": "94301"
+ }
+ },
+ "xml": {
+ "name": "address"
+ }
+ },
+ "Category": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "integer",
+ "format": "int64",
+ "example": 1
+ },
+ "name": {
+ "type": "string",
+ "example": "Dogs"
+ }
+ },
+ "xml": {
+ "name": "category"
+ }
+ },
+ "User": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "integer",
+ "format": "int64",
+ "example": 10
+ },
+ "username": {
+ "type": "string",
+ "example": "theUser"
+ },
+ "firstName": {
+ "type": "string",
+ "example": "John"
+ },
+ "lastName": {
+ "type": "string",
+ "example": "James"
+ },
+ "email": {
+ "type": "string",
+ "example": "john@email.com"
+ },
+ "password": {
+ "type": "string",
+ "example": "12345"
+ },
+ "phone": {
+ "type": "string",
+ "example": "12345"
+ },
+ "userStatus": {
+ "type": "integer",
+ "description": "User Status",
+ "format": "int32",
+ "example": 1
+ }
+ },
+ "xml": {
+ "name": "user"
+ }
+ },
+ "Tag": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "integer",
+ "format": "int64"
+ },
+ "name": {
+ "type": "string"
+ }
+ },
+ "xml": {
+ "name": "tag"
+ }
+ },
+ "Pet": {
+ "required": [
+ "name",
+ "photoUrls"
+ ],
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "integer",
+ "format": "int64",
+ "example": 10
+ },
+ "name": {
+ "type": "string",
+ "example": "doggie"
+ },
+ "category": {
+ "$ref": "#/components/schemas/Category"
+ },
+ "photoUrls": {
+ "type": "array",
+ "xml": {
+ "wrapped": true
+ },
+ "items": {
+ "type": "string",
+ "xml": {
+ "name": "photoUrl"
+ }
+ }
+ },
+ "tags": {
+ "type": "array",
+ "xml": {
+ "wrapped": true
+ },
+ "items": {
+ "$ref": "#/components/schemas/Tag"
+ }
+ },
+ "status": {
+ "type": "string",
+ "description": "pet status in the store",
+ "enum": [
+ "available",
+ "pending",
+ "sold"
+ ]
+ }
+ },
+ "xml": {
+ "name": "pet"
+ }
+ },
+ "ApiResponse": {
+ "type": "object",
+ "properties": {
+ "code": {
+ "type": "integer",
+ "format": "int32"
+ },
+ "type": {
+ "type": "string"
+ },
+ "message": {
+ "type": "string"
+ }
+ },
+ "xml": {
+ "name": "##default"
+ }
+ }
+ },
+ "requestBodies": {
+ "Pet": {
+ "description": "Pet object that needs to be added to the store",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/Pet"
+ }
+ },
+ "application/xml": {
+ "schema": {
+ "$ref": "#/components/schemas/Pet"
+ }
+ }
+ }
+ },
+ "UserArray": {
+ "description": "List of user object",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/User"
+ }
+ }
+ }
+ }
+ }
+ },
+ "securitySchemes": {
+ "petstore_auth": {
+ "type": "oauth2",
+ "flows": {
+ "implicit": {
+ "authorizationUrl": "https://petstore.swagger.io/oauth/authorize",
+ "scopes": {
+ "write:pets": "modify pets in your account",
+ "read:pets": "read your pets"
+ }
+ }
+ }
+ },
+ "api_key": {
+ "type": "apiKey",
+ "name": "api_key",
+ "in": "header"
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/core-extra/pom.xml b/core-extra/pom.xml
index 6869da7949..fda712de45 100644
--- a/core-extra/pom.xml
+++ b/core-extra/pom.xml
@@ -16,5 +16,6 @@
dbconstraint
solver
+ arazzo-parser
\ No newline at end of file
diff --git a/core-parent/pom.xml b/core-parent/pom.xml
index 317eb240bb..3acc9ef8ef 100644
--- a/core-parent/pom.xml
+++ b/core-parent/pom.xml
@@ -20,6 +20,8 @@
2.1.14
2.2.7
1.15.0
+ 2.2.34
+ 2.2.3
@@ -63,6 +65,21 @@
swagger-annotations
${swagger.annotations.version}
+
+ io.swagger.core.v3
+ swagger-models
+ ${swagger.core.version}
+
+
+ io.swagger.core.v3
+ swagger-core
+ ${swagger.core.version}
+
+
+ com.graphql-java
+ java-dataloader
+ ${java.dataloader}
+
com.atlassian.oai
swagger-request-validator-core