updated jackson-databind and changed json schema validator library 46/99846/3
authorPawel <pawel.kasperkiewicz@nokia.com>
Fri, 20 Dec 2019 08:56:29 +0000 (09:56 +0100)
committerPawel <pawel.kasperkiewicz@nokia.com>
Wed, 15 Jan 2020 08:36:22 +0000 (09:36 +0100)
Issue-ID: DCAEGEN2-1825
Signed-off-by: Pawel <pawel.kasperkiewicz@nokia.com>
Change-Id: Ia4c9c6286adcf84631a58f9d5bfef124fed1cee6

pom.xml
src/main/java/org/onap/dcae/ApplicationSettings.java
src/main/java/org/onap/dcae/JSonSchemasSupplier.java [new file with mode: 0644]
src/main/java/org/onap/dcae/restapi/EventValidator.java
src/main/java/org/onap/dcae/restapi/SchemaValidator.java [new file with mode: 0644]
src/test/java/org/onap/dcae/ApplicationSettingsTest.java
src/test/java/org/onap/dcae/restapi/EventValidatorTest.java
version.properties

diff --git a/pom.xml b/pom.xml
index f36068f..5dfcaf4 100644 (file)
--- a/pom.xml
+++ b/pom.xml
@@ -24,7 +24,7 @@
   </parent>\r
   <groupId>org.onap.dcaegen2.collectors.ves</groupId>\r
   <artifactId>VESCollector</artifactId>\r
-  <version>1.5.2-SNAPSHOT</version>\r
+  <version>1.5.3-SNAPSHOT</version>\r
   <name>dcaegen2-collectors-ves</name>\r
   <description>VESCollector</description>\r
   <properties>\r
         <!-- Import dependency management from Spring Boot -->\r
         <groupId>org.springframework.boot</groupId>\r
         <artifactId>spring-boot-dependencies</artifactId>\r
-        <version>2.1.0.RELEASE</version>\r
+        <version>2.2.2.RELEASE</version>\r
         <type>pom</type>\r
         <scope>import</scope>\r
       </dependency>\r
       <version>1.1.1</version>\r
     </dependency>\r
     <dependency>\r
-      <groupId>com.github.fge</groupId>\r
+      <groupId>com.networknt</groupId>\r
       <artifactId>json-schema-validator</artifactId>\r
-      <version>2.2.6</version>\r
-    </dependency>\r
-    <dependency>\r
-      <groupId>com.github.fge</groupId>\r
-      <artifactId>json-schema-core</artifactId>\r
-      <version>1.2.5</version>\r
+      <version>1.0.29</version>\r
+      <exclusions>\r
+        <exclusion>\r
+          <groupId>com.fasterxml.jackson.core</groupId>\r
+          <artifactId>jackson-databind</artifactId>\r
+        </exclusion>\r
+      </exclusions>\r
     </dependency>\r
     <dependency>\r
       <groupId>com.google.code.gson</groupId>\r
index 5164f87..1e9ae69 100644 (file)
@@ -3,7 +3,7 @@
  * PROJECT
  * ================================================================================
  * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
- * Copyright (C) 2018 Nokia. All rights reserved.s
+ * Copyright (C) 2018 - 2019 Nokia. All rights reserved.s
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 
 package org.onap.dcae;
 
-import static io.vavr.API.Tuple;
-import static java.lang.String.format;
-import static java.nio.file.Files.readAllBytes;
-
-import com.fasterxml.jackson.databind.JsonNode;
-import com.github.fge.jackson.JsonLoader;
-import com.github.fge.jsonschema.core.exceptions.ProcessingException;
-import com.github.fge.jsonschema.main.JsonSchema;
-import com.github.fge.jsonschema.main.JsonSchemaFactory;
 import com.google.common.annotations.VisibleForTesting;
+import com.networknt.schema.JsonSchema;
 import io.vavr.Function1;
-import io.vavr.Tuple2;
 import io.vavr.collection.HashMap;
 import io.vavr.collection.List;
 import io.vavr.collection.Map;
-import java.io.IOException;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import javax.annotation.Nullable;
 import org.apache.commons.configuration.ConfigurationException;
 import org.apache.commons.configuration.PropertiesConfiguration;
-import org.json.JSONObject;
 import org.onap.dcae.common.configuration.AuthMethodType;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import javax.annotation.Nullable;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import static java.lang.String.format;
 
 /**
  * Abstraction over application configuration.
@@ -58,6 +48,7 @@ public class ApplicationSettings {
     private final String appInvocationDir;
     private final String configurationFileLocation;
     private final PropertiesConfiguration properties = new PropertiesConfiguration();
+    private final JSonSchemasSupplier jSonSchemasSupplier = new JSonSchemasSupplier();
     private final Map<String, JsonSchema> loadedJsonSchemas;
 
     public ApplicationSettings(String[] args, Function1<String[], Map<String, String>> argsParser) {
@@ -71,7 +62,9 @@ public class ApplicationSettings {
         configurationFileLocation = findOutConfigurationFileLocation(parsedArgs);
         loadPropertiesFromFile();
         parsedArgs.filterKeys(k -> !"c".equals(k)).forEach(this::addOrUpdate);
-        loadedJsonSchemas = loadJsonSchemas();
+        String collectorSchemaFile = properties.getString("collector.schema.file",
+                format("{\"%s\":\"etc/CommonEventFormat_28.4.1.json\"}", FALLBACK_VES_VERSION));
+        loadedJsonSchemas = jSonSchemasSupplier.loadJsonSchemas(collectorSchemaFile);
     }
 
     public void reloadProperties() {
@@ -187,24 +180,6 @@ public class ApplicationSettings {
         return prependWithUserDirOnRelative(parsedArgs.get("c").getOrElse("etc/collector.properties"));
     }
 
-    private Map<String, JsonSchema> loadJsonSchemas() {
-        return jsonSchema().toMap().entrySet().stream()
-            .map(this::readSchemaForVersion)
-            .collect(HashMap.collector());
-    }
-
-    private Tuple2<String, JsonSchema> readSchemaForVersion(java.util.Map.Entry<String, Object> versionToFilePath) {
-        try {
-            String schemaContent = new String(
-                readAllBytes(Paths.get(versionToFilePath.getValue().toString())));
-            JsonNode schemaNode = JsonLoader.fromString(schemaContent);
-            JsonSchema schema = JsonSchemaFactory.byDefault().getJsonSchema(schemaNode);
-            return Tuple(versionToFilePath.getKey(), schema);
-        } catch (IOException | ProcessingException e) {
-            throw new ApplicationException("Could not read schema from path: " + versionToFilePath.getValue(), e);
-        }
-    }
-
     private Map<String, String> prepareUsersMap(@Nullable String allowedUsers) {
         return allowedUsers == null ? HashMap.empty()
             : List.of(allowedUsers.split("\\|"))
@@ -212,11 +187,6 @@ public class ApplicationSettings {
                 .toMap(t-> t[0].trim(), t -> t[1].trim());
     }
 
-    private JSONObject jsonSchema() {
-        return new JSONObject(properties.getString("collector.schema.file",
-                format("{\"%s\":\"etc/CommonEventFormat_28.4.1.json\"}", FALLBACK_VES_VERSION)));
-    }
-
     private Map<String, String[]> convertDMaaPStreamsPropertyToMap(String streamIdsProperty) {
         java.util.HashMap<String, String[]> domainToStreamIdsMapping = new java.util.HashMap<>();
         String[] topics = streamIdsProperty.split("\\|");
diff --git a/src/main/java/org/onap/dcae/JSonSchemasSupplier.java b/src/main/java/org/onap/dcae/JSonSchemasSupplier.java
new file mode 100644 (file)
index 0000000..d7cd566
--- /dev/null
@@ -0,0 +1,58 @@
+/*\r
+ * ============LICENSE_START=======================================================\r
+ * PROJECT\r
+ * ================================================================================\r
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.\r
+ * Copyright (C) 2019 Nokia. All rights reserved.s\r
+ * ================================================================================\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ * ============LICENSE_END=========================================================\r
+ */\r
+package org.onap.dcae;\r
+\r
+import com.networknt.schema.JsonSchema;\r
+import com.networknt.schema.JsonSchemaFactory;\r
+import io.vavr.Tuple2;\r
+import io.vavr.collection.HashMap;\r
+import io.vavr.collection.Map;\r
+import org.json.JSONObject;\r
+\r
+import java.io.IOException;\r
+import java.nio.file.Paths;\r
+\r
+import static io.vavr.API.Tuple;\r
+import static java.nio.file.Files.readAllBytes;\r
+\r
+class JSonSchemasSupplier {\r
+\r
+    public Map<String, JsonSchema> loadJsonSchemas(String collectorSchemaFile) {\r
+        JSONObject jsonObject = new JSONObject(collectorSchemaFile);\r
+        return jsonObject.toMap().entrySet().stream()\r
+            .map(JSonSchemasSupplier::readSchemaForVersion)\r
+            .collect(HashMap.collector());\r
+    }\r
+\r
+\r
+    private static Tuple2<String, JsonSchema> readSchemaForVersion(java.util.Map.Entry<String, Object> versionToFilePath) {\r
+        try {\r
+            String schemaContent = new String(\r
+                readAllBytes(Paths.get(versionToFilePath.getValue().toString())));\r
+            JsonSchemaFactory factory = JsonSchemaFactory.getInstance();\r
+            JsonSchema schema = factory.getSchema(schemaContent);\r
+\r
+            return Tuple(versionToFilePath.getKey(), schema);\r
+        } catch (IOException e) {\r
+            throw new ApplicationException("Could not read schema from path: " + versionToFilePath.getValue(), e);\r
+        }\r
+    }\r
+}\r
index f119b50..009247c 100644 (file)
  */
 package org.onap.dcae.restapi;
 
-import static java.util.stream.StreamSupport.stream;
-
-import com.github.fge.jackson.JsonLoader;
-import com.github.fge.jsonschema.core.report.ProcessingReport;
-import com.github.fge.jsonschema.main.JsonSchema;
-import java.util.Optional;
 import org.json.JSONObject;
-import org.onap.dcae.ApplicationException;
 import org.onap.dcae.ApplicationSettings;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.http.ResponseEntity;
-
+import java.util.Optional;
 public class EventValidator {
 
-  private static final Logger log = LoggerFactory.getLogger(EventValidator.class);
-
+  private final SchemaValidator schemaValidator = new SchemaValidator();
   private ApplicationSettings applicationSettings;
 
   public EventValidator(ApplicationSettings applicationSettings) {
@@ -46,7 +38,7 @@ public class EventValidator {
   public Optional<ResponseEntity<String>> validate(JSONObject jsonObject, String type, String version){
     if (applicationSettings.jsonSchemaValidationEnabled()) {
       if (jsonObject.has(type)) {
-        if (!conformsToSchema(jsonObject, version)) {
+        if (!schemaValidator.conformsToSchema(jsonObject, applicationSettings.jsonSchema(version))) {
           return errorResponse(ApiException.SCHEMA_VALIDATION_FAILED);
         }
       } else {
@@ -56,21 +48,6 @@ public class EventValidator {
     return Optional.empty();
   }
 
-  private boolean conformsToSchema(JSONObject payload, String version) {
-    try {
-      JsonSchema schema = applicationSettings.jsonSchema(version);
-      ProcessingReport report = schema.validate(JsonLoader.fromString(payload.toString()));
-      if (report.isSuccess()) {
-        return true;
-      }
-      log.warn("Schema validation failed for event: " + payload);
-      stream(report.spliterator(), false).forEach(e -> log.warn(e.getMessage()));
-      return false;
-    } catch (Exception e) {
-      throw new ApplicationException("Unable to validate against schema", e);
-    }
-  }
-
   private Optional<ResponseEntity<String>> errorResponse(ApiException noServerResources) {
     return Optional.of(ResponseEntity.status(noServerResources.httpStatusCode)
         .body(noServerResources.toJSON().toString()));
diff --git a/src/main/java/org/onap/dcae/restapi/SchemaValidator.java b/src/main/java/org/onap/dcae/restapi/SchemaValidator.java
new file mode 100644 (file)
index 0000000..9463807
--- /dev/null
@@ -0,0 +1,58 @@
+/*\r
+ * ============LICENSE_START=======================================================\r
+ * PROJECT\r
+ * ================================================================================\r
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.\r
+ * Copyright (C) 2019 Nokia. All rights reserved.s\r
+ * ================================================================================\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ * ============LICENSE_END=========================================================\r
+ */\r
+package org.onap.dcae.restapi;\r
+\r
+\r
+import com.fasterxml.jackson.databind.JsonNode;\r
+import com.fasterxml.jackson.databind.ObjectMapper;\r
+import com.networknt.schema.JsonSchema;\r
+import com.networknt.schema.ValidationMessage;\r
+import org.json.JSONObject;\r
+import org.onap.dcae.ApplicationException;\r
+import org.slf4j.Logger;\r
+import org.slf4j.LoggerFactory;\r
+\r
+import java.util.Set;\r
+\r
+class SchemaValidator {\r
+    public static final Logger log = LoggerFactory.getLogger(SchemaValidator.class);\r
+\r
+    public boolean conformsToSchema(JSONObject payload, JsonSchema schema) {\r
+        try {\r
+            ObjectMapper mapper = new ObjectMapper();\r
+\r
+            String content = payload.toString();\r
+            JsonNode node = mapper.readTree(content);\r
+            Set<ValidationMessage> messageSet = schema.validate(node);\r
+\r
+            if (messageSet.isEmpty()) {\r
+                return true;\r
+            }\r
+\r
+            log.warn("Schema validation failed for event: " + payload);\r
+            messageSet.stream().forEach(it->log.warn(it.getMessage()) );\r
+\r
+            return false;\r
+        } catch (Exception e) {\r
+            throw new ApplicationException("Unable to validate against schema", e);\r
+        }\r
+    }\r
+}\r
index 6b0023f..c4ba586 100644 (file)
@@ -2,7 +2,7 @@
  * ============LICENSE_START=======================================================
  * org.onap.dcaegen2.collectors.ves
  * ================================================================================
- * Copyright (C) 2018 Nokia. All rights reserved.
+ * Copyright (C) 2018 - 2019 Nokia. All rights reserved.
  * Copyright (C) 2018 AT&T Intellectual Property. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -32,8 +32,7 @@ import static org.onap.dcae.TestingUtilities.createTemporaryFile;
 
 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.main.JsonSchema;
+import com.networknt.schema.JsonSchema;
 import io.vavr.collection.HashMap;
 import io.vavr.collection.Map;
 import java.io.File;
@@ -47,6 +46,13 @@ import org.junit.Test;
 
 public class ApplicationSettingsTest {
 
+    private static final String SAMPLE_JSON_SCHEMA = "{"
+            + "  \"type\": \"object\","
+            + "  \"properties\": {"
+            + "     \"state\": { \"type\": \"string\" }"
+            + "  }"
+            + "}";
+
     @Test
     public void shouldMakeApplicationSettingsOutOfCLIArguments() {
         // given
@@ -254,15 +260,9 @@ public class ApplicationSettingsTest {
     }
 
     @Test
-    public void shouldReturnJSONSchema() throws IOException, ProcessingException {
+    public void shouldReportValidateJSONSchemaErrorWhenJsonContainsIntegerValueNotString() throws IOException {
         // when
-        String sampleJsonSchema = "{"
-            + "  \"type\": \"object\","
-            + "  \"properties\": {"
-            + "     \"state\": { \"type\": \"string\" }" 
-            + "  }" 
-            + "}";
-        Path temporarySchemaFile = createTemporaryFile(sampleJsonSchema);
+        Path temporarySchemaFile = createTemporaryFile(SAMPLE_JSON_SCHEMA);
 
         // when
         JsonSchema schema = fromTemporaryConfiguration(
@@ -271,9 +271,25 @@ public class ApplicationSettingsTest {
 
         // then
         JsonNode incorrectTestObject = new ObjectMapper().readTree("{ \"state\": 1 }");
+
+        assertFalse(schema.validate(incorrectTestObject).isEmpty());
+
+    }
+
+    @Test
+    public void shouldDoNotReportAnyValidateJSONSchemaError() throws IOException {
+        // when
+        Path temporarySchemaFile = createTemporaryFile(SAMPLE_JSON_SCHEMA);
+
+        // when
+        JsonSchema schema = fromTemporaryConfiguration(
+                String.format("collector.schema.file={\"v1\": \"%s\"}", temporarySchemaFile))
+                .jsonSchema("v1");
+
+        // then
         JsonNode correctTestObject = new ObjectMapper().readTree("{ \"state\": \"hi\" }");
-        assertFalse(schema.validate(incorrectTestObject).isSuccess());
-        assertTrue(schema.validate(correctTestObject).isSuccess());
+     ;
+        assertTrue(schema.validate(correctTestObject).isEmpty());
     }
 
     @Test
index 5bacd31..4ac3c48 100644 (file)
@@ -20,9 +20,8 @@
 
 package org.onap.dcae.restapi;
 
-import com.github.fge.jackson.JsonLoader;
-import com.github.fge.jsonschema.core.exceptions.ProcessingException;
-import com.github.fge.jsonschema.main.JsonSchemaFactory;
+import com.networknt.schema.JsonSchema;
+import com.networknt.schema.JsonSchemaFactory;
 import org.json.JSONObject;
 import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
@@ -84,7 +83,7 @@ public class EventValidatorTest {
     }
 
     @Test
-    public void shouldReturnSchemaValidationFailedErrorOnInvalidJsonObjectSchema() throws ProcessingException, IOException {
+    public void shouldReturnSchemaValidationFailedErrorOnInvalidJsonObjectSchema() throws IOException {
         //given
         String schemaRejectingEverything = "{\"not\":{}}";
         mockJsonSchema(schemaRejectingEverything);
@@ -98,7 +97,7 @@ public class EventValidatorTest {
     }
 
     @Test
-    public void shouldReturnEmptyOptionalOnValidJsonObjectSchema() throws ProcessingException, IOException {
+    public void shouldReturnEmptyOptionalOnValidJsonObjectSchema() throws IOException {
         //given
         String schemaAcceptingEverything = "{}";
         mockJsonSchema(schemaAcceptingEverything);
@@ -111,10 +110,11 @@ public class EventValidatorTest {
         assertEquals(Optional.empty(), result);
     }
 
-    private void mockJsonSchema(String jsonSchema) throws IOException, ProcessingException {
-        when(settings.jsonSchema(any())).thenReturn(
-                JsonSchemaFactory.byDefault()
-                        .getJsonSchema(JsonLoader.fromString(jsonSchema)));
+    private void mockJsonSchema(String jsonSchemaContent) {
+        JsonSchemaFactory factory = JsonSchemaFactory.getInstance();
+
+        JsonSchema schema = factory.getSchema(jsonSchemaContent);
+        when(settings.jsonSchema(any())).thenReturn(schema);
     }
 
     private Optional<ResponseEntity<String>> generateResponseOptional(ApiException schemaValidationFailed) {
index 3f9d877..d897763 100644 (file)
@@ -1,6 +1,6 @@
 major=1
 minor=5
-patch=2
+patch=3
 base_version=${major}.${minor}.${patch}
 release_version=${base_version}
 snapshot_version=${base_version}-SNAPSHOT