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

Side by Side Diff: chrome/browser/extensions/settings/settings_frontend.cc

Issue 8670012: Extension Settings API: move the API functions into an object SettingsNamepace, (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 9 years, 1 month 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
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/extensions/settings/settings_frontend.h" 5 #include "chrome/browser/extensions/settings/settings_frontend.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/file_path.h" 8 #include "base/file_path.h"
9 #include "chrome/browser/extensions/extension_event_names.h" 9 #include "chrome/browser/extensions/extension_event_names.h"
10 #include "chrome/browser/extensions/extension_event_router.h" 10 #include "chrome/browser/extensions/extension_event_router.h"
11 #include "chrome/browser/extensions/extension_service.h" 11 #include "chrome/browser/extensions/extension_service.h"
12 #include "chrome/browser/extensions/settings/settings_backend.h" 12 #include "chrome/browser/extensions/settings/settings_backend.h"
13 #include "chrome/browser/extensions/settings/settings_namespace.h"
13 #include "chrome/browser/extensions/settings/settings_leveldb_storage.h" 14 #include "chrome/browser/extensions/settings/settings_leveldb_storage.h"
14 #include "chrome/browser/profiles/profile.h" 15 #include "chrome/browser/profiles/profile.h"
15 #include "content/public/browser/browser_thread.h" 16 #include "content/public/browser/browser_thread.h"
16 #include "content/public/browser/notification_service.h" 17 #include "content/public/browser/notification_service.h"
17 18
19 using content::BrowserThread;
20
18 namespace extensions { 21 namespace extensions {
19 22
20 using content::BrowserThread;
21
22 namespace { 23 namespace {
23 24
24 struct Backends { 25 // Settings change Observer which forwards changes on to the extension
25 Backends( 26 // processes for |profile| and its incognito partner if it exists.
26 // Ownership taken. 27 class DefaultObserver : public SettingsObserver {
27 SettingsStorageFactory* storage_factory, 28 public:
28 const FilePath& profile_path, 29 explicit DefaultObserver(Profile* profile) : profile_(profile) {}
29 const scoped_refptr<SettingsObserverList>& observers)
30 : storage_factory_(storage_factory),
31 extensions_backend_(
32 storage_factory,
33 profile_path.AppendASCII(
34 ExtensionService::kExtensionSettingsDirectoryName),
35 observers),
36 apps_backend_(
37 storage_factory,
38 profile_path.AppendASCII(
39 ExtensionService::kAppSettingsDirectoryName),
40 observers) {}
41 30
42 scoped_ptr<SettingsStorageFactory> storage_factory_; 31 // SettingsObserver implementation.
43 SettingsBackend extensions_backend_; 32 virtual void OnSettingsChanged(
44 SettingsBackend apps_backend_; 33 const std::string& extension_id,
34 settings_namespace::Namespace settings_namespace,
35 const std::string& change_json) OVERRIDE {
36 profile_->GetExtensionEventRouter()->DispatchEventToExtension(
37 extension_id,
38 extension_event_names::kOnSettingsChanged,
39 // This is the list of function arguments to pass to the onChanged
40 // handler of extensions, an array of [changes, settings_namespace].
41 std::string("[") + change_json + ",\"" +
42 settings_namespace::NamespaceToString(settings_namespace) + "\"]",
43 NULL,
44 GURL());
45 }
46
47 private:
48 Profile* const profile_;
45 }; 49 };
46 50
47 static void CallbackWithExtensionsBackend( 51 void CallbackWithSyncableService(
48 const SettingsFrontend::SyncableServiceCallback& callback, 52 const SettingsFrontend::SyncableServiceCallback& callback,
49 Backends* backends) { 53 SettingsBackend* backend) {
50 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 54 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
51 callback.Run(&backends->extensions_backend_); 55 callback.Run(backend);
52 } 56 }
53 57
54 void CallbackWithAppsBackend( 58 void CallbackWithStorage(
55 const SettingsFrontend::SyncableServiceCallback& callback,
56 Backends* backends) {
57 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
58 callback.Run(&backends->apps_backend_);
59 }
60
61 void CallbackWithExtensionsStorage(
62 const std::string& extension_id, 59 const std::string& extension_id,
63 const SettingsFrontend::StorageCallback& callback, 60 const SettingsFrontend::StorageCallback& callback,
64 Backends* backends) { 61 SettingsBackend* backend) {
65 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 62 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
66 callback.Run(backends->extensions_backend_.GetStorage(extension_id)); 63 callback.Run(backend->GetStorage(extension_id));
67 }
68
69 void CallbackWithAppsStorage(
70 const std::string& extension_id,
71 const SettingsFrontend::StorageCallback& callback,
72 Backends* backends) {
73 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
74 callback.Run(backends->apps_backend_.GetStorage(extension_id));
75 } 64 }
76 65
77 void CallbackWithNullStorage( 66 void CallbackWithNullStorage(
78 const SettingsFrontend::StorageCallback& callback) { 67 const SettingsFrontend::StorageCallback& callback) {
79 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 68 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
80 callback.Run(NULL); 69 callback.Run(NULL);
81 } 70 }
82 71
83 void DeleteStorageOnFileThread( 72 void DeleteStorageOnFileThread(
84 const std::string& extension_id, Backends* backends) { 73 const std::string& extension_id, SettingsBackend* backend) {
85 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 74 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
86 backends->extensions_backend_.DeleteStorage(extension_id); 75 backend->DeleteStorage(extension_id);
87 backends->apps_backend_.DeleteStorage(extension_id);
88 } 76 }
89 77
90 } // namespace 78 } // namespace
91 79
92 // DefaultObserver 80 // Ref-counted container for a SettingsBackend object.
93 81 class SettingsFrontend::BackendWrapper
not at google - send to devlin 2011/11/23 02:24:43 This is basically what used to be Core, and replac
94 SettingsFrontend::DefaultObserver::DefaultObserver(Profile* profile) 82 : public base::RefCountedThreadSafe<BackendWrapper> {
95 : profile_(profile) {}
96
97 SettingsFrontend::DefaultObserver::~DefaultObserver() {}
98
99 void SettingsFrontend::DefaultObserver::OnSettingsChanged(
100 const std::string& extension_id, const std::string& changes_json) {
101 profile_->GetExtensionEventRouter()->DispatchEventToExtension(
102 extension_id,
103 extension_event_names::kOnSettingsChanged,
104 // This is the list of function arguments to pass to the onChanged
105 // handler of extensions, a single argument with the list of changes.
106 std::string("[") + changes_json + "]",
107 NULL,
108 GURL());
109 }
110
111 // Core
112
113 class SettingsFrontend::Core
114 : public base::RefCountedThreadSafe<Core> {
115 public: 83 public:
116 explicit Core( 84 // Creates a new BackendWrapper and initializes it on the FILE thread.
117 // Ownership taken. 85 static scoped_refptr<BackendWrapper> CreateAndInit(
118 SettingsStorageFactory* storage_factory, 86 const scoped_refptr<SettingsStorageFactory>& factory,
119 const scoped_refptr<SettingsObserverList>& observers) 87 const scoped_refptr<SettingsObserverList>& observers,
120 : storage_factory_(storage_factory), 88 const FilePath& path) {
121 observers_(observers),
122 backends_(NULL) {
123 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 89 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
90 scoped_refptr<BackendWrapper> backend_wrapper =
91 new BackendWrapper(factory, observers);
92 BrowserThread::PostTask(
93 BrowserThread::FILE,
94 FROM_HERE,
95 base::Bind(
96 &SettingsFrontend::BackendWrapper::InitOnFileThread,
97 backend_wrapper,
98 path));
99 return backend_wrapper;
124 } 100 }
125 101
126 typedef base::Callback<void(Backends*)> BackendsCallback; 102 typedef base::Callback<void(SettingsBackend*)> BackendCallback;
127 103
128 // Does any FILE thread specific initialization, such as construction of 104 // Runs |callback| with the wrapped Backend on the FILE thread.
129 // |backend_|. Must be called before any call to 105 void RunWithBackend(const BackendCallback& callback) {
130 // RunWithBackendOnFileThread().
131 void InitOnFileThread(const FilePath& profile_path) {
132 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
133 DCHECK(!backends_);
134 backends_ =
135 new Backends(
136 storage_factory_.release(), profile_path, observers_);
137 }
138
139 // Runs |callback| with both the extensions and apps settings on the FILE
140 // thread.
141 void RunWithBackends(const BackendsCallback& callback) {
142 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 106 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
143 BrowserThread::PostTask( 107 BrowserThread::PostTask(
144 BrowserThread::FILE, 108 BrowserThread::FILE,
145 FROM_HERE, 109 FROM_HERE,
146 base::Bind( 110 base::Bind(
147 &SettingsFrontend::Core::RunWithBackendsOnFileThread, 111 &SettingsFrontend::BackendWrapper::RunWithBackendOnFileThread,
148 this, 112 this,
149 callback)); 113 callback));
150 } 114 }
151 115
152 private: 116 private:
153 void RunWithBackendsOnFileThread(const BackendsCallback& callback) { 117 friend class base::RefCountedThreadSafe<BackendWrapper>;
154 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 118
155 DCHECK(backends_); 119 BackendWrapper(
156 callback.Run(backends_); 120 const scoped_refptr<SettingsStorageFactory>& storage_factory,
121 const scoped_refptr<SettingsObserverList>& observers)
122 : storage_factory_(storage_factory),
123 observers_(observers),
124 backend_(NULL) {
125 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
157 } 126 }
158 127
159 virtual ~Core() { 128 virtual ~BackendWrapper() {
160 if (BrowserThread::CurrentlyOn(BrowserThread::FILE)) { 129 if (BrowserThread::CurrentlyOn(BrowserThread::FILE)) {
161 delete backends_; 130 delete backend_;
162 } else if (BrowserThread::CurrentlyOn(BrowserThread::UI)) { 131 } else if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
163 BrowserThread::DeleteSoon(BrowserThread::FILE, FROM_HERE, backends_); 132 BrowserThread::DeleteSoon(BrowserThread::FILE, FROM_HERE, backend_);
164 } else { 133 } else {
165 NOTREACHED(); 134 NOTREACHED();
166 } 135 }
167 } 136 }
168 137
169 friend class base::RefCountedThreadSafe<Core>; 138 void InitOnFileThread(const FilePath& path) {
139 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
140 DCHECK(!backend_);
141 backend_ = new SettingsBackend(storage_factory_, path, observers_);
142 storage_factory_ = NULL;
143 observers_ = NULL;
144 }
170 145
171 // Leveldb storage area factory. Ownership passed to Backends on Init. 146 void RunWithBackendOnFileThread(const BackendCallback& callback) {
172 scoped_ptr<SettingsStorageFactory> storage_factory_; 147 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
148 DCHECK(backend_);
149 callback.Run(backend_);
150 }
173 151
174 // Observers to settings changes (thread safe). 152 // Only need these until |backend_| exists.
153 scoped_refptr<SettingsStorageFactory> storage_factory_;
175 scoped_refptr<SettingsObserverList> observers_; 154 scoped_refptr<SettingsObserverList> observers_;
176 155
177 // Backends for extensions and apps settings. Lives on FILE thread. 156 // Wrapped Backend.
178 Backends* backends_; 157 SettingsBackend* backend_;
Matt Perry 2011/11/23 03:35:05 add a comment to point out the ownership and threa
not at google - send to devlin 2011/11/23 11:04:52 Done.
179 158
180 DISALLOW_COPY_AND_ASSIGN(Core); 159 DISALLOW_COPY_AND_ASSIGN(BackendWrapper);
181 }; 160 };
182 161
183 // SettingsFrontend 162 // SettingsFrontend
184 163
185 /* static */ 164 /* static */
186 SettingsFrontend* SettingsFrontend::Create(Profile* profile) { 165 SettingsFrontend* SettingsFrontend::Create(Profile* profile) {
187 return new SettingsFrontend(new SettingsLeveldbStorage::Factory(), profile); 166 return new SettingsFrontend(new SettingsLeveldbStorage::Factory(), profile);
188 } 167 }
189 168
190 /* static */ 169 /* static */
191 SettingsFrontend* SettingsFrontend::Create( 170 SettingsFrontend* SettingsFrontend::Create(
192 SettingsStorageFactory* storage_factory, Profile* profile) { 171 const scoped_refptr<SettingsStorageFactory>& storage_factory,
172 Profile* profile) {
193 return new SettingsFrontend(storage_factory, profile); 173 return new SettingsFrontend(storage_factory, profile);
194 } 174 }
195 175
196 SettingsFrontend::SettingsFrontend( 176 SettingsFrontend::SettingsFrontend(
197 SettingsStorageFactory* storage_factory, Profile* profile) 177 const scoped_refptr<SettingsStorageFactory>& factory, Profile* profile)
198 : profile_(profile), 178 : profile_(profile),
199 observers_(new SettingsObserverList()), 179 observers_(new SettingsObserverList()),
200 default_observer_(profile), 180 profile_observer_(new DefaultObserver(profile)) {
201 core_(new SettingsFrontend::Core(storage_factory, observers_)) {
202 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 181 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
203 DCHECK(!profile->IsOffTheRecord()); 182 DCHECK(!profile->IsOffTheRecord());
204 183
205 observers_->AddObserver(&default_observer_); 184 observers_->AddObserver(profile_observer_.get());
206 185
207 BrowserThread::PostTask( 186 const FilePath& profile_path = profile->GetPath();
208 BrowserThread::FILE, 187 backends_[settings_namespace::LOCAL][true] =
209 FROM_HERE, 188 BackendWrapper::CreateAndInit(
210 base::Bind( 189 factory,
not at google - send to devlin 2011/11/23 02:24:43 This (and the other 3 occurrences) is basically wh
Matt Perry 2011/11/23 03:35:05 This seems fine to me. If you really hate it, here
not at google - send to devlin 2011/11/23 11:04:52 Yeah, not so keen on that because of the 3 interde
211 &SettingsFrontend::Core::InitOnFileThread, 190 observers_,
212 core_.get(), 191 profile_path.AppendASCII(
213 profile->GetPath())); 192 ExtensionService::kLocalAppSettingsDirectoryName));
193 backends_[settings_namespace::LOCAL][false] =
194 BackendWrapper::CreateAndInit(
195 factory,
196 observers_,
197 profile_path.AppendASCII(
198 ExtensionService::kLocalExtensionSettingsDirectoryName));
199 backends_[settings_namespace::SYNC][true] =
200 BackendWrapper::CreateAndInit(
201 factory,
202 observers_,
203 profile_path.AppendASCII(
204 ExtensionService::kSyncAppSettingsDirectoryName));
205 backends_[settings_namespace::SYNC][false] =
206 BackendWrapper::CreateAndInit(
207 factory,
208 observers_,
209 profile_path.AppendASCII(
210 ExtensionService::kSyncExtensionSettingsDirectoryName));
not at google - send to devlin 2011/11/23 02:24:43 except this is kinda yuck
214 } 211 }
215 212
216 SettingsFrontend::~SettingsFrontend() { 213 SettingsFrontend::~SettingsFrontend() {
217 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 214 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
218 observers_->RemoveObserver(&default_observer_); 215 observers_->RemoveObserver(profile_observer_.get());
219 } 216 }
220 217
221 void SettingsFrontend::RunWithSyncableService( 218 void SettingsFrontend::RunWithSyncableService(
222 syncable::ModelType model_type, const SyncableServiceCallback& callback) { 219 syncable::ModelType model_type, const SyncableServiceCallback& callback) {
223 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 220 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
224 switch (model_type) { 221 DCHECK(model_type == syncable::APP_SETTINGS ||
225 case syncable::EXTENSION_SETTINGS: 222 model_type == syncable::EXTENSION_SETTINGS);
226 core_->RunWithBackends( 223 bool is_app = model_type == syncable::APP_SETTINGS;
227 base::Bind(&CallbackWithExtensionsBackend, callback)); 224 backends_[settings_namespace::SYNC][is_app]->RunWithBackend(
228 break; 225 base::Bind(&CallbackWithSyncableService, callback));
229 case syncable::APP_SETTINGS:
230 core_->RunWithBackends(
231 base::Bind(&CallbackWithAppsBackend, callback));
232 break;
233 default:
234 NOTREACHED();
235 }
236 } 226 }
237 227
238 void SettingsFrontend::RunWithStorage( 228 void SettingsFrontend::RunWithStorage(
239 const std::string& extension_id, 229 const std::string& extension_id,
230 settings_namespace::Namespace settings_namespace,
240 const StorageCallback& callback) { 231 const StorageCallback& callback) {
241 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 232 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
242 233
243 const Extension* extension = 234 const Extension* extension =
244 profile_->GetExtensionService()->GetExtensionById(extension_id, true); 235 profile_->GetExtensionService()->GetExtensionById(extension_id, true);
245 if (!extension) { 236 if (!extension) {
246 BrowserThread::PostTask( 237 BrowserThread::PostTask(
247 BrowserThread::FILE, 238 BrowserThread::FILE,
248 FROM_HERE, 239 FROM_HERE,
249 base::Bind(&CallbackWithNullStorage, callback)); 240 base::Bind(&CallbackWithNullStorage, callback));
250 return; 241 return;
251 } 242 }
252 243
253 if (extension->is_app()) { 244 backends_[settings_namespace][extension->is_app()]->RunWithBackend(
254 core_->RunWithBackends( 245 base::Bind(&CallbackWithStorage, extension_id, callback));
255 base::Bind(&CallbackWithAppsStorage, extension_id, callback));
256 } else {
257 core_->RunWithBackends(
258 base::Bind(&CallbackWithExtensionsStorage, extension_id, callback));
259 }
260 } 246 }
261 247
262 void SettingsFrontend::DeleteStorageSoon( 248 void SettingsFrontend::DeleteStorageSoon(
263 const std::string& extension_id) { 249 const std::string& extension_id) {
264 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 250 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
265 core_->RunWithBackends(base::Bind(&DeleteStorageOnFileThread, extension_id)); 251 SettingsFrontend::BackendWrapper::BackendCallback callback =
252 base::Bind(&DeleteStorageOnFileThread, extension_id);
253 backends_[settings_namespace::LOCAL][true]->RunWithBackend(callback);
254 backends_[settings_namespace::LOCAL][false]->RunWithBackend(callback);
255 backends_[settings_namespace::SYNC][true]->RunWithBackend(callback);
256 backends_[settings_namespace::SYNC][false]->RunWithBackend(callback);
not at google - send to devlin 2011/11/23 02:24:43 as is this
Matt Perry 2011/11/23 03:35:05 again, seems ok (and better than the alternatives)
not at google - send to devlin 2011/11/23 11:04:52 iterator'd
266 } 257 }
267 258
268 scoped_refptr<SettingsObserverList> 259 scoped_refptr<SettingsObserverList> SettingsFrontend::GetObservers() {
269 SettingsFrontend::GetObservers() {
270 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 260 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
271 return observers_; 261 return observers_;
272 } 262 }
273 263
274 } // namespace extensions 264 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698