Set error code for getParsedJson API

This commit updates getParsedJson API to set error codes in case of
error. This helps caller of the API to take action based on the error
code returned from the API.

Change-Id: I0b88806bbc2201ae162e1714613fa6a9bfe3df9d
Signed-off-by: Rekha Aparna <vrekhaaparna@ibm.com>
diff --git a/test/utest_json_utility.cpp b/test/utest_json_utility.cpp
index 4f0b5c5..283640f 100644
--- a/test/utest_json_utility.cpp
+++ b/test/utest_json_utility.cpp
@@ -1,6 +1,7 @@
 #include "parser.hpp"
 #include "types.hpp"
 #include "utility/json_utility.hpp"
+#include "utility/vpd_specific_utility.hpp"
 
 #include <iostream>
 
@@ -10,9 +11,19 @@
 
 TEST(IsFruPowerOffOnlyTest, PositiveTestCase)
 {
+    uint16_t l_errCode = 0;
     const std::string l_jsonPath{"/usr/local/share/vpd/50001001.json"};
     const std::string l_vpdPath{"/sys/bus/spi/drivers/at25/spi12.0/eeprom"};
-    const nlohmann::json l_parsedJson = jsonUtility::getParsedJson(l_jsonPath);
+    const nlohmann::json l_parsedJson =
+        jsonUtility::getParsedJson(l_jsonPath, l_errCode);
+
+    if (l_errCode)
+    {
+        logging::logMessage(
+            "Failed to parse JSON file [" + l_jsonPath +
+            "], error : " + vpdSpecificUtility::getErrCodeMsg(l_errCode));
+    }
+
     const bool l_result =
         jsonUtility::isFruPowerOffOnly(l_parsedJson, l_vpdPath);
     EXPECT_TRUE(l_result);
@@ -20,9 +31,19 @@
 
 TEST(IsFruPowerOffOnlyTest, NegativeTestCase)
 {
+    uint16_t l_errCode = 0;
     const std::string l_jsonPath{"/usr/local/share/vpd/50001001.json"};
     const std::string l_vpdPath{"/sys/bus/i2c/drivers/at24/4-0050/eeprom"};
-    const nlohmann::json l_parsedJson = jsonUtility::getParsedJson(l_jsonPath);
+    const nlohmann::json l_parsedJson =
+        jsonUtility::getParsedJson(l_jsonPath, l_errCode);
+
+    if (l_errCode)
+    {
+        logging::logMessage(
+            "Failed to parse JSON file [" + l_jsonPath +
+            "], error : " + vpdSpecificUtility::getErrCodeMsg(l_errCode));
+    }
+
     const bool l_result =
         jsonUtility::isFruPowerOffOnly(l_parsedJson, l_vpdPath);
     EXPECT_FALSE(l_result);
diff --git a/vpd-manager/include/error_codes.hpp b/vpd-manager/include/error_codes.hpp
index 161e747..ad436c4 100644
--- a/vpd-manager/include/error_codes.hpp
+++ b/vpd-manager/include/error_codes.hpp
@@ -17,6 +17,7 @@
 static constexpr auto MISSING_FLAG = 2002;
 static constexpr auto MISSING_ACTION_TAG = 2003;
 static constexpr auto FRU_PATH_NOT_FOUND = 2004;
+static constexpr auto JSON_PARSE_ERROR = 2005;
 
 // Generic errors.
 static constexpr auto INVALID_INPUT_PARAMETER = 3001;
@@ -30,6 +31,7 @@
     {MISSING_ACTION_TAG,
      "JSON is missing the action tag to be performed for the FRU."},
     {FRU_PATH_NOT_FOUND, "The FRU path is not found in the JSON."},
+    {JSON_PARSE_ERROR, "Error while parsing JSON file."},
     {INVALID_INPUT_PARAMETER,
      "Either one of the input parameter is invalid or empty."}};
 } // namespace error_code
diff --git a/vpd-manager/include/utility/json_utility.hpp b/vpd-manager/include/utility/json_utility.hpp
index e60e6f2..66be4fe 100644
--- a/vpd-manager/include/utility/json_utility.hpp
+++ b/vpd-manager/include/utility/json_utility.hpp
@@ -9,6 +9,7 @@
 #include <gpiod.hpp>
 #include <nlohmann/json.hpp>
 #include <utility/common_utility.hpp>
+#include <utility/vpd_specific_utility.hpp>
 
 #include <fstream>
 #include <type_traits>
@@ -93,42 +94,48 @@
  * @brief API to parse respective JSON.
  *
  * @param[in] pathToJson - Path to JSON.
+ * @param[out] o_errCode - To set error code in case of error.
  * @return on success parsed JSON. On failure empty JSON object.
  *
  * Note: Caller has to handle it in case an empty JSON object is received.
  */
-inline nlohmann::json getParsedJson(const std::string& pathToJson) noexcept
+inline nlohmann::json getParsedJson(const std::string& pathToJson,
+                                    uint16_t& o_errCode) noexcept
 {
+    if (pathToJson.empty())
+    {
+        o_errCode = error_code::INVALID_INPUT_PARAMETER;
+        return nlohmann::json{};
+    }
+
+    if (!std::filesystem::exists(pathToJson))
+    {
+        o_errCode = error_code::FILE_NOT_FOUND;
+        return nlohmann::json{};
+    }
+
+    if (std::filesystem::is_empty(pathToJson))
+    {
+        o_errCode = error_code::EMPTY_FILE;
+        return nlohmann::json{};
+    }
+
+    std::ifstream l_jsonFile(pathToJson);
+    if (!l_jsonFile)
+    {
+        o_errCode = error_code::FILE_ACCESS_ERROR;
+        return nlohmann::json{};
+    }
+
     try
     {
-        if (pathToJson.empty())
-        {
-            throw std::runtime_error("Path to JSON is missing");
-        }
-
-        if (!std::filesystem::exists(pathToJson) ||
-            std::filesystem::is_empty(pathToJson))
-        {
-            throw std::runtime_error(
-                "File does not exist or empty file: [" + pathToJson + "]");
-        }
-
-        std::ifstream l_jsonFile(pathToJson);
-        if (!l_jsonFile)
-        {
-            throw std::runtime_error(
-                "Failed to access Json path = " + pathToJson);
-        }
-
         return nlohmann::json::parse(l_jsonFile);
     }
     catch (const std::exception& l_ex)
     {
-        logging::logMessage(
-            "Failed to parse JSON file, error: " + std::string(l_ex.what()));
+        o_errCode = error_code::JSON_PARSE_ERROR;
+        return nlohmann::json{};
     }
-
-    return nlohmann::json{};
 }
 
 /**
@@ -1143,17 +1150,42 @@
 {
     try
     {
+        uint16_t l_errCode = 0;
         if ((i_imValue.at(0) == constants::HEX_VALUE_50) &&
             (i_imValue.at(1) == constants::HEX_VALUE_00) &&
             (i_imValue.at(2) == constants::HEX_VALUE_30))
         {
-            return jsonUtility::getParsedJson(constants::power_vs_50003_json);
+            nlohmann::json l_parsedJson = jsonUtility::getParsedJson(
+                constants::power_vs_50003_json, l_errCode);
+
+            if (l_errCode)
+            {
+                logging::logMessage(
+                    "Failed to parse JSON file [ " +
+                    std::string(constants::power_vs_50003_json) +
+                    " ], error : " +
+                    vpdSpecificUtility::getErrCodeMsg(l_errCode));
+            }
+
+            return l_parsedJson;
         }
         else if (i_imValue.at(0) == constants::HEX_VALUE_50 &&
                  (i_imValue.at(1) == constants::HEX_VALUE_00) &&
                  (i_imValue.at(2) == constants::HEX_VALUE_10))
         {
-            return jsonUtility::getParsedJson(constants::power_vs_50001_json);
+            nlohmann::json l_parsedJson = jsonUtility::getParsedJson(
+                constants::power_vs_50001_json, l_errCode);
+
+            if (l_errCode)
+            {
+                logging::logMessage(
+                    "Failed to parse JSON file [ " +
+                    std::string(constants::power_vs_50001_json) +
+                    " ], error : " +
+                    vpdSpecificUtility::getErrCodeMsg(l_errCode));
+            }
+
+            return l_parsedJson;
         }
         return nlohmann::json{};
     }
diff --git a/vpd-manager/src/backup_restore.cpp b/vpd-manager/src/backup_restore.cpp
index 61d5ba5..89d7d2a 100644
--- a/vpd-manager/src/backup_restore.cpp
+++ b/vpd-manager/src/backup_restore.cpp
@@ -21,13 +21,16 @@
     std::string l_backupAndRestoreCfgFilePath =
         i_sysCfgJsonObj.value("backupRestoreConfigPath", "");
 
+    uint16_t l_errCode = 0;
     m_backupAndRestoreCfgJsonObj =
-        jsonUtility::getParsedJson(l_backupAndRestoreCfgFilePath);
+        jsonUtility::getParsedJson(l_backupAndRestoreCfgFilePath, l_errCode);
 
-    if (m_backupAndRestoreCfgJsonObj.empty())
+    if (l_errCode)
     {
-        throw JsonException("JSON parsing failed",
-                            l_backupAndRestoreCfgFilePath);
+        throw JsonException(
+            "JSON parsing failed for file [" + l_backupAndRestoreCfgFilePath +
+                "], error : " + vpdSpecificUtility::getErrCodeMsg(l_errCode),
+            l_backupAndRestoreCfgFilePath);
     }
 }
 
diff --git a/vpd-manager/src/event_logger.cpp b/vpd-manager/src/event_logger.cpp
index a9ba077..9959d2f 100644
--- a/vpd-manager/src/event_logger.cpp
+++ b/vpd-manager/src/event_logger.cpp
@@ -354,9 +354,20 @@
             {
                 if (!l_ec)
                 {
+                    nlohmann::json l_parsedJson = jsonUtility::getParsedJson(
+                        INVENTORY_JSON_SYM_LINK, l_errCode);
+
+                    if (l_errCode)
+                    {
+                        logging::logMessage(
+                            "Failed to parse JSON file [ " +
+                            std::string(INVENTORY_JSON_SYM_LINK) +
+                            " ], error : " +
+                            vpdSpecificUtility::getErrCodeMsg(l_errCode));
+                    }
+
                     l_calloutInvPath = jsonUtility::getInventoryObjPathFromJson(
-                        jsonUtility::getParsedJson(INVENTORY_JSON_SYM_LINK),
-                        std::get<0>(i_callouts[0]), l_errCode);
+                        l_parsedJson, std::get<0>(i_callouts[0]), l_errCode);
                 }
                 else
                 {
diff --git a/vpd-manager/src/listener.cpp b/vpd-manager/src/listener.cpp
index 435f3d9..87cb182 100644
--- a/vpd-manager/src/listener.cpp
+++ b/vpd-manager/src/listener.cpp
@@ -269,12 +269,17 @@
 {
     try
     {
+        uint16_t l_errCode = 0;
         m_correlatedPropJson =
-            jsonUtility::getParsedJson(i_correlatedPropJsonFile);
-        if (m_correlatedPropJson.empty())
+            jsonUtility::getParsedJson(i_correlatedPropJsonFile, l_errCode);
+
+        if (l_errCode)
         {
-            throw JsonException("Failed to parse correlated properties JSON",
-                                i_correlatedPropJsonFile);
+            throw JsonException(
+                "Failed to parse correlated properties JSON [" +
+                    i_correlatedPropJsonFile + "], error : " +
+                    vpdSpecificUtility::getErrCodeMsg(l_errCode),
+                i_correlatedPropJsonFile);
         }
 
         const nlohmann::json& l_serviceJsonObjectList =
diff --git a/vpd-manager/src/single_fab.cpp b/vpd-manager/src/single_fab.cpp
index f2c73f8..0b3875e 100644
--- a/vpd-manager/src/single_fab.cpp
+++ b/vpd-manager/src/single_fab.cpp
@@ -23,14 +23,24 @@
 {
     try
     {
+        uint16_t l_errCode = 0;
         auto l_parsedVsbpJsonObj =
-            jsonUtility::getParsedJson(pimPersistVsbpPath);
+            jsonUtility::getParsedJson(pimPersistVsbpPath, l_errCode);
+
+        if (l_errCode)
+        {
+            throw JsonException(
+                "Failed to parse JSON file [ " +
+                    std::string(pimPersistVsbpPath) + " ], error : " +
+                    vpdSpecificUtility::getErrCodeMsg(l_errCode),
+                pimPersistVsbpPath);
+        }
+
         if (!l_parsedVsbpJsonObj.contains("value0") ||
             !l_parsedVsbpJsonObj["value0"].contains(constants::kwdIM) ||
             !l_parsedVsbpJsonObj["value0"][constants::kwdIM].is_array())
         {
-            throw std::runtime_error(
-                "Json is empty or mandatory tag(s) missing from JSON");
+            throw std::runtime_error("Mandatory tag(s) missing from JSON");
         }
 
         const types::BinaryVector l_imValue =
diff --git a/vpd-manager/src/worker.cpp b/vpd-manager/src/worker.cpp
index 63989dc..a80957d 100644
--- a/vpd-manager/src/worker.cpp
+++ b/vpd-manager/src/worker.cpp
@@ -42,7 +42,17 @@
 
         try
         {
-            m_parsedJson = jsonUtility::getParsedJson(m_configJsonPath);
+            uint16_t l_errCode = 0;
+            m_parsedJson =
+                jsonUtility::getParsedJson(m_configJsonPath, l_errCode);
+
+            if (l_errCode)
+            {
+                throw std::runtime_error(
+                    "JSON parsing failed for file [ " + m_configJsonPath +
+                    " ], error : " +
+                    vpdSpecificUtility::getErrCodeMsg(l_errCode));
+            }
 
             // check for mandatory fields at this point itself.
             if (!m_parsedJson.contains("frus"))
@@ -373,12 +383,17 @@
             "No system JSON found corresponding to IM read from VPD.");
     }
 
-    // re-parse the JSON once appropriate JSON has been selected.
-    m_parsedJson = jsonUtility::getParsedJson(systemJson);
+    uint16_t l_errCode = 0;
 
-    if (m_parsedJson.empty())
+    // re-parse the JSON once appropriate JSON has been selected.
+    m_parsedJson = jsonUtility::getParsedJson(systemJson, l_errCode);
+
+    if (l_errCode)
     {
-        throw(JsonException("Json parsing failed", systemJson));
+        throw(JsonException(
+            "JSON parsing failed for file [ " + systemJson +
+                " ], error : " + vpdSpecificUtility::getErrCodeMsg(l_errCode),
+            systemJson));
     }
 
     std::string devTreeFromJson;
@@ -1594,16 +1609,21 @@
 {
     try
     {
+        uint16_t l_errCode = 0;
         std::string l_backupAndRestoreCfgFilePath =
             m_parsedJson.value("backupRestoreConfigPath", "");
 
         nlohmann::json l_backupAndRestoreCfgJsonObj =
-            jsonUtility::getParsedJson(l_backupAndRestoreCfgFilePath);
+            jsonUtility::getParsedJson(l_backupAndRestoreCfgFilePath,
+                                       l_errCode);
 
-        if (l_backupAndRestoreCfgJsonObj.empty())
+        if (l_errCode)
         {
-            throw JsonException("JSON parsing failed",
-                                l_backupAndRestoreCfgFilePath);
+            throw JsonException(
+                "JSON parsing failed for file [ " +
+                    l_backupAndRestoreCfgFilePath + " ], error : " +
+                    vpdSpecificUtility::getErrCodeMsg(l_errCode),
+                l_backupAndRestoreCfgFilePath);
         }
 
         // check if either of "source" or "destination" has inventory path.