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::OnSchemaRegistryShuttingDown(
147 SchemaRegistry
* registry
) {
148 registry
->RemoveObserver(this);
149 registry
->RemoveInternalObserver(this);
150 if (registries_
.erase(registry
) != 0) {
151 if (registry
->schema_map()->HasComponents())
158 void CombinedSchemaRegistry::Combine(bool has_new_schemas
) {
159 // If two registries publish a Schema for the same component then it's
160 // undefined which version gets in the combined registry.
162 // The common case is that both registries want policy for the same component,
163 // and the Schemas should be the same; in that case this makes no difference.
165 // But if the Schemas are different then one of the components is out of date.
166 // In that case the policy loaded will be valid only for one of them, until
167 // the outdated components are updated. This is a known limitation of the
168 // way policies are loaded currently, but isn't a problem worth fixing for
170 DomainMap
map(own_schema_map_
->GetDomains());
171 for (std::set
<SchemaRegistry
*>::const_iterator reg_it
= registries_
.begin();
172 reg_it
!= registries_
.end(); ++reg_it
) {
173 const DomainMap
& reg_domain_map
= (*reg_it
)->schema_map()->GetDomains();
174 for (DomainMap::const_iterator domain_it
= reg_domain_map
.begin();
175 domain_it
!= reg_domain_map
.end(); ++domain_it
) {
176 const ComponentMap
& reg_component_map
= domain_it
->second
;
177 for (ComponentMap::const_iterator comp_it
= reg_component_map
.begin();
178 comp_it
!= reg_component_map
.end(); ++comp_it
) {
179 map
[domain_it
->first
][comp_it
->first
] = comp_it
->second
;
183 schema_map_
= new SchemaMap(map
);
184 Notify(has_new_schemas
);
187 ForwardingSchemaRegistry::ForwardingSchemaRegistry(SchemaRegistry
* wrapped
)
188 : wrapped_(wrapped
) {
189 schema_map_
= wrapped_
->schema_map();
190 wrapped_
->AddObserver(this);
191 wrapped_
->AddInternalObserver(this);
194 ForwardingSchemaRegistry::~ForwardingSchemaRegistry() {
196 wrapped_
->RemoveObserver(this);
197 wrapped_
->RemoveInternalObserver(this);
201 void ForwardingSchemaRegistry::RegisterComponents(
203 const ComponentMap
& components
) {
204 // POLICY_DOMAIN_CHROME is skipped to avoid spurious updates when a new
205 // Profile is created. If the ForwardingSchemaRegistry is used outside
206 // device-level accounts then this should become configurable.
207 if (wrapped_
&& domain
!= POLICY_DOMAIN_CHROME
)
208 wrapped_
->RegisterComponents(domain
, components
);
212 void ForwardingSchemaRegistry::UnregisterComponent(const PolicyNamespace
& ns
) {
214 wrapped_
->UnregisterComponent(ns
);
218 void ForwardingSchemaRegistry::OnSchemaRegistryUpdated(bool has_new_schemas
) {
219 schema_map_
= wrapped_
->schema_map();
220 Notify(has_new_schemas
);
223 void ForwardingSchemaRegistry::OnSchemaRegistryShuttingDown(
224 SchemaRegistry
* registry
) {
225 DCHECK_EQ(wrapped_
, registry
);
226 wrapped_
->RemoveObserver(this);
227 wrapped_
->RemoveInternalObserver(this);
229 // Keep serving the same |schema_map_|.
232 } // namespace policy