summaryrefslogtreecommitdiffstats
path: root/chrome/browser/extensions/app_notification_storage.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/browser/extensions/app_notification_storage.cc')
-rw-r--r--chrome/browser/extensions/app_notification_storage.cc211
1 files changed, 211 insertions, 0 deletions
diff --git a/chrome/browser/extensions/app_notification_storage.cc b/chrome/browser/extensions/app_notification_storage.cc
new file mode 100644
index 0000000..57d7612
--- /dev/null
+++ b/chrome/browser/extensions/app_notification_storage.cc
@@ -0,0 +1,211 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/extensions/app_notification_storage.h"
+
+#include "base/file_path.h"
+#include "base/file_util.h"
+#include "base/json/json_reader.h"
+#include "base/json/json_writer.h"
+#include "base/location.h"
+#include "base/sys_string_conversions.h"
+#include "base/values.h"
+#include "base/version.h"
+#include "chrome/common/extensions/extension.h"
+#include "content/browser/browser_thread.h"
+#include "third_party/leveldatabase/src/include/leveldb/db.h"
+
+using base::JSONReader;
+using base::JSONWriter;
+
+// A concrete implementation of the AppNotificationStorage interface, using
+// LevelDb for backing storage.
+class LevelDbAppNotificationStorage : public AppNotificationStorage {
+ public:
+ explicit LevelDbAppNotificationStorage(const FilePath& path);
+ virtual ~LevelDbAppNotificationStorage();
+
+ // Must be called exactly once before any other operations. This will return
+ // false if any condition would prevent further operations from being
+ // successful (eg unable to create files at |path_|).
+ bool Initialize();
+
+ // Implementing the AppNotificationStorage interface.
+ virtual bool GetExtensionIds(std::set<std::string>* result) OVERRIDE;
+ virtual bool Get(const std::string& extension_id,
+ AppNotificationList* result) OVERRIDE;
+ virtual bool Set(const std::string& extension_id,
+ const AppNotificationList& list) OVERRIDE;
+ virtual bool Delete(const std::string& extension_id) OVERRIDE;
+
+ private:
+ // The path where the database will reside.
+ FilePath path_;
+
+ // This should be used for all read operations on the db.
+ leveldb::ReadOptions read_options_;
+
+ // The leveldb database object - will be NULL until Initialize is called.
+ scoped_ptr<leveldb::DB> db_;
+
+ DISALLOW_COPY_AND_ASSIGN(LevelDbAppNotificationStorage);
+};
+
+// static
+AppNotificationStorage* AppNotificationStorage::Create(
+ const FilePath& path) {
+ scoped_ptr<LevelDbAppNotificationStorage> result(
+ new LevelDbAppNotificationStorage(path));
+ if (!result->Initialize())
+ return NULL;
+ return result.release();
+}
+
+AppNotificationStorage::~AppNotificationStorage() {}
+
+namespace {
+
+void AppNotificationListToJSON(const AppNotificationList& list,
+ std::string* result) {
+ ListValue list_value;
+ AppNotificationList::const_iterator i;
+ for (i = list.begin(); i != list.end(); ++i) {
+ DictionaryValue* dictionary = new DictionaryValue();
+ (*i)->ToDictionaryValue(dictionary);
+ list_value.Append(dictionary);
+ }
+ JSONWriter::Write(&list_value, false /* pretty_print */, result);
+}
+
+bool JSONToAppNotificationList(const std::string& json,
+ AppNotificationList* list) {
+ CHECK(list);
+ scoped_ptr<Value> value(JSONReader::Read(json,
+ false /* allow_trailing_comma */));
+ if (!value.get() || value->GetType() != Value::TYPE_LIST)
+ return false;
+
+ ListValue* list_value = static_cast<ListValue*>(value.get());
+ for (size_t i = 0; i < list_value->GetSize(); i++) {
+ Value* item = NULL;
+ if (!list_value->Get(i, &item) || !item ||
+ item->GetType() != Value::TYPE_DICTIONARY)
+ return false;
+ DictionaryValue* dictionary = static_cast<DictionaryValue*>(item);
+ AppNotification* notification =
+ AppNotification::FromDictionaryValue(*dictionary);
+ if (!notification)
+ return false;
+ list->push_back(linked_ptr<AppNotification>(notification));
+ }
+ return true;
+}
+
+void LogLevelDbError(tracked_objects::Location location,
+ const leveldb::Status& status) {
+ LOG(ERROR) << "AppNotificationStorage database error at "
+ << location.ToString() << " status:" << status.ToString();
+}
+
+} // namespace
+
+
+LevelDbAppNotificationStorage::LevelDbAppNotificationStorage(
+ const FilePath& path) : path_(path) {
+ CHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ read_options_.verify_checksums = true;
+}
+
+LevelDbAppNotificationStorage::~LevelDbAppNotificationStorage() {
+ CHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+}
+
+bool LevelDbAppNotificationStorage::Initialize() {
+ CHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ CHECK(!db_.get());
+ CHECK(!path_.empty());
+
+#if defined(OS_POSIX)
+ std::string os_path = path_.value();
+#elif defined(OS_WIN)
+ std::string os_path = base::SysWideToUTF8(path_.value());
+#endif
+
+ leveldb::Options options;
+ options.create_if_missing = true;
+ leveldb::DB* db = NULL;
+ leveldb::Status status = leveldb::DB::Open(options, os_path, &db);
+ if (!status.ok()) {
+ LogLevelDbError(FROM_HERE, status);
+ return false;
+ }
+ db_.reset(db);
+ return true;
+}
+
+bool LevelDbAppNotificationStorage::GetExtensionIds(
+ std::set<std::string>* result) {
+ CHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ CHECK(db_.get());
+ CHECK(result);
+
+ scoped_ptr<leveldb::Iterator> iter(db_->NewIterator(read_options_));
+ for (iter->SeekToFirst(); iter->Valid(); iter->Next()) {
+ std::string key = iter->key().ToString();
+ if (Extension::IdIsValid(key))
+ result->insert(key);
+ }
+
+ return true;
+}
+
+bool LevelDbAppNotificationStorage::Get(const std::string& extension_id,
+ AppNotificationList* result) {
+ CHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ CHECK(db_.get());
+ CHECK(result);
+
+ std::string json;
+ leveldb::Status status = db_->Get(read_options_, extension_id, &json);
+ if (status.IsNotFound()) {
+ return true;
+ } else if (!status.ok()) {
+ LogLevelDbError(FROM_HERE, status);
+ return false;
+ }
+
+ return JSONToAppNotificationList(json, result);
+}
+
+bool LevelDbAppNotificationStorage::Set(const std::string& extension_id,
+ const AppNotificationList& list) {
+ CHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ CHECK(db_.get());
+
+ std::string json;
+ AppNotificationListToJSON(list, &json);
+ leveldb::Status status = db_->Put(leveldb::WriteOptions(),
+ extension_id,
+ json);
+ if (!status.ok()) {
+ LogLevelDbError(FROM_HERE, status);
+ return false;
+ }
+ return true;
+}
+
+bool LevelDbAppNotificationStorage::Delete(const std::string& extension_id) {
+ CHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ CHECK(db_.get());
+
+ // Leveldb does not consider it an error if the key to delete isn't present,
+ // so we don't bother checking that first.
+ leveldb::Status status = db_->Delete(leveldb::WriteOptions(), extension_id);
+
+ if (!status.ok()) {
+ LogLevelDbError(FROM_HERE, status);
+ return false;
+ }
+ return true;
+}