tizen 2.4 release
[framework/context/context-service.git] / src / context_mgr_impl.cpp
1 /*
2  * Copyright (c) 2015 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 <glib.h>
18 #include <string>
19 #include <list>
20
21 #include <types_internal.h>
22 #include <json.h>
23 #include <provider_iface.h>
24 #include "server.h"
25 #include "context_mgr_impl.h"
26 #include "access_control/privilege.h"
27
28 /* Context Providers */
29 #include <internal/device_context_provider.h>
30 #include <internal/statistics_context_provider.h>
31 #include <internal/place_context_provider.h>
32
33 struct trigger_item_format_s {
34         std::string subject;
35         int operation;
36         ctx::json attributes;
37         ctx::json options;
38         trigger_item_format_s(std::string subj, int ops, ctx::json attr, ctx::json opt)
39                 : subject(subj), operation(ops), attributes(attr), options(opt) {}
40 };
41
42 static std::list<trigger_item_format_s> __trigger_item_list;
43
44 ctx::context_manager_impl::context_manager_impl()
45 {
46 }
47
48 ctx::context_manager_impl::~context_manager_impl()
49 {
50         release();
51 }
52
53 bool ctx::context_manager_impl::init()
54 {
55         bool ret;
56
57         ret = init_device_context_provider();
58         IF_FAIL_RETURN_TAG(ret, false, _E, "Initialization failed: device-context-provider");
59
60         ret = init_statistics_context_provider();
61         IF_FAIL_RETURN_TAG(ret, false, _E, "Initialization failed: statistics-context-provider");
62
63         ret = init_place_context_provider();
64         IF_FAIL_RETURN_TAG(ret, false, _E, "Initialization failed: place-context-provider");
65
66         return true;
67 }
68
69 void ctx::context_manager_impl::release()
70 {
71         for (provider_map_t::iterator it = provider_map.begin(); it != provider_map.end(); ++it) {
72                 it->second.destroy(it->second.data);
73         }
74         provider_map.clear();
75
76         for (request_list_t::iterator it = subscribe_request_list.begin(); it != subscribe_request_list.end(); ++it) {
77                 delete *it;
78         }
79         subscribe_request_list.clear();
80
81         for (request_list_t::iterator it = read_request_list.begin(); it != read_request_list.end(); ++it) {
82                 delete *it;
83         }
84         read_request_list.clear();
85 }
86
87 bool ctx::context_manager_impl::register_provider(const char *subject, ctx::context_provider_info &provider_info)
88 {
89         if (provider_map.find(subject) != provider_map.end()) {
90                 _E("The provider for the subject '%s' is already registered.", subject);
91                 return false;
92         }
93
94         _SI("Subj: %s, Priv: %s", subject, provider_info.privilege);
95         provider_map[subject] = provider_info;
96
97         return true;
98 }
99
100 bool ctx::context_manager_impl::register_trigger_item(const char *subject, int operation, ctx::json attributes, ctx::json options)
101 {
102         IF_FAIL_RETURN_TAG(subject, false, _E, "Invalid parameter");
103         __trigger_item_list.push_back(trigger_item_format_s(subject, operation, attributes, options));
104         return true;
105 }
106
107 bool ctx::context_manager_impl::pop_trigger_item(std::string &subject, int &operation, ctx::json &attributes, ctx::json &options)
108 {
109         IF_FAIL_RETURN(!__trigger_item_list.empty(), false);
110
111         trigger_item_format_s format = __trigger_item_list.front();
112         __trigger_item_list.pop_front();
113
114         subject = format.subject;
115         operation = format.operation;
116         attributes = format.attributes;
117         options = format.options;
118
119         return true;
120 }
121
122 void ctx::context_manager_impl::assign_request(ctx::request_info* request)
123 {
124         switch (request->get_type()) {
125         case REQ_SUBSCRIBE:
126                 subscribe(request);
127                 break;
128         case REQ_UNSUBSCRIBE:
129                 unsubscribe(request);
130                 break;
131         case REQ_READ:
132         case REQ_READ_SYNC:
133                 read(request);
134                 break;
135         case REQ_WRITE:
136                 write(request);
137                 break;
138         case REQ_SUPPORT:
139                 is_supported(request);
140                 break;
141         default:
142                 _E("Invalid type of request");
143                 delete request;
144         }
145 }
146
147 bool ctx::context_manager_impl::is_supported(const char *subject)
148 {
149         provider_map_t::iterator it = provider_map.find(subject);
150         return (it != provider_map.end());
151 }
152
153 void ctx::context_manager_impl::is_supported(request_info *request)
154 {
155         if (is_supported(request->get_subject()))
156                 request->reply(ERR_NONE);
157         else
158                 request->reply(ERR_NOT_SUPPORTED);
159
160         delete request;
161 }
162
163 bool ctx::context_manager_impl::is_allowed(const char *client, const char *subject)
164 {
165         provider_map_t::iterator it = provider_map.find(subject);
166         IF_FAIL_RETURN(it != provider_map.end(), false);
167         IF_FAIL_RETURN(ctx::privilege_manager::is_allowed(client, it->second.privilege), false);
168         return true;
169 }
170
171 ctx::context_manager_impl::request_list_t::iterator
172 ctx::context_manager_impl::find_request(request_list_t& r_list, std::string subject, json& option)
173 {
174         return find_request(r_list.begin(), r_list.end(), subject, option);
175 }
176
177 ctx::context_manager_impl::request_list_t::iterator
178 ctx::context_manager_impl::find_request(request_list_t& r_list, std::string client, int req_id)
179 {
180         request_list_t::iterator it;
181         for (it = r_list.begin(); it != r_list.end(); ++it) {
182                 if (client == (*it)->get_client() && req_id == (*it)->get_id()) {
183                         break;
184                 }
185         }
186         return it;
187 }
188
189 ctx::context_manager_impl::request_list_t::iterator
190 ctx::context_manager_impl::find_request(request_list_t::iterator begin, request_list_t::iterator end, std::string subject, json& option)
191 {
192         //TODO: Do we need to consider the case that the inparam option is a subset of the request description?
193         request_list_t::iterator it;
194         for (it = begin; it != end; ++it) {
195                 if (subject == (*it)->get_subject() && option == (*it)->get_description()) {
196                         break;
197                 }
198         }
199         return it;
200 }
201
202 ctx::context_provider_iface *ctx::context_manager_impl::get_provider(ctx::request_info *request)
203 {
204         provider_map_t::iterator it = provider_map.find(request->get_subject());
205
206         if (it == provider_map.end()) {
207                 _W("Unsupported subject");
208                 request->reply(ERR_NOT_SUPPORTED);
209                 delete request;
210                 return NULL;
211         }
212
213         if (!STR_EQ(TRIGGER_CLIENT_NAME, request->get_client()) &&
214                         !ctx::privilege_manager::is_allowed(request->get_client(), it->second.privilege)) {
215                 _W("Permission denied");
216                 request->reply(ERR_PERMISSION_DENIED);
217                 delete request;
218                 return NULL;
219         }
220
221         return it->second.create(it->second.data);
222 }
223
224 void ctx::context_manager_impl::subscribe(ctx::request_info *request)
225 {
226         _I(CYAN("'%s' subscribes '%s' (RID-%d)"), request->get_client(), request->get_subject(), request->get_id());
227
228         context_provider_iface *provider = get_provider(request);
229         IF_FAIL_VOID(provider);
230
231         ctx::json request_result;
232         int error = provider->subscribe(request->get_subject(), request->get_description().str(), &request_result);
233
234         _D("Analyzer returned %d", error);
235
236         if (!request->reply(error, request_result) || error != ERR_NONE) {
237                 delete request;
238                 return;
239         }
240
241         subscribe_request_list.push_back(request);
242 }
243
244 void ctx::context_manager_impl::unsubscribe(ctx::request_info *request)
245 {
246         _I(CYAN("'%s' unsubscribes '%s' (RID-%d)"), request->get_client(), request->get_subject(), request->get_id());
247
248         // Search the subscribe request to be removed
249         request_list_t::iterator target = find_request(subscribe_request_list, request->get_client(), request->get_id());
250         if (target == subscribe_request_list.end()) {
251                 _W("Unknown request");
252                 delete request;
253                 return;
254         }
255
256         // Keep the pointer to the request found
257         request_info *req_found = *target;
258
259         // Remove the request from the list
260         subscribe_request_list.erase(target);
261
262         // Check if there exist the same requests
263         if (find_request(subscribe_request_list, req_found->get_subject(), req_found->get_description()) != subscribe_request_list.end()) {
264                 // Do not stop detecting the subject
265                 _D("A same request from '%s' exists", req_found->get_client());
266                 request->reply(ERR_NONE);
267                 delete request;
268                 delete req_found;
269                 return;
270         }
271
272         // Find the proper provider
273         provider_map_t::iterator ca = provider_map.find(req_found->get_subject());
274         if (ca == provider_map.end()) {
275                 _E("Invalid subject '%s'", req_found->get_subject());
276                 delete request;
277                 delete req_found;
278                 return;
279         }
280
281         // Stop detecting the subject
282         int error = ca->second.create(ca->second.data)->unsubscribe(req_found->get_subject(), req_found->get_description());
283         request->reply(error);
284         delete request;
285         delete req_found;
286 }
287
288 void ctx::context_manager_impl::read(ctx::request_info *request)
289 {
290         _I(CYAN("'%s' reads '%s' (RID-%d)"), request->get_client(), request->get_subject(), request->get_id());
291
292         context_provider_iface *provider = get_provider(request);
293         IF_FAIL_VOID(provider);
294
295         ctx::json request_result;
296         int error = provider->read(request->get_subject(), request->get_description().str(), &request_result);
297
298         _D("Analyzer returned %d", error);
299
300         if (!request->reply(error, request_result) || error != ERR_NONE) {
301                 delete request;
302                 return;
303         }
304
305         read_request_list.push_back(request);
306 }
307
308 void ctx::context_manager_impl::write(ctx::request_info *request)
309 {
310         _I(CYAN("'%s' writes '%s' (RID-%d)"), request->get_client(), request->get_subject(), request->get_id());
311
312         context_provider_iface *provider = get_provider(request);
313         IF_FAIL_VOID(provider);
314
315         ctx::json request_result;
316         int error = provider->write(request->get_subject(), request->get_description(), &request_result);
317
318         _D("Analyzer returned %d", error);
319
320         request->reply(error, request_result);
321         delete request;
322 }
323
324 bool ctx::context_manager_impl::_publish(const char* subject, ctx::json option, int error, ctx::json data_updated)
325 {
326         IF_FAIL_RETURN_TAG(subject, false, _E, "Invalid parameter");
327
328         _I("Publishing '%s'", subject);
329         _J("Option", option);
330
331         request_list_t::iterator end = subscribe_request_list.end();
332         request_list_t::iterator target = find_request(subscribe_request_list.begin(), end, subject, option);
333
334         while (target != end) {
335                 if (!(*target)->publish(error, data_updated)) {
336                         return false;
337                 }
338                 target = find_request(++target, end, subject, option);
339         }
340
341         return true;
342 }
343
344 bool ctx::context_manager_impl::_reply_to_read(const char* subject, ctx::json option, int error, ctx::json data_read)
345 {
346         IF_FAIL_RETURN_TAG(subject, false, _E, "Invalid parameter");
347
348         _I("Sending data of '%s'", subject);
349         _J("Option", option);
350         _J("Data", data_read);
351
352         request_list_t::iterator end = read_request_list.end();
353         request_list_t::iterator target = find_request(read_request_list.begin(), end, subject, option);
354         request_list_t::iterator prev;
355
356         ctx::json dummy;
357
358         while (target != end) {
359                 (*target)->reply(error, dummy, data_read);
360                 prev = target;
361                 target = find_request(++target, end, subject, option);
362
363                 delete *prev;
364                 read_request_list.erase(prev);
365         }
366
367         return true;
368 }
369
370 struct published_data_s {
371         int type;
372         ctx::context_manager_impl *mgr;
373         std::string subject;
374         int error;
375         ctx::json option;
376         ctx::json data;
377         published_data_s(int t, ctx::context_manager_impl *m, const char* s, ctx::json& o, int e, ctx::json& d)
378                 : type(t), mgr(m), subject(s), error(e)
379         {
380                 option = o.str();
381                 data = d.str();
382         }
383 };
384
385 gboolean ctx::context_manager_impl::thread_switcher(gpointer data)
386 {
387         published_data_s *tuple = static_cast<published_data_s*>(data);
388
389         switch (tuple->type) {
390                 case REQ_SUBSCRIBE:
391                         tuple->mgr->_publish(tuple->subject.c_str(), tuple->option, tuple->error, tuple->data);
392                         break;
393                 case REQ_READ:
394                         tuple->mgr->_reply_to_read(tuple->subject.c_str(), tuple->option, tuple->error, tuple->data);
395                         break;
396                 default:
397                         _W("Invalid type");
398         }
399
400         delete tuple;
401         return FALSE;
402 }
403
404 bool ctx::context_manager_impl::publish(const char* subject, ctx::json& option, int error, ctx::json& data_updated)
405 {
406         IF_FAIL_RETURN_TAG(subject, false, _E, "Invalid parameter");
407
408         published_data_s *tuple = new(std::nothrow) published_data_s(REQ_SUBSCRIBE, this, subject, option, error, data_updated);
409         IF_FAIL_RETURN_TAG(tuple, false, _E, "Memory allocation failed");
410
411         g_idle_add(thread_switcher, tuple);
412
413         return true;
414 }
415
416 bool ctx::context_manager_impl::reply_to_read(const char* subject, ctx::json& option, int error, ctx::json& data_read)
417 {
418         IF_FAIL_RETURN_TAG(subject, false, _E, "Invalid parameter");
419
420         published_data_s *tuple = new(std::nothrow) published_data_s(REQ_READ, this, subject, option, error, data_read);
421         IF_FAIL_RETURN_TAG(tuple, false, _E, "Memory allocation failed");
422
423         g_idle_add(thread_switcher, tuple);
424
425         return true;
426 }