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 "types.hpp"
19 
20 #include <nlohmann/json.hpp>
21 #include <phosphor-logging/log.hpp>
22 
23 namespace phosphor::fan::control::json
24 {
25 
26 using json = nlohmann::json;
27 using namespace phosphor::logging;
28 
29 /**
30  * @class ConfigBase - Base configuration object
31  *
32  * Base class for fan control's JSON configuration objects.
33  */
34 class ConfigBase
35 {
36   public:
37     ConfigBase() = delete;
38     ConfigBase(const ConfigBase&) = delete;
39     ConfigBase(ConfigBase&&) = delete;
40     ConfigBase& operator=(const ConfigBase&) = delete;
41     ConfigBase& operator=(ConfigBase&&) = delete;
42     virtual ~ConfigBase() = default;
43 
44     explicit ConfigBase(const json& jsonObj)
45     {
46         // Set the name of this configuration object
47         setName(jsonObj);
48     }
49 
50     /**
51      * @brief Get the configuration object's name
52      *
53      * @return Name of the configuration object
54      */
55     inline const std::string& getName() const
56     {
57         return _name;
58     }
59 
60     /**
61      * @brief Get the configuration object's list of profiles
62      *
63      * Gets the list of profiles this configuration object belongs to if any
64      * are configured, otherwise an empty list of profiles results in the
65      * object always being included in the configuration.
66      *
67      * @return List of profiles the configuration object belongs to
68      */
69     inline const auto& getProfiles() const
70     {
71         return _profiles;
72     }
73 
74   protected:
75     /**
76      * @brief Determines the data type of a JSON configured parameter that is
77      * used as a variant within the fan control application and returns the
78      * value as that variant.
79      * @details Retrieves a JSON object by the first derived data type that
80      * is not null. Expected data types should appear in a logical order of
81      * conversion. i.e.) uint and int could both be uint
82      *
83      * @param[in] object - A single JSON object
84      *
85      * @return A `PropertyVariantType` variant containing the JSON object's
86      * value
87      */
88     static const PropertyVariantType getJsonValue(const json& object)
89     {
90         if (auto boolPtr = object.get_ptr<const bool*>())
91         {
92             return *boolPtr;
93         }
94         if (auto intPtr = object.get_ptr<const int64_t*>())
95         {
96             return *intPtr;
97         }
98         if (auto doublePtr = object.get_ptr<const double*>())
99         {
100             return *doublePtr;
101         }
102         if (auto stringPtr = object.get_ptr<const std::string*>())
103         {
104             return *stringPtr;
105         }
106 
107         log<level::ERR>(
108             "Unsupported data type for JSON object's value",
109             entry("JSON_ENTRY=%s", object.dump().c_str()),
110             entry("SUPPORTED_TYPES=%s", "{bool, int, double, string}"));
111         throw std::runtime_error(
112             "Unsupported data type for JSON object's value");
113     }
114 
115     /**
116      * Profiles this configuration object belongs to (OPTIONAL).
117      * Otherwise always include this object in the configuration
118      * when no profiles are given
119      */
120     std::vector<std::string> _profiles;
121 
122   private:
123     /* Name of the configuration object */
124     std::string _name;
125 
126     /**
127      * @brief Sets the configuration object's name from the given JSON
128      *
129      * @param[in] jsonObj - JSON to get configuration object's name from
130      */
131     inline void setName(const json& jsonObj)
132     {
133         if (!jsonObj.contains("name"))
134         {
135             // Log error on missing configuration object's name
136             log<level::ERR>("Missing required configuration object's name",
137                             entry("JSON=%s", jsonObj.dump().c_str()));
138             throw std::runtime_error(
139                 "Missing required configuration object's name");
140         }
141         _name = jsonObj["name"].get<std::string>();
142     }
143 };
144 
145 } // namespace phosphor::fan::control::json
146