Home | History | Annotate | Download | only in notifier
      1 // Copyright (c) 2011 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/sync/notifier/non_blocking_invalidation_notifier.h"
      6 
      7 #include "base/logging.h"
      8 #include "base/memory/scoped_ptr.h"
      9 #include "base/message_loop.h"
     10 #include "base/observer_list_threadsafe.h"
     11 #include "base/threading/thread.h"
     12 #include "chrome/browser/sync/notifier/invalidation_notifier.h"
     13 #include "chrome/browser/sync/notifier/sync_notifier_observer.h"
     14 
     15 namespace sync_notifier {
     16 
     17 class NonBlockingInvalidationNotifier::Core
     18     : public base::RefCountedThreadSafe<NonBlockingInvalidationNotifier::Core>,
     19       public SyncNotifierObserver {
     20  public:
     21   // Called on parent thread.
     22   Core();
     23 
     24   // Called on parent thread.
     25   void AddObserver(SyncNotifierObserver* observer);
     26   void RemoveObserver(SyncNotifierObserver* observer);
     27 
     28   // Helpers called on I/O thread.
     29   void Initialize(const notifier::NotifierOptions& notifier_options,
     30                   const std::string& client_info);
     31   void Teardown();
     32   void SetState(const std::string& state);
     33   void UpdateCredentials(const std::string& email, const std::string& token);
     34   void UpdateEnabledTypes(const syncable::ModelTypeSet& types);
     35   void SendNotification();
     36 
     37   // SyncNotifierObserver implementation (all called on I/O thread).
     38   virtual void OnIncomingNotification(
     39       const syncable::ModelTypePayloadMap& type_payloads);
     40   virtual void OnNotificationStateChange(bool notifications_enabled);
     41   virtual void StoreState(const std::string& state);
     42 
     43  private:
     44   friend class
     45       base::RefCountedThreadSafe<NonBlockingInvalidationNotifier::Core>;
     46   // Called on parent or I/O thread.
     47   ~Core();
     48 
     49   scoped_ptr<InvalidationNotifier> invalidation_notifier_;
     50   scoped_refptr<base::MessageLoopProxy> io_message_loop_proxy_;
     51   scoped_refptr<ObserverListThreadSafe<SyncNotifierObserver> > observers_;
     52   DISALLOW_COPY_AND_ASSIGN(Core);
     53 };
     54 
     55 NonBlockingInvalidationNotifier::Core::Core()
     56     : observers_(new ObserverListThreadSafe<SyncNotifierObserver>()) {
     57 }
     58 
     59 NonBlockingInvalidationNotifier::Core::~Core() {
     60 }
     61 
     62 void NonBlockingInvalidationNotifier::Core::Initialize(
     63     const notifier::NotifierOptions& notifier_options,
     64     const std::string& client_info) {
     65   DCHECK(notifier_options.request_context_getter);
     66   DCHECK_EQ(notifier::NOTIFICATION_SERVER,
     67             notifier_options.notification_method);
     68   io_message_loop_proxy_ = notifier_options.request_context_getter->
     69       GetIOMessageLoopProxy();
     70   DCHECK(io_message_loop_proxy_->BelongsToCurrentThread());
     71   invalidation_notifier_.reset(
     72       new InvalidationNotifier(notifier_options, client_info));
     73   invalidation_notifier_->AddObserver(this);
     74 }
     75 
     76 
     77 void NonBlockingInvalidationNotifier::Core::Teardown() {
     78   DCHECK(io_message_loop_proxy_->BelongsToCurrentThread());
     79   invalidation_notifier_->RemoveObserver(this);
     80   invalidation_notifier_.reset();
     81   io_message_loop_proxy_ = NULL;
     82 }
     83 
     84 void NonBlockingInvalidationNotifier::Core::AddObserver(
     85     SyncNotifierObserver* observer) {
     86   observers_->AddObserver(observer);
     87 }
     88 
     89 void NonBlockingInvalidationNotifier::Core::RemoveObserver(
     90     SyncNotifierObserver* observer) {
     91   observers_->RemoveObserver(observer);
     92 }
     93 
     94 void NonBlockingInvalidationNotifier::Core::SetState(
     95     const std::string& state) {
     96   DCHECK(io_message_loop_proxy_->BelongsToCurrentThread());
     97   invalidation_notifier_->SetState(state);
     98 }
     99 
    100 void NonBlockingInvalidationNotifier::Core::UpdateCredentials(
    101     const std::string& email, const std::string& token) {
    102   DCHECK(io_message_loop_proxy_->BelongsToCurrentThread());
    103   invalidation_notifier_->UpdateCredentials(email, token);
    104 }
    105 
    106 void NonBlockingInvalidationNotifier::Core::UpdateEnabledTypes(
    107     const syncable::ModelTypeSet& types) {
    108   DCHECK(io_message_loop_proxy_->BelongsToCurrentThread());
    109   invalidation_notifier_->UpdateEnabledTypes(types);
    110 }
    111 
    112 void NonBlockingInvalidationNotifier::Core::OnIncomingNotification(
    113         const syncable::ModelTypePayloadMap& type_payloads) {
    114   DCHECK(io_message_loop_proxy_->BelongsToCurrentThread());
    115   observers_->Notify(&SyncNotifierObserver::OnIncomingNotification,
    116                      type_payloads);
    117 }
    118 
    119 void NonBlockingInvalidationNotifier::Core::OnNotificationStateChange(
    120         bool notifications_enabled) {
    121   DCHECK(io_message_loop_proxy_->BelongsToCurrentThread());
    122   observers_->Notify(&SyncNotifierObserver::OnNotificationStateChange,
    123                      notifications_enabled);
    124 }
    125 
    126 void NonBlockingInvalidationNotifier::Core::StoreState(
    127     const std::string& state) {
    128   DCHECK(io_message_loop_proxy_->BelongsToCurrentThread());
    129   observers_->Notify(&SyncNotifierObserver::StoreState, state);
    130 }
    131 
    132 NonBlockingInvalidationNotifier::NonBlockingInvalidationNotifier(
    133     const notifier::NotifierOptions& notifier_options,
    134     const std::string& client_info)
    135         : core_(new Core),
    136           construction_message_loop_proxy_(
    137               base::MessageLoopProxy::CreateForCurrentThread()),
    138           io_message_loop_proxy_(notifier_options.request_context_getter->
    139               GetIOMessageLoopProxy()) {
    140   io_message_loop_proxy_->PostTask(
    141       FROM_HERE,
    142       NewRunnableMethod(
    143           core_.get(),
    144           &NonBlockingInvalidationNotifier::Core::Initialize,
    145           notifier_options, client_info));
    146 }
    147 
    148 NonBlockingInvalidationNotifier::~NonBlockingInvalidationNotifier() {
    149   DCHECK(construction_message_loop_proxy_->BelongsToCurrentThread());
    150   io_message_loop_proxy_->PostTask(
    151       FROM_HERE,
    152       NewRunnableMethod(
    153           core_.get(),
    154           &NonBlockingInvalidationNotifier::Core::Teardown));
    155 }
    156 
    157 void NonBlockingInvalidationNotifier::AddObserver(
    158     SyncNotifierObserver* observer) {
    159   CheckOrSetValidThread();
    160   core_->AddObserver(observer);
    161 }
    162 
    163 void NonBlockingInvalidationNotifier::RemoveObserver(
    164     SyncNotifierObserver* observer) {
    165   CheckOrSetValidThread();
    166   core_->RemoveObserver(observer);
    167 }
    168 
    169 void NonBlockingInvalidationNotifier::SetState(const std::string& state) {
    170   CheckOrSetValidThread();
    171   io_message_loop_proxy_->PostTask(
    172       FROM_HERE,
    173       NewRunnableMethod(
    174           core_.get(),
    175           &NonBlockingInvalidationNotifier::Core::SetState,
    176           state));
    177 }
    178 
    179 void NonBlockingInvalidationNotifier::UpdateCredentials(
    180     const std::string& email, const std::string& token) {
    181   CheckOrSetValidThread();
    182   io_message_loop_proxy_->PostTask(
    183       FROM_HERE,
    184       NewRunnableMethod(
    185           core_.get(),
    186           &NonBlockingInvalidationNotifier::Core::UpdateCredentials,
    187           email, token));
    188 }
    189 
    190 void NonBlockingInvalidationNotifier::UpdateEnabledTypes(
    191     const syncable::ModelTypeSet& types) {
    192   CheckOrSetValidThread();
    193   io_message_loop_proxy_->PostTask(
    194       FROM_HERE,
    195       NewRunnableMethod(
    196           core_.get(),
    197           &NonBlockingInvalidationNotifier::Core::UpdateEnabledTypes,
    198           types));
    199 }
    200 
    201 void NonBlockingInvalidationNotifier::SendNotification() {
    202   CheckOrSetValidThread();
    203   // InvalidationClient doesn't implement SendNotification(), so no
    204   // need to forward on the call.
    205 }
    206 
    207 void NonBlockingInvalidationNotifier::CheckOrSetValidThread() {
    208   if (method_message_loop_proxy_) {
    209     DCHECK(method_message_loop_proxy_->BelongsToCurrentThread());
    210   } else {
    211     method_message_loop_proxy_ =
    212         base::MessageLoopProxy::CreateForCurrentThread();
    213   }
    214 }
    215 
    216 }  // namespace sync_notifier
    217