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"
20 #include "xwalk/application/common/id_util.h"
22 namespace db_fields = xwalk::application_storage_constants;
24 namespace application {
26 const base::FilePath::CharType ApplicationStorageImpl::kDBFileName[] =
27 FILE_PATH_LITERAL("applications.db");
29 const char kPermissionSeparator = '^';
31 // Switching the JSON format DB(version 0) to SQLite backend version 1,
32 // should migrate all data from JSON DB to SQLite applications table.
33 static const int kVersionNumber = 1;
37 const std::string StoredPermissionStr[] = {
43 std::string ToString(StoredPermission permission) {
44 if (permission == UNDEFINED_STORED_PERM)
45 return std::string("");
46 return StoredPermissionStr[permission];
49 StoredPermission ToPermission(const std::string& str) {
51 for (i = 0; i < UNDEFINED_STORED_PERM; ++i) {
52 if (str == StoredPermissionStr[i])
55 return static_cast<StoredPermission>(i);
58 inline const base::FilePath GetDBPath(const base::FilePath& path) {
59 return path.Append(ApplicationStorageImpl::kDBFileName);
62 // Initializes the applications table, returning true on success.
63 bool InitApplicationsTable(sql::Connection* db) {
64 sql::Transaction transaction(db);
66 // The table is named "applications", the primary key is "id".
67 if (!db->DoesTableExist(db_fields::kAppTableName)) {
68 if (!db->Execute(db_fields::kCreateAppTableOp))
71 return transaction.Commit();
74 // Permissions are stored like "bluetooth^ALLOW;calendar^DENY;contacts^ALLOW"
75 std::string ToString(StoredPermissionMap permissions) {
77 StoredPermissionMap::iterator iter;
78 for (iter = permissions.begin(); iter != permissions.end(); ++iter) {
81 str += (iter->first + kPermissionSeparator + ToString(iter->second));
86 StoredPermissionMap ToPermissionMap(const std::string& str) {
87 StoredPermissionMap map;
88 std::vector<std::string> vec;
89 base::SplitString(str, ';', &vec);
91 for (std::vector<std::string>::iterator iter = vec.begin();
92 iter != vec.end(); ++iter) {
93 std::vector<std::string> perm_item;
94 base::SplitString(*iter, kPermissionSeparator, &perm_item);
95 if (perm_item.size() != 2) {
96 LOG(ERROR) << "Permission format error! Corrupted database?";
100 map[perm_item[0]] = ToPermission(perm_item[1]);
106 bool InitPermissionsTable(sql::Connection* db) {
107 sql::Transaction transaction(db);
109 if (!db->DoesTableExist(db_fields::kPermissionTableName)) {
110 if (!db->Execute(db_fields::kCreatePermissionTableOp))
113 return transaction.Commit();
118 ApplicationStorageImpl::ApplicationStorageImpl(const base::FilePath& path)
120 db_initialized_(false) {
121 // Ensure the parent directory for database file is created before reading
123 if (!base::PathExists(path) && !base::CreateDirectory(path))
127 bool ApplicationStorageImpl::UpgradeToVersion1(const base::FilePath& v0_file) {
128 JSONFileValueSerializer serializer(v0_file);
131 base::Value* old_db = serializer.Deserialize(&error_code, &error);
133 LOG(ERROR) << "Unable to read applications information from JSON DB, "
134 "the error message is: "
139 scoped_ptr<base::DictionaryValue> value;
140 for (base::DictionaryValue::Iterator it(
141 *static_cast<base::DictionaryValue*>(old_db));
142 !it.IsAtEnd(); it.Advance()) {
143 value.reset(static_cast<base::DictionaryValue*>(it.value().DeepCopy()));
144 base::DictionaryValue* manifest;
145 value->GetDictionary("manifest", &manifest);
147 value->GetString("path", &path);
149 scoped_refptr<ApplicationData> application =
150 ApplicationData::Create(base::FilePath::FromUTF8Unsafe(path),
156 LOG(ERROR) << "Unable to migrate the information to Version 1: " << error;
161 value->GetDouble("install_time", &install_time);
162 if (!AddApplication(application, base::Time::FromDoubleT(install_time)))
165 meta_table_.SetVersionNumber(1);
170 ApplicationStorageImpl::~ApplicationStorageImpl() {
173 bool ApplicationStorageImpl::Init() {
174 bool does_db_exist = base::PathExists(GetDBPath(data_path_));
175 scoped_ptr<sql::Connection> sqlite_db(new sql::Connection);
176 if (!sqlite_db->Open(GetDBPath(data_path_))) {
177 LOG(ERROR) << "Unable to open applications DB.";
180 sqlite_db->Preload();
182 if (!meta_table_.Init(sqlite_db.get(), kVersionNumber, kVersionNumber) ||
183 meta_table_.GetVersionNumber() != kVersionNumber) {
184 LOG(ERROR) << "Unable to init the META table.";
188 if (!InitApplicationsTable(sqlite_db.get())) {
189 LOG(ERROR) << "Unable to open applications table.";
193 if (!InitPermissionsTable(sqlite_db.get())) {
194 LOG(ERROR) << "Unable to open registered permissions table.";
198 if (!sqlite_db->Execute("PRAGMA foreign_keys=ON")) {
199 LOG(ERROR) << "Unable to enforce foreign key contraints.";
203 sqlite_db_.reset(sqlite_db.release());
205 db_initialized_ = (sqlite_db_ && sqlite_db_->is_open());
207 base::FilePath v0_file = data_path_.Append(
208 FILE_PATH_LITERAL("applications_db"));
209 if (base::PathExists(v0_file) &&
211 if (!UpgradeToVersion1(v0_file)) {
212 LOG(ERROR) << "Unable to migrate database from JSON format to SQLite.";
215 // After migrated to SQLite, delete the old JSON DB file is safe,
216 // since all information has been migrated and it will not be used anymore.
217 if (!base::DeleteFile(v0_file, false)) {
218 LOG(ERROR) << "Unalbe to delete old JSON DB file.";
223 db_initialized_ = true;
225 return db_initialized_;
228 scoped_refptr<ApplicationData> ApplicationStorageImpl::ExtractApplicationData(
229 const sql::Statement& smt) {
230 std::string id = smt.ColumnString(0);
233 std::string manifest_str = smt.ColumnString(1);
234 JSONStringValueSerializer serializer(&manifest_str);
235 std::string error_msg;
236 scoped_ptr<base::DictionaryValue> manifest(
237 static_cast<base::DictionaryValue*>(
238 serializer.Deserialize(&error_code, &error_msg)));
241 LOG(ERROR) << "An error occured when deserializing the manifest, "
242 "the error message is: "
246 std::string path = smt.ColumnString(2);
247 double install_time = smt.ColumnDouble(3);
250 scoped_refptr<ApplicationData> app_data =
251 ApplicationData::Create(
252 base::FilePath::FromUTF8Unsafe(path),
258 LOG(ERROR) << "Load appliation error: " << error;
262 app_data->install_time_ = base::Time::FromDoubleT(install_time);
264 app_data->permission_map_ = ToPermissionMap(smt.ColumnString(4));
269 scoped_refptr<ApplicationData> ApplicationStorageImpl::GetApplicationData(
270 const std::string& app_id) {
271 if (!db_initialized_) {
272 LOG(ERROR) << "The database hasn't been initilized.";
276 sql::Statement smt(sqlite_db_->GetUniqueStatement(
277 db_fields::kGetRowFromAppTableOp));
278 smt.BindString(0, app_id);
285 return ExtractApplicationData(smt);
288 bool ApplicationStorageImpl::GetInstalledApplications(
289 ApplicationData::ApplicationDataMap& applications) { // NOLINT
290 if (!db_initialized_) {
291 LOG(ERROR) << "The database hasn't been initilized.";
295 sql::Statement smt(sqlite_db_->GetUniqueStatement(
296 db_fields::kGetAllRowsFromAppTableOp));
301 scoped_refptr<ApplicationData> data = ExtractApplicationData(smt);
303 LOG(ERROR) << "Failed to obtain ApplicationData from SQL query";
307 std::pair<std::string, scoped_refptr<ApplicationData> >(
314 bool ApplicationStorageImpl::GetInstalledApplicationIDs(
315 std::vector<std::string>& app_ids) { // NOLINT
316 if (!db_initialized_) {
317 LOG(ERROR) << "The database hasn't been initilized.";
321 sql::Statement smt(sqlite_db_->GetUniqueStatement(
322 db_fields::kGetAllIDsFromAppTableOp));
327 const std::string& id = smt.ColumnString(0);
328 if (!IsValidApplicationID(id)) {
329 LOG(ERROR) << "Failed to obtain Application ID from SQL query";
332 app_ids.push_back(id);
338 bool ApplicationStorageImpl::AddApplication(const ApplicationData* application,
339 const base::Time& install_time) {
340 if (!db_initialized_) {
341 LOG(ERROR) << "The database hasn't been initilized.";
345 return (SetApplicationValue(
346 application, install_time, db_fields::kSetApplicationWithBindOp) &&
347 SetPermissions(application->ID(), application->permission_map_));
350 bool ApplicationStorageImpl::UpdateApplication(
351 ApplicationData* application, const base::Time& install_time) {
352 if (!db_initialized_) {
353 LOG(ERROR) << "The database hasn't been initilized.";
357 if (SetApplicationValue(
358 application, install_time, db_fields::kUpdateApplicationWithBindOp) &&
359 UpdatePermissions(application->ID(), application->permission_map_)) {
366 bool ApplicationStorageImpl::RemoveApplication(const std::string& id) {
367 if (!db_initialized_) {
368 LOG(ERROR) << "The database hasn't been initilized.";
372 sql::Transaction transaction(sqlite_db_.get());
373 if (!transaction.Begin())
376 sql::Statement smt(sqlite_db_->GetUniqueStatement(
377 db_fields::kDeleteApplicationWithBindOp));
378 smt.BindString(0, id);
380 LOG(ERROR) << "Could not delete application "
381 "information from DB.";
385 return transaction.Commit();
388 bool ApplicationStorageImpl::ContainsApplication(const std::string& app_id) {
389 return GetApplicationData(app_id) != NULL;
392 bool ApplicationStorageImpl::SetApplicationValue(
393 const ApplicationData* application,
394 const base::Time& install_time,
395 const std::string& operation) {
397 LOG(ERROR) << "A value is needed when inserting/updating in DB.";
401 std::string manifest;
402 JSONStringValueSerializer serializer(&manifest);
403 if (!serializer.Serialize(*(application->GetManifest()->value()))) {
404 LOG(ERROR) << "An error occured when serializing the manifest value.";
408 sql::Transaction transaction(sqlite_db_.get());
409 if (!transaction.Begin())
412 sql::Statement smt(sqlite_db_->GetUniqueStatement(operation.c_str()));
413 if (!smt.is_valid()) {
414 LOG(ERROR) << "Unable to insert/update application info in DB.";
417 smt.BindString(0, manifest);
418 smt.BindString(1, application->Path().AsUTF8Unsafe());
419 smt.BindDouble(2, install_time.ToDoubleT());
420 smt.BindString(3, application->ID());
422 LOG(ERROR) << "An error occured when inserting/updating "
423 "application info in DB.";
427 return transaction.Commit();
430 bool ApplicationStorageImpl::SetPermissions(const std::string& id,
431 const StoredPermissionMap& permissions) {
432 if (!db_initialized_) {
433 LOG(ERROR) << "Database is not initialized.";
436 return SetPermissionsValue(id, permissions,
437 db_fields::kInsertPermissionsWithBindOp);
440 bool ApplicationStorageImpl::UpdatePermissions(const std::string& id,
441 const StoredPermissionMap& permissions) {
442 if (!db_initialized_) {
443 LOG(ERROR) << "Database is not initialized.";
446 if (permissions.empty())
447 return RevokePermissions(id);
449 return SetPermissionsValue(id, permissions,
450 db_fields::kUpdatePermissionsWithBindOp);
453 bool ApplicationStorageImpl::RevokePermissions(const std::string& id) {
454 sql::Transaction transaction(sqlite_db_.get());
455 if (!transaction.Begin())
458 sql::Statement statement(sqlite_db_->GetUniqueStatement(
459 db_fields::kDeletePermissionsWithBindOp));
460 statement.BindString(0, id);
462 if (!statement.Run()) {
464 "An error occurred while removing permissions.";
467 return transaction.Commit();
470 bool ApplicationStorageImpl::SetPermissionsValue(
471 const std::string& id,
472 const StoredPermissionMap& permissions,
473 const std::string& operation) {
474 sql::Transaction transaction(sqlite_db_.get());
475 std::string permission_str = ToString(permissions);
477 if (!transaction.Begin())
480 sql::Statement statement(sqlite_db_->GetUniqueStatement(
482 statement.BindString(0, permission_str);
483 statement.BindString(1, id);
484 if (!statement.Run()) {
486 "An error occurred while inserting permissions.";
489 return transaction.Commit();
492 } // namespace application