Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(54)

Side by Side Diff: chrome/browser/extensions/extension_settings.cc

Issue 7189029: Implement an initial extension settings API. (Closed) Base URL: http://git.chromium.org/git/chromium.git@trunk
Patch Set: Use base::Closure for storage callback, style fixes, mac/windows fixes Created 9 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2011 The Chromium Authors. 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.
4
5 #include "chrome/browser/extensions/extension_settings.h"
6
7 #include "base/bind.h"
8 #include "base/json/json_reader.h"
9 #include "base/json/json_writer.h"
10 #include "base/logging.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "content/browser/browser_thread.h"
13 #include "chrome/browser/extensions/extension_settings_leveldb_storage.h"
14 #include "chrome/browser/extensions/extension_settings_noop_storage.h"
15 #include "chrome/browser/extensions/extension_settings_storage_cache.h"
16 #include "third_party/leveldb/include/leveldb/iterator.h"
17 #include "third_party/leveldb/include/leveldb/write_batch.h"
18
19 // TODO(kalman): Policy for dots in the key names. Make sure the behaviour of
20 // DictionaryValue and JSON classes is consistent with leveldb.
21 // TODO(kalman): Integration tests.
22 // TODO(kalman): More unit tests (see extension_settings_storage_unittest.cc).
23 // TODO(kalman): Use structured cloning rather than JSON.
24 // TODO(kalman): Quotas.
25
26 namespace {
27
28 // Creates a storage area of a requested type on the FILE thread.
29 class CreateStorageClosure {
30 public:
31 CreateStorageClosure(
32 const FilePath& base_path,
33 std::map<std::string, ExtensionSettingsStorage*>* storage_objs,
34 const std::string& extension_id,
35 ExtensionSettingsStorage::Type type,
36 ExtensionSettingsStorage::Type fallback_type,
37 bool cached,
38 const ExtensionSettings::Callback& callback)
39 : base_path_(base_path),
40 storage_objs_(storage_objs),
41 extension_id_(extension_id),
42 type_(type),
43 fallback_type_(fallback_type),
44 cached_(cached),
45 callback_(callback),
46 storage_(NULL) {}
47
48 ~CreateStorageClosure() {}
49
50 void Run() {
51 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
52 BrowserThread::PostTask(
53 BrowserThread::FILE,
54 FROM_HERE,
55 base::Bind(
56 &CreateStorageClosure::RunOnFileThread, base::Unretained(this)));
Matt Perry 2011/06/23 19:14:11 nit: indent +2
not at google - send to devlin 2011/06/27 08:51:02 Done.
57 }
58
59 private:
60 void RunOnFileThread() {
61 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
62 storage_ = CreateStorage(type_);
63 if (storage_ == NULL && type_ != fallback_type_) {
64 storage_ = CreateStorage(fallback_type_);
65 }
66 BrowserThread::PostTask(
67 BrowserThread::UI,
68 FROM_HERE,
69 base::Bind(&CreateStorageClosure::Done, base::Unretained(this)));
70 }
71
72 void Done() {
73 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
74 DCHECK(storage_ != NULL);
75 // Cache the result now. To avoid a race condition, check again to see
76 // whether a storage has been created already; if so, use that one.
77 std::map<std::string, ExtensionSettingsStorage*>::iterator existing =
78 storage_objs_->find(extension_id_);
79 if (existing == storage_objs_->end()) {
80 (*storage_objs_)[extension_id_] = storage_;
81 } else {
82 delete storage_;
83 storage_ = existing->second;
84 DCHECK(storage_ != NULL);
85 }
86 callback_.Run(storage_);
87 delete this;
88 }
89
90 // Creates a storage object of a given type. If that fails, returns NULL.
91 ExtensionSettingsStorage* CreateStorage(ExtensionSettingsStorage::Type type) {
92 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
93 ExtensionSettingsStorage* storage = NULL;
94
95 switch (type) {
96 case ExtensionSettingsStorage::NOOP:
97 storage = new ExtensionSettingsNoopStorage();
98 break;
99 case ExtensionSettingsStorage::LEVELDB:
100 storage = ExtensionSettingsLeveldbStorage::Create(
101 base_path_, extension_id_);
102 break;
103 default:
104 NOTREACHED();
105 }
106
107 if (storage != NULL && cached_) {
108 storage = new ExtensionSettingsStorageCache(storage);
109 }
110
111 return storage;
112 }
113
114 const FilePath& base_path_;
115 std::map<std::string, ExtensionSettingsStorage*>* storage_objs_;
116 std::string extension_id_;
117 ExtensionSettingsStorage::Type type_;
118 ExtensionSettingsStorage::Type fallback_type_;
119 bool cached_;
120 ExtensionSettings::Callback callback_;
121
122 ExtensionSettingsStorage* storage_;
123 };
124
125 } // namespace
126
127 ExtensionSettings::ExtensionSettings(const FilePath& base_path)
128 : base_path_(base_path) {
129 }
130
131 ExtensionSettings::~ExtensionSettings() {
132 std::map<std::string, ExtensionSettingsStorage*>::iterator it;
133 for (it = storage_objs_.begin(); it != storage_objs_.end(); ++it) {
134 it->second->DestroyEventually();
135 }
136 }
137
138 void ExtensionSettings::GetStorage(
139 const std::string& extension_id,
140 const ExtensionSettings::Callback& callback) {
141 if (!GetExistingStorage(extension_id, callback)) {
142 (new CreateStorageClosure(
143 base_path_,
144 &storage_objs_,
145 extension_id,
146 ExtensionSettingsStorage::LEVELDB,
147 ExtensionSettingsStorage::NOOP,
148 true,
149 callback))->Run();
150 }
151 }
152
153 void ExtensionSettings::GetStorageForTesting(
154 ExtensionSettingsStorage::Type type,
155 bool cached,
156 const std::string& extension_id,
157 const Callback& callback) {
158 if (!GetExistingStorage(extension_id, callback)) {
159 (new CreateStorageClosure(
160 base_path_,
161 &storage_objs_,
162 extension_id,
163 type,
164 type,
165 cached,
166 callback))->Run();
167 }
168 }
169
170 bool ExtensionSettings::GetExistingStorage(
171 const std::string& extension_id, const Callback& callback) {
172 std::map<std::string, ExtensionSettingsStorage*>::iterator existing =
173 storage_objs_.find(extension_id);
174 if (existing == storage_objs_.end()) {
175 // No existing storage.
176 return false;
177 }
178 // Existing storage. Reply with that.
179 ExtensionSettingsStorage* storage = existing->second;
180 DCHECK(storage != NULL);
181 MessageLoop::current()->PostTask(
182 FROM_HERE,
183 base::Bind(&Callback::Run, base::Unretained(&callback), storage));
184 return true;
185 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698