2 * Copyright (c) 2015 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.
19 #include <TriggerRuleTypes.h>
20 #include "RuleEvaluator.h"
21 #include "FactTypes.h"
23 #define OPERATOR_EQ "=="
24 #define OPERATOR_NEQ "!="
25 #define OPERATOR_LEQ "<="
26 #define OPERATOR_GEQ ">="
27 #define OPERATOR_LT "<"
28 #define OPERATOR_GT ">"
31 using namespace ctx::trigger;
33 RuleEvaluator::RuleEvaluator()
38 bool RuleEvaluator::__evaluateSingleData(T factVal, Json& comparison, std::string op)
41 comparison.get(NULL, TRIG_RULE_KEY_VALUE, &ruleVal);
43 if (op == TRIG_RULE_OP_EQUAL_TO) {
44 return (ruleVal == factVal);
45 } else if (op == TRIG_RULE_OP_NOT_EQUAL_TO) {
46 return (ruleVal != factVal);
47 } else if (op == TRIG_RULE_OP_GREATER_THAN) {
48 return (ruleVal > factVal);
49 } else if (op == TRIG_RULE_OP_GREATER_THAN_OR_EQUAL_TO) {
50 return (ruleVal >= factVal);
51 } else if (op == TRIG_RULE_OP_LESS_THAN) {
52 return (ruleVal < factVal);
53 } else if (op == TRIG_RULE_OP_LESS_THAN_OR_EQUAL_TO) {
54 return (ruleVal <= factVal);
61 bool RuleEvaluator::__evaluateDualData(T factVal, Json& comparison, std::string op)
64 comparison.getAt(NULL, TRIG_RULE_KEY_VALUE, 0, &ruleVal1);
65 comparison.getAt(NULL, TRIG_RULE_KEY_VALUE, 1, &ruleVal2);
67 if (op == TRIG_RULE_OP_IN) {
68 return (ruleVal1 <= factVal && factVal <= ruleVal2);
69 } else if (op == TRIG_RULE_OP_NOT_IN) {
70 return (factVal < ruleVal1 || ruleVal2 < factVal);
77 bool RuleEvaluator::__evaluateMultipleData(T factVal, Json& comparison, std::string op)
80 for (int i = 0; comparison.getAt(NULL, TRIG_RULE_KEY_VALUE, i, &ruleVal); i++) {
81 if (ruleVal == factVal) {
82 if (op == TRIG_RULE_OP_ONE_OF) {
84 } else if (op == TRIG_RULE_OP_NONE_OF) {
90 if (op == TRIG_RULE_OP_NONE_OF) {
98 bool RuleEvaluator::__evaluateData(T factVal, Json& comparison)
101 comparison.get(NULL, TRIG_RULE_KEY_OPERATOR, &op);
103 if (op == TRIG_RULE_OP_EQUAL_TO || op == TRIG_RULE_OP_NOT_EQUAL_TO ||
104 op == TRIG_RULE_OP_GREATER_THAN || op == TRIG_RULE_OP_GREATER_THAN_OR_EQUAL_TO ||
105 op == TRIG_RULE_OP_LESS_THAN || op == TRIG_RULE_OP_LESS_THAN_OR_EQUAL_TO) {
106 return __evaluateSingleData(factVal, comparison, op);
107 } else if (op == TRIG_RULE_OP_IN || op == TRIG_RULE_OP_NOT_IN) {
108 return __evaluateDualData(factVal, comparison, op);
109 } else if (op == TRIG_RULE_OP_ONE_OF || op == TRIG_RULE_OP_NONE_OF) {
110 return __evaluateMultipleData(factVal, comparison, op);
116 void RuleEvaluator::__replaceSingleDataReferences(Json& eventFactData, Json& ruleComp, std::string& dataKey)
119 std::string eventRefStr;
122 if (!ruleComp.get(dataKey.c_str(), TRIG_RULE_KEY_VALUE, &refVal)) {
126 if (refVal.substr(0, 1) != TRIG_RULE_REF_KEY_PREFIX) {
130 std::string eventKey = refVal.substr(1, refVal.length() - 1);
131 if (eventFactData.get(NULL, eventKey.c_str(), &eventRefStr)) {
132 ruleComp.set(dataKey.c_str(), TRIG_RULE_KEY_VALUE, eventRefStr);
133 } else if (eventFactData.get(NULL, eventKey.c_str(), &eventRefInt)) {
134 ruleComp.set(dataKey.c_str(), TRIG_RULE_KEY_VALUE, eventRefInt);
136 _W("Attribute %s not found in event_data", eventKey.c_str());
140 void RuleEvaluator::__replaceMultipleDataReferences(Json& eventFactData, Json& ruleComp, std::string& dataKey)
143 std::string eventRefStr;
146 for (int i = 0; ruleComp.getAt(dataKey.c_str(), TRIG_RULE_KEY_VALUE, i, &refVal); i++) {
147 if (refVal.substr(0, 1) != TRIG_RULE_REF_KEY_PREFIX) {
151 std::string eventKey = refVal.substr(1, refVal.length() - 1);
152 if (eventFactData.get(NULL, eventKey.c_str(), &eventRefStr)) {
153 ruleComp.setAt(dataKey.c_str(), TRIG_RULE_KEY_VALUE, i, eventRefStr);
154 } else if (eventFactData.get(NULL, eventKey.c_str(), &eventRefInt)) {
155 ruleComp.setAt(dataKey.c_str(), TRIG_RULE_KEY_VALUE, i, eventRefInt);
157 _W("Attribute %s not found in event_data", eventKey.c_str());
162 void RuleEvaluator::__replaceDataReferences(Json eventFactData, Json& ruleComp)
164 // Replace referencing data to actual value
165 std::list<std::string> compKeys;
166 ruleComp.getKeys(&compKeys);
168 for (auto it = compKeys.begin(); it != compKeys.end(); ++it) {
169 std::string dataKey = *it;
172 ruleComp.get(dataKey.c_str(), TRIG_RULE_KEY_OPERATOR, &op);
175 if (op == TRIG_RULE_OP_EQUAL_TO || op == TRIG_RULE_OP_NOT_EQUAL_TO ||
176 op == TRIG_RULE_OP_GREATER_THAN || op == TRIG_RULE_OP_GREATER_THAN_OR_EQUAL_TO ||
177 op == TRIG_RULE_OP_LESS_THAN || op == TRIG_RULE_OP_LESS_THAN_OR_EQUAL_TO) {
179 __replaceSingleDataReferences(eventFactData, ruleComp, dataKey);
181 __replaceMultipleDataReferences(eventFactData, ruleComp, dataKey);
186 bool RuleEvaluator::__evaluateItem(Json& factItem, Json& ruleItem, std::string logicalOp)
189 factItem.get(NULL, FACT_KEY_NAME, &name);
192 ruleItem.get(name.c_str(), TRIG_RULE_KEY_COMPARISON, &comparison);
194 std::list<std::string> compKeys;
195 comparison.getKeys(&compKeys);
196 if (compKeys.size() == 0) {
200 bool isConjunction = (TRIG_RULE_LOGICAL_CONJUNCTION == logicalOp);
202 for (auto it = compKeys.begin(); it != compKeys.end(); ++it) {
203 std::string dataKey = *it;
206 comparison.get(NULL, dataKey.c_str(), &comp);
208 std::string factValStr;
212 if (factItem.get(FACT_KEY_DATA, dataKey.c_str(), &factValStr)) {
213 result = __evaluateData(factValStr, comp);
214 } else if (factItem.get(FACT_KEY_DATA, dataKey.c_str(), &factValInt)) {
215 result = __evaluateData(factValInt, comp);
217 _W("Could not get value corresponding to data key %s", dataKey.c_str());
221 if (isConjunction && !result) {
223 } else if (!isConjunction && result) {
227 return isConjunction;
230 bool RuleEvaluator::__evaluateRuleEvent(Json& fact, Json& rule)
234 fact.get(NULL, FACT_KEY_EVENT, &factItem);
235 rule.get(NULL, TRIG_RULE_KEY_EVENT, &ruleItem);
238 rule.get(_TRIG_RULE_KEY_EXTRA, _TRIG_RULE_KEY_EVENT_LOGICAL_OP, &eventOp);
240 return __evaluateItem(factItem, ruleItem, eventOp);
243 Json RuleEvaluator::__getConditionFact(Json& fact, Json& ruleCond)
245 std::list<std::string> condKey;
246 ruleCond.getKeys(&condKey);
247 std::string ruleCondName = *(condKey.begin());
250 for (int i = 0; fact.getAt(NULL, FACT_KEY_CONDITION, i, &factCond); i++) {
251 // Check if fact item name is matched with condition
252 std::string factCondName;
253 factCond.get(NULL, FACT_KEY_NAME, &factCondName);
254 if (factCondName != ruleCondName) {
258 // Check if fact item option is mathced with condition
261 ruleCond.get(ruleCondName.c_str(), TRIG_RULE_KEY_OPTION, &ruleCondOption);
262 factCond.get(NULL, FACT_KEY_OPTION, &factCondOption);
263 if (factCondOption == ruleCondOption) {
268 _W(YELLOW("find condition failed for condition"));
269 return EMPTY_JSON_OBJECT;
272 bool RuleEvaluator::__evaluateRuleCondition(Json& fact, Json& rule)
275 rule.get(_TRIG_RULE_KEY_EXTRA, _TRIG_RULE_KEY_RULE_LOGICAL_OP, &ruleOp);
276 bool isConjunction = (TRIG_RULE_LOGICAL_CONJUNCTION == ruleOp);
279 for (int i = 0; rule.getAt(NULL, TRIG_RULE_KEY_CONDITION, i, &ruleCond); i++) {
280 Json factCond = __getConditionFact(fact, ruleCond);
283 if (factCond == EMPTY_JSON_OBJECT) {
287 rule.getAt(_TRIG_RULE_KEY_EXTRA, _TRIG_RULE_KEY_CONDITION_LOGICAL_OP, i, &condOp);
288 result = __evaluateItem(factCond, ruleCond, condOp);
291 if (isConjunction && !result) {
293 } else if (!isConjunction && result) {
298 return isConjunction;
301 bool RuleEvaluator::__replaceOptionReferences(Json eventFactData, Json& ruleOption)
303 // Replace referencing option to actual value
305 std::string eventRefStr;
308 std::list<std::string> keyList;
309 ruleOption.getKeys(&keyList);
311 for (std::list<std::string>::iterator it = keyList.begin(); it != keyList.end(); ++it) {
312 std::string optionKey = *it;
314 if (!ruleOption.get(NULL, optionKey.c_str(), &refVal)) {
317 if (!(refVal.substr(0, 1) == TRIG_RULE_REF_KEY_PREFIX)) {
321 std::string eventKey = refVal.substr(1, refVal.length() - 1);
322 if (eventFactData.get(NULL, eventKey.c_str(), &eventRefStr)) {
323 ruleOption.set(NULL, optionKey.c_str(), eventRefStr);
324 } else if (eventFactData.get(NULL, eventKey.c_str(), &eventRefInt)) {
325 ruleOption.set(NULL, optionKey.c_str(), eventRefInt);
327 _W("Option %s not found in event_data", eventKey.c_str());
335 bool RuleEvaluator::__replaceEventReferences(Json& fact, Json& rule)
337 // Replace referencing data/option to actual value
339 if (!fact.get(FACT_KEY_EVENT, FACT_KEY_DATA, &eventFactData)) {
340 _E("No event data found, error");
345 for (int i = 0; rule.getAt(NULL, TRIG_RULE_KEY_CONDITION, i, &ruleCond); i++) {
346 std::list<std::string> condKey;
347 ruleCond.getKeys(&condKey);
348 std::string ruleCondName = *(condKey.begin());
351 for (int j = 0; ruleCond.getAt(ruleCondName.c_str(), TRIG_RULE_KEY_COMPARISON, j, &ruleComp); j++) {
352 __replaceDataReferences(eventFactData, ruleComp);
356 if (ruleCond.get(ruleCondName.c_str(), TRIG_RULE_KEY_OPTION, &ruleOption)) {
357 __replaceOptionReferences(eventFactData, ruleOption);
364 bool RuleEvaluator::evaluateRule(Json rule, Json fact)
366 _D("Rule is %s ", rule.str().c_str());
367 _D("fact is %s ", fact.str().c_str());
372 if (fact.get(NULL, FACT_KEY_CONDITION, &tempJson)) {
373 Json ruleCopy(rule.str());
374 if (!eval.__replaceEventReferences(fact, ruleCopy)) {
375 _W("Replace failed");
377 ret = eval.__evaluateRuleCondition(fact, ruleCopy);
378 _D("Checking condition %s", ret ? "true" : "false");
380 ret = eval.__evaluateRuleEvent(fact, rule);
381 _D("Checking event %s", ret ? "true" : "false");