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