Replace CLIPS with the internal rule evaluator 02/56602/1
authorSomin Kim <somin926.kim@samsung.com>
Mon, 11 Jan 2016 09:38:57 +0000 (18:38 +0900)
committerSomin Kim <somin926.kim@samsung.com>
Mon, 11 Jan 2016 09:38:57 +0000 (18:38 +0900)
Change-Id: Ic1cb589030b8660150114fa5194734c8233ebe0c
Signed-off-by: kunal <kunal.chawla@samsung.com>
Signed-off-by: Somin Kim <somin926.kim@samsung.com>
src/context_trigger/rule.cpp
src/context_trigger/rule_evaluator.cpp
src/context_trigger/rule_evaluator.h

index deae787e39f1c2ec58bec50f0f7b1de032c70469..13a7a68fe1abdc291ea61add872c498c9e6fd582 100644 (file)
@@ -145,8 +145,7 @@ void ctx::trigger_rule::on_event_received(std::string name, ctx::json option, ct
                return;
        }
 
-       // TODO check if event matched first
-
+       IF_FAIL_VOID_TAG(ctx::rule_evaluator::evaluate_rule(statement, result), _E, "Event not matched");
 
        // Request read conditions
        for (std::list<context_item_t>::iterator it = condition.begin(); it != condition.end(); ++it) {
@@ -190,7 +189,6 @@ void ctx::trigger_rule::on_context_data_prepared(void)
        if (ctx::rule_evaluator::evaluate_rule(statement, result)) {
                ctx::action_manager::trigger_action(action, creator);
        }
-
        clear_result();
 }
 
index 8071800f9a0bdc21cf588e2726642c76e31a25b8..1bb90ed378d0e7c78c0d53ff6b2a0b48a53148e7 100644 (file)
  */
 
 #include <json.h>
+#include <types_internal.h>
 #include <context_trigger_types_internal.h>
 #include "rule_evaluator.h"
 #include "context_fact_types.h"
 
-bool ctx::rule_evaluator::evaluate_rule(ctx::json& rule, ctx::json& data)
+#define AND_STRING "and"
+#define OR_STRING "or"
+#define EVENT_REFERENCE "?"
+#define OPERATOR_EQ "=="
+#define OPERATOR_NEQ "!="
+#define OPERATOR_LEQ "<="
+#define OPERATOR_GEQ ">="
+#define OPERATOR_LT "<"
+#define OPERATOR_GT ">"
+
+ctx::rule_evaluator::rule_evaluator()
+{
+}
+
+bool ctx::rule_evaluator::compare_string(std::string operation, std::string rule_var, std::string fact_var)
+{
+       if (operation == OPERATOR_EQ) {
+               return (rule_var == fact_var);
+       } else if (operation == OPERATOR_NEQ) {
+               return (rule_var != fact_var);
+       } else {
+               _E("Operator %s not supported", operation.c_str());
+               return false;
+       }
+}
+
+bool ctx::rule_evaluator::compare_int(std::string operation, int rule_var, int fact_var)
+{
+       if (operation == OPERATOR_EQ) {
+               return (rule_var == fact_var);
+       } else if (operation == OPERATOR_NEQ) {
+               return (rule_var != fact_var);
+       } else if (operation == OPERATOR_LEQ) {
+               return (rule_var <= fact_var);
+       } else if (operation == OPERATOR_GEQ) {
+               return (rule_var >= fact_var);
+       } else if (operation == OPERATOR_LT) {
+               return (rule_var < fact_var);
+       } else if (operation == OPERATOR_GT) {
+               return (rule_var > fact_var);
+       } else {
+               _E("Operator %s not supported", operation.c_str());
+               return false;
+       }
+}
+
+bool ctx::rule_evaluator::replace_data_references(ctx::json& rule_data_arr, ctx::json event_fact_data)
+{
+       std::string arr_string;
+       std::string event_reference_string;
+       int event_reference_int;
+
+       for (int i = 0; i < rule_data_arr.array_get_size(NULL, CT_RULE_DATA_VALUE_ARR); i++) {
+               if (!rule_data_arr.get_array_elem(NULL, CT_RULE_DATA_VALUE_ARR, i, &arr_string)) {
+                       continue;
+               }
+               if (arr_string.substr(0, 1) != EVENT_REFERENCE) {
+                       continue;
+               }
+
+               std::string event_key = arr_string.substr(1, arr_string.length() - 1);
+               if (event_fact_data.get(NULL, event_key.c_str(), &event_reference_string)) {
+                       rule_data_arr.array_set_at(NULL, CT_RULE_DATA_VALUE_ARR, i, event_reference_string);
+               } else if (event_fact_data.get(NULL, event_key.c_str(), &event_reference_int)) {
+                       rule_data_arr.array_set_at(NULL, CT_RULE_DATA_VALUE_ARR, i, event_reference_int);
+               } else {
+                       _W("Option %s not found in event_data", event_key.c_str());
+               }
+       }
+
+       return true;
+}
+
+bool ctx::rule_evaluator::replace_option_references(ctx::json& rule_option, ctx::json event_fact_data)
+{
+       std::list<std::string> key_list;
+       rule_option.get_keys(&key_list);
+
+       for (std::list<std::string>::iterator it = key_list.begin(); it != key_list.end(); ++it) {
+               std::string option_key = *it;
+               std::string rule_key_value_str;
+
+               if (!rule_option.get(NULL, (*it).c_str(), &rule_key_value_str)) {
+                       continue;
+               }
+               if (!(rule_key_value_str.substr(0, 1) == EVENT_REFERENCE)) {
+                       continue;
+               }
+
+               int rule_event_key_value_int;
+               std::string rule_event_key_value_str;
+               std::string event_key = rule_key_value_str.substr(1, rule_key_value_str.length() - 1);
+               if (event_fact_data.get(NULL, event_key.c_str(), &rule_event_key_value_str)) {
+                       rule_option.set(NULL, (*it).c_str(), rule_event_key_value_str);
+               } else if (event_fact_data.get(NULL, event_key.c_str(), &rule_event_key_value_int)) {
+                       rule_option.set(NULL, (*it).c_str(), rule_event_key_value_int);
+               } else {
+                       _W("Option %s not found in event_data", event_key.c_str());
+                       return false;
+               }
+       }
+
+       return true;
+}
+
+bool ctx::rule_evaluator::replace_event_references(ctx::json& rule, ctx::json& fact)
 {
+       ctx::json event_fact_data;
+       if (!fact.get(CONTEXT_FACT_EVENT, CONTEXT_FACT_DATA, &event_fact_data)) {
+               _E("No event data found, error");
+               return false;
+       }
+
+       ctx::json rule_condition;
+       for (int i = 0; rule.get_array_elem(NULL, CT_RULE_CONDITION, i, &rule_condition); i++) {
+               ctx::json rule_data_arr;
+               for (int j = 0; rule_condition.get_array_elem(NULL, CT_RULE_DATA_ARR, j, &rule_data_arr); j++) {
+                       replace_data_references(rule_data_arr, event_fact_data);
+               }
+
+               ctx::json rule_option;
+               if (rule_condition.get(NULL, CT_RULE_CONDITION_OPTION, &rule_option)) {
+                       replace_option_references(rule_option, event_fact_data);
+               }
+       }
+
        return true;
 }
+
+bool ctx::rule_evaluator::evaluate_data_string(ctx::json& rule_data_arr, std::string fact_value_str)
+{
+       std::string operate_internal;
+       rule_data_arr.get(NULL, CT_RULE_DATA_KEY_OPERATOR, &operate_internal);
+       bool is_and = false;
+       if (AND_STRING == operate_internal) {
+               is_and = true;
+       }
+
+       std::string operator_str;
+       for (int j = 0; rule_data_arr.get_array_elem(NULL, CT_RULE_DATA_VALUE_OPERATOR_ARR, j, &operator_str); j++) {
+               bool data_arr_vale_match;
+               std::string get_str_val;
+               rule_data_arr.get_array_elem(NULL, CT_RULE_DATA_VALUE_ARR, j, &get_str_val);
+               data_arr_vale_match = compare_string(operator_str, fact_value_str, get_str_val);
+
+               if (is_and && !data_arr_vale_match) {
+                       return false;
+               } else if (!is_and && data_arr_vale_match) {
+                       return true;
+               }
+       }
+       return is_and;
+}
+
+bool ctx::rule_evaluator::evaluate_data_int(ctx::json& rule_data_arr, int fact_value_int)
+{
+       std::string operate_internal;
+       rule_data_arr.get(NULL, CT_RULE_DATA_KEY_OPERATOR, &operate_internal);
+       bool is_and = false;
+       if (AND_STRING == operate_internal) {
+               is_and = true;
+       }
+
+       std::string operator_str;
+       for (int j = 0; rule_data_arr.get_array_elem(NULL, CT_RULE_DATA_VALUE_OPERATOR_ARR, j, &operator_str); j++) {
+               bool data_arr_vale_match;
+               int get_int_val;
+               if (!rule_data_arr.get_array_elem(NULL, CT_RULE_DATA_VALUE_ARR, j, &get_int_val)) {
+                       data_arr_vale_match = false;
+               }
+               data_arr_vale_match = compare_int(operator_str, fact_value_int, get_int_val);
+
+               if (is_and && !data_arr_vale_match) {
+                       return false;
+               } else if (!is_and && data_arr_vale_match) {
+                       return true;
+               }
+       }
+       return is_and;
+}
+
+bool ctx::rule_evaluator::evaluate_item(ctx::json& rule_item, ctx::json& fact_item)
+{
+       ctx::json rule_data_arr;
+       if (rule_item.array_get_size(NULL, CT_RULE_DATA_ARR) == 0) {
+               return true;
+       }
+
+       std::string operate;
+       bool is_and = false;
+       rule_item.get(NULL, CT_RULE_CONDITION_OPERATOR, &operate);
+       if (AND_STRING == operate) {
+               is_and = true;
+       }
+
+       for (int i = 0; rule_item.get_array_elem(NULL, CT_RULE_DATA_ARR, i, &rule_data_arr); i++) {
+               std::string data_key;
+               rule_data_arr.get(NULL, CT_RULE_DATA_KEY, &data_key);
+               std::string fact_value_str;
+               int fact_value_int;
+
+               bool rule_data_arr_true;
+               if (fact_item.get(CONTEXT_FACT_DATA, data_key.c_str(), &fact_value_str)) {
+                       rule_data_arr_true = evaluate_data_string(rule_data_arr, fact_value_str);
+               } else if (fact_item.get(CONTEXT_FACT_DATA, data_key.c_str(), &fact_value_int)) {
+                       rule_data_arr_true = evaluate_data_int(rule_data_arr, fact_value_int);
+               } else {
+                       _W("Could not get value corresponding to data key %s", data_key.c_str());
+                       rule_data_arr_true = false;
+               }
+
+               if (is_and && !rule_data_arr_true) {
+                       return false;
+               } else if (!is_and && rule_data_arr_true) {
+                       return true;
+               }
+       }
+       return is_and;
+}
+
+bool ctx::rule_evaluator::check_rule_event(ctx::json& rule, ctx::json& fact)
+{
+       ctx::json fact_item;
+       fact.get(NULL, CONTEXT_FACT_EVENT, &fact_item);
+       ctx::json rule_item;
+       rule.get(NULL, CT_RULE_EVENT, &rule_item);
+       return evaluate_item(rule_item, fact_item);
+}
+
+ctx::json ctx::rule_evaluator::find_condition_fact(ctx::json& rule_condition, ctx::json& fact)
+{
+       ctx::json fact_condition;
+       std::string item_name_rule_condition;
+       rule_condition.get(NULL, CT_RULE_CONDITION_ITEM, &item_name_rule_condition);
+
+       std::string item_name_fact_condition;
+       for (int i = 0; fact.get_array_elem(NULL, CONTEXT_FACT_CONDITION, i, &fact_condition); i++) {
+               fact_condition.get(NULL, CONTEXT_FACT_NAME, &item_name_fact_condition);
+               if (item_name_fact_condition != item_name_rule_condition) {
+                       continue;
+               }
+
+               ctx::json rule_condition_option;
+               ctx::json fact_condition_option;
+               rule_condition.get(NULL, CT_RULE_CONDITION_OPTION, &rule_condition_option);
+               fact_condition.get(NULL, CONTEXT_FACT_OPTION, &fact_condition_option);
+               if (fact_condition_option == rule_condition_option) {
+                       return fact_condition;
+               }
+       }
+
+       _W(YELLOW("find_condition failed for condition"));
+       return EMPTY_JSON_OBJECT;
+}
+
+bool ctx::rule_evaluator::check_rule_condition(ctx::json& rule, ctx::json& fact)
+{
+       ctx::json rule_condition;
+       ctx::json fact_condition;
+
+       std::string operate;
+       rule.get(NULL, CT_RULE_OPERATOR, &operate);
+       bool is_and = false;
+       if (operate == AND_STRING) {
+               is_and = true;
+       }
+
+       for (int i = 0; rule.get_array_elem(NULL, CT_RULE_CONDITION, i, &rule_condition); i++) {
+               fact_condition = find_condition_fact(rule_condition, fact);
+               bool condition_satisfied;
+               if (fact_condition == EMPTY_JSON_OBJECT) {
+                       condition_satisfied = false;
+               } else {
+                       condition_satisfied = evaluate_item(rule_condition, fact_condition);
+               }
+
+               if (is_and && !condition_satisfied) {
+                       return false;
+               } else if (!is_and && condition_satisfied) {
+                       return true;
+               }
+       }
+
+       return is_and;
+}
+
+bool ctx::rule_evaluator::evaluate_rule(ctx::json rule, ctx::json fact)
+{
+       _D("Rule is %s ", rule.str().c_str());
+       _D("fact is %s ", fact.str().c_str());
+       rule_evaluator eval;
+       bool ret;
+       ctx::json temp_json;
+       if (fact.get(NULL, CT_RULE_CONDITION, &temp_json)) {
+               ctx::json rule_copy(rule.str());
+               if (!eval.replace_event_references(rule_copy, fact)) {
+                       _W("Replace failed");
+               }
+               ret = eval.check_rule_condition(rule_copy, fact);
+               _D("Checking condition %s", ret ? "true" : "false");
+       } else {
+               ret = eval.check_rule_event(rule, fact);
+               _D("Checking event %s", ret ? "true" : "false");
+       }
+       return ret;
+}
\ No newline at end of file
index e116fc1568812bf6bbbf1d8ca3015bf47812ea86..9147eae692e588e6a77ebb2335fc0719920afa1b 100644 (file)
@@ -21,11 +21,23 @@ namespace ctx {
 
        class json;
 
-       namespace rule_evaluator {
-
-               bool evaluate_rule(ctx::json& rule, ctx::json& data);
-
-       }
+       class rule_evaluator {
+       private:
+               rule_evaluator();
+               bool evaluate_item(ctx::json& rule_item, ctx::json& fact_item);
+               bool compare_int(std::string operation, int rule_var, int fact_var);
+               bool compare_string(std::string operation, std::string rule_var, std::string fact_var);
+               bool check_rule_event(ctx::json& rule, ctx::json& fact);
+               ctx::json find_condition_fact(ctx::json& rule_condition, ctx::json& fact);
+               bool check_rule_condition(ctx::json& rule, ctx::json& fact);
+               bool replace_data_references(ctx::json& rule_data_arr, ctx::json event_fact_data);
+               bool replace_option_references(ctx::json& rule_option, ctx::json event_fact_data);
+               bool replace_event_references(ctx::json& rule, ctx::json& fact);
+               bool evaluate_data_string(ctx::json& rule_data_arr, std::string fact_value_str);
+               bool evaluate_data_int(ctx::json& rule_data_arr, int fact_value_int);
+       public:
+               static bool evaluate_rule(ctx::json rule, ctx::json data);
+       };
 
 }      /* namespace ctx */