Instantiation of handler class

The commit adds implementation of handler class.
Mostly, oem specific implementation has been moved from manager class
to handler class.

Change-Id: Ie2a4ed3f2265b77c260c190809b18b465a81b2f9
Signed-off-by: Sunny Srivastava <sunnsr25@in.ibm.com>
diff --git a/vpd-manager/include/manager.hpp b/vpd-manager/include/manager.hpp
index 94c5693..9de9675 100644
--- a/vpd-manager/include/manager.hpp
+++ b/vpd-manager/include/manager.hpp
@@ -6,6 +6,7 @@
 #include "types.hpp"
 #include "worker.hpp"
 
+#include <oem-handler/ibm_handler.hpp>
 #include <sdbusplus/asio/object_server.hpp>
 
 namespace vpd
@@ -219,71 +220,6 @@
         const std::string& i_expandedLocationCode);
 
   private:
-#ifdef IBM_SYSTEM
-    /**
-     * @brief API to set timer to detect system VPD over D-Bus.
-     *
-     * System VPD is required before bus name for VPD-Manager is claimed. Once
-     * system VPD is published, VPD for other FRUs should be collected. This API
-     * detects id system VPD is already published on D-Bus and based on that
-     * triggers VPD collection for rest of the FRUs.
-     *
-     * Note: Throws exception in case of any failure. Needs to be handled by the
-     * caller.
-     */
-    void SetTimerToDetectSVPDOnDbus();
-
-    /**
-     * @brief Set timer to detect and set VPD collection status for the system.
-     *
-     * Collection of FRU VPD is triggered in a separate thread. Resulting in
-     * multiple threads at  a given time. The API creates a timer which on
-     * regular interval will check if all the threads were collected back and
-     * sets the status of the VPD collection for the system accordingly.
-     *
-     * @throw std::runtime_error
-     */
-    void SetTimerToDetectVpdCollectionStatus();
-
-    /**
-     * @brief API to register callback for "AssetTag" property change.
-     */
-    void registerAssetTagChangeCallback();
-
-    /**
-     * @brief Callback API to be triggered on "AssetTag" property change.
-     *
-     * @param[in] i_msg - The callback message.
-     */
-    void processAssetTagChangeCallback(sdbusplus::message_t& i_msg);
-
-    /**
-     * @brief API to process VPD collection thread failed EEPROMs.
-     */
-    void processFailedEeproms();
-
-    /**
-     * @brief API to check and update PowerVS VPD.
-     *
-     * The API will read the existing data from the DBus and if found
-     * different than what has been read from JSON, it will update the VPD with
-     * JSON data on hardware and DBus both.
-     *
-     * @param[in] i_powerVsJsonObj - PowerVS JSON object.
-     * @param[out] o_failedPathList - List of path failed to update.
-     */
-    void checkAndUpdatePowerVsVpd(const nlohmann::json& i_powerVsJsonObj,
-                                  std::vector<std::string>& o_failedPathList);
-
-    /**
-     * @brief API to handle configuration w.r.t. PowerVS systems.
-     *
-     * Some FRUs VPD is specific to powerVS system. The API detects the
-     * powerVS configuration and updates the VPD accordingly.
-     */
-    void ConfigurePowerVsSystem();
-#endif
-
     /**
      * @brief An api to check validity of unexpanded location code.
      *
@@ -325,6 +261,9 @@
 
     // Shared pointer to backup and restore class
     std::shared_ptr<BackupAndRestore> m_backupAndRestoreObj;
+
+    // Shared pointer to oem specific class.
+    std::shared_ptr<IbmHandler> m_ibmHandler;
 };
 
 } // namespace vpd
diff --git a/vpd-manager/oem-handler/ibm_handler.cpp b/vpd-manager/oem-handler/ibm_handler.cpp
index 14ef090..665a7af 100644
--- a/vpd-manager/oem-handler/ibm_handler.cpp
+++ b/vpd-manager/oem-handler/ibm_handler.cpp
@@ -1,6 +1,436 @@
+#include "config.h"
+
 #include "ibm_handler.hpp"
 
+#include "parser.hpp"
+
+#include <utility/dbus_utility.hpp>
+#include <utility/json_utility.hpp>
+#include <utility/vpd_specific_utility.hpp>
+
 namespace vpd
 {
-// TODO: add implementation
+IbmHandler::IbmHandler(
+    std::shared_ptr<Worker>& o_worker,
+    std::shared_ptr<BackupAndRestore>& o_backupAndRestoreObj,
+    const std::shared_ptr<sdbusplus::asio::dbus_interface>& i_iFace,
+    const std::shared_ptr<boost::asio::io_context>& i_ioCon,
+    const std::shared_ptr<sdbusplus::asio::connection>& i_asioConnection) :
+    m_worker(o_worker), m_backupAndRestoreObj(o_backupAndRestoreObj),
+    m_interface(i_iFace), m_ioContext(i_ioCon),
+    m_asioConnection(i_asioConnection)
+{
+    if (dbusUtility::isChassisPowerOn())
+    {
+        // At power on, less number of FRU(s) needs collection. we can scale
+        // down the threads to reduce CPU utilization.
+        m_worker = std::make_shared<Worker>(INVENTORY_JSON_DEFAULT,
+                                            constants::VALUE_1);
+    }
+    else
+    {
+        // Initialize with default configuration
+        m_worker = std::make_shared<Worker>(INVENTORY_JSON_DEFAULT);
+    }
+
+    // Set up minimal things that is needed before bus name is claimed.
+    m_worker->performInitialSetup();
+
+    // Get the system config JSON object
+    m_sysCfgJsonObj = m_worker->getSysCfgJsonObj();
+
+    if (!m_sysCfgJsonObj.empty() &&
+        jsonUtility::isBackupAndRestoreRequired(m_sysCfgJsonObj))
+    {
+        try
+        {
+            m_backupAndRestoreObj =
+                std::make_shared<BackupAndRestore>(m_sysCfgJsonObj);
+        }
+        catch (const std::exception& l_ex)
+        {
+            logging::logMessage("Back up and restore instantiation failed. {" +
+                                std::string(l_ex.what()) + "}");
+
+            EventLogger::createSyncPel(
+                EventLogger::getErrorType(l_ex), types::SeverityType::Warning,
+                __FILE__, __FUNCTION__, 0, EventLogger::getErrorMsg(l_ex),
+                std::nullopt, std::nullopt, std::nullopt, std::nullopt);
+        }
+    }
+
+    // set callback to detect any asset tag change
+    registerAssetTagChangeCallback();
+
+    // set async timer to detect if system VPD is published on D-Bus.
+    SetTimerToDetectSVPDOnDbus();
+
+    // set async timer to detect if VPD collection is done.
+    SetTimerToDetectVpdCollectionStatus();
+
+    // Instantiate GpioMonitor class
+    m_gpioMonitor =
+        std::make_shared<GpioMonitor>(m_sysCfgJsonObj, m_worker, m_ioContext);
+}
+
+void IbmHandler::registerAssetTagChangeCallback()
+{
+    static std::shared_ptr<sdbusplus::bus::match_t> l_assetMatch =
+        std::make_shared<sdbusplus::bus::match_t>(
+            *m_asioConnection,
+            sdbusplus::bus::match::rules::propertiesChanged(
+                constants::systemInvPath, constants::assetTagInf),
+            [this](sdbusplus::message_t& l_msg) {
+                processAssetTagChangeCallback(l_msg);
+            });
+}
+
+void IbmHandler::processAssetTagChangeCallback(sdbusplus::message_t& i_msg)
+{
+    try
+    {
+        if (i_msg.is_method_error())
+        {
+            throw std::runtime_error(
+                "Error reading callback msg for asset tag.");
+        }
+
+        std::string l_objectPath;
+        types::PropertyMap l_propMap;
+        i_msg.read(l_objectPath, l_propMap);
+
+        const auto& l_itrToAssetTag = l_propMap.find("AssetTag");
+        if (l_itrToAssetTag != l_propMap.end())
+        {
+            if (auto l_assetTag =
+                    std::get_if<std::string>(&(l_itrToAssetTag->second)))
+            {
+                // Call Notify to persist the AssetTag
+                types::ObjectMap l_objectMap = {
+                    {sdbusplus::message::object_path(constants::systemInvPath),
+                     {{constants::assetTagInf, {{"AssetTag", *l_assetTag}}}}}};
+
+                // Notify PIM
+                if (!dbusUtility::callPIM(move(l_objectMap)))
+                {
+                    throw std::runtime_error(
+                        "Call to PIM failed for asset tag update.");
+                }
+            }
+        }
+        else
+        {
+            throw std::runtime_error(
+                "Could not find asset tag in callback message.");
+        }
+    }
+    catch (const std::exception& l_ex)
+    {
+        // TODO: Log PEL with below description.
+        logging::logMessage("Asset tag callback update failed with error: " +
+                            std::string(l_ex.what()));
+    }
+}
+
+void IbmHandler::SetTimerToDetectSVPDOnDbus()
+{
+    try
+    {
+        static boost::asio::steady_timer timer(*m_ioContext);
+
+        // timer for 2 seconds
+        auto asyncCancelled = timer.expires_after(std::chrono::seconds(2));
+
+        (asyncCancelled == 0) ? logging::logMessage("Timer started")
+                              : logging::logMessage("Timer re-started");
+
+        timer.async_wait([this](const boost::system::error_code& ec) {
+            if (ec == boost::asio::error::operation_aborted)
+            {
+                throw std::runtime_error(
+                    std::string(__FUNCTION__) +
+                    ": Timer to detect system VPD collection status was aborted.");
+            }
+
+            if (ec)
+            {
+                throw std::runtime_error(
+                    std::string(__FUNCTION__) +
+                    ": Timer to detect System VPD collection failed");
+            }
+
+            if (m_worker->isSystemVPDOnDBus())
+            {
+                // cancel the timer
+                timer.cancel();
+
+                // Triggering FRU VPD collection. Setting status to "In
+                // Progress".
+                m_interface->set_property("CollectionStatus",
+                                          std::string("InProgress"));
+                m_worker->collectFrusFromJson();
+            }
+        });
+    }
+    catch (const std::exception& l_ex)
+    {
+        EventLogger::createAsyncPel(
+            EventLogger::getErrorType(l_ex), types::SeverityType::Critical,
+            __FILE__, __FUNCTION__, 0,
+            std::string("Collection for FRUs failed with reason:") +
+                EventLogger::getErrorMsg(l_ex),
+            std::nullopt, std::nullopt, std::nullopt, std::nullopt);
+    }
+}
+
+void IbmHandler::SetTimerToDetectVpdCollectionStatus()
+{
+    // Keeping max retry for 2 minutes. TODO: Make it configurable based on
+    // system type.
+    static constexpr auto MAX_RETRY = 12;
+
+    static boost::asio::steady_timer l_timer(*m_ioContext);
+    static uint8_t l_timerRetry = 0;
+
+    auto l_asyncCancelled = l_timer.expires_after(std::chrono::seconds(10));
+
+    (l_asyncCancelled == 0)
+        ? logging::logMessage("Collection Timer started")
+        : logging::logMessage("Collection Timer re-started");
+
+    l_timer.async_wait([this](const boost::system::error_code& ec) {
+        if (ec == boost::asio::error::operation_aborted)
+        {
+            throw std::runtime_error(
+                "Timer to detect thread collection status was aborted");
+        }
+
+        if (ec)
+        {
+            throw std::runtime_error(
+                "Timer to detect thread collection failed");
+        }
+
+        if (m_worker->isAllFruCollectionDone())
+        {
+            // cancel the timer
+            l_timer.cancel();
+            processFailedEeproms();
+
+            // update VPD for powerVS system.
+            ConfigurePowerVsSystem();
+
+            std::cout << "m_worker->isSystemVPDOnDBus() completed" << std::endl;
+            m_interface->set_property("CollectionStatus",
+                                      std::string("Completed"));
+
+            if (m_backupAndRestoreObj)
+            {
+                m_backupAndRestoreObj->backupAndRestore();
+            }
+        }
+        else
+        {
+            auto l_threadCount = m_worker->getActiveThreadCount();
+            if (l_timerRetry == MAX_RETRY)
+            {
+                l_timer.cancel();
+                logging::logMessage("Taking too long. Active thread = " +
+                                    std::to_string(l_threadCount));
+            }
+            else
+            {
+                l_timerRetry++;
+                logging::logMessage("Collection is in progress for [" +
+                                    std::to_string(l_threadCount) + "] FRUs.");
+
+                SetTimerToDetectVpdCollectionStatus();
+            }
+        }
+    });
+}
+
+void IbmHandler::checkAndUpdatePowerVsVpd(
+    const nlohmann::json& i_powerVsJsonObj,
+    std::vector<std::string>& o_failedPathList)
+{
+    for (const auto& [l_fruPath, l_recJson] : i_powerVsJsonObj.items())
+    {
+        nlohmann::json l_sysCfgJsonObj{};
+        if (m_worker.get() != nullptr)
+        {
+            l_sysCfgJsonObj = m_worker->getSysCfgJsonObj();
+        }
+
+        // The utility method will handle emty JSON case. No explicit
+        // handling required here.
+        auto l_inventoryPath = jsonUtility::getInventoryObjPathFromJson(
+            l_sysCfgJsonObj, l_fruPath);
+
+        // Mark it as failed if inventory path not found in JSON.
+        if (l_inventoryPath.empty())
+        {
+            o_failedPathList.push_back(l_fruPath);
+            continue;
+        }
+
+        // check if the FRU is present
+        if (!dbusUtility::isInventoryPresent(l_inventoryPath))
+        {
+            logging::logMessage(
+                "Inventory not present, skip updating part number. Path: " +
+                l_inventoryPath);
+            continue;
+        }
+
+        // check if the FRU needs CCIN check before updating PN.
+        if (l_recJson.contains("CCIN"))
+        {
+            const auto& l_ccinFromDbus =
+                vpdSpecificUtility::getCcinFromDbus(l_inventoryPath);
+
+            // Not an ideal situation as CCIN can't be empty.
+            if (l_ccinFromDbus.empty())
+            {
+                o_failedPathList.push_back(l_fruPath);
+                continue;
+            }
+
+            std::vector<std::string> l_ccinListFromJson = l_recJson["CCIN"];
+
+            if (find(l_ccinListFromJson.begin(), l_ccinListFromJson.end(),
+                     l_ccinFromDbus) == l_ccinListFromJson.end())
+            {
+                // Don't update PN in this case.
+                continue;
+            }
+        }
+
+        for (const auto& [l_recordName, l_kwdJson] : l_recJson.items())
+        {
+            // Record name can't be CCIN, skip processing as it is there for PN
+            // update based on CCIN check.
+            if (l_recordName == constants::kwdCCIN)
+            {
+                continue;
+            }
+
+            for (const auto& [l_kwdName, l_kwdValue] : l_kwdJson.items())
+            {
+                // Is value of type array.
+                if (!l_kwdValue.is_array())
+                {
+                    o_failedPathList.push_back(l_fruPath);
+                    continue;
+                }
+
+                // Get current FRU Part number.
+                auto l_retVal = dbusUtility::readDbusProperty(
+                    constants::pimServiceName, l_inventoryPath,
+                    constants::viniInf, constants::kwdFN);
+
+                auto l_ptrToFn = std::get_if<types::BinaryVector>(&l_retVal);
+
+                if (!l_ptrToFn)
+                {
+                    o_failedPathList.push_back(l_fruPath);
+                    continue;
+                }
+
+                types::BinaryVector l_binaryKwdValue =
+                    l_kwdValue.get<types::BinaryVector>();
+                if (l_binaryKwdValue == (*l_ptrToFn))
+                {
+                    continue;
+                }
+
+                // Update part number only if required.
+                std::shared_ptr<Parser> l_parserObj =
+                    std::make_shared<Parser>(l_fruPath, l_sysCfgJsonObj);
+                if (l_parserObj->updateVpdKeyword(std::make_tuple(
+                        l_recordName, l_kwdName, l_binaryKwdValue)) ==
+                    constants::FAILURE)
+                {
+                    o_failedPathList.push_back(l_fruPath);
+                    continue;
+                }
+
+                // update the Asset interface Spare part number explicitly.
+                if (!dbusUtility::callPIM(types::ObjectMap{
+                        {l_inventoryPath,
+                         {{constants::assetInf,
+                           {{"SparePartNumber",
+                             std::string(l_binaryKwdValue.begin(),
+                                         l_binaryKwdValue.end())}}}}}}))
+                {
+                    logging::logMessage(
+                        "Updating Spare Part Number under Asset interface failed for path [" +
+                        l_inventoryPath + "]");
+                }
+
+                // Just needed for logging.
+                std::string l_initialPartNum((*l_ptrToFn).begin(),
+                                             (*l_ptrToFn).end());
+                std::string l_finalPartNum(l_binaryKwdValue.begin(),
+                                           l_binaryKwdValue.end());
+                logging::logMessage(
+                    "FRU Part number updated for path [" + l_inventoryPath +
+                    "]" + "From [" + l_initialPartNum + "]" + " to [" +
+                    l_finalPartNum + "]");
+            }
+        }
+    }
+}
+
+void IbmHandler::ConfigurePowerVsSystem()
+{
+    std::vector<std::string> l_failedPathList;
+    try
+    {
+        types::BinaryVector l_imValue = dbusUtility::getImFromDbus();
+        if (l_imValue.empty())
+        {
+            throw DbusException("Invalid IM value read from Dbus");
+        }
+
+        if (!vpdSpecificUtility::isPowerVsConfiguration(l_imValue))
+        {
+            // TODO: Should booting be blocked in case of some
+            // misconfigurations?
+            return;
+        }
+
+        const nlohmann::json& l_powerVsJsonObj =
+            jsonUtility::getPowerVsJson(l_imValue);
+
+        if (l_powerVsJsonObj.empty())
+        {
+            throw std::runtime_error("PowerVS Json not found");
+        }
+
+        checkAndUpdatePowerVsVpd(l_powerVsJsonObj, l_failedPathList);
+
+        if (!l_failedPathList.empty())
+        {
+            throw std::runtime_error(
+                "Part number update failed for following paths: ");
+        }
+    }
+    catch (const std::exception& l_ex)
+    {
+        // TODO log appropriate PEL
+    }
+}
+
+void IbmHandler::processFailedEeproms()
+{
+    if (m_worker.get() != nullptr)
+    {
+        // TODO:
+        // - iterate through list of EEPROMs for which thread creation has
+        // failed
+        // - For each failed EEPROM, trigger VPD collection
+        m_worker->getFailedEepromPaths().clear();
+    }
+}
 } // namespace vpd
diff --git a/vpd-manager/oem-handler/ibm_handler.hpp b/vpd-manager/oem-handler/ibm_handler.hpp
index c94b700..35b905e 100644
--- a/vpd-manager/oem-handler/ibm_handler.hpp
+++ b/vpd-manager/oem-handler/ibm_handler.hpp
@@ -1,9 +1,17 @@
 #pragma once
 
+#include "backup_restore.hpp"
+#include "gpio_monitor.hpp"
+#include "worker.hpp"
+
+#include <sdbusplus/asio/object_server.hpp>
+
+#include <memory>
+
 namespace vpd
 {
 /**
- * @brief Class to handle specific use case.
+ * @brief Class to handle OEM specific use case.
  *
  * Few pre-requisites needs to be taken case specifically, which will be
  * encapsulated by this class.
@@ -20,7 +28,103 @@
 
     /**
      * @brief Constructor.
+     *
+     * @param[in] o_worker - Reference to worker class object.
+     * @param[in] o_backupAndRestoreObj - Ref to back up and restore class
+     * object.
+     * @param[in] i_iFace - interface to implement.
+     * @param[in] i_ioCon - IO context.
+     * @param[in] i_asioConnection - Dbus Connection.
      */
-    IbmHandler() {}
+    IbmHandler(
+        std::shared_ptr<Worker>& o_worker,
+        std::shared_ptr<BackupAndRestore>& o_backupAndRestoreObj,
+        const std::shared_ptr<sdbusplus::asio::dbus_interface>& i_iFace,
+        const std::shared_ptr<boost::asio::io_context>& i_ioCon,
+        const std::shared_ptr<sdbusplus::asio::connection>& i_asioConnection);
+
+  private:
+    /**
+     * @brief API to set timer to detect system VPD over D-Bus.
+     *
+     * System VPD is required before bus name for VPD-Manager is claimed. Once
+     * system VPD is published, VPD for other FRUs should be collected. This API
+     * detects id system VPD is already published on D-Bus and based on that
+     * triggers VPD collection for rest of the FRUs.
+     *
+     * Note: Throws exception in case of any failure. Needs to be handled by the
+     * caller.
+     */
+    void SetTimerToDetectSVPDOnDbus();
+
+    /**
+     * @brief Set timer to detect and set VPD collection status for the system.
+     *
+     * Collection of FRU VPD is triggered in a separate thread. Resulting in
+     * multiple threads at  a given time. The API creates a timer which on
+     * regular interval will check if all the threads were collected back and
+     * sets the status of the VPD collection for the system accordingly.
+     *
+     * @throw std::runtime_error
+     */
+    void SetTimerToDetectVpdCollectionStatus();
+
+    /**
+     * @brief API to register callback for "AssetTag" property change.
+     */
+    void registerAssetTagChangeCallback();
+
+    /**
+     * @brief Callback API to be triggered on "AssetTag" property change.
+     *
+     * @param[in] i_msg - The callback message.
+     */
+    void processAssetTagChangeCallback(sdbusplus::message_t& i_msg);
+
+    /**
+     * @brief API to process VPD collection thread failed EEPROMs.
+     */
+    void processFailedEeproms();
+
+    /**
+     * @brief API to check and update PowerVS VPD.
+     *
+     * The API will read the existing data from the DBus and if found
+     * different than what has been read from JSON, it will update the VPD with
+     * JSON data on hardware and DBus both.
+     *
+     * @param[in] i_powerVsJsonObj - PowerVS JSON object.
+     * @param[out] o_failedPathList - List of path failed to update.
+     */
+    void checkAndUpdatePowerVsVpd(const nlohmann::json& i_powerVsJsonObj,
+                                  std::vector<std::string>& o_failedPathList);
+    /**
+     * @brief API to handle configuration w.r.t. PowerVS systems.
+     *
+     * Some FRUs VPD is specific to powerVS system. The API detects the
+     * powerVS configuration and updates the VPD accordingly.
+     */
+    void ConfigurePowerVsSystem();
+
+    // Parsed system config json object.
+    nlohmann::json m_sysCfgJsonObj{};
+
+    // Shared pointer to worker class
+    std::shared_ptr<Worker>& m_worker;
+
+    // Shared pointer to backup and restore object.
+    std::shared_ptr<BackupAndRestore>& m_backupAndRestoreObj;
+
+    // Shared pointer to GpioMonitor object.
+    std::shared_ptr<GpioMonitor> m_gpioMonitor;
+
+    // Shared pointer to Dbus interface class.
+    const std::shared_ptr<sdbusplus::asio::dbus_interface>& m_interface;
+
+    // Shared pointer to asio context object.
+    const std::shared_ptr<boost::asio::io_context>& m_ioContext;
+
+    // Shared pointer to bus connection.
+    const std::shared_ptr<sdbusplus::asio::connection>& m_asioConnection;
 };
 } // namespace vpd
diff --git a/vpd-manager/src/manager.cpp b/vpd-manager/src/manager.cpp
index 0df9f80..979078c 100644
--- a/vpd-manager/src/manager.cpp
+++ b/vpd-manager/src/manager.cpp
@@ -43,63 +43,6 @@
 
     try
     {
-#ifdef IBM_SYSTEM
-        if (dbusUtility::isChassisPowerOn())
-        {
-            // At power on, less number of FRU(s) needs collection. we can scale
-            // down the threads to reduce CPU utilization.
-            m_worker = std::make_shared<Worker>(INVENTORY_JSON_DEFAULT,
-                                                constants::VALUE_1);
-        }
-        else
-        {
-            // Initialize with default configuration
-            m_worker = std::make_shared<Worker>(INVENTORY_JSON_DEFAULT);
-        }
-
-        // Set up minimal things that is needed before bus name is claimed.
-        m_worker->performInitialSetup();
-
-        const nlohmann::json& l_sysCfgJsonObj = m_worker->getSysCfgJsonObj();
-        if (!m_worker->getSysCfgJsonObj().empty() &&
-            jsonUtility::isBackupAndRestoreRequired(l_sysCfgJsonObj))
-        {
-            try
-            {
-                m_backupAndRestoreObj =
-                    std::make_shared<BackupAndRestore>(l_sysCfgJsonObj);
-            }
-            catch (const std::exception& l_ex)
-            {
-                logging::logMessage(
-                    "Back up and restore instantiation failed. {" +
-                    std::string(l_ex.what()) + "}");
-
-                EventLogger::createSyncPel(
-                    EventLogger::getErrorType(l_ex),
-                    types::SeverityType::Warning, __FILE__, __FUNCTION__, 0,
-                    EventLogger::getErrorMsg(l_ex), std::nullopt, std::nullopt,
-                    std::nullopt, std::nullopt);
-            }
-        }
-
-        // set callback to detect any asset tag change
-        registerAssetTagChangeCallback();
-
-        // set async timer to detect if system VPD is published on D-Bus.
-        SetTimerToDetectSVPDOnDbus();
-
-        // set async timer to detect if VPD collection is done.
-        SetTimerToDetectVpdCollectionStatus();
-
-        // Instantiate GpioMonitor class
-        m_gpioMonitor = std::make_shared<GpioMonitor>(
-            m_worker->getSysCfgJsonObj(), m_worker, m_ioContext);
-
-#endif
-        // set callback to detect host state change.
-        registerHostStateChangeCallback();
-
         // For backward compatibility. Should be depricated.
         iFace->register_method(
             "WriteKeyword",
@@ -186,6 +129,21 @@
                 return 0;
             },
             [this](const auto&) { return m_vpdCollectionStatus; });
+
+        // If required, instantiate OEM specific handler here.
+#ifdef IBM_SYSTEM
+        m_ibmHandler = std::make_shared<IbmHandler>(
+            m_worker, m_backupAndRestoreObj, m_interface, m_ioContext,
+            m_asioConnection);
+
+        // TODO: Move to respective handler class as this is OEM specific. To
+        // move this, collect single FRU VPD API needs to be modified. set
+        // callback to detect host state change.
+        registerHostStateChangeCallback();
+#else
+        m_worker = std::make_shared<Worker>(INVENTORY_JSON_DEFAULT);
+        m_interface->set_property("CollectionStatus", std::string("Completed"));
+#endif
     }
     catch (const std::exception& e)
     {
@@ -199,367 +157,6 @@
     }
 }
 
-#ifdef IBM_SYSTEM
-void Manager::registerAssetTagChangeCallback()
-{
-    static std::shared_ptr<sdbusplus::bus::match_t> l_assetMatch =
-        std::make_shared<sdbusplus::bus::match_t>(
-            *m_asioConnection,
-            sdbusplus::bus::match::rules::propertiesChanged(
-                constants::systemInvPath, constants::assetTagInf),
-            [this](sdbusplus::message_t& l_msg) {
-                processAssetTagChangeCallback(l_msg);
-            });
-}
-
-void Manager::processAssetTagChangeCallback(sdbusplus::message_t& i_msg)
-{
-    try
-    {
-        if (i_msg.is_method_error())
-        {
-            throw std::runtime_error(
-                "Error reading callback msg for asset tag.");
-        }
-
-        std::string l_objectPath;
-        types::PropertyMap l_propMap;
-        i_msg.read(l_objectPath, l_propMap);
-
-        const auto& l_itrToAssetTag = l_propMap.find("AssetTag");
-        if (l_itrToAssetTag != l_propMap.end())
-        {
-            if (auto l_assetTag =
-                    std::get_if<std::string>(&(l_itrToAssetTag->second)))
-            {
-                // Call Notify to persist the AssetTag
-                types::ObjectMap l_objectMap = {
-                    {sdbusplus::message::object_path(constants::systemInvPath),
-                     {{constants::assetTagInf, {{"AssetTag", *l_assetTag}}}}}};
-
-                // Notify PIM
-                if (!dbusUtility::callPIM(move(l_objectMap)))
-                {
-                    throw std::runtime_error(
-                        "Call to PIM failed for asset tag update.");
-                }
-            }
-        }
-        else
-        {
-            throw std::runtime_error(
-                "Could not find asset tag in callback message.");
-        }
-    }
-    catch (const std::exception& l_ex)
-    {
-        // TODO: Log PEL with below description.
-        logging::logMessage("Asset tag callback update failed with error: " +
-                            std::string(l_ex.what()));
-    }
-}
-
-void Manager::SetTimerToDetectSVPDOnDbus()
-{
-    try
-    {
-        static boost::asio::steady_timer timer(*m_ioContext);
-
-        // timer for 2 seconds
-        auto asyncCancelled = timer.expires_after(std::chrono::seconds(2));
-
-        (asyncCancelled == 0) ? logging::logMessage("Timer started")
-                              : logging::logMessage("Timer re-started");
-
-        timer.async_wait([this](const boost::system::error_code& ec) {
-            if (ec == boost::asio::error::operation_aborted)
-            {
-                throw std::runtime_error(
-                    std::string(__FUNCTION__) +
-                    ": Timer to detect system VPD collection status was aborted.");
-            }
-
-            if (ec)
-            {
-                throw std::runtime_error(
-                    std::string(__FUNCTION__) +
-                    ": Timer to detect System VPD collection failed");
-            }
-
-            if (m_worker->isSystemVPDOnDBus())
-            {
-                // cancel the timer
-                timer.cancel();
-
-                // Triggering FRU VPD collection. Setting status to "In
-                // Progress".
-                m_interface->set_property("CollectionStatus",
-                                          std::string("InProgress"));
-                m_worker->collectFrusFromJson();
-            }
-        });
-    }
-    catch (const std::exception& l_ex)
-    {
-        EventLogger::createAsyncPel(
-            EventLogger::getErrorType(l_ex), types::SeverityType::Critical,
-            __FILE__, __FUNCTION__, 0,
-            std::string("Collection for FRUs failed with reason:") +
-                EventLogger::getErrorMsg(l_ex),
-            std::nullopt, std::nullopt, std::nullopt, std::nullopt);
-    }
-}
-
-void Manager::SetTimerToDetectVpdCollectionStatus()
-{
-    // Keeping max retry for 2 minutes. TODO: Make it configurable based on
-    // system type.
-    static constexpr auto MAX_RETRY = 12;
-
-    static boost::asio::steady_timer l_timer(*m_ioContext);
-    static uint8_t l_timerRetry = 0;
-
-    auto l_asyncCancelled = l_timer.expires_after(std::chrono::seconds(10));
-
-    (l_asyncCancelled == 0)
-        ? logging::logMessage("Collection Timer started")
-        : logging::logMessage("Collection Timer re-started");
-
-    l_timer.async_wait([this](const boost::system::error_code& ec) {
-        if (ec == boost::asio::error::operation_aborted)
-        {
-            throw std::runtime_error(
-                "Timer to detect thread collection status was aborted");
-        }
-
-        if (ec)
-        {
-            throw std::runtime_error(
-                "Timer to detect thread collection failed");
-        }
-
-        if (m_worker->isAllFruCollectionDone())
-        {
-            // cancel the timer
-            l_timer.cancel();
-            processFailedEeproms();
-
-            // update VPD for powerVS system.
-            ConfigurePowerVsSystem();
-
-            m_interface->set_property("CollectionStatus",
-                                      std::string("Completed"));
-
-            if (m_backupAndRestoreObj)
-            {
-                m_backupAndRestoreObj->backupAndRestore();
-            }
-        }
-        else
-        {
-            auto l_threadCount = m_worker->getActiveThreadCount();
-            if (l_timerRetry == MAX_RETRY)
-            {
-                l_timer.cancel();
-                logging::logMessage("Taking too long. Active thread = " +
-                                    std::to_string(l_threadCount));
-            }
-            else
-            {
-                l_timerRetry++;
-                logging::logMessage("Collection is in progress for [" +
-                                    std::to_string(l_threadCount) + "] FRUs.");
-
-                SetTimerToDetectVpdCollectionStatus();
-            }
-        }
-    });
-}
-
-void Manager::checkAndUpdatePowerVsVpd(
-    const nlohmann::json& i_powerVsJsonObj,
-    std::vector<std::string>& o_failedPathList)
-{
-    for (const auto& [l_fruPath, l_recJson] : i_powerVsJsonObj.items())
-    {
-        nlohmann::json l_sysCfgJsonObj{};
-        if (m_worker.get() != nullptr)
-        {
-            l_sysCfgJsonObj = m_worker->getSysCfgJsonObj();
-        }
-
-        // The utility method will handle emty JSON case. No explicit
-        // handling required here.
-        auto l_inventoryPath = jsonUtility::getInventoryObjPathFromJson(
-            l_sysCfgJsonObj, l_fruPath);
-
-        // Mark it as failed if inventory path not found in JSON.
-        if (l_inventoryPath.empty())
-        {
-            o_failedPathList.push_back(l_fruPath);
-            continue;
-        }
-
-        // check if the FRU is present
-        if (!dbusUtility::isInventoryPresent(l_inventoryPath))
-        {
-            logging::logMessage(
-                "Inventory not present, skip updating part number. Path: " +
-                l_inventoryPath);
-            continue;
-        }
-
-        // check if the FRU needs CCIN check before updating PN.
-        if (l_recJson.contains("CCIN"))
-        {
-            const auto& l_ccinFromDbus =
-                vpdSpecificUtility::getCcinFromDbus(l_inventoryPath);
-
-            // Not an ideal situation as CCIN can't be empty.
-            if (l_ccinFromDbus.empty())
-            {
-                o_failedPathList.push_back(l_fruPath);
-                continue;
-            }
-
-            std::vector<std::string> l_ccinListFromJson = l_recJson["CCIN"];
-
-            if (find(l_ccinListFromJson.begin(), l_ccinListFromJson.end(),
-                     l_ccinFromDbus) == l_ccinListFromJson.end())
-            {
-                // Don't update PN in this case.
-                continue;
-            }
-        }
-
-        for (const auto& [l_recordName, l_kwdJson] : l_recJson.items())
-        {
-            // Record name can't be CCIN, skip processing as it is there for PN
-            // update based on CCIN check.
-            if (l_recordName == constants::kwdCCIN)
-            {
-                continue;
-            }
-
-            for (const auto& [l_kwdName, l_kwdValue] : l_kwdJson.items())
-            {
-                // Is value of type array.
-                if (!l_kwdValue.is_array())
-                {
-                    o_failedPathList.push_back(l_fruPath);
-                    continue;
-                }
-
-                // Get current FRU Part number.
-                auto l_retVal = dbusUtility::readDbusProperty(
-                    constants::pimServiceName, l_inventoryPath,
-                    constants::viniInf, constants::kwdFN);
-
-                auto l_ptrToFn = std::get_if<types::BinaryVector>(&l_retVal);
-
-                if (!l_ptrToFn)
-                {
-                    o_failedPathList.push_back(l_fruPath);
-                    continue;
-                }
-
-                types::BinaryVector l_binaryKwdValue =
-                    l_kwdValue.get<types::BinaryVector>();
-                if (l_binaryKwdValue == (*l_ptrToFn))
-                {
-                    continue;
-                }
-
-                // Update part number only if required.
-                if (updateKeyword(
-                        l_fruPath,
-                        std::make_tuple(l_recordName, l_kwdName, l_kwdValue)) ==
-                    constants::FAILURE)
-                {
-                    o_failedPathList.push_back(l_fruPath);
-                    continue;
-                }
-
-                // update the Asset interface Spare part number explicitly.
-                if (!dbusUtility::callPIM(types::ObjectMap{
-                        {l_inventoryPath,
-                         {{constants::assetInf,
-                           {{"SparePartNumber",
-                             std::string(l_binaryKwdValue.begin(),
-                                         l_binaryKwdValue.end())}}}}}}))
-                {
-                    logging::logMessage(
-                        "Updating Spare Part Number under Asset interface failed for path [" +
-                        l_inventoryPath + "]");
-                }
-
-                // Just needed for logging.
-                std::string l_initialPartNum((*l_ptrToFn).begin(),
-                                             (*l_ptrToFn).end());
-                std::string l_finalPartNum(l_binaryKwdValue.begin(),
-                                           l_binaryKwdValue.end());
-                logging::logMessage(
-                    "FRU Part number updated for path [" + l_inventoryPath +
-                    "]" + "From [" + l_initialPartNum + "]" + " to [" +
-                    l_finalPartNum + "]");
-            }
-        }
-    }
-}
-
-void Manager::ConfigurePowerVsSystem()
-{
-    std::vector<std::string> l_failedPathList;
-    try
-    {
-        types::BinaryVector l_imValue = dbusUtility::getImFromDbus();
-        if (l_imValue.empty())
-        {
-            throw DbusException("Invalid IM value read from Dbus");
-        }
-
-        if (!vpdSpecificUtility::isPowerVsConfiguration(l_imValue))
-        {
-            // TODO: Should booting be blocked in case of some
-            // misconfigurations?
-            return;
-        }
-
-        const nlohmann::json& l_powerVsJsonObj =
-            jsonUtility::getPowerVsJson(l_imValue);
-
-        if (l_powerVsJsonObj.empty())
-        {
-            throw std::runtime_error("PowerVS Json not found");
-        }
-
-        checkAndUpdatePowerVsVpd(l_powerVsJsonObj, l_failedPathList);
-
-        if (!l_failedPathList.empty())
-        {
-            throw std::runtime_error(
-                "Part number update failed for following paths: ");
-        }
-    }
-    catch (const std::exception& l_ex)
-    {
-        // TODO log appropriate PEL
-    }
-}
-
-void Manager::processFailedEeproms()
-{
-    if (m_worker.get() != nullptr)
-    {
-        // TODO:
-        // - iterate through list of EEPROMs for which thread creation has
-        // failed
-        // - For each failed EEPROM, trigger VPD collection
-        m_worker->getFailedEepromPaths().clear();
-    }
-}
-#endif
-
 int Manager::updateKeyword(const types::Path i_vpdPath,
                            const types::WriteVpdParams i_paramsToWriteData)
 {