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

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: Add missing files 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 DCHECK(delegate->type() == NOOP || delegate->type() == LEVELDB);
111 }
112
113 void ExtensionSettingsStorageCache::Get(const std::string& key,
114 ExtensionSettingsStorageCache::Callback* callback) {
115 Value *value;
116 if (GetFromCache(key, &value)) {
117 DictionaryValue* settings = new DictionaryValue();
118 settings->Set(key, value);
119 (new SuccessClosure(callback, settings))->Run();
120 } else {
121 delegate_->Get(key, CacheModifyingCallback::Create(callback, &cache_));
122 }
123 }
124
125 void ExtensionSettingsStorageCache::Get(const ListValue& keys,
126 ExtensionSettingsStorageCache::Callback* callback) {
127 std::string key;
128 DictionaryValue* settings = new DictionaryValue();
129 ListValue missing_keys;
130
131 for (ListValue::const_iterator it = keys.begin(); it != keys.end(); ++it) {
132 if ((*it)->GetAsString(&key)) {
133 Value *value;
134 if (GetFromCache(key, &value)) {
135 settings->Set(key, value);
136 } else {
137 missing_keys.Append(Value::CreateStringValue(key));
138 }
139 }
140 }
141
142 if (missing_keys.empty()) {
143 (new SuccessClosure(callback, settings))->Run();
144 } else {
145 delegate_->Get(missing_keys,
146 CacheModifyingCallback::Create(callback, &cache_, settings));
147 }
148 }
149
150 void ExtensionSettingsStorageCache::Get(
151 ExtensionSettingsStorageCache::Callback* callback) {
152 // Copy the cache when passing in, as a semi-hack so that caching a no-op
153 // storage object works (which always returns empty from Get()).
154 // TODO(kalman): Consider doing this conditionally on type == NOOP.
155 delegate_->Get(
156 CacheModifyingCallback::Create(callback, &cache_, cache_.DeepCopy()));
157 }
158
159 void ExtensionSettingsStorageCache::Set(const std::string& key,
160 const Value& value, ExtensionSettingsStorageCache::Callback* callback) {
161 // Invalidate the cached entry first, in case the set fails.
162 cache_.Remove(key, NULL);
163 delegate_->Set(key, value, CacheModifyingCallback::Create(callback, &cache_));
164 }
165
166 void ExtensionSettingsStorageCache::Set(const DictionaryValue& values,
167 ExtensionSettingsStorageCache::Callback* callback) {
168 // Invalidate the cached entries first, in case the set fails.
169 for (DictionaryValue::key_iterator it = values.begin_keys();
170 it != values.end_keys(); ++it) {
171 cache_.RemoveWithoutPathExpansion(*it, NULL);
172 }
173 delegate_->Set(values, CacheModifyingCallback::Create(callback, &cache_));
174 }
175
176 void ExtensionSettingsStorageCache::Remove(const std::string& key,
177 ExtensionSettingsStorageCache::Callback *callback) {
178 // Invalidate the cached entry first, in case the remove fails.
179 // We will also need to do if after the callback, to avoid race conditions
180 // whether other API calls fill the cache on the UI thread.
181 // This would be a good time to use structured cloning...
182 cache_.Remove(key, NULL);
183 ListValue* key_list = new ListValue();
184 key_list->Append(Value::CreateStringValue(key));
185 delegate_->Remove(key,
186 CacheModifyingCallback::Create(callback, &cache_, key_list));
187 }
188
189 void ExtensionSettingsStorageCache::Remove(const ListValue& keys,
190 ExtensionSettingsStorageCache::Callback *callback) {
191 std::string key;
192 // Invalidate each cached entry first, in case the remove fails.
193 // We will also need to do if after the callback, to avoid race conditions
194 // whether other API calls fill the cache on the UI thread.
195 RemoveAll(&cache_, &keys);
196 delegate_->Remove(keys,
197 CacheModifyingCallback::Create(callback, &cache_, keys.DeepCopy()));
198 }
199
200 void ExtensionSettingsStorageCache::Clear(
201 ExtensionSettingsStorageCache::Callback* callback) {
202 cache_.Clear();
203 delegate_->Clear(CacheModifyingCallback::Create(callback, &cache_));
204 }
205
206 bool ExtensionSettingsStorageCache::GetFromCache(const std::string& key,
207 Value** value) {
208 Value* cached_value;
209 if (!cache_.Get(key, &cached_value)) {
210 return false;
211 }
212 *value = cached_value->DeepCopy();
213 return true;
214 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698