2 * Copyright (c) 2015 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 #include <types_internal.h>
23 #include <provider_iface.h>
25 #include "context_mgr_impl.h"
26 #include "access_control/privilege.h"
28 /* Context Providers */
29 #include <internal/device_context_provider.h>
30 #include <internal/statistics_context_provider.h>
31 #include <internal/place_context_provider.h>
33 struct trigger_item_format_s {
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) {}
42 static std::list<trigger_item_format_s> __trigger_item_list;
44 ctx::context_manager_impl::context_manager_impl()
48 ctx::context_manager_impl::~context_manager_impl()
53 bool ctx::context_manager_impl::init()
57 ret = init_device_context_provider();
58 IF_FAIL_RETURN_TAG(ret, false, _E, "Initialization failed: device-context-provider");
60 ret = init_statistics_context_provider();
61 IF_FAIL_RETURN_TAG(ret, false, _E, "Initialization failed: statistics-context-provider");
63 ret = init_place_context_provider();
64 IF_FAIL_RETURN_TAG(ret, false, _E, "Initialization failed: place-context-provider");
69 void ctx::context_manager_impl::release()
71 for (provider_map_t::iterator it = provider_map.begin(); it != provider_map.end(); ++it) {
72 it->second.destroy(it->second.data);
76 for (request_list_t::iterator it = subscribe_request_list.begin(); it != subscribe_request_list.end(); ++it) {
79 subscribe_request_list.clear();
81 for (request_list_t::iterator it = read_request_list.begin(); it != read_request_list.end(); ++it) {
84 read_request_list.clear();
87 bool ctx::context_manager_impl::register_provider(const char *subject, ctx::context_provider_info &provider_info)
89 if (provider_map.find(subject) != provider_map.end()) {
90 _E("The provider for the subject '%s' is already registered.", subject);
94 _SI("Subj: %s, Priv: %s", subject, provider_info.privilege);
95 provider_map[subject] = provider_info;
100 bool ctx::context_manager_impl::register_trigger_item(const char *subject, int operation, ctx::json attributes, ctx::json options)
102 IF_FAIL_RETURN_TAG(subject, false, _E, "Invalid parameter");
103 __trigger_item_list.push_back(trigger_item_format_s(subject, operation, attributes, options));
107 bool ctx::context_manager_impl::pop_trigger_item(std::string &subject, int &operation, ctx::json &attributes, ctx::json &options)
109 IF_FAIL_RETURN(!__trigger_item_list.empty(), false);
111 trigger_item_format_s format = __trigger_item_list.front();
112 __trigger_item_list.pop_front();
114 subject = format.subject;
115 operation = format.operation;
116 attributes = format.attributes;
117 options = format.options;
122 void ctx::context_manager_impl::assign_request(ctx::request_info* request)
124 switch (request->get_type()) {
128 case REQ_UNSUBSCRIBE:
129 unsubscribe(request);
139 is_supported(request);
142 _E("Invalid type of request");
147 bool ctx::context_manager_impl::is_supported(const char *subject)
149 provider_map_t::iterator it = provider_map.find(subject);
150 return (it != provider_map.end());
153 void ctx::context_manager_impl::is_supported(request_info *request)
155 if (is_supported(request->get_subject()))
156 request->reply(ERR_NONE);
158 request->reply(ERR_NOT_SUPPORTED);
163 bool ctx::context_manager_impl::is_allowed(const char *client, const char *subject)
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);
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)
174 return find_request(r_list.begin(), r_list.end(), subject, option);
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)
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()) {
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)
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()) {
202 ctx::context_provider_iface *ctx::context_manager_impl::get_provider(ctx::request_info *request)
204 provider_map_t::iterator it = provider_map.find(request->get_subject());
206 if (it == provider_map.end()) {
207 _W("Unsupported subject");
208 request->reply(ERR_NOT_SUPPORTED);
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);
221 return it->second.create(it->second.data);
224 void ctx::context_manager_impl::subscribe(ctx::request_info *request)
226 _I(CYAN("'%s' subscribes '%s' (RID-%d)"), request->get_client(), request->get_subject(), request->get_id());
228 context_provider_iface *provider = get_provider(request);
229 IF_FAIL_VOID(provider);
231 ctx::json request_result;
232 int error = provider->subscribe(request->get_subject(), request->get_description().str(), &request_result);
234 _D("Analyzer returned %d", error);
236 if (!request->reply(error, request_result) || error != ERR_NONE) {
241 subscribe_request_list.push_back(request);
244 void ctx::context_manager_impl::unsubscribe(ctx::request_info *request)
246 _I(CYAN("'%s' unsubscribes '%s' (RID-%d)"), request->get_client(), request->get_subject(), request->get_id());
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");
256 // Keep the pointer to the request found
257 request_info *req_found = *target;
259 // Remove the request from the list
260 subscribe_request_list.erase(target);
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);
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());
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);
288 void ctx::context_manager_impl::read(ctx::request_info *request)
290 _I(CYAN("'%s' reads '%s' (RID-%d)"), request->get_client(), request->get_subject(), request->get_id());
292 context_provider_iface *provider = get_provider(request);
293 IF_FAIL_VOID(provider);
295 ctx::json request_result;
296 int error = provider->read(request->get_subject(), request->get_description().str(), &request_result);
298 _D("Analyzer returned %d", error);
300 if (!request->reply(error, request_result) || error != ERR_NONE) {
305 read_request_list.push_back(request);
308 void ctx::context_manager_impl::write(ctx::request_info *request)
310 _I(CYAN("'%s' writes '%s' (RID-%d)"), request->get_client(), request->get_subject(), request->get_id());
312 context_provider_iface *provider = get_provider(request);
313 IF_FAIL_VOID(provider);
315 ctx::json request_result;
316 int error = provider->write(request->get_subject(), request->get_description(), &request_result);
318 _D("Analyzer returned %d", error);
320 request->reply(error, request_result);
324 bool ctx::context_manager_impl::_publish(const char* subject, ctx::json option, int error, ctx::json data_updated)
326 IF_FAIL_RETURN_TAG(subject, false, _E, "Invalid parameter");
328 _I("Publishing '%s'", subject);
329 _J("Option", option);
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);
334 while (target != end) {
335 if (!(*target)->publish(error, data_updated)) {
338 target = find_request(++target, end, subject, option);
344 bool ctx::context_manager_impl::_reply_to_read(const char* subject, ctx::json option, int error, ctx::json data_read)
346 IF_FAIL_RETURN_TAG(subject, false, _E, "Invalid parameter");
348 _I("Sending data of '%s'", subject);
349 _J("Option", option);
350 _J("Data", data_read);
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;
358 while (target != end) {
359 (*target)->reply(error, dummy, data_read);
361 target = find_request(++target, end, subject, option);
364 read_request_list.erase(prev);
370 struct published_data_s {
372 ctx::context_manager_impl *mgr;
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)
385 gboolean ctx::context_manager_impl::thread_switcher(gpointer data)
387 published_data_s *tuple = static_cast<published_data_s*>(data);
389 switch (tuple->type) {
391 tuple->mgr->_publish(tuple->subject.c_str(), tuple->option, tuple->error, tuple->data);
394 tuple->mgr->_reply_to_read(tuple->subject.c_str(), tuple->option, tuple->error, tuple->data);
404 bool ctx::context_manager_impl::publish(const char* subject, ctx::json& option, int error, ctx::json& data_updated)
406 IF_FAIL_RETURN_TAG(subject, false, _E, "Invalid parameter");
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");
411 g_idle_add(thread_switcher, tuple);
416 bool ctx::context_manager_impl::reply_to_read(const char* subject, ctx::json& option, int error, ctx::json& data_read)
418 IF_FAIL_RETURN_TAG(subject, false, _E, "Invalid parameter");
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");
423 g_idle_add(thread_switcher, tuple);