xref: /openbmc/phosphor-fan-presence/control/json/config_base.hpp (revision 64b5ac203518568ec8b7569d0e785352278f2472)
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/lg2.hpp>
20 
21 #include <vector>
22 
23 namespace phosphor::fan::control::json
24 {
25 
26 using json = nlohmann::json;
27 
28 using PropertyVariantType =
29     std::variant<bool, int32_t, int64_t, double, std::string>;
30 
31 /**
32  * Configuration object key to uniquely map to the configuration object
33  * Pair constructed of:
34  *      std::string = Configuration object's name
35  *      std::vector<std::string> = List of profiles the configuration object
36  *                                 is included in
37  */
38 using configKey = std::pair<std::string, std::vector<std::string>>;
39 
40 /**
41  * @class ConfigBase - Base configuration object
42  *
43  * Base class for fan control's JSON configuration objects.
44  */
45 class ConfigBase
46 {
47   public:
48     ConfigBase() = delete;
49     ConfigBase(ConfigBase&&) = delete;
50     ConfigBase& operator=(const ConfigBase&) = delete;
51     ConfigBase& operator=(ConfigBase&&) = delete;
52 
53     virtual ~ConfigBase() = default;
54 
ConfigBase(const json & jsonObj)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      */
ConfigBase(const ConfigBase & origObj)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      */
getName() const86     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      */
getProfiles() const100     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      */
getJsonValue(const json & object)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         lg2::error(
138             "Unsupported data type for JSON object's value. Supported Types are 'bool, int, double, string'",
139             "JSON_ENTRY", object.dump());
140         throw std::runtime_error(
141             "Unsupported data type for JSON object's value");
142     }
143 
144   protected:
145     /* Name of the configuration object */
146     std::string _name;
147 
148     /**
149      * Profiles this configuration object belongs to (OPTIONAL).
150      * Otherwise always include this object in the configuration
151      * when no profiles are given
152      */
153     std::vector<std::string> _profiles;
154 
155   private:
156     /**
157      * @brief Sets the configuration object's name from the given JSON
158      *
159      * @param[in] jsonObj - JSON to get configuration object's name from
160      */
setName(const json & jsonObj)161     inline void setName(const json& jsonObj)
162     {
163         if (!jsonObj.contains("name"))
164         {
165             // Log error on missing configuration object's name
166             lg2::error("Missing required configuration object's name", "JSON",
167                        jsonObj.dump());
168             throw std::runtime_error(
169                 "Missing required configuration object's name");
170         }
171         _name = jsonObj["name"].get<std::string>();
172     }
173 };
174 
175 } // namespace phosphor::fan::control::json
176