1// Copyright 2014 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 "components/invalidation/invalidator_storage.h"
6
7#include <string>
8#include <utility>
9
10#include "base/base64.h"
11#include "base/basictypes.h"
12#include "base/logging.h"
13#include "base/memory/scoped_ptr.h"
14#include "base/prefs/pref_registry_simple.h"
15#include "base/prefs/pref_service.h"
16#include "base/values.h"
17#include "components/invalidation/invalidation_prefs.h"
18#include "components/invalidation/unacked_invalidation_set.h"
19#include "components/pref_registry/pref_registry_syncable.h"
20#include "google/cacheinvalidation/types.pb.h"
21
22namespace {
23
24const char kInvalidatorMaxInvalidationVersions[] =
25    "invalidator.max_invalidation_versions";
26
27bool ValueToUnackedInvalidationStorageMap(
28    const base::ListValue& value,
29    syncer::UnackedInvalidationsMap* map) {
30  for (size_t i = 0; i != value.GetSize(); ++i) {
31    invalidation::ObjectId invalid_id;
32    syncer::UnackedInvalidationSet storage(invalid_id);
33    const base::DictionaryValue* dict;
34    if (!value.GetDictionary(i, &dict) || !storage.ResetFromValue(*dict)) {
35      DLOG(WARNING) << "Failed to parse ObjectState at position " << i;
36      return false;
37    }
38    map->insert(std::make_pair(storage.object_id(), storage));
39  }
40  return true;
41}
42
43scoped_ptr<base::ListValue> UnackedInvalidationStorageMapToValue(
44    const syncer::UnackedInvalidationsMap& map) {
45  scoped_ptr<base::ListValue> value(new base::ListValue);
46  for (syncer::UnackedInvalidationsMap::const_iterator it = map.begin();
47       it != map.end(); ++it) {
48    value->Append(it->second.ToValue().release());
49  }
50  return value.Pass();
51}
52
53}  // namespace
54
55namespace invalidation {
56
57// static
58void InvalidatorStorage::RegisterProfilePrefs(
59    user_prefs::PrefRegistrySyncable* registry) {
60  registry->RegisterListPref(prefs::kInvalidatorSavedInvalidations,
61                             user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
62  registry->RegisterStringPref(
63      prefs::kInvalidatorInvalidationState,
64      std::string(),
65      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
66  registry->RegisterStringPref(
67      prefs::kInvalidatorClientId,
68      std::string(),
69      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
70
71  // This pref is obsolete.  We register it so we can clear it.
72  // At some point in the future, it will be safe to remove this.
73  registry->RegisterListPref(kInvalidatorMaxInvalidationVersions,
74                             user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
75}
76
77// static
78void InvalidatorStorage::RegisterPrefs(PrefRegistrySimple* registry) {
79  registry->RegisterListPref(prefs::kInvalidatorSavedInvalidations);
80  registry->RegisterStringPref(prefs::kInvalidatorInvalidationState,
81                               std::string());
82  registry->RegisterStringPref(prefs::kInvalidatorClientId, std::string());
83}
84
85InvalidatorStorage::InvalidatorStorage(PrefService* pref_service)
86    : pref_service_(pref_service) {
87  DCHECK(pref_service_);
88  if (pref_service_->FindPreference(kInvalidatorMaxInvalidationVersions))
89    pref_service_->ClearPref(kInvalidatorMaxInvalidationVersions);
90}
91
92InvalidatorStorage::~InvalidatorStorage() {
93}
94
95void InvalidatorStorage::ClearAndSetNewClientId(const std::string& client_id) {
96  DCHECK(thread_checker_.CalledOnValidThread());
97  Clear();  // We can't reuse our old invalidation state if the ID changes.
98  pref_service_->SetString(prefs::kInvalidatorClientId, client_id);
99}
100
101std::string InvalidatorStorage::GetInvalidatorClientId() const {
102  return pref_service_->GetString(prefs::kInvalidatorClientId);
103}
104
105void InvalidatorStorage::SetBootstrapData(const std::string& data) {
106  DCHECK(thread_checker_.CalledOnValidThread());
107  std::string base64_data;
108  base::Base64Encode(data, &base64_data);
109  pref_service_->SetString(prefs::kInvalidatorInvalidationState,
110                           base64_data);
111}
112
113std::string InvalidatorStorage::GetBootstrapData() const {
114  std::string base64_data(
115      pref_service_->GetString(prefs::kInvalidatorInvalidationState));
116  std::string data;
117  base::Base64Decode(base64_data, &data);
118  return data;
119}
120
121void InvalidatorStorage::SetSavedInvalidations(
122      const syncer::UnackedInvalidationsMap& map) {
123  scoped_ptr<base::ListValue> value(UnackedInvalidationStorageMapToValue(map));
124  pref_service_->Set(prefs::kInvalidatorSavedInvalidations, *value.get());
125}
126
127syncer::UnackedInvalidationsMap
128InvalidatorStorage::GetSavedInvalidations() const {
129  syncer::UnackedInvalidationsMap map;
130  const base::ListValue* value =
131      pref_service_->GetList(prefs::kInvalidatorSavedInvalidations);
132  if (!ValueToUnackedInvalidationStorageMap(*value, &map)) {
133    return syncer::UnackedInvalidationsMap();
134  } else {
135    return map;
136  }
137}
138
139void InvalidatorStorage::Clear() {
140  DCHECK(thread_checker_.CalledOnValidThread());
141  pref_service_->ClearPref(prefs::kInvalidatorSavedInvalidations);
142  pref_service_->ClearPref(prefs::kInvalidatorClientId);
143  pref_service_->ClearPref(prefs::kInvalidatorInvalidationState);
144}
145
146}  // namespace invalidation
147