7fd11a73fdf12611c418b0e7378abd0f6dda08b2
[platform/core/context/context-provider.git] / src / app-stats / app_inactive_detector / InactiveDetectorStorage.cpp
1 /*
2  * Copyright (c) 2016 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 <sstream>
18 #include <ctime>
19 #include <string>
20 #include <memory>
21 #include <Types.h>
22 #include "InactiveDetector.h"
23 #include "InactiveDetectorStorage.h"
24 #include "InactiveDetectorStorageQueries.h"
25 #include "InactiveDetectorClassificator.h"
26 #include "AppInactiveDetectorTypes.h"
27
28 /*int ctx::InactiveDetectorStorage::create_table()
29 {
30         bool ret = __dbManager.createTable(0, WIFI_TABLE_NAME, WIFI_CREATE_TABLE_COLUMNS, NULL, NULL);
31         _D("Table Creation Request: %s", ret ? "SUCCESS" : "FAIL");
32         return ret;
33 }*/
34
35 // expected Json format example: {timeframe: 1; isActive: 0}
36 int ctx::InactiveDetectorStorage::read(const char *subject, ctx::Json filter)
37 {
38         std::string query;
39         query = __getQueryGetApps(subject, filter);
40
41         IF_FAIL_RETURN(!query.empty(), ERR_OPERATION_FAILED);
42
43         bool ret = __dbManager.execute(STR_EQ(subject, APP_INACTIVE_SUBJ_GET_APPS_INACTIVE) ?
44                         APP_INACTIVE_QUERY_ID_GET_APPS_INACTIVE : APP_INACTIVE_QUERY_ID_GET_APPS_ACTIVE,
45                         query.c_str(), this);
46
47         IF_FAIL_RETURN(ret, ERR_OPERATION_FAILED);
48
49         return ERR_NONE;
50 }
51
52 std::string ctx::InactiveDetectorStorage::__getQueryGetApps(const char *subject, ctx::Json filter)
53 {
54         double timeframe;
55         int isActive;
56
57         std::string query(GET_APP_INFO_INACTIVE_QUERY);
58         std::string placeholderTimeframe(APP_INACTIVE_DETECTOR_VALUE_PLACEHOLDER_TIMEFRAME);
59         std::string placeholderIsActive(APP_INACTIVE_DETECTOR_VALUE_PLACEHOLDER_CLUSTER);
60
61         filter.get(NULL, APP_INACTIVE_DETECTOR_DATA_TIMEFRAME, &timeframe);
62         filter.get(NULL, APP_INACTIVE_DETECTOR_DATA_ISACTIVE, &isActive);
63
64         std::stringstream timeframeStream;
65         timeframeStream << timeframe;
66
67         std::stringstream isActiveStream;
68         isActiveStream << isActive;
69
70         __injectParams(query, placeholderTimeframe, timeframeStream.str());
71         __injectParams(query, placeholderIsActive, isActiveStream.str());
72
73         return query;
74 }
75
76 std::string ctx::InactiveDetectorStorage::__getQueryUpdateApps(std::vector<AppInfo> *appsWithWeights)
77 {
78         std::string deleteQuery(DELETE_APP_ACTIVITY_CLASSIFIED_BY_TIMEFRAME);
79         std::string insertQuery(INSERT_APP_ACTIVITY_CLASSIFIED);
80         std::string placeholderTimeframe(APP_INACTIVE_DETECTOR_VALUE_PLACEHOLDER_TIMEFRAME);
81         std::string placeholderValues(APP_INACTIVE_DETECTOR_VALUE_PLACEHOLDER_VALUES);
82         std::string placeholderIsActive(APP_INACTIVE_DETECTOR_VALUE_PLACEHOLDER_CLUSTER);
83
84         std::stringstream timeframeStream;
85         timeframeStream << appsWithWeights->front().timeframe;
86
87         __injectParams(deleteQuery, placeholderTimeframe, timeframeStream.str());
88         __injectParams(insertQuery, placeholderValues, __getSubqueryFormValues(appsWithWeights));
89
90         std::stringstream result;
91         result << deleteQuery << insertQuery;
92         return result.str();
93 }
94
95 // foreach app_info id+cluster -> select for insert
96 std::string ctx::InactiveDetectorStorage::__getSubqueryFormValues(std::vector<AppInfo> *appsWithWeights)
97 {
98         std::stringstream selectElements;
99
100         for (auto row = appsWithWeights->begin(); row != appsWithWeights->end(); row++)
101         {
102                 //SELECT 1 as isActive, 1 as timeframe,  3964 as context_app_info_id
103                 std::stringstream selectElement;
104                 selectElement << " SELECT " << row->isActive << " as ";
105                 selectElement << APP_INACTIVE_DETECTOR_ACTIVITYCLASSIFIED_COLUMN_IS_ACTIVE;
106                 selectElement << ", " << row->timeframe << " as ";
107                 selectElement << APP_INACTIVE_DETECTOR_ACTIVITYCLASSIFIED_COLUMN_TIMEFRAME;
108                 selectElement << ", " << row->id << " as ";
109                 selectElement << APP_INACTIVE_DETECTOR_ACTIVITYCLASSIFIED_COLUMN_CONTEXT_APP_INFO_ID;
110
111                 if ((row != appsWithWeights->end()) && (row == --appsWithWeights->end()))
112                         selectElement << " UNION ";
113
114                 selectElements << selectElement;
115         }
116
117         return selectElements.str();
118 }
119
120 void ctx::InactiveDetectorStorage::__jsonToObject(std::vector<Json>& records, std::vector<AppInfo> *appsWithWeights, bool resultMode)
121 {
122         for (auto row = records.begin(); row != records.end(); row++) {
123                 AppInfo appWithWeight;
124                 if (resultMode) {
125                         row->get(NULL, APP_INACTIVE_DETECTOR_APPINFO_COLUMN_PACKAGE_NAME, &appWithWeight.packageName);
126                         row->get(NULL, APP_INACTIVE_DETECTOR_APPINFO_COLUMN_IS_NODISPLAY, &appWithWeight.isNodisplay);
127                         row->get(NULL, APP_INACTIVE_DETECTOR_APPINFO_COLUMN_IS_ENABLED, &appWithWeight.isEnabled);
128                         row->get(NULL, APP_INACTIVE_DETECTOR_APPINFO_COLUMN_IS_ATBOOT, &appWithWeight.isAtBoot);
129                         row->get(NULL, APP_INACTIVE_DETECTOR_APPINFO_COLUMN_IS_PRELOADED, &appWithWeight.isPreloaded);
130                         row->get(NULL, APP_INACTIVE_DETECTOR_VIRTUAL_COLUMN_WEIGHT, &appWithWeight.weight);
131                 } else {
132                         row->get(NULL, APP_INACTIVE_DETECTOR_APPINFO_COLUMN_ID, &appWithWeight.id);
133                         row->get(NULL, APP_INACTIVE_DETECTOR_APPINFO_COLUMN_TIMESTAMP, &appWithWeight.timestamp);
134                         row->get(NULL, APP_INACTIVE_DETECTOR_VIRTUAL_COLUMN_WEIGHT, &appWithWeight.weight);
135                         row->get(NULL, APP_INACTIVE_DETECTOR_ACTIVITYCLASSIFIED_COLUMN_IS_ACTIVE, &appWithWeight.isActive);
136                 }
137
138                 appsWithWeights->push_back(appWithWeight);
139         }
140 }
141
142 void ctx::InactiveDetectorStorage::onExecuted(unsigned int queryId, int error, std::vector<Json>& records)
143 {
144         if (error != ERR_NONE) {
145                 _E("queryId:%d, error:%d", queryId, error);
146                 return;
147         }
148
149         std::vector<AppInfo> *appsWithWeights = NULL;
150         if (queryId == APP_INACTIVE_QUERY_ID_GET_APPS_INACTIVE || queryId == APP_INACTIVE_QUERY_ID_GET_APPS_ACTIVE) {
151                 __jsonToObject(records, appsWithWeights, TRUE);
152         } else if (queryId == APP_INACTIVE_QUERY_ID_GET_APPS_WEIGHT) {
153                 __jsonToObject(records, appsWithWeights, FALSE);
154
155                 if (appsWithWeights->size() > 0) {
156                         InactiveDetectorClassificator inactDetClassificator;
157                         int err = inactDetClassificator.classify(appsWithWeights);
158
159                         if (err == ERR_NONE) {
160                                 std::string query;
161                                 query = __getQueryUpdateApps(appsWithWeights);
162                                 bool ret = __dbManager.execute(APP_INACTIVE_QUERY_ID_UPDATE_CLUSTERS, query.c_str(), this);
163                                 _D("load visits execute query result: %s", ret ? "SUCCESS" : "FAIL");
164                         } else {
165                                 _E("classification queryId:%d, error:%d", queryId, err);
166                         }
167                 }
168         } else if (queryId == APP_INACTIVE_QUERY_ID_UPDATE_CLUSTERS) {
169                 _D("UPDATE_CLUSTERS execute query id: %d", queryId);
170         } else {
171                 _E("unknown queryId:%d", queryId);
172         }
173 }
174
175 void ctx::InactiveDetectorStorage::__injectParams(std::string& str, const std::string& from, const std::string& to)
176 {
177         if (from.empty())
178                 return;
179
180         size_t startPos = 0;
181         while((startPos = str.find(from, startPos)) != std::string::npos) {
182                 str.replace(startPos, from.length(), to);
183                 startPos += to.length();
184         }
185 }
186
187 // normalzie weights
188 int ctx::InactiveDetectorStorage::updateRanks()
189 {
190         return ERR_NONE;
191 }
192
193 int ctx::InactiveDetectorStorage::getAppsInfoWithWeights(double timestampFrom)
194 {
195         std::stringstream timestampStream;
196         timestampStream << timestampFrom;
197         std::string timestampStr = timestampStream.str();
198
199         std::string query(GET_APP_INFO_W_WEIGHT_QUERY);
200         std::string placeholder(APP_INACTIVE_DETECTOR_VALUE_PLACEHOLDER_TIMESTAMP);
201
202         __injectParams(query, placeholder, timestampStr);
203
204         bool ret = __dbManager.execute(APP_INACTIVE_QUERY_ID_GET_APPS_WEIGHT, query.c_str(), this);
205         _D("load visits execute query result: %s", ret ? "SUCCESS" : "FAIL");
206
207         return ERR_NONE ;
208 }