Refactor mapper calls to use getAssociatedSubTreePathsById

This commit refactors power_supply to use the new ObjectMapper method
`getAssociatedSubTreePathsById`. Replaced the two separate mapper calls
`getValidChassisPath` and `getAssociatedSubTreePaths` with one call to
`getAssociatedSubTreePathsById`.

Tested: Validator passed
1. List Powersupplies in the system

```
curl -k https://${bmc}/redfish/v1/Chassis/chassis/PowerSubsystem/PowerSupplies
{
  "@odata.id": "/redfish/v1/Chassis/chassis/PowerSubsystem/PowerSupplies",
  "@odata.type": "#PowerSupplyCollection.PowerSupplyCollection",
  "Description": "The collection of PowerSupply resource instances.",
  "Members": [
    {
      "@odata.id": "/redfish/v1/Chassis/chassis/PowerSubsystem/PowerSupplies/powersupply0"
    },
    {
      "@odata.id": "/redfish/v1/Chassis/chassis/PowerSubsystem/PowerSupplies/powersupply1"
    },
    {
      "@odata.id": "/redfish/v1/Chassis/chassis/PowerSubsystem/PowerSupplies/powersupply2"
    },
    {
      "@odata.id": "/redfish/v1/Chassis/chassis/PowerSubsystem/PowerSupplies/powersupply3"
    }
  ],
  "Members@odata.count": 4,
  "Name": "Power Supply Collection"
}
```

2. List powersupply0 properties

```
curl -k https://${bmc}/redfish/v1/Chassis/chassis/PowerSubsystem/PowerSupplies/powersupply0
{
  "@odata.id": "/redfish/v1/Chassis/chassis/PowerSubsystem/PowerSupplies/powersupply0",
  "@odata.type": "#PowerSupply.v1_5_0.PowerSupply",
  "EfficiencyRatings": [
    {
      "EfficiencyPercent": 90
    }
  ],
  "FirmwareVersion": "030303030303",
  "Id": "powersupply0",
  "Location": {
    "PartLocation": {
      "ServiceLabel": "U78DB.ND0.WZS002U-E0"
    }
  },
  "LocationIndicatorActive": false,
  "Manufacturer": "",
  "Model": "2B1E",
  "Name": "Power Supply",
  "PartNumber": "03FP729",
  "SerialNumber": "YL30NH1BN229",
  "SparePartNumber": "03FP728",
  "Status": {
    "Health": "OK",
    "State": "Enabled"
  }
}
```

3. Error condition, list unknown powersupply

```
curl -k https://${bmc}/redfish/v1/Chassis/chassis/PowerSubsystem/PowerSupplies/powersupply8
{
  "error": {
    "@Message.ExtendedInfo": [
      {
        "@odata.type": "#Message.v1_1_1.Message",
        "Message": "The requested resource of type PowerSupplies named 'powersupply8' was not found.",
        "MessageArgs": [
          "PowerSupplies",
          "powersupply8"
        ],
        "MessageId": "Base.1.13.0.ResourceNotFound",
        "MessageSeverity": "Critical",
        "Resolution": "Provide a valid resource identifier and resubmit the request."
      }
    ],
    "code": "Base.1.13.0.ResourceNotFound",
    "message": "The requested resource of type PowerSupplies named 'powersupply8' was not found."
  }
}
```

4. Error condition, list unknown invalid chassis
```
curl -k https://${bmc}/redfish/v1/Chassis/InvalidChassis/PowerSubsystem/PowerSupplies/powersupply0
{
  "error": {
    "@Message.ExtendedInfo": [
      {
        "@odata.type": "#Message.v1_1_1.Message",
        "Message": "The requested resource of type Chassis named 'InvalidChassis' was not found.",
        "MessageArgs": [
          "Chassis",
          "InvalidChassis"
        ],
        "MessageId": "Base.1.18.1.ResourceNotFound",
        "MessageSeverity": "Critical",
        "Resolution": "Provide a valid resource identifier and resubmit the request."
      }
    ],
    "code": "Base.1.18.1.ResourceNotFound",
    "message": "The requested resource of type Chassis named 'InvalidChassis' was not found."
  }
}
```

Change-Id: I07043b15cbfa0ac9a44cbf155fad3315eeacc859
Signed-off-by: Lakshmi Yadlapati <lakshmiy@us.ibm.com>
Signed-off-by: Myung Bae <myungbae@us.ibm.com>
diff --git a/redfish-core/lib/power_supply.hpp b/redfish-core/lib/power_supply.hpp
index 7905885..26ea26c 100644
--- a/redfish-core/lib/power_supply.hpp
+++ b/redfish-core/lib/power_supply.hpp
@@ -47,17 +47,20 @@
     asyncResp->res.jsonValue["Members@odata.count"] = powerSupplyList.size();
 }
 
-inline void
-    doPowerSupplyCollection(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
-                            const std::string& chassisId,
-                            const std::optional<std::string>& validChassisPath)
+inline void doPowerSupplyCollection(
+    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+    const std::string& chassisId, const boost::system::error_code& ec,
+    const dbus::utility::MapperGetSubTreePathsResponse& subtreePaths)
 {
-    if (!validChassisPath)
+    if (ec)
     {
-        messages::resourceNotFound(asyncResp->res, "Chassis", chassisId);
+        if (ec.value() != EBADR)
+        {
+            BMCWEB_LOG_ERROR("DBUS response error{}", ec.value());
+            messages::internalError(asyncResp->res);
+        }
         return;
     }
-
     asyncResp->res.addHeader(
         boost::beast::http::field::link,
         "</redfish/v1/JsonSchemas/PowerSupplyCollection/PowerSupplyCollection.json>; rel=describedby");
@@ -71,26 +74,7 @@
     asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
     asyncResp->res.jsonValue["Members@odata.count"] = 0;
 
-    std::string powerPath = *validChassisPath + "/powered_by";
-    dbus::utility::getAssociatedSubTreePaths(
-        powerPath,
-        sdbusplus::message::object_path("/xyz/openbmc_project/inventory"), 0,
-        powerSupplyInterface,
-        [asyncResp, chassisId](
-            const boost::system::error_code& ec,
-            const dbus::utility::MapperGetSubTreePathsResponse& subtreePaths) {
-            if (ec)
-            {
-                if (ec.value() != EBADR)
-                {
-                    BMCWEB_LOG_ERROR("DBUS response error{}", ec.value());
-                    messages::internalError(asyncResp->res);
-                }
-                return;
-            }
-
-            updatePowerSupplyList(asyncResp, chassisId, subtreePaths);
-        });
+    updatePowerSupplyList(asyncResp, chassisId, subtreePaths);
 }
 
 inline void handlePowerSupplyCollectionHead(
@@ -129,9 +113,19 @@
         return;
     }
 
-    redfish::chassis_utils::getValidChassisPath(
-        asyncResp, chassisId,
-        std::bind_front(doPowerSupplyCollection, asyncResp, chassisId));
+    constexpr std::array<std::string_view, 2> chasisInterfaces = {
+        "xyz.openbmc_project.Inventory.Item.Board",
+        "xyz.openbmc_project.Inventory.Item.Chassis"};
+    const std::string reqpath = "/xyz/openbmc_project/inventory";
+
+    dbus::utility::getAssociatedSubTreePathsById(
+        chassisId, reqpath, chasisInterfaces, "powered_by",
+        powerSupplyInterface,
+        [asyncResp, chassisId](
+            const boost::system::error_code& ec,
+            const dbus::utility::MapperGetSubTreePathsResponse& subtreePaths) {
+            doPowerSupplyCollection(asyncResp, chassisId, ec, subtreePaths);
+        });
 }
 
 inline void requestRoutesPowerSupplyCollection(App& app)
@@ -147,59 +141,55 @@
             std::bind_front(handlePowerSupplyCollectionGet, std::ref(app)));
 }
 
-inline bool checkPowerSupplyId(const std::string& powerSupplyPath,
-                               const std::string& powerSupplyId)
+inline void afterGetValidPowerSupplyPath(
+    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+    const std::string& powerSupplyId, const boost::system::error_code& ec,
+    const dbus::utility::MapperGetSubTreeResponse& subtree,
+    const std::function<void(const std::string& powerSupplyPath,
+                             const std::string& service)>& callback)
 {
-    std::string powerSupplyName =
-        sdbusplus::message::object_path(powerSupplyPath).filename();
+    if (ec)
+    {
+        if (ec.value() != EBADR)
+        {
+            BMCWEB_LOG_ERROR("DBUS response error{}", ec.value());
+            messages::internalError(asyncResp->res);
+        }
+        return;
+    }
+    for (const auto& [objectPath, service] : subtree)
+    {
+        sdbusplus::message::object_path path(objectPath);
+        if (path == powerSupplyId)
+        {
+            callback(path, service.begin()->first);
+            return;
+        }
+    }
 
-    return !(powerSupplyName.empty() || powerSupplyName != powerSupplyId);
+    BMCWEB_LOG_WARNING("Power supply not found: {}", powerSupplyId);
+    messages::resourceNotFound(asyncResp->res, "PowerSupplies", powerSupplyId);
 }
 
 inline void getValidPowerSupplyPath(
     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
-    const std::string& validChassisPath, const std::string& powerSupplyId,
-    std::function<void(const std::string& powerSupplyPath)>&& callback)
+    const std::string& chassisId, const std::string& powerSupplyId,
+    std::function<void(const std::string& powerSupplyPath,
+                       const std::string& service)>&& callback)
 {
-    std::string powerPath = validChassisPath + "/powered_by";
-    dbus::utility::getAssociatedSubTreePaths(
-        powerPath,
-        sdbusplus::message::object_path("/xyz/openbmc_project/inventory"), 0,
+    constexpr std::array<std::string_view, 2> chasisInterfaces = {
+        "xyz.openbmc_project.Inventory.Item.Board",
+        "xyz.openbmc_project.Inventory.Item.Chassis"};
+    const std::string reqpath = "/xyz/openbmc_project/inventory";
+
+    dbus::utility::getAssociatedSubTreeById(
+        chassisId, reqpath, chasisInterfaces, "powered_by",
         powerSupplyInterface,
-        [asyncResp, powerSupplyId, callback{std::move(callback)}](
+        [asyncResp, chassisId, powerSupplyId, callback{std::move(callback)}](
             const boost::system::error_code& ec,
-            const dbus::utility::MapperGetSubTreePathsResponse& subtreePaths) {
-            if (ec)
-            {
-                if (ec.value() != EBADR)
-                {
-                    BMCWEB_LOG_ERROR(
-                        "DBUS response error for getAssociatedSubTreePaths{}",
-                        ec.value());
-                    messages::internalError(asyncResp->res);
-                    return;
-                }
-                messages::resourceNotFound(asyncResp->res, "PowerSupplies",
-                                           powerSupplyId);
-                return;
-            }
-
-            for (const std::string& path : subtreePaths)
-            {
-                if (checkPowerSupplyId(path, powerSupplyId))
-                {
-                    callback(path);
-                    return;
-                }
-            }
-
-            if (!subtreePaths.empty())
-            {
-                BMCWEB_LOG_WARNING("Power supply not found: {}", powerSupplyId);
-                messages::resourceNotFound(asyncResp->res, "PowerSupplies",
-                                           powerSupplyId);
-                return;
-            }
+            const dbus::utility::MapperGetSubTreeResponse& subtree) {
+            afterGetValidPowerSupplyPath(asyncResp, powerSupplyId, ec, subtree,
+                                         callback);
         });
 }
 
@@ -457,59 +447,27 @@
 inline void doPowerSupplyGet(
     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
     const std::string& chassisId, const std::string& powerSupplyId,
-    const std::optional<std::string>& validChassisPath)
+    const std::string& powerSupplyPath, const std::string& service)
 {
-    if (!validChassisPath)
-    {
-        messages::resourceNotFound(asyncResp->res, "Chassis", chassisId);
-        return;
-    }
+    asyncResp->res.addHeader(
+        boost::beast::http::field::link,
+        "</redfish/v1/JsonSchemas/PowerSupply/PowerSupply.json>; rel=describedby");
+    asyncResp->res.jsonValue["@odata.type"] = "#PowerSupply.v1_5_0.PowerSupply";
+    asyncResp->res.jsonValue["Name"] = "Power Supply";
+    asyncResp->res.jsonValue["Id"] = powerSupplyId;
+    asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
+        "/redfish/v1/Chassis/{}/PowerSubsystem/PowerSupplies/{}", chassisId,
+        powerSupplyId);
 
-    // Get the correct Path and Service that match the input parameters
-    getValidPowerSupplyPath(
-        asyncResp, *validChassisPath, powerSupplyId,
-        [asyncResp, chassisId,
-         powerSupplyId](const std::string& powerSupplyPath) {
-            asyncResp->res.addHeader(
-                boost::beast::http::field::link,
-                "</redfish/v1/JsonSchemas/PowerSupply/PowerSupply.json>; rel=describedby");
-            asyncResp->res.jsonValue["@odata.type"] =
-                "#PowerSupply.v1_5_0.PowerSupply";
-            asyncResp->res.jsonValue["Name"] = "Power Supply";
-            asyncResp->res.jsonValue["Id"] = powerSupplyId;
-            asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
-                "/redfish/v1/Chassis/{}/PowerSubsystem/PowerSupplies/{}",
-                chassisId, powerSupplyId);
+    asyncResp->res.jsonValue["Status"]["State"] = resource::State::Enabled;
+    asyncResp->res.jsonValue["Status"]["Health"] = resource::Health::OK;
 
-            asyncResp->res.jsonValue["Status"]["State"] =
-                resource::State::Enabled;
-            asyncResp->res.jsonValue["Status"]["Health"] = resource::Health::OK;
-
-            dbus::utility::getDbusObject(
-                powerSupplyPath, powerSupplyInterface,
-                [asyncResp, powerSupplyPath](
-                    const boost::system::error_code& ec,
-                    const dbus::utility::MapperGetObject& object) {
-                    if (ec || object.empty())
-                    {
-                        messages::internalError(asyncResp->res);
-                        return;
-                    }
-
-                    getPowerSupplyState(asyncResp, object.begin()->first,
-                                        powerSupplyPath);
-                    getPowerSupplyHealth(asyncResp, object.begin()->first,
-                                         powerSupplyPath);
-                    getPowerSupplyAsset(asyncResp, object.begin()->first,
-                                        powerSupplyPath);
-                    getPowerSupplyFirmwareVersion(
-                        asyncResp, object.begin()->first, powerSupplyPath);
-                    getPowerSupplyLocation(asyncResp, object.begin()->first,
-                                           powerSupplyPath);
-                });
-
-            getEfficiencyPercent(asyncResp);
-        });
+    getPowerSupplyState(asyncResp, service, powerSupplyPath);
+    getPowerSupplyHealth(asyncResp, service, powerSupplyPath);
+    getPowerSupplyAsset(asyncResp, service, powerSupplyPath);
+    getPowerSupplyFirmwareVersion(asyncResp, service, powerSupplyPath);
+    getPowerSupplyLocation(asyncResp, service, powerSupplyPath);
+    getEfficiencyPercent(asyncResp);
 }
 
 inline void handlePowerSupplyHead(
@@ -522,25 +480,13 @@
         return;
     }
 
-    redfish::chassis_utils::getValidChassisPath(
-        asyncResp, chassisId,
-        [asyncResp, chassisId,
-         powerSupplyId](const std::optional<std::string>& validChassisPath) {
-            if (!validChassisPath)
-            {
-                messages::resourceNotFound(asyncResp->res, "Chassis",
-                                           chassisId);
-                return;
-            }
-
-            // Get the correct Path and Service that match the input parameters
-            getValidPowerSupplyPath(
-                asyncResp, *validChassisPath, powerSupplyId,
-                [asyncResp](const std::string&) {
-                    asyncResp->res.addHeader(
-                        boost::beast::http::field::link,
-                        "</redfish/v1/JsonSchemas/PowerSupply/PowerSupply.json>; rel=describedby");
-                });
+    // Get the correct Path and Service that match the input parameters
+    getValidPowerSupplyPath(
+        asyncResp, chassisId, powerSupplyId,
+        [asyncResp](const std::string&, const std::string&) {
+            asyncResp->res.addHeader(
+                boost::beast::http::field::link,
+                "</redfish/v1/JsonSchemas/PowerSupply/PowerSupply.json>; rel=describedby");
         });
 }
 
@@ -553,9 +499,8 @@
     {
         return;
     }
-
-    redfish::chassis_utils::getValidChassisPath(
-        asyncResp, chassisId,
+    getValidPowerSupplyPath(
+        asyncResp, chassisId, powerSupplyId,
         std::bind_front(doPowerSupplyGet, asyncResp, chassisId, powerSupplyId));
 }