signed_settings_helper.cc revision 731df977c0511bca2206b5f333555b1205ff1f43
1// Copyright (c) 2010 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/chromeos/login/signed_settings_helper.h"
6
7#include <string>
8#include <vector>
9
10#include "base/logging.h"
11#include "base/ref_counted.h"
12#include "base/singleton.h"
13#include "chrome/browser/browser_thread.h"
14#include "chrome/browser/chromeos/login/signed_settings.h"
15
16namespace chromeos {
17
18namespace {
19
20class OpContext {
21 public:
22  class Delegate {
23   public:
24    virtual void OnOpCreated(OpContext* context) = 0;
25    virtual void OnOpStarted(OpContext* context) = 0;
26    virtual void OnOpCompleted(OpContext* context) = 0;
27  };
28
29  virtual ~OpContext() {}
30
31  // Creates and execute op.
32  void Execute() {
33    CreateOp();
34    CHECK(op_.get());
35    if (delegate_)
36      delegate_->OnOpCreated(this);
37
38    // Note that the context could be released when op_->Execute() returns.
39    // So keep a local copy of delegate and executing flag to use after
40    // the call.
41    Delegate* delegate = delegate_;
42    bool executing = executing_ = op_->Execute();
43    if (executing) {
44      if (delegate)
45        delegate->OnOpStarted(this);
46    } else {
47      OnOpFailed();
48    }
49  }
50
51  // Cancels the callback.
52  void CancelCallback() {
53    callback_ = NULL;
54  }
55
56  // Cancels the callback and cancels the op if it is not executing.
57  void Cancel() {
58    CancelCallback();
59
60   if (!executing_)
61      OnOpCompleted();
62  }
63
64  // Accessors.
65  SignedSettings* op() const {
66    return op_.get();
67  }
68
69  SignedSettingsHelper::Callback* callback() const {
70    return callback_;
71  }
72
73  void set_delegate(Delegate* delegate) {
74    delegate_ = delegate;
75  }
76
77 protected:
78  OpContext(SignedSettingsHelper::Callback* callback,
79            Delegate* delegate)
80      : executing_(false),
81        delegate_(delegate),
82        callback_(callback) {
83  }
84
85  // Creates the op to execute.
86  virtual void CreateOp() = 0;
87
88  // Callback on op completion.
89  virtual void OnOpCompleted() {
90    if (delegate_)
91      delegate_->OnOpCompleted(this);
92
93    delete this;
94  }
95
96  // Callback on op failure.
97  virtual void OnOpFailed() {
98    OnOpCompleted();
99  }
100
101  bool executing_;
102  Delegate* delegate_;
103
104  scoped_refptr<SignedSettings> op_;
105  SignedSettingsHelper::Callback* callback_;
106};
107
108class WhitelistOpContext : public SignedSettings::Delegate<bool>,
109                           public OpContext {
110 public:
111  enum Type {
112    CHECK,
113    ADD,
114    REMOVE,
115  };
116
117  WhitelistOpContext(Type type,
118                     const std::string& email,
119                     SignedSettingsHelper::Callback* callback,
120                     Delegate* delegate)
121      : OpContext(callback, delegate),
122        type_(type),
123        email_(email) {
124  }
125
126  // chromeos::SignedSettings::Delegate implementation
127  virtual void OnSettingsOpSucceeded(bool value) {
128    if (callback_) {
129      switch (type_) {
130        case CHECK:
131          callback_->OnCheckWhiteListCompleted(value, email_);
132          break;
133        case ADD:
134          callback_->OnWhitelistCompleted(value, email_);
135          break;
136        case REMOVE:
137          callback_->OnUnwhitelistCompleted(value, email_);
138          break;
139        default:
140          LOG(ERROR) << "Unknown WhitelistOpContext type " << type_;
141          break;
142      }
143    }
144
145    OnOpCompleted();
146  }
147
148  virtual void OnSettingsOpFailed() {
149    OnOpFailed();
150  }
151
152 protected:
153  // OpContext implemenetation
154  virtual void CreateOp() {
155    switch (type_) {
156      case CHECK:
157        op_ = SignedSettings::CreateCheckWhitelistOp(email_, this);
158        break;
159      case ADD:
160        op_ = SignedSettings::CreateWhitelistOp(email_, true, this);
161        break;
162      case REMOVE:
163        op_ = SignedSettings::CreateWhitelistOp(email_, false, this);
164        break;
165      default:
166        LOG(ERROR) << "Unknown WhitelistOpContext type " << type_;
167        break;
168    }
169  }
170
171  virtual void OnOpFailed() {
172    if (callback_) {
173      switch (type_) {
174        case CHECK:
175          callback_->OnCheckWhiteListCompleted(false, email_);
176          break;
177        case ADD:
178          callback_->OnWhitelistCompleted(false, email_);
179          break;
180        case REMOVE:
181          callback_->OnUnwhitelistCompleted(false, email_);
182          break;
183        default:
184          LOG(ERROR) << "Unknown WhitelistOpContext type " << type_;
185          break;
186      }
187    }
188
189    OnOpCompleted();
190  }
191
192 private:
193  Type type_;
194  std::string email_;
195
196  DISALLOW_COPY_AND_ASSIGN(WhitelistOpContext);
197};
198
199class StorePropertyOpContext : public SignedSettings::Delegate<bool>,
200                               public OpContext {
201 public:
202  StorePropertyOpContext(const std::string& name,
203                         const std::string& value,
204                         SignedSettingsHelper::Callback* callback,
205                         Delegate* delegate)
206      : OpContext(callback, delegate),
207        name_(name),
208        value_(value) {
209  }
210
211  // chromeos::SignedSettings::Delegate implementation
212  virtual void OnSettingsOpSucceeded(bool value) {
213    if (callback_)
214      callback_->OnStorePropertyCompleted(true, name_, value_);
215    OnOpCompleted();
216  }
217
218  virtual void OnSettingsOpFailed() {
219    OnOpFailed();
220  }
221
222 protected:
223  // OpContext implemenetation
224  virtual void CreateOp() {
225    op_ = SignedSettings::CreateStorePropertyOp(name_, value_, this);
226  }
227
228  virtual void OnOpFailed() {
229    if (callback_)
230      callback_->OnStorePropertyCompleted(false, name_, value_);
231    OnOpCompleted();
232  }
233
234 private:
235  std::string name_;
236  std::string value_;
237
238  DISALLOW_COPY_AND_ASSIGN(StorePropertyOpContext);
239};
240
241class RetrievePropertyOpContext
242    : public SignedSettings::Delegate<std::string>,
243      public OpContext {
244 public:
245  RetrievePropertyOpContext(const std::string& name,
246                            SignedSettingsHelper::Callback* callback,
247                            Delegate* delegate)
248      : OpContext(callback, delegate),
249        name_(name) {
250  }
251
252  // chromeos::SignedSettings::Delegate implementation
253  virtual void OnSettingsOpSucceeded(std::string value) {
254    if (callback_)
255      callback_->OnRetrievePropertyCompleted(true, name_, value);
256
257    OnOpCompleted();
258  }
259
260  virtual void OnSettingsOpFailed() {
261    OnOpFailed();
262  }
263
264 protected:
265  // OpContext implemenetation
266  virtual void CreateOp() {
267    op_ = SignedSettings::CreateRetrievePropertyOp(name_, this);
268  }
269
270  virtual void OnOpFailed() {
271    if (callback_)
272      callback_->OnRetrievePropertyCompleted(false, name_, std::string());
273    OnOpCompleted();
274  }
275
276 private:
277  std::string name_;
278
279  DISALLOW_COPY_AND_ASSIGN(RetrievePropertyOpContext);
280};
281
282}  // namespace
283
284
285class SignedSettingsHelperImpl : public SignedSettingsHelper,
286                                 public OpContext::Delegate {
287 public:
288  // SignedSettingsHelper implementation
289  virtual void StartCheckWhitelistOp(const std::string& email,
290                                     Callback* callback);
291  virtual void StartWhitelistOp(const std::string& email,
292                                bool add_to_whitelist,
293                                Callback* callback);
294  virtual void StartStorePropertyOp(const std::string& name,
295                                    const std::string& value,
296                                    Callback* callback);
297  virtual void StartRetrieveProperty(const std::string& name,
298                                     Callback* callback);
299  virtual void CancelCallback(Callback* callback);
300
301  // OpContext::Delegate implementation
302  virtual void OnOpCreated(OpContext* context);
303  virtual void OnOpStarted(OpContext* context);
304  virtual void OnOpCompleted(OpContext* context);
305
306 private:
307  SignedSettingsHelperImpl();
308  ~SignedSettingsHelperImpl();
309
310  void AddOpContext(OpContext* context);
311  void ClearAll();
312
313  std::vector<OpContext*> pending_contexts_;
314
315  friend struct DefaultSingletonTraits<SignedSettingsHelperImpl>;
316  DISALLOW_COPY_AND_ASSIGN(SignedSettingsHelperImpl);
317};
318
319SignedSettingsHelperImpl::SignedSettingsHelperImpl() {
320}
321
322SignedSettingsHelperImpl::~SignedSettingsHelperImpl() {
323  if (!pending_contexts_.empty()) {
324    LOG(WARNING) << "SignedSettingsHelperImpl shutdown with pending ops, "
325                 << "changes will be lost.";
326    ClearAll();
327  }
328}
329
330void SignedSettingsHelperImpl::StartCheckWhitelistOp(
331    const std::string&email,
332    SignedSettingsHelper::Callback* callback) {
333  AddOpContext(new WhitelistOpContext(
334      WhitelistOpContext::CHECK,
335      email,
336      callback,
337      this));
338}
339
340void SignedSettingsHelperImpl::StartWhitelistOp(
341    const std::string&email,
342    bool add_to_whitelist,
343    SignedSettingsHelper::Callback* callback) {
344  AddOpContext(new WhitelistOpContext(
345      add_to_whitelist ? WhitelistOpContext::ADD : WhitelistOpContext::REMOVE,
346      email,
347      callback,
348      this));
349}
350
351void SignedSettingsHelperImpl::StartStorePropertyOp(
352    const std::string& name,
353    const std::string& value,
354    SignedSettingsHelper::SignedSettingsHelper::Callback* callback) {
355  AddOpContext(new StorePropertyOpContext(
356      name,
357      value,
358      callback,
359      this));
360}
361
362void SignedSettingsHelperImpl::StartRetrieveProperty(
363    const std::string& name,
364    SignedSettingsHelper::Callback* callback) {
365  AddOpContext(new RetrievePropertyOpContext(
366      name,
367      callback,
368      this));
369}
370
371void SignedSettingsHelperImpl::CancelCallback(
372    SignedSettingsHelper::Callback* callback) {
373  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
374
375  for (size_t i = 0; i < pending_contexts_.size(); ++i) {
376    if (pending_contexts_[i]->callback() == callback) {
377      pending_contexts_[i]->CancelCallback();
378    }
379  }
380}
381
382void SignedSettingsHelperImpl::AddOpContext(OpContext* context) {
383  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
384  CHECK(context);
385
386  pending_contexts_.push_back(context);
387  if (pending_contexts_.size() == 1)
388    context->Execute();
389}
390
391void SignedSettingsHelperImpl::ClearAll() {
392  for (size_t i = 0; i < pending_contexts_.size(); ++i) {
393    pending_contexts_[i]->set_delegate(NULL);
394    pending_contexts_[i]->Cancel();
395  }
396  pending_contexts_.clear();
397}
398
399void SignedSettingsHelperImpl::OnOpCreated(OpContext* context) {
400  if (test_delegate_)
401    test_delegate_->OnOpCreated(context->op());
402}
403
404void SignedSettingsHelperImpl::OnOpStarted(OpContext* context) {
405  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
406
407  if (test_delegate_)
408    test_delegate_->OnOpStarted(context->op());
409}
410
411void SignedSettingsHelperImpl::OnOpCompleted(OpContext* context) {
412  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
413  DCHECK(pending_contexts_.front() == context);
414
415  pending_contexts_.erase(pending_contexts_.begin());
416  if (!pending_contexts_.empty())
417    pending_contexts_.front()->Execute();
418
419  if (test_delegate_)
420    test_delegate_->OnOpCompleted(context->op());
421}
422
423SignedSettingsHelper* SignedSettingsHelper::Get() {
424  return Singleton<SignedSettingsHelperImpl>::get();
425}
426
427}  // namespace chromeos
428