| Matt Spinler | 852db67 | 2019-03-06 13:46:14 -0600 | [diff] [blame] | 1 | #include "association_manager.hpp" | 
|  | 2 |  | 
| Matt Spinler | 99e66a0 | 2019-03-06 14:11:22 -0600 | [diff] [blame] | 3 | #include <nlohmann/json.hpp> | 
|  | 4 | #include <phosphor-logging/log.hpp> | 
|  | 5 |  | 
| Brad Bishop | a83db30 | 2020-12-06 14:51:23 -0500 | [diff] [blame] | 6 | #include <filesystem> | 
|  | 7 | #include <fstream> | 
|  | 8 |  | 
| Matt Spinler | 852db67 | 2019-03-06 13:46:14 -0600 | [diff] [blame] | 9 | namespace phosphor | 
|  | 10 | { | 
|  | 11 | namespace inventory | 
|  | 12 | { | 
|  | 13 | namespace manager | 
|  | 14 | { | 
|  | 15 | namespace associations | 
|  | 16 | { | 
| Matt Spinler | 99e66a0 | 2019-03-06 14:11:22 -0600 | [diff] [blame] | 17 | using namespace phosphor::logging; | 
|  | 18 | using sdbusplus::exception::SdBusError; | 
| Matt Spinler | 852db67 | 2019-03-06 13:46:14 -0600 | [diff] [blame] | 19 |  | 
|  | 20 | Manager::Manager(sdbusplus::bus::bus& bus, const std::string& jsonPath) : | 
|  | 21 | _bus(bus), _jsonFile(jsonPath) | 
|  | 22 | { | 
| Matt Spinler | 99e66a0 | 2019-03-06 14:11:22 -0600 | [diff] [blame] | 23 | 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 | */ | 
|  | 32 | void throwIfZero(int num) | 
|  | 33 | { | 
|  | 34 | if (!num) | 
|  | 35 | { | 
|  | 36 | throw std::invalid_argument("Invalid empty field in JSON"); | 
|  | 37 | } | 
|  | 38 | } | 
|  | 39 |  | 
|  | 40 | void 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 Spinler | 852db67 | 2019-03-06 13:46:14 -0600 | [diff] [blame] | 80 | } | 
|  | 81 |  | 
|  | 82 | void Manager::createAssociations(const std::string& objectPath) | 
|  | 83 | { | 
| Matt Spinler | c47ca58 | 2019-03-06 14:37:42 -0600 | [diff] [blame] | 84 | auto endpoints = _associations.find(objectPath); | 
|  | 85 | if (endpoints == _associations.end()) | 
|  | 86 | { | 
|  | 87 | return; | 
|  | 88 | } | 
|  | 89 |  | 
|  | 90 | if (std::find(_handled.begin(), _handled.end(), objectPath) != | 
|  | 91 | _handled.end()) | 
|  | 92 | { | 
|  | 93 | return; | 
|  | 94 | } | 
|  | 95 |  | 
|  | 96 | _handled.push_back(objectPath); | 
|  | 97 |  | 
|  | 98 | for (const auto& endpoint : endpoints->second) | 
|  | 99 | { | 
|  | 100 | const auto& types = std::get<typesPos>(endpoint); | 
|  | 101 | const auto& paths = std::get<pathsPos>(endpoint); | 
|  | 102 |  | 
|  | 103 | for (const auto& endpointPath : paths) | 
|  | 104 | { | 
|  | 105 | const auto& forwardType = std::get<forwardTypePos>(types); | 
|  | 106 | const auto& reverseType = std::get<reverseTypePos>(types); | 
|  | 107 |  | 
|  | 108 | createAssociation(objectPath, forwardType, endpointPath, | 
|  | 109 | reverseType); | 
|  | 110 | } | 
|  | 111 | } | 
|  | 112 | } | 
|  | 113 |  | 
|  | 114 | void Manager::createAssociation(const std::string& forwardPath, | 
|  | 115 | const std::string& forwardType, | 
|  | 116 | const std::string& reversePath, | 
|  | 117 | const std::string& reverseType) | 
|  | 118 | { | 
|  | 119 | auto object = _associationIfaces.find(forwardPath); | 
|  | 120 | if (object == _associationIfaces.end()) | 
|  | 121 | { | 
|  | 122 | auto a = std::make_unique<AssociationObject>(_bus, forwardPath.c_str(), | 
|  | 123 | true); | 
|  | 124 |  | 
|  | 125 | using AssociationProperty = | 
|  | 126 | std::vector<std::tuple<std::string, std::string, std::string>>; | 
|  | 127 | AssociationProperty prop; | 
|  | 128 |  | 
|  | 129 | prop.emplace_back(forwardType, reverseType, reversePath); | 
|  | 130 | a->associations(std::move(prop)); | 
|  | 131 | a->emit_object_added(); | 
|  | 132 | _associationIfaces.emplace(forwardPath, std::move(a)); | 
|  | 133 | } | 
|  | 134 | else | 
|  | 135 | { | 
|  | 136 | // Interface exists, just update the property | 
|  | 137 | auto prop = object->second->associations(); | 
|  | 138 | prop.emplace_back(forwardType, reverseType, reversePath); | 
|  | 139 | object->second->associations(std::move(prop)); | 
|  | 140 | } | 
| Matt Spinler | 852db67 | 2019-03-06 13:46:14 -0600 | [diff] [blame] | 141 | } | 
|  | 142 | } // namespace associations | 
|  | 143 | } // namespace manager | 
|  | 144 | } // namespace inventory | 
|  | 145 | } // namespace phosphor |