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