1 /** 2 * Copyright © 2020 IBM Corporation 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 #pragma once 17 18 #include <nlohmann/json.hpp> 19 #include <phosphor-logging/log.hpp> 20 21 #include <vector> 22 23 namespace phosphor::fan::control::json 24 { 25 26 using json = nlohmann::json; 27 using namespace phosphor::logging; 28 29 using PropertyVariantType = 30 std::variant<bool, int32_t, int64_t, double, std::string>; 31 32 /** 33 * Configuration object key to uniquely map to the configuration object 34 * Pair constructed of: 35 * std::string = Configuration object's name 36 * std::vector<std::string> = List of profiles the configuration object 37 * is included in 38 */ 39 using configKey = std::pair<std::string, std::vector<std::string>>; 40 41 /** 42 * @class ConfigBase - Base configuration object 43 * 44 * Base class for fan control's JSON configuration objects. 45 */ 46 class ConfigBase 47 { 48 public: 49 ConfigBase() = delete; 50 ConfigBase(ConfigBase&&) = delete; 51 ConfigBase& operator=(const ConfigBase&) = delete; 52 ConfigBase& operator=(ConfigBase&&) = delete; 53 54 virtual ~ConfigBase() = default; 55 ConfigBase(const json & jsonObj)56 explicit ConfigBase(const json& jsonObj) 57 { 58 // Set the name of this configuration object 59 setName(jsonObj); 60 if (jsonObj.contains("profiles")) 61 { 62 for (const auto& profile : jsonObj["profiles"]) 63 { 64 _profiles.emplace_back(profile.get<std::string>()); 65 } 66 } 67 } 68 69 /** 70 * Copy Constructor 71 * Creates a config base from another config base's originally parsed JSON 72 * object data 73 * 74 * @param[in] origObj - Original ConfigBase object to be created from 75 */ ConfigBase(const ConfigBase & origObj)76 ConfigBase(const ConfigBase& origObj) 77 { 78 _name = origObj._name; 79 _profiles = origObj._profiles; 80 } 81 82 /** 83 * @brief Get the configuration object's name 84 * 85 * @return Name of the configuration object 86 */ getName() const87 inline const std::string& getName() const 88 { 89 return _name; 90 } 91 92 /** 93 * @brief Get the configuration object's list of profiles 94 * 95 * Gets the list of profiles this configuration object belongs to if any 96 * are configured, otherwise an empty list of profiles results in the 97 * object always being included in the configuration. 98 * 99 * @return List of profiles the configuration object belongs to 100 */ getProfiles() const101 inline const auto& getProfiles() const 102 { 103 return _profiles; 104 } 105 106 /** 107 * @brief Determines the data type of a JSON configured parameter that is 108 * used as a variant within the fan control application and returns the 109 * value as that variant. 110 * @details Retrieves a JSON object by the first derived data type that 111 * is not null. Expected data types should appear in a logical order of 112 * conversion. i.e.) uint and int could both be uint 113 * 114 * @param[in] object - A single JSON object 115 * 116 * @return A `PropertyVariantType` variant containing the JSON object's 117 * value 118 */ getJsonValue(const json & object)119 static const PropertyVariantType getJsonValue(const json& object) 120 { 121 if (auto boolPtr = object.get_ptr<const bool*>()) 122 { 123 return *boolPtr; 124 } 125 if (auto intPtr = object.get_ptr<const int64_t*>()) 126 { 127 return *intPtr; 128 } 129 if (auto doublePtr = object.get_ptr<const double*>()) 130 { 131 return *doublePtr; 132 } 133 if (auto stringPtr = object.get_ptr<const std::string*>()) 134 { 135 return *stringPtr; 136 } 137 138 log<level::ERR>( 139 "Unsupported data type for JSON object's value", 140 entry("JSON_ENTRY=%s", object.dump().c_str()), 141 entry("SUPPORTED_TYPES=%s", "{bool, int, double, string}")); 142 throw std::runtime_error( 143 "Unsupported data type for JSON object's value"); 144 } 145 146 protected: 147 /* Name of the configuration object */ 148 std::string _name; 149 150 /** 151 * Profiles this configuration object belongs to (OPTIONAL). 152 * Otherwise always include this object in the configuration 153 * when no profiles are given 154 */ 155 std::vector<std::string> _profiles; 156 157 private: 158 /** 159 * @brief Sets the configuration object's name from the given JSON 160 * 161 * @param[in] jsonObj - JSON to get configuration object's name from 162 */ setName(const json & jsonObj)163 inline void setName(const json& jsonObj) 164 { 165 if (!jsonObj.contains("name")) 166 { 167 // Log error on missing configuration object's name 168 log<level::ERR>("Missing required configuration object's name", 169 entry("JSON=%s", jsonObj.dump().c_str())); 170 throw std::runtime_error( 171 "Missing required configuration object's name"); 172 } 173 _name = jsonObj["name"].get<std::string>(); 174 } 175 }; 176 177 } // namespace phosphor::fan::control::json 178