schema_registry.cc revision f2477e01787aa58f445919b809d89e252beef54f
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.
4
5#include "components/policy/core/common/schema_registry.h"
6
7#include "base/logging.h"
8
9namespace policy {
10
11SchemaRegistry::Observer::~Observer() {}
12
13SchemaRegistry::SchemaRegistry() : schema_map_(new SchemaMap) {
14  for (int i = 0; i < POLICY_DOMAIN_SIZE; ++i)
15    domains_ready_[i] = false;
16#if !defined(ENABLE_EXTENSIONS)
17  domains_ready_[POLICY_DOMAIN_EXTENSIONS] = true;
18#endif
19}
20
21SchemaRegistry::~SchemaRegistry() {}
22
23void SchemaRegistry::RegisterComponent(const PolicyNamespace& ns,
24                                       const Schema& schema) {
25  ComponentMap map;
26  map[ns.component_id] = schema;
27  RegisterComponents(ns.domain, map);
28}
29
30void SchemaRegistry::RegisterComponents(PolicyDomain domain,
31                                        const ComponentMap& components) {
32  // Don't issue notifications if nothing is being registered.
33  if (components.empty())
34    return;
35  // Assume that a schema was updated if the namespace was already registered
36  // before.
37  DomainMap map(schema_map_->GetDomains());
38  for (ComponentMap::const_iterator it = components.begin();
39       it != components.end(); ++it) {
40    map[domain][it->first] = it->second;
41  }
42  schema_map_ = new SchemaMap(map);
43  Notify(true);
44}
45
46void SchemaRegistry::UnregisterComponent(const PolicyNamespace& ns) {
47  DomainMap map(schema_map_->GetDomains());
48  if (map[ns.domain].erase(ns.component_id) != 0) {
49    schema_map_ = new SchemaMap(map);
50    Notify(false);
51  } else {
52    NOTREACHED();
53  }
54}
55
56bool SchemaRegistry::IsReady() const {
57  for (int i = 0; i < POLICY_DOMAIN_SIZE; ++i) {
58    if (!domains_ready_[i])
59      return false;
60  }
61  return true;
62}
63
64void SchemaRegistry::SetReady(PolicyDomain domain) {
65  if (domains_ready_[domain])
66    return;
67  domains_ready_[domain] = true;
68  if (IsReady())
69    FOR_EACH_OBSERVER(Observer, observers_, OnSchemaRegistryReady());
70}
71
72void SchemaRegistry::AddObserver(Observer* observer) {
73  observers_.AddObserver(observer);
74}
75
76void SchemaRegistry::RemoveObserver(Observer* observer) {
77  observers_.RemoveObserver(observer);
78}
79
80void SchemaRegistry::Notify(bool has_new_schemas) {
81  FOR_EACH_OBSERVER(
82      Observer, observers_, OnSchemaRegistryUpdated(has_new_schemas));
83}
84
85bool SchemaRegistry::HasObservers() const {
86  return observers_.might_have_observers();
87}
88
89CombinedSchemaRegistry::CombinedSchemaRegistry()
90    : own_schema_map_(new SchemaMap) {
91  // The combined registry is always ready, since it can always start tracking
92  // another registry that is not ready yet and going from "ready" to "not
93  // ready" is not allowed.
94  for (int i = 0; i < POLICY_DOMAIN_SIZE; ++i)
95    SetReady(static_cast<PolicyDomain>(i));
96}
97
98CombinedSchemaRegistry::~CombinedSchemaRegistry() {}
99
100void CombinedSchemaRegistry::Track(SchemaRegistry* registry) {
101  registries_.insert(registry);
102  registry->AddObserver(this);
103  // Recombine the maps only if the |registry| has any components other than
104  // POLICY_DOMAIN_CHROME.
105  if (registry->schema_map()->HasComponents())
106    Combine(true);
107}
108
109void CombinedSchemaRegistry::Untrack(SchemaRegistry* registry) {
110  registry->RemoveObserver(this);
111  if (registries_.erase(registry) != 0) {
112    if (registry->schema_map()->HasComponents())
113      Combine(false);
114  } else {
115    NOTREACHED();
116  }
117}
118
119void CombinedSchemaRegistry::RegisterComponents(
120    PolicyDomain domain,
121    const ComponentMap& components) {
122  DomainMap map(own_schema_map_->GetDomains());
123  for (ComponentMap::const_iterator it = components.begin();
124       it != components.end(); ++it) {
125    map[domain][it->first] = it->second;
126  }
127  own_schema_map_ = new SchemaMap(map);
128  Combine(true);
129}
130
131void CombinedSchemaRegistry::UnregisterComponent(const PolicyNamespace& ns) {
132  DomainMap map(own_schema_map_->GetDomains());
133  if (map[ns.domain].erase(ns.component_id) != 0) {
134    own_schema_map_ = new SchemaMap(map);
135    Combine(false);
136  } else {
137    NOTREACHED();
138  }
139}
140
141void CombinedSchemaRegistry::OnSchemaRegistryUpdated(bool has_new_schemas) {
142  Combine(has_new_schemas);
143}
144
145void CombinedSchemaRegistry::OnSchemaRegistryReady() {
146  // Ignore.
147}
148
149void CombinedSchemaRegistry::Combine(bool has_new_schemas) {
150  // If two registries publish a Schema for the same component then it's
151  // undefined which version gets in the combined registry.
152  //
153  // The common case is that both registries want policy for the same component,
154  // and the Schemas should be the same; in that case this makes no difference.
155  //
156  // But if the Schemas are different then one of the components is out of date.
157  // In that case the policy loaded will be valid only for one of them, until
158  // the outdated components are updated. This is a known limitation of the
159  // way policies are loaded currently, but isn't a problem worth fixing for
160  // the time being.
161  DomainMap map(own_schema_map_->GetDomains());
162  for (std::set<SchemaRegistry*>::const_iterator reg_it = registries_.begin();
163       reg_it != registries_.end(); ++reg_it) {
164    const DomainMap& reg_domain_map = (*reg_it)->schema_map()->GetDomains();
165    for (DomainMap::const_iterator domain_it = reg_domain_map.begin();
166         domain_it != reg_domain_map.end(); ++domain_it) {
167      const ComponentMap& reg_component_map = domain_it->second;
168      for (ComponentMap::const_iterator comp_it = reg_component_map.begin();
169           comp_it != reg_component_map.end(); ++comp_it) {
170        map[domain_it->first][comp_it->first] = comp_it->second;
171      }
172    }
173  }
174  schema_map_ = new SchemaMap(map);
175  Notify(has_new_schemas);
176}
177
178}  // namespace policy
179