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"
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;
23 SchemaRegistry::~SchemaRegistry() {
24 FOR_EACH_OBSERVER(InternalObserver
,
26 OnSchemaRegistryShuttingDown(this));
29 void SchemaRegistry::RegisterComponent(const PolicyNamespace
& ns
,
30 const Schema
& schema
) {
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())
41 // Assume that a schema was updated if the namespace was already registered
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
);
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
);
62 bool SchemaRegistry::IsReady() const {
63 for (int i
= 0; i
< POLICY_DOMAIN_SIZE
; ++i
) {
64 if (!domains_ready_
[i
])
70 void SchemaRegistry::SetReady(PolicyDomain domain
) {
71 if (domains_ready_
[domain
])
73 domains_ready_
[domain
] = true;
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
) {
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())
120 void CombinedSchemaRegistry::RegisterComponents(
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
);
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
);
142 void CombinedSchemaRegistry::OnSchemaRegistryUpdated(bool has_new_schemas
) {
143 Combine(has_new_schemas
);
146 void CombinedSchemaRegistry::OnSchemaRegistryReady() {
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())
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
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() {
200 wrapped_
->RemoveObserver(this);
201 wrapped_
->RemoveInternalObserver(this);
205 void ForwardingSchemaRegistry::RegisterComponents(
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
);
216 void ForwardingSchemaRegistry::UnregisterComponent(const PolicyNamespace
& ns
) {
218 wrapped_
->UnregisterComponent(ns
);
222 void ForwardingSchemaRegistry::OnSchemaRegistryUpdated(bool has_new_schemas
) {
223 schema_map_
= wrapped_
->schema_map();
224 Notify(has_new_schemas
);
227 void ForwardingSchemaRegistry::OnSchemaRegistryReady() {
231 void ForwardingSchemaRegistry::OnSchemaRegistryShuttingDown(
232 SchemaRegistry
* registry
) {
233 DCHECK_EQ(wrapped_
, registry
);
234 wrapped_
->RemoveObserver(this);
235 wrapped_
->RemoveInternalObserver(this);
237 // Keep serving the same |schema_map_|.
240 } // namespace policy