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

Side by Side Diff: chrome/browser/extensions/extension_settings_storage_cache.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_storage_cache.h"
6
7 #include "base/bind.h"
8 #include "base/logging.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "base/message_loop.h"
11 #include "base/task.h"
12 #include "base/json/json_writer.h"
13
14 namespace {
15
16 void RemoveAll(DictionaryValue* from, const ListValue* keys_to_remove) {
17 std::string key;
18 for (ListValue::const_iterator it = keys_to_remove->begin();
19 it != keys_to_remove->end(); ++it) {
20 if ((*it)->GetAsString(&key)) {
21 from->Remove(key, NULL);
22 }
23 }
24 }
25
26 // Callback which delegates to a given callback but caches any result if
27 // successful. Takes an optional parameter of existing settings to merge with
28 // before returning to the callback (may be NULL) and an optional parameter of
29 // keys to remove from the cache post-success (may be NULL).
30 class CacheModifyingCallback : public ExtensionSettingsStorage::Callback {
31 public:
32 // Takes ownership of callback, existing, and keys_to_remove.
33 CacheModifyingCallback(
34 ExtensionSettingsStorage::Callback* delegate,
35 DictionaryValue* cache,
36 DictionaryValue* existing,
37 ListValue* keys_to_remove)
38 : delegate_(delegate),
39 cache_(cache),
40 existing_(existing),
41 keys_to_remove_(keys_to_remove) {
42 }
43
44 ~CacheModifyingCallback() {}
45
46 static CacheModifyingCallback* Create(
47 ExtensionSettingsStorage::Callback* delegate, DictionaryValue* cache) {
48 return new CacheModifyingCallback(delegate, cache, NULL, NULL);
49 }
50
51 static CacheModifyingCallback* Create(
52 ExtensionSettingsStorage::Callback* delegate,
53 DictionaryValue* cache,
54 DictionaryValue* existing) {
55 return new CacheModifyingCallback(delegate, cache, existing, NULL);
56 }
57
58 static CacheModifyingCallback* Create(
59 ExtensionSettingsStorage::Callback* delegate,
60 DictionaryValue* cache,
61 ListValue* remove) {
62 return new CacheModifyingCallback(delegate, cache, NULL, remove);
63 }
64
65 virtual void OnSuccess(DictionaryValue* settings) OVERRIDE {
66 cache_->MergeDictionary(settings);
67 if (existing_ != NULL) {
68 settings->MergeDictionary(existing_.get());
69 }
70 if (keys_to_remove_ != NULL) {
71 RemoveAll(cache_, keys_to_remove_.get());
72 }
73 delegate_->OnSuccess(settings);
74 }
75
76 virtual void OnFailure(const std::string& message) OVERRIDE {
77 delegate_->OnFailure(message);
78 }
79
80 private:
81 scoped_ptr<ExtensionSettingsStorage::Callback> delegate_;
82 DictionaryValue* cache_;
Matt Perry 2011/06/23 19:14:11 who owns this ptr? it seems it won't get deleted i
not at google - send to devlin 2011/06/27 08:51:02 cache is owned by ExtensionSettingsStorageCache.
83 scoped_ptr<DictionaryValue> existing_;
84 scoped_ptr<ListValue> keys_to_remove_;
85 };
86
87 // Runs OnSuccess() on the message loop of the calling thread.
88 class SuccessClosure {
89 public:
90 SuccessClosure(
91 ExtensionSettingsStorage::Callback* callback, DictionaryValue* settings)
92 : callback_(callback), settings_(settings) {
93 }
94
95 ~SuccessClosure() {
96 delete callback_;
Matt Perry 2011/06/23 19:14:11 make callback_ a scoped_ptr
not at google - send to devlin 2011/06/27 08:51:02 Done.
97 }
98
99 void Run() {
100 MessageLoop::current()->PostTask(
101 FROM_HERE,
102 base::Bind(&SuccessClosure::Run2, base::Unretained(this)));
103 }
104
105 private:
106 void Run2() {
107 callback_->OnSuccess(settings_);
108 delete this;
109 }
110
111 ExtensionSettingsStorage::Callback* callback_;
112 DictionaryValue* settings_;
113 };
114
115 } // namespace
116
117 ExtensionSettingsStorageCache::ExtensionSettingsStorageCache(
118 ExtensionSettingsStorage* delegate)
119 : delegate_(delegate) {
120 }
121
122 void ExtensionSettingsStorageCache::DestroyEventually() {
123 delegate_->DestroyEventually();
124 delete this;
125 }
126
127 void ExtensionSettingsStorageCache::Get(const std::string& key,
128 ExtensionSettingsStorageCache::Callback* callback) {
129 Value *value;
130 if (GetFromCache(key, &value)) {
131 DictionaryValue* settings = new DictionaryValue();
132 settings->Set(key, value);
133 (new SuccessClosure(callback, settings))->Run();
134 } else {
135 delegate_->Get(key, CacheModifyingCallback::Create(callback, &cache_));
136 }
137 }
138
139 void ExtensionSettingsStorageCache::Get(const ListValue& keys,
140 ExtensionSettingsStorageCache::Callback* callback) {
141 std::string key;
142 DictionaryValue* settings = new DictionaryValue();
143 ListValue missing_keys;
144
145 for (ListValue::const_iterator it = keys.begin(); it != keys.end(); ++it) {
146 if ((*it)->GetAsString(&key)) {
147 Value *value;
148 if (GetFromCache(key, &value)) {
149 settings->Set(key, value);
150 } else {
151 missing_keys.Append(Value::CreateStringValue(key));
152 }
153 }
154 }
155
156 if (missing_keys.empty()) {
157 (new SuccessClosure(callback, settings))->Run();
158 } else {
159 delegate_->Get(missing_keys,
160 CacheModifyingCallback::Create(callback, &cache_, settings));
161 }
162 }
163
164 void ExtensionSettingsStorageCache::Get(
165 ExtensionSettingsStorageCache::Callback* callback) {
166 // Copy the cache when passing in, as a semi-hack so that caching a no-op
167 // storage object works (which always returns empty from Get()).
168 // TODO(kalman): Consider doing this conditionally on type == NOOP.
169 delegate_->Get(
170 CacheModifyingCallback::Create(callback, &cache_, cache_.DeepCopy()));
171 }
172
173 void ExtensionSettingsStorageCache::Set(
174 const std::string& key,
175 const Value& value,
176 ExtensionSettingsStorageCache::Callback* callback) {
177 // Invalidate the cached entry first, in case the set fails.
178 cache_.Remove(key, NULL);
179 delegate_->Set(key, value, CacheModifyingCallback::Create(callback, &cache_));
180 }
181
182 void ExtensionSettingsStorageCache::Set(
183 const DictionaryValue& values,
184 ExtensionSettingsStorageCache::Callback* callback) {
185 // Invalidate the cached entries first, in case the set fails.
186 for (DictionaryValue::key_iterator it = values.begin_keys();
187 it != values.end_keys(); ++it) {
188 cache_.RemoveWithoutPathExpansion(*it, NULL);
189 }
190 delegate_->Set(values, CacheModifyingCallback::Create(callback, &cache_));
191 }
192
193 void ExtensionSettingsStorageCache::Remove(
194 const std::string& key,
195 ExtensionSettingsStorageCache::Callback *callback) {
196 // Invalidate the cached entry first, in case the remove fails.
197 // We will also need to do if after the callback, to avoid race conditions
198 // whether other API calls fill the cache on the UI thread.
199 // This would be a good time to use structured cloning...
200 cache_.Remove(key, NULL);
201 ListValue* key_list = new ListValue();
202 key_list->Append(Value::CreateStringValue(key));
203 delegate_->Remove(key,
204 CacheModifyingCallback::Create(callback, &cache_, key_list));
205 }
206
207 void ExtensionSettingsStorageCache::Remove(
208 const ListValue& keys,
209 ExtensionSettingsStorageCache::Callback *callback) {
210 std::string key;
211 // Invalidate each cached entry first, in case the remove fails.
212 // We will also need to do if after the callback, to avoid race conditions
213 // whether other API calls fill the cache on the UI thread.
214 RemoveAll(&cache_, &keys);
215 delegate_->Remove(keys,
216 CacheModifyingCallback::Create(callback, &cache_, keys.DeepCopy()));
217 }
218
219 void ExtensionSettingsStorageCache::Clear(
220 ExtensionSettingsStorageCache::Callback* callback) {
221 cache_.Clear();
222 delegate_->Clear(CacheModifyingCallback::Create(callback, &cache_));
223 }
224
225 bool ExtensionSettingsStorageCache::GetFromCache(
226 const std::string& key, Value** value) {
227 Value* cached_value;
228 if (!cache_.Get(key, &cached_value)) {
229 return false;
230 }
231 *value = cached_value->DeepCopy();
232 return true;
233 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698