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 virtual ~ConfigBase() = default; 54 55 explicit ConfigBase(const json& jsonObj) 56 { 57 // Set the name of this configuration object 58 setName(jsonObj); 59 if (jsonObj.contains("profiles")) 60 { 61 for (const auto& profile : jsonObj["profiles"]) 62 { 63 _profiles.emplace_back(profile.get<std::string>()); 64 } 65 } 66 } 67 68 /** 69 * Copy Constructor 70 * Creates a config base from another config base's originally parsed JSON 71 * object data 72 * 73 * @param[in] origObj - Original ConfigBase object to be created from 74 */ 75 ConfigBase(const ConfigBase& origObj) 76 { 77 _name = origObj._name; 78 _profiles = origObj._profiles; 79 } 80 81 /** 82 * @brief Get the configuration object's name 83 * 84 * @return Name of the configuration object 85 */ 86 inline const std::string& getName() const 87 { 88 return _name; 89 } 90 91 /** 92 * @brief Get the configuration object's list of profiles 93 * 94 * Gets the list of profiles this configuration object belongs to if any 95 * are configured, otherwise an empty list of profiles results in the 96 * object always being included in the configuration. 97 * 98 * @return List of profiles the configuration object belongs to 99 */ 100 inline const auto& getProfiles() const 101 { 102 return _profiles; 103 } 104 105 /** 106 * @brief Determines the data type of a JSON configured parameter that is 107 * used as a variant within the fan control application and returns the 108 * value as that variant. 109 * @details Retrieves a JSON object by the first derived data type that 110 * is not null. Expected data types should appear in a logical order of 111 * conversion. i.e.) uint and int could both be uint 112 * 113 * @param[in] object - A single JSON object 114 * 115 * @return A `PropertyVariantType` variant containing the JSON object's 116 * value 117 */ 118 static const PropertyVariantType getJsonValue(const json& object) 119 { 120 if (auto boolPtr = object.get_ptr<const bool*>()) 121 { 122 return *boolPtr; 123 } 124 if (auto intPtr = object.get_ptr<const int64_t*>()) 125 { 126 return *intPtr; 127 } 128 if (auto doublePtr = object.get_ptr<const double*>()) 129 { 130 return *doublePtr; 131 } 132 if (auto stringPtr = object.get_ptr<const std::string*>()) 133 { 134 return *stringPtr; 135 } 136 137 log<level::ERR>( 138 "Unsupported data type for JSON object's value", 139 entry("JSON_ENTRY=%s", object.dump().c_str()), 140 entry("SUPPORTED_TYPES=%s", "{bool, int, double, string}")); 141 throw std::runtime_error( 142 "Unsupported data type for JSON object's value"); 143 } 144 145 protected: 146 /* Name of the configuration object */ 147 std::string _name; 148 149 /** 150 * Profiles this configuration object belongs to (OPTIONAL). 151 * Otherwise always include this object in the configuration 152 * when no profiles are given 153 */ 154 std::vector<std::string> _profiles; 155 156 private: 157 /** 158 * @brief Sets the configuration object's name from the given JSON 159 * 160 * @param[in] jsonObj - JSON to get configuration object's name from 161 */ 162 inline void setName(const json& jsonObj) 163 { 164 if (!jsonObj.contains("name")) 165 { 166 // Log error on missing configuration object's name 167 log<level::ERR>("Missing required configuration object's name", 168 entry("JSON=%s", jsonObj.dump().c_str())); 169 throw std::runtime_error( 170 "Missing required configuration object's name"); 171 } 172 _name = jsonObj["name"].get<std::string>(); 173 } 174 }; 175 176 } // namespace phosphor::fan::control::json 177