- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / policy / policy_service_impl.cc
1 // Copyright (c) 2012 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 "chrome/browser/policy/policy_service_impl.h"
6
7 #include <algorithm>
8
9 #include "base/bind.h"
10 #include "base/message_loop/message_loop.h"
11 #include "base/stl_util.h"
12 #include "chrome/browser/policy/policy_domain_descriptor.h"
13 #include "chrome/browser/policy/policy_map.h"
14
15 namespace policy {
16
17 typedef PolicyServiceImpl::Providers::const_iterator Iterator;
18
19 PolicyServiceImpl::PolicyServiceImpl(const Providers& providers)
20     : update_task_ptr_factory_(this) {
21   for (int domain = 0; domain < POLICY_DOMAIN_SIZE; ++domain)
22     initialization_complete_[domain] = true;
23   providers_ = providers;
24   for (Iterator it = providers.begin(); it != providers.end(); ++it) {
25     ConfigurationPolicyProvider* provider = *it;
26     provider->AddObserver(this);
27     for (int domain = 0; domain < POLICY_DOMAIN_SIZE; ++domain) {
28       initialization_complete_[domain] &=
29           provider->IsInitializationComplete(static_cast<PolicyDomain>(domain));
30     }
31   }
32   // There are no observers yet, but calls to GetPolicies() should already get
33   // the processed policy values.
34   MergeAndTriggerUpdates();
35 }
36
37 PolicyServiceImpl::~PolicyServiceImpl() {
38   for (Iterator it = providers_.begin(); it != providers_.end(); ++it)
39     (*it)->RemoveObserver(this);
40   STLDeleteValues(&observers_);
41 }
42
43 void PolicyServiceImpl::AddObserver(PolicyDomain domain,
44                                     PolicyService::Observer* observer) {
45   Observers*& list = observers_[domain];
46   if (!list)
47     list = new Observers();
48   list->AddObserver(observer);
49 }
50
51 void PolicyServiceImpl::RemoveObserver(PolicyDomain domain,
52                                        PolicyService::Observer* observer) {
53   ObserverMap::iterator it = observers_.find(domain);
54   if (it == observers_.end()) {
55     NOTREACHED();
56     return;
57   }
58   it->second->RemoveObserver(observer);
59   if (!it->second->might_have_observers()) {
60     delete it->second;
61     observers_.erase(it);
62   }
63 }
64
65 void PolicyServiceImpl::RegisterPolicyDomain(
66     scoped_refptr<const PolicyDomainDescriptor> descriptor) {
67   domain_descriptors_[descriptor->domain()] = descriptor;
68   for (Iterator it = providers_.begin(); it != providers_.end(); ++it)
69     (*it)->RegisterPolicyDomain(descriptor);
70 }
71
72 const PolicyMap& PolicyServiceImpl::GetPolicies(
73     const PolicyNamespace& ns) const {
74   return policy_bundle_.Get(ns);
75 }
76
77 scoped_refptr<const PolicyDomainDescriptor>
78 PolicyServiceImpl::GetPolicyDomainDescriptor(PolicyDomain domain) const {
79   return domain_descriptors_[domain];
80 }
81
82 bool PolicyServiceImpl::IsInitializationComplete(PolicyDomain domain) const {
83   DCHECK(domain >= 0 && domain < POLICY_DOMAIN_SIZE);
84   return initialization_complete_[domain];
85 }
86
87 void PolicyServiceImpl::RefreshPolicies(const base::Closure& callback) {
88   if (!callback.is_null())
89     refresh_callbacks_.push_back(callback);
90
91   if (providers_.empty()) {
92     // Refresh is immediately complete if there are no providers. See the note
93     // on OnUpdatePolicy() about why this is a posted task.
94     update_task_ptr_factory_.InvalidateWeakPtrs();
95     base::MessageLoop::current()->PostTask(
96         FROM_HERE,
97         base::Bind(&PolicyServiceImpl::MergeAndTriggerUpdates,
98                    update_task_ptr_factory_.GetWeakPtr()));
99   } else {
100     // Some providers might invoke OnUpdatePolicy synchronously while handling
101     // RefreshPolicies. Mark all as pending before refreshing.
102     for (Iterator it = providers_.begin(); it != providers_.end(); ++it)
103       refresh_pending_.insert(*it);
104     for (Iterator it = providers_.begin(); it != providers_.end(); ++it)
105       (*it)->RefreshPolicies();
106   }
107 }
108
109 void PolicyServiceImpl::OnUpdatePolicy(ConfigurationPolicyProvider* provider) {
110   DCHECK_EQ(1, std::count(providers_.begin(), providers_.end(), provider));
111   refresh_pending_.erase(provider);
112
113   // Note: a policy change may trigger further policy changes in some providers.
114   // For example, disabling SigninAllowed would cause the CloudPolicyManager to
115   // drop all its policies, which makes this method enter again for that
116   // provider.
117   //
118   // Therefore this update is posted asynchronously, to prevent reentrancy in
119   // MergeAndTriggerUpdates. Also, cancel a pending update if there is any,
120   // since both will produce the same PolicyBundle.
121   update_task_ptr_factory_.InvalidateWeakPtrs();
122   base::MessageLoop::current()->PostTask(
123       FROM_HERE,
124       base::Bind(&PolicyServiceImpl::MergeAndTriggerUpdates,
125                  update_task_ptr_factory_.GetWeakPtr()));
126 }
127
128 void PolicyServiceImpl::NotifyNamespaceUpdated(
129     const PolicyNamespace& ns,
130     const PolicyMap& previous,
131     const PolicyMap& current) {
132   ObserverMap::iterator iterator = observers_.find(ns.domain);
133   if (iterator != observers_.end()) {
134     FOR_EACH_OBSERVER(PolicyService::Observer,
135                       *iterator->second,
136                       OnPolicyUpdated(ns, previous, current));
137   }
138 }
139
140 void PolicyServiceImpl::MergeAndTriggerUpdates() {
141   // Merge from each provider in their order of priority.
142   PolicyBundle bundle;
143   for (Iterator it = providers_.begin(); it != providers_.end(); ++it)
144     bundle.MergeFrom((*it)->policies());
145
146   // Swap first, so that observers that call GetPolicies() see the current
147   // values.
148   policy_bundle_.Swap(&bundle);
149
150   // Only notify observers of namespaces that have been modified.
151   const PolicyMap kEmpty;
152   PolicyBundle::const_iterator it_new = policy_bundle_.begin();
153   PolicyBundle::const_iterator end_new = policy_bundle_.end();
154   PolicyBundle::const_iterator it_old = bundle.begin();
155   PolicyBundle::const_iterator end_old = bundle.end();
156   while (it_new != end_new && it_old != end_old) {
157     if (it_new->first < it_old->first) {
158       // A new namespace is available.
159       NotifyNamespaceUpdated(it_new->first, kEmpty, *it_new->second);
160       ++it_new;
161     } else if (it_old->first < it_new->first) {
162       // A previously available namespace is now gone.
163       NotifyNamespaceUpdated(it_old->first, *it_old->second, kEmpty);
164       ++it_old;
165     } else {
166       if (!it_new->second->Equals(*it_old->second)) {
167         // An existing namespace's policies have changed.
168         NotifyNamespaceUpdated(it_new->first, *it_old->second, *it_new->second);
169       }
170       ++it_new;
171       ++it_old;
172     }
173   }
174
175   // Send updates for the remaining new namespaces, if any.
176   for (; it_new != end_new; ++it_new)
177     NotifyNamespaceUpdated(it_new->first, kEmpty, *it_new->second);
178
179   // Sends updates for the remaining removed namespaces, if any.
180   for (; it_old != end_old; ++it_old)
181     NotifyNamespaceUpdated(it_old->first, *it_old->second, kEmpty);
182
183   CheckInitializationComplete();
184   CheckRefreshComplete();
185 }
186
187 void PolicyServiceImpl::CheckInitializationComplete() {
188   // Check if all the providers just became initialized for each domain; if so,
189   // notify that domain's observers.
190   for (int domain = 0; domain < POLICY_DOMAIN_SIZE; ++domain) {
191     if (initialization_complete_[domain])
192       continue;
193
194     PolicyDomain policy_domain = static_cast<PolicyDomain>(domain);
195
196     bool all_complete = true;
197     for (Iterator it = providers_.begin(); it != providers_.end(); ++it) {
198       if (!(*it)->IsInitializationComplete(policy_domain)) {
199         all_complete = false;
200         break;
201       }
202     }
203     if (all_complete) {
204       initialization_complete_[domain] = true;
205       ObserverMap::iterator iter = observers_.find(policy_domain);
206       if (iter != observers_.end()) {
207         FOR_EACH_OBSERVER(PolicyService::Observer,
208                           *iter->second,
209                           OnPolicyServiceInitialized(policy_domain));
210       }
211     }
212   }
213 }
214
215 void PolicyServiceImpl::CheckRefreshComplete() {
216   // Invoke all the callbacks if a refresh has just fully completed.
217   if (refresh_pending_.empty() && !refresh_callbacks_.empty()) {
218     std::vector<base::Closure> callbacks;
219     callbacks.swap(refresh_callbacks_);
220     std::vector<base::Closure>::iterator it;
221     for (it = callbacks.begin(); it != callbacks.end(); ++it)
222       it->Run();
223   }
224 }
225
226 }  // namespace policy