make building handlers from json more generic

Problem: version-handler, a new feature that will be added to this
repository will also parse json files from the same directory ipmi-flash
does. Currently buildjson is a mix of some code that can be reused and
other code that is pretty specific to firmware updates; this makes it
hard to reuse the code.

Solution: factor out the generic parts and place it in bmc and then
leave the specific parts in firmware-handler. Also code changes have
been made to buildjson: wrap functions in a templated class that leaves
feature specific parsing as a pure virtual method.

Tested:
Ran the unit tests, which do test the parsing functionality.

Signed-off-by: Jason Ling <jasonling@google.com>
Change-Id: I021dc829a82d1719b4cb862cdfb224eca629a44d
diff --git a/bmc/buildjson.cpp b/bmc/buildjson.cpp
new file mode 100644
index 0000000..c4bc4b5
--- /dev/null
+++ b/bmc/buildjson.cpp
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2019 Google Inc.
+ *
+ * Licensed 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.
+ */
+#include "buildjson.hpp"
+
+#include "file_handler.hpp"
+#include "fs.hpp"
+
+#include <nlohmann/json.hpp>
+#include <sdbusplus/bus.hpp>
+
+#include <algorithm>
+#include <cstdio>
+#include <exception>
+#include <fstream>
+#include <string>
+#include <vector>
+
+namespace ipmi_flash
+{
+
+std::unique_ptr<TriggerableActionInterface>
+    buildFileSystemd(const nlohmann::json& data)
+{
+    /* This type of action requires a path and unit, and optionally a mode. */
+    const auto& path = data.at("path");
+    const auto& unit = data.at("unit");
+
+    /* the mode parameter is optional. */
+    std::string systemdMode = "replace";
+    const auto& mode = data.find("mode");
+    if (mode != data.end())
+    {
+        systemdMode = data.at("mode").get<std::string>();
+    }
+
+    return SystemdWithStatusFile::CreateSystemdWithStatusFile(
+        sdbusplus::bus::new_default(), path, unit, systemdMode);
+}
+
+std::unique_ptr<TriggerableActionInterface>
+    buildSystemd(const nlohmann::json& data)
+{
+    /* This type of action requires a unit, and optionally a mode. */
+    const auto& unit = data.at("unit");
+
+    /* the mode parameter is optional. */
+    std::string systemdMode = "replace";
+    const auto& mode = data.find("mode");
+    if (mode != data.end())
+    {
+        systemdMode = data.at("mode").get<std::string>();
+    }
+
+    return SystemdNoFile::CreateSystemdNoFile(sdbusplus::bus::new_default(),
+                                              unit, systemdMode);
+}
+
+template <typename T>
+std::vector<HandlerConfig<T>>
+    HandlersBuilderIfc<T>::buildHandlerConfigs(const std::string& directory)
+{
+    std::vector<HandlerConfig<T>> output;
+
+    std::vector<std::string> jsonPaths = GetJsonList(directory);
+
+    for (const auto& path : jsonPaths)
+    {
+        std::ifstream jsonFile(path);
+        if (!jsonFile.is_open())
+        {
+            std::fprintf(stderr, "Unable to open json file: %s\n",
+                         path.c_str());
+            continue;
+        }
+
+        auto data = nlohmann::json::parse(jsonFile, nullptr, false);
+        if (data.is_discarded())
+        {
+            std::fprintf(stderr, "Parsing json failed: %s\n", path.c_str());
+        }
+
+        std::vector<HandlerConfig<T>> configs = buildHandlerFromJson(data);
+        std::move(configs.begin(), configs.end(), std::back_inserter(output));
+    }
+    return output;
+}
+
+} // namespace ipmi_flash