pref_value_store.cc revision 5af4e3efaa07e1369024c188538dcf582ed5a21e
1// Copyright (c) 2010 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/prefs/pref_value_store.h"
6
7#ifdef ANDROID
8#include "base/logging.h"
9#endif
10#include "chrome/browser/prefs/pref_notifier.h"
11
12PrefValueStore::PrefStoreKeeper::PrefStoreKeeper()
13    : pref_value_store_(NULL),
14      type_(PrefValueStore::INVALID_STORE) {
15}
16
17PrefValueStore::PrefStoreKeeper::~PrefStoreKeeper() {
18  if (pref_store_.get())
19    pref_store_->RemoveObserver(this);
20}
21
22void PrefValueStore::PrefStoreKeeper::Initialize(
23    PrefValueStore* store,
24    PrefStore* pref_store,
25    PrefValueStore::PrefStoreType type) {
26  if (pref_store_.get())
27    pref_store_->RemoveObserver(this);
28  type_ = type;
29  pref_value_store_ = store;
30  pref_store_.reset(pref_store);
31  if (pref_store_.get())
32    pref_store_->AddObserver(this);
33}
34
35void PrefValueStore::PrefStoreKeeper::OnPrefValueChanged(
36    const std::string& key) {
37  pref_value_store_->OnPrefValueChanged(type_, key);
38}
39
40void PrefValueStore::PrefStoreKeeper::OnInitializationCompleted() {
41  pref_value_store_->OnInitializationCompleted(type_);
42}
43
44PrefValueStore::PrefValueStore(PrefStore* managed_platform_prefs,
45                               PrefStore* device_management_prefs,
46                               PrefStore* extension_prefs,
47                               PrefStore* command_line_prefs,
48                               PrefStore* user_prefs,
49                               PrefStore* recommended_prefs,
50                               PrefStore* default_prefs,
51                               PrefNotifier* pref_notifier)
52    : pref_notifier_(pref_notifier) {
53  InitPrefStore(MANAGED_PLATFORM_STORE, managed_platform_prefs);
54  InitPrefStore(DEVICE_MANAGEMENT_STORE, device_management_prefs);
55  InitPrefStore(EXTENSION_STORE, extension_prefs);
56  InitPrefStore(COMMAND_LINE_STORE, command_line_prefs);
57  InitPrefStore(USER_STORE, user_prefs);
58  InitPrefStore(RECOMMENDED_STORE, recommended_prefs);
59  InitPrefStore(DEFAULT_STORE, default_prefs);
60
61  CheckInitializationCompleted();
62}
63
64PrefValueStore::~PrefValueStore() {}
65
66bool PrefValueStore::GetValue(const std::string& name,
67                              Value** out_value) const {
68  // Check the |PrefStore|s in order of their priority from highest to lowest
69  // to find the value of the preference described by the given preference name.
70  for (size_t i = 0; i <= PREF_STORE_TYPE_MAX; ++i) {
71    if (GetValueFromStore(name.c_str(), static_cast<PrefStoreType>(i),
72                          out_value))
73      return true;
74  }
75  return false;
76}
77
78void PrefValueStore::RegisterPreferenceType(const std::string& name,
79                                            Value::ValueType type) {
80  pref_types_[name] = type;
81}
82
83Value::ValueType PrefValueStore::GetRegisteredType(
84    const std::string& name) const {
85  PrefTypeMap::const_iterator found = pref_types_.find(name);
86  if (found == pref_types_.end())
87    return Value::TYPE_NULL;
88  return found->second;
89}
90
91bool PrefValueStore::HasPrefPath(const char* path) const {
92  Value* tmp_value = NULL;
93  const std::string name(path);
94  bool rv = GetValue(name, &tmp_value);
95  // Merely registering a pref doesn't count as "having" it: we require a
96  // non-default value set.
97  return rv && !PrefValueFromDefaultStore(path);
98}
99
100void PrefValueStore::NotifyPrefChanged(
101    const char* path,
102    PrefValueStore::PrefStoreType new_store) {
103  DCHECK(new_store != INVALID_STORE);
104
105  // If this pref is not registered, just discard the notification.
106  if (!pref_types_.count(path))
107    return;
108
109  bool changed = true;
110  // Replying that the pref has changed in case the new store is invalid may
111  // cause problems, but it's the safer choice.
112  if (new_store != INVALID_STORE) {
113    PrefStoreType controller = ControllingPrefStoreForPref(path);
114    DCHECK(controller != INVALID_STORE);
115    // If the pref is controlled by a higher-priority store, its effective value
116    // cannot have changed.
117    if (controller != INVALID_STORE &&
118        controller < new_store) {
119      changed = false;
120    }
121  }
122
123  if (changed)
124    pref_notifier_->OnPreferenceChanged(path);
125}
126
127bool PrefValueStore::PrefValueInManagedPlatformStore(const char* name) const {
128  return PrefValueInStore(name, MANAGED_PLATFORM_STORE);
129}
130
131bool PrefValueStore::PrefValueInDeviceManagementStore(const char* name) const {
132  return PrefValueInStore(name, DEVICE_MANAGEMENT_STORE);
133}
134
135bool PrefValueStore::PrefValueInExtensionStore(const char* name) const {
136  return PrefValueInStore(name, EXTENSION_STORE);
137}
138
139bool PrefValueStore::PrefValueInUserStore(const char* name) const {
140  return PrefValueInStore(name, USER_STORE);
141}
142
143bool PrefValueStore::PrefValueFromExtensionStore(const char* name) const {
144  return ControllingPrefStoreForPref(name) == EXTENSION_STORE;
145}
146
147bool PrefValueStore::PrefValueFromUserStore(const char* name) const {
148  return ControllingPrefStoreForPref(name) == USER_STORE;
149}
150
151bool PrefValueStore::PrefValueFromDefaultStore(const char* name) const {
152  return ControllingPrefStoreForPref(name) == DEFAULT_STORE;
153}
154
155bool PrefValueStore::PrefValueUserModifiable(const char* name) const {
156  PrefStoreType effective_store = ControllingPrefStoreForPref(name);
157  return effective_store >= USER_STORE ||
158         effective_store == INVALID_STORE;
159}
160
161// Returns true if the actual value is a valid type for the expected type when
162// found in the given store.
163bool PrefValueStore::IsValidType(Value::ValueType expected,
164                                 Value::ValueType actual,
165                                 PrefValueStore::PrefStoreType store) {
166  if (expected == actual)
167    return true;
168
169  // Dictionaries and lists are allowed to hold TYPE_NULL values too, but only
170  // in the default pref store.
171  if (store == DEFAULT_STORE &&
172      actual == Value::TYPE_NULL &&
173      (expected == Value::TYPE_DICTIONARY || expected == Value::TYPE_LIST)) {
174    return true;
175  }
176  return false;
177}
178
179bool PrefValueStore::PrefValueInStore(
180    const char* name,
181    PrefValueStore::PrefStoreType store) const {
182  // Declare a temp Value* and call GetValueFromStore,
183  // ignoring the output value.
184  Value* tmp_value = NULL;
185  return GetValueFromStore(name, store, &tmp_value);
186}
187
188bool PrefValueStore::PrefValueInStoreRange(
189    const char* name,
190    PrefValueStore::PrefStoreType first_checked_store,
191    PrefValueStore::PrefStoreType last_checked_store) const {
192  if (first_checked_store > last_checked_store) {
193    NOTREACHED();
194    return false;
195  }
196
197  for (size_t i = first_checked_store;
198       i <= static_cast<size_t>(last_checked_store); ++i) {
199    if (PrefValueInStore(name, static_cast<PrefStoreType>(i)))
200      return true;
201  }
202  return false;
203}
204
205PrefValueStore::PrefStoreType PrefValueStore::ControllingPrefStoreForPref(
206    const char* name) const {
207  for (size_t i = 0; i <= PREF_STORE_TYPE_MAX; ++i) {
208    if (PrefValueInStore(name, static_cast<PrefStoreType>(i)))
209      return static_cast<PrefStoreType>(i);
210  }
211  return INVALID_STORE;
212}
213
214bool PrefValueStore::GetValueFromStore(const char* name,
215                                       PrefValueStore::PrefStoreType store_type,
216                                       Value** out_value) const {
217  // Only return true if we find a value and it is the correct type, so stale
218  // values with the incorrect type will be ignored.
219  const PrefStore* store = GetPrefStore(static_cast<PrefStoreType>(store_type));
220  if (store) {
221    switch (store->GetValue(name, out_value)) {
222      case PrefStore::READ_USE_DEFAULT:
223        store = GetPrefStore(DEFAULT_STORE);
224        if (!store || store->GetValue(name, out_value) != PrefStore::READ_OK) {
225          *out_value = NULL;
226          return false;
227        }
228        // Fall through...
229      case PrefStore::READ_OK:
230        if (IsValidType(GetRegisteredType(name),
231                        (*out_value)->GetType(),
232                        store_type)) {
233          return true;
234        }
235        break;
236      case PrefStore::READ_NO_VALUE:
237        break;
238    }
239  }
240
241  // No valid value found for the given preference name: set the return false.
242  *out_value = NULL;
243  return false;
244}
245
246void PrefValueStore::OnPrefValueChanged(PrefValueStore::PrefStoreType type,
247                                        const std::string& key) {
248  NotifyPrefChanged(key.c_str(), type);
249}
250
251void PrefValueStore::OnInitializationCompleted(
252    PrefValueStore::PrefStoreType type) {
253  CheckInitializationCompleted();
254}
255
256void PrefValueStore::InitPrefStore(PrefValueStore::PrefStoreType type,
257                                   PrefStore* pref_store) {
258  pref_stores_[type].Initialize(this, pref_store, type);
259}
260
261void PrefValueStore::CheckInitializationCompleted() {
262  for (size_t i = 0; i <= PREF_STORE_TYPE_MAX; ++i) {
263    PrefStore* store = GetPrefStore(static_cast<PrefStoreType>(i));
264    if (store && !store->IsInitializationComplete())
265      return;
266  }
267  pref_notifier_->OnInitializationCompleted();
268}
269