Remove profile build dependencies
[platform/core/context/context-service.git] / src / trigger / Rule.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 <TriggerRuleTypes.h>
18 #include "Rule.h"
19 #include "ActionManager.h"
20 #include "RuleEvaluator.h"
21 #include "ContextMonitor.h"
22 #include "FactTypes.h"
23 #include "RuleManager.h"
24
25 using namespace ctx;
26 using namespace ctx::trigger;
27
28 RuleManager *Rule::__ruleMgr = NULL;
29
30 Rule::Rule(int i, Json& d, const char* p, RuleManager* rm) :
31          __result(EMPTY_JSON_OBJECT),
32         id(i),
33         pkgId(p)
34 {
35         // Rule manager
36         if (!__ruleMgr) {
37                 __ruleMgr = rm;
38         }
39
40         // Statement
41         __statement = d.str();
42
43         // Event
44         Json e;
45         d.get(NULL, TRIG_RULE_KEY_EVENT, &e);
46         __event = new(std::nothrow) ContextItem(e);
47
48         // Condition
49         int condNum = d.getSize(NULL, TRIG_RULE_KEY_CONDITION);
50         for (int j = 0; j < condNum; j++) {
51                 Json c;
52                 d.getAt(NULL, TRIG_RULE_KEY_CONDITION, j, &c);
53                 __condition.push_back(new(std::nothrow) ContextItem(c));
54         }
55
56         // Extra
57         Json extra;
58         d.get(NULL, _TRIG_RULE_KEY_EXTRA, &extra);
59         __extra = extra.str();
60
61         // Action
62         Json a;
63         d.get(NULL, TRIG_RULE_KEY_ACTION, &a);
64         __action = a.str();
65 }
66
67 Rule::~Rule()
68 {
69         // Release resources
70         delete __event;
71         for (auto it = __condition.begin(); it != __condition.end(); ++it) {
72                 delete *it;
73         }
74 }
75
76 int Rule::start(void)
77 {
78         // Subscribe event
79         int error = ContextMonitor::getInstance()->subscribe(id, __event->name, __event->option, this);
80         IF_FAIL_RETURN_TAG(error == ERR_NONE, error, _E, "Failed to start rule%d", id);
81
82         return error;
83 }
84
85 int Rule::stop(void)
86 {
87         // Unsubscribe event
88         int error = ContextMonitor::getInstance()->unsubscribe(id, __event->name, __event->option, this);
89         if (error == ERR_NOT_SUPPORTED) {
90                 _E("Stop rule%d (event not supported)");
91                 return ERR_NONE;
92         }
93         IF_FAIL_RETURN_TAG(error == ERR_NONE, error, _E, "Failed to stop rule%d", id);
94
95         return error;
96 }
97
98 bool Rule::__setConditionOptionBasedOnEvent(Json& option)
99 {
100         // Set condition option if it references event data
101         std::list<std::string> optionKeys;
102         option.getKeys(&optionKeys);
103
104         for (auto it = optionKeys.begin(); it != optionKeys.end(); ++it) {
105                 std::string optKey = (*it);
106
107                 std::string optVal;
108                 if (option.get(NULL, optKey.c_str(), &optVal)) {
109                         if (optVal.find("?") != 0) {
110                                 continue;
111                         }
112
113                         std::string eventKey = optVal.substr(1, optVal.length() - 1);
114
115                         std::string newStr;
116                         int new_val;
117                         if (__result.get(FACT_KEY_EVENT "." FACT_KEY_DATA, eventKey.c_str(), &newStr)) {
118                                 option.set(NULL, optKey.c_str(), newStr);
119                         } else if (__result.get(FACT_KEY_EVENT "." FACT_KEY_DATA, eventKey.c_str(), &new_val)) {
120                                 option.set(NULL, optKey.c_str(), new_val);
121                         } else {
122                                 _W("Failed to find '%s' in event data", eventKey.c_str());
123                                 return false;
124                         }
125                 }
126         }
127
128         return true;
129 }
130
131 void Rule::onEventReceived(std::string name, Json option, Json data)
132 {
133         if (__result != EMPTY_JSON_OBJECT) {
134                 __clearResult();
135         }
136
137         // Check if creator package is uninstalled
138         if (RuleManager::isUninstalledPackage(pkgId)) {
139                 _D("Creator(%s) of rule%d is uninstalled.", pkgId.c_str(), id);
140                 g_idle_add(__handleUninstalledRule, &pkgId);
141                 return;
142         }
143
144         _D("Rule%d received event data", id);
145
146         // Set event data
147         __result.set(FACT_KEY_EVENT, FACT_KEY_NAME, name);
148         __result.set(FACT_KEY_EVENT, FACT_KEY_OPTION, option);
149         __result.set(FACT_KEY_EVENT, FACT_KEY_DATA, data);
150
151         if (__condition.size() == 0) {
152                 __onContextDataPrepared();
153                 return;
154         }
155
156         IF_FAIL_VOID_TAG(RuleEvaluator::evaluateRule(__statement, __result), _E, "Event not matched");
157
158         // Request read conditions
159         for (auto it = __condition.begin(); it != __condition.end(); ++it) {
160                 Json condOption = (*it)->option.str();
161                 if (!__setConditionOptionBasedOnEvent(condOption)) { // condOption should be copy of original option.
162                         __clearResult();
163                         return;
164                 }
165
166                 int error = ContextMonitor::getInstance()->read((*it)->name.c_str(), condOption, this);
167                 IF_FAIL_VOID_TAG(error == ERR_NONE, _E, "Failed to read condition");
168         }
169
170         // TODO timer set
171 }
172
173 void Rule::onConditionReceived(std::string name, Json option, Json data)
174 {
175         _D("Rule%d received condition data", id);
176
177         // Set condition data
178         Json item;
179         item.set(NULL, FACT_KEY_NAME, name);
180         item.set(NULL, FACT_KEY_OPTION, option);
181         item.set(NULL, FACT_KEY_DATA, data);
182         __result.append(NULL, FACT_KEY_CONDITION, item);
183
184         if (__result.getSize(NULL, FACT_KEY_CONDITION) == (int) __condition.size()) {
185                 __onContextDataPrepared();
186         }
187 }
188
189 void Rule::__clearResult()
190 {
191         __result = EMPTY_JSON_OBJECT;
192         // TODO timer cancel
193 }
194
195 void Rule::__onContextDataPrepared(void)
196 {
197         if (RuleEvaluator::evaluateRule(__statement, __result)) {
198                 action_manager::triggerAction(__action, pkgId);
199         }
200         __clearResult();
201 }
202
203 gboolean Rule::__handleUninstalledRule(gpointer data)
204 {
205         std::string* pkgId = static_cast<std::string*>(data);
206         __ruleMgr->handleRuleOfUninstalledPackage(*pkgId);
207
208         return FALSE;
209 }