schema_registry.cc revision 6d86b77056ed63eb6871182f42a9fd5f07550f90
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::InternalObserver::~InternalObserver() {} 14 15SchemaRegistry::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 21} 22 23SchemaRegistry::~SchemaRegistry() { 24 FOR_EACH_OBSERVER(InternalObserver, 25 internal_observers_, 26 OnSchemaRegistryShuttingDown(this)); 27} 28 29void SchemaRegistry::RegisterComponent(const PolicyNamespace& ns, 30 const Schema& schema) { 31 ComponentMap map; 32 map[ns.component_id] = schema; 33 RegisterComponents(ns.domain, map); 34} 35 36void 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; 47 } 48 schema_map_ = new SchemaMap(map); 49 Notify(true); 50} 51 52void 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(); 59 } 60} 61 62bool SchemaRegistry::IsReady() const { 63 for (int i = 0; i < POLICY_DOMAIN_SIZE; ++i) { 64 if (!domains_ready_[i]) 65 return false; 66 } 67 return true; 68} 69 70void 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()); 76} 77 78void SchemaRegistry::AddObserver(Observer* observer) { 79 observers_.AddObserver(observer); 80} 81 82void SchemaRegistry::RemoveObserver(Observer* observer) { 83 observers_.RemoveObserver(observer); 84} 85 86void SchemaRegistry::AddInternalObserver(InternalObserver* observer) { 87 internal_observers_.AddObserver(observer); 88} 89 90void SchemaRegistry::RemoveInternalObserver(InternalObserver* observer) { 91 internal_observers_.RemoveObserver(observer); 92} 93 94void SchemaRegistry::Notify(bool has_new_schemas) { 95 FOR_EACH_OBSERVER( 96 Observer, observers_, OnSchemaRegistryUpdated(has_new_schemas)); 97} 98 99CombinedSchemaRegistry::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)); 106} 107 108CombinedSchemaRegistry::~CombinedSchemaRegistry() {} 109 110void 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); 118} 119 120void 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; 127 } 128 own_schema_map_ = new SchemaMap(map); 129 Combine(true); 130} 131 132void 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(); 139 } 140} 141 142void CombinedSchemaRegistry::OnSchemaRegistryUpdated(bool has_new_schemas) { 143 Combine(has_new_schemas); 144} 145 146void CombinedSchemaRegistry::OnSchemaRegistryReady() { 147 // Ignore. 148} 149 150void 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(); 159 } 160} 161 162void 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. 165 // 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. 168 // 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; 184 } 185 } 186 } 187 schema_map_ = new SchemaMap(map); 188 Notify(has_new_schemas); 189} 190 191ForwardingSchemaRegistry::ForwardingSchemaRegistry(SchemaRegistry* wrapped) 192 : wrapped_(wrapped) { 193 schema_map_ = wrapped_->schema_map(); 194 wrapped_->AddObserver(this); 195 wrapped_->AddInternalObserver(this); 196 // This registry is always ready. 197 for (int i = 0; i < POLICY_DOMAIN_SIZE; ++i) 198 SetReady(static_cast<PolicyDomain>(i)); 199} 200 201ForwardingSchemaRegistry::~ForwardingSchemaRegistry() { 202 if (wrapped_) { 203 wrapped_->RemoveObserver(this); 204 wrapped_->RemoveInternalObserver(this); 205 } 206} 207 208void ForwardingSchemaRegistry::RegisterComponents( 209 PolicyDomain domain, 210 const ComponentMap& components) { 211 if (wrapped_) 212 wrapped_->RegisterComponents(domain, components); 213 // Ignore otherwise. 214} 215 216void ForwardingSchemaRegistry::UnregisterComponent(const PolicyNamespace& ns) { 217 if (wrapped_) 218 wrapped_->UnregisterComponent(ns); 219 // Ignore otherwise. 220} 221 222void ForwardingSchemaRegistry::OnSchemaRegistryUpdated(bool has_new_schemas) { 223 schema_map_ = wrapped_->schema_map(); 224 Notify(has_new_schemas); 225} 226 227void ForwardingSchemaRegistry::OnSchemaRegistryReady() { 228 // Ignore. 229} 230 231void 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_|. 238} 239 240} // namespace policy 241