c355fc2a134f30845f0abfcd3ff903b8b42b17bc
[archive/platform/core/system/libConfig.git] / src / config / from-kvjson-visitor.hpp
1 /*
2  *  Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *  Contact: Krzysztof Dynowski (k.dynowski@samsumg.com)
5  *
6  *  Licensed under the Apache License, Version 2.0 (the "License");
7  *  you may not use this file except in compliance with the License.
8  *  You may obtain a copy of the License at
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
12  *  Unless required by applicable law or agreed to in writing, software
13  *  distributed under the License is distributed on an "AS IS" BASIS,
14  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  *  See the License for the specific language governing permissions and
16  *  limitations under the License
17  */
18
19
20 /**
21  * @file
22  * @author  Krzysztof Dynowski (k.dynowski@samsumg.com)
23  * @brief   KVStore visitor with defaults values from json
24  */
25
26 #ifndef CONFIG_FROM_KVJSON_VISITOR_HPP
27 #define CONFIG_FROM_KVJSON_VISITOR_HPP
28
29 #include "config/from-kvstore-visitor.hpp"
30 #include "config/is-union.hpp"
31 #include <json/json.h>
32
33 namespace config {
34
35 class FromKVJsonVisitor {
36 public:
37     FromKVJsonVisitor(const std::string& db, const std::string& json, const std::string& prefix)
38         : mStorePtr(new KVStore(db))
39         , mKeyPrefix(prefix)
40         , mIsUnion(false)
41     {
42         mObject = json_tokener_parse(json.c_str());
43         if (mObject == nullptr) {
44             throw ConfigException("Json parsing error");
45         }
46     }
47
48
49     ~FromKVJsonVisitor() {
50         json_object_put(mObject);
51     }
52
53     FromKVJsonVisitor(const FromKVJsonVisitor& v) :
54         mObject(v.mObject ? json_object_get(v.mObject) : nullptr),
55         mStorePtr(v.mStorePtr),
56         mKeyPrefix(v.mKeyPrefix),
57         mIsUnion(v.mIsUnion)
58     {
59     }
60     FromKVJsonVisitor& operator=(const FromKVJsonVisitor&) = delete;
61
62     template<typename T>
63     void visit(const std::string& name, T& value) {
64         getValue(name, value);
65     }
66
67 private:
68     std::shared_ptr<KVStore> mStorePtr;
69     std::string mKeyPrefix;
70     json_object* mObject;
71     bool mIsUnion;
72
73     // create visitor for field object (visitable object)
74     FromKVJsonVisitor(const FromKVJsonVisitor& v, const std::string& name, const bool isUnion) :
75         mStorePtr(v.mStorePtr), mIsUnion(isUnion || v.mIsUnion)
76     {
77         mKeyPrefix = key(v.mKeyPrefix, name);
78         json_object* object = nullptr;
79         if (v.mObject && !json_object_object_get_ex(v.mObject, name.c_str(), &object)) {
80             if (!mIsUnion)
81                 throw ConfigException("Missing json field " + mKeyPrefix);
82         }
83         mObject = object ? json_object_get(object) : nullptr;
84     }
85
86     // create visitor for vector i-th element (visitable object)
87     FromKVJsonVisitor(const FromKVJsonVisitor& v, int i, const bool isUnion) :
88         mStorePtr(v.mStorePtr), mIsUnion(isUnion || v.mIsUnion)
89     {
90         mKeyPrefix = key(v.mKeyPrefix, std::to_string(i));
91         json_object* object = nullptr;
92         if (v.mObject) {
93             object = json_object_array_get_idx(v.mObject, i);
94             checkType(object, json_type_object);
95         }
96         mObject = object ? json_object_get(object) : nullptr;
97     }
98
99     template<typename T, typename std::enable_if<!isVisitable<T>::value, int>::type = 0>
100     void getValue(const std::string& name, T& t)
101     {
102         std::string k = key(mKeyPrefix, name);
103         if (mStorePtr->exists(k)) {
104             t = mStorePtr->get<T>(k);
105         }
106         else {
107             json_object* object = nullptr;
108             if (mObject) {
109                 json_object_object_get_ex(mObject, name.c_str(), &object);
110             }
111             if (!object) {
112                 throw ConfigException("Missing json field " + key(mKeyPrefix, name));
113             }
114             fromJsonObject(object, t);
115         }
116     }
117
118     template<typename T, typename std::enable_if<isUnion<T>::value, int>::type = 0>
119     void getValue(const std::string& name, T& t)
120     {
121         FromKVJsonVisitor visitor(*this, name, true);
122         t.accept(visitor);
123     }
124
125     template<typename T, typename std::enable_if<isVisitable<T>::value && !isUnion<T>::value, int>::type = 0>
126     void getValue(const std::string& name, T& t)
127     {
128         FromKVJsonVisitor visitor(*this, name, false);
129         t.accept(visitor);
130     }
131
132     int getArraySize(std::string& name, json_object* object)
133     {
134         if (mStorePtr->exists(name)) {
135             return mStorePtr->get<int>(name);
136         }
137         if (object) {
138             return json_object_array_length(object);
139         }
140         return -1;
141     }
142
143     template<typename T>
144     void getValue(const std::string& name, std::vector<T>& value)
145     {
146         json_object* object = nullptr;
147         if (mObject && json_object_object_get_ex(mObject, name.c_str(), &object)) {
148             checkType(object, json_type_array);
149         }
150
151         std::string k = key(mKeyPrefix, name);
152         int length = getArraySize(k, object);
153         if (length < 0) {
154             throw ConfigException("Missing array length " + k);
155         }
156         value.resize(static_cast<size_t>(length));
157         FromKVJsonVisitor visitor(*this, name, false);
158         if (mStorePtr->exists(k)) {
159             visitor.mObject = nullptr;
160         }
161         for (int i = 0; i < length; ++i) {
162             visitor.getValue(i, value[i]);
163         }
164     }
165
166     template<typename T, typename std::enable_if<!isVisitable<T>::value, int>::type = 0>
167     void getValue(int i, T& t)
168     {
169         std::string k = key(mKeyPrefix, std::to_string(i));
170         if (mStorePtr->exists(k)) {
171             t = mStorePtr->get<T>(k);
172         }
173         else {
174             json_object* object = mObject ? json_object_array_get_idx(mObject, i) : nullptr;
175             if (!object) {
176                 throw ConfigException("Missing json array elem " + k);
177             }
178             fromJsonObject(object, t);
179         }
180     }
181
182     template<typename T, typename std::enable_if<isUnion<T>::value, int>::type = 0>
183     void getValue(int i, T& t)
184     {
185         FromKVJsonVisitor visitor(*this, i, true);
186         t.accept(visitor);
187     }
188
189     template<typename T, typename std::enable_if<isVisitable<T>::value && !isUnion<T>::value, int>::type = 0>
190     void getValue(int i, T& t)
191     {
192         FromKVJsonVisitor visitor(*this, i, false);
193         t.accept(visitor);
194     }
195
196     template<typename T>
197     void getValue(int i, std::vector<T>& value)
198     {
199         std::string k = key(mKeyPrefix, std::to_string(i));
200         int length = getArraySize(k, mObject);
201         value.resize(static_cast<size_t>(length));
202         FromKVJsonVisitor visitor(*this, i, false);
203         if (mStorePtr->exists(k)) {
204             visitor.mObject = nullptr;
205         }
206         for (int i = 0; i < length; ++i) {
207             visitor.getValue(i, value[i]);
208         }
209     }
210
211     static void checkType(json_object* object, json_type type)
212     {
213         if (type != json_object_get_type(object)) {
214             throw ConfigException("Invalid field type " + std::to_string(type));
215         }
216     }
217
218     static void fromJsonObject(json_object* object, int& value)
219     {
220         checkType(object, json_type_int);
221         std::int64_t value64 = json_object_get_int64(object);
222         if (value64 > INT32_MAX || value64 < INT32_MIN) {
223             throw ConfigException("Value out of range");
224         }
225         value = static_cast<int>(value64);
226     }
227
228     static void fromJsonObject(json_object* object, std::int64_t& value)
229     {
230         checkType(object, json_type_int);
231         value = json_object_get_int64(object);
232     }
233
234     static void fromJsonObject(json_object* object, bool& value)
235     {
236         checkType(object, json_type_boolean);
237         value = json_object_get_boolean(object);
238     }
239
240     static void fromJsonObject(json_object* object, double& value)
241     {
242         checkType(object, json_type_double);
243         value = json_object_get_double(object);
244     }
245
246     static void fromJsonObject(json_object* object, std::string& value)
247     {
248         checkType(object, json_type_string);
249         value = json_object_get_string(object);
250     }
251 };
252
253 } // namespace config
254
255 #endif // CONFIG_FROM_KVJSON_VISITOR_HPP