Remove profile build dependencies
[platform/core/context/context-service.git] / src / ProviderHandler.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 <Types.h>
19 #include <ProviderTypes.h>
20 #include "access_control/Privilege.h"
21 #include "Request.h"
22 #include "ProviderHandler.h"
23
24 #define DELETE_DELAY 20
25
26 using namespace ctx;
27
28 std::map<std::string, ProviderHandler*> ProviderHandler::__instanceMap;
29
30 ProviderHandler::ProviderHandler(const std::string &subject) :
31         __subject(subject),
32         __deleteScheduled(false)
33 {
34         _D("Subject: %s", __subject.c_str());
35 }
36
37 ProviderHandler::~ProviderHandler()
38 {
39         _D("Subject: %s", __subject.c_str());
40
41         for (RequestInfo*& info : __subscribeRequests) {
42                 delete info;
43         }
44         __subscribeRequests.clear();
45
46         for (RequestInfo*& info : __readRequests) {
47                 delete info;
48         }
49         __readRequests.clear();
50
51         delete __provider;
52 }
53
54 /* TODO: Return proper error code */
55 ProviderHandler* ProviderHandler::getInstance(std::string subject, bool force)
56 {
57         InstanceMap::iterator it = __instanceMap.find(subject);
58
59         if (it != __instanceMap.end())
60                 return it->second;
61
62         if (!force)
63                 return NULL;
64
65         ProviderHandler *handle = new(std::nothrow) ProviderHandler(subject);
66         IF_FAIL_RETURN_TAG(handle, NULL, _E, "Memory allocation failed");
67
68         if (!handle->__loadProvider()) {
69                 delete handle;
70                 return NULL;
71         }
72
73         __instanceMap[subject] = handle;
74
75         return handle;
76 }
77
78 void ProviderHandler::purge()
79 {
80         for (InstanceMap::iterator it = __instanceMap.begin(); it != __instanceMap.end(); ++it) {
81                 delete it->second;
82         }
83
84         __instanceMap.clear();
85 }
86
87 int ProviderHandler::unregisterCustomProvider(std::string subject)
88 {
89         InstanceMap::iterator it = __instanceMap.find(subject);
90         IF_FAIL_RETURN_TAG(it != __instanceMap.end(), ERR_NOT_SUPPORTED, _E, "'%s' not found", subject.c_str());
91
92         __instanceMap.erase(subject);
93         delete it->second;
94
95         _D("'%s' unregistered", subject.c_str());
96         return ERR_NONE;
97 }
98
99 bool ProviderHandler::isSupported()
100 {
101         /* If idle, self destruct */
102         __scheduleToDelete();
103
104         return __provider->isSupported();
105 }
106
107 bool ProviderHandler::isAllowed(const Credentials *creds)
108 {
109         /* If idle, self destruct */
110         __scheduleToDelete();
111
112         IF_FAIL_RETURN(creds, true);    /* In case of internal requests */
113
114         std::vector<const char*> priv;
115         __provider->getPrivilege(priv);
116
117         for (unsigned int i = 0; i < priv.size(); ++i) {
118                 if (!privilege_manager::isAllowed(creds, priv[i]))
119                         return false;
120         }
121
122         return true;
123 }
124
125 void ProviderHandler::subscribe(RequestInfo *request)
126 {
127         _I(CYAN("'%s' subscribes '%s' (RID-%d)"), request->getClient(), __subject.c_str(), request->getId());
128
129         Json requestResult;
130         int error = __provider->subscribe(request->getDescription().str(), &requestResult);
131
132         if (!request->reply(error, requestResult) || error != ERR_NONE) {
133                 delete request;
134                 /* If idle, self destruct */
135                 __scheduleToDelete();
136                 return;
137         }
138
139         __subscribeRequests.push_back(request);
140 }
141
142 void ProviderHandler::unsubscribe(RequestInfo *request)
143 {
144         _I(CYAN("'%s' unsubscribes '%s' (RID-%d)"), request->getClient(), __subject.c_str(), request->getId());
145
146         /* Search the subscribe request to be removed */
147         auto target = __findRequest(__subscribeRequests, request->getClient(), request->getId());
148         if (target == __subscribeRequests.end()) {
149                 _W("Unknown request");
150                 delete request;
151                 return;
152         }
153
154         /* Keep the pointer to the request found */
155         RequestInfo *reqFound = *target;
156
157         /* Remove the request from the list */
158         __subscribeRequests.erase(target);
159
160         /* Check if there exist the same requests */
161         if (__findRequest(__subscribeRequests, reqFound->getDescription()) != __subscribeRequests.end()) {
162                 /* Do not stop detecting the subject */
163                 _D("A same request from '%s' exists", reqFound->getClient());
164                 request->reply(ERR_NONE);
165                 delete request;
166                 delete reqFound;
167                 return;
168         }
169
170         /* Stop detecting the subject */
171         int error = __provider->unsubscribe(reqFound->getDescription());
172         request->reply(error);
173         delete request;
174         delete reqFound;
175
176         /* If idle, self destruct */
177         __scheduleToDelete();
178 }
179
180 void ProviderHandler::read(RequestInfo *request)
181 {
182         _I(CYAN("'%s' reads '%s' (RID-%d)"), request->getClient(), __subject.c_str(), request->getId());
183
184         Json requestResult;
185         int error = __provider->read(request->getDescription().str(), &requestResult);
186
187         if (!request->reply(error, requestResult) || error != ERR_NONE) {
188                 delete request;
189                 /* If idle, self destruct */
190                 __scheduleToDelete();
191                 return;
192         }
193
194         __readRequests.push_back(request);
195 }
196
197 void ProviderHandler::write(RequestInfo *request)
198 {
199         _I(CYAN("'%s' writes '%s' (RID-%d)"), request->getClient(), __subject.c_str(), request->getId());
200
201         Json requestResult;
202         request->getDescription().set(NULL, KEY_CLIENT_PKG_ID, request->getPackageId()? request->getPackageId() : "SYSTEM");
203         int error = __provider->write(request->getDescription(), &requestResult);
204
205         request->reply(error, requestResult);
206         delete request;
207
208         /* If idle, self destruct */
209         __scheduleToDelete();
210 }
211
212 bool ProviderHandler::publish(Json &option, int error, Json &dataUpdated)
213 {
214         auto end = __subscribeRequests.end();
215         auto target = __findRequest(__subscribeRequests.begin(), end, option);
216
217         while (target != end) {
218                 if (!(*target)->publish(error, dataUpdated)) {
219                         return false;
220                 }
221                 target = __findRequest(++target, end, option);
222         }
223
224         return true;
225 }
226
227 bool ProviderHandler::replyToRead(Json &option, int error, Json &dataRead)
228 {
229         auto end = __readRequests.end();
230         auto target = __findRequest(__readRequests.begin(), end, option);
231         auto prev = target;
232
233         Json dummy;
234
235         while (target != end) {
236                 (*target)->reply(error, dummy, dataRead);
237                 prev = target;
238                 target = __findRequest(++target, end, option);
239
240                 delete *prev;
241                 __readRequests.erase(prev);
242         }
243
244         /* If idle, self destruct */
245         __scheduleToDelete();
246
247         return true;
248 }
249
250 bool ProviderHandler::__loadProvider()
251 {
252         __provider = __loader.load(__subject.c_str());
253         return (__provider != NULL);
254 }
255
256 bool ProviderHandler::__idle()
257 {
258         return __subscribeRequests.empty() && __readRequests.empty();
259 }
260
261 void ProviderHandler::__scheduleToDelete()
262 {
263         if (__provider->unloadable() && !__deleteScheduled && __idle()) {
264                 __deleteScheduled = true;
265                 g_timeout_add_seconds(DELETE_DELAY, __deletor, this);
266                 _D("Delete scheduled for '%s' (%#x)", __subject.c_str(), this);
267         }
268 }
269
270 gboolean ProviderHandler::__deletor(gpointer data)
271 {
272         ProviderHandler *handle = static_cast<ProviderHandler*>(data);
273
274         if (handle->__idle()) {
275                 __instanceMap.erase(handle->__subject);
276                 delete handle;
277                 return FALSE;
278         }
279
280         handle->__deleteScheduled = false;
281         return FALSE;
282 }
283
284 ProviderHandler::RequestList::iterator
285 ProviderHandler::__findRequest(RequestList &reqList, Json &option)
286 {
287         return __findRequest(reqList.begin(), reqList.end(), option);
288 }
289
290 ProviderHandler::RequestList::iterator
291 ProviderHandler::__findRequest(RequestList &reqList, std::string client, int reqId)
292 {
293         for (auto it = reqList.begin(); it != reqList.end(); ++it) {
294                 if (client == (*it)->getClient() && reqId == (*it)->getId()) {
295                         return it;
296                 }
297         }
298         return reqList.end();
299 }
300
301 ProviderHandler::RequestList::iterator
302 ProviderHandler::__findRequest(RequestList::iterator begin, RequestList::iterator end, Json &option)
303 {
304         for (auto it = begin; it != end; ++it) {
305                 if (option == (*it)->getDescription()) {
306                         return it;
307                 }
308         }
309         return end;
310 }