Search in sources :

Example 1 with Document

use of io.apicurio.datamodels.core.models.Document in project apicurio-data-models by Apicurio.

the class Library method validateDocument.

/**
 * Called to validate a data model node.  All validation rules will be evaluated and reported.  The list
 * of validation problems found during validation is returned.  In addition, validation problems will be
 * reported on the individual nodes themselves.  Validation problem severity is determined by checking
 * with the included severity registry.  If the severity registry is null, a default registry is used.
 * Custom validators can be passed to provide additional validation rules beyond what this Library offers out of the box.
 *
 * @param node The document to be validated
 * @param severityRegistry Supply a custom severity registry. If nothing is passed, the default severity registry will be used
 * @param extensions Supply an optional list of validation extensions, enabling the use of 3rd-party validators or custom validation rules
 * @return full list of the validation problems found in the document
 */
public static CompletableFuture<List<ValidationProblem>> validateDocument(Node node, IValidationSeverityRegistry severityRegistry, List<IDocumentValidatorExtension> extensions) {
    List<ValidationProblem> totalValidationProblems = Library.validate(node, severityRegistry);
    if (extensions != null && !extensions.isEmpty()) {
        for (IDocumentValidatorExtension extension : extensions) {
            CompletableFuture<List<ValidationProblem>> extensionValidationProblems = extension.validateDocument(node);
            extensionValidationProblems.thenAccept(problems -> problems.forEach(p -> {
                totalValidationProblems.add(p);
                node.ownerDocument().addValidationProblem(p.errorCode, p.nodePath, p.property, p.message, p.severity);
            }));
        }
    }
    return CompletableFuture.completedFuture(totalValidationProblems);
}
Also used : IDocumentValidatorExtension(io.apicurio.datamodels.core.validation.IDocumentValidatorExtension) IVisitor(io.apicurio.datamodels.core.visitors.IVisitor) Dereferencer(io.apicurio.datamodels.openapi.visitors.dereference.Dereferencer) DefaultSeverityRegistry(io.apicurio.datamodels.core.validation.DefaultSeverityRegistry) IReferenceResolver(io.apicurio.datamodels.core.util.IReferenceResolver) CompletableFuture(java.util.concurrent.CompletableFuture) NodePathUtil(io.apicurio.datamodels.core.util.NodePathUtil) Aai20Document(io.apicurio.datamodels.asyncapi.v2.models.Aai20Document) DocumentType(io.apicurio.datamodels.core.models.DocumentType) Oas30Document(io.apicurio.datamodels.openapi.v3.models.Oas30Document) DataModelReader(io.apicurio.datamodels.core.io.DataModelReader) IDocumentValidatorExtension(io.apicurio.datamodels.core.validation.IDocumentValidatorExtension) TraverserDirection(io.apicurio.datamodels.core.visitors.TraverserDirection) IValidationSeverityRegistry(io.apicurio.datamodels.core.validation.IValidationSeverityRegistry) ValidationProblemsResetVisitor(io.apicurio.datamodels.core.validation.ValidationProblemsResetVisitor) VisitorFactory(io.apicurio.datamodels.core.factories.VisitorFactory) Document(io.apicurio.datamodels.core.models.Document) VisitorUtil(io.apicurio.datamodels.core.util.VisitorUtil) NodePath(io.apicurio.datamodels.core.models.NodePath) DataModelWriter(io.apicurio.datamodels.core.io.DataModelWriter) JsonCompat(io.apicurio.datamodels.compat.JsonCompat) Node(io.apicurio.datamodels.core.models.Node) ValidationProblem(io.apicurio.datamodels.core.models.ValidationProblem) Oas20to30TransformationVisitor(io.apicurio.datamodels.openapi.visitors.transform.Oas20to30TransformationVisitor) List(java.util.List) Oas30Operation(io.apicurio.datamodels.openapi.v3.models.Oas30Operation) ReferenceResolverChain(io.apicurio.datamodels.core.util.ReferenceResolverChain) DataModelReaderDispatcher(io.apicurio.datamodels.core.io.DataModelReaderDispatcher) ValidationVisitor(io.apicurio.datamodels.core.validation.ValidationVisitor) DocumentFactory(io.apicurio.datamodels.core.factories.DocumentFactory) Oas20Document(io.apicurio.datamodels.openapi.v2.models.Oas20Document) Constants(io.apicurio.datamodels.core.Constants) ValidationProblem(io.apicurio.datamodels.core.models.ValidationProblem) List(java.util.List)

Example 2 with Document

use of io.apicurio.datamodels.core.models.Document in project apicurio-data-models by Apicurio.

the class TestValidationExtension method testReadDocumentFromJSONString.

@Test
public void testReadDocumentFromJSONString() {
    String jsonString = "{\r\n" + "    \"openapi\": \"3.0.2\",\r\n" + "    \"info\": {\r\n" + "        \"title\": \"Very Simple API\",\r\n" + "        \"version\": \"1.0.0\"\r\n" + "    }\r\n" + "}";
    Document doc = Library.readDocumentFromJSONString(jsonString);
    Assert.assertEquals(DocumentType.openapi3, doc.getDocumentType());
    Assert.assertEquals("3.0.2", ((Oas30Document) doc).openapi);
}
Also used : Oas30Document(io.apicurio.datamodels.openapi.v3.models.Oas30Document) Document(io.apicurio.datamodels.core.models.Document) Test(org.junit.Test)

Example 3 with Document

use of io.apicurio.datamodels.core.models.Document in project apicurio-data-models by Apicurio.

the class TestValidationExtension method testValidate.

@Test
public void testValidate() throws Exception {
    String jsonString = "{\r\n" + "    \"openapi\": \"3.0.9\",\r\n" + "    \"info\": {\r\n" + "        \"title\": \"Very Simple API\",\r\n" + "        \"version\": \"1.0.0\"\r\n" + "    }\r\n" + "}";
    Document doc = Library.readDocumentFromJSONString(jsonString);
    List<ValidationProblem> problems = Library.validateDocument(doc, null, null).get();
    Assert.assertTrue(problems.size() > 0);
}
Also used : ValidationProblem(io.apicurio.datamodels.core.models.ValidationProblem) Oas30Document(io.apicurio.datamodels.openapi.v3.models.Oas30Document) Document(io.apicurio.datamodels.core.models.Document) Test(org.junit.Test)

Example 4 with Document

use of io.apicurio.datamodels.core.models.Document in project apicurio-data-models by Apicurio.

the class TestValidationExtension method testValidateDocumentWithCustomExtension.

@Test
public void testValidateDocumentWithCustomExtension() {
    String jsonString = "{\r\n" + "    \"openapi\": \"3.0.9\",\r\n" + "    \"info\": {\r\n" + "        \"title\": \"Very Simple API\",\r\n" + "        \"version\": \"1.0.0\"\r\n" + "    }\r\n" + "}";
    Document doc = Library.readDocumentFromJSONString(jsonString);
    List<IDocumentValidatorExtension> extensions = new ArrayList<>();
    extensions.add(new TestValidationExtension());
    CompletableFuture<List<ValidationProblem>> problems = Library.validateDocument(doc, null, extensions);
    problems.whenCompleteAsync((validationProblems, done) -> {
        List<String> expectedErrorCodes = Arrays.asList("R-003", "TEST-001");
        List<String> documentErrorCodes = doc.getValidationProblemCodes();
        Assert.assertEquals(expectedErrorCodes, documentErrorCodes);
        List<String> problemErrorCodes = validationProblems.stream().map(p -> p.errorCode).collect(Collectors.toList());
        Assert.assertEquals(expectedErrorCodes, problemErrorCodes);
    });
}
Also used : IDocumentValidatorExtension(io.apicurio.datamodels.core.validation.IDocumentValidatorExtension) Arrays(java.util.Arrays) NodePath(io.apicurio.datamodels.core.models.NodePath) CompletableFuture(java.util.concurrent.CompletableFuture) Test(org.junit.Test) Node(io.apicurio.datamodels.core.models.Node) DocumentType(io.apicurio.datamodels.core.models.DocumentType) Collectors(java.util.stream.Collectors) Oas30Document(io.apicurio.datamodels.openapi.v3.models.Oas30Document) ArrayList(java.util.ArrayList) ValidationProblem(io.apicurio.datamodels.core.models.ValidationProblem) List(java.util.List) IDocumentValidatorExtension(io.apicurio.datamodels.core.validation.IDocumentValidatorExtension) ValidationProblemSeverity(io.apicurio.datamodels.core.models.ValidationProblemSeverity) Assert(org.junit.Assert) Document(io.apicurio.datamodels.core.models.Document) ArrayList(java.util.ArrayList) ArrayList(java.util.ArrayList) List(java.util.List) Oas30Document(io.apicurio.datamodels.openapi.v3.models.Oas30Document) Document(io.apicurio.datamodels.core.models.Document) Test(org.junit.Test)

Example 5 with Document

use of io.apicurio.datamodels.core.models.Document in project apicurio-data-models by Apicurio.

the class Dereferencer method dereference.

/**
 * Execute the algorithm.
 *
 * @return dereferenced clone of the source document.
 * @throws java.lang.RuntimeException if strict and some references could not be dereferenced
 */
public Document dereference() {
    Document clone = Library.cloneDocument(source);
    IReferenceManipulationStrategy strategy = null;
    switch(clone.getDocumentType()) {
        case asyncapi2:
            strategy = new Aai20IReferenceManipulationStrategy();
            break;
        case openapi2:
            strategy = new Oas20IReferenceManipulationStrategy();
            break;
        case openapi3:
            strategy = new Oas30IReferenceManipulationStrategy();
            break;
        default:
            throw new RuntimeException("Unknown document type: " + clone.getDocumentType());
    }
    // Keeps the nodes waiting to be processed (BFS-style)
    Queue<Context> processQueue = new LinkedList<>();
    // start with the whole model
    processQueue.add(new Context(null, clone));
    // Prevents recursive loops
    Map<String, String> resolvedToLocalMap = new HashMap<>();
    for (String ref : strategy.getExistingLocalComponents(clone).keySet()) {
        resolvedToLocalMap.put(ref, ref);
    }
    while (!processQueue.isEmpty()) {
        Context item = processQueue.remove();
        // Local components
        Map<String, Node> localComponents = strategy.getExistingLocalComponents(clone);
        // Collect all reference objects in the processed node
        ReferenceCollectionVisitor rcv = new ReferenceCollectionVisitor();
        VisitorUtil.visitTree(item.node, rcv, TraverserDirection.down);
        List<IReferenceNode> referencedNodes = rcv.getReferencedNodes();
        // For each reference node ...
        for (IReferenceNode node : referencedNodes) {
            // skip if already local, this makes sense if we're initially processing the whole Document
            if (item.parentRef == null && localComponents.containsKey(node.getReference()))
                continue;
            // Reference to be resolved
            Reference originalRef = new Reference(node.getReference());
            // Attempt to resolve
            if (item.parentRef != null && originalRef.isRelative()) {
                originalRef = originalRef.withAbsoluteFrom(new Reference(item.parentRef));
            }
            // to avoid cycles
            if (resolvedToLocalMap.containsKey(originalRef.getRef())) {
                node.setReference(resolvedToLocalMap.get(originalRef.getRef()));
                continue;
            }
            Node resolved = resolver.resolveRef(originalRef.getRef(), (Node) node);
            // if null keep the reference in an 'unresolvable' set to decide later
            if (resolved == null) {
                unresolvable.add(node.getReference());
            } else {
                IReferenceManipulationStrategy.ReferenceAndNode localRef = null;
                String name = originalRef.getName();
                // Remove the reference node so its name can be reused if possible.
                boolean nameReused = false;
                if (name.equals(strategy.getComponentName(clone, resolved))) {
                    nameReused = strategy.removeComponent(clone, name);
                }
                // repeat in case of name conflict
                for (int i = 0; i < Integer.MAX_VALUE; i++) {
                    if (i > 0)
                        name = originalRef.getName() + i;
                    try {
                        localRef = strategy.attachAsComponent(clone, name, resolved);
                        break;
                    } catch (IllegalArgumentException ex) {
                        // Assert we should be reusing the name
                        if (nameReused)
                            throw new IllegalStateException("Assertion error: " + "Component with name '" + name + "' should be reused, but can't be attached.");
                    // TODO maybe avoid exceptions?
                    }
                }
                if (localRef == null) {
                    unresolvable.add(node.getReference());
                } else {
                    // rename the original reference
                    if (!nameReused) {
                        node.setReference(localRef.getRef());
                    }
                    // add resolved node to processing queue
                    processQueue.add(new Context(originalRef.getRef(), localRef.getNode()));
                    // remember, to prevent cycles
                    resolvedToLocalMap.put(originalRef.getRef(), localRef.getRef());
                }
            }
        }
    }
    // we're done, if strict, throw
    if (unresolvable.size() != 0 && strict)
        throw new RuntimeException("Could not resolve some references: " + unresolvable);
    return clone;
}
Also used : IReferenceNode(io.apicurio.datamodels.core.models.IReferenceNode) HashMap(java.util.HashMap) IReferenceNode(io.apicurio.datamodels.core.models.IReferenceNode) Node(io.apicurio.datamodels.core.models.Node) Document(io.apicurio.datamodels.core.models.Document) LinkedList(java.util.LinkedList)

Aggregations

Document (io.apicurio.datamodels.core.models.Document)21 Node (io.apicurio.datamodels.core.models.Node)7 Oas30Document (io.apicurio.datamodels.openapi.v3.models.Oas30Document)7 URL (java.net.URL)7 Description (org.junit.runner.Description)6 Statement (org.junit.runners.model.Statement)6 DocumentType (io.apicurio.datamodels.core.models.DocumentType)5 NodePath (io.apicurio.datamodels.core.models.NodePath)4 ValidationProblem (io.apicurio.datamodels.core.models.ValidationProblem)4 OasDocument (io.apicurio.datamodels.openapi.models.OasDocument)4 Oas20Document (io.apicurio.datamodels.openapi.v2.models.Oas20Document)4 Test (org.junit.Test)4 JsonNode (com.fasterxml.jackson.databind.JsonNode)3 Aai20Document (io.apicurio.datamodels.asyncapi.v2.models.Aai20Document)2 DataModelReader (io.apicurio.datamodels.core.io.DataModelReader)2 ValidationProblemSeverity (io.apicurio.datamodels.core.models.ValidationProblemSeverity)2 IDocumentValidatorExtension (io.apicurio.datamodels.core.validation.IDocumentValidatorExtension)2 ArrayList (java.util.ArrayList)2 List (java.util.List)2 CompletableFuture (java.util.concurrent.CompletableFuture)2