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 15namespace sync_notifier { 16 17class 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 55NonBlockingInvalidationNotifier::Core::Core() 56 : observers_(new ObserverListThreadSafe<SyncNotifierObserver>()) { 57} 58 59NonBlockingInvalidationNotifier::Core::~Core() { 60} 61 62void 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 77void 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 84void NonBlockingInvalidationNotifier::Core::AddObserver( 85 SyncNotifierObserver* observer) { 86 observers_->AddObserver(observer); 87} 88 89void NonBlockingInvalidationNotifier::Core::RemoveObserver( 90 SyncNotifierObserver* observer) { 91 observers_->RemoveObserver(observer); 92} 93 94void NonBlockingInvalidationNotifier::Core::SetState( 95 const std::string& state) { 96 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); 97 invalidation_notifier_->SetState(state); 98} 99 100void 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 106void NonBlockingInvalidationNotifier::Core::UpdateEnabledTypes( 107 const syncable::ModelTypeSet& types) { 108 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); 109 invalidation_notifier_->UpdateEnabledTypes(types); 110} 111 112void 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 119void NonBlockingInvalidationNotifier::Core::OnNotificationStateChange( 120 bool notifications_enabled) { 121 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); 122 observers_->Notify(&SyncNotifierObserver::OnNotificationStateChange, 123 notifications_enabled); 124} 125 126void NonBlockingInvalidationNotifier::Core::StoreState( 127 const std::string& state) { 128 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); 129 observers_->Notify(&SyncNotifierObserver::StoreState, state); 130} 131 132NonBlockingInvalidationNotifier::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 148NonBlockingInvalidationNotifier::~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 157void NonBlockingInvalidationNotifier::AddObserver( 158 SyncNotifierObserver* observer) { 159 CheckOrSetValidThread(); 160 core_->AddObserver(observer); 161} 162 163void NonBlockingInvalidationNotifier::RemoveObserver( 164 SyncNotifierObserver* observer) { 165 CheckOrSetValidThread(); 166 core_->RemoveObserver(observer); 167} 168 169void 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 179void 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 190void 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 201void NonBlockingInvalidationNotifier::SendNotification() { 202 CheckOrSetValidThread(); 203 // InvalidationClient doesn't implement SendNotification(), so no 204 // need to forward on the call. 205} 206 207void 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