blob: 91956ba3e08074c8fbe4607ce9647dceea11e5b9 [file] [log] [blame]
Matt Spinler852db672019-03-06 13:46:14 -06001#include "association_manager.hpp"
2
Matt Spinler99e66a02019-03-06 14:11:22 -06003#include <nlohmann/json.hpp>
4#include <phosphor-logging/log.hpp>
5
Brad Bishopa83db302020-12-06 14:51:23 -05006#include <filesystem>
7#include <fstream>
8
Matt Spinler852db672019-03-06 13:46:14 -06009namespace phosphor
10{
11namespace inventory
12{
13namespace manager
14{
15namespace associations
16{
Matt Spinler99e66a02019-03-06 14:11:22 -060017using namespace phosphor::logging;
18using sdbusplus::exception::SdBusError;
Matt Spinler852db672019-03-06 13:46:14 -060019
20Manager::Manager(sdbusplus::bus::bus& bus, const std::string& jsonPath) :
21 _bus(bus), _jsonFile(jsonPath)
22{
Matt Spinler99e66a02019-03-06 14:11:22 -060023 load();
24}
25
26/**
27 * @brief Throws an exception if 'num' is zero. Used for JSON
28 * sanity checking.
29 *
30 * @param[in] num - the number to check
31 */
32void throwIfZero(int num)
33{
34 if (!num)
35 {
36 throw std::invalid_argument("Invalid empty field in JSON");
37 }
38}
39
40void Manager::load()
41{
42 // Load the contents of _jsonFile into _associations and throw
43 // an exception on any problem.
44
45 std::ifstream file{_jsonFile};
46
47 auto json = nlohmann::json::parse(file, nullptr, true);
48
49 const std::string root{INVENTORY_ROOT};
50
51 for (const auto& jsonAssoc : json)
52 {
53 // Only add the slash if necessary
54 std::string path = jsonAssoc.at("path");
55 throwIfZero(path.size());
56 if (path.front() != '/')
57 {
58 path = root + "/" + path;
59 }
60 else
61 {
62 path = root + path;
63 }
64
65 auto& assocEndpoints = _associations[path];
66
67 for (const auto& endpoint : jsonAssoc.at("endpoints"))
68 {
69 std::string ftype = endpoint.at("types").at("fType");
70 std::string rtype = endpoint.at("types").at("rType");
71 throwIfZero(ftype.size());
72 throwIfZero(rtype.size());
73 Types types{std::move(ftype), std::move(rtype)};
74
75 Paths paths = endpoint.at("paths");
76 throwIfZero(paths.size());
77 assocEndpoints.emplace_back(std::move(types), std::move(paths));
78 }
79 }
Matt Spinler852db672019-03-06 13:46:14 -060080}
81
Brad Bishop104ccba2020-12-06 15:22:10 -050082void Manager::createAssociations(const std::string& objectPath,
83 bool deferSignal)
Matt Spinler852db672019-03-06 13:46:14 -060084{
Matt Spinlerc47ca582019-03-06 14:37:42 -060085 auto endpoints = _associations.find(objectPath);
86 if (endpoints == _associations.end())
87 {
88 return;
89 }
90
91 if (std::find(_handled.begin(), _handled.end(), objectPath) !=
92 _handled.end())
93 {
94 return;
95 }
96
97 _handled.push_back(objectPath);
98
99 for (const auto& endpoint : endpoints->second)
100 {
101 const auto& types = std::get<typesPos>(endpoint);
102 const auto& paths = std::get<pathsPos>(endpoint);
103
104 for (const auto& endpointPath : paths)
105 {
106 const auto& forwardType = std::get<forwardTypePos>(types);
107 const auto& reverseType = std::get<reverseTypePos>(types);
108
109 createAssociation(objectPath, forwardType, endpointPath,
Brad Bishop104ccba2020-12-06 15:22:10 -0500110 reverseType, deferSignal);
Matt Spinlerc47ca582019-03-06 14:37:42 -0600111 }
112 }
113}
114
115void Manager::createAssociation(const std::string& forwardPath,
116 const std::string& forwardType,
117 const std::string& reversePath,
Brad Bishop104ccba2020-12-06 15:22:10 -0500118 const std::string& reverseType,
119 bool deferSignal)
Matt Spinlerc47ca582019-03-06 14:37:42 -0600120{
121 auto object = _associationIfaces.find(forwardPath);
122 if (object == _associationIfaces.end())
123 {
124 auto a = std::make_unique<AssociationObject>(_bus, forwardPath.c_str(),
125 true);
126
127 using AssociationProperty =
128 std::vector<std::tuple<std::string, std::string, std::string>>;
129 AssociationProperty prop;
130
131 prop.emplace_back(forwardType, reverseType, reversePath);
132 a->associations(std::move(prop));
Brad Bishop104ccba2020-12-06 15:22:10 -0500133 if (!deferSignal)
134 {
135 a->emit_object_added();
136 }
Matt Spinlerc47ca582019-03-06 14:37:42 -0600137 _associationIfaces.emplace(forwardPath, std::move(a));
138 }
139 else
140 {
141 // Interface exists, just update the property
142 auto prop = object->second->associations();
143 prop.emplace_back(forwardType, reverseType, reversePath);
Brad Bishop104ccba2020-12-06 15:22:10 -0500144 object->second->associations(std::move(prop), deferSignal);
Matt Spinlerc47ca582019-03-06 14:37:42 -0600145 }
Matt Spinler852db672019-03-06 13:46:14 -0600146}
147} // namespace associations
148} // namespace manager
149} // namespace inventory
150} // namespace phosphor