2624ad31c80a14bd9b060c5065880bf4a907b680
[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         , mTransaction(mStorePtr->getTransaction())
42     {
43         mObject = json_tokener_parse(json.c_str());
44         if (mObject == nullptr) {
45             throw ConfigException("Json parsing error");
46         }
47     }
48
49
50     ~FromKVJsonVisitor() {
51         json_object_put(mObject);
52     }
53
54     FromKVJsonVisitor(const FromKVJsonVisitor& v) :
55         mObject(v.mObject ? json_object_get(v.mObject) : nullptr),
56         mStorePtr(v.mStorePtr),
57         mKeyPrefix(v.mKeyPrefix),
58         mIsUnion(v.mIsUnion),
59         mTransaction(v.mTransaction)
60     {
61     }
62     FromKVJsonVisitor& operator=(const FromKVJsonVisitor&) = delete;
63
64     template<typename T>
65     void visit(const std::string& name, T& value) {
66         getValue(name, value);
67     }
68
69 private:
70     std::shared_ptr<KVStore> mStorePtr;
71     std::string mKeyPrefix;
72     json_object* mObject;
73     bool mIsUnion;
74     KVStore::Transaction mTransaction;
75
76     // create visitor for field object (visitable object)
77     FromKVJsonVisitor(const FromKVJsonVisitor& v, const std::string& name, const bool isUnion) :
78         mStorePtr(v.mStorePtr),
79         mKeyPrefix(key(v.mKeyPrefix, name)),
80         mIsUnion(isUnion || v.mIsUnion),
81         mTransaction(v.mTransaction)
82     {
83         json_object* object = nullptr;
84         if (v.mObject && !json_object_object_get_ex(v.mObject, name.c_str(), &object)) {
85             if (!mIsUnion)
86                 throw ConfigException("Missing json field " + mKeyPrefix);
87         }
88         mObject = object ? json_object_get(object) : nullptr;
89     }
90
91     // create visitor for vector i-th element (visitable object)
92     FromKVJsonVisitor(const FromKVJsonVisitor& v, int i, const bool isUnion) :
93         mStorePtr(v.mStorePtr),
94         mKeyPrefix(key(v.mKeyPrefix, std::to_string(i))),
95         mIsUnion(isUnion || v.mIsUnion),
96         mTransaction(v.mTransaction)
97     {
98         json_object* object = nullptr;
99         if (v.mObject) {
100             object = json_object_array_get_idx(v.mObject, i);
101             checkType(object, json_type_object);
102         }
103         mObject = object ? json_object_get(object) : nullptr;
104     }
105
106     template<typename T, typename std::enable_if<!isVisitable<T>::value, int>::type = 0>
107     void getValue(const std::string& name, T& t)
108     {
109         std::string k = key(mKeyPrefix, name);
110         if (mStorePtr->exists(k)) {
111             t = mStorePtr->get<T>(k);
112         }
113         else {
114             json_object* object = nullptr;
115             if (mObject) {
116                 json_object_object_get_ex(mObject, name.c_str(), &object);
117             }
118             if (!object) {
119                 throw ConfigException("Missing json field " + key(mKeyPrefix, name));
120             }
121             fromJsonObject(object, t);
122         }
123     }
124
125     template<typename T, typename std::enable_if<isUnion<T>::value, int>::type = 0>
126     void getValue(const std::string& name, T& t)
127     {
128         FromKVJsonVisitor visitor(*this, name, true);
129         t.accept(visitor);
130     }
131
132     template<typename T, typename std::enable_if<isVisitable<T>::value && !isUnion<T>::value, int>::type = 0>
133     void getValue(const std::string& name, T& t)
134     {
135         FromKVJsonVisitor visitor(*this, name, false);
136         t.accept(visitor);
137     }
138
139     int getArraySize(std::string& name, json_object* object)
140     {
141         if (mStorePtr->exists(name)) {
142             return mStorePtr->get<int>(name);
143         }
144         if (object) {
145             return json_object_array_length(object);
146         }
147         return -1;
148     }
149
150     template<typename T>
151     void getValue(const std::string& name, std::vector<T>& value)
152     {
153         json_object* object = nullptr;
154         if (mObject && json_object_object_get_ex(mObject, name.c_str(), &object)) {
155             checkType(object, json_type_array);
156         }
157
158         std::string k = key(mKeyPrefix, name);
159         int length = getArraySize(k, object);
160         if (length < 0) {
161             throw ConfigException("Missing array length " + k);
162         }
163         value.resize(static_cast<size_t>(length));
164         FromKVJsonVisitor visitor(*this, name, false);
165         if (mStorePtr->exists(k)) {
166             json_object_put(visitor.mObject);
167             visitor.mObject = nullptr;
168         }
169         for (int i = 0; i < length; ++i) {
170             visitor.getValue(i, value[i]);
171         }
172     }
173
174     template<typename T, typename std::enable_if<!isVisitable<T>::value, int>::type = 0>
175     void getValue(int i, T& t)
176     {
177         std::string k = key(mKeyPrefix, std::to_string(i));
178         if (mStorePtr->exists(k)) {
179             t = mStorePtr->get<T>(k);
180         }
181         else {
182             json_object* object = mObject ? json_object_array_get_idx(mObject, i) : nullptr;
183             if (!object) {
184                 throw ConfigException("Missing json array elem " + k);
185             }
186             fromJsonObject(object, t);
187         }
188     }
189
190     template<typename T, typename std::enable_if<isUnion<T>::value, int>::type = 0>
191     void getValue(int i, T& t)
192     {
193         FromKVJsonVisitor visitor(*this, i, true);
194         t.accept(visitor);
195     }
196
197     template<typename T, typename std::enable_if<isVisitable<T>::value && !isUnion<T>::value, int>::type = 0>
198     void getValue(int i, T& t)
199     {
200         FromKVJsonVisitor visitor(*this, i, false);
201         t.accept(visitor);
202     }
203
204     template<typename T>
205     void getValue(int i, std::vector<T>& value)
206     {
207         std::string k = key(mKeyPrefix, std::to_string(i));
208         int length = getArraySize(k, mObject);
209         value.resize(static_cast<size_t>(length));
210         FromKVJsonVisitor visitor(*this, i, false);
211         if (mStorePtr->exists(k)) {
212             json_object_put(visitor.mObject);
213             visitor.mObject = nullptr;
214         }
215         for (int i = 0; i < length; ++i) {
216             visitor.getValue(i, value[i]);
217         }
218     }
219
220     static void checkType(json_object* object, json_type type)
221     {
222         if (type != json_object_get_type(object)) {
223             throw ConfigException("Invalid field type " + std::to_string(type));
224         }
225     }
226
227     static void fromJsonObject(json_object* object, int& value)
228     {
229         checkType(object, json_type_int);
230         std::int64_t value64 = json_object_get_int64(object);
231         if (value64 > INT32_MAX || value64 < INT32_MIN) {
232             throw ConfigException("Value out of range");
233         }
234         value = static_cast<int>(value64);
235     }
236
237     static void fromJsonObject(json_object* object, std::int64_t& value)
238     {
239         checkType(object, json_type_int);
240         value = json_object_get_int64(object);
241     }
242
243     static void fromJsonObject(json_object* object, bool& value)
244     {
245         checkType(object, json_type_boolean);
246         value = json_object_get_boolean(object);
247     }
248
249     static void fromJsonObject(json_object* object, double& value)
250     {
251         checkType(object, json_type_double);
252         value = json_object_get_double(object);
253     }
254
255     static void fromJsonObject(json_object* object, std::string& value)
256     {
257         checkType(object, json_type_string);
258         value = json_object_get_string(object);
259     }
260 };
261
262 } // namespace config
263
264 #endif // CONFIG_FROM_KVJSON_VISITOR_HPP