Refactor: bios_parser: Implement a new parsing process

The new version parses the configuration file before `bios module` is loaded.

Assume that configuration files consist of bios attributes. For each attribute,
Parsing process has the following 3 steps.

1. Get bios strings for BIOS String Table
2. Implement an `attribute to dbus object` mapping
3. Get the type-related values for the attribute

1), 3) are type-related, need to implement handlers for those.

Signed-off-by: John Wang <wangzqbj@inspur.com>
Change-Id: Id7de7f163e75945fb4efdc9b58aa199cb363dd9b
diff --git a/libpldmresponder/bios.cpp b/libpldmresponder/bios.cpp
index 31b4ec0..8dbc80e 100644
--- a/libpldmresponder/bios.cpp
+++ b/libpldmresponder/bios.cpp
@@ -8,7 +8,6 @@
 #include <boost/crc.hpp>
 #include <chrono>
 #include <ctime>
-#include <iostream>
 #include <memory>
 #include <numeric>
 #include <phosphor-logging/elog-errors.hpp>
@@ -156,12 +155,11 @@
  *  @param[in] transferOpFlag - flag to indicate which part of data being
  * transferred
  *  @param[in] instanceID - instance ID to identify the command
- *  @param[in] biosJsonDir - path where the BIOS json files are present
  */
 Response getBIOSStringTable(BIOSTable& BIOSStringTable,
                             uint32_t /*transferHandle*/,
-                            uint8_t /*transferOpFlag*/, uint8_t instanceID,
-                            const char* biosJsonDir)
+                            uint8_t /*transferOpFlag*/, uint8_t instanceID)
+
 {
     Response response(sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES,
                       0);
@@ -169,14 +167,7 @@
 
     if (BIOSStringTable.isEmpty())
     { // no persisted table, constructing fresh table and file
-        auto biosStrings = bios_parser::getStrings(biosJsonDir);
-        if (biosStrings.empty())
-        {
-            encode_get_bios_table_resp(instanceID, PLDM_BIOS_TABLE_UNAVAILABLE,
-                                       0, PLDM_START_AND_END, nullptr,
-                                       response.size(), responsePtr);
-            return response;
-        }
+        auto biosStrings = bios_parser::getStrings();
         std::sort(biosStrings.begin(), biosStrings.end());
         // remove all duplicate strings received from bios json
         biosStrings.erase(std::unique(biosStrings.begin(), biosStrings.end()),
@@ -408,10 +399,8 @@
  *  @param[in,out] attributeTable - the attribute table
  *
  */
-void constructAttrTable(const BIOSTable& BIOSStringTable,
-                        const char* biosJsonDir, Table& attributeTable)
+void constructAttrTable(const BIOSTable& BIOSStringTable, Table& attributeTable)
 {
-    setupValueLookup(biosJsonDir);
     const auto& attributeMap = getValues();
     StringHandle strHandle;
 
@@ -535,15 +524,8 @@
  *  @param[in,out] attributeTable - the attribute table
  *
  */
-void constructAttrTable(const BIOSTable& BIOSStringTable,
-                        const char* biosJsonDir, Table& attributeTable)
+void constructAttrTable(const BIOSTable& BIOSStringTable, Table& attributeTable)
 {
-    auto rc = setupValueLookup(biosJsonDir);
-    if (rc == -1)
-    {
-        log<level::ERR>("Failed to parse entries in Json file");
-        return;
-    }
     const auto& attributeMap = getValues();
     StringHandle strHandle;
 
@@ -650,9 +632,8 @@
     }
 }
 
-using typeHandler =
-    std::function<void(const BIOSTable& BIOSStringTable,
-                       const char* biosJsonDir, Table& attributeTable)>;
+using typeHandler = std::function<void(const BIOSTable& BIOSStringTable,
+                                       Table& attributeTable)>;
 std::map<BIOSJsonName, typeHandler> attrTypeHandlers{
     {bios_parser::bIOSEnumJson, bios_type_enum::constructAttrTable},
     {bios_parser::bIOSStrJson, bios_type_string::constructAttrTable}};
@@ -690,7 +671,7 @@
             fs::path file = dir / it->first;
             if (fs::exists(file))
             {
-                it->second(BIOSStringTable, biosJsonDir, attributeTable);
+                it->second(BIOSStringTable, attributeTable);
             }
         }
 
@@ -843,6 +824,15 @@
                       0);
     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
 
+    if (setupConfig(biosJsonDir) != 0)
+    {
+        encode_get_bios_table_resp(
+            request->hdr.instance_id, PLDM_BIOS_TABLE_UNAVAILABLE,
+            0 /* nxtTransferHandle */, PLDM_START_AND_END, nullptr,
+            response.size(), responsePtr);
+        return response;
+    }
+
     uint32_t transferHandle{};
     uint8_t transferOpFlag{};
     uint8_t tableType{};
@@ -861,9 +851,9 @@
         {
             case PLDM_BIOS_STRING_TABLE:
 
-                response = getBIOSStringTable(
-                    BIOSStringTable, transferHandle, transferOpFlag,
-                    request->hdr.instance_id, biosJsonDir);
+                response = getBIOSStringTable(BIOSStringTable, transferHandle,
+                                              transferOpFlag,
+                                              request->hdr.instance_id);
                 break;
             case PLDM_BIOS_ATTR_TABLE:
 
diff --git a/libpldmresponder/bios_parser.cpp b/libpldmresponder/bios_parser.cpp
index 99c1149..30fee04 100644
--- a/libpldmresponder/bios_parser.cpp
+++ b/libpldmresponder/bios_parser.cpp
@@ -15,21 +15,38 @@
 namespace fs = std::filesystem;
 using namespace phosphor::logging;
 
-namespace
-{
-
 const std::vector<Json> emptyJsonList{};
 const Json emptyJson{};
 
-} // namespace
+struct DBusMapping
+{
+    std::string objectPath;   //!< D-Bus object path
+    std::string interface;    //!< D-Bus interface
+    std::string propertyName; //!< D-Bus property name
+};
 
-int parseBiosJsonFile(const char* dirPath, const std::string& fileName,
+using AttrName = std::string;
+using BIOSJsonName = std::string;
+using AttrLookup = std::map<AttrName, std::optional<DBusMapping>>;
+using BIOSStringHandler =
+    std::function<int(const Json& entry, Strings& strings)>;
+using AttrLookupHandler = std::function<int(const Json& entry, AttrLookup)>;
+using typeHandler = std::function<int(const Json& entry)>;
+
+Strings BIOSStrings;
+AttrLookup BIOSAttrLookup;
+
+const Strings& getStrings()
+{
+    return BIOSStrings;
+}
+
+int parseBiosJsonFile(const fs::path& dirPath, const std::string& fileName,
                       Json& fileData)
 {
     int rc = 0;
 
-    fs::path filePath(dirPath);
-    filePath /= fileName;
+    fs::path filePath = dirPath / fileName;
 
     std::ifstream jsonFile(filePath);
     if (!jsonFile.is_open())
@@ -63,45 +80,34 @@
                  uint64_t, double, std::string>;
 using Value = std::string;
 
-/** @struct DBusMapping
- *
- *  Data structure for storing information regarding BIOS enumeration attribute
- *  and the D-Bus object for the attribute.
+/** @brief Map of DBus property value to attribute value
  */
-struct DBusMapping
-{
-    std::string objectPath;   //!< D-Bus object path
-    std::string interface;    //!< D-Bus interface
-    std::string propertyName; //!< D-Bus property name
-    std::map<PropertyValue, Value>
-        dBusValToValMap; //!< Map of D-Bus property
-                         //!< value to attribute value
-};
+using DbusValToValMap = std::map<PropertyValue, Value>;
+
+/** @brief Map containing the DBus property value to attribute value map for the
+ * BIOS enumeration type attributes
+ */
+std::map<AttrName, DbusValToValMap> dbusValToValMaps;
 
 /** @brief Map containing the possible and the default values for the BIOS
  *         enumeration type attributes.
  */
 AttrValuesMap valueMap;
 
-/** @brief Map containing the optional D-Bus property information about the
- *         BIOS enumeration type attributes.
- */
-std::map<AttrName, std::optional<DBusMapping>> attrLookup;
-
 /** @brief Populate the mapping between D-Bus property value and attribute value
  *         for the BIOS enumeration attribute.
  *
  *  @param[in] type - type of the D-Bus property
  *  @param[in] dBusValues - json array of D-Bus property values
  *  @param[in] pv - Possible values for the BIOS enumeration attribute
- *  @param[out] mapping - D-Bus mapping object for the attribute
  *
  */
-void populateMapping(const std::string& type, const Json& dBusValues,
-                     const PossibleValues& pv, DBusMapping& mapping)
+DbusValToValMap populateMapping(const std::string& type, const Json& dBusValues,
+                                const PossibleValues& pv)
 {
     size_t pos = 0;
     PropertyValue value;
+    DbusValToValMap valueMap;
     for (auto it = dBusValues.begin(); it != dBusValues.end(); ++it, ++pos)
     {
         if (type == "uint8_t")
@@ -150,102 +156,57 @@
                             entry("TYPE=%s", type.c_str()));
         }
 
-        mapping.dBusValToValMap.emplace(value, pv[pos]);
-    }
-}
-
-/** @brief Read the possible values for the BIOS enumeration type
- *
- *  @param[in] possibleValues - json array of BIOS enumeration possible values
- */
-PossibleValues readPossibleValues(Json& possibleValues)
-{
-    Strings biosStrings{};
-
-    for (auto& val : possibleValues)
-    {
-        biosStrings.emplace_back(std::move(val));
+        valueMap.emplace(value, pv[pos]);
     }
 
-    return biosStrings;
+    return valueMap;
 }
 
 } // namespace internal
 
-int setupValueLookup(const char* dirPath)
+int setupBIOSStrings(const Json& entry, Strings& strings)
 {
-    int rc = 0;
+    Json pvs = entry.value("possible_values", emptyJsonList);
 
-    if (!internal::valueMap.empty() && !internal::attrLookup.empty())
+    for (auto& pv : pvs)
     {
-        return rc;
+        strings.emplace_back(std::move(pv.get<std::string>()));
     }
 
-    // Parse the BIOS enumeration config file
-    fs::path filePath(dirPath);
-    filePath /= bIOSEnumJson;
+    return 0;
+}
 
-    std::ifstream jsonFile(filePath);
-    if (!jsonFile.is_open())
+int setup(const Json& entry)
+{
+    PossibleValues possibleValues;
+    DefaultValues defaultValues;
+
+    std::string attrName = entry.value("attribute_name", "");
+    Json pv = entry["possible_values"];
+    for (auto& val : pv)
     {
-        log<level::ERR>("BIOS enum config file does not exist",
-                        entry("FILE=%s", filePath.c_str()));
-        rc = -1;
-        return rc;
+        possibleValues.emplace_back(std::move(val));
     }
-
-    auto fileData = Json::parse(jsonFile, nullptr, false);
-    if (fileData.is_discarded())
+    Json dv = entry["default_values"];
+    for (auto& val : dv)
     {
-        log<level::ERR>("Parsing config file failed");
-        rc = -1;
-        return rc;
+        defaultValues.emplace_back(std::move(val));
     }
-
-    auto entries = fileData.value("entries", emptyJsonList);
-    // Iterate through each JSON object in the config file
-    for (const auto& entry : entries)
+    if (entry.count("dbus") != 0)
     {
-        std::string attr = entry.value("attribute_name", "");
-        PossibleValues possibleValues;
-        DefaultValues defaultValues;
-
-        Json pv = entry["possible_values"];
-        for (auto& val : pv)
-        {
-            possibleValues.emplace_back(std::move(val));
-        }
-
-        Json dv = entry["default_values"];
-        for (auto& val : dv)
-        {
-            defaultValues.emplace_back(std::move(val));
-        }
-
-        std::optional<internal::DBusMapping> dBusMap = std::nullopt;
-
-        if (entry.count("dbus") != 0)
-        {
-            auto dBusEntry = entry.value("dbus", emptyJson);
-            dBusMap = std::make_optional<internal::DBusMapping>();
-            dBusMap.value().objectPath = dBusEntry.value("object_path", "");
-            dBusMap.value().interface = dBusEntry.value("interface", "");
-            dBusMap.value().propertyName = dBusEntry.value("property_name", "");
-            std::string propType = dBusEntry.value("property_type", "");
-            Json propValues = dBusEntry["property_values"];
-            internal::populateMapping(propType, propValues, possibleValues,
-                                      dBusMap.value());
-        }
-
-        internal::attrLookup.emplace(attr, std::move(dBusMap));
-
-        // Defaulting all the types of attributes to BIOSEnumeration
-        internal::valueMap.emplace(
-            std::move(attr), std::make_tuple(false, std::move(possibleValues),
-                                             std::move(defaultValues)));
+        auto dbusEntry = entry.value("dbus", emptyJson);
+        std::string propertyType = dbusEntry.value("property_type", "");
+        Json propValues = dbusEntry["property_values"];
+        internal::dbusValToValMaps.emplace(
+            attrName, internal::populateMapping(propertyType, propValues,
+                                                possibleValues));
     }
-
-    return rc;
+    // Defaulting all the types of attributes to BIOSEnumeration
+    internal::valueMap.emplace(std::move(attrName),
+                               std::make_tuple(entry.count("dbus") == 0,
+                                               std::move(possibleValues),
+                                               std::move(defaultValues)));
+    return 0;
 }
 
 const AttrValuesMap& getValues()
@@ -255,7 +216,7 @@
 
 CurrentValues getAttrValue(const AttrName& attrName)
 {
-    const auto& dBusMap = internal::attrLookup.at(attrName);
+    const auto& dBusMap = BIOSAttrLookup.at(attrName);
     CurrentValues currentValues;
     internal::PropertyValue propValue;
 
@@ -266,18 +227,19 @@
         return currentValues;
     }
 
+    const auto& dbusValToValMap = internal::dbusValToValMaps.at(attrName);
     auto bus = sdbusplus::bus::new_default();
     auto service = pldm::responder::getService(bus, dBusMap.value().objectPath,
                                                dBusMap.value().interface);
     auto method =
         bus.new_method_call(service.c_str(), dBusMap.value().objectPath.c_str(),
                             "org.freedesktop.DBus.Properties", "Get");
-    method.append(dBusMap.value().interface, dBusMap.value().propertyName);
+    method.append(dBusMap->interface, dBusMap->propertyName);
     auto reply = bus.call(method);
     reply.read(propValue);
 
-    auto iter = dBusMap.value().dBusValToValMap.find(propValue);
-    if (iter != dBusMap.value().dBusValToValMap.end())
+    auto iter = dbusValToValMap.find(propValue);
+    if (iter != dbusValToValMap.end())
     {
         currentValues.push_back(iter->second);
     }
@@ -315,118 +277,56 @@
 namespace internal
 {
 
-/** @struct DBusMapping
- *
- *  Data structure for storing information regarding BIOS string attribute
- *  and the D-Bus object for the attribute.
- */
-struct DBusMapping
-{
-    std::string objectPath;   //!< D-Bus object path
-    std::string interface;    //!< D-Bus interface
-    std::string propertyName; //!< D-Bus property name
-};
-
 /** @brief Map containing the possible and the default values for the BIOS
  *         string type attributes.
  */
 AttrValuesMap valueMap;
 
-/** @brief Map containing the optional D-Bus property information about the
- *         BIOS string type attributes.
- */
-std::map<AttrName, std::optional<DBusMapping>> attrLookup;
-
 } // namespace internal
 
-int setupValueLookup(const char* dirPath)
+int setup(const Json& entry)
 {
-    int rc = 0;
 
-    if (!internal::valueMap.empty() && !internal::attrLookup.empty())
+    std::string attr = entry.value("attribute_name", "");
+    // Transfer string type from string to enum
+    std::string strTypeTmp = entry.value("string_type", "Unknown");
+    auto iter = strTypeMap.find(strTypeTmp);
+    if (iter == strTypeMap.end())
     {
-        return rc;
+        log<level::ERR>(
+            "Wrong string type",
+            phosphor::logging::entry("STRING_TYPE=%s", strTypeTmp.c_str()),
+            phosphor::logging::entry("ATTRIBUTE_NAME=%s", attr.c_str()));
+        return -1;
+    }
+    uint8_t strType = iter->second;
+
+    uint16_t minStrLen = entry.value("minimum_string_length", 0);
+    uint16_t maxStrLen = entry.value("maximum_string_length", 0);
+    if (maxStrLen - minStrLen < 0)
+    {
+        log<level::ERR>(
+            "Maximum string length is smaller than minimum string length",
+            phosphor::logging::entry("ATTRIBUTE_NAME=%s", attr.c_str()));
+        return -1;
+    }
+    uint16_t defaultStrLen = entry.value("default_string_length", 0);
+    std::string defaultStr = entry.value("default_string", "");
+    if ((defaultStrLen == 0) && (defaultStr.size() > 0))
+    {
+        log<level::ERR>(
+            "Default string length is 0, but default string is existing",
+            phosphor::logging::entry("ATTRIBUTE_NAME=%s", attr.c_str()));
+        return -1;
     }
 
-    Json fileData;
-    rc = parseBiosJsonFile(dirPath, bIOSStrJson, fileData);
-    if (rc != 0)
-    {
-        return rc;
-    }
+    // Defaulting all the types of attributes to BIOSString
+    internal::valueMap.emplace(
+        std::move(attr),
+        std::make_tuple(entry.count("dbus") == 0, strType, minStrLen, maxStrLen,
+                        defaultStrLen, std::move(defaultStr)));
 
-    auto entries = fileData.value("entries", emptyJsonList);
-    // Iterate through each JSON object in the config file
-    for (const auto& entry : entries)
-    {
-        std::string attr = entry.value("attribute_name", "");
-        // Transfer string type from string to enum
-        std::string strTypeTmp = entry.value("string_type", "Unknown");
-        auto iter = strTypeMap.find(strTypeTmp);
-        if (iter == strTypeMap.end())
-        {
-            log<level::ERR>(
-                "Wrong string type",
-                phosphor::logging::entry("STRING_TYPE=%s", strTypeTmp.c_str()),
-                phosphor::logging::entry("ATTRIBUTE_NAME=%s", attr.c_str()));
-            return -1;
-        }
-        uint8_t strType = iter->second;
-
-        uint16_t minStrLen = entry.value("minimum_string_length", 0);
-        uint16_t maxStrLen = entry.value("maximum_string_length", 0);
-        if (maxStrLen - minStrLen < 0)
-        {
-            log<level::ERR>(
-                "Maximum string length is smaller than minimum string length",
-                phosphor::logging::entry("ATTRIBUTE_NAME=%s", attr.c_str()));
-            return -1;
-        }
-        uint16_t defaultStrLen = entry.value("default_string_length", 0);
-        std::string defaultStr = entry.value("default_string", "");
-        if ((defaultStrLen == 0) && (defaultStr.size() > 0))
-        {
-            log<level::ERR>(
-                "Default string length is 0, but default string is existing",
-                phosphor::logging::entry("ATTRIBUTE_NAME=%s", attr.c_str()));
-            return -1;
-        }
-
-        // dbus handling
-        std::optional<internal::DBusMapping> dBusMap;
-
-        if (entry.count("dbus") != 0)
-        {
-            auto dBusEntry = entry.value("dbus", emptyJson);
-            dBusMap = std::make_optional<internal::DBusMapping>();
-            dBusMap->objectPath = dBusEntry.value("object_path", "");
-            dBusMap->interface = dBusEntry.value("interface", "");
-            dBusMap->propertyName = dBusEntry.value("property_name", "");
-            if (dBusMap->objectPath.empty() || dBusMap->interface.empty() ||
-                dBusMap->propertyName.empty())
-            {
-                log<level::ERR>(
-                    "Invalid dbus config",
-                    phosphor::logging::entry("OBJPATH=%s",
-                                             dBusMap->objectPath.c_str()),
-                    phosphor::logging::entry("INTERFACE=%s",
-                                             dBusMap->interface.c_str()),
-                    phosphor::logging::entry("PROPERTY_NAME=%s",
-                                             dBusMap->propertyName.c_str()));
-                return -1;
-            }
-        }
-
-        internal::attrLookup.emplace(attr, std::move(dBusMap));
-
-        // Defaulting all the types of attributes to BIOSString
-        internal::valueMap.emplace(
-            std::move(attr),
-            std::make_tuple(entry.count("dbus") == 0, strType, minStrLen,
-                            maxStrLen, defaultStrLen, std::move(defaultStr)));
-    }
-
-    return rc;
+    return 0;
 }
 
 const AttrValuesMap& getValues()
@@ -436,7 +336,7 @@
 
 std::string getAttrValue(const AttrName& attrName)
 {
-    const auto& dBusMap = internal::attrLookup.at(attrName);
+    const auto& dBusMap = BIOSAttrLookup.at(attrName);
     std::variant<std::string> propValue;
 
     if (dBusMap == std::nullopt)
@@ -460,53 +360,105 @@
 
 } // namespace bios_string
 
-Strings getStrings(const char* dirPath)
-{
-    Strings biosStrings{};
-    fs::path dir(dirPath);
+const std::map<BIOSJsonName, BIOSStringHandler> BIOSStringHandlers = {
+    {bIOSEnumJson, bios_enum::setupBIOSStrings},
+};
 
+const std::map<BIOSJsonName, typeHandler> BIOSTypeHandlers = {
+    {bIOSEnumJson, bios_enum::setup},
+    {bIOSStrJson, bios_string::setup},
+};
+
+void setupBIOSStrings(const BIOSJsonName& jsonName, const Json& entry,
+                      Strings& strings)
+{
+    strings.emplace_back(entry.value("attribute_name", ""));
+    auto iter = BIOSStringHandlers.find(jsonName);
+    if (iter != BIOSStringHandlers.end())
+    {
+        iter->second(entry, strings);
+    }
+}
+
+void setupBIOSAttrLookup(const Json& entry, AttrLookup& lookup)
+{
+    std::optional<DBusMapping> dBusMap;
+    std::string attrName = entry.value("attribute_name", "");
+
+    if (entry.count("dbus") != 0)
+    {
+        auto dBusEntry = entry.value("dbus", emptyJson);
+        std::string objectPath = dBusEntry.value("object_path", "");
+        std::string interface = dBusEntry.value("interface", "");
+        std::string propertyName = dBusEntry.value("property_name", "");
+        if (!objectPath.empty() && !interface.empty() && !propertyName.empty())
+        {
+            dBusMap = std::optional<DBusMapping>(
+                {objectPath, interface, propertyName});
+        }
+        else
+        {
+            log<level::ERR>(
+                "Invalid dbus config",
+                phosphor::logging::entry("OBJPATH=%s",
+                                         dBusMap->objectPath.c_str()),
+                phosphor::logging::entry("INTERFACE=%s",
+                                         dBusMap->interface.c_str()),
+                phosphor::logging::entry("PROPERTY_NAME=%s",
+                                         dBusMap->propertyName.c_str()));
+        }
+    }
+    lookup.emplace(attrName, dBusMap);
+}
+
+int setupBIOSType(const BIOSJsonName& jsonName, const Json& entry)
+{
+    auto iter = BIOSTypeHandlers.find(jsonName);
+    if (iter != BIOSTypeHandlers.end())
+    {
+        iter->second(entry);
+    }
+    return 0;
+}
+
+const std::vector<BIOSJsonName> BIOSConfigFiles = {bIOSEnumJson, bIOSStrJson};
+
+int setupConfig(const char* dirPath)
+{
+    if (!BIOSStrings.empty() && !BIOSAttrLookup.empty())
+    {
+        return 0;
+    }
+
+    fs::path dir(dirPath);
     if (!fs::exists(dir) || fs::is_empty(dir))
     {
-        return biosStrings;
+        log<level::ERR>("BIOS config directory does not exist or empty",
+                        entry("DIR=%s", dirPath));
+        return -1;
     }
-
-    for (const auto& file : fs::directory_iterator(dir))
+    for (auto jsonName : BIOSConfigFiles)
     {
-        std::ifstream jsonFile(file.path().c_str());
-        if (!jsonFile.is_open())
+        Json json;
+        if (parseBiosJsonFile(dir, jsonName, json) < 0)
         {
-            log<level::ERR>("JSON BIOS config file does not exist",
-                            entry("FILE=%s", file.path().filename().c_str()));
             continue;
         }
-
-        auto fileData = Json::parse(jsonFile, nullptr, false);
-        if (fileData.is_discarded())
-        {
-            log<level::ERR>("Parsing config file failed",
-                            entry("FILE=%s", file.path().filename().c_str()));
-            continue;
-        }
-
-        auto entries = fileData.value("entries", emptyJsonList);
-
-        // Iterate through each entry in the config file
+        auto entries = json.value("entries", emptyJsonList);
         for (auto& entry : entries)
         {
-            biosStrings.emplace_back(entry.value("attribute_name", ""));
-
-            // For BIOS enumeration attributes the possible values are strings
-            if (file.path().filename() == bIOSEnumJson)
-            {
-                auto possibleValues = bios_enum::internal::readPossibleValues(
-                    entry["possible_values"]);
-                std::move(possibleValues.begin(), possibleValues.end(),
-                          std::back_inserter(biosStrings));
-            }
+            setupBIOSStrings(jsonName, entry, BIOSStrings);
+            setupBIOSAttrLookup(entry, BIOSAttrLookup);
+            setupBIOSType(jsonName, entry);
         }
     }
-
-    return biosStrings;
+    if (BIOSStrings.empty())
+    { // means there is no attribute
+        log<level::ERR>("No attribute is found in the config directory",
+                        entry("DIR=%s", dirPath));
+        return -1;
+    }
+    return 0;
 }
 
 } // namespace bios_parser
diff --git a/libpldmresponder/bios_parser.hpp b/libpldmresponder/bios_parser.hpp
index e922b09..bc92e3c 100644
--- a/libpldmresponder/bios_parser.hpp
+++ b/libpldmresponder/bios_parser.hpp
@@ -13,10 +13,9 @@
  *    strings used in representing the values of the attributes. This will be
  *    used to populate the BIOS String table.
  *
- * 2) bios_enum::setupValueLookup (similar API for other supported BIOS
- *    attribute types) has to be invoked to setup the lookup data structure for
- *    all the attributes of that type. This API needs to be invoked before
- *    invoking bios_enum::getValues and bios_enum::getAttrValue.
+ * 2) bios_parser::setupConfig has to be invoked to setup the lookup data
+ *    structure all the attributes of that type. This API needs to be invoked
+ *    before invoking bios_enum::getValues and bios_enum::getAttrValue.
  *
  * 3) bios_enum::getValues is invoked to populate the BIOS attribute table for
  *    BIOSEnumeration and BIOSEnumerationReadonly types.(similar API for other
@@ -35,33 +34,19 @@
 inline constexpr auto bIOSEnumJson = "enum_attrs.json";
 inline constexpr auto bIOSStrJson = "string_attrs.json";
 
-/** @brief Parse every BIOS configuration JSON files in the directory path
- *         and populate all the attribute names and all the preconfigured
- *         strings used in representing the values of attributes.
- *
- *  @param[in] dirPath - directory path where all the BIOS configuration JSON
- *                      files exist.
- *
- *  @return all the strings that should be populated in the BIOS string table
+/** @brief Get all the preconfigured strings
+ *  @return all the preconfigurated strings
  */
-Strings getStrings(const char* dirPath);
+const Strings& getStrings();
+/** @brief Parse every BIOS Configuration JSON file in the directory path
+ *  @param[in] dirPath - directory path where all the bios configuration JSON
+ * files exist
+ */
+int setupConfig(const char* dirPath);
 
 namespace bios_enum
 {
 
-/** @brief Parse the JSON file specific to BIOSEnumeration and
- *         BIOSEnumerationReadOnly types and populate the data structure for
- *         the corresponding possible values and the default value. Setup the
- *         data structure to lookup the current value of the BIOS enumeration
- *         attribute. JSON is parsed once and the information is cached.
- *
- *  @param[in] dirPath - directory path where all the BIOS configuration JSON
- *                      exist
- *
- *  @return 0 for success and negative return code for failure
- */
-int setupValueLookup(const char* dirPath);
-
 using AttrName = std::string;
 using IsReadOnly = bool;
 using PossibleValues = std::vector<std::string>;
@@ -92,19 +77,6 @@
 namespace bios_string
 {
 
-/** @brief Parse the JSON file specific to BIOSString and
- *         BIOSStringReadOnly types and populate the data structure for
- *         the corresponding possible values and the default value. Setup the
- *         data structure to lookup the current value of the BIOS string
- *         attribute. JSON is parsed once and the information is cached.
- *
- *  @param[in] dirPath - directory path where all the BIOS configuration JSON
- *                      exist
- *
- *  @return 0 for success and negative return code for failure
- */
-int setupValueLookup(const char* dirPath);
-
 using AttrName = std::string;
 using IsReadOnly = bool;
 using StrType = uint8_t;
diff --git a/test/libpldmresponder_bios_test.cpp b/test/libpldmresponder_bios_test.cpp
index 1df46cc..f667142 100644
--- a/test/libpldmresponder_bios_test.cpp
+++ b/test/libpldmresponder_bios_test.cpp
@@ -65,10 +65,12 @@
     Strings nullVec{};
 
     // Invalid directory
-    auto strings = bios_parser::getStrings("./bios_json");
+    bios_parser::setupConfig("./bios_json_invalid");
+    auto strings = bios_parser::getStrings();
     ASSERT_EQ(strings == nullVec, true);
 
-    strings = bios_parser::getStrings("./bios_jsons");
+    bios_parser::setupConfig("./bios_jsons");
+    strings = bios_parser::getStrings();
     std::sort(strings.begin(), strings.end());
     std::sort(vec.begin(), vec.end());
     ASSERT_EQ(strings == vec, true);
@@ -82,10 +84,7 @@
         {"FWBootSide", {false, {"Perm", "Temp"}, {"Perm"}}},
         {"InbandCodeUpdate", {false, {"Allowed", "NotAllowed"}, {"Allowed"}}},
         {"CodeUpdatePolicy",
-         {false, {"Concurrent", "Disruptive"}, {"Concurrent"}}}};
-
-    auto rc = bios_parser::bios_enum::setupValueLookup("./bios_jsons");
-    ASSERT_EQ(rc, 0);
+         {true, {"Concurrent", "Disruptive"}, {"Concurrent"}}}};
 
     auto values = bios_parser::bios_enum::getValues();
     ASSERT_EQ(valueMap == values, true);
@@ -107,9 +106,6 @@
         {"str_example2", {false, 2, 0, 100, 0, ""}},
         {"str_example3", {true, 0, 1, 100, 2, "ef"}}};
 
-    auto rc = bios_parser::bios_string::setupValueLookup("./bios_jsons");
-    EXPECT_EQ(rc, 0);
-
     auto values = bios_parser::bios_string::getValues();
     ASSERT_EQ(valueMap == values, true);
 
@@ -260,7 +256,7 @@
     req->transfer_op_flag = PLDM_GET_FIRSTPART;
     req->table_type = PLDM_BIOS_STRING_TABLE;
 
-    Strings biosStrings = getStrings("./bios_jsons");
+    Strings biosStrings = getStrings();
     std::sort(biosStrings.begin(), biosStrings.end());
     biosStrings.erase(std::unique(biosStrings.begin(), biosStrings.end()),
                       biosStrings.end());
@@ -347,7 +343,7 @@
             attrHdl = ptr->attr_handle;
             attrType = ptr->attr_type;
             EXPECT_EQ(0, attrHdl);
-            EXPECT_EQ(PLDM_BIOS_ENUMERATION, attrType);
+            EXPECT_EQ(PLDM_BIOS_ENUMERATION_READ_ONLY, attrType);
             stringHdl = ptr->string_handle;
             EXPECT_EQ(stringHdl, 1);
             tableData += sizeof(attrHdl) + sizeof(attrType) + sizeof(stringHdl);
@@ -439,7 +435,7 @@
             attrHdl = ptr->attr_handle;
             attrType = ptr->attr_type;
             EXPECT_EQ(0, attrHdl);
-            EXPECT_EQ(PLDM_BIOS_ENUMERATION, attrType);
+            EXPECT_EQ(PLDM_BIOS_ENUMERATION_READ_ONLY, attrType);
             tableData += sizeof(attrHdl) + sizeof(attrType);
             traversed += sizeof(attrHdl) + sizeof(attrType);
             numCurrVals = *tableData;