pldmd: implement a new handler registration scheme

Implement a PLDM request handler registration scheme that requires
handlers to be C++ objects rather than plain functions. This was needed
for a couple of reasons:

- Perform specific actions at the PLDM daemon startup (that's when the
  handlers are loaded).
- Share data across PLDM request messages (for eg FRU/BIOS tables),
  without having to resort to globals and statics.

Tested:
- existing unit tests still pass
- added tests for the new registration scheme

Signed-off-by: Deepak Kodihalli <dkodihal@in.ibm.com>
Change-Id: I1cf1c0a6fccd15da54f08120e61a5f256df6bc36
diff --git a/handler.hpp b/handler.hpp
new file mode 100644
index 0000000..67ad471
--- /dev/null
+++ b/handler.hpp
@@ -0,0 +1,45 @@
+#pragma once
+
+#include <functional>
+#include <map>
+
+#include "libpldm/base.h"
+
+namespace pldm
+{
+
+using Command = uint8_t;
+
+namespace responder
+{
+
+using Response = std::vector<uint8_t>;
+class CmdHandler;
+using HandlerFunc =
+    std::function<Response(const pldm_msg* request, size_t reqMsgLen)>;
+
+class CmdHandler
+{
+  public:
+    /** @brief Invoke a PLDM command handler
+     *
+     *  @param[in] pldmCommand - PLDM command code
+     *  @param[in] request - PLDM request message
+     *  @param[in] reqMsgLen - PLDM request message size
+     *  @return PLDM response message
+     */
+    Response handle(Command pldmCommand, const pldm_msg* request,
+                    size_t reqMsgLen)
+    {
+        return handlers.at(pldmCommand)(request, reqMsgLen);
+    }
+
+  protected:
+    /** @brief map of PLDM command code to handler - to be populated by derived
+     *         classes.
+     */
+    std::map<Command, HandlerFunc> handlers;
+};
+
+} // namespace responder
+} // namespace pldm
diff --git a/invoker.hpp b/invoker.hpp
new file mode 100644
index 0000000..c885ee8
--- /dev/null
+++ b/invoker.hpp
@@ -0,0 +1,50 @@
+#pragma once
+
+#include "handler.hpp"
+
+#include <map>
+#include <memory>
+
+#include "libpldm/base.h"
+
+namespace pldm
+{
+
+using Type = uint8_t;
+
+namespace responder
+{
+
+class Invoker
+{
+  public:
+    /** @brief Register a handler for a PLDM Type
+     *
+     *  @param[in] pldmType - PLDM type code
+     *  @param[in] handler - PLDM Type handler
+     */
+    void registerHandler(Type pldmType, std::unique_ptr<CmdHandler> handler)
+    {
+        handlers.emplace(pldmType, std::move(handler));
+    }
+
+    /** @brief Invoke a PLDM command handler
+     *
+     *  @param[in] pldmType - PLDM type code
+     *  @param[in] pldmCommand - PLDM command code
+     *  @param[in] request - PLDM request message
+     *  @param[in] reqMsgLen - PLDM request message size
+     *  @return PLDM response message
+     */
+    Response handle(Type pldmType, Command pldmCommand, const pldm_msg* request,
+                    size_t reqMsgLen)
+    {
+        return handlers.at(pldmType)->handle(pldmCommand, request, reqMsgLen);
+    }
+
+  private:
+    std::map<Type, std::unique_ptr<CmdHandler>> handlers;
+};
+
+} // namespace responder
+} // namespace pldm
diff --git a/libpldmresponder/base.cpp b/libpldmresponder/base.cpp
index e94597a..b9f5ff1 100644
--- a/libpldmresponder/base.cpp
+++ b/libpldmresponder/base.cpp
@@ -1,7 +1,6 @@
 #include "libpldm/base.h"
 
 #include "base.hpp"
-#include "registration.hpp"
 
 #include <array>
 #include <cstring>
@@ -14,6 +13,9 @@
 
 namespace pldm
 {
+
+using Type = uint8_t;
+
 namespace responder
 {
 
@@ -36,19 +38,8 @@
 namespace base
 {
 
-void registerHandlers()
-{
-    registerHandler(PLDM_BASE, PLDM_GET_PLDM_TYPES, std::move(getPLDMTypes));
-    registerHandler(PLDM_BASE, PLDM_GET_PLDM_COMMANDS,
-                    std::move(getPLDMCommands));
-    registerHandler(PLDM_BASE, PLDM_GET_PLDM_VERSION,
-                    std::move(getPLDMVersion));
-    registerHandler(PLDM_BASE, PLDM_GET_TID, std::move(getTID));
-}
-
-} // namespace base
-
-Response getPLDMTypes(const pldm_msg* request, size_t /*payloadLength*/)
+Response Handler::getPLDMTypes(const pldm_msg* request,
+                               size_t /*payloadLength*/)
 {
     // DSP0240 has this as a bitfield8[N], where N = 0 to 7
     std::array<bitfield8_t, 8> types{};
@@ -68,7 +59,7 @@
     return response;
 }
 
-Response getPLDMCommands(const pldm_msg* request, size_t payloadLength)
+Response Handler::getPLDMCommands(const pldm_msg* request, size_t payloadLength)
 {
     ver32_t version{};
     Type type;
@@ -109,7 +100,7 @@
     return response;
 }
 
-Response getPLDMVersion(const pldm_msg* request, size_t payloadLength)
+Response Handler::getPLDMVersion(const pldm_msg* request, size_t payloadLength)
 {
     uint32_t transferHandle;
     Type type;
@@ -147,7 +138,7 @@
     return response;
 }
 
-Response getTID(const pldm_msg* request, size_t /*payloadLength*/)
+Response Handler::getTID(const pldm_msg* request, size_t /*payloadLength*/)
 {
     // assigned 1 to the bmc as the PLDM terminus
     uint8_t tid = 1;
@@ -160,5 +151,6 @@
     return response;
 }
 
+} // namespace base
 } // namespace responder
 } // namespace pldm
diff --git a/libpldmresponder/base.hpp b/libpldmresponder/base.hpp
index a6e5abd..519bff2 100644
--- a/libpldmresponder/base.hpp
+++ b/libpldmresponder/base.hpp
@@ -1,5 +1,7 @@
 #pragma once
 
+#include "handler.hpp"
+
 #include <stdint.h>
 
 #include <vector>
@@ -8,51 +10,67 @@
 
 namespace pldm
 {
-
-using Type = uint8_t;
-
-using Response = std::vector<uint8_t>;
-
 namespace responder
 {
-
 namespace base
 {
-/** @brief Register handlers for command from the base spec
- */
-void registerHandlers();
+
+class Handler : public CmdHandler
+{
+  public:
+    Handler()
+    {
+        handlers.emplace(PLDM_GET_PLDM_TYPES,
+                         [this](const pldm_msg* request, size_t payloadLength) {
+                             return this->getPLDMTypes(request, payloadLength);
+                         });
+        handlers.emplace(PLDM_GET_PLDM_COMMANDS, [this](const pldm_msg* request,
+                                                        size_t payloadLength) {
+            return this->getPLDMCommands(request, payloadLength);
+        });
+        handlers.emplace(PLDM_GET_PLDM_VERSION, [this](const pldm_msg* request,
+                                                       size_t payloadLength) {
+            return this->getPLDMVersion(request, payloadLength);
+        });
+        handlers.emplace(PLDM_GET_TID,
+                         [this](const pldm_msg* request, size_t payloadLength) {
+                             return this->getTID(request, payloadLength);
+                         });
+    }
+
+    /** @brief Handler for getPLDMTypes
+     *
+     *  @param[in] request - Request message payload
+     *  @param[in] payload_length - Request message payload length
+     *  @param[return] Response - PLDM Response message
+     */
+    Response getPLDMTypes(const pldm_msg* request, size_t payloadLength);
+
+    /** @brief Handler for getPLDMCommands
+     *
+     *  @param[in] request - Request message payload
+     *  @param[in] payload_length - Request message payload length
+     *  @param[return] Response - PLDM Response message
+     */
+    Response getPLDMCommands(const pldm_msg* request, size_t payloadLength);
+
+    /** @brief Handler for getPLDMCommands
+     *
+     *  @param[in] request - Request message payload
+     *  @param[in] payload_length - Request message payload length
+     *  @param[return] Response - PLDM Response message
+     */
+    Response getPLDMVersion(const pldm_msg* request, size_t payloadLength);
+
+    /** @brief Handler for getTID
+     *
+     *  @param[in] request - Request message payload
+     *  @param[in] payload_length - Request message payload length
+     *  @param[return] Response - PLDM Response message
+     */
+    Response getTID(const pldm_msg* request, size_t payloadLength);
+};
+
 } // namespace base
-
-/** @brief Handler for getPLDMTypes
- *
- *  @param[in] request - Request message payload
- *  @param[in] payload_length - Request message payload length
- *  @param[return] Response - PLDM Response message
- */
-Response getPLDMTypes(const pldm_msg* request, size_t payloadLength);
-
-/** @brief Handler for getPLDMCommands
- *
- *  @param[in] request - Request message payload
- *  @param[in] payload_length - Request message payload length
- *  @param[return] Response - PLDM Response message
- */
-Response getPLDMCommands(const pldm_msg* request, size_t payloadLength);
-
-/** @brief Handler for getPLDMCommands
- *
- *  @param[in] request - Request message payload
- *  @param[in] payload_length - Request message payload length
- *  @param[return] Response - PLDM Response message
- */
-Response getPLDMVersion(const pldm_msg* request, size_t payloadLength);
-
-/** @brief Handler for getTID
- *
- *  @param[in] request - Request message payload
- *  @param[in] payload_length - Request message payload length
- *  @param[return] Response - PLDM Response message
- */
-Response getTID(const pldm_msg* request, size_t payloadLength);
 } // namespace responder
 } // namespace pldm
diff --git a/libpldmresponder/bios.cpp b/libpldmresponder/bios.cpp
index 1c48f1a..c3a1c53 100644
--- a/libpldmresponder/bios.cpp
+++ b/libpldmresponder/bios.cpp
@@ -1,7 +1,6 @@
 #include "bios.hpp"
 
 #include "libpldmresponder/utils.hpp"
-#include "registration.hpp"
 #include "xyz/openbmc_project/Common/error.hpp"
 
 #include <array>
@@ -72,7 +71,10 @@
 
 } // namespace utils
 
-Response getDateTime(const pldm_msg* request, size_t /*payloadLength*/)
+namespace bios
+{
+
+Response Handler::getDateTime(const pldm_msg* request, size_t /*payloadLength*/)
 {
     uint8_t seconds = 0;
     uint8_t minutes = 0;
@@ -117,7 +119,8 @@
                            std::chrono::microseconds(timeUsec))
                            .count();
 
-    utils::epochToBCDTime(timeSec, seconds, minutes, hours, day, month, year);
+    pldm::responder::utils::epochToBCDTime(timeSec, seconds, minutes, hours,
+                                           day, month, year);
 
     encode_get_date_time_resp(request->hdr.instance_id, PLDM_SUCCESS, seconds,
                               minutes, hours, day, month, year, responsePtr);
@@ -163,7 +166,8 @@
         });
 
     Table stringTable;
-    stringTable.reserve(utils::getTableTotalsize(sizeWithoutPad));
+    stringTable.reserve(
+        pldm::responder::utils::getTableTotalsize(sizeWithoutPad));
 
     stringTable.resize(sizeWithoutPad);
     auto tablePtr = stringTable.data();
@@ -177,7 +181,7 @@
         sizeWithoutPad -= entry_length;
     }
 
-    utils::padAndChecksum(stringTable);
+    pldm::responder::utils::padAndChecksum(stringTable);
     BIOSStringTable.store(stringTable);
     response.resize(sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES +
                         stringTable.size(),
@@ -647,7 +651,7 @@
                                        response.size(), responsePtr);
             return response;
         }
-        utils::padAndChecksum(attributeTable);
+        pldm::responder::utils::padAndChecksum(attributeTable);
         BIOSAttributeTable.store(attributeTable);
         response.resize(sizeof(pldm_msg_hdr) +
                         PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES +
@@ -751,7 +755,7 @@
                                    response.size(), responsePtr);
         return response;
     }
-    utils::padAndChecksum(attributeValueTable);
+    pldm::responder::utils::padAndChecksum(attributeValueTable);
     BIOSAttributeValueTable.store(attributeValueTable);
 
     response.resize(sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES +
@@ -764,7 +768,7 @@
     return response;
 }
 
-Response getBIOSTable(const pldm_msg* request, size_t payloadLength)
+Response Handler::getBIOSTable(const pldm_msg* request, size_t payloadLength)
 {
     fs::create_directory(BIOS_TABLES_DIR);
     auto response = internal::buildBIOSTables(request, payloadLength,
@@ -773,15 +777,6 @@
     return response;
 }
 
-namespace bios
-{
-
-void registerHandlers()
-{
-    registerHandler(PLDM_BIOS, PLDM_GET_DATE_TIME, std::move(getDateTime));
-    registerHandler(PLDM_BIOS, PLDM_GET_BIOS_TABLE, std::move(getBIOSTable));
-}
-
 namespace internal
 {
 
diff --git a/libpldmresponder/bios.hpp b/libpldmresponder/bios.hpp
index 412e07a..e9abed2 100644
--- a/libpldmresponder/bios.hpp
+++ b/libpldmresponder/bios.hpp
@@ -4,6 +4,7 @@
 
 #include "bios_parser.hpp"
 #include "bios_table.hpp"
+#include "handler.hpp"
 
 #include <stdint.h>
 
@@ -17,7 +18,6 @@
 namespace pldm
 {
 
-using Response = std::vector<uint8_t>;
 using AttributeHandle = uint16_t;
 using StringHandle = uint16_t;
 using PossibleValuesByHandle = std::vector<StringHandle>;
@@ -25,18 +25,15 @@
 namespace responder
 {
 
+namespace bios
+{
+
 using AttrTableEntryHandler =
     std::function<void(const struct pldm_bios_attr_table_entry*)>;
 
 void traverseBIOSAttrTable(const bios::Table& BIOSAttrTable,
                            AttrTableEntryHandler handler);
 
-namespace bios
-{
-/** @brief Register handlers for command from the platform spec
- */
-void registerHandlers();
-
 namespace internal
 {
 
@@ -49,25 +46,41 @@
  */
 Response buildBIOSTables(const pldm_msg* request, size_t payloadLength,
                          const char* biosJsonDir, const char* biosTablePath);
-} // end namespace internal
+} // namespace internal
+
+class Handler : public CmdHandler
+{
+  public:
+    Handler()
+    {
+        handlers.emplace(PLDM_GET_DATE_TIME,
+                         [this](const pldm_msg* request, size_t payloadLength) {
+                             return this->getDateTime(request, payloadLength);
+                         });
+        handlers.emplace(PLDM_GET_BIOS_TABLE,
+                         [this](const pldm_msg* request, size_t payloadLength) {
+                             return this->getBIOSTable(request, payloadLength);
+                         });
+    }
+
+    /** @brief Handler for GetDateTime
+     *
+     *  @param[in] request - Request message payload
+     *  @param[return] Response - PLDM Response message
+     */
+    Response getDateTime(const pldm_msg* request, size_t payloadLength);
+
+    /** @brief Handler for GetBIOSTable
+     *
+     *  @param[in] request - Request message
+     *  @param[in] payload_length - Request message payload length
+     *  @param[return] Response - PLDM Response message
+     */
+    Response getBIOSTable(const pldm_msg* request, size_t payloadLength);
+};
 
 } // namespace bios
 
-/** @brief Handler for GetDateTime
- *
- *  @param[in] request - Request message payload
- *  @param[return] Response - PLDM Response message
- */
-Response getDateTime(const pldm_msg* request, size_t payloadLength);
-
-/** @brief Handler for GetBIOSTable
- *
- *  @param[in] request - Request message
- *  @param[in] payload_length - Request message payload length
- *  @param[return] Response - PLDM Response message
- */
-Response getBIOSTable(const pldm_msg* request, size_t payloadLength);
-
 namespace utils
 {
 
diff --git a/libpldmresponder/meson.build b/libpldmresponder/meson.build
index 770ef8c..8ad31d4 100644
--- a/libpldmresponder/meson.build
+++ b/libpldmresponder/meson.build
@@ -14,7 +14,6 @@
   'effecters.cpp',
   'utils.cpp',
   'platform.cpp',
-  '../registration.cpp'
 ]
 
 if get_option('oem-ibm').enabled()
diff --git a/libpldmresponder/platform.cpp b/libpldmresponder/platform.cpp
index 538c49c..50237cf 100644
--- a/libpldmresponder/platform.cpp
+++ b/libpldmresponder/platform.cpp
@@ -1,30 +1,17 @@
 
 #include "platform.hpp"
 
-#include "registration.hpp"
-
 namespace pldm
 {
-
 namespace responder
 {
-
 namespace platform
 {
 
-void registerHandlers()
-{
-    registerHandler(PLDM_PLATFORM, PLDM_GET_PDR, std::move(getPDR));
-    registerHandler(PLDM_PLATFORM, PLDM_SET_STATE_EFFECTER_STATES,
-                    std::move(setStateEffecterStates));
-}
-
-} // namespace platform
-
 using namespace phosphor::logging;
 using namespace pldm::responder::effecter::dbus_mapping;
 
-Response getPDR(const pldm_msg* request, size_t payloadLength)
+Response Handler::getPDR(const pldm_msg* request, size_t payloadLength)
 {
     Response response(sizeof(pldm_msg_hdr) + PLDM_GET_PDR_MIN_RESP_BYTES, 0);
     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
@@ -92,7 +79,8 @@
     return response;
 }
 
-Response setStateEffecterStates(const pldm_msg* request, size_t payloadLength)
+Response Handler::setStateEffecterStates(const pldm_msg* request,
+                                         size_t payloadLength)
 {
     Response response(
         sizeof(pldm_msg_hdr) + PLDM_SET_STATE_EFFECTER_STATES_RESP_BYTES, 0);
@@ -129,5 +117,6 @@
     return response;
 }
 
+} // namespace platform
 } // namespace responder
 } // namespace pldm
diff --git a/libpldmresponder/platform.hpp b/libpldmresponder/platform.hpp
index ec168f4..be48950 100644
--- a/libpldmresponder/platform.hpp
+++ b/libpldmresponder/platform.hpp
@@ -2,6 +2,7 @@
 
 #include "config.h"
 
+#include "handler.hpp"
 #include "libpldmresponder/pdr.hpp"
 #include "libpldmresponder/utils.hpp"
 
@@ -14,254 +15,269 @@
 
 namespace pldm
 {
-
-using Response = std::vector<uint8_t>;
-
 namespace responder
 {
-
 namespace platform
 {
 
-/** @brief Register handlers for commands from the platform spec
- */
-void registerHandlers();
-
-} // namespace platform
-
-/** @brief Handler for GetPDR
- *
- *  @param[in] request - Request message payload
- *  @param[in] payloadLength - Request payload length
- *  @param[out] Response - Response message written here
- */
-Response getPDR(const pldm_msg* request, size_t payloadLength);
-
-/** @brief Handler for setStateEffecterStates
- *
- *  @param[in] request - Request message
- *  @param[in] payloadLength - Request payload length
- *  @return Response - PLDM Response message
- */
-Response setStateEffecterStates(const pldm_msg* request, size_t payloadLength);
-
-/** @brief Function to set the effecter requested by pldm requester
- *  @param[in] dBusIntf - The interface object
- *  @param[in] effecterId - Effecter ID sent by the requester to act on
- *  @param[in] stateField - The state field data for each of the states, equal
- *        to composite effecter count in number
- *  @return - Success or failure in setting the states. Returns failure in terms
- *        of PLDM completion codes if atleast one state fails to be set
- */
-template <class DBusInterface>
-int setStateEffecterStatesHandler(
-    const DBusInterface& dBusIntf, effecter::Id effecterId,
-    const std::vector<set_effecter_state_field>& stateField)
+class Handler : public CmdHandler
 {
-    using namespace std::string_literals;
-    using DBusProperty = std::variant<std::string, bool>;
-    using StateSetId = uint16_t;
-    using StateSetNum = uint8_t;
-    using PropertyMap =
-        std::map<StateSetId, std::map<StateSetNum, DBusProperty>>;
-    static const PropertyMap stateNumToDbusProp = {
-        {PLDM_BOOT_PROGRESS_STATE,
-         {{PLDM_BOOT_NOT_ACTIVE,
-           "xyz.openbmc_project.State.OperatingSystem.Status.OSStatus."
-           "Standby"s},
-          {PLDM_BOOT_COMPLETED,
-           "xyz.openbmc_project.State.OperatingSystem.Status.OSStatus."
-           "BootComplete"s}}},
-        {PLDM_SYSTEM_POWER_STATE,
-         {{PLDM_OFF_SOFT_GRACEFUL,
-           "xyz.openbmc_project.State.Chassis.Transition.Off"s}}}};
-    using namespace phosphor::logging;
-    using namespace pldm::responder::pdr;
-    using namespace pldm::responder::effecter::dbus_mapping;
-
-    state_effecter_possible_states* states = nullptr;
-    pldm_state_effecter_pdr* pdr = nullptr;
-    uint8_t compEffecterCnt = stateField.size();
-    uint32_t recordHndl{};
-    Repo& pdrRepo = get(PDR_JSONS_DIR);
-    pdr::Entry pdrEntry{};
-
-    while (!pdr)
+  public:
+    Handler()
     {
-        pdrEntry = pdrRepo.at(recordHndl);
-        pldm_pdr_hdr* header = reinterpret_cast<pldm_pdr_hdr*>(pdrEntry.data());
-        if (header->type != PLDM_STATE_EFFECTER_PDR)
-        {
-            recordHndl = pdrRepo.getNextRecordHandle(recordHndl);
-            if (recordHndl)
-            {
-                continue;
-            }
-            return PLDM_PLATFORM_INVALID_EFFECTER_ID;
-        }
-        pdr = reinterpret_cast<pldm_state_effecter_pdr*>(pdrEntry.data());
-        recordHndl = pdr->hdr.record_handle;
-        if (pdr->effecter_id == effecterId)
-        {
-            states = reinterpret_cast<state_effecter_possible_states*>(
-                pdr->possible_states);
-            if (compEffecterCnt > pdr->composite_effecter_count)
-            {
-                log<level::ERR>("The requester sent wrong composite effecter "
-                                "count for the effecter",
-                                entry("EFFECTER_ID=%d", effecterId),
-                                entry("COMP_EFF_CNT=%d", compEffecterCnt));
-                return PLDM_ERROR_INVALID_DATA;
-            }
-            break;
-        }
-        recordHndl = pdrRepo.getNextRecordHandle(recordHndl);
-        if (!recordHndl)
-        {
-            return PLDM_PLATFORM_INVALID_EFFECTER_ID;
-        }
-        pdr = nullptr;
+        handlers.emplace(PLDM_GET_PDR,
+                         [this](const pldm_msg* request, size_t payloadLength) {
+                             return this->getPDR(request, payloadLength);
+                         });
+        handlers.emplace(PLDM_SET_STATE_EFFECTER_STATES,
+                         [this](const pldm_msg* request, size_t payloadLength) {
+                             return this->setStateEffecterStates(request,
+                                                                 payloadLength);
+                         });
     }
 
-    std::map<StateSetId, std::function<int(const std::string& objPath,
-                                           const uint8_t currState)>>
-        effecterToDbusEntries = {
-            {PLDM_BOOT_PROGRESS_STATE,
-             [&](const std::string& objPath, const uint8_t currState) {
-                 auto stateSet =
-                     stateNumToDbusProp.find(PLDM_BOOT_PROGRESS_STATE);
-                 if (stateSet == stateNumToDbusProp.end())
-                 {
-                     log<level::ERR>("Couldn't find D-Bus mapping for "
-                                     "PLDM_BOOT_PROGRESS_STATE",
-                                     entry("EFFECTER_ID=%d", effecterId));
-                     return PLDM_ERROR;
-                 }
-                 auto iter = stateSet->second.find(
-                     stateField[currState].effecter_state);
-                 if (iter == stateSet->second.end())
-                 {
-                     log<level::ERR>(
-                         "Invalid state field passed or field not "
-                         "found for PLDM_BOOT_PROGRESS_STATE",
-                         entry("EFFECTER_ID=%d", effecterId),
-                         entry("FIELD=%d",
-                               stateField[currState].effecter_state),
-                         entry("OBJECT_PATH=%s", objPath.c_str()));
-                     return PLDM_ERROR_INVALID_DATA;
-                 }
-                 auto dbusProp = "OperatingSystemState";
-                 std::variant<std::string> value{
-                     std::get<std::string>(iter->second)};
-                 auto dbusInterface =
-                     "xyz.openbmc_project.State.OperatingSystem.Status";
-                 try
-                 {
-                     dBusIntf.setDbusProperty(objPath.c_str(), dbusProp,
-                                              dbusInterface, value);
-                 }
-                 catch (const std::exception& e)
-                 {
-                     log<level::ERR>("Error setting property",
-                                     entry("ERROR=%s", e.what()),
-                                     entry("PROPERTY=%s", dbusProp),
-                                     entry("INTERFACE=%s", dbusInterface),
-                                     entry("PATH=%s", objPath.c_str()));
-                     return PLDM_ERROR;
-                 }
-                 return PLDM_SUCCESS;
-             }},
-            {PLDM_SYSTEM_POWER_STATE,
-             [&](const std::string& objPath, const uint8_t currState) {
-                 auto stateSet =
-                     stateNumToDbusProp.find(PLDM_SYSTEM_POWER_STATE);
-                 if (stateSet == stateNumToDbusProp.end())
-                 {
-                     log<level::ERR>("Couldn't find D-Bus mapping for "
-                                     "PLDM_SYSTEM_POWER_STATE",
-                                     entry("EFFECTER_ID=%d", effecterId));
-                     return PLDM_ERROR;
-                 }
-                 auto iter = stateSet->second.find(
-                     stateField[currState].effecter_state);
-                 if (iter == stateSet->second.end())
-                 {
-                     log<level::ERR>(
-                         "Invalid state field passed or field not "
-                         "found for PLDM_SYSTEM_POWER_STATE",
-                         entry("EFFECTER_ID=%d", effecterId),
-                         entry("FIELD=%d",
-                               stateField[currState].effecter_state),
-                         entry("OBJECT_PATH=%s", objPath.c_str()));
-                     return PLDM_ERROR_INVALID_DATA;
-                 }
-                 auto dbusProp = "RequestedPowerTransition";
-                 std::variant<std::string> value{
-                     std::get<std::string>(iter->second)};
-                 auto dbusInterface = "xyz.openbmc_project.State.Chassis";
-                 try
-                 {
-                     dBusIntf.setDbusProperty(objPath.c_str(), dbusProp,
-                                              dbusInterface, value);
-                 }
-                 catch (const std::exception& e)
-                 {
-                     log<level::ERR>("Error setting property",
-                                     entry("ERROR=%s", e.what()),
-                                     entry("PROPERTY=%s", dbusProp),
-                                     entry("INTERFACE=%s", dbusInterface),
-                                     entry("PATH=%s", objPath.c_str()));
-                     return PLDM_ERROR;
-                 }
-                 return PLDM_SUCCESS;
-             }}};
+    /** @brief Handler for GetPDR
+     *
+     *  @param[in] request - Request message payload
+     *  @param[in] payloadLength - Request payload length
+     *  @param[out] Response - Response message written here
+     */
+    Response getPDR(const pldm_msg* request, size_t payloadLength);
 
-    int rc = PLDM_SUCCESS;
-    auto paths = get(effecterId);
-    for (uint8_t currState = 0; currState < compEffecterCnt; ++currState)
+    /** @brief Handler for setStateEffecterStates
+     *
+     *  @param[in] request - Request message
+     *  @param[in] payloadLength - Request payload length
+     *  @return Response - PLDM Response message
+     */
+    Response setStateEffecterStates(const pldm_msg* request,
+                                    size_t payloadLength);
+
+    /** @brief Function to set the effecter requested by pldm requester
+     *  @param[in] dBusIntf - The interface object
+     *  @param[in] effecterId - Effecter ID sent by the requester to act on
+     *  @param[in] stateField - The state field data for each of the states,
+     * equal to composite effecter count in number
+     *  @return - Success or failure in setting the states. Returns failure in
+     * terms of PLDM completion codes if atleast one state fails to be set
+     */
+    template <class DBusInterface>
+    int setStateEffecterStatesHandler(
+        const DBusInterface& dBusIntf, effecter::Id effecterId,
+        const std::vector<set_effecter_state_field>& stateField)
     {
-        std::vector<StateSetNum> allowed{};
-        // computation is based on table 79 from DSP0248 v1.1.1
-        uint8_t bitfieldIndex = stateField[currState].effecter_state / 8;
-        uint8_t bit =
-            stateField[currState].effecter_state - (8 * bitfieldIndex);
-        if (states->possible_states_size < bitfieldIndex ||
-            !(states->states[bitfieldIndex].byte & (1 << bit)))
+        using namespace std::string_literals;
+        using DBusProperty = std::variant<std::string, bool>;
+        using StateSetId = uint16_t;
+        using StateSetNum = uint8_t;
+        using PropertyMap =
+            std::map<StateSetId, std::map<StateSetNum, DBusProperty>>;
+        static const PropertyMap stateNumToDbusProp = {
+            {PLDM_BOOT_PROGRESS_STATE,
+             {{PLDM_BOOT_NOT_ACTIVE,
+               "xyz.openbmc_project.State.OperatingSystem.Status.OSStatus."
+               "Standby"s},
+              {PLDM_BOOT_COMPLETED,
+               "xyz.openbmc_project.State.OperatingSystem.Status.OSStatus."
+               "BootComplete"s}}},
+            {PLDM_SYSTEM_POWER_STATE,
+             {{PLDM_OFF_SOFT_GRACEFUL,
+               "xyz.openbmc_project.State.Chassis.Transition.Off"s}}}};
+        using namespace phosphor::logging;
+        using namespace pldm::responder::pdr;
+        using namespace pldm::responder::effecter::dbus_mapping;
+
+        state_effecter_possible_states* states = nullptr;
+        pldm_state_effecter_pdr* pdr = nullptr;
+        uint8_t compEffecterCnt = stateField.size();
+        uint32_t recordHndl{};
+        Repo& pdrRepo = get(PDR_JSONS_DIR);
+        pdr::Entry pdrEntry{};
+
+        while (!pdr)
         {
-            log<level::ERR>(
-                "Invalid state set value", entry("EFFECTER_ID=%d", effecterId),
-                entry("VALUE=%d", stateField[currState].effecter_state),
-                entry("COMPOSITE_EFFECTER_ID=%d", currState),
-                entry("DBUS_PATH=%c", paths[currState].c_str()));
-            rc = PLDM_PLATFORM_SET_EFFECTER_UNSUPPORTED_SENSORSTATE;
-            break;
-        }
-        auto iter = effecterToDbusEntries.find(states->state_set_id);
-        if (iter == effecterToDbusEntries.end())
-        {
-            uint16_t setId = states->state_set_id;
-            log<level::ERR>(
-                "Did not find the state set for the state effecter pdr  ",
-                entry("STATE=%d", setId), entry("EFFECTER_ID=%d", effecterId));
-            rc = PLDM_PLATFORM_INVALID_STATE_VALUE;
-            break;
-        }
-        if (stateField[currState].set_request == PLDM_REQUEST_SET)
-        {
-            rc = iter->second(paths[currState], currState);
-            if (rc != PLDM_SUCCESS)
+            pdrEntry = pdrRepo.at(recordHndl);
+            pldm_pdr_hdr* header =
+                reinterpret_cast<pldm_pdr_hdr*>(pdrEntry.data());
+            if (header->type != PLDM_STATE_EFFECTER_PDR)
             {
+                recordHndl = pdrRepo.getNextRecordHandle(recordHndl);
+                if (recordHndl)
+                {
+                    continue;
+                }
+                return PLDM_PLATFORM_INVALID_EFFECTER_ID;
+            }
+            pdr = reinterpret_cast<pldm_state_effecter_pdr*>(pdrEntry.data());
+            recordHndl = pdr->hdr.record_handle;
+            if (pdr->effecter_id == effecterId)
+            {
+                states = reinterpret_cast<state_effecter_possible_states*>(
+                    pdr->possible_states);
+                if (compEffecterCnt > pdr->composite_effecter_count)
+                {
+                    log<level::ERR>(
+                        "The requester sent wrong composite effecter "
+                        "count for the effecter",
+                        entry("EFFECTER_ID=%d", effecterId),
+                        entry("COMP_EFF_CNT=%d", compEffecterCnt));
+                    return PLDM_ERROR_INVALID_DATA;
+                }
                 break;
             }
+            recordHndl = pdrRepo.getNextRecordHandle(recordHndl);
+            if (!recordHndl)
+            {
+                return PLDM_PLATFORM_INVALID_EFFECTER_ID;
+            }
+            pdr = nullptr;
         }
-        uint8_t* nextState =
-            reinterpret_cast<uint8_t*>(states) +
-            sizeof(state_effecter_possible_states) - sizeof(states->states) +
-            (states->possible_states_size * sizeof(states->states));
-        states = reinterpret_cast<state_effecter_possible_states*>(nextState);
-    }
-    return rc;
-}
 
+        std::map<StateSetId, std::function<int(const std::string& objPath,
+                                               const uint8_t currState)>>
+            effecterToDbusEntries = {
+                {PLDM_BOOT_PROGRESS_STATE,
+                 [&](const std::string& objPath, const uint8_t currState) {
+                     auto stateSet =
+                         stateNumToDbusProp.find(PLDM_BOOT_PROGRESS_STATE);
+                     if (stateSet == stateNumToDbusProp.end())
+                     {
+                         log<level::ERR>("Couldn't find D-Bus mapping for "
+                                         "PLDM_BOOT_PROGRESS_STATE",
+                                         entry("EFFECTER_ID=%d", effecterId));
+                         return PLDM_ERROR;
+                     }
+                     auto iter = stateSet->second.find(
+                         stateField[currState].effecter_state);
+                     if (iter == stateSet->second.end())
+                     {
+                         log<level::ERR>(
+                             "Invalid state field passed or field not "
+                             "found for PLDM_BOOT_PROGRESS_STATE",
+                             entry("EFFECTER_ID=%d", effecterId),
+                             entry("FIELD=%d",
+                                   stateField[currState].effecter_state),
+                             entry("OBJECT_PATH=%s", objPath.c_str()));
+                         return PLDM_ERROR_INVALID_DATA;
+                     }
+                     auto dbusProp = "OperatingSystemState";
+                     std::variant<std::string> value{
+                         std::get<std::string>(iter->second)};
+                     auto dbusInterface =
+                         "xyz.openbmc_project.State.OperatingSystem.Status";
+                     try
+                     {
+                         dBusIntf.setDbusProperty(objPath.c_str(), dbusProp,
+                                                  dbusInterface, value);
+                     }
+                     catch (const std::exception& e)
+                     {
+                         log<level::ERR>("Error setting property",
+                                         entry("ERROR=%s", e.what()),
+                                         entry("PROPERTY=%s", dbusProp),
+                                         entry("INTERFACE=%s", dbusInterface),
+                                         entry("PATH=%s", objPath.c_str()));
+                         return PLDM_ERROR;
+                     }
+                     return PLDM_SUCCESS;
+                 }},
+                {PLDM_SYSTEM_POWER_STATE,
+                 [&](const std::string& objPath, const uint8_t currState) {
+                     auto stateSet =
+                         stateNumToDbusProp.find(PLDM_SYSTEM_POWER_STATE);
+                     if (stateSet == stateNumToDbusProp.end())
+                     {
+                         log<level::ERR>("Couldn't find D-Bus mapping for "
+                                         "PLDM_SYSTEM_POWER_STATE",
+                                         entry("EFFECTER_ID=%d", effecterId));
+                         return PLDM_ERROR;
+                     }
+                     auto iter = stateSet->second.find(
+                         stateField[currState].effecter_state);
+                     if (iter == stateSet->second.end())
+                     {
+                         log<level::ERR>(
+                             "Invalid state field passed or field not "
+                             "found for PLDM_SYSTEM_POWER_STATE",
+                             entry("EFFECTER_ID=%d", effecterId),
+                             entry("FIELD=%d",
+                                   stateField[currState].effecter_state),
+                             entry("OBJECT_PATH=%s", objPath.c_str()));
+                         return PLDM_ERROR_INVALID_DATA;
+                     }
+                     auto dbusProp = "RequestedPowerTransition";
+                     std::variant<std::string> value{
+                         std::get<std::string>(iter->second)};
+                     auto dbusInterface = "xyz.openbmc_project.State.Chassis";
+                     try
+                     {
+                         dBusIntf.setDbusProperty(objPath.c_str(), dbusProp,
+                                                  dbusInterface, value);
+                     }
+                     catch (const std::exception& e)
+                     {
+                         log<level::ERR>("Error setting property",
+                                         entry("ERROR=%s", e.what()),
+                                         entry("PROPERTY=%s", dbusProp),
+                                         entry("INTERFACE=%s", dbusInterface),
+                                         entry("PATH=%s", objPath.c_str()));
+                         return PLDM_ERROR;
+                     }
+                     return PLDM_SUCCESS;
+                 }}};
+
+        int rc = PLDM_SUCCESS;
+        auto paths = get(effecterId);
+        for (uint8_t currState = 0; currState < compEffecterCnt; ++currState)
+        {
+            std::vector<StateSetNum> allowed{};
+            // computation is based on table 79 from DSP0248 v1.1.1
+            uint8_t bitfieldIndex = stateField[currState].effecter_state / 8;
+            uint8_t bit =
+                stateField[currState].effecter_state - (8 * bitfieldIndex);
+            if (states->possible_states_size < bitfieldIndex ||
+                !(states->states[bitfieldIndex].byte & (1 << bit)))
+            {
+                log<level::ERR>(
+                    "Invalid state set value",
+                    entry("EFFECTER_ID=%d", effecterId),
+                    entry("VALUE=%d", stateField[currState].effecter_state),
+                    entry("COMPOSITE_EFFECTER_ID=%d", currState),
+                    entry("DBUS_PATH=%c", paths[currState].c_str()));
+                rc = PLDM_PLATFORM_SET_EFFECTER_UNSUPPORTED_SENSORSTATE;
+                break;
+            }
+            auto iter = effecterToDbusEntries.find(states->state_set_id);
+            if (iter == effecterToDbusEntries.end())
+            {
+                uint16_t setId = states->state_set_id;
+                log<level::ERR>(
+                    "Did not find the state set for the state effecter pdr  ",
+                    entry("STATE=%d", setId),
+                    entry("EFFECTER_ID=%d", effecterId));
+                rc = PLDM_PLATFORM_INVALID_STATE_VALUE;
+                break;
+            }
+            if (stateField[currState].set_request == PLDM_REQUEST_SET)
+            {
+                rc = iter->second(paths[currState], currState);
+                if (rc != PLDM_SUCCESS)
+                {
+                    break;
+                }
+            }
+            uint8_t* nextState =
+                reinterpret_cast<uint8_t*>(states) +
+                sizeof(state_effecter_possible_states) -
+                sizeof(states->states) +
+                (states->possible_states_size * sizeof(states->states));
+            states =
+                reinterpret_cast<state_effecter_possible_states*>(nextState);
+        }
+        return rc;
+    }
+};
+
+} // namespace platform
 } // namespace responder
 } // namespace pldm
diff --git a/oem/ibm/libpldmresponder/file_io.cpp b/oem/ibm/libpldmresponder/file_io.cpp
index 05051b6..963a6b6 100644
--- a/oem/ibm/libpldmresponder/file_io.cpp
+++ b/oem/ibm/libpldmresponder/file_io.cpp
@@ -5,7 +5,6 @@
 #include "file_io_by_type.hpp"
 #include "file_table.hpp"
 #include "libpldmresponder/utils.hpp"
-#include "registration.hpp"
 #include "xyz/openbmc_project/Common/error.hpp"
 
 #include <fcntl.h>
@@ -31,28 +30,6 @@
 namespace responder
 {
 
-namespace oem_ibm
-{
-
-void registerHandlers()
-{
-    registerHandler(PLDM_OEM, PLDM_GET_FILE_TABLE, std::move(getFileTable));
-    registerHandler(PLDM_OEM, PLDM_READ_FILE_INTO_MEMORY,
-                    std::move(readFileIntoMemory));
-    registerHandler(PLDM_OEM, PLDM_WRITE_FILE_FROM_MEMORY,
-                    std::move(writeFileFromMemory));
-    registerHandler(PLDM_OEM, PLDM_READ_FILE, std::move(readFile));
-    registerHandler(PLDM_OEM, PLDM_WRITE_FILE, std::move(writeFile));
-    registerHandler(PLDM_OEM, PLDM_WRITE_FILE_BY_TYPE_FROM_MEMORY,
-                    std::move(writeFileByTypeFromMemory));
-    registerHandler(PLDM_OEM, PLDM_READ_FILE_BY_TYPE_INTO_MEMORY,
-                    std::move(readFileByTypeIntoMemory));
-    registerHandler(PLDM_OEM, PLDM_READ_FILE_BY_TYPE,
-                    std::move(readFileByType));
-}
-
-} // namespace oem_ibm
-
 namespace fs = std::filesystem;
 using namespace phosphor::logging;
 
@@ -173,7 +150,11 @@
 
 } // namespace dma
 
-Response readFileIntoMemory(const pldm_msg* request, size_t payloadLength)
+namespace oem_ibm
+{
+
+Response Handler::readFileIntoMemory(const pldm_msg* request,
+                                     size_t payloadLength)
 {
     uint32_t fileHandle = 0;
     uint32_t offset = 0;
@@ -254,7 +235,8 @@
                             request->hdr.instance_id);
 }
 
-Response writeFileFromMemory(const pldm_msg* request, size_t payloadLength)
+Response Handler::writeFileFromMemory(const pldm_msg* request,
+                                      size_t payloadLength)
 {
     uint32_t fileHandle = 0;
     uint32_t offset = 0;
@@ -330,7 +312,7 @@
                             request->hdr.instance_id);
 }
 
-Response getFileTable(const pldm_msg* request, size_t payloadLength)
+Response Handler::getFileTable(const pldm_msg* request, size_t payloadLength)
 {
     uint32_t transferHandle = 0;
     uint8_t transferFlag = 0;
@@ -385,7 +367,7 @@
     return response;
 }
 
-Response readFile(const pldm_msg* request, size_t payloadLength)
+Response Handler::readFile(const pldm_msg* request, size_t payloadLength)
 {
     uint32_t fileHandle = 0;
     uint32_t offset = 0;
@@ -465,7 +447,7 @@
     return response;
 }
 
-Response writeFile(const pldm_msg* request, size_t payloadLength)
+Response Handler::writeFile(const pldm_msg* request, size_t payloadLength)
 {
     uint32_t fileHandle = 0;
     uint32_t offset = 0;
@@ -601,20 +583,21 @@
     return response;
 }
 
-Response writeFileByTypeFromMemory(const pldm_msg* request,
-                                   size_t payloadLength)
+Response Handler::writeFileByTypeFromMemory(const pldm_msg* request,
+                                            size_t payloadLength)
 {
     return rwFileByTypeIntoMemory(PLDM_WRITE_FILE_BY_TYPE_FROM_MEMORY, request,
                                   payloadLength);
 }
 
-Response readFileByTypeIntoMemory(const pldm_msg* request, size_t payloadLength)
+Response Handler::readFileByTypeIntoMemory(const pldm_msg* request,
+                                           size_t payloadLength)
 {
     return rwFileByTypeIntoMemory(PLDM_READ_FILE_BY_TYPE_INTO_MEMORY, request,
                                   payloadLength);
 }
 
-Response readFileByType(const pldm_msg* request, size_t payloadLength)
+Response Handler::readFileByType(const pldm_msg* request, size_t payloadLength)
 {
     Response response(sizeof(pldm_msg_hdr) + PLDM_RW_FILE_BY_TYPE_RESP_BYTES);
     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
@@ -661,5 +644,6 @@
     return response;
 }
 
+} // namespace oem_ibm
 } // namespace responder
 } // namespace pldm
diff --git a/oem/ibm/libpldmresponder/file_io.hpp b/oem/ibm/libpldmresponder/file_io.hpp
index 07a13aa..231222c 100644
--- a/oem/ibm/libpldmresponder/file_io.hpp
+++ b/oem/ibm/libpldmresponder/file_io.hpp
@@ -1,5 +1,7 @@
 #pragma once
 
+#include "handler.hpp"
+
 #include <stdint.h>
 #include <unistd.h>
 
@@ -11,19 +13,8 @@
 
 namespace pldm
 {
-
 namespace responder
 {
-
-namespace oem_ibm
-{
-/** @brief Register handlers for command from the platform spec
- */
-void registerHandlers();
-} // namespace oem_ibm
-
-using Response = std::vector<uint8_t>;
-
 namespace dma
 {
 
@@ -121,79 +112,128 @@
 
 } // namespace dma
 
-/** @brief Handler for readFileIntoMemory command
- *
- *  @param[in] request - pointer to PLDM request payload
- *  @param[in] payloadLength - length of the message
- *
- *  @return PLDM response message
- */
-Response readFileIntoMemory(const pldm_msg* request, size_t payloadLength);
+namespace oem_ibm
+{
 
-/** @brief Handler for writeFileIntoMemory command
- *
- *  @param[in] request - pointer to PLDM request payload
- *  @param[in] payloadLength - length of the message
- *
- *  @return PLDM response message
- */
-Response writeFileFromMemory(const pldm_msg* request, size_t payloadLength);
+class Handler : public CmdHandler
+{
+  public:
+    Handler()
+    {
+        handlers.emplace(PLDM_READ_FILE_INTO_MEMORY,
+                         [this](const pldm_msg* request, size_t payloadLength) {
+                             return this->readFileIntoMemory(request,
+                                                             payloadLength);
+                         });
+        handlers.emplace(PLDM_WRITE_FILE_FROM_MEMORY,
+                         [this](const pldm_msg* request, size_t payloadLength) {
+                             return this->writeFileFromMemory(request,
+                                                              payloadLength);
+                         });
+        handlers.emplace(PLDM_WRITE_FILE_BY_TYPE_FROM_MEMORY,
+                         [this](const pldm_msg* request, size_t payloadLength) {
+                             return this->writeFileByTypeFromMemory(
+                                 request, payloadLength);
+                         });
+        handlers.emplace(PLDM_READ_FILE_BY_TYPE_INTO_MEMORY,
+                         [this](const pldm_msg* request, size_t payloadLength) {
+                             return this->readFileByTypeIntoMemory(
+                                 request, payloadLength);
+                         });
+        handlers.emplace(PLDM_READ_FILE_BY_TYPE, [this](const pldm_msg* request,
+                                                        size_t payloadLength) {
+            return this->readFileByType(request, payloadLength);
+        });
+        handlers.emplace(PLDM_GET_FILE_TABLE,
+                         [this](const pldm_msg* request, size_t payloadLength) {
+                             return this->getFileTable(request, payloadLength);
+                         });
+        handlers.emplace(PLDM_READ_FILE,
+                         [this](const pldm_msg* request, size_t payloadLength) {
+                             return this->readFile(request, payloadLength);
+                         });
+        handlers.emplace(PLDM_WRITE_FILE,
+                         [this](const pldm_msg* request, size_t payloadLength) {
+                             return this->writeFile(request, payloadLength);
+                         });
+    }
 
-/** @brief Handler for writeFileByTypeFromMemory command
- *
- *  @param[in] request - pointer to PLDM request payload
- *  @param[in] payloadLength - length of the message
- *
- *  @return PLDM response message
- */
+    /** @brief Handler for readFileIntoMemory command
+     *
+     *  @param[in] request - pointer to PLDM request payload
+     *  @param[in] payloadLength - length of the message
+     *
+     *  @return PLDM response message
+     */
+    Response readFileIntoMemory(const pldm_msg* request, size_t payloadLength);
 
-Response writeFileByTypeFromMemory(const pldm_msg* request,
-                                   size_t payloadLength);
+    /** @brief Handler for writeFileIntoMemory command
+     *
+     *  @param[in] request - pointer to PLDM request payload
+     *  @param[in] payloadLength - length of the message
+     *
+     *  @return PLDM response message
+     */
+    Response writeFileFromMemory(const pldm_msg* request, size_t payloadLength);
 
-/** @brief Handler for readFileByTypeIntoMemory command
- *
- *  @param[in] request - pointer to PLDM request payload
- *  @param[in] payloadLength - length of the message
- *
- *  @return PLDM response message
- */
-Response readFileByTypeIntoMemory(const pldm_msg* request,
-                                  size_t payloadLength);
+    /** @brief Handler for writeFileByTypeFromMemory command
+     *
+     *  @param[in] request - pointer to PLDM request payload
+     *  @param[in] payloadLength - length of the message
+     *
+     *  @return PLDM response message
+     */
 
-/** @brief Handler for readFileByType command
- *
- *  @param[in] request - pointer to PLDM request payload
- *  @param[in] payloadLength - length of the message
- *
- *  @return PLDM response message
- */
-Response readFileByType(const pldm_msg* request, size_t payloadLength);
+    Response writeFileByTypeFromMemory(const pldm_msg* request,
+                                       size_t payloadLength);
 
-/** @brief Handler for GetFileTable command
- *
- *  @param[in] request - pointer to PLDM request payload
- *  @param[in] payloadLength - length of the message payload
- *
- *  @return PLDM response message
- */
-Response getFileTable(const pldm_msg* request, size_t payloadLength);
+    /** @brief Handler for readFileByTypeIntoMemory command
+     *
+     *  @param[in] request - pointer to PLDM request payload
+     *  @param[in] payloadLength - length of the message
+     *
+     *  @return PLDM response message
+     */
+    Response readFileByTypeIntoMemory(const pldm_msg* request,
+                                      size_t payloadLength);
 
-/** @brief Handler for readFile command
- *
- *  @param[in] request - PLDM request msg
- *  @param[in] payloadLength - length of the message payload
- *
- *  @return PLDM response message
- */
-Response readFile(const pldm_msg* request, size_t payloadLength);
+    /** @brief Handler for readFileByType command
+     *
+     *  @param[in] request - pointer to PLDM request payload
+     *  @param[in] payloadLength - length of the message
+     *
+     *  @return PLDM response message
+     */
+    Response readFileByType(const pldm_msg* request, size_t payloadLength);
 
-/** @brief Handler for writeFile command
- *
- *  @param[in] request - PLDM request msg
- *  @param[in] payloadLength - length of the message payload
- *
- *  @return PLDM response message
- */
-Response writeFile(const pldm_msg* request, size_t payloadLength);
+    /** @brief Handler for GetFileTable command
+     *
+     *  @param[in] request - pointer to PLDM request payload
+     *  @param[in] payloadLength - length of the message payload
+     *
+     *  @return PLDM response message
+     */
+    Response getFileTable(const pldm_msg* request, size_t payloadLength);
+
+    /** @brief Handler for readFile command
+     *
+     *  @param[in] request - PLDM request msg
+     *  @param[in] payloadLength - length of the message payload
+     *
+     *  @return PLDM response message
+     */
+    Response readFile(const pldm_msg* request, size_t payloadLength);
+
+    /** @brief Handler for writeFile command
+     *
+     *  @param[in] request - PLDM request msg
+     *  @param[in] payloadLength - length of the message payload
+     *
+     *  @return PLDM response message
+     */
+    Response writeFile(const pldm_msg* request, size_t payloadLength);
+};
+
+} // namespace oem_ibm
 } // namespace responder
 } // namespace pldm
diff --git a/oem/ibm/test/libpldmresponder_fileio_test.cpp b/oem/ibm/test/libpldmresponder_fileio_test.cpp
index 3894ff3..e62e8e1 100644
--- a/oem/ibm/test/libpldmresponder_fileio_test.cpp
+++ b/oem/ibm/test/libpldmresponder_fileio_test.cpp
@@ -20,6 +20,7 @@
 namespace fs = std::filesystem;
 using Json = nlohmann::json;
 using namespace pldm::filetable;
+using namespace pldm::responder;
 
 class TestFileTable : public testing::Test
 {
@@ -213,7 +214,8 @@
            &address, sizeof(address));
 
     // Pass invalid payload length
-    auto response = readFileIntoMemory(request, 0);
+    oem_ibm::Handler handler;
+    auto response = handler.readFileIntoMemory(request, 0);
     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
     ASSERT_EQ(responsePtr->payload[0], PLDM_ERROR_INVALID_LENGTH);
 }
@@ -242,7 +244,8 @@
     // Initialise the file table with 2 valid file handles 0 & 1.
     auto& table = buildFileTable(fileTableConfig.c_str());
 
-    auto response = readFileIntoMemory(request, requestPayloadLength);
+    oem_ibm::Handler handler;
+    auto response = handler.readFileIntoMemory(request, requestPayloadLength);
     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
     ASSERT_EQ(responsePtr->payload[0], PLDM_INVALID_FILE_HANDLE);
     // Clear the file table contents.
@@ -272,7 +275,8 @@
     using namespace pldm::filetable;
     auto& table = buildFileTable(fileTableConfig.c_str());
 
-    auto response = readFileIntoMemory(request, requestPayloadLength);
+    oem_ibm::Handler handler;
+    auto response = handler.readFileIntoMemory(request, requestPayloadLength);
     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
     ASSERT_EQ(responsePtr->payload[0], PLDM_DATA_OUT_OF_RANGE);
     // Clear the file table contents.
@@ -302,7 +306,8 @@
     using namespace pldm::filetable;
     auto& table = buildFileTable(fileTableConfig.c_str());
 
-    auto response = readFileIntoMemory(request, requestPayloadLength);
+    oem_ibm::Handler handler;
+    auto response = handler.readFileIntoMemory(request, requestPayloadLength);
     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
     ASSERT_EQ(responsePtr->payload[0], PLDM_INVALID_READ_LENGTH);
     // Clear the file table contents.
@@ -335,7 +340,8 @@
     using namespace pldm::filetable;
     auto& table = buildFileTable(fileTableConfig.c_str());
 
-    auto response = readFileIntoMemory(request, requestPayloadLength);
+    oem_ibm::Handler handler;
+    auto response = handler.readFileIntoMemory(request, requestPayloadLength);
     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
     ASSERT_EQ(responsePtr->payload[0], PLDM_INVALID_READ_LENGTH);
     // Clear the file table contents.
@@ -362,12 +368,13 @@
            &address, sizeof(address));
 
     // Pass invalid payload length
-    auto response = writeFileFromMemory(request, 0);
+    oem_ibm::Handler handler;
+    auto response = handler.writeFileFromMemory(request, 0);
     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
     ASSERT_EQ(responsePtr->payload[0], PLDM_ERROR_INVALID_LENGTH);
 
     // The length field is not a multiple of DMA minsize
-    response = writeFileFromMemory(request, requestPayloadLength);
+    response = handler.writeFileFromMemory(request, requestPayloadLength);
     responsePtr = reinterpret_cast<pldm_msg*>(response.data());
     ASSERT_EQ(responsePtr->payload[0], PLDM_INVALID_WRITE_LENGTH);
 }
@@ -396,7 +403,8 @@
     // Initialise the file table with 2 valid file handles 0 & 1.
     auto& table = buildFileTable(fileTableConfig.c_str());
 
-    auto response = writeFileFromMemory(request, requestPayloadLength);
+    oem_ibm::Handler handler;
+    auto response = handler.writeFileFromMemory(request, requestPayloadLength);
     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
     ASSERT_EQ(responsePtr->payload[0], PLDM_INVALID_FILE_HANDLE);
     // Clear the file table contents.
@@ -427,7 +435,8 @@
     // Initialise the file table with 2 valid file handles 0 & 1.
     auto& table = buildFileTable(TestFileTable::fileTableConfig.c_str());
 
-    auto response = writeFileFromMemory(request, requestPayloadLength);
+    oem_ibm::Handler handler;
+    auto response = handler.writeFileFromMemory(request, requestPayloadLength);
     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
     ASSERT_EQ(responsePtr->payload[0], PLDM_DATA_OUT_OF_RANGE);
     // Clear the file table contents.
@@ -495,7 +504,8 @@
     request->operation_flag = opFlag;
     request->table_type = type;
 
-    auto response = getFileTable(requestMsgPtr, requestPayloadLength);
+    oem_ibm::Handler handler;
+    auto response = handler.getFileTable(requestMsgPtr, requestPayloadLength);
     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
     ASSERT_EQ(responsePtr->payload[0], PLDM_SUCCESS);
     size_t offsetSize = sizeof(responsePtr->payload[0]);
@@ -517,7 +527,8 @@
     auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
 
     // Pass invalid command payload length
-    auto response = getFileTable(request, 0);
+    oem_ibm::Handler handler;
+    auto response = handler.getFileTable(request, 0);
     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
     ASSERT_EQ(responsePtr->payload[0], PLDM_ERROR_INVALID_LENGTH);
 }
@@ -538,7 +549,8 @@
     request->operation_flag = opFlag;
     request->table_type = type;
 
-    auto response = getFileTable(requestMsgPtr, requestPayloadLength);
+    oem_ibm::Handler handler;
+    auto response = handler.getFileTable(requestMsgPtr, requestPayloadLength);
     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
     ASSERT_EQ(responsePtr->payload[0], PLDM_INVALID_FILE_TABLE_TYPE);
 }
@@ -565,21 +577,22 @@
     auto& table = buildFileTable(fileTableConfig.c_str());
 
     // Invalid payload length
-    auto response = readFile(requestMsgPtr, 0);
+    oem_ibm::Handler handler;
+    auto response = handler.readFile(requestMsgPtr, 0);
     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
     ASSERT_EQ(responsePtr->payload[0], PLDM_ERROR_INVALID_LENGTH);
 
     // Data out of range. File size is 1024, offset = 1024 is invalid.
     request->offset = 1024;
 
-    response = readFile(requestMsgPtr, payload_length);
+    response = handler.readFile(requestMsgPtr, payload_length);
     responsePtr = reinterpret_cast<pldm_msg*>(response.data());
     ASSERT_EQ(responsePtr->payload[0], PLDM_DATA_OUT_OF_RANGE);
 
     // Invalid file handle
     request->file_handle = 2;
 
-    response = readFile(requestMsgPtr, payload_length);
+    response = handler.readFile(requestMsgPtr, payload_length);
     responsePtr = reinterpret_cast<pldm_msg*>(response.data());
     ASSERT_EQ(responsePtr->payload[0], PLDM_INVALID_FILE_HANDLE);
 
@@ -614,7 +627,8 @@
     std::vector<char> buffer(length);
     stream.read(buffer.data(), length);
 
-    auto responseMsg = readFile(requestMsgPtr, payload_length);
+    oem_ibm::Handler handler;
+    auto responseMsg = handler.readFile(requestMsgPtr, payload_length);
     auto response = reinterpret_cast<pldm_read_file_resp*>(
         responseMsg.data() + sizeof(pldm_msg_hdr));
     ASSERT_EQ(response->completion_code, PLDM_SUCCESS);
@@ -630,7 +644,7 @@
     buffer.resize(fileSize - request->offset);
     stream.read(buffer.data(), (fileSize - request->offset));
 
-    responseMsg = readFile(requestMsgPtr, payload_length);
+    responseMsg = handler.readFile(requestMsgPtr, payload_length);
     response = reinterpret_cast<pldm_read_file_resp*>(responseMsg.data() +
                                                       sizeof(pldm_msg_hdr));
     ASSERT_EQ(response->completion_code, PLDM_SUCCESS);
@@ -663,21 +677,22 @@
     request->length = length;
 
     // Invalid payload length
-    auto response = writeFile(requestMsgPtr, 0);
+    oem_ibm::Handler handler;
+    auto response = handler.writeFile(requestMsgPtr, 0);
     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
     ASSERT_EQ(responsePtr->payload[0], PLDM_ERROR_INVALID_LENGTH);
 
     // Data out of range. File size is 1024, offset = 1024 is invalid.
     request->offset = 1024;
 
-    response = writeFile(requestMsgPtr, payload_length);
+    response = handler.writeFile(requestMsgPtr, payload_length);
     responsePtr = reinterpret_cast<pldm_msg*>(response.data());
     ASSERT_EQ(responsePtr->payload[0], PLDM_DATA_OUT_OF_RANGE);
 
     // Invalid file handle
     request->file_handle = 2;
 
-    response = writeFile(requestMsgPtr, payload_length);
+    response = handler.writeFile(requestMsgPtr, payload_length);
     responsePtr = reinterpret_cast<pldm_msg*>(response.data());
     ASSERT_EQ(responsePtr->payload[0], PLDM_INVALID_FILE_HANDLE);
 
@@ -709,7 +724,8 @@
     request->length = length;
     memcpy(request->file_data, fileData.data(), fileData.size());
 
-    auto responseMsg = writeFile(requestMsgPtr, payload_length);
+    oem_ibm::Handler handler;
+    auto responseMsg = handler.writeFile(requestMsgPtr, payload_length);
     auto response = reinterpret_cast<pldm_read_file_resp*>(
         responseMsg.data() + sizeof(pldm_msg_hdr));
 
@@ -741,7 +757,8 @@
     request->length = 17;
     request->address = 0;
 
-    auto response = writeFileByTypeFromMemory(req, 0);
+    oem_ibm::Handler handler;
+    auto response = handler.writeFileByTypeFromMemory(req, 0);
     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
 
     struct pldm_read_write_file_by_type_memory_resp* resp =
@@ -749,7 +766,7 @@
             responsePtr->payload);
     ASSERT_EQ(PLDM_ERROR_INVALID_LENGTH, resp->completion_code);
 
-    response = writeFileByTypeFromMemory(req, requestPayloadLength);
+    response = handler.writeFileByTypeFromMemory(req, requestPayloadLength);
     responsePtr = reinterpret_cast<pldm_msg*>(response.data());
 
     resp = reinterpret_cast<struct pldm_read_write_file_by_type_memory_resp*>(
@@ -792,23 +809,24 @@
     request->length = 17;
     request->address = 0;
 
-    auto response = readFileByTypeIntoMemory(req, 0);
+    oem_ibm::Handler handler;
+    auto response = handler.readFileByTypeIntoMemory(req, 0);
     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
     struct pldm_read_write_file_by_type_memory_resp* resp =
         reinterpret_cast<struct pldm_read_write_file_by_type_memory_resp*>(
             responsePtr->payload);
     ASSERT_EQ(PLDM_ERROR_INVALID_LENGTH, resp->completion_code);
 
-    response =
-        readFileByTypeIntoMemory(req, PLDM_RW_FILE_BY_TYPE_MEM_REQ_BYTES);
+    response = handler.readFileByTypeIntoMemory(
+        req, PLDM_RW_FILE_BY_TYPE_MEM_REQ_BYTES);
     responsePtr = reinterpret_cast<pldm_msg*>(response.data());
     resp = reinterpret_cast<struct pldm_read_write_file_by_type_memory_resp*>(
         responsePtr->payload);
     ASSERT_EQ(PLDM_INVALID_WRITE_LENGTH, resp->completion_code);
 
     request->length = 16;
-    response =
-        readFileByTypeIntoMemory(req, PLDM_RW_FILE_BY_TYPE_MEM_REQ_BYTES);
+    response = handler.readFileByTypeIntoMemory(
+        req, PLDM_RW_FILE_BY_TYPE_MEM_REQ_BYTES);
     responsePtr = reinterpret_cast<pldm_msg*>(response.data());
     resp = reinterpret_cast<struct pldm_read_write_file_by_type_memory_resp*>(
         responsePtr->payload);
@@ -829,14 +847,15 @@
     request->offset = 0;
     request->length = 13;
 
-    auto response = readFileByType(req, 0);
+    oem_ibm::Handler handler;
+    auto response = handler.readFileByType(req, 0);
     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
     struct pldm_read_write_file_by_type_resp* resp =
         reinterpret_cast<struct pldm_read_write_file_by_type_resp*>(
             responsePtr->payload);
     ASSERT_EQ(PLDM_ERROR_INVALID_LENGTH, resp->completion_code);
 
-    response = readFileByType(req, payloadLength);
+    response = handler.readFileByType(req, payloadLength);
     responsePtr = reinterpret_cast<pldm_msg*>(response.data());
     resp = reinterpret_cast<struct pldm_read_write_file_by_type_resp*>(
         responsePtr->payload);
diff --git a/pldmd.cpp b/pldmd.cpp
index 39bee54..1b37726 100644
--- a/pldmd.cpp
+++ b/pldmd.cpp
@@ -1,9 +1,9 @@
 #include "dbus_impl_requester.hpp"
+#include "invoker.hpp"
 #include "libpldmresponder/base.hpp"
 #include "libpldmresponder/bios.hpp"
 #include "libpldmresponder/platform.hpp"
 #include "libpldmresponder/utils.hpp"
-#include "registration.hpp"
 
 #include <err.h>
 #include <getopt.h>
@@ -23,6 +23,7 @@
 #include <sdeventplus/event.hpp>
 #include <sdeventplus/source/io.hpp>
 #include <sstream>
+#include <stdexcept>
 #include <string>
 #include <vector>
 
@@ -36,13 +37,14 @@
 
 constexpr uint8_t MCTP_MSG_TYPE_PLDM = 1;
 
+using namespace pldm::responder;
 using namespace phosphor::logging;
 using namespace pldm;
 using namespace sdeventplus;
 using namespace sdeventplus::source;
 
 static Response processRxMsg(const std::vector<uint8_t>& requestMsg,
-                             dbus_api::Requester& requester)
+                             Invoker& invoker, dbus_api::Requester& requester)
 {
 
     Response response;
@@ -60,9 +62,12 @@
         auto request = reinterpret_cast<const pldm_msg*>(hdr);
         size_t requestLen = requestMsg.size() - sizeof(struct pldm_msg_hdr) -
                             sizeof(eid) - sizeof(type);
-        response = pldm::responder::invokeHandler(
-            hdrFields.pldm_type, hdrFields.command, request, requestLen);
-        if (response.empty())
+        try
+        {
+            response = invoker.handle(hdrFields.pldm_type, hdrFields.command,
+                                      request, requestLen);
+        }
+        catch (const std::out_of_range& e)
         {
             uint8_t completion_code = PLDM_ERROR_UNSUPPORTED_PLDM_CMD;
             response.resize(sizeof(pldm_msg_hdr));
@@ -140,12 +145,14 @@
             break;
     }
 
-    pldm::responder::base::registerHandlers();
-    pldm::responder::bios::registerHandlers();
-    pldm::responder::platform::registerHandlers();
+    Invoker invoker{};
+    invoker.registerHandler(PLDM_BASE, std::make_unique<base::Handler>());
+    invoker.registerHandler(PLDM_BIOS, std::make_unique<bios::Handler>());
+    invoker.registerHandler(PLDM_PLATFORM,
+                            std::make_unique<platform::Handler>());
 
 #ifdef OEM_IBM
-    pldm::responder::oem_ibm::registerHandlers();
+    invoker.registerHandler(PLDM_OEM, std::make_unique<oem_ibm::Handler>());
 #endif
 
     /* Create local socket. */
@@ -188,8 +195,8 @@
 
     auto bus = sdbusplus::bus::new_default();
     dbus_api::Requester dbusImplReq(bus, "/xyz/openbmc_project/pldm");
-    auto callback = [verbose, &dbusImplReq](IO& /*io*/, int fd,
-                                            uint32_t revents) {
+    auto callback = [verbose, &invoker, &dbusImplReq](IO& /*io*/, int fd,
+                                                      uint32_t revents) {
         if (!(revents & EPOLLIN))
         {
             return;
@@ -240,7 +247,8 @@
                 else
                 {
                     // process message and send response
-                    auto response = processRxMsg(requestMsg, dbusImplReq);
+                    auto response =
+                        processRxMsg(requestMsg, invoker, dbusImplReq);
                     if (!response.empty())
                     {
                         if (verbose)
diff --git a/registration.cpp b/registration.cpp
deleted file mode 100644
index 7fb7957..0000000
--- a/registration.cpp
+++ /dev/null
@@ -1,63 +0,0 @@
-#include "registration.hpp"
-
-#include <map>
-#include <phosphor-logging/log.hpp>
-
-using namespace phosphor::logging;
-
-namespace pldm
-{
-
-namespace responder
-{
-
-namespace internal
-{
-using Command = uint8_t;
-using CommandHandler = std::map<Command, Handler>;
-using Type = uint8_t;
-std::map<Type, CommandHandler> typeHandlers;
-} // namespace internal
-
-void registerHandler(uint8_t pldmType, uint8_t pldmCommand, Handler&& handler)
-{
-    using namespace internal;
-    CommandHandler& ch = typeHandlers[pldmType];
-    ch.emplace(pldmCommand, std::move(handler));
-}
-
-Response invokeHandler(uint8_t pldmType, uint8_t pldmCommand,
-                       const pldm_msg* request, size_t payloadLength)
-{
-    using namespace internal;
-    Response response;
-    if (!(typeHandlers.end() == typeHandlers.find(pldmType)))
-    {
-        if (!((typeHandlers.at(pldmType)).end() ==
-              (typeHandlers.at(pldmType)).find(pldmCommand)))
-        {
-            response = typeHandlers.at(pldmType).at(pldmCommand)(request,
-                                                                 payloadLength);
-            if (response.empty())
-            {
-                log<level::ERR>("Encountered invalid response");
-            }
-        }
-        else
-        {
-            log<level::ERR>("Unsupported PLDM command",
-                            entry("TYPE=0x%02x", pldmType),
-                            entry("COMMAND=0x%02x", pldmCommand));
-        }
-    }
-    else
-    {
-        log<level::ERR>("Unsupported PLDM TYPE",
-                        entry("TYPE=0x%02x", pldmType));
-    }
-
-    return response;
-}
-
-} // namespace responder
-} // namespace pldm
diff --git a/registration.hpp b/registration.hpp
deleted file mode 100644
index 0bd496f..0000000
--- a/registration.hpp
+++ /dev/null
@@ -1,39 +0,0 @@
-#pragma once
-
-#include <functional>
-#include <map>
-
-#include "libpldm/base.h"
-
-namespace pldm
-{
-
-using Response = std::vector<uint8_t>;
-
-namespace responder
-{
-
-using Handler =
-    std::function<Response(const pldm_msg* request, size_t payloadLength)>;
-
-/** @brief Register a handler for input PLDM command
- *
- *  @param[in] pldmType - PLDM type code
- *  @param[in] pldmCommand - PLDM command code
- *  @param[in] handler - PLDM command handler
- */
-void registerHandler(uint8_t pldmType, uint8_t pldmCommand, Handler&& handler);
-
-/** @brief Invoke a handler for input PLDM command
- *
- *  @param[in] pldmType - PLDM type code
- *  @param[in] pldmCommand - PLDM command code
- *  @param[in] request - PLDM request message
- *  @param[in] payloadLength - PLDM request message length
- *  @return PLDM Response message
- */
-Response invokeHandler(uint8_t pldmType, uint8_t pldmCommand,
-                       const pldm_msg* request, size_t payloadLength);
-
-} // namespace responder
-} // namespace pldm
diff --git a/test/libpldmresponder_base_test.cpp b/test/libpldmresponder_base_test.cpp
index bbd986a..885ef24 100644
--- a/test/libpldmresponder_base_test.cpp
+++ b/test/libpldmresponder_base_test.cpp
@@ -16,7 +16,8 @@
     auto request = reinterpret_cast<pldm_msg*>(requestPayload.data());
     // payload length will be 0 in this case
     size_t requestPayloadLength = 0;
-    auto response = getPLDMTypes(request, requestPayloadLength);
+    base::Handler handler;
+    auto response = handler.getPLDMTypes(request, requestPayloadLength);
     // Only base type supported at the moment
     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
     uint8_t* payload_ptr = responsePtr->payload;
@@ -33,7 +34,8 @@
         requestPayload{};
     auto request = reinterpret_cast<pldm_msg*>(requestPayload.data());
     size_t requestPayloadLength = requestPayload.size() - sizeof(pldm_msg_hdr);
-    auto response = getPLDMCommands(request, requestPayloadLength);
+    base::Handler handler;
+    auto response = handler.getPLDMCommands(request, requestPayloadLength);
     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
     uint8_t* payload_ptr = responsePtr->payload;
     ASSERT_EQ(payload_ptr[0], 0);
@@ -49,7 +51,8 @@
 
     request->payload[0] = 0xFF;
     size_t requestPayloadLength = requestPayload.size() - sizeof(pldm_msg_hdr);
-    auto response = getPLDMCommands(request, requestPayloadLength);
+    base::Handler handler;
+    auto response = handler.getPLDMCommands(request, requestPayloadLength);
     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
     uint8_t* payload_ptr = responsePtr->payload;
     ASSERT_EQ(payload_ptr[0], PLDM_ERROR_INVALID_PLDM_TYPE);
@@ -72,7 +75,8 @@
 
     ASSERT_EQ(0, rc);
 
-    auto response = getPLDMVersion(request, requestPayloadLength);
+    base::Handler handler;
+    auto response = handler.getPLDMVersion(request, requestPayloadLength);
     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
 
     ASSERT_EQ(responsePtr->payload[0], 0);
@@ -101,7 +105,8 @@
 
     ASSERT_EQ(0, rc);
 
-    auto response = getPLDMVersion(request, requestPayloadLength - 1);
+    base::Handler handler;
+    auto response = handler.getPLDMVersion(request, requestPayloadLength - 1);
     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
 
     ASSERT_EQ(responsePtr->payload[0], PLDM_ERROR_INVALID_LENGTH);
@@ -113,7 +118,7 @@
 
     ASSERT_EQ(0, rc);
 
-    response = getPLDMVersion(request, requestPayloadLength);
+    response = handler.getPLDMVersion(request, requestPayloadLength);
     responsePtr = reinterpret_cast<pldm_msg*>(response.data());
 
     ASSERT_EQ(responsePtr->payload[0], PLDM_ERROR_INVALID_PLDM_TYPE);
@@ -125,7 +130,8 @@
     auto request = reinterpret_cast<pldm_msg*>(requestPayload.data());
     size_t requestPayloadLength = 0;
 
-    auto response = getTID(request, requestPayloadLength);
+    base::Handler handler;
+    auto response = handler.getTID(request, requestPayloadLength);
 
     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
     uint8_t* payload = responsePtr->payload;
diff --git a/test/libpldmresponder_bios_test.cpp b/test/libpldmresponder_bios_test.cpp
index 7271567..1271dda 100644
--- a/test/libpldmresponder_bios_test.cpp
+++ b/test/libpldmresponder_bios_test.cpp
@@ -177,7 +177,7 @@
     table.insert(table.end(), padSize, 0);
     table.insert(table.end(), sizeof(uint32_t) /*checksum*/, 0);
 
-    pldm::responder::traverseBIOSAttrTable(
+    pldm::responder::bios::traverseBIOSAttrTable(
         table, [&](const struct pldm_bios_attr_table_entry* entry) {
             int rc;
             switch (entry->attr_type)
diff --git a/test/libpldmresponder_platform_test.cpp b/test/libpldmresponder_platform_test.cpp
index 6b89b2e..88a6eb4 100644
--- a/test/libpldmresponder_platform_test.cpp
+++ b/test/libpldmresponder_platform_test.cpp
@@ -25,7 +25,8 @@
     using namespace pdr;
     Repo& pdrRepo = get("./pdr_jsons/state_effecter/good");
     ASSERT_EQ(pdrRepo.empty(), false);
-    auto response = getPDR(request, requestPayloadLength);
+    platform::Handler handler;
+    auto response = handler.getPDR(request, requestPayloadLength);
     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
 
     ASSERT_EQ(responsePtr->payload[0], PLDM_SUCCESS);
@@ -59,7 +60,8 @@
     using namespace pdr;
     Repo& pdrRepo = get("./pdr_jsons/state_effecter/good");
     ASSERT_EQ(pdrRepo.empty(), false);
-    auto response = getPDR(request, requestPayloadLength);
+    platform::Handler handler;
+    auto response = handler.getPDR(request, requestPayloadLength);
     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
 
     ASSERT_EQ(responsePtr->payload[0], PLDM_SUCCESS);
@@ -86,7 +88,8 @@
     using namespace pdr;
     Repo& pdrRepo = get("./pdr_jsons/state_effecter/good");
     ASSERT_EQ(pdrRepo.empty(), false);
-    auto response = getPDR(request, requestPayloadLength);
+    platform::Handler handler;
+    auto response = handler.getPDR(request, requestPayloadLength);
     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
 
     ASSERT_EQ(responsePtr->payload[0], PLDM_PLATFORM_INVALID_RECORD_HANDLE);
@@ -105,7 +108,8 @@
     using namespace pdr;
     Repo& pdrRepo = get("./pdr_jsons/state_effecter/good");
     ASSERT_EQ(pdrRepo.empty(), false);
-    auto response = getPDR(request, requestPayloadLength);
+    platform::Handler handler;
+    auto response = handler.getPDR(request, requestPayloadLength);
     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
 
     ASSERT_EQ(responsePtr->payload[0], PLDM_SUCCESS);
@@ -129,7 +133,8 @@
     using namespace pdr;
     Repo& pdrRepo = get("./pdr_jsons/state_effecter/good");
     ASSERT_EQ(pdrRepo.empty(), false);
-    auto response = getPDR(request, requestPayloadLength);
+    platform::Handler handler;
+    auto response = handler.getPDR(request, requestPayloadLength);
 
     // Let's try to find a PDR of type stateEffecter (= 11) and entity type =
     // 100
@@ -141,7 +146,8 @@
         start = request->payload;
         recordHandle = reinterpret_cast<uint32_t*>(start);
         *recordHandle = handle;
-        auto response = getPDR(request, requestPayloadLength);
+        platform::Handler handler;
+        auto response = handler.getPDR(request, requestPayloadLength);
         auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
 
         ASSERT_EQ(responsePtr->payload[0], PLDM_SUCCESS);
@@ -218,8 +224,9 @@
     EXPECT_CALL(handlerObj, setDbusProperty(objPath, bootProgressProp,
                                             bootProgressInf, value))
         .Times(2);
-    auto rc = setStateEffecterStatesHandler<MockdBusHandler>(handlerObj, 0x1,
-                                                             stateField);
+    platform::Handler handler;
+    auto rc = handler.setStateEffecterStatesHandler<MockdBusHandler>(
+        handlerObj, 0x1, stateField);
     ASSERT_EQ(rc, 0);
 }
 
@@ -236,23 +243,24 @@
     stateField.push_back({PLDM_REQUEST_SET, 4});
 
     MockdBusHandler handlerObj;
-    auto rc = setStateEffecterStatesHandler<MockdBusHandler>(handlerObj, 0x1,
-                                                             stateField);
+    platform::Handler handler;
+    auto rc = handler.setStateEffecterStatesHandler<MockdBusHandler>(
+        handlerObj, 0x1, stateField);
     ASSERT_EQ(rc, PLDM_PLATFORM_SET_EFFECTER_UNSUPPORTED_SENSORSTATE);
 
-    rc = setStateEffecterStatesHandler<MockdBusHandler>(handlerObj, 0x9,
-                                                        stateField);
+    rc = handler.setStateEffecterStatesHandler<MockdBusHandler>(handlerObj, 0x9,
+                                                                stateField);
     ASSERT_EQ(rc, PLDM_PLATFORM_INVALID_EFFECTER_ID);
 
     stateField.push_back({PLDM_REQUEST_SET, 4});
-    rc = setStateEffecterStatesHandler<MockdBusHandler>(handlerObj, 0x1,
-                                                        stateField);
+    rc = handler.setStateEffecterStatesHandler<MockdBusHandler>(handlerObj, 0x1,
+                                                                stateField);
     ASSERT_EQ(rc, PLDM_ERROR_INVALID_DATA);
 
     std::vector<set_effecter_state_field> newStateField;
     newStateField.push_back({PLDM_REQUEST_SET, 1});
 
-    rc = setStateEffecterStatesHandler<MockdBusHandler>(handlerObj, 0x2,
-                                                        newStateField);
+    rc = handler.setStateEffecterStatesHandler<MockdBusHandler>(handlerObj, 0x2,
+                                                                newStateField);
     ASSERT_EQ(rc, PLDM_PLATFORM_INVALID_STATE_VALUE);
 }
diff --git a/test/meson.build b/test/meson.build
index ee509db..4019cde 100644
--- a/test/meson.build
+++ b/test/meson.build
@@ -29,6 +29,7 @@
   'libpldm_fru_test',
   'libpldm_utils_test',
   'pldmd_instanceid_test',
+  'pldmd_registration_test',
 ]
 
 if get_option('oem-ibm').enabled()
diff --git a/test/pldmd_registration_test.cpp b/test/pldmd_registration_test.cpp
new file mode 100644
index 0000000..d51efdd
--- /dev/null
+++ b/test/pldmd_registration_test.cpp
@@ -0,0 +1,49 @@
+#include "invoker.hpp"
+
+#include <stdexcept>
+
+#include "libpldm/base.h"
+
+#include <gtest/gtest.h>
+
+using namespace pldm;
+using namespace pldm::responder;
+constexpr Command testCmd = 0xFF;
+constexpr Type testType = 0xFF;
+
+class TestHandler : public CmdHandler
+{
+  public:
+    TestHandler()
+    {
+        handlers.emplace(testCmd,
+                         [this](const pldm_msg* request, size_t payloadLength) {
+                             return this->handle(request, payloadLength);
+                         });
+    }
+
+    Response handle(const pldm_msg* /*request*/, size_t /*payloadLength*/)
+    {
+        return {100, 200};
+    }
+};
+
+TEST(Registration, testSuccess)
+{
+    Invoker invoker{};
+    invoker.registerHandler(testType, std::make_unique<TestHandler>());
+    auto result = invoker.handle(testType, testCmd, nullptr, 0);
+    ASSERT_EQ(result[0], 100);
+    ASSERT_EQ(result[1], 200);
+}
+
+TEST(Registration, testFailure)
+{
+    Invoker invoker{};
+    ASSERT_THROW(invoker.handle(testType, testCmd, nullptr, 0),
+                 std::out_of_range);
+    invoker.registerHandler(testType, std::make_unique<TestHandler>());
+    uint8_t badCmd = 0xFE;
+    ASSERT_THROW(invoker.handle(testType, badCmd, nullptr, 0),
+                 std::out_of_range);
+}