1 // Copyright (c) 2013 Intel Corporation. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "xwalk/application/common/application_storage_impl.h"
10 #include "base/file_util.h"
11 #include "base/strings/stringprintf.h"
12 #include "base/strings/string_split.h"
13 #include "base/strings/string_util.h"
14 #include "base/json/json_file_value_serializer.h"
15 #include "base/json/json_string_value_serializer.h"
16 #include "sql/statement.h"
17 #include "sql/transaction.h"
18 #include "xwalk/application/common/application_storage.h"
19 #include "xwalk/application/common/application_storage_constants.h"
21 namespace db_fields = xwalk::application_storage_constants;
23 namespace application {
25 const base::FilePath::CharType ApplicationStorageImpl::kDBFileName[] =
26 FILE_PATH_LITERAL("applications.db");
28 const char kPermissionSeparator = '^';
30 // Switching the JSON format DB(version 0) to SQLite backend version 1,
31 // should migrate all data from JSON DB to SQLite applications table.
32 static const int kVersionNumber = 1;
36 const std::string StoredPermissionStr[] = {
42 std::string ToString(StoredPermission permission) {
43 if (permission == UNDEFINED_STORED_PERM)
44 return std::string("");
45 return StoredPermissionStr[permission];
48 StoredPermission ToPermission(const std::string& str) {
50 for (i = 0; i < UNDEFINED_STORED_PERM; ++i) {
51 if (str == StoredPermissionStr[i])
54 return static_cast<StoredPermission>(i);
57 inline const base::FilePath GetDBPath(const base::FilePath& path) {
58 return path.Append(ApplicationStorageImpl::kDBFileName);
61 // Initializes the applications table, returning true on success.
62 bool InitApplicationsTable(sql::Connection* db) {
63 sql::Transaction transaction(db);
65 // The table is named "applications", the primary key is "id".
66 if (!db->DoesTableExist(db_fields::kAppTableName)) {
67 if (!db->Execute(db_fields::kCreateAppTableOp))
70 return transaction.Commit();
73 // Permissions are stored like "bluetooth^ALLOW;calendar^DENY;contacts^ALLOW"
74 std::string ToString(StoredPermissionMap permissions) {
76 StoredPermissionMap::iterator iter;
77 for (iter = permissions.begin(); iter != permissions.end(); ++iter) {
80 str += (iter->first + kPermissionSeparator + ToString(iter->second));
85 StoredPermissionMap ToPermissionMap(const std::string& str) {
86 StoredPermissionMap map;
87 std::vector<std::string> vec;
88 base::SplitString(str, ';', &vec);
90 for (std::vector<std::string>::iterator iter = vec.begin();
91 iter != vec.end(); ++iter) {
92 std::vector<std::string> perm_item;
93 base::SplitString(*iter, kPermissionSeparator, &perm_item);
94 if (perm_item.size() != 2) {
95 LOG(ERROR) << "Permission format error! Corrupted database?";
99 map[perm_item[0]] = ToPermission(perm_item[1]);
105 bool InitPermissionsTable(sql::Connection* db) {
106 sql::Transaction transaction(db);
108 if (!db->DoesTableExist(db_fields::kPermissionTableName)) {
109 if (!db->Execute(db_fields::kCreatePermissionTableOp))
112 return transaction.Commit();
117 ApplicationStorageImpl::ApplicationStorageImpl(const base::FilePath& path)
119 db_initialized_(false) {
120 // Ensure the parent directory for database file is created before reading
122 if (!base::PathExists(path) && !base::CreateDirectory(path))
126 bool ApplicationStorageImpl::UpgradeToVersion1(const base::FilePath& v0_file) {
127 JSONFileValueSerializer serializer(v0_file);
130 base::Value* old_db = serializer.Deserialize(&error_code, &error);
132 LOG(ERROR) << "Unable to read applications information from JSON DB, "
133 "the error message is: "
138 scoped_ptr<base::DictionaryValue> value;
139 for (base::DictionaryValue::Iterator it(
140 *static_cast<base::DictionaryValue*>(old_db));
141 !it.IsAtEnd(); it.Advance()) {
142 value.reset(static_cast<base::DictionaryValue*>(it.value().DeepCopy()));
143 base::DictionaryValue* manifest;
144 value->GetDictionary("manifest", &manifest);
146 value->GetString("path", &path);
148 scoped_refptr<ApplicationData> application =
149 ApplicationData::Create(base::FilePath::FromUTF8Unsafe(path),
155 LOG(ERROR) << "Unable to migrate the information to Version 1: " << error;
160 value->GetDouble("install_time", &install_time);
161 if (!AddApplication(application, base::Time::FromDoubleT(install_time)))
164 meta_table_.SetVersionNumber(1);
169 ApplicationStorageImpl::~ApplicationStorageImpl() {
172 bool ApplicationStorageImpl::Init() {
173 bool does_db_exist = base::PathExists(GetDBPath(data_path_));
174 scoped_ptr<sql::Connection> sqlite_db(new sql::Connection);
175 if (!sqlite_db->Open(GetDBPath(data_path_))) {
176 LOG(ERROR) << "Unable to open applications DB.";
179 sqlite_db->Preload();
181 if (!meta_table_.Init(sqlite_db.get(), kVersionNumber, kVersionNumber) ||
182 meta_table_.GetVersionNumber() != kVersionNumber) {
183 LOG(ERROR) << "Unable to init the META table.";
187 if (!InitApplicationsTable(sqlite_db.get())) {
188 LOG(ERROR) << "Unable to open applications table.";
192 if (!InitPermissionsTable(sqlite_db.get())) {
193 LOG(ERROR) << "Unable to open registered permissions table.";
197 if (!sqlite_db->Execute("PRAGMA foreign_keys=ON")) {
198 LOG(ERROR) << "Unable to enforce foreign key contraints.";
202 sqlite_db_.reset(sqlite_db.release());
204 db_initialized_ = (sqlite_db_ && sqlite_db_->is_open());
206 base::FilePath v0_file = data_path_.Append(
207 FILE_PATH_LITERAL("applications_db"));
208 if (base::PathExists(v0_file) &&
210 if (!UpgradeToVersion1(v0_file)) {
211 LOG(ERROR) << "Unable to migrate database from JSON format to SQLite.";
214 // After migrated to SQLite, delete the old JSON DB file is safe,
215 // since all information has been migrated and it will not be used anymore.
216 if (!base::DeleteFile(v0_file, false)) {
217 LOG(ERROR) << "Unalbe to delete old JSON DB file.";
222 db_initialized_ = true;
224 return db_initialized_;
227 scoped_refptr<ApplicationData> ApplicationStorageImpl::ExtractApplicationData(
228 const sql::Statement& smt) {
229 std::string id = smt.ColumnString(0);
232 std::string manifest_str = smt.ColumnString(1);
233 JSONStringValueSerializer serializer(&manifest_str);
234 std::string error_msg;
235 scoped_ptr<base::DictionaryValue> manifest(
236 static_cast<base::DictionaryValue*>(
237 serializer.Deserialize(&error_code, &error_msg)));
240 LOG(ERROR) << "An error occured when deserializing the manifest, "
241 "the error message is: "
245 std::string path = smt.ColumnString(2);
246 double install_time = smt.ColumnDouble(3);
249 scoped_refptr<ApplicationData> app_data =
250 ApplicationData::Create(
251 base::FilePath::FromUTF8Unsafe(path),
257 LOG(ERROR) << "Load appliation error: " << error;
261 app_data->install_time_ = base::Time::FromDoubleT(install_time);
263 app_data->permission_map_ = ToPermissionMap(smt.ColumnString(5));
268 scoped_refptr<ApplicationData> ApplicationStorageImpl::GetApplicationData(
269 const std::string& app_id) {
270 if (!db_initialized_) {
271 LOG(ERROR) << "The database hasn't been initilized.";
275 sql::Statement smt(sqlite_db_->GetUniqueStatement(
276 db_fields::kGetRowFromAppTableOp));
277 smt.BindString(0, app_id);
284 return ExtractApplicationData(smt);
287 bool ApplicationStorageImpl::GetInstalledApplications(
288 ApplicationData::ApplicationDataMap& applications) { // NOLINT
289 if (!db_initialized_) {
290 LOG(ERROR) << "The database hasn't been initilized.";
294 sql::Statement smt(sqlite_db_->GetUniqueStatement(
295 db_fields::kGetAllRowsFromAppTableOp));
300 scoped_refptr<ApplicationData> data = ExtractApplicationData(smt);
302 LOG(ERROR) << "Failed to obtain ApplicationData from SQL query";
306 std::pair<std::string, scoped_refptr<ApplicationData> >(
313 bool ApplicationStorageImpl::GetInstalledApplicationIDs(
314 std::vector<std::string>& app_ids) { // NOLINT
315 if (!db_initialized_) {
316 LOG(ERROR) << "The database hasn't been initilized.";
320 sql::Statement smt(sqlite_db_->GetUniqueStatement(
321 db_fields::kGetAllIDsFromAppTableOp));
326 const std::string& id = smt.ColumnString(0);
327 if (!ApplicationData::IsIDValid(id)) {
328 LOG(ERROR) << "Failed to obtain Application ID from SQL query";
331 app_ids.push_back(id);
337 bool ApplicationStorageImpl::AddApplication(const ApplicationData* application,
338 const base::Time& install_time) {
339 if (!db_initialized_) {
340 LOG(ERROR) << "The database hasn't been initilized.";
344 return (SetApplicationValue(
345 application, install_time, db_fields::kSetApplicationWithBindOp) &&
346 SetPermissions(application->ID(), application->permission_map_));
349 bool ApplicationStorageImpl::UpdateApplication(
350 ApplicationData* application, const base::Time& install_time) {
351 if (!db_initialized_) {
352 LOG(ERROR) << "The database hasn't been initilized.";
356 if (SetApplicationValue(
357 application, install_time, db_fields::kUpdateApplicationWithBindOp) &&
358 UpdatePermissions(application->ID(), application->permission_map_)) {
365 bool ApplicationStorageImpl::RemoveApplication(const std::string& id) {
366 if (!db_initialized_) {
367 LOG(ERROR) << "The database hasn't been initilized.";
371 sql::Transaction transaction(sqlite_db_.get());
372 if (!transaction.Begin())
375 sql::Statement smt(sqlite_db_->GetUniqueStatement(
376 db_fields::kDeleteApplicationWithBindOp));
377 smt.BindString(0, id);
379 LOG(ERROR) << "Could not delete application "
380 "information from DB.";
384 return transaction.Commit();
387 bool ApplicationStorageImpl::ContainsApplication(const std::string& app_id) {
388 return GetApplicationData(app_id) != NULL;
391 bool ApplicationStorageImpl::SetApplicationValue(
392 const ApplicationData* application,
393 const base::Time& install_time,
394 const std::string& operation) {
396 LOG(ERROR) << "A value is needed when inserting/updating in DB.";
400 std::string manifest;
401 JSONStringValueSerializer serializer(&manifest);
402 if (!serializer.Serialize(*(application->GetManifest()->value()))) {
403 LOG(ERROR) << "An error occured when serializing the manifest value.";
407 sql::Transaction transaction(sqlite_db_.get());
408 if (!transaction.Begin())
411 sql::Statement smt(sqlite_db_->GetUniqueStatement(operation.c_str()));
412 if (!smt.is_valid()) {
413 LOG(ERROR) << "Unable to insert/update application info in DB.";
416 smt.BindString(0, manifest);
417 smt.BindString(1, application->Path().AsUTF8Unsafe());
418 smt.BindDouble(2, install_time.ToDoubleT());
419 smt.BindString(3, application->ID());
421 LOG(ERROR) << "An error occured when inserting/updating "
422 "application info in DB.";
426 return transaction.Commit();
429 bool ApplicationStorageImpl::SetPermissions(const std::string& id,
430 const StoredPermissionMap& permissions) {
431 if (!db_initialized_) {
432 LOG(ERROR) << "Database is not initialized.";
435 return SetPermissionsValue(id, permissions,
436 db_fields::kInsertPermissionsWithBindOp);
439 bool ApplicationStorageImpl::UpdatePermissions(const std::string& id,
440 const StoredPermissionMap& permissions) {
441 if (!db_initialized_) {
442 LOG(ERROR) << "Database is not initialized.";
445 if (permissions.empty())
446 return RevokePermissions(id);
448 return SetPermissionsValue(id, permissions,
449 db_fields::kUpdatePermissionsWithBindOp);
452 bool ApplicationStorageImpl::RevokePermissions(const std::string& id) {
453 sql::Transaction transaction(sqlite_db_.get());
454 if (!transaction.Begin())
457 sql::Statement statement(sqlite_db_->GetUniqueStatement(
458 db_fields::kDeletePermissionsWithBindOp));
459 statement.BindString(0, id);
461 if (!statement.Run()) {
463 "An error occurred while removing permissions.";
466 return transaction.Commit();
469 bool ApplicationStorageImpl::SetPermissionsValue(
470 const std::string& id,
471 const StoredPermissionMap& permissions,
472 const std::string& operation) {
473 sql::Transaction transaction(sqlite_db_.get());
474 std::string permission_str = ToString(permissions);
476 if (!transaction.Begin())
479 sql::Statement statement(sqlite_db_->GetUniqueStatement(
481 statement.BindString(0, permission_str);
482 statement.BindString(1, id);
483 if (!statement.Run()) {
485 "An error occurred while inserting permissions.";
488 return transaction.Commit();
491 } // namespace application