OLD | NEW |
---|---|
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 |
OLD | NEW |