// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chrome/browser/chromeos/login/signed_settings_helper.h" #include #include #include "base/lazy_instance.h" #include "base/logging.h" #include "base/memory/ref_counted.h" #include "chrome/browser/chromeos/login/signed_settings.h" #include "chrome/browser/policy/proto/device_management_backend.pb.h" #include "content/browser/browser_thread.h" namespace chromeos { namespace { class OpContext { public: class Delegate { public: virtual void OnOpCreated(OpContext* context) = 0; virtual void OnOpStarted(OpContext* context) = 0; virtual void OnOpCompleted(OpContext* context) = 0; }; virtual ~OpContext() {} // Creates and execute op. void Execute() { CreateOp(); CHECK(op_.get()); if (delegate_) delegate_->OnOpCreated(this); // Note that the context could be released when op_->Execute() returns. // So keep a local copy of delegate and executing flag to use after // the call. Delegate* delegate = delegate_; executing_ = true; op_->Execute(); if (delegate) delegate->OnOpStarted(this); } // Cancels the callback. void CancelCallback() { callback_ = NULL; } // Cancels the callback and cancels the op if it is not executing. void Cancel() { CancelCallback(); if (!executing_) OnOpCompleted(); } // Accessors. SignedSettings* op() const { return op_.get(); } SignedSettingsHelper::Callback* callback() const { return callback_; } void set_delegate(Delegate* delegate) { delegate_ = delegate; } protected: OpContext(SignedSettingsHelper::Callback* callback, Delegate* delegate) : executing_(false), delegate_(delegate), callback_(callback) { } // Creates the op to execute. virtual void CreateOp() = 0; // Callback on op completion. virtual void OnOpCompleted() { if (delegate_) delegate_->OnOpCompleted(this); delete this; } bool executing_; Delegate* delegate_; scoped_refptr op_; SignedSettingsHelper::Callback* callback_; }; class WhitelistOpContext : public SignedSettings::Delegate, public OpContext { public: enum Type { CHECK, ADD, REMOVE, }; WhitelistOpContext(Type type, const std::string& email, SignedSettingsHelper::Callback* callback, OpContext::Delegate* delegate) : OpContext(callback, delegate), type_(type), email_(email) { } // chromeos::SignedSettings::Delegate implementation virtual void OnSettingsOpCompleted(SignedSettings::ReturnCode code, bool value) OVERRIDE { if (callback_) { switch (type_) { case CHECK: callback_->OnCheckWhitelistCompleted(code, email_); break; case ADD: callback_->OnWhitelistCompleted(code, email_); break; case REMOVE: callback_->OnUnwhitelistCompleted(code, email_); break; default: LOG(ERROR) << "Unknown WhitelistOpContext type " << type_; break; } } OnOpCompleted(); } protected: // OpContext implemenetation virtual void CreateOp() OVERRIDE { switch (type_) { case CHECK: op_ = SignedSettings::CreateCheckWhitelistOp(email_, this); break; case ADD: op_ = SignedSettings::CreateWhitelistOp(email_, true, this); break; case REMOVE: op_ = SignedSettings::CreateWhitelistOp(email_, false, this); break; default: LOG(ERROR) << "Unknown WhitelistOpContext type " << type_; break; } } private: Type type_; std::string email_; DISALLOW_COPY_AND_ASSIGN(WhitelistOpContext); }; class StorePropertyOpContext : public SignedSettings::Delegate, public OpContext { public: StorePropertyOpContext(const std::string& name, const std::string& value, SignedSettingsHelper::Callback* callback, OpContext::Delegate* delegate) : OpContext(callback, delegate), name_(name), value_(value) { } // chromeos::SignedSettings::Delegate implementation virtual void OnSettingsOpCompleted(SignedSettings::ReturnCode code, bool unused) OVERRIDE { VLOG(2) << "OnSettingsOpCompleted, code = " << code; if (callback_) callback_->OnStorePropertyCompleted(code, name_, value_); OnOpCompleted(); } protected: // OpContext implemenetation virtual void CreateOp() OVERRIDE { op_ = SignedSettings::CreateStorePropertyOp(name_, value_, this); } private: std::string name_; std::string value_; DISALLOW_COPY_AND_ASSIGN(StorePropertyOpContext); }; class RetrievePropertyOpContext : public SignedSettings::Delegate, public OpContext { public: RetrievePropertyOpContext(const std::string& name, SignedSettingsHelper::Callback* callback, OpContext::Delegate* delegate) : OpContext(callback, delegate), name_(name) { } // chromeos::SignedSettings::Delegate implementation virtual void OnSettingsOpCompleted(SignedSettings::ReturnCode code, std::string value) OVERRIDE { if (callback_) callback_->OnRetrievePropertyCompleted(code, name_, value); OnOpCompleted(); } protected: // OpContext implemenetation virtual void CreateOp() OVERRIDE { op_ = SignedSettings::CreateRetrievePropertyOp(name_, this); } private: std::string name_; DISALLOW_COPY_AND_ASSIGN(RetrievePropertyOpContext); }; class StorePolicyOpContext : public SignedSettings::Delegate, public OpContext { public: StorePolicyOpContext(const em::PolicyFetchResponse& policy, SignedSettingsHelper::Callback* callback, OpContext::Delegate* delegate) : OpContext(callback, delegate), policy_(policy) { } // chromeos::SignedSettings::Delegate implementation virtual void OnSettingsOpCompleted(SignedSettings::ReturnCode code, bool unused) OVERRIDE { VLOG(2) << "OnSettingsOpCompleted, code = " << code; if (callback_) callback_->OnStorePolicyCompleted(code); OnOpCompleted(); } protected: // OpContext implementation virtual void CreateOp() OVERRIDE { op_ = SignedSettings::CreateStorePolicyOp(&policy_, this); } private: em::PolicyFetchResponse policy_; DISALLOW_COPY_AND_ASSIGN(StorePolicyOpContext); }; class RetrievePolicyOpContext : public SignedSettings::Delegate, public OpContext { public: RetrievePolicyOpContext(SignedSettingsHelper::Callback* callback, OpContext::Delegate* delegate) : OpContext(callback, delegate) { } // chromeos::SignedSettings::Delegate implementation virtual void OnSettingsOpCompleted( SignedSettings::ReturnCode code, const em::PolicyFetchResponse& policy) OVERRIDE { if (callback_) callback_->OnRetrievePolicyCompleted(code, policy); OnOpCompleted(); } protected: // OpContext implementation virtual void CreateOp() OVERRIDE { op_ = SignedSettings::CreateRetrievePolicyOp(this); } private: DISALLOW_COPY_AND_ASSIGN(RetrievePolicyOpContext); }; } // namespace class SignedSettingsHelperImpl : public SignedSettingsHelper, public OpContext::Delegate { public: // SignedSettingsHelper implementation virtual void StartCheckWhitelistOp(const std::string& email, Callback* callback) OVERRIDE; virtual void StartWhitelistOp(const std::string& email, bool add_to_whitelist, Callback* callback) OVERRIDE; virtual void StartStorePropertyOp(const std::string& name, const std::string& value, Callback* callback) OVERRIDE; virtual void StartRetrieveProperty(const std::string& name, Callback* callback) OVERRIDE; virtual void StartStorePolicyOp(const em::PolicyFetchResponse& policy, Callback* callback) OVERRIDE; virtual void StartRetrievePolicyOp(Callback* callback) OVERRIDE; virtual void CancelCallback(Callback* callback) OVERRIDE; // OpContext::Delegate implementation virtual void OnOpCreated(OpContext* context); virtual void OnOpStarted(OpContext* context); virtual void OnOpCompleted(OpContext* context); private: SignedSettingsHelperImpl(); ~SignedSettingsHelperImpl(); void AddOpContext(OpContext* context); void ClearAll(); std::vector pending_contexts_; friend struct base::DefaultLazyInstanceTraits; DISALLOW_COPY_AND_ASSIGN(SignedSettingsHelperImpl); }; static base::LazyInstance g_signed_settings_helper_impl(base::LINKER_INITIALIZED); SignedSettingsHelperImpl::SignedSettingsHelperImpl() { } SignedSettingsHelperImpl::~SignedSettingsHelperImpl() { if (!pending_contexts_.empty()) { LOG(WARNING) << "SignedSettingsHelperImpl shutdown with pending ops, " << "changes will be lost."; ClearAll(); } } void SignedSettingsHelperImpl::StartCheckWhitelistOp( const std::string&email, SignedSettingsHelper::Callback* callback) { AddOpContext(new WhitelistOpContext( WhitelistOpContext::CHECK, email, callback, this)); } void SignedSettingsHelperImpl::StartWhitelistOp( const std::string&email, bool add_to_whitelist, SignedSettingsHelper::Callback* callback) { AddOpContext(new WhitelistOpContext( add_to_whitelist ? WhitelistOpContext::ADD : WhitelistOpContext::REMOVE, email, callback, this)); } void SignedSettingsHelperImpl::StartStorePropertyOp( const std::string& name, const std::string& value, SignedSettingsHelper::Callback* callback) { AddOpContext(new StorePropertyOpContext( name, value, callback, this)); } void SignedSettingsHelperImpl::StartRetrieveProperty( const std::string& name, SignedSettingsHelper::Callback* callback) { AddOpContext(new RetrievePropertyOpContext( name, callback, this)); } void SignedSettingsHelperImpl::StartStorePolicyOp( const em::PolicyFetchResponse& policy, SignedSettingsHelper::Callback* callback) { AddOpContext(new StorePolicyOpContext(policy, callback, this)); } void SignedSettingsHelperImpl::StartRetrievePolicyOp( SignedSettingsHelper::Callback* callback) { AddOpContext(new RetrievePolicyOpContext(callback, this)); } void SignedSettingsHelperImpl::CancelCallback( SignedSettingsHelper::Callback* callback) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); for (size_t i = 0; i < pending_contexts_.size(); ++i) { if (pending_contexts_[i]->callback() == callback) { pending_contexts_[i]->CancelCallback(); } } } void SignedSettingsHelperImpl::AddOpContext(OpContext* context) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); CHECK(context); pending_contexts_.push_back(context); if (pending_contexts_.size() == 1) context->Execute(); } void SignedSettingsHelperImpl::ClearAll() { for (size_t i = 0; i < pending_contexts_.size(); ++i) { pending_contexts_[i]->set_delegate(NULL); pending_contexts_[i]->Cancel(); } pending_contexts_.clear(); } void SignedSettingsHelperImpl::OnOpCreated(OpContext* context) { if (test_delegate_) test_delegate_->OnOpCreated(context->op()); } void SignedSettingsHelperImpl::OnOpStarted(OpContext* context) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); if (test_delegate_) test_delegate_->OnOpStarted(context->op()); } void SignedSettingsHelperImpl::OnOpCompleted(OpContext* context) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); DCHECK(pending_contexts_.front() == context); pending_contexts_.erase(pending_contexts_.begin()); if (!pending_contexts_.empty()) pending_contexts_.front()->Execute(); if (test_delegate_) test_delegate_->OnOpCompleted(context->op()); } SignedSettingsHelper* SignedSettingsHelper::Get() { return g_signed_settings_helper_impl.Pointer(); } } // namespace chromeos