Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / extensions / api / storage / syncable_settings_storage.cc
1 // Copyright (c) 2012 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/api/storage/syncable_settings_storage.h"
6
7 #include "base/strings/stringprintf.h"
8 #include "chrome/browser/extensions/api/storage/settings_sync_processor.h"
9 #include "chrome/browser/extensions/api/storage/settings_sync_util.h"
10 #include "content/public/browser/browser_thread.h"
11 #include "extensions/browser/api/storage/settings_namespace.h"
12 #include "sync/api/sync_data.h"
13 #include "sync/protocol/extension_setting_specifics.pb.h"
14
15 namespace extensions {
16
17 using content::BrowserThread;
18
19 SyncableSettingsStorage::SyncableSettingsStorage(
20     const scoped_refptr<ObserverListThreadSafe<SettingsObserver> >&
21         observers,
22     const std::string& extension_id,
23     ValueStore* delegate,
24     syncer::ModelType sync_type,
25     const syncer::SyncableService::StartSyncFlare& flare)
26     : observers_(observers),
27       extension_id_(extension_id),
28       delegate_(delegate),
29       sync_type_(sync_type),
30       flare_(flare) {
31   DCHECK_CURRENTLY_ON(BrowserThread::FILE);
32 }
33
34 SyncableSettingsStorage::~SyncableSettingsStorage() {
35   DCHECK_CURRENTLY_ON(BrowserThread::FILE);
36 }
37
38 size_t SyncableSettingsStorage::GetBytesInUse(const std::string& key) {
39   DCHECK_CURRENTLY_ON(BrowserThread::FILE);
40   return delegate_->GetBytesInUse(key);
41 }
42
43 size_t SyncableSettingsStorage::GetBytesInUse(
44     const std::vector<std::string>& keys) {
45   DCHECK_CURRENTLY_ON(BrowserThread::FILE);
46   return delegate_->GetBytesInUse(keys);
47 }
48
49 size_t SyncableSettingsStorage::GetBytesInUse() {
50   DCHECK_CURRENTLY_ON(BrowserThread::FILE);
51   return delegate_->GetBytesInUse();
52 }
53
54 ValueStore::ReadResult SyncableSettingsStorage::Get(
55     const std::string& key) {
56   DCHECK_CURRENTLY_ON(BrowserThread::FILE);
57   return delegate_->Get(key);
58 }
59
60 ValueStore::ReadResult SyncableSettingsStorage::Get(
61     const std::vector<std::string>& keys) {
62   DCHECK_CURRENTLY_ON(BrowserThread::FILE);
63   return delegate_->Get(keys);
64 }
65
66 ValueStore::ReadResult SyncableSettingsStorage::Get() {
67   DCHECK_CURRENTLY_ON(BrowserThread::FILE);
68   return delegate_->Get();
69 }
70
71 ValueStore::WriteResult SyncableSettingsStorage::Set(
72     WriteOptions options, const std::string& key, const base::Value& value) {
73   DCHECK_CURRENTLY_ON(BrowserThread::FILE);
74   WriteResult result = delegate_->Set(options, key, value);
75   if (result->HasError()) {
76     return result.Pass();
77   }
78   SyncResultIfEnabled(result);
79   return result.Pass();
80 }
81
82 ValueStore::WriteResult SyncableSettingsStorage::Set(
83     WriteOptions options, const base::DictionaryValue& values) {
84   DCHECK_CURRENTLY_ON(BrowserThread::FILE);
85   WriteResult result = delegate_->Set(options, values);
86   if (result->HasError()) {
87     return result.Pass();
88   }
89   SyncResultIfEnabled(result);
90   return result.Pass();
91 }
92
93 ValueStore::WriteResult SyncableSettingsStorage::Remove(
94     const std::string& key) {
95   DCHECK_CURRENTLY_ON(BrowserThread::FILE);
96   WriteResult result = delegate_->Remove(key);
97   if (result->HasError()) {
98     return result.Pass();
99   }
100   SyncResultIfEnabled(result);
101   return result.Pass();
102 }
103
104 ValueStore::WriteResult SyncableSettingsStorage::Remove(
105     const std::vector<std::string>& keys) {
106   DCHECK_CURRENTLY_ON(BrowserThread::FILE);
107   WriteResult result = delegate_->Remove(keys);
108   if (result->HasError()) {
109     return result.Pass();
110   }
111   SyncResultIfEnabled(result);
112   return result.Pass();
113 }
114
115 ValueStore::WriteResult SyncableSettingsStorage::Clear() {
116   DCHECK_CURRENTLY_ON(BrowserThread::FILE);
117   WriteResult result = delegate_->Clear();
118   if (result->HasError()) {
119     return result.Pass();
120   }
121   SyncResultIfEnabled(result);
122   return result.Pass();
123 }
124
125 bool SyncableSettingsStorage::Restore() {
126   // If we're syncing, stop - we don't want to push the deletion of any data.
127   // At next startup, when we start up the sync service, we'll get back any
128   // data which was stored intact on Sync.
129   // TODO (rdevlin.cronin): Investigate if there's a way we can trigger
130   // MergeDataAndStartSyncing() to immediately get back any data we can,
131   // and continue syncing.
132   StopSyncing();
133   return delegate_->Restore();
134 }
135
136 bool SyncableSettingsStorage::RestoreKey(const std::string& key) {
137   // If we're syncing, stop - we don't want to push the deletion of any data.
138   // At next startup, when we start up the sync service, we'll get back any
139   // data which was stored intact on Sync.
140   // TODO (rdevlin.cronin): Investigate if there's a way we can trigger
141   // MergeDataAndStartSyncing() to immediately get back any data we can,
142   // and continue syncing.
143   StopSyncing();
144   return delegate_->RestoreKey(key);
145 }
146
147 void SyncableSettingsStorage::SyncResultIfEnabled(
148     const ValueStore::WriteResult& result) {
149   if (result->changes().empty())
150     return;
151
152   if (sync_processor_.get()) {
153     syncer::SyncError error = sync_processor_->SendChanges(result->changes());
154     if (error.IsSet())
155       StopSyncing();
156   } else {
157     // Tell sync to try and start soon, because syncable changes to sync_type_
158     // have started happening. This will cause sync to call us back
159     // asynchronously via StartSyncing(...) as soon as possible.
160     flare_.Run(sync_type_);
161   }
162 }
163
164 // Sync-related methods.
165
166 syncer::SyncError SyncableSettingsStorage::StartSyncing(
167     const base::DictionaryValue& sync_state,
168     scoped_ptr<SettingsSyncProcessor> sync_processor) {
169   DCHECK_CURRENTLY_ON(BrowserThread::FILE);
170   DCHECK(!sync_processor_.get());
171
172   sync_processor_ = sync_processor.Pass();
173   sync_processor_->Init(sync_state);
174
175   ReadResult maybe_settings = delegate_->Get();
176   if (maybe_settings->HasError()) {
177     return syncer::SyncError(
178         FROM_HERE,
179         syncer::SyncError::DATATYPE_ERROR,
180         base::StringPrintf("Failed to get settings: %s",
181             maybe_settings->error().message.c_str()),
182         sync_processor_->type());
183   }
184
185   const base::DictionaryValue& settings = maybe_settings->settings();
186   return sync_state.empty() ?
187       SendLocalSettingsToSync(settings) :
188       OverwriteLocalSettingsWithSync(sync_state, settings);
189 }
190
191 syncer::SyncError SyncableSettingsStorage::SendLocalSettingsToSync(
192     const base::DictionaryValue& settings) {
193   DCHECK_CURRENTLY_ON(BrowserThread::FILE);
194
195   ValueStoreChangeList changes;
196   for (base::DictionaryValue::Iterator i(settings); !i.IsAtEnd(); i.Advance()) {
197     changes.push_back(ValueStoreChange(i.key(), NULL, i.value().DeepCopy()));
198   }
199
200   if (changes.empty())
201     return syncer::SyncError();
202
203   syncer::SyncError error = sync_processor_->SendChanges(changes);
204   if (error.IsSet())
205     StopSyncing();
206
207   return error;
208 }
209
210 syncer::SyncError SyncableSettingsStorage::OverwriteLocalSettingsWithSync(
211     const base::DictionaryValue& sync_state,
212     const base::DictionaryValue& settings) {
213   DCHECK_CURRENTLY_ON(BrowserThread::FILE);
214   // Treat this as a list of changes to sync and use ProcessSyncChanges.
215   // This gives notifications etc for free.
216   scoped_ptr<base::DictionaryValue> new_sync_state(sync_state.DeepCopy());
217
218   SettingSyncDataList changes;
219   for (base::DictionaryValue::Iterator it(settings);
220        !it.IsAtEnd(); it.Advance()) {
221     scoped_ptr<base::Value> sync_value;
222     if (new_sync_state->RemoveWithoutPathExpansion(it.key(), &sync_value)) {
223       if (sync_value->Equals(&it.value())) {
224         // Sync and local values are the same, no changes to send.
225       } else {
226         // Sync value is different, update local setting with new value.
227         changes.push_back(
228             SettingSyncData(
229                 syncer::SyncChange::ACTION_UPDATE,
230                 extension_id_,
231                 it.key(),
232                 sync_value.Pass()));
233       }
234     } else {
235       // Not synced, delete local setting.
236       changes.push_back(
237           SettingSyncData(
238               syncer::SyncChange::ACTION_DELETE,
239               extension_id_,
240               it.key(),
241               scoped_ptr<base::Value>(new base::DictionaryValue())));
242     }
243   }
244
245   // Add all new settings to local settings.
246   while (!new_sync_state->empty()) {
247     base::DictionaryValue::Iterator first_entry(*new_sync_state);
248     std::string key = first_entry.key();
249     scoped_ptr<base::Value> value;
250     CHECK(new_sync_state->RemoveWithoutPathExpansion(key, &value));
251     changes.push_back(
252         SettingSyncData(
253             syncer::SyncChange::ACTION_ADD,
254             extension_id_,
255             key,
256             value.Pass()));
257   }
258
259   if (changes.empty())
260     return syncer::SyncError();
261
262   return ProcessSyncChanges(changes);
263 }
264
265 void SyncableSettingsStorage::StopSyncing() {
266   DCHECK_CURRENTLY_ON(BrowserThread::FILE);
267   sync_processor_.reset();
268 }
269
270 syncer::SyncError SyncableSettingsStorage::ProcessSyncChanges(
271     const SettingSyncDataList& sync_changes) {
272   DCHECK_CURRENTLY_ON(BrowserThread::FILE);
273   DCHECK(!sync_changes.empty()) << "No sync changes for " << extension_id_;
274
275   if (!sync_processor_.get()) {
276     return syncer::SyncError(
277         FROM_HERE,
278         syncer::SyncError::DATATYPE_ERROR,
279         std::string("Sync is inactive for ") + extension_id_,
280         syncer::UNSPECIFIED);
281   }
282
283   std::vector<syncer::SyncError> errors;
284   ValueStoreChangeList changes;
285
286   for (SettingSyncDataList::const_iterator it = sync_changes.begin();
287       it != sync_changes.end(); ++it) {
288     DCHECK_EQ(extension_id_, it->extension_id());
289
290     const std::string& key = it->key();
291     const base::Value& value = it->value();
292
293     scoped_ptr<base::Value> current_value;
294     {
295       ReadResult maybe_settings = Get(it->key());
296       if (maybe_settings->HasError()) {
297         errors.push_back(syncer::SyncError(
298             FROM_HERE,
299             syncer::SyncError::DATATYPE_ERROR,
300             base::StringPrintf("Error getting current sync state for %s/%s: %s",
301                 extension_id_.c_str(), key.c_str(),
302                 maybe_settings->error().message.c_str()),
303             sync_processor_->type()));
304         continue;
305       }
306       maybe_settings->settings().RemoveWithoutPathExpansion(key,
307                                                             &current_value);
308     }
309
310     syncer::SyncError error;
311
312     switch (it->change_type()) {
313       case syncer::SyncChange::ACTION_ADD:
314         if (!current_value.get()) {
315           error = OnSyncAdd(key, value.DeepCopy(), &changes);
316         } else {
317           // Already a value; hopefully a local change has beaten sync in a
318           // race and it's not a bug, so pretend it's an update.
319           LOG(WARNING) << "Got add from sync for existing setting " <<
320               extension_id_ << "/" << key;
321           error = OnSyncUpdate(
322               key, current_value.release(), value.DeepCopy(), &changes);
323         }
324         break;
325
326       case syncer::SyncChange::ACTION_UPDATE:
327         if (current_value.get()) {
328           error = OnSyncUpdate(
329               key, current_value.release(), value.DeepCopy(), &changes);
330         } else {
331           // Similarly, pretend it's an add.
332           LOG(WARNING) << "Got update from sync for nonexistent setting" <<
333               extension_id_ << "/" << key;
334           error = OnSyncAdd(key, value.DeepCopy(), &changes);
335         }
336         break;
337
338       case syncer::SyncChange::ACTION_DELETE:
339         if (current_value.get()) {
340           error = OnSyncDelete(key, current_value.release(), &changes);
341         } else {
342           // Similarly, ignore it.
343           LOG(WARNING) << "Got delete from sync for nonexistent setting " <<
344               extension_id_ << "/" << key;
345         }
346         break;
347
348       default:
349         NOTREACHED();
350     }
351
352     if (error.IsSet()) {
353       errors.push_back(error);
354     }
355   }
356
357   sync_processor_->NotifyChanges(changes);
358
359   observers_->Notify(
360       &SettingsObserver::OnSettingsChanged,
361       extension_id_,
362       settings_namespace::SYNC,
363       ValueStoreChange::ToJson(changes));
364
365   // TODO(kalman): Something sensible with multiple errors.
366   return errors.empty() ? syncer::SyncError() : errors[0];
367 }
368
369 syncer::SyncError SyncableSettingsStorage::OnSyncAdd(
370     const std::string& key,
371     base::Value* new_value,
372     ValueStoreChangeList* changes) {
373   DCHECK(new_value);
374   WriteResult result = delegate_->Set(IGNORE_QUOTA, key, *new_value);
375   if (result->HasError()) {
376     return syncer::SyncError(
377         FROM_HERE,
378         syncer::SyncError::DATATYPE_ERROR,
379         base::StringPrintf("Error pushing sync add to local settings: %s",
380             result->error().message.c_str()),
381         sync_processor_->type());
382   }
383   changes->push_back(ValueStoreChange(key, NULL, new_value));
384   return syncer::SyncError();
385 }
386
387 syncer::SyncError SyncableSettingsStorage::OnSyncUpdate(
388     const std::string& key,
389     base::Value* old_value,
390     base::Value* new_value,
391     ValueStoreChangeList* changes) {
392   DCHECK(old_value);
393   DCHECK(new_value);
394   WriteResult result = delegate_->Set(IGNORE_QUOTA, key, *new_value);
395   if (result->HasError()) {
396     return syncer::SyncError(
397         FROM_HERE,
398         syncer::SyncError::DATATYPE_ERROR,
399         base::StringPrintf("Error pushing sync update to local settings: %s",
400             result->error().message.c_str()),
401         sync_processor_->type());
402   }
403   changes->push_back(ValueStoreChange(key, old_value, new_value));
404   return syncer::SyncError();
405 }
406
407 syncer::SyncError SyncableSettingsStorage::OnSyncDelete(
408     const std::string& key,
409     base::Value* old_value,
410     ValueStoreChangeList* changes) {
411   DCHECK(old_value);
412   WriteResult result = delegate_->Remove(key);
413   if (result->HasError()) {
414     return syncer::SyncError(
415         FROM_HERE,
416         syncer::SyncError::DATATYPE_ERROR,
417         base::StringPrintf("Error pushing sync remove to local settings: %s",
418             result->error().message.c_str()),
419         sync_processor_->type());
420   }
421   changes->push_back(ValueStoreChange(key, old_value, NULL));
422   return syncer::SyncError();
423 }
424
425 }  // namespace extensions