Start validating json

Make sure json matches the schema, or don't load the file.
Also start installing json files using CMakeLists instead of
in the recipe.

Change-Id: I78622b961d1185d864d6ddd27e5baad34bc3ef5e
Signed-off-by: James Feist <james.feist@linux.intel.com>
diff --git a/CMakeLists.txt b/CMakeLists.txt
index ce5d5e1..f14f97f 100755
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -108,4 +108,4 @@
 install (TARGETS fru-device entity-manager DESTINATION bin)
 install (DIRECTORY configurations DESTINATION share)
 install (DIRECTORY overlay_templates DESTINATION share)
-# install (DIRECTORY schemas DESTINATION share/configurations)
+install (DIRECTORY schemas DESTINATION share/configurations)
diff --git a/include/Utils.hpp b/include/Utils.hpp
index d991f0d..1e54477 100644
--- a/include/Utils.hpp
+++ b/include/Utils.hpp
@@ -16,8 +16,12 @@
 
 #pragma once
 #include <experimental/filesystem>
+#include <nlohmann/json.hpp>
 
 bool find_files(const std::experimental::filesystem::path &dir_path,
                 const std::string &match_string,
                 std::vector<std::experimental::filesystem::path> &found_paths,
                 unsigned int symlink_depth = 1);
+
+bool validateJson(const nlohmann::json &schemaFile,
+                  const nlohmann::json &input);
diff --git a/src/EntityManager.cpp b/src/EntityManager.cpp
index ab658b2..81df6e1 100644
--- a/src/EntityManager.cpp
+++ b/src/EntityManager.cpp
@@ -33,8 +33,9 @@
 #include <experimental/filesystem>
 
 constexpr const char *OUTPUT_DIR = "/var/configuration/";
-constexpr const char *CONFIGURATION_DIR = "/usr/share/configurations";
-constexpr const char *schemaFile = "schema.json";
+constexpr const char *configurationDirectory = "/usr/share/configurations";
+constexpr const char *schemaDirectory = "/usr/share/configurations/schemas";
+constexpr const char *globalSchema = "global.json";
 constexpr const char *TEMPLATE_CHAR = "$";
 constexpr const size_t PROPERTIES_CHANGED_UNTIL_FLUSH_COUNT = 20;
 constexpr const int32_t MAX_MAPPER_DEPTH = 0;
@@ -960,19 +961,32 @@
 {
     // find configuration files
     std::vector<fs::path> jsonPaths;
-    if (!find_files(fs::path(CONFIGURATION_DIR), R"(.*\.json)", jsonPaths, 0))
+    if (!find_files(fs::path(configurationDirectory), R"(.*\.json)", jsonPaths,
+                    0))
     {
         std::cerr << "Unable to find any configuration files in "
-                  << CONFIGURATION_DIR << "\n";
+                  << configurationDirectory << "\n";
         return false;
     }
+
+    std::ifstream schemaStream(std::string(schemaDirectory) + "/" +
+                               globalSchema);
+    if (!schemaStream.good())
+    {
+        std::cerr
+            << "Cannot open schema file,  cannot validate JSON, exiting\n\n";
+        std::exit(EXIT_FAILURE);
+    }
+    nlohmann::json schema = nlohmann::json::parse(schemaStream, nullptr, false);
+    if (schema.is_discarded())
+    {
+        std::cerr
+            << "Illegal schema file detected, cannot validate JSON, exiting\n";
+        std::exit(EXIT_FAILURE);
+    }
+
     for (auto &jsonPath : jsonPaths)
     {
-        if (boost::algorithm::ends_with(jsonPath.string(), schemaFile))
-        {
-            // todo: parse using schema
-            continue;
-        }
         std::ifstream jsonStream(jsonPath.c_str());
         if (!jsonStream.good())
         {
@@ -985,6 +999,12 @@
             std::cerr << "syntax error in " << jsonPath.string() << "\n";
             continue;
         }
+        if (!validateJson(schema, data))
+        {
+            std::cerr << "Error validating " << jsonPath.string() << "\n";
+            continue;
+        }
+
         if (data.type() == nlohmann::json::value_t::array)
         {
             for (auto &d : data)
diff --git a/src/Utils.cpp b/src/Utils.cpp
index b5c3787..6db1157 100644
--- a/src/Utils.cpp
+++ b/src/Utils.cpp
@@ -18,6 +18,10 @@
 #include <experimental/filesystem>
 #include <fstream>
 #include <regex>
+#include <valijson/adapters/nlohmann_json_adapter.hpp>
+#include <valijson/schema.hpp>
+#include <valijson/schema_parser.hpp>
+#include <valijson/validator.hpp>
 
 namespace fs = std::experimental::filesystem;
 
@@ -45,4 +49,19 @@
         }
     }
     return true;
+}
+
+bool validateJson(const nlohmann::json &schemaFile, const nlohmann::json &input)
+{
+    valijson::Schema schema;
+    valijson::SchemaParser parser;
+    valijson::adapters::NlohmannJsonAdapter schemaAdapter(schemaFile);
+    parser.populateSchema(schemaAdapter, schema);
+    valijson::Validator validator;
+    valijson::adapters::NlohmannJsonAdapter targetAdapter(input);
+    if (!validator.validate(schema, targetAdapter, NULL))
+    {
+        return false;
+    }
+    return true;
 }
\ No newline at end of file