2 * Copyright (c) 2014 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.
20 #include <types_internal.h>
22 #include <provider_iface.h>
24 #include "context_mgr_impl.h"
25 #include "zone_util_impl.h"
26 #include "access_control/privilege.h"
28 /* Analyzer Headers */
29 #include <internal/device_context_provider.h>
30 #include <internal/app_statistics_provider.h>
31 #include <internal/social_statistics_provider.h>
32 #include <internal/media_statistics_provider.h>
33 #include <internal/place_context_provider.h>
35 ctx::context_manager_impl::context_manager_impl()
39 ctx::context_manager_impl::~context_manager_impl()
44 bool ctx::context_manager_impl::init()
46 IF_FAIL_RETURN_TAG(provider_list.size()==0, false, _W, "Re-initialization");
49 /* List of all providers */
50 load_provider(new ctx::device_context_provider());
51 load_provider(new ctx::app_statistics_provider());
52 load_provider(new ctx::social_statistics_provider());
53 load_provider(new ctx::media_statistics_provider());
54 load_provider(new ctx::place_context_provider());
56 } catch (std::bad_alloc& ba) {
57 _E("Analyzer loading failed (bad alloc)");
60 _E("Analyzer loading failed (%#x)", e);
67 void ctx::context_manager_impl::release()
69 subject_provider_map.clear();
71 for (provider_list_t::iterator it = provider_list.begin(); it != provider_list.end(); ++it) {
74 provider_list.clear();
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 void ctx::context_manager_impl::load_provider(context_provider_iface* provider)
91 throw static_cast<int>(ERR_INVALID_PARAMETER);
94 provider_list.push_back(provider);
96 if (!provider->init()) {
97 _E("Analyzer initialization failed");
98 throw ERR_OPERATION_FAILED;
102 bool ctx::context_manager_impl::register_provider(const char* subject, ctx::context_provider_iface* cp)
104 IF_FAIL_RETURN_TAG(subject && cp, false, _E, "Invalid parameter");
106 if (subject_provider_map.find(subject) != subject_provider_map.end()) {
107 _E("The provider for the subject '%s' is already registered.", subject);
111 _I("Registering provider for '%s'", subject);
112 subject_provider_map[subject] = cp;
117 void ctx::context_manager_impl::assign_request(ctx::request_info* request)
119 int req_type = request->get_type();
120 context_provider_iface *provider = NULL;
122 if (req_type != REQ_UNSUBSCRIBE) {
123 subject_provider_map_t::iterator it = subject_provider_map.find(request->get_subject());
124 if (it == subject_provider_map.end()) {
125 _E("Unknown subject '%s'", request->get_subject());
126 request->reply(ERR_NOT_SUPPORTED);
130 provider = it->second;
134 // If the ClientAppId attribute exists but is empty.
135 if (request->get_description().get(NULL, COMMON_ATTR_CLIENT_APP_ID, &app_id)) {
136 if (app_id.empty() && request->get_app_id()) {
137 request->get_description().set(NULL, COMMON_ATTR_CLIENT_APP_ID, request->get_app_id());
143 if (!check_permission(request)) {
144 request->reply(ERR_PERMISSION_DENIED);
148 subscribe(request, provider);
150 case REQ_UNSUBSCRIBE:
151 unsubscribe(request);
155 if (!check_permission(request)) {
156 request->reply(ERR_PERMISSION_DENIED);
160 read(request, provider);
163 if (!check_permission(request)) {
164 request->reply(ERR_PERMISSION_DENIED);
168 write(request, provider);
171 if (provider->is_supported(request->get_subject(), request->get_zone_name())) {
172 request->reply(ERR_NONE);
174 request->reply(ERR_NOT_SUPPORTED);
179 _E("Invalid type of request");
184 bool ctx::context_manager_impl::is_supported(const char* subject, const char* zone)
186 subject_provider_map_t::iterator it = subject_provider_map.find(subject);
187 IF_FAIL_RETURN(it != subject_provider_map.end(), false);
189 return it->second->is_supported(subject, zone);
192 ctx::context_manager_impl::request_list_t::iterator
193 ctx::context_manager_impl::find_request(request_list_t& r_list, std::string subject, json& option, const char* zone)
195 return find_request(r_list.begin(), r_list.end(), subject, option, zone);
198 ctx::context_manager_impl::request_list_t::iterator
199 ctx::context_manager_impl::find_request(request_list_t& r_list, std::string client, int req_id)
201 request_list_t::iterator it;
202 for (it = r_list.begin(); it != r_list.end(); ++it) {
203 if (client == (*it)->get_client() && req_id == (*it)->get_id()) {
210 ctx::context_manager_impl::request_list_t::iterator
211 ctx::context_manager_impl::find_request(request_list_t::iterator begin, request_list_t::iterator end, std::string subject, json& option, const char* zone)
213 //TODO: Do we need to consider the case that the inparam option is a subset of the request description?
214 request_list_t::iterator it;
215 for (it = begin; it != end; ++it) {
216 if (subject == (*it)->get_subject() && option == (*it)->get_description() && STR_EQ(zone, (*it)->get_zone_name())) {
223 bool ctx::context_manager_impl::check_permission(ctx::request_info* request)
225 const char* app_id = request->get_app_id();
226 _D("Peer AppID: %s", app_id);
227 IF_FAIL_RETURN_TAG(app_id, false, _E, "AppID NULL");
228 IF_FAIL_RETURN_TAG(!STR_EQ(app_id, TRIGGER_CLIENT_NAME), true, _D, "Skipping permission check for Trigger");
230 scope_zone_joiner sz(request->get_zone_name());
232 bool allowed = ctx::privilege_manager::is_allowed(app_id, request->get_subject());
233 IF_FAIL_RETURN_TAG(allowed, false, _W, "Permission denied");
238 void ctx::context_manager_impl::subscribe(ctx::request_info* request, ctx::context_provider_iface* provider)
240 _I(CYAN("[%s] '%s' subscribes '%s' (RID-%d)"), request->get_zone_name(), request->get_client(), request->get_subject(), request->get_id());
242 ctx::json request_result;
243 int error = provider->subscribe(request->get_subject(), request->get_description().str(), &request_result, request->get_zone_name());
245 _D("Analyzer returned %d", error);
247 if (!request->reply(error, request_result) || error != ERR_NONE) {
252 subscribe_request_list.push_back(request);
255 void ctx::context_manager_impl::unsubscribe(ctx::request_info* request)
257 _I(CYAN("[%s] '%s' unsubscribes RID-%d"), request->get_zone_name(), request->get_client(), request->get_id());
259 // Search the subscribe request to be removed
260 request_list_t::iterator target = find_request(subscribe_request_list, request->get_client(), request->get_id());
261 if (target == subscribe_request_list.end()) {
262 _W("Unknown request");
267 // Keep the pointer to the request found
268 request_info *req_found = *target;
270 // Remove the request from the list
271 subscribe_request_list.erase(target);
273 // Check if there exist the same requests
274 if (find_request(subscribe_request_list, req_found->get_subject(), req_found->get_description(), req_found->get_zone_name()) != subscribe_request_list.end()) {
275 // Do not stop detecting the subject
276 _D("A same request from '%s' exists", req_found->get_client());
277 request->reply(ERR_NONE);
283 // Find the proper provider
284 subject_provider_map_t::iterator ca = subject_provider_map.find(req_found->get_subject());
285 if (ca == subject_provider_map.end()) {
286 _E("Invalid subject '%s'", req_found->get_subject());
292 // Stop detecting the subject
293 int error = ca->second->unsubscribe(req_found->get_subject(), req_found->get_description(), req_found->get_zone_name());
294 request->reply(error);
299 void ctx::context_manager_impl::read(ctx::request_info* request, ctx::context_provider_iface* provider)
301 _I(CYAN("[%s] '%s' reads '%s' (RID-%d)"), request->get_zone_name(), request->get_client(), request->get_subject(), request->get_id());
303 ctx::json request_result;
304 int error = provider->read(request->get_subject(), request->get_description().str(), &request_result, request->get_zone_name());
306 _D("Analyzer returned %d", error);
308 if (!request->reply(error, request_result) || error != ERR_NONE) {
313 read_request_list.push_back(request);
316 void ctx::context_manager_impl::write(ctx::request_info* request, ctx::context_provider_iface* provider)
318 _I(CYAN("[%s] '%s' writes '%s' (RID-%d)"), request->get_zone_name(), request->get_client(), request->get_subject(), request->get_id());
320 ctx::json request_result;
321 int error = provider->write(request->get_subject(), request->get_description(), &request_result, request->get_zone_name());
323 _D("Analyzer returned %d", error);
325 request->reply(error, request_result);
329 bool ctx::context_manager_impl::_publish(const char* subject, ctx::json option, int error, ctx::json data_updated, const char* zone)
331 IF_FAIL_RETURN_TAG(subject, false, _E, "Invalid parameter");
333 _I("Publishing '%s'", subject);
334 _J("Option", option);
336 request_list_t::iterator end = subscribe_request_list.end();
337 request_list_t::iterator target = find_request(subscribe_request_list.begin(), end, subject, option, zone);
339 while (target != end) {
340 if (!(*target)->publish(error, data_updated)) {
343 target = find_request(++target, end, subject, option, zone);
349 bool ctx::context_manager_impl::_reply_to_read(const char* subject, ctx::json option, int error, ctx::json data_read, const char* zone)
351 IF_FAIL_RETURN_TAG(subject, false, _E, "Invalid parameter");
353 _I("Sending data of '%s'", subject);
354 _J("Option", option);
355 _J("Data", data_read);
356 _SI("Zone: '%s'", zone);
358 request_list_t::iterator end = read_request_list.end();
359 request_list_t::iterator target = find_request(read_request_list.begin(), end, subject, option, zone);
360 request_list_t::iterator prev;
364 while (target != end) {
365 (*target)->reply(error, dummy, data_read);
367 target = find_request(++target, end, subject, option, zone);
370 read_request_list.erase(prev);
376 struct published_data_s {
378 ctx::context_manager_impl *mgr;
384 published_data_s(int t, ctx::context_manager_impl *m, const char* s, ctx::json& o, int e, ctx::json& d, const char* z)
385 : type(t), mgr(m), subject(s), error(e)
393 gboolean ctx::context_manager_impl::thread_switcher(gpointer data)
395 published_data_s *tuple = static_cast<published_data_s*>(data);
397 switch (tuple->type) {
399 tuple->mgr->_publish(tuple->subject.c_str(), tuple->option, tuple->error, tuple->data, tuple->zone.c_str());
402 tuple->mgr->_reply_to_read(tuple->subject.c_str(), tuple->option, tuple->error, tuple->data, tuple->zone.c_str());
412 bool ctx::context_manager_impl::publish(const char* subject, ctx::json& option, int error, ctx::json& data_updated, const char* zone)
414 IF_FAIL_RETURN_TAG(subject && zone, false, _E, "Invalid parameter");
416 published_data_s *tuple = new(std::nothrow) published_data_s(REQ_SUBSCRIBE, this, subject, option, error, data_updated, zone);
417 IF_FAIL_RETURN_TAG(tuple, false, _E, "Memory allocation failed");
419 g_idle_add(thread_switcher, tuple);
424 bool ctx::context_manager_impl::reply_to_read(const char* subject, ctx::json& option, int error, ctx::json& data_read, const char* zone)
426 IF_FAIL_RETURN_TAG(subject && zone, false, _E, "Invalid parameter");
428 published_data_s *tuple = new(std::nothrow) published_data_s(REQ_READ, this, subject, option, error, data_read, zone);
429 IF_FAIL_RETURN_TAG(tuple, false, _E, "Memory allocation failed");
431 g_idle_add(thread_switcher, tuple);