Migrate from 2.4 code repo
[platform/core/context/context-service.git] / src / context_trigger / trigger.cpp
1 /*
2  * Copyright (c) 2014 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 <types_internal.h>
18 #include <context_trigger_types_internal.h>
19 #include "fact_reader.h"
20 #include "trigger.h"
21 #include "rule_manager.h"
22
23 ctx::context_trigger::context_trigger()
24         : _reader(NULL)
25 {
26 }
27
28 ctx::context_trigger::~context_trigger()
29 {
30 }
31
32 bool ctx::context_trigger::init(ctx::context_manager_impl* mgr)
33 {
34         // Do the necessary initialization process.
35         // This function is called from the main thread during the service launching process.
36         _reader = new(std::nothrow) fact_reader(mgr, this);
37         IF_FAIL_RETURN_TAG(_reader, false, _E, "Memory allocation failed");
38
39         _D("Starting Context Trigger Thread");
40         IF_FAIL_RETURN(start(), false);
41
42         push_thread_event(ETYPE_INITIALIZE, NULL);
43
44         return true;
45 }
46
47 void ctx::context_trigger::release()
48 {
49         _D("Stopping Context Trigger Thread");
50         stop();
51
52         // Release the occupied resources.
53         // This function is called from the main thread during the service termination process.
54         delete _reader;
55         _reader = NULL;
56 }
57
58 void ctx::context_trigger::on_thread_event_popped(int type, void* data)
59 {
60         switch (type) {
61                 case ETYPE_REQUEST:
62                         IF_FAIL_VOID(data);
63                         process_request(static_cast<request_info*>(data));
64                         break;
65                 case ETYPE_FACT:
66                         IF_FAIL_VOID(data);
67                         process_fact(static_cast<context_fact*>(data));
68                         break;
69                 case ETYPE_INITIALIZE:
70                         process_initialize();
71                         break;
72                 default:
73                         _W("Unknown event type");
74                         return;
75         }
76
77         delete_thread_event(type, data);
78 }
79
80 void ctx::context_trigger::delete_thread_event(int type, void* data)
81 {
82         IF_FAIL_VOID(data);
83
84         switch (type) {
85                 case ETYPE_REQUEST:
86                         {
87                                 std::string subject = static_cast<ctx::request_info*>(data)->get_subject();
88                                 if (subject != CONTEXT_TRIGGER_SUBJECT_ENABLE) {
89                                         delete (static_cast<request_info*>(data));
90                                 }
91                         }
92                         return;
93                 case ETYPE_FACT:
94                         delete (static_cast<context_fact*>(data));
95                         return;
96                 case ETYPE_INITIALIZE:
97                         return;
98                 default:
99                         _W("Unknown event type");
100                         return;
101         }
102 }
103
104 bool ctx::context_trigger::assign_request(ctx::request_info* request)
105 {
106         std::string subject = request->get_subject();
107         if (subject != CONTEXT_TRIGGER_SUBJECT_ADD && subject != CONTEXT_TRIGGER_SUBJECT_REMOVE &&
108                         subject != CONTEXT_TRIGGER_SUBJECT_ENABLE && subject != CONTEXT_TRIGGER_SUBJECT_DISABLE &&
109                         subject != CONTEXT_TRIGGER_SUBJECT_GET && subject != CONTEXT_TRIGGER_SUBJECT_GET_RULE_IDS) {
110                 return false;
111         }
112
113         push_thread_event(ETYPE_REQUEST, request);
114         return true;
115 }
116
117 void ctx::context_trigger::process_request(ctx::request_info* request)
118 {
119         // Process the request, and reply to the client if necessary.
120         const char* req_sbj = request->get_subject();
121         _D("Request is %s", req_sbj);
122         std::string subject(req_sbj);
123
124         if (subject == CONTEXT_TRIGGER_SUBJECT_ADD) {
125                 add_rule(request);
126         } else if (subject == CONTEXT_TRIGGER_SUBJECT_REMOVE) {
127                 remove_rule(request);
128         } else if (subject == CONTEXT_TRIGGER_SUBJECT_ENABLE) {
129                 enable_rule(request);
130         } else if (subject == CONTEXT_TRIGGER_SUBJECT_DISABLE) {
131                 disable_rule(request);
132         } else if (subject == CONTEXT_TRIGGER_SUBJECT_GET) {
133                 get_rule_by_id(request);
134         } else if (subject == CONTEXT_TRIGGER_SUBJECT_GET_RULE_IDS) {
135                 get_rule_ids(request);
136         } else {
137                 _E("Invalid request");
138         }
139 }
140
141 void ctx::context_trigger::push_fact(int req_id, int error, const char* subject, ctx::json& option, ctx::json& data, const char* zone)
142 {
143         context_fact *fact = new(std::nothrow) context_fact(req_id, error, subject, option, data, zone);
144         IF_FAIL_VOID_TAG(fact, _E, "Memory allocation failed");
145
146         push_thread_event(ETYPE_FACT, fact);
147 }
148
149 void ctx::context_trigger::process_fact(ctx::context_fact* fact)
150 {
151         // Process the context fact.
152         rule_mgr->on_event_received(fact->get_subject(), fact->get_option(), fact->get_data(), fact->get_zone_name());
153 }
154
155 void ctx::context_trigger::process_initialize(void)
156 {
157         rule_mgr = new(std::nothrow) rule_manager();
158         IF_FAIL_VOID_TAG(rule_mgr, _E, "Memory allocation failed");
159
160         bool ret = rule_mgr->init(this, _reader);
161         if (!ret) {
162                 _E("Context trigger initialization failed.");
163                 raise(SIGTERM);
164         }
165 }
166
167 void ctx::context_trigger::add_rule(ctx::request_info* request)
168 {
169         ctx::json rule_id;
170
171         const char* app_id = request->get_app_id();
172         if (app_id == NULL) {
173                 request->reply(ERR_OPERATION_FAILED);
174                 return;
175         }
176
177         const char* zone_name = request->get_zone_name();
178         if (zone_name == NULL) {
179                 request->reply(ERR_OPERATION_FAILED);
180                 return;
181         }
182
183         int error = rule_mgr->add_rule(app_id, request->get_description(), zone_name, &rule_id);
184         _I("'%s' adds a rule (Error: %#x)", request->get_client(), error);
185
186         request->reply(error, rule_id);
187 }
188
189 void ctx::context_trigger::remove_rule(ctx::request_info* request)
190 {
191         int id;
192         int error;
193
194         const char* app_id = request->get_app_id();
195         if (app_id == NULL) {
196                 request->reply(ERR_OPERATION_FAILED);
197                 return;
198         }
199
200         ctx::json rule_id = request->get_description();
201         rule_id.get(NULL, CT_RULE_ID, &id);
202
203         error = rule_mgr->check_rule(app_id, id);
204         if (error != ERR_NONE) {
205                 request->reply(error);
206                 return;
207         }
208
209         bool ret = rule_mgr->is_rule_enabled(id);
210         if (ret) {
211                 request->reply(ERR_RULE_ENABLED);
212                 return;
213         }
214
215         error = rule_mgr->remove_rule(id);
216         _I("'%s' removes rule%d (Error: %#x)", request->get_client(), id, error);
217         request->reply(error);
218 }
219
220 void ctx::context_trigger::enable_rule(ctx::request_info* request)
221 {
222         int id;
223         int error;
224
225         const char* app_id = request->get_app_id();
226         if (app_id == NULL) {
227                 request->reply(ERR_OPERATION_FAILED);
228                 return;
229         }
230
231         ctx::json rule_id = request->get_description();
232         rule_id.get(NULL, CT_RULE_ID, &id);
233
234         error = rule_mgr->check_rule(app_id, id);
235         if (error != ERR_NONE) {
236                 request->reply(error);
237                 return;
238         }
239
240         bool ret = rule_mgr->is_rule_enabled(id);
241         if (ret) {
242                 request->reply(ERR_RULE_ENABLED);
243                 return;
244         }
245
246         error = rule_mgr->enable_rule(id);
247         _I("'%s' enables rule%d (Error: %#x)", request->get_client(), id, error);
248         request->reply(error);
249 }
250
251 void ctx::context_trigger::disable_rule(ctx::request_info* request)
252 {
253         int id;
254         int error;
255
256         const char* app_id = request->get_app_id();
257         if (app_id == NULL) {
258                 request->reply(ERR_OPERATION_FAILED);
259                 return;
260         }
261
262         ctx::json rule_id = request->get_description();
263         rule_id.get(NULL, CT_RULE_ID, &id);
264
265         error = rule_mgr->check_rule(app_id, id);
266         if (error != ERR_NONE) {
267                 request->reply(error);
268                 return;
269         }
270
271         bool ret = rule_mgr->is_rule_enabled(id);
272         if (!ret) {
273                 request->reply(ERR_RULE_NOT_ENABLED);
274                 return;
275         }
276
277         error = rule_mgr->disable_rule(id);
278         _I("'%s' disables rule%d (Error: %#x)", request->get_client(), id, error);
279         request->reply(error);
280 }
281
282 void ctx::context_trigger::get_rule_by_id(ctx::request_info* request)
283 {
284         int error;
285
286         ctx::json option = request->get_description();
287         int id;
288         option.get(NULL, CT_RULE_ID, &id);
289
290         const char* app_id = request->get_app_id();
291         if (app_id == NULL) {
292                 request->reply(ERR_OPERATION_FAILED);
293                 return;
294         }
295
296         ctx::json read_data;
297         error = rule_mgr->get_rule_by_id(app_id, id, &read_data);
298
299         ctx::json dummy;
300         request->reply(error, dummy, read_data);
301 }
302
303 void ctx::context_trigger::get_rule_ids(ctx::request_info* request)
304 {
305         int error;
306
307         const char* app_id = request->get_app_id();
308         if (app_id == NULL) {
309                 request->reply(ERR_OPERATION_FAILED);
310                 return;
311         }
312
313         ctx::json read_data;
314         error = rule_mgr->get_rule_ids(app_id, &read_data);
315
316         ctx::json dummy;
317         request->reply(error, dummy, read_data);
318 }