4 * Copyright (c) 2014 Samsung Electronics Co., Ltd.
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
23 #include <types_internal.h>
27 #include <app_control.h>
29 #include <app_control_internal.h>
30 #include <notification.h>
31 #include <notification_internal.h>
32 #include <context_trigger_types_internal.h>
33 #include <context_trigger.h>
35 #include <zone_util.h>
36 #include "../access_control/privilege.h"
37 #include "rule_manager.h"
38 #include "script_generator.h"
41 #define RULE_TABLE "context_trigger_rule"
42 #define EVENT_TABLE "context_trigger_event"
43 #define CONDITION_TABLE "context_trigger_condition"
44 #define TEMPLATE_TABLE "context_trigger_template"
46 #define RULE_TABLE_COLUMNS "enabled INTEGER DEFAULT 0 NOT NULL, creator TEXT DEFAULT '' NOT NULL, description TEXT DEFAULT '', details TEXT DEFAULT '' NOT NULL, zone TEXT DEFAULT '' NOT NULL"
47 #define EVENT_TABLE_COLUMNS "rule_id INTEGER references context_trigger_rule(row_id) ON DELETE CASCADE NOT NULL, name TEXT DEFAULT '' NOT NULL, instance_name TEXT DEFAULT '', zone TEXT DEFAULT '' NOT NULL"
48 #define CONDITION_TABLE_COLUMNS "rule_id INTEGER references context_trigger_rule(row_id) ON DELETE CASCADE NOT NULL, name TEXT DEFAULT '' NOT NULL, option TEXT DEFAULT '', instance_name TEXT DEFAULT '', zone TEXT DEFAULT '' NOT NULL"
49 #define CREATE_TEMPLATE_TABLE "CREATE TABLE IF NOT EXISTS context_trigger_template (name TEXT DEFAULT '' NOT NULL PRIMARY KEY, j_template TEXT DEFAULT '' NOT NULL)"
50 #define QUERY_TEMPLATE_TABLE "SELECT j_template FROM context_trigger_template"
51 #define FOREIGN_KEYS_ON "PRAGMA foreign_keys = ON"
52 #define DELETE_RULE_STATEMENT "DELETE FROM 'context_trigger_rule' where row_id = "
53 #define UPDATE_RULE_ENABLED_STATEMENT "UPDATE context_trigger_rule SET enabled = 1 WHERE row_id = "
54 #define UPDATE_RULE_DISABLED_STATEMENT "UPDATE context_trigger_rule SET enabled = 0 WHERE row_id = "
55 #define QUERY_NAME_INSTANCE_NAME_AND_TEMPLATE_BY_RULE_ID_STATEMENT "SELECT context_trigger_condition.name, instance_name, j_template as templates FROM context_trigger_condition JOIN context_trigger_template ON (context_trigger_condition.name = context_trigger_template.name) WHERE rule_id = "
56 #define QUERY_CONDITION_TEMPLATES_OF_INVOKED_EVENT_STATEMENT "SELECT DISTINCT context_trigger_condition.name, instance_name, option, j_template FROM context_trigger_condition JOIN context_trigger_template ON (context_trigger_condition.name = context_trigger_template.name) WHERE rule_id IN (SELECT row_id FROM context_trigger_rule WHERE enabled = 1 AND row_id IN (SELECT rule_id FROM context_trigger_event WHERE context_trigger_event.instance_name = '"
57 #define QUERY_RULE_AND_ZONE_BY_RULE_ID "SELECT details, zone FROM context_trigger_rule WHERE row_id = "
58 #define QUERY_EVENT_TEMPLATE_BY_RULE_ID "SELECT j_template FROM context_trigger_template WHERE name IN (SELECT name FROM context_trigger_event WHERE rule_id = "
59 #define QUERY_CONDITION_BY_RULE_ID "SELECT name, option FROM context_trigger_condition WHERE rule_id = "
61 #define INSTANCE_NAME_DELIMITER "/"
62 #define EVENT_KEY_PREFIX "?"
64 static ctx::context_trigger* trigger = NULL;
66 static int string_to_int(std::string str)
69 std::istringstream convert(str);
77 static std::string int_to_string(int i)
79 std::ostringstream convert;
81 std::string str = convert.str();
85 ctx::rule_manager::rule_manager()
89 ctx::rule_manager::~rule_manager()
93 bool ctx::rule_manager::init(ctx::context_trigger* tr, ctx::fact_reader* fr)
100 ret = clips_h.init(this);
101 IF_FAIL_RETURN_TAG(ret, false, _E, "CLIPS handler initialization failed");
103 ret = c_monitor.init(fr, tr);
105 // Create tables into db (rule, event, condition, action, template)
106 ret = db_manager::create_table(1, RULE_TABLE, RULE_TABLE_COLUMNS, NULL, NULL);
107 IF_FAIL_RETURN_TAG(ret, false, _E, "Create rule table failed");
109 ret = db_manager::create_table(2, EVENT_TABLE, EVENT_TABLE_COLUMNS, NULL, NULL);
110 IF_FAIL_RETURN_TAG(ret, false, _E, "Create event table failed");
112 ret = db_manager::create_table(3, CONDITION_TABLE, CONDITION_TABLE_COLUMNS, NULL, NULL);
113 IF_FAIL_RETURN_TAG(ret, false, _E, "Create condition table failed");
115 ret = db_manager::execute(4, CREATE_TEMPLATE_TABLE, NULL);
116 IF_FAIL_RETURN_TAG(ret, false, _E, "Create template table failed");
118 // Load all templates from DB
119 std::vector<json> record;
120 ret = db_manager::execute_sync(QUERY_TEMPLATE_TABLE, &record);
121 IF_FAIL_RETURN_TAG(ret, false, _E, "Query template table failed");
123 // Make scripts for deftemplate, defclass, make-instance and load them to clips
124 std::vector<json>::iterator vec_end = record.end();
125 for (std::vector<json>::iterator vec_pos = record.begin(); vec_pos != vec_end; ++vec_pos) {
126 ctx::json elem = *vec_pos;
127 std::string tmpl_str;
128 elem.get(NULL, "j_template", &tmpl_str);
129 ctx::json tmpl = tmpl_str;
131 std::string deftemplate_str = script_generator::generate_deftemplate(&tmpl);
132 error = clips_h.define_template(deftemplate_str);
133 IF_FAIL_RETURN_TAG(error == ERR_NONE, false, _E, "Deftemplate failed");
135 std::string defclass_str = script_generator::generate_defclass(&tmpl);
136 error = clips_h.define_class(defclass_str);
137 IF_FAIL_RETURN_TAG(error == ERR_NONE, false, _E, "Defclass failed");
139 std::string makeinstance_str = script_generator::generate_makeinstance(&tmpl);
140 error = clips_h.make_instance(makeinstance_str);
141 IF_FAIL_RETURN_TAG(error == ERR_NONE, false, _E, "Makeinstance failed");
145 ret = db_manager::execute_sync(FOREIGN_KEYS_ON, &record);
146 IF_FAIL_RETURN_TAG(ret, false, _E, "Foreign keys on failed");
148 ret = reenable_rule();
153 bool ctx::rule_manager::reenable_rule(void)
156 std::string q = "SELECT row_id FROM context_trigger_rule where enabled = 1";
158 std::vector<json> record;
159 bool ret = db_manager::execute_sync(q.c_str(), &record);
160 IF_FAIL_RETURN_TAG(ret, false, _E, "Query row_ids of enabled rules failed");
162 std::vector<json>::iterator vec_end = record.end();
163 for (std::vector<json>::iterator vec_pos = record.begin(); vec_pos != vec_end; ++vec_pos) {
164 ctx::json elem = *vec_pos;
166 elem.get(NULL, "row_id", &row_id);
168 error = enable_rule(row_id);
169 if (error != ERR_NONE) {
170 _E("Re-enable rule%d failed(%d)", row_id, error);
172 _E("Re-enable rule%d succeeded", row_id);
179 bool ctx::rule_manager::rule_data_arr_elem_equals(ctx::json& lelem, ctx::json& relem)
181 std::string lkey, rkey;
182 lelem.get(NULL, CT_RULE_DATA_KEY, &lkey);
183 relem.get(NULL, CT_RULE_DATA_KEY, &rkey);
184 if (lkey.compare(rkey))
187 int lvc, rvc, lvoc, rvoc;
188 lvc = lelem.array_get_size(NULL, CT_RULE_DATA_VALUE_ARR);
189 rvc = relem.array_get_size(NULL, CT_RULE_DATA_VALUE_ARR);
190 lvoc = lelem.array_get_size(NULL, CT_RULE_DATA_VALUE_OPERATOR_ARR);
191 rvoc = relem.array_get_size(NULL, CT_RULE_DATA_VALUE_OPERATOR_ARR);
192 if (!((lvc == rvc) && (lvc == lvoc) && (lvc && rvoc)))
196 std::string lop, rop;
197 lelem.get(NULL, CT_RULE_DATA_KEY_OPERATOR, &lop);
198 relem.get(NULL, CT_RULE_DATA_KEY_OPERATOR, &rop);
199 if (lop.compare(rop))
203 for (int i = 0; i < lvc; i++) {
206 lelem.get_array_elem(NULL, CT_RULE_DATA_VALUE_ARR, i, &lv);
207 lelem.get_array_elem(NULL, CT_RULE_DATA_VALUE_OPERATOR_ARR, i, &lvo);
209 for (int j = 0; j < lvc; j++) {
211 relem.get_array_elem(NULL, CT_RULE_DATA_VALUE_ARR, j, &rv);
212 relem.get_array_elem(NULL, CT_RULE_DATA_VALUE_OPERATOR_ARR, j, &rvo);
214 if (!lv.compare(rv) && !lvo.compare(rvo)) {
226 bool ctx::rule_manager::rule_item_equals(ctx::json& litem, ctx::json& ritem)
229 std::string lei, rei;
230 litem.get(NULL, CT_RULE_EVENT_ITEM, &lei);
231 ritem.get(NULL, CT_RULE_EVENT_ITEM, &rei);
232 if (lei.compare(rei))
236 ctx::json loption, roption;
237 std::string linst, rinst;
238 litem.get(NULL, CT_RULE_EVENT_OPTION, &loption);
239 ritem.get(NULL, CT_RULE_EVENT_OPTION, &roption);
240 linst = get_instance_name(lei, loption);
241 rinst = get_instance_name(rei, roption);
242 if (linst.compare(rinst))
246 ledac = litem.array_get_size(NULL, CT_RULE_DATA_ARR);
247 redac = ritem.array_get_size(NULL, CT_RULE_DATA_ARR);
251 // Compare item operator;
253 std::string leop, reop;
254 litem.get(NULL, CT_RULE_EVENT_OPERATOR, &leop);
255 ritem.get(NULL, CT_RULE_EVENT_OPERATOR, &reop);
256 if (leop.compare(reop))
260 for (int i = 0; i < ledac; i++) {
263 litem.get_array_elem(NULL, CT_RULE_DATA_ARR, i, &lelem);
265 for (int j = 0; j < ledac; j++) {
267 ritem.get_array_elem(NULL, CT_RULE_DATA_ARR, j, &relem);
269 if (rule_data_arr_elem_equals(lelem, relem)) {
281 bool ctx::rule_manager::rule_equals(ctx::json& lrule, ctx::json& rrule)
285 lrule.get(NULL, CT_RULE_EVENT, &le);
286 rrule.get(NULL, CT_RULE_EVENT, &re);
287 if (!rule_item_equals(le, re))
290 // Compare conditions
292 lcc = lrule.array_get_size(NULL, CT_RULE_CONDITION);
293 rcc = rrule.array_get_size(NULL, CT_RULE_CONDITION);
298 std::string lop, rop;
299 lrule.get(NULL, CT_RULE_OPERATOR, &lop);
300 rrule.get(NULL, CT_RULE_OPERATOR, &rop);
301 if (lop.compare(rop))
305 for (int i = 0; i < lcc; i++) {
308 lrule.get_array_elem(NULL, CT_RULE_CONDITION, i, &lc);
310 for (int j = 0; j < lcc; j++) {
312 rrule.get_array_elem(NULL, CT_RULE_CONDITION, j, &rc);
314 if (rule_item_equals(lc, rc)) {
324 std::string laction, raction;
325 lrule.get(NULL, CT_RULE_ACTION, &laction);
326 rrule.get(NULL, CT_RULE_ACTION, &raction);
327 if (laction.compare(raction))
333 int64_t ctx::rule_manager::get_duplicated_rule(std::string creator, std::string zone, ctx::json& rule)
335 std::string q = "SELECT row_id, details FROM context_trigger_rule WHERE creator = '";
337 q += "' AND zone ='";
341 std::vector<json> record;
342 bool ret = db_manager::execute_sync(q.c_str(), &record);
343 IF_FAIL_RETURN_TAG(ret, false, _E, "Query row_id, details by creator failed");
346 rule.get(NULL, CT_RULE_DETAILS, &r_details);
347 std::vector<json>::iterator vec_end = record.end();
349 for (std::vector<json>::iterator vec_pos = record.begin(); vec_pos != vec_end; ++vec_pos) {
350 ctx::json elem = *vec_pos;
354 elem.get(NULL, "details", &details);
357 if (rule_equals(r_details, d_details)) {
359 elem.get(NULL, "row_id", &row_id);
367 int ctx::rule_manager::verify_rule(ctx::json& rule, const char* app_id, const char* zone)
370 rule.get(NULL, CT_RULE_DETAILS, &details);
373 rule.get(CT_RULE_DETAILS "." CT_RULE_EVENT, CT_RULE_EVENT_ITEM, &e_name);
375 IF_FAIL_RETURN_TAG(c_monitor.is_supported(e_name, zone), ERR_NOT_SUPPORTED, _I, "Event(%s) is not supported", e_name.c_str());
378 if (!ctx::privilege_manager::is_allowed(app_id, e_name.c_str())) {
379 _W("Permission denied for '%s'", e_name.c_str());
380 return ERR_PERMISSION_DENIED;
385 for (int i = 0; rule.get_array_elem(CT_RULE_DETAILS, CT_RULE_CONDITION, i, &it); i++){
387 it.get(NULL, CT_RULE_CONDITION_ITEM, &c_name);
389 IF_FAIL_RETURN_TAG(c_monitor.is_supported(c_name, zone), ERR_NOT_SUPPORTED, _I, "Condition(%s) is not supported", c_name.c_str());
391 if (!ctx::privilege_manager::is_allowed(app_id, c_name.c_str())) {
392 _W("Permission denied for '%s'", c_name.c_str());
393 return ERR_PERMISSION_DENIED;
400 int ctx::rule_manager::add_rule(std::string creator, ctx::json rule, std::string zone, ctx::json* rule_id)
402 // * Insert rule to DB
406 // Check if all items are supported && allowed to access
407 int err = verify_rule(rule, creator.c_str(), zone.c_str());
408 IF_FAIL_RETURN(err==ERR_NONE, err);
410 // Check if duplicated rule exits
411 if ((rid = get_duplicated_rule(creator, zone, rule)) > 0) {
413 rule_id->set(NULL, CT_RULE_ID, rid);
417 // Insert rule to rule table, get rule id and save it to json parameter
419 std::string description;
421 rule.get(NULL, CT_RULE_DESCRIPTION, &description);
422 rule.get(NULL, CT_RULE_DETAILS, &details);
423 r_record.set(NULL, "creator", creator);
424 r_record.set(NULL, "description", description);
425 r_record.set(NULL, "details", details.str());
426 r_record.set(NULL, "zone", zone);
427 ret = db_manager::insert_sync(RULE_TABLE, r_record, &rid);
428 IF_FAIL_RETURN_TAG(ret, ERR_OPERATION_FAILED, _E, "Insert rule to db failed");
431 rule_id->set(NULL, CT_RULE_ID, rid);
433 // Insert event & conditions of a rule into each table
436 ctx::json e_option_j;
439 rule.get(CT_RULE_DETAILS "." CT_RULE_EVENT, CT_RULE_EVENT_ITEM, &e_name);
440 rule.get(CT_RULE_DETAILS "." CT_RULE_EVENT, CT_RULE_EVENT_OPTION, &e_option_j);
441 e_inst = get_instance_name(e_name, e_option_j);
443 e_record.set(NULL, "rule_id", rid);
444 e_record.set(NULL, "name", e_name);
445 e_record.set(NULL, "instance_name", e_inst);
446 e_record.set(NULL, "zone", zone);
447 ret = db_manager::insert(1, EVENT_TABLE, e_record, NULL);
448 IF_FAIL_RETURN_TAG(ret, ERR_OPERATION_FAILED, _E, "Insert event to db failed");
451 for (int i = 0; rule.get_array_elem(CT_RULE_DETAILS, CT_RULE_CONDITION, i, &it); i++){
456 ctx::json tmp_option;
459 it.get(NULL, CT_RULE_CONDITION_ITEM, &c_name);
460 it.get(NULL, CT_RULE_CONDITION_OPTION, &tmp_option);
461 c_inst = get_instance_name(c_name, tmp_option);
462 c_option.set(NULL, CT_RULE_CONDITION_OPTION, tmp_option);
463 c_option_str = c_option.dup_cstr();
465 c_record.set(NULL, "rule_id", rid);
466 c_record.set(NULL, "name", c_name);
467 c_record.set(NULL, "option", (c_option_str)? c_option_str : "");
468 c_record.set(NULL, "instance_name", c_inst);
469 c_record.set(NULL, "zone", zone);
471 ret = db_manager::insert(2, CONDITION_TABLE, c_record, NULL);
472 IF_FAIL_RETURN_TAG(ret, ERR_OPERATION_FAILED, _E, "Insert conditions to db failed");
477 _D("Add rule%d succeeded", (int)rid);
482 int ctx::rule_manager::remove_rule(int rule_id)
484 // Delete rule from DB
487 std::string query = DELETE_RULE_STATEMENT;
488 query += int_to_string(rule_id);
489 std::vector<json> record;
490 ret = db_manager::execute_sync(query.c_str(), &record);
491 IF_FAIL_RETURN_TAG(ret, ERR_OPERATION_FAILED, _E, "Remove rule from db failed");
497 int ctx::rule_manager::enable_rule(int rule_id)
502 std::string id_str = int_to_string(rule_id);
504 // Get rule json by rule id;
505 std::string q1 = QUERY_RULE_AND_ZONE_BY_RULE_ID;
506 q1 += int_to_string(rule_id);
507 std::vector<json> rule_record;
508 ret = db_manager::execute_sync(q1.c_str(), &rule_record);
509 IF_FAIL_RETURN_TAG(ret, ERR_OPERATION_FAILED, _E, "Query rule by rule id failed");
512 rule_record[0].get(NULL, "details", &r1);
513 rule_record[0].get(NULL, "zone", &zone);
516 rule.get(NULL, CT_RULE_EVENT, &event);
518 // Get event template by rule id
519 std::string q2 = QUERY_EVENT_TEMPLATE_BY_RULE_ID;
520 q2 += int_to_string(rule_id);
522 std::vector<json> etemplate_record;
523 ret = db_manager::execute_sync(q2.c_str(), &etemplate_record);
524 IF_FAIL_RETURN_TAG(ret, ERR_OPERATION_FAILED, _E, "Query event template by rule id failed");
526 etemplate_record[0].get(NULL, "j_template", &r2);
527 ctx::json etemplate = r2;
529 // Query name, instance name & template for conditions of the rule
530 std::string q3 = QUERY_NAME_INSTANCE_NAME_AND_TEMPLATE_BY_RULE_ID_STATEMENT;
532 std::vector<json> cond_record;
533 ret = db_manager::execute_sync(q3.c_str(), &cond_record);
534 IF_FAIL_RETURN_TAG(ret, ERR_OPERATION_FAILED, _E, "Query condition's names, instance names, templates by rule id failed");
536 ctx::json inst_names;
537 std::vector<json>::iterator vec_end = cond_record.end();
538 for (std::vector<json>::iterator vec_pos = cond_record.begin(); vec_pos != vec_end; ++vec_pos) {
539 ctx::json elem = *vec_pos;
544 elem.get(NULL, "name", &cname);
545 elem.get(NULL, "instance_name", &ciname);
546 elem.get(NULL, "templates", &temp);
547 ctx::json ctemplate = temp;
548 ctemplate.set(NULL, "instance_name", ciname);
549 // TODO ctemplate (name, instance_name, attributes) now - it is based on form using when templates are inserted into db when rebooting
551 // For defrule script generation
552 inst_names.set(NULL, cname.c_str(), ciname);
554 if (cname.compare(ciname) != 0) {
555 if (!clips_h.find_instance(ciname)) {
556 std::string makeinst_script = script_generator::generate_makeinstance(&ctemplate);
557 error = clips_h.make_instance(makeinst_script);
558 IF_FAIL_RETURN_TAG(error == ERR_NONE, ERR_OPERATION_FAILED, _E, "Add condition instance([%s]) failed", ciname.c_str());
560 cond_cnt_map[ciname] = 1;
562 cond_cnt_map[ciname]++;
569 etemplate.get(NULL, "name", &ename);
571 //TODO: set the proper zone
572 error = c_monitor.subscribe(rule_id, ename, event, zone.c_str());
573 IF_FAIL_RETURN(error == ERR_NONE, ERR_OPERATION_FAILED);
575 // Generate defrule script and execute it
576 std::string script = script_generator::generate_defrule(id_str, etemplate, rule, &inst_names, zone);
577 error = clips_h.define_rule(script);
578 IF_FAIL_RETURN_TAG(error == ERR_NONE, ERR_OPERATION_FAILED, _E, "Defrule failed");
580 // Update db to set 'enabled'
581 std::string q4 = UPDATE_RULE_ENABLED_STATEMENT;
583 std::vector<json> record;
584 ret = db_manager::execute_sync(q4.c_str(), &record);
585 IF_FAIL_RETURN_TAG(ret, ERR_OPERATION_FAILED, _E, "Update db failed");
587 _D(YELLOW("Enable Rule%d succeeded"), rule_id);
592 std::string ctx::rule_manager::get_instance_name(std::string name, ctx::json& option)
594 std::string inst_name = name;
596 // Get template for the option
597 std::string q = "SELECT j_template FROM context_trigger_template WHERE name = '";
600 std::vector<json> template_record;
601 db_manager::execute_sync(q.c_str(), &template_record);
604 template_record[0].get(NULL, "j_template", &ct_str);
605 ctx::json j_template = ct_str;
607 std::string option_key;
608 for (int i = 0; j_template.get_array_elem(NULL, "option", i, &option_key); i++) {
611 if (option.get(NULL, option_key.c_str(), &val_str)) {
612 inst_name += INSTANCE_NAME_DELIMITER;
613 inst_name += val_str;
614 } else if (option.get(NULL, option_key.c_str(), &val)) {
615 inst_name += INSTANCE_NAME_DELIMITER;
616 inst_name += int_to_string(val);
618 inst_name += INSTANCE_NAME_DELIMITER;
625 int ctx::rule_manager::disable_rule(int rule_id)
630 // For event with options
631 // Get rule json by rule id;
632 std::string q1 = QUERY_RULE_AND_ZONE_BY_RULE_ID;
633 q1 += int_to_string(rule_id);
634 std::vector<json> rule_record;
635 ret = db_manager::execute_sync(q1.c_str(), &rule_record);
636 IF_FAIL_RETURN_TAG(ret, ERR_OPERATION_FAILED, _E, "Query rule by rule id failed");
639 rule_record[0].get(NULL, "details", &r1);
640 rule_record[0].get(NULL, "zone", &zone);
643 rule.get(NULL, CT_RULE_EVENT, &event);
645 event.get(NULL, CT_RULE_EVENT_ITEM, &ename);
648 error = c_monitor.unsubscribe(rule_id, ename, event, zone.c_str());
649 IF_FAIL_RETURN(error == ERR_NONE, ERR_OPERATION_FAILED);
651 // Undef rule in clips
652 std::string id_str = int_to_string(rule_id);
653 std::string script = script_generator::generate_undefrule(id_str);
654 error = clips_h.route_string_command(script);
655 IF_FAIL_RETURN_TAG(error == ERR_NONE, ERR_OPERATION_FAILED, _E, "Undefrule failed");
657 // Update db to set 'disabled'
658 std::string q2 = UPDATE_RULE_DISABLED_STATEMENT;
660 std::vector<json> record;
661 ret = db_manager::execute_sync(q2.c_str(), &record);
662 IF_FAIL_RETURN_TAG(ret, ERR_OPERATION_FAILED, _E, "Update db failed");
664 // Remove condition instances TODO
665 std::string q3 = "SELECT name, instance_name FROM context_trigger_condition WHERE rule_id = ";
667 std::vector<json> name_record;
668 ret = db_manager::execute_sync(q3.c_str(), &name_record);
669 IF_FAIL_RETURN_TAG(ret, ERR_OPERATION_FAILED, _E, "Query condition's name, instance names by rule id failed");
671 std::vector<json>::iterator vec_end = name_record.end();
672 for (std::vector<json>::iterator vec_pos = name_record.begin(); vec_pos != vec_end; ++vec_pos) {
673 ctx::json elem = *vec_pos;
677 elem.get(NULL, "name", &cname);
678 elem.get(NULL, "instance_name", &ciname);
680 if (cname.compare(ciname) != 0) {
681 cond_cnt_map[ciname]--;
683 if (cond_cnt_map[ciname] == 0) {
684 error = clips_h.unmake_instance(ciname);
685 IF_FAIL_RETURN(error == ERR_NONE, error);
687 cond_cnt_map.erase(ciname);
695 void ctx::rule_manager::make_condition_option_based_on_event_data(ctx::json& ctemplate, ctx::json& edata, ctx::json* coption)
697 std::string option_key;
698 for (int i = 0; ctemplate.get_array_elem(NULL, "option", i, &option_key); i++) {
699 std::string coption_valstr;
700 if (coption->get(NULL, option_key.c_str(), &coption_valstr)) {
701 if (coption_valstr.find(EVENT_KEY_PREFIX) == 0) {
702 std::string event_key = coption_valstr.substr(1, coption_valstr.length() - 1);
704 std::string e_valstr;
706 if (edata.get(NULL, event_key.c_str(), &e_valstr)) {
707 coption->set(NULL, option_key.c_str(), e_valstr);
708 } else if (edata.get(NULL, event_key.c_str(), &e_val)) {
709 coption->set(NULL, option_key.c_str(), e_val);
716 void ctx::rule_manager::on_event_received(std::string item, ctx::json option, ctx::json data, std::string zone)
718 _D(YELLOW("Event(%s(%s) - %s) is invoked."), item.c_str(), option.str().c_str(), data.str().c_str());
719 // TODO: Check permission of an event(item), if permission denied, return
724 ret = clips_h.set_global_variable_string("zone", zone);
726 _E("Set clips zone to %s failed", zone.c_str());
730 // Generate event fact script
731 std::string q1 = "SELECT j_template FROM context_trigger_template WHERE name = '";
734 std::vector<json> etemplate_record;
735 db_manager::execute_sync(q1.c_str(), &etemplate_record);
737 etemplate_record[0].get(NULL, "j_template", &r1);
738 ctx::json etemplate = r1;
740 std::string eventfact_str = script_generator::generate_fact(item, etemplate, option, data);
742 // Get Conditions template of invoked event (db query)
743 std::string e_inst = get_instance_name(item, option);
744 std::string query = QUERY_CONDITION_TEMPLATES_OF_INVOKED_EVENT_STATEMENT;
746 query += "' AND zone = '";
749 std::vector<json> conds;
750 ret = db_manager::execute_sync(query.c_str(), &conds);
751 IF_FAIL_VOID_TAG(ret, _E, "Query condition templates of invoked event failed");
753 int cond_num = conds.size();
754 for (int i = 0; i < cond_num; i++) {
756 conds[i].get(NULL, "j_template", &temp);
757 ctx::json ctemplate = temp;
760 conds[i].get(NULL, "name", &cname);
763 conds[i].get(NULL, "instance_name", &ciname);
765 std::string coption_str;
766 conds[i].get(NULL, "option", &coption_str);
767 ctx::json coption = NULL;
768 if (!coption_str.empty()) {
769 ctx::json coption_tmp = coption_str;
770 coption_tmp.get(NULL, CT_RULE_CONDITION_OPTION, &coption);
773 // Check if the condition uses event data key as an option
774 if (ciname.find(EVENT_KEY_PREFIX) != std::string::npos) {
775 make_condition_option_based_on_event_data(ctemplate, data, &coption);
778 // TODO: Check permission of a condition(cname), if permission granted, read condition data. (or, condition data should be empty json)
780 // Get Context Data and Set the proper zone.
781 ctx::json condition_data;
782 err = c_monitor.read(cname, coption, zone.c_str(), &condition_data);
785 _D(YELLOW("Condition(%s(%s) - %s)."), cname.c_str(), coption.str().c_str(), condition_data.str().c_str());
787 // Generate ModifyInstance script
788 std::string modifyinst_script = script_generator::generate_modifyinstance(ciname, ctemplate, condition_data);
790 err = clips_h.route_string_command(modifyinst_script);
791 IF_FAIL_VOID_TAG(err == ERR_NONE, _E, "Modify condition instance failed");
794 // Add fact and Run environment
795 err = clips_h.add_fact(eventfact_str);
796 IF_FAIL_VOID_TAG(err == ERR_NONE, _E, "Assert event fact failed");
798 err = clips_h.run_environment();
799 IF_FAIL_VOID_TAG(err == ERR_NONE, _E, "Run environment failed");
801 // Retract event fact
802 std::string retract_command = "(retract *)";
803 err = clips_h.route_string_command(retract_command);
804 IF_FAIL_VOID_TAG(err == ERR_NONE, _E, "Retract event fact failed");
807 static void trigger_action_app_control(ctx::json& action, std::string zone)
810 std::string appctl_str;
811 action.get(NULL, CT_RULE_ACTION_APP_CONTROL, &appctl_str);
813 char* str = static_cast<char*>(malloc(appctl_str.length()));
815 _E("Memory allocation failed");
818 appctl_str.copy(str, appctl_str.length(), 0);
819 bundle_raw* encoded = reinterpret_cast<unsigned char*>(str);
820 bundle* appctl_bundle = bundle_decode(encoded, appctl_str.length());
822 app_control_h app = NULL;
823 app_control_create(&app);
824 app_control_import_from_bundle(app, appctl_bundle);
827 app_control_get_operation(app, &op);
828 app_control_set_operation(app, APP_SVC_OPERATION_JUMP);
829 app_control_add_extra_data(app, APP_SVC_K_JUMP_ZONE_NAME, zone.c_str());
831 app_control_add_extra_data(app, APP_SVC_K_JUMP_ORIGIN_OPERATION, op);
834 error = app_control_send_launch_request(app, NULL, NULL);
835 if (error != APP_CONTROL_ERROR_NONE) {
836 _E("Launch request failed(%d)", error);
838 _D("Launch request succeeded");
840 bundle_free(appctl_bundle);
842 app_control_destroy(app);
845 static void trigger_action_notification(ctx::json& action, std::string creator, std::string zone)
848 notification_h notification = notification_create(NOTIFICATION_TYPE_NOTI);
850 if (action.get(NULL, CT_RULE_ACTION_NOTI_TITLE, &title)) {
851 error = notification_set_text(notification, NOTIFICATION_TEXT_TYPE_TITLE, title.c_str(), NULL, NOTIFICATION_VARIABLE_TYPE_NONE);
852 if (error != NOTIFICATION_ERROR_NONE) {
853 _E("Set notification title failed(%d)", error);
858 if (action.get(NULL, CT_RULE_ACTION_NOTI_CONTENT, &content)) {
859 error = notification_set_text(notification, NOTIFICATION_TEXT_TYPE_CONTENT, content.c_str(), NULL, NOTIFICATION_VARIABLE_TYPE_NONE);
860 if (error != NOTIFICATION_ERROR_NONE) {
861 _E("Set notification contents failed(%d)", error);
865 std::string image_path;
866 if (action.get(NULL, CT_RULE_ACTION_NOTI_ICON_PATH, &image_path)) {
867 error = notification_set_image(notification, NOTIFICATION_IMAGE_TYPE_ICON, image_path.c_str());
868 if (error != NOTIFICATION_ERROR_NONE) {
869 _E("Set notification icon image failed(%d)", error);
873 std::string appctl_str;
875 bundle_raw* encoded = NULL;
876 bundle* appctl_bundle = NULL;
877 app_control_h app = NULL;
878 if (action.get(NULL, CT_RULE_ACTION_APP_CONTROL, &appctl_str)) {
879 str = static_cast<char*>(malloc(appctl_str.length()));
881 _E("Memory allocation failed");
882 notification_free(notification);
885 appctl_str.copy(str, appctl_str.length(), 0);
886 encoded = reinterpret_cast<unsigned char*>(str);
887 appctl_bundle = bundle_decode(encoded, appctl_str.length());
889 app_control_create(&app);
890 app_control_import_from_bundle(app, appctl_bundle);
892 error = notification_set_launch_option(notification, NOTIFICATION_LAUNCH_OPTION_APP_CONTROL, app);
893 if (error != NOTIFICATION_ERROR_NONE) {
894 _E("Set launch option failed(%d)", error);
898 error = notification_set_pkgname(notification, creator.c_str());
899 if (error != NOTIFICATION_ERROR_NONE) {
900 _E("Set pkgname(%s) failed(%d)", creator.c_str(), error);
903 ctx::scope_zone_joiner sz(zone.c_str());
905 error = notification_post(notification);
906 if (error != NOTIFICATION_ERROR_NONE) {
907 _E("Post notification failed(%d)", error);
909 _D("Post notification succeeded");
912 bundle_free(appctl_bundle);
914 notification_free(notification);
916 app_control_destroy(app);
920 void ctx::rule_manager::on_rule_triggered(int rule_id)
922 _D(YELLOW("Rule%d is triggered"), rule_id);
924 std::string q = "SELECT details, creator, zone FROM context_trigger_rule WHERE row_id =";
925 q += int_to_string(rule_id);
927 std::vector<json> record;
928 db_manager::execute_sync(q.c_str(), &record);
930 std::string details_str;
931 record[0].get(NULL, "details", &details_str);
932 ctx::json details = details_str;
934 details.get(NULL, CT_RULE_ACTION, &action);
936 record[0].get(NULL, "zone", &zone);
939 if (action.get(NULL, CT_RULE_ACTION_TYPE, &type)) {
940 if (type.compare(CT_RULE_ACTION_TYPE_APP_CONTROL) == 0) {
941 trigger_action_app_control(action, zone);
942 } else if (type.compare(CT_RULE_ACTION_TYPE_NOTIFICATION) == 0) {
944 record[0].get(NULL, "creator", &creator);
945 trigger_action_notification(action, creator, zone);
950 int ctx::rule_manager::check_rule(std::string creator, int rule_id)
952 // Get creator app id
953 std::string q = "SELECT creator FROM context_trigger_rule WHERE row_id =";
954 q += int_to_string(rule_id);
956 std::vector<json> record;
957 bool ret = db_manager::execute_sync(q.c_str(), &record);
958 IF_FAIL_RETURN_TAG(ret, false, _E, "Query creator by rule id failed");
960 if (record.size() == 0) {
965 record[0].get(NULL, "creator", &c);
967 if (c.compare(creator) == 0){
974 bool ctx::rule_manager::is_rule_enabled(int rule_id)
976 std::string q = "SELECT enabled FROM context_trigger_rule WHERE row_id =";
977 q += int_to_string(rule_id);
979 std::vector<json> record;
980 bool ret = db_manager::execute_sync(q.c_str(), &record);
981 IF_FAIL_RETURN_TAG(ret, false, _E, "Query enabled by rule id failed");
984 record[0].get(NULL, "enabled", &enabled);
992 int ctx::rule_manager::get_rule_by_id(std::string creator, int rule_id, ctx::json* request_result)
994 // std::string q = "SELECT description, details FROM context_trigger_rule WHERE (creator = '";
995 std::string q = "SELECT description FROM context_trigger_rule WHERE (creator = '";
997 q += "') and (row_id = ";
998 q += int_to_string(rule_id);
1001 std::vector<json> record;
1002 bool ret = db_manager::execute_sync(q.c_str(), &record);
1003 IF_FAIL_RETURN_TAG(ret, false, _E, "Query rule by rule id failed");
1005 if (record.size() == 0) {
1007 } else if (record.size() != 1) {
1008 return ERR_OPERATION_FAILED;
1011 std::string description;
1012 // std::string details;
1013 record[0].get(NULL, "description", &description);
1014 // record[0].get(NULL, "details", &details);
1016 (*request_result).set(NULL, CT_RULE_ID, rule_id);
1017 (*request_result).set(NULL, CT_RULE_DESCRIPTION, description);
1018 // (*request_result).set(NULL, CT_RULE_DETAILS, details);
1023 int ctx::rule_manager::get_rule_ids(std::string creator, ctx::json* request_result)
1025 (*request_result) = "{ \"" CT_RULE_ARRAY_ENABLED "\" : [ ] , \"" CT_RULE_ARRAY_DISABLED "\" : [ ] }";
1027 std::string q = "SELECT row_id, enabled FROM context_trigger_rule WHERE (creator = '";
1031 std::vector<json> record;
1032 bool ret = db_manager::execute_sync(q.c_str(), &record);
1033 IF_FAIL_RETURN_TAG(ret, ERR_OPERATION_FAILED, _E, "Query rules failed");
1035 std::vector<json>::iterator vec_end = record.end();
1036 for (std::vector<json>::iterator vec_pos = record.begin(); vec_pos != vec_end; ++vec_pos) {
1037 ctx::json elem = *vec_pos;
1041 elem.get(NULL, "row_id", &id);
1042 elem.get(NULL, "enabled", &enabled);
1045 (*request_result).array_append(NULL, CT_RULE_ARRAY_ENABLED, string_to_int(id));
1046 } else if (enabled == 0) {
1047 (*request_result).array_append(NULL, CT_RULE_ARRAY_DISABLED, string_to_int(id));