Fix crash on app list start page contents not existing.
[chromium-blink-merge.git] / components / policy / core / common / schema_registry.cc
blob705df7bdd6014e26900db8963ee5548e8b721bef
1 // Copyright 2013 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.
5 #include "components/policy/core/common/schema_registry.h"
7 #include "base/logging.h"
9 namespace policy {
11 SchemaRegistry::Observer::~Observer() {}
13 SchemaRegistry::InternalObserver::~InternalObserver() {}
15 SchemaRegistry::SchemaRegistry() : schema_map_(new SchemaMap) {
16 for (int i = 0; i < POLICY_DOMAIN_SIZE; ++i)
17 domains_ready_[i] = false;
18 #if !defined(ENABLE_EXTENSIONS)
19 domains_ready_[POLICY_DOMAIN_EXTENSIONS] = true;
20 #endif
23 SchemaRegistry::~SchemaRegistry() {
24 FOR_EACH_OBSERVER(InternalObserver,
25 internal_observers_,
26 OnSchemaRegistryShuttingDown(this));
29 void SchemaRegistry::RegisterComponent(const PolicyNamespace& ns,
30 const Schema& schema) {
31 ComponentMap map;
32 map[ns.component_id] = schema;
33 RegisterComponents(ns.domain, map);
36 void SchemaRegistry::RegisterComponents(PolicyDomain domain,
37 const ComponentMap& components) {
38 // Don't issue notifications if nothing is being registered.
39 if (components.empty())
40 return;
41 // Assume that a schema was updated if the namespace was already registered
42 // before.
43 DomainMap map(schema_map_->GetDomains());
44 for (ComponentMap::const_iterator it = components.begin();
45 it != components.end(); ++it) {
46 map[domain][it->first] = it->second;
48 schema_map_ = new SchemaMap(map);
49 Notify(true);
52 void SchemaRegistry::UnregisterComponent(const PolicyNamespace& ns) {
53 DomainMap map(schema_map_->GetDomains());
54 if (map[ns.domain].erase(ns.component_id) != 0) {
55 schema_map_ = new SchemaMap(map);
56 Notify(false);
57 } else {
58 NOTREACHED();
62 bool SchemaRegistry::IsReady() const {
63 for (int i = 0; i < POLICY_DOMAIN_SIZE; ++i) {
64 if (!domains_ready_[i])
65 return false;
67 return true;
70 void SchemaRegistry::SetReady(PolicyDomain domain) {
71 if (domains_ready_[domain])
72 return;
73 domains_ready_[domain] = true;
74 if (IsReady())
75 FOR_EACH_OBSERVER(Observer, observers_, OnSchemaRegistryReady());
78 void SchemaRegistry::AddObserver(Observer* observer) {
79 observers_.AddObserver(observer);
82 void SchemaRegistry::RemoveObserver(Observer* observer) {
83 observers_.RemoveObserver(observer);
86 void SchemaRegistry::AddInternalObserver(InternalObserver* observer) {
87 internal_observers_.AddObserver(observer);
90 void SchemaRegistry::RemoveInternalObserver(InternalObserver* observer) {
91 internal_observers_.RemoveObserver(observer);
94 void SchemaRegistry::Notify(bool has_new_schemas) {
95 FOR_EACH_OBSERVER(
96 Observer, observers_, OnSchemaRegistryUpdated(has_new_schemas));
99 CombinedSchemaRegistry::CombinedSchemaRegistry()
100 : own_schema_map_(new SchemaMap) {
101 // The combined registry is always ready, since it can always start tracking
102 // another registry that is not ready yet and going from "ready" to "not
103 // ready" is not allowed.
104 for (int i = 0; i < POLICY_DOMAIN_SIZE; ++i)
105 SetReady(static_cast<PolicyDomain>(i));
108 CombinedSchemaRegistry::~CombinedSchemaRegistry() {}
110 void CombinedSchemaRegistry::Track(SchemaRegistry* registry) {
111 registries_.insert(registry);
112 registry->AddObserver(this);
113 registry->AddInternalObserver(this);
114 // Recombine the maps only if the |registry| has any components other than
115 // POLICY_DOMAIN_CHROME.
116 if (registry->schema_map()->HasComponents())
117 Combine(true);
120 void CombinedSchemaRegistry::RegisterComponents(
121 PolicyDomain domain,
122 const ComponentMap& components) {
123 DomainMap map(own_schema_map_->GetDomains());
124 for (ComponentMap::const_iterator it = components.begin();
125 it != components.end(); ++it) {
126 map[domain][it->first] = it->second;
128 own_schema_map_ = new SchemaMap(map);
129 Combine(true);
132 void CombinedSchemaRegistry::UnregisterComponent(const PolicyNamespace& ns) {
133 DomainMap map(own_schema_map_->GetDomains());
134 if (map[ns.domain].erase(ns.component_id) != 0) {
135 own_schema_map_ = new SchemaMap(map);
136 Combine(false);
137 } else {
138 NOTREACHED();
142 void CombinedSchemaRegistry::OnSchemaRegistryUpdated(bool has_new_schemas) {
143 Combine(has_new_schemas);
146 void CombinedSchemaRegistry::OnSchemaRegistryReady() {
147 // Ignore.
150 void CombinedSchemaRegistry::OnSchemaRegistryShuttingDown(
151 SchemaRegistry* registry) {
152 registry->RemoveObserver(this);
153 registry->RemoveInternalObserver(this);
154 if (registries_.erase(registry) != 0) {
155 if (registry->schema_map()->HasComponents())
156 Combine(false);
157 } else {
158 NOTREACHED();
162 void CombinedSchemaRegistry::Combine(bool has_new_schemas) {
163 // If two registries publish a Schema for the same component then it's
164 // undefined which version gets in the combined registry.
166 // The common case is that both registries want policy for the same component,
167 // and the Schemas should be the same; in that case this makes no difference.
169 // But if the Schemas are different then one of the components is out of date.
170 // In that case the policy loaded will be valid only for one of them, until
171 // the outdated components are updated. This is a known limitation of the
172 // way policies are loaded currently, but isn't a problem worth fixing for
173 // the time being.
174 DomainMap map(own_schema_map_->GetDomains());
175 for (std::set<SchemaRegistry*>::const_iterator reg_it = registries_.begin();
176 reg_it != registries_.end(); ++reg_it) {
177 const DomainMap& reg_domain_map = (*reg_it)->schema_map()->GetDomains();
178 for (DomainMap::const_iterator domain_it = reg_domain_map.begin();
179 domain_it != reg_domain_map.end(); ++domain_it) {
180 const ComponentMap& reg_component_map = domain_it->second;
181 for (ComponentMap::const_iterator comp_it = reg_component_map.begin();
182 comp_it != reg_component_map.end(); ++comp_it) {
183 map[domain_it->first][comp_it->first] = comp_it->second;
187 schema_map_ = new SchemaMap(map);
188 Notify(has_new_schemas);
191 ForwardingSchemaRegistry::ForwardingSchemaRegistry(SchemaRegistry* wrapped)
192 : wrapped_(wrapped) {
193 schema_map_ = wrapped_->schema_map();
194 wrapped_->AddObserver(this);
195 wrapped_->AddInternalObserver(this);
198 ForwardingSchemaRegistry::~ForwardingSchemaRegistry() {
199 if (wrapped_) {
200 wrapped_->RemoveObserver(this);
201 wrapped_->RemoveInternalObserver(this);
205 void ForwardingSchemaRegistry::RegisterComponents(
206 PolicyDomain domain,
207 const ComponentMap& components) {
208 // POLICY_DOMAIN_CHROME is skipped to avoid spurious updates when a new
209 // Profile is created. If the ForwardingSchemaRegistry is used outside
210 // device-level accounts then this should become configurable.
211 if (wrapped_ && domain != POLICY_DOMAIN_CHROME)
212 wrapped_->RegisterComponents(domain, components);
213 // Ignore otherwise.
216 void ForwardingSchemaRegistry::UnregisterComponent(const PolicyNamespace& ns) {
217 if (wrapped_)
218 wrapped_->UnregisterComponent(ns);
219 // Ignore otherwise.
222 void ForwardingSchemaRegistry::OnSchemaRegistryUpdated(bool has_new_schemas) {
223 schema_map_ = wrapped_->schema_map();
224 Notify(has_new_schemas);
227 void ForwardingSchemaRegistry::OnSchemaRegistryReady() {
228 // Ignore.
231 void ForwardingSchemaRegistry::OnSchemaRegistryShuttingDown(
232 SchemaRegistry* registry) {
233 DCHECK_EQ(wrapped_, registry);
234 wrapped_->RemoveObserver(this);
235 wrapped_->RemoveInternalObserver(this);
236 wrapped_ = NULL;
237 // Keep serving the same |schema_map_|.
240 } // namespace policy