Specifiy that this supports M47
[platform/framework/web/crosswalk-tizen.git] / common / app_db.cc
1 /*
2  * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
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 "common/app_db.h"
18
19 //  #define USE_APP_PREFERENCE;
20 #ifdef USE_APP_PREFERENCE
21 #include <app_preference.h>
22 #else
23 #include <app.h>
24 #include <sqlite3.h>
25 #include <unistd.h>
26 #include <fstream>
27 #endif
28
29 #include <memory>
30
31 #include "common/logger.h"
32 #include "common/string_utils.h"
33 #include "common/file_utils.h"
34 #include "common/picojson.h"
35
36 #ifndef USE_APP_PREFERENCE
37 #include "common/app_db_sqlite.h"
38 #endif
39
40 namespace common {
41
42 namespace {
43 #ifdef USE_APP_PREFERENCE
44 const char* kSectionPrefix = "_SECT_";
45 const char* kSectionSuffix = "_SECT_";
46 #else
47 const char* kCreateDbQuery = "CREATE TABLE IF NOT EXISTS appdb ("
48                              "section TEXT, "
49                              "key TEXT, "
50                              "value TEXT,"
51                              "PRIMARY KEY(section, key));";
52 #endif
53 }  // namespace
54
55 #ifdef USE_APP_PREFERENCE
56
57 class PreferenceAppDB : public AppDB {
58  public:
59   PreferenceAppDB();
60   virtual bool HasKey(const std::string& section,
61                       const std::string& key) const;
62   virtual std::string Get(const std::string& section,
63                           const std::string& key) const;
64   virtual void Set(const std::string& section,
65                    const std::string& key,
66                    const std::string& value);
67   virtual void GetKeys(const std::string& section,
68                        std::list<std::string>* keys) const;
69   virtual void Remove(const std::string& section,
70                       const std::string& key);
71 };
72
73 PreferenceAppDB::PreferenceAppDB() {
74 }
75
76 bool PreferenceAppDB::HasKey(const std::string& section,
77                              const std::string& key) const {
78   bool existed = false;
79   std::string combined_key = kSectionPrefix + section + kSectionSuffix + key;
80   return preference_is_existing(combined_key.c_str(), &existed) == 0 && existed;
81 }
82
83 std::string PreferenceAppDB::Get(const std::string& section,
84                                  const std::string& key) const {
85   std::string combined_key = kSectionPrefix + section + kSectionSuffix + key;
86   char* value;
87   if (preference_get_string(combined_key.c_str(), &value) == 0) {
88     std::unique_ptr<char, decltype(std::free)*> ptr {value, std::free};
89     return std::string(value);
90   }
91   return std::string();
92 }
93
94 void PreferenceAppDB::Set(const std::string& section,
95                           const std::string& key,
96                           const std::string& value) {
97   std::string combined_key = kSectionPrefix + section + kSectionSuffix + key;
98   preference_set_string(combined_key.c_str(), value.c_str());
99 }
100
101 void PreferenceAppDB::GetKeys(const std::string& section,
102                               std::list<std::string>* keys) const {
103   auto callback = [](const char* key, void *user_data) {
104     auto list = static_cast<std::list<std::string>*>(user_data);
105     if (utils::StartsWith(key, list->front())) {
106       list->push_back(key+list->front().size());
107     }
108     return true;
109   };
110   std::string key_prefix = kSectionPrefix + section + kSectionSuffix;
111   keys->push_front(key_prefix);
112   preference_foreach_item(callback, keys);
113   keys->pop_front();
114 }
115
116 void PreferenceAppDB::Remove(const std::string& section,
117                              const std::string& key) {
118   std::string combined_key = kSectionPrefix + section + kSectionSuffix + key;
119   preference_remove(combined_key.c_str());
120 }
121
122 #else  // end of USE_APP_PREFERENCE
123
124 SqliteDB::SqliteDB(const std::string& app_data_path)
125     : app_data_path_(app_data_path),
126       sqldb_(NULL) {
127   if (app_data_path_.empty()) {
128     std::unique_ptr<char, decltype(std::free)*>
129     path {app_get_data_path(), std::free};
130     if (path.get() != NULL)
131       app_data_path_ = path.get();
132   }
133   Initialize();
134 }
135
136 SqliteDB::~SqliteDB() {
137   if (sqldb_ != NULL) {
138     sqlite3_close(sqldb_);
139     sqldb_ = NULL;
140   }
141 }
142
143 void SqliteDB::MigrationAppdb() {
144   // file check
145   std::string migration_path = app_data_path_ + ".runtime.migration";
146   if (!common::utils::Exists(migration_path)) {
147     return;
148   } else {
149     LOGGER(DEBUG) << "Migration file found : " << migration_path;
150   }
151
152   std::ifstream migration_file(migration_path);
153   if (!migration_file.is_open()) {
154     LOGGER(ERROR) << "Fail to open file";
155     return;
156   }
157   picojson::value v;
158   std::string err;
159   err = picojson::parse(v, migration_file);
160   if (!err.empty()) {
161     LOGGER(ERROR) << "Fail to parse file :" << err;
162     return;
163   }
164
165   LOGGER(DEBUG) << "Start to get list data";
166
167   picojson::array data_list;
168
169   if (!v.get("preference").is<picojson::null>()) {
170     picojson::array preference_list
171       = v.get("preference").get<picojson::array>();
172     data_list.insert(data_list.end(),
173                      preference_list.begin(),
174                      preference_list.end());
175   }
176   if (!v.get("certificate").is<picojson::null>()) {
177     picojson::array certificate_list
178       = v.get("certificate").get<picojson::array>();
179     data_list.insert(data_list.end(),
180                      certificate_list.begin(),
181                      certificate_list.end());
182   }
183   if (!v.get("security_origin").is<picojson::null>()) {
184     picojson::array security_origin_list
185       = v.get("security_origin").get<picojson::array>();
186     data_list.insert(data_list.end(),
187                      security_origin_list.begin(),
188                      security_origin_list.end());
189   }
190
191   for (auto it = data_list.begin(); it != data_list.end(); ++it) {
192     if (!it->is<picojson::object>()) continue;
193     std::string section = it->get("section").to_str();
194     std::string key = it->get("key").to_str();
195     std::string value = it->get("value").to_str();
196
197     LOGGER(DEBUG) << "INPUT[" << section << "][" << key << "][" << value << "]";
198     Set(section, key, value);
199   }
200
201   LOGGER(DEBUG) << "Migration complete";
202
203   if (0 != remove(migration_path.c_str())) {
204     LOGGER(ERROR) << "Fail to remove migration file";
205   }
206 }
207
208
209 void SqliteDB::Initialize() {
210   if (app_data_path_.empty()) {
211     LOGGER(ERROR) << "app data path was empty";
212     return;
213   }
214   std::string db_path = app_data_path_ + "/.appdb.db";
215   int ret = sqlite3_open(db_path.c_str(), &sqldb_);
216   if (ret != SQLITE_OK) {
217     LOGGER(ERROR) << "Fail to open app db :" << sqlite3_errmsg(sqldb_);
218     sqldb_ = NULL;
219     return;
220   }
221   sqlite3_busy_handler(sqldb_, [](void *, int count) {
222     if (count < 5) {
223       LOGGER(ERROR) << "App db was busy, Wait the lock count(" << count << ")";
224       usleep(100000*(count+1));
225       return 1;
226     } else {
227       LOGGER(ERROR) << "App db was busy, Fail to access";
228       return 0;
229     }
230   }, NULL);
231
232   char *errmsg = NULL;
233   ret = sqlite3_exec(sqldb_, kCreateDbQuery, NULL, NULL, &errmsg);
234   if (ret != SQLITE_OK) {
235     LOGGER(ERROR) << "Error to create appdb : " << (errmsg ? errmsg : "");
236     if (errmsg)
237       sqlite3_free(errmsg);
238   }
239   MigrationAppdb();
240 }
241
242 bool SqliteDB::HasKey(const std::string& section,
243                       const std::string& key) const {
244   char *buffer = NULL;
245   sqlite3_stmt *stmt = NULL;
246   bool result = false;
247
248   int ret = 0;
249   buffer = sqlite3_mprintf(
250       "select count(*) from appdb where section = %Q and key = %Q",
251       section.c_str(),
252       key.c_str());
253   if (buffer == NULL) {
254     LOGGER(ERROR) << "error to make query";
255     return false;
256   }
257
258   std::unique_ptr<char, decltype(sqlite3_free)*>
259       scoped_data {buffer, sqlite3_free};
260
261   ret = sqlite3_prepare(sqldb_, buffer, strlen(buffer), &stmt, NULL);
262   if (ret != SQLITE_OK) {
263     LOGGER(ERROR) << "Fail to prepare query : " << sqlite3_errmsg(sqldb_);
264     return false;
265   }
266
267   ret = sqlite3_step(stmt);
268   if (ret == SQLITE_ROW) {
269     int value = sqlite3_column_int(stmt, 0);
270     result = value > 0;
271   }
272
273   sqlite3_finalize(stmt);
274   return result;
275 }
276
277 std::string SqliteDB::Get(const std::string& section,
278                           const std::string& key) const {
279   char *buffer = NULL;
280   sqlite3_stmt *stmt = NULL;
281   std::string result;
282
283   int ret = 0;
284   buffer = sqlite3_mprintf(
285       "select value from appdb where section = %Q and key = %Q",
286       section.c_str(),
287       key.c_str());
288   if (buffer == NULL) {
289     LOGGER(ERROR) << "error to make query";
290     return result;
291   }
292
293   std::unique_ptr<char, decltype(sqlite3_free)*>
294       scoped_data {buffer, sqlite3_free};
295
296   ret = sqlite3_prepare(sqldb_, buffer, strlen(buffer), &stmt, NULL);
297   if (ret != SQLITE_OK) {
298     LOGGER(ERROR) << "Fail to prepare query : " << sqlite3_errmsg(sqldb_);
299     return result;
300   }
301
302   ret = sqlite3_step(stmt);
303   if (ret == SQLITE_ROW) {
304     result = std::string(
305         reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0)));
306   }
307
308   sqlite3_finalize(stmt);
309   return result;
310 }
311
312 void SqliteDB::Set(const std::string& section,
313                    const std::string& key,
314                    const std::string& value) {
315   char *buffer = NULL;
316   sqlite3_stmt *stmt = NULL;
317
318   int ret = 0;
319   buffer = sqlite3_mprintf(
320       "replace into appdb (section, key, value) values (?, ?, ?);");
321   if (buffer == NULL) {
322     LOGGER(ERROR) << "error to make query";
323     return;
324   }
325
326   std::unique_ptr<char, decltype(sqlite3_free)*>
327       scoped_data {buffer, sqlite3_free};
328
329   ret = sqlite3_prepare(sqldb_, buffer, strlen(buffer), &stmt, NULL);
330   if (ret != SQLITE_OK) {
331     LOGGER(ERROR) << "Fail to prepare query : " << sqlite3_errmsg(sqldb_);
332     return;
333   }
334
335   std::unique_ptr<sqlite3_stmt, decltype(sqlite3_finalize)*>
336       scoped_stmt {stmt, sqlite3_finalize};
337
338   ret = sqlite3_bind_text(stmt,
339                           1,
340                           section.c_str(),
341                           section.length(),
342                           SQLITE_STATIC);
343   if (ret != SQLITE_OK) {
344     LOGGER(ERROR) << "Fail to prepare query bind argument : "
345                   << sqlite3_errmsg(sqldb_);
346     return;
347   }
348   ret = sqlite3_bind_text(stmt,
349                           2,
350                           key.c_str(),
351                           key.length(),
352                           SQLITE_STATIC);
353   if (ret != SQLITE_OK) {
354     LOGGER(ERROR) << "Fail to prepare query bind argument : "
355                   << sqlite3_errmsg(sqldb_);
356     return;
357   }
358   ret = sqlite3_bind_text(stmt,
359                           3,
360                           value.c_str(),
361                           value.length(),
362                           SQLITE_STATIC);
363   if (ret != SQLITE_OK) {
364     LOGGER(ERROR) << "Fail to prepare query bind argument : "
365                   << sqlite3_errmsg(sqldb_);
366     return;
367   }
368   ret = sqlite3_step(stmt);
369   if (ret != SQLITE_DONE) {
370     LOGGER(ERROR) << "Fail to insert data : " << sqlite3_errmsg(sqldb_);
371   }
372 }
373
374 void SqliteDB::Remove(const std::string& section,
375                       const std::string& key) {
376   char *buffer = NULL;
377
378   buffer = sqlite3_mprintf(
379       "delete from appdb where section = %Q and key = %Q",
380       section.c_str(),
381       key.c_str());
382
383   if (buffer == NULL) {
384     LOGGER(ERROR) << "error to make query";
385     return;
386   }
387
388   std::unique_ptr<char, decltype(sqlite3_free)*>
389       scoped_data {buffer, sqlite3_free};
390
391   char *errmsg = NULL;
392   int ret = sqlite3_exec(sqldb_, buffer, NULL, NULL, &errmsg);
393   if (ret != SQLITE_OK) {
394     LOGGER(ERROR) << "Error to delete value : " << (errmsg ? errmsg : "");
395     if (errmsg)
396       sqlite3_free(errmsg);
397   }
398 }
399
400 void SqliteDB::GetKeys(const std::string& section,
401                        std::list<std::string>* keys) const {
402   char *buffer = NULL;
403   sqlite3_stmt *stmt = NULL;
404
405   int ret = 0;
406   buffer = sqlite3_mprintf(
407       "select key from appdb where section = %Q",
408       section.c_str());
409   if (buffer == NULL) {
410     LOGGER(ERROR) << "error to make query";
411     return;
412   }
413
414   std::unique_ptr<char, decltype(sqlite3_free)*>
415       scoped_data {buffer, sqlite3_free};
416
417   ret = sqlite3_prepare(sqldb_, buffer, strlen(buffer), &stmt, NULL);
418   if (ret != SQLITE_OK) {
419     LOGGER(ERROR) << "Fail to prepare query : " << sqlite3_errmsg(sqldb_);
420     return;
421   }
422
423   ret = sqlite3_step(stmt);
424   while (ret == SQLITE_ROW) {
425     const char* value =
426         reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0));
427     keys->push_back(std::string(value));
428     ret = sqlite3_step(stmt);
429   }
430
431   sqlite3_finalize(stmt);
432   return;
433 }
434
435 #endif  // end of else
436
437 AppDB* AppDB::GetInstance() {
438 #ifdef USE_APP_PREFERENCE
439   static PreferenceAppDB instance;
440 #else
441   static SqliteDB instance;
442 #endif
443   return &instance;
444 }
445
446 }  // namespace common