You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by si...@apache.org on 2018/11/08 16:15:32 UTC

[sling-slingfeature-maven-plugin] 01/01: SLING-8032 - Add a MOJO which is able to validate JSON Feature file against the JSON Schema

This is an automated email from the ASF dual-hosted git repository.

simonetripodi pushed a commit to branch SLING-8032
in repository https://gitbox.apache.org/repos/asf/sling-slingfeature-maven-plugin.git

commit 23959e83d63c36b313fba44362a6eb59863f6968
Author: Simo Tripodi <st...@adobe.com>
AuthorDate: Thu Nov 8 17:15:13 2018 +0100

    SLING-8032 - Add a MOJO which is able to validate JSON Feature file
    against the JSON Schema
    
    JSON schema validation moved from MOJO to Preprocessor
---
 pom.xml                                            | 11 +++
 src/it/schema-validation-ko/invoker.properties     | 18 +++++
 src/it/schema-validation-ko/pom.xml                | 44 ++++++++++++
 .../src/main/features/invalid-feature.json         |  5 ++
 src/it/schema-validation-ko/verify.bsh             | 42 ++++++++++++
 .../apache/sling/feature/maven/Preprocessor.java   | 80 ++++++++++++++++++----
 6 files changed, 186 insertions(+), 14 deletions(-)

diff --git a/pom.xml b/pom.xml
index 32c0684..e8e3826 100644
--- a/pom.xml
+++ b/pom.xml
@@ -232,6 +232,17 @@
             <artifactId>maven-filtering</artifactId>
             <version>3.1.1</version>
         </dependency>
+        <!-- schema validation -->
+        <dependency>
+            <groupId>com.github.java-json-tools</groupId>
+            <artifactId>json-schema-validator</artifactId>
+            <version>2.2.10</version>
+        </dependency>
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-core</artifactId>
+            <version>2.2.3</version>
+        </dependency>
         <dependency>
             <groupId>org.mockito</groupId>
             <artifactId>mockito-all</artifactId>
diff --git a/src/it/schema-validation-ko/invoker.properties b/src/it/schema-validation-ko/invoker.properties
new file mode 100644
index 0000000..57af569
--- /dev/null
+++ b/src/it/schema-validation-ko/invoker.properties
@@ -0,0 +1,18 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+invoker.goals = clean validate
+invoker.buildResult = failure
+invoker.debug = true
diff --git a/src/it/schema-validation-ko/pom.xml b/src/it/schema-validation-ko/pom.xml
new file mode 100644
index 0000000..185ab58
--- /dev/null
+++ b/src/it/schema-validation-ko/pom.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+    Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+    agreements. See the NOTICE file distributed with this work for additional information
+    regarding copyright ownership. The ASF licenses this file to you under the Apache License,
+    Version 2.0 (the "License"); you may not use this file except in compliance with the
+    License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software distributed under the
+    License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+    either express or implied. See the License for the specific language governing permissions
+    and limitations under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.apache.sling</groupId>
+  <artifactId>slingfeature-maven-plugin-test</artifactId>
+  <packaging>jar</packaging>
+  <version>1.0.0-SNAPSHOT</version>
+
+  <name>Apache Sling Features Maven plugin test</name>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>@project.groupId@</groupId>
+        <artifactId>@project.artifactId@</artifactId>
+        <version>@project.version@</version>
+        <extensions>true</extensions>
+        <executions>
+          <execution>
+            <id>analyze</id>
+            <phase>validate</phase>
+            <goals>
+              <goal>features-schema-validation</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+
+</project>
diff --git a/src/it/schema-validation-ko/src/main/features/invalid-feature.json b/src/it/schema-validation-ko/src/main/features/invalid-feature.json
new file mode 100644
index 0000000..59ff8cc
--- /dev/null
+++ b/src/it/schema-validation-ko/src/main/features/invalid-feature.json
@@ -0,0 +1,5 @@
+{
+  "id":"org.apache.sling:slingfeature-maven-plugin-test:1.0.0-SNAPSHOT",
+  "model-version": 5,
+  "bundles": [ false ]
+}
diff --git a/src/it/schema-validation-ko/verify.bsh b/src/it/schema-validation-ko/verify.bsh
new file mode 100644
index 0000000..e41e362
--- /dev/null
+++ b/src/it/schema-validation-ko/verify.bsh
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ import java.io.*;
+import java.util.*;
+ import org.codehaus.plexus.util.*;
+     boolean check() {
+        File file = new File(basedir, "build.log");
+        String log = FileUtils.fileRead(file);
+         String[] values = {
+            " * /definitions/Bundle: instance type (boolean) does not match any allowed primitive type (allowed: [\"object\",\"string\"])",
+            " * /properties/model-version: instance type (integer) does not match any allowed primitive type (allowed: [\"string\"])"
+        };
+         for (String value : values) {
+            if (log.indexOf(value) < 0) {
+                System.out.println("FAILED!");
+                return false;
+            }
+        }
+         return true;
+    }
+     try {
+      return check();
+    }
+    catch(Throwable t) {
+      t.printStackTrace();
+      return false;
+    }
+     return true;
diff --git a/src/main/java/org/apache/sling/feature/maven/Preprocessor.java b/src/main/java/org/apache/sling/feature/maven/Preprocessor.java
index 6e03c84..931c5d7 100644
--- a/src/main/java/org/apache/sling/feature/maven/Preprocessor.java
+++ b/src/main/java/org/apache/sling/feature/maven/Preprocessor.java
@@ -16,20 +16,6 @@
  */
 package org.apache.sling.feature.maven;
 
-import org.apache.maven.model.Dependency;
-import org.apache.maven.project.MavenProject;
-import org.apache.maven.shared.utils.io.DirectoryScanner;
-import org.apache.sling.feature.Artifact;
-import org.apache.sling.feature.ArtifactId;
-import org.apache.sling.feature.Extension;
-import org.apache.sling.feature.ExtensionType;
-import org.apache.sling.feature.Feature;
-import org.apache.sling.feature.builder.BuilderContext;
-import org.apache.sling.feature.builder.FeatureBuilder;
-import org.apache.sling.feature.builder.FeatureProvider;
-import org.apache.sling.feature.io.json.FeatureJSONReader;
-import org.codehaus.plexus.logging.Logger;
-
 import java.io.File;
 import java.io.FileReader;
 import java.io.IOException;
@@ -37,6 +23,7 @@ import java.io.Reader;
 import java.io.StringReader;
 import java.io.StringWriter;
 import java.util.ArrayList;
+import java.util.Formatter;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
@@ -50,11 +37,73 @@ import javax.json.JsonReader;
 import javax.json.JsonValue;
 import javax.json.stream.JsonGenerator;
 
+import org.apache.maven.model.Dependency;
+import org.apache.maven.project.MavenProject;
+import org.apache.maven.shared.utils.io.DirectoryScanner;
+import org.apache.sling.feature.Artifact;
+import org.apache.sling.feature.ArtifactId;
+import org.apache.sling.feature.Extension;
+import org.apache.sling.feature.ExtensionType;
+import org.apache.sling.feature.Feature;
+import org.apache.sling.feature.builder.BuilderContext;
+import org.apache.sling.feature.builder.FeatureBuilder;
+import org.apache.sling.feature.builder.FeatureProvider;
+import org.apache.sling.feature.io.json.FeatureJSONReader;
+import org.codehaus.plexus.logging.Logger;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.github.fge.jsonschema.core.exceptions.ProcessingException;
+import com.github.fge.jsonschema.core.report.LogLevel;
+import com.github.fge.jsonschema.core.report.ProcessingMessage;
+import com.github.fge.jsonschema.core.report.ProcessingReport;
+import com.github.fge.jsonschema.main.JsonSchema;
+import com.github.fge.jsonschema.main.JsonSchemaFactory;
+
 /**
  * The processor processes all feature projects.
  */
 public class Preprocessor {
 
+    private final JsonSchema schema;
+
+    private final ObjectMapper objectMapper;
+
+    public Preprocessor() {
+       JsonSchemaFactory schemaFactory = JsonSchemaFactory.byDefault();
+       String jsonSchemaUri = getClass().getClassLoader().getResource("META-INF/feature/Feature-1.0.0.schema.json").toExternalForm();
+       try {
+           schema = schemaFactory.getJsonSchema(jsonSchemaUri);
+       } catch (ProcessingException e) {
+           throw new RuntimeException("An error occured when retrieving the JSON Schema from " + jsonSchemaUri, e);
+       }
+        objectMapper = new ObjectMapper();
+   }
+    private void checkFeatureFileValidation(File featureFile) {
+       try {
+           JsonNode instance = objectMapper.readTree(featureFile);
+           ProcessingReport report = schema.validate(instance, true);
+           if (!report.isSuccess()) {
+               Formatter formatter = new Formatter();
+               formatter.format("Feature file %s validation detected one or more errors:%n", featureFile);
+                for (ProcessingMessage message : report) {
+                   if (LogLevel.FATAL == message.getLogLevel()
+                           || LogLevel.ERROR == message.getLogLevel())
+                   formatter.format(" * %s: %s%n",
+                                    message.asJson().get("schema").get("pointer").asText(),
+                                    message.getMessage());
+               }
+                String errorMessage = formatter.toString();
+               formatter.close();
+               throw new RuntimeException(errorMessage);
+           }
+       } catch (IOException e) {
+           throw new RuntimeException("An error occurred while reading " + featureFile + " Feature file:", e);
+       } catch (ProcessingException e) {
+           throw new RuntimeException("An error occurred while validating Feature " + featureFile + ", read the log for details:", e);
+       }
+   }
+
     /**
      * Process the provided projects.
      * @param env The environment with all maven settings and projects
@@ -256,6 +305,8 @@ public class Preprocessor {
                     throw new RuntimeException("Unable to read feature " + file.getAbsolutePath(), io);
                 }
 
+                checkFeatureFileValidation(file);
+
                 final String json = preprocessFeature(logger, info, config, file, sb.toString());
                 try (final Reader reader = new StringReader(json)) {
                     final Feature feature = FeatureJSONReader.read(reader, file.getAbsolutePath());
@@ -404,6 +455,7 @@ public class Preprocessor {
 
 	                    // "external" dependency, we can already resolve it
 	                    final File featureFile = ProjectHelper.getOrResolveArtifact(info.project, env.session, env.artifactHandlerManager, env.resolver, id).getFile();
+	                    checkFeatureFileValidation(featureFile);
 	                    try (final FileReader r = new FileReader(featureFile)) {
 	                        return FeatureJSONReader.read(r, featureFile.getAbsolutePath());
 	                    } catch ( final IOException ioe) {