Modified item definition format
[platform/core/context/context-provider.git] / src / custom / CustomManager.cpp
1 /*
2  * Copyright (c) 2016 Samsung Electronics Co., Ltd.
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
17 #include <map>
18 #include <Util.h>
19 #include <DatabaseManager.h>
20 #include "CustomManager.h"
21 #include "CustomProvider.h"
22 #include "CustomTypes.h"
23
24 using namespace ctx;
25
26 static std::map<std::string, CustomProvider*> __customMap;
27 static DatabaseManager __dbManager;
28
29 static bool __isValidFact(std::string subject, Json& fact);
30 static bool __checkValueInt(Json& tmpl, std::string key, int value);
31 static bool __checkValueString(Json& tmpl, std::string key, std::string value);
32 static bool __checkValueEnum(Json& tmpl, std::string key, std::string value);
33
34 CustomManager::CustomManager() :
35         BasicProvider(SUBJ_CUSTOM)
36 {
37         __initialize();
38 }
39
40 CustomManager::~CustomManager()
41 {
42         /* Custom provider instances will be deleted by Provider Handler */
43         __customMap.clear();
44 }
45
46 bool CustomManager::isSupported()
47 {
48         return true;
49 }
50
51 bool CustomManager::unloadable()
52 {
53         return false;
54 }
55
56 int CustomManager::subscribe()
57 {
58         return ERR_NONE;
59 }
60
61 int CustomManager::unsubscribe()
62 {
63         return ERR_NONE;
64 }
65
66 int CustomManager::write(Json data, Json *requestResult)
67 {
68         int error = ERR_NONE;
69         std::string req;
70         data.get(NULL, CUSTOM_KEY_REQ, &req);
71
72         std::string packageId;
73         std::string name;
74         data.get(NULL, KEY_CLIENT_PKG_ID, &packageId);
75         data.get(NULL, CUSTOM_KEY_NAME, &name);
76         std::string subj = std::string(SUBJ_CUSTOM) + CUSTOM_SEPERATOR + packageId + CUSTOM_SEPERATOR + name;
77
78         if (req == CUSTOM_REQ_TYPE_ADD) {
79                 Json tmpl;
80                 data.get(NULL, CUSTOM_KEY_ATTRIBUTES, &tmpl);
81
82                 error = __addCustomItem(subj, name, tmpl, packageId);
83         } else if (req == CUSTOM_REQ_TYPE_REMOVE) {
84                 error = __removeCustomItem(subj);
85                 if (error == ERR_NONE) {
86                         requestResult->set(NULL, CUSTOM_KEY_SUBJECT, subj);
87                 }
88         } else if (req == CUSTOM_REQ_TYPE_PUBLISH) {
89                 Json fact;
90                 data.get(NULL, CUSTOM_KEY_FACT, &fact);
91
92                 error = __publishData(subj, fact);
93         }
94
95         return error;
96 }
97
98 ContextProvider* CustomManager::getProvider(const char* subject)
99 {
100         auto it = __customMap.find(subject);
101         IF_FAIL_RETURN_TAG(it != __customMap.end(), NULL, _E, "'%s' not found", subject);
102
103         CustomProvider* custom = static_cast<CustomProvider*>(it->second);
104         return custom;
105 }
106
107 bool CustomManager::__initialize()
108 {
109         /* Create custom template table */
110         std::vector<Json> record;
111         bool ret = __dbManager.executeSync(CUSTOM_TEMPLATE_TABLE_SCHEMA, &record);
112         IF_FAIL_RETURN_TAG(ret, false, _E, "Create template table failed");
113
114         /* Register custom items */
115         std::string qSelect = "SELECT * FROM ContextTriggerCustomTemplate";
116         ret = __dbManager.executeSync(qSelect.c_str(), &record);
117         IF_FAIL_RETURN_TAG(ret, false, _E, "Failed to query custom templates");
118         IF_FAIL_RETURN(record.size() > 0, true);
119
120         int error;
121         std::vector<Json>::iterator vedEnd = record.end();
122         for (auto vecPos = record.begin(); vecPos != vedEnd; ++vecPos) {
123                 Json elem = *vecPos;
124                 std::string subject;
125                 std::string name;
126                 std::string attributes;
127                 std::string owner;
128                 elem.get(NULL, CUSTOM_KEY_SUBJECT, &subject);
129                 elem.get(NULL, CUSTOM_KEY_NAME, &name);
130                 elem.get(NULL, CUSTOM_KEY_ATTRIBUTES, &attributes);
131                 elem.get(NULL, CUSTOM_KEY_OWNER, &owner);
132
133                 error = __addCustomItem(subject.c_str(), name, Json(attributes), owner, true);
134                 if (error != ERR_NONE) {
135                         _E("Failed to add custom item(%s): %#x", subject.c_str(), error);
136                 }
137         }
138
139         return true;
140 }
141
142 int CustomManager::__addCustomItem(std::string subject, std::string name, Json tmpl, std::string owner, bool isInit)
143 {
144         std::map<std::string, CustomProvider*>::iterator it;
145         it = __customMap.find(subject);
146
147         if (it != __customMap.end()) {
148                 if ((it->second)->getTemplate() != tmpl) {      /* Same item name, different template */
149                         return ERR_DATA_EXIST;
150                 }
151
152                 return ERR_NONE;        /* Same item */
153         }
154
155         /* Create custom provider */
156         CustomProvider* custom = new(std::nothrow) CustomProvider(subject.c_str(), name, tmpl, owner);
157         IF_FAIL_RETURN_TAG(custom, ERR_OUT_OF_MEMORY, _E, "Memory allocation failed");
158         __customMap[subject] = custom;
159
160         /* Register provider handler & template */
161         registerCustomProvider(subject.c_str(), OPS_SUBSCRIBE | OPS_READ, tmpl, NULL, owner.c_str());
162
163         /* Insert item to custom template db */
164         if (!isInit) {
165                 std::string q = "INSERT OR IGNORE INTO ContextTriggerCustomTemplate (subject, name, attributes, owner) VALUES ('"
166                                 + subject + "', '" + name +  "', '" + tmpl.str() + "', '" + owner + "'); ";
167                 std::vector<Json> record;
168                 bool ret = __dbManager.executeSync(q.c_str(), &record);
169                 IF_FAIL_RETURN_TAG(ret, ERR_OPERATION_FAILED, _E, "Failed to query custom templates");
170         }
171
172         return ERR_NONE;
173 }
174
175 int CustomManager::__removeCustomItem(std::string subject)
176 {
177         std::map<std::string, CustomProvider*>::iterator it;
178         it = __customMap.find(subject);
179         IF_FAIL_RETURN_TAG(it != __customMap.end(), ERR_NOT_SUPPORTED, _E, "%s not supported", subject.c_str());
180
181         /* Unregister provider handler & template */
182         unregisterCustomProvider(subject.c_str());
183         __customMap.erase(it);
184
185         /* Delete item from custom template db */
186         std::string q = "DELETE FROM ContextTriggerCustomTemplate WHERE subject = '" + subject + "'";
187         std::vector<Json> record;
188         bool ret = __dbManager.executeSync(q.c_str(), &record);
189         IF_FAIL_RETURN_TAG(ret, ERR_OPERATION_FAILED, _E, "Failed to query custom templates");
190
191         return ERR_NONE;
192 }
193
194 int CustomManager::__publishData(std::string subject, Json fact)
195 {
196         std::map<std::string, CustomProvider*>::iterator it;
197         it = __customMap.find(subject);
198         IF_FAIL_RETURN_TAG(it != __customMap.end(), ERR_NOT_SUPPORTED, _E, "%s not supported", subject.c_str());
199
200         bool ret = __isValidFact(subject, fact);
201         IF_FAIL_RETURN_TAG(ret, ERR_INVALID_DATA, _E, "Invalid fact(%s)", subject.c_str());
202
203         __customMap[subject]->handleUpdate(fact);
204         return ERR_NONE;
205 }
206
207 bool __isValidFact(std::string subject, Json& fact)
208 {
209         Json tmpl = __customMap[subject]->getTemplate();
210         IF_FAIL_RETURN_TAG(tmpl != EMPTY_JSON_OBJECT, false, _E, "Failed to get template");
211
212         bool ret;
213         std::list<std::string> keys;
214         fact.getKeys(&keys);
215
216         for (std::list<std::string>::iterator it = keys.begin(); it != keys.end(); it++) {
217                 std::string key = *it;
218
219                 std::string type;
220                 ret = tmpl.get(key.c_str(), "type", &type);
221                 if (!ret) {
222                         int size = tmpl.getSize(key.c_str(), "enum");
223                         IF_FAIL_RETURN_TAG(size >= 0, false, _E, "Invalid template");
224                         type = "enum";
225                 }
226
227                 if (type == "integer") {
228                         int val;
229                         ret = fact.get(NULL, key.c_str(), &val);
230                         IF_FAIL_RETURN_TAG(ret, false, _E, "Custom fact: invalid data type");
231
232                         ret = __checkValueInt(tmpl, key, val);
233                         IF_FAIL_RETURN_TAG(ret, false, _E, "Custom fact: invalid value");
234                 } else if (type == "string") {
235                         std::string val_str;
236                         ret = fact.get(NULL, key.c_str(), &val_str);
237                         IF_FAIL_RETURN_TAG(ret, false, _E, "Custom fact: invalid data type");
238
239                         ret = __checkValueString(tmpl, key, val_str);
240                         IF_FAIL_RETURN_TAG(ret, false, _E, "Custom fact: invalid value");
241                 } else if (type == "enum") {
242                         std::string val_str;
243                         ret = fact.get(NULL, key.c_str(), &val_str);
244                         IF_FAIL_RETURN_TAG(ret, false, _E, "Custom fact: invalid data type");
245
246                         ret = __checkValueEnum(tmpl, key, val_str);
247                         IF_FAIL_RETURN_TAG(ret, false, _E, "Custom fact: invalid value");
248                 } else {
249                         _E("Custom fact: invalid data type");
250                         return false;
251                 }
252         }
253
254         return true;
255 }
256
257 bool __checkValueInt(Json& tmpl, std::string key, int value)
258 {
259         int min, max;
260
261         if (tmpl.get(key.c_str(), "minimum", &min)) {
262                 IF_FAIL_RETURN(value >= min, false);
263         }
264
265         if (tmpl.get(key.c_str(), "maximum", &max)) {
266                 IF_FAIL_RETURN(value <= max, false);
267         }
268
269         return true;
270 }
271
272 bool __checkValueString(Json& tmpl, std::string key, std::string value)
273 {
274         /* any value is accepted */
275         return true;
276 }
277
278 bool __checkValueEnum(Json& tmpl, std::string key, std::string value)
279 {
280         /* check acceptable value */
281         std::string tmplValue;
282         for (int i = 0; tmpl.getAt(key.c_str(), "enum", i, &tmplValue); i++) {
283                 if (tmplValue == value)
284                         return true;
285         }
286
287         return false;
288 }