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

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

Powered by Google App Engine
This is Rietveld 408576698