Add the getAssociationEndPoints method

There are currently many files that use the get endpoints methods[1].
Since they are general methods, they are defined in the
dbus_utility.hpp file and will be further refactored in subsequent
patches.

Also, Updated the populateSoftwareInformation method of sw_utils.hpp

[1] https://github.com/openbmc/docs/blob/master/architecture/object-mapper.md#associations
When an object with, for example, an object path of pathA uses
the following values:

["foo", "bar", "pathB"]

The mapper will create 2 new objects:

pathA/foo
pathB/bar

Tested: Built bmcweb successuflly and Validator passes
curl -k -H "X-Auth-Token: $token" -X GET
https://${bmc}/redfish/v1/Managers/bmc
{
  "@odata.id": "/redfish/v1/Managers/bmc",
  "@odata.type": "#Manager.v1_14_0.Manager",
  ...
  "FirmwareVersion": "2.14.0-dev-95-gea3949e76-dirty",
  ...
}

Signed-off-by: George Liu <liuxiwei@inspur.com>
Change-Id: I6567f63ab63709504b46ed49b00055a8ffc34124
diff --git a/include/dbus_utility.hpp b/include/dbus_utility.hpp
index e953a9f..eac3099 100644
--- a/include/dbus_utility.hpp
+++ b/include/dbus_utility.hpp
@@ -18,6 +18,7 @@
 #include "dbus_singleton.hpp"
 
 #include <boost/system/error_code.hpp> // IWYU pragma: keep
+#include <sdbusplus/asio/property.hpp>
 #include <sdbusplus/message/native_types.hpp>
 
 #include <array>
@@ -94,6 +95,7 @@
               std::vector<std::pair<std::string, std::vector<std::string>>>>>;
 
 using MapperGetSubTreePathsResponse = std::vector<std::string>;
+using MapperEndPoints = std::vector<sdbusplus::message::object_path>;
 
 inline void escapePathForDbus(std::string& path)
 {
@@ -193,5 +195,15 @@
         "xyz.openbmc_project.ObjectMapper", "GetObject", path, interfaces);
 }
 
+inline void getAssociationEndPoints(
+    const std::string& path,
+    std::function<void(const boost::system::error_code&,
+                       const MapperEndPoints&)>&& callback)
+{
+    sdbusplus::asio::getProperty<MapperEndPoints>(
+        *crow::connections::systemBus, "xyz.openbmc_project.ObjectMapper", path,
+        "xyz.openbmc_project.Association", "endpoints", std::move(callback));
+}
+
 } // namespace utility
 } // namespace dbus
diff --git a/redfish-core/include/utils/sw_utils.hpp b/redfish-core/include/utils/sw_utils.hpp
index 31c3ea3..ef21ff6 100644
--- a/redfish-core/include/utils/sw_utils.hpp
+++ b/redfish-core/include/utils/sw_utils.hpp
@@ -47,13 +47,11 @@
                                 const bool populateLinkToImages)
 {
     // Used later to determine running (known on Redfish as active) Sw images
-    sdbusplus::asio::getProperty<std::vector<std::string>>(
-        *crow::connections::systemBus, "xyz.openbmc_project.ObjectMapper",
+    dbus::utility::getAssociationEndPoints(
         "/xyz/openbmc_project/software/functional",
-        "xyz.openbmc_project.Association", "endpoints",
-        [aResp, swVersionPurpose, activeVersionPropName,
-         populateLinkToImages](const boost::system::error_code ec,
-                               const std::vector<std::string>& functionalSw) {
+        [aResp, swVersionPurpose, activeVersionPropName, populateLinkToImages](
+            const boost::system::error_code& ec,
+            const dbus::utility::MapperEndPoints& functionalSw) {
         BMCWEB_LOG_DEBUG << "populateSoftwareInformation enter";
         if (ec)
         {
@@ -76,9 +74,8 @@
         // example functionalSw:
         // v as 2 "/xyz/openbmc_project/software/ace821ef"
         //        "/xyz/openbmc_project/software/230fb078"
-        for (const auto& sw : functionalSw)
+        for (const auto& path : functionalSw)
         {
-            sdbusplus::message::object_path path(sw);
             std::string leaf = path.filename();
             if (leaf.empty())
             {