Create associations

When a new inventory object is created, check if it has an association
that needs to be created in the data loaded from the JSON associations
configuration file.  If it does, then create an
xyz.openbmc_project.Association.Definitions interface object for the
association.

Change-Id: Ie850601cbd0acba631c5b66cb4541decf66e286d
Signed-off-by: Matt Spinler <spinler@us.ibm.com>
diff --git a/association_manager.cpp b/association_manager.cpp
index 91bb309..fd36eef 100644
--- a/association_manager.cpp
+++ b/association_manager.cpp
@@ -80,7 +80,63 @@
 
 void Manager::createAssociations(const std::string& objectPath)
 {
-    // TODO
+    auto endpoints = _associations.find(objectPath);
+    if (endpoints == _associations.end())
+    {
+        return;
+    }
+
+    if (std::find(_handled.begin(), _handled.end(), objectPath) !=
+        _handled.end())
+    {
+        return;
+    }
+
+    _handled.push_back(objectPath);
+
+    for (const auto& endpoint : endpoints->second)
+    {
+        const auto& types = std::get<typesPos>(endpoint);
+        const auto& paths = std::get<pathsPos>(endpoint);
+
+        for (const auto& endpointPath : paths)
+        {
+            const auto& forwardType = std::get<forwardTypePos>(types);
+            const auto& reverseType = std::get<reverseTypePos>(types);
+
+            createAssociation(objectPath, forwardType, endpointPath,
+                              reverseType);
+        }
+    }
+}
+
+void Manager::createAssociation(const std::string& forwardPath,
+                                const std::string& forwardType,
+                                const std::string& reversePath,
+                                const std::string& reverseType)
+{
+    auto object = _associationIfaces.find(forwardPath);
+    if (object == _associationIfaces.end())
+    {
+        auto a = std::make_unique<AssociationObject>(_bus, forwardPath.c_str(),
+                                                     true);
+
+        using AssociationProperty =
+            std::vector<std::tuple<std::string, std::string, std::string>>;
+        AssociationProperty prop;
+
+        prop.emplace_back(forwardType, reverseType, reversePath);
+        a->associations(std::move(prop));
+        a->emit_object_added();
+        _associationIfaces.emplace(forwardPath, std::move(a));
+    }
+    else
+    {
+        // Interface exists, just update the property
+        auto prop = object->second->associations();
+        prop.emplace_back(forwardType, reverseType, reversePath);
+        object->second->associations(std::move(prop));
+    }
 }
 } // namespace associations
 } // namespace manager
diff --git a/association_manager.hpp b/association_manager.hpp
index 0196c36..240bbdc 100644
--- a/association_manager.hpp
+++ b/association_manager.hpp
@@ -2,7 +2,7 @@
 
 #include "config.h"
 
-#include <sdbusplus/bus.hpp>
+#include <xyz/openbmc_project/Association/Definitions/server.hpp>
 
 namespace phosphor
 {
@@ -24,6 +24,12 @@
 
 using AssociationMap = std::map<std::string, EndpointsEntry>;
 
+using AssociationObject = sdbusplus::server::object::object<
+    sdbusplus::xyz::openbmc_project::Association::server::Definitions>;
+
+using AssociationIfaceMap =
+    std::map<std::string, std::unique_ptr<AssociationObject>>;
+
 /**
  * @class Manager
  *
@@ -97,6 +103,20 @@
     void load();
 
     /**
+     * @brief Creates an instance of an org.openbmc.Associations
+     *        interface using the passed in properties.
+     *
+     * @param[in] forwardPath - the path of the forward association
+     * @param[in] forwardType - the type of the forward association
+     * @param[in] reversePath - the path of the reverse association
+     * @param[in] reverseType - the type of the reverse association
+     */
+    void createAssociation(const std::string& forwardPath,
+                           const std::string& forwardType,
+                           const std::string& reversePath,
+                           const std::string& reverseType);
+
+    /**
      * @brief The map of association data that is loaded from its
      *        JSON definition.  Association D-Bus objects will be
      *        created from this data.
@@ -104,6 +124,12 @@
     AssociationMap _associations;
 
     /**
+     * @brief The map of org.openbmc_project.Associations D-Bus
+     *        interfaces objects based on their object path.
+     */
+    AssociationIfaceMap _associationIfaces;
+
+    /**
      * @brief The sdbusplus bus object.
      */
     sdbusplus::bus::bus& _bus;
@@ -112,6 +138,11 @@
      * @brief The path to the associations JSON File.
      */
     const std::string _jsonFile;
+
+    /**
+     * A list of the inventory association paths that have already been handled.
+     */
+    std::vector<std::string> _handled;
 };
 
 } // namespace associations