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