// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/prefs/pref_value_store.h"
#include "base/logging.h"
#include "base/prefs/pref_notifier.h"
#include "base/prefs/pref_observer.h"
PrefValueStore::PrefStoreKeeper::PrefStoreKeeper()
: pref_value_store_(NULL),
type_(PrefValueStore::INVALID_STORE) {
}
PrefValueStore::PrefStoreKeeper::~PrefStoreKeeper() {
if (pref_store_.get()) {
pref_store_->RemoveObserver(this);
pref_store_ = NULL;
}
pref_value_store_ = NULL;
}
void PrefValueStore::PrefStoreKeeper::Initialize(
PrefValueStore* store,
PrefStore* pref_store,
PrefValueStore::PrefStoreType type) {
if (pref_store_.get()) {
pref_store_->RemoveObserver(this);
DCHECK(!pref_store_->HasObservers());
}
type_ = type;
pref_value_store_ = store;
pref_store_ = pref_store;
if (pref_store_.get())
pref_store_->AddObserver(this);
}
void PrefValueStore::PrefStoreKeeper::OnPrefValueChanged(
const std::string& key) {
pref_value_store_->OnPrefValueChanged(type_, key);
}
void PrefValueStore::PrefStoreKeeper::OnInitializationCompleted(
bool succeeded) {
pref_value_store_->OnInitializationCompleted(type_, succeeded);
}
PrefValueStore::PrefValueStore(PrefStore* managed_prefs,
PrefStore* supervised_user_prefs,
PrefStore* extension_prefs,
PrefStore* command_line_prefs,
PrefStore* user_prefs,
PrefStore* recommended_prefs,
PrefStore* default_prefs,
PrefNotifier* pref_notifier)
: pref_notifier_(pref_notifier),
initialization_failed_(false) {
InitPrefStore(MANAGED_STORE, managed_prefs);
InitPrefStore(SUPERVISED_USER_STORE, supervised_user_prefs);
InitPrefStore(EXTENSION_STORE, extension_prefs);
InitPrefStore(COMMAND_LINE_STORE, command_line_prefs);
InitPrefStore(USER_STORE, user_prefs);
InitPrefStore(RECOMMENDED_STORE, recommended_prefs);
InitPrefStore(DEFAULT_STORE, default_prefs);
CheckInitializationCompleted();
}
PrefValueStore::~PrefValueStore() {}
PrefValueStore* PrefValueStore::CloneAndSpecialize(
PrefStore* managed_prefs,
PrefStore* supervised_user_prefs,
PrefStore* extension_prefs,
PrefStore* command_line_prefs,
PrefStore* user_prefs,
PrefStore* recommended_prefs,
PrefStore* default_prefs,
PrefNotifier* pref_notifier) {
DCHECK(pref_notifier);
if (!managed_prefs)
managed_prefs = GetPrefStore(MANAGED_STORE);
if (!supervised_user_prefs)
supervised_user_prefs = GetPrefStore(SUPERVISED_USER_STORE);
if (!extension_prefs)
extension_prefs = GetPrefStore(EXTENSION_STORE);
if (!command_line_prefs)
command_line_prefs = GetPrefStore(COMMAND_LINE_STORE);
if (!user_prefs)
user_prefs = GetPrefStore(USER_STORE);
if (!recommended_prefs)
recommended_prefs = GetPrefStore(RECOMMENDED_STORE);
if (!default_prefs)
default_prefs = GetPrefStore(DEFAULT_STORE);
return new PrefValueStore(
managed_prefs, supervised_user_prefs, extension_prefs, command_line_prefs,
user_prefs, recommended_prefs, default_prefs, pref_notifier);
}
void PrefValueStore::set_callback(const PrefChangedCallback& callback) {
pref_changed_callback_ = callback;
}
bool PrefValueStore::GetValue(const std::string& name,
base::Value::Type type,
const base::Value** out_value) const {
// Check the |PrefStore|s in order of their priority from highest to lowest,
// looking for the first preference value with the given |name| and |type|.
for (size_t i = 0; i <= PREF_STORE_TYPE_MAX; ++i) {
if (GetValueFromStoreWithType(name.c_str(), type,
static_cast<PrefStoreType>(i), out_value))
return true;
}
return false;
}
bool PrefValueStore::GetRecommendedValue(const std::string& name,
base::Value::Type type,
const base::Value** out_value) const {
return GetValueFromStoreWithType(name.c_str(), type, RECOMMENDED_STORE,
out_value);
}
void PrefValueStore::NotifyPrefChanged(
const char* path,
PrefValueStore::PrefStoreType new_store) {
DCHECK(new_store != INVALID_STORE);
// A notification is sent when the pref value in any store changes. If this
// store is currently being overridden by a higher-priority store, the
// effective value of the pref will not have changed.
pref_notifier_->OnPreferenceChanged(path);
if (!pref_changed_callback_.is_null())
pref_changed_callback_.Run(path);
}
bool PrefValueStore::PrefValueInManagedStore(const char* name) const {
return PrefValueInStore(name, MANAGED_STORE);
}
bool PrefValueStore::PrefValueInExtensionStore(const char* name) const {
return PrefValueInStore(name, EXTENSION_STORE);
}
bool PrefValueStore::PrefValueInUserStore(const char* name) const {
return PrefValueInStore(name, USER_STORE);
}
bool PrefValueStore::PrefValueFromExtensionStore(const char* name) const {
return ControllingPrefStoreForPref(name) == EXTENSION_STORE;
}
bool PrefValueStore::PrefValueFromUserStore(const char* name) const {
return ControllingPrefStoreForPref(name) == USER_STORE;
}
bool PrefValueStore::PrefValueFromRecommendedStore(const char* name) const {
return ControllingPrefStoreForPref(name) == RECOMMENDED_STORE;
}
bool PrefValueStore::PrefValueFromDefaultStore(const char* name) const {
return ControllingPrefStoreForPref(name) == DEFAULT_STORE;
}
bool PrefValueStore::PrefValueUserModifiable(const char* name) const {
PrefStoreType effective_store = ControllingPrefStoreForPref(name);
return effective_store >= USER_STORE ||
effective_store == INVALID_STORE;
}
bool PrefValueStore::PrefValueExtensionModifiable(const char* name) const {
PrefStoreType effective_store = ControllingPrefStoreForPref(name);
return effective_store >= EXTENSION_STORE ||
effective_store == INVALID_STORE;
}
void PrefValueStore::UpdateCommandLinePrefStore(PrefStore* command_line_prefs) {
InitPrefStore(COMMAND_LINE_STORE, command_line_prefs);
}
bool PrefValueStore::PrefValueInStore(
const char* name,
PrefValueStore::PrefStoreType store) const {
// Declare a temp Value* and call GetValueFromStore,
// ignoring the output value.
const base::Value* tmp_value = NULL;
return GetValueFromStore(name, store, &tmp_value);
}
bool PrefValueStore::PrefValueInStoreRange(
const char* name,
PrefValueStore::PrefStoreType first_checked_store,
PrefValueStore::PrefStoreType last_checked_store) const {
if (first_checked_store > last_checked_store) {
NOTREACHED();
return false;
}
for (size_t i = first_checked_store;
i <= static_cast<size_t>(last_checked_store); ++i) {
if (PrefValueInStore(name, static_cast<PrefStoreType>(i)))
return true;
}
return false;
}
PrefValueStore::PrefStoreType PrefValueStore::ControllingPrefStoreForPref(
const char* name) const {
for (size_t i = 0; i <= PREF_STORE_TYPE_MAX; ++i) {
if (PrefValueInStore(name, static_cast<PrefStoreType>(i)))
return static_cast<PrefStoreType>(i);
}
return INVALID_STORE;
}
bool PrefValueStore::GetValueFromStore(const char* name,
PrefValueStore::PrefStoreType store_type,
const base::Value** out_value) const {
// Only return true if we find a value and it is the correct type, so stale
// values with the incorrect type will be ignored.
const PrefStore* store = GetPrefStore(static_cast<PrefStoreType>(store_type));
if (store && store->GetValue(name, out_value))
return true;
// No valid value found for the given preference name: set the return value
// to false.
*out_value = NULL;
return false;
}
bool PrefValueStore::GetValueFromStoreWithType(
const char* name,
base::Value::Type type,
PrefStoreType store,
const base::Value** out_value) const {
if (GetValueFromStore(name, store, out_value)) {
if ((*out_value)->IsType(type))
return true;
LOG(WARNING) << "Expected type for " << name << " is " << type
<< " but got " << (*out_value)->GetType()
<< " in store " << store;
}
*out_value = NULL;
return false;
}
void PrefValueStore::OnPrefValueChanged(PrefValueStore::PrefStoreType type,
const std::string& key) {
NotifyPrefChanged(key.c_str(), type);
}
void PrefValueStore::OnInitializationCompleted(
PrefValueStore::PrefStoreType type, bool succeeded) {
if (initialization_failed_)
return;
if (!succeeded) {
initialization_failed_ = true;
pref_notifier_->OnInitializationCompleted(false);
return;
}
CheckInitializationCompleted();
}
void PrefValueStore::InitPrefStore(PrefValueStore::PrefStoreType type,
PrefStore* pref_store) {
pref_stores_[type].Initialize(this, pref_store, type);
}
void PrefValueStore::CheckInitializationCompleted() {
if (initialization_failed_)
return;
for (size_t i = 0; i <= PREF_STORE_TYPE_MAX; ++i) {
scoped_refptr<PrefStore> store =
GetPrefStore(static_cast<PrefStoreType>(i));
if (store.get() && !store->IsInitializationComplete())
return;
}
pref_notifier_->OnInitializationCompleted(true);
}