1 // Copyright (c) 2012 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 "jingle/notifier/listener/non_blocking_push_client.h" 6 7 #include "base/bind.h" 8 #include "base/location.h" 9 #include "base/logging.h" 10 #include "base/message_loop/message_loop_proxy.h" 11 #include "jingle/notifier/listener/push_client_observer.h" 12 13 namespace notifier { 14 15 // All methods are called on the delegate thread unless specified 16 // otherwise. 17 class NonBlockingPushClient::Core 18 : public base::RefCountedThreadSafe<NonBlockingPushClient::Core>, 19 public PushClientObserver { 20 public: 21 // Called on the parent thread. 22 explicit Core( 23 const scoped_refptr<base::SingleThreadTaskRunner>& 24 delegate_task_runner, 25 const base::WeakPtr<NonBlockingPushClient>& parent_push_client); 26 27 // Must be called after being created. 28 // 29 // This is separated out from the constructor since posting tasks 30 // from the constructor is dangerous. 31 void CreateOnDelegateThread( 32 const CreateBlockingPushClientCallback& 33 create_blocking_push_client_callback); 34 35 // Must be called before being destroyed. 36 void DestroyOnDelegateThread(); 37 38 void UpdateSubscriptions(const SubscriptionList& subscriptions); 39 void UpdateCredentials(const std::string& email, const std::string& token); 40 void SendNotification(const Notification& data); 41 void SendPing(); 42 43 virtual void OnNotificationsEnabled() OVERRIDE; 44 virtual void OnNotificationsDisabled( 45 NotificationsDisabledReason reason) OVERRIDE; 46 virtual void OnIncomingNotification( 47 const Notification& notification) OVERRIDE; 48 virtual void OnPingResponse() OVERRIDE; 49 50 private: 51 friend class base::RefCountedThreadSafe<NonBlockingPushClient::Core>; 52 53 // Called on either the parent thread or the delegate thread. 54 virtual ~Core(); 55 56 const scoped_refptr<base::SingleThreadTaskRunner> parent_task_runner_; 57 const scoped_refptr<base::SingleThreadTaskRunner> delegate_task_runner_; 58 59 const base::WeakPtr<NonBlockingPushClient> parent_push_client_; 60 scoped_ptr<PushClient> delegate_push_client_; 61 62 DISALLOW_COPY_AND_ASSIGN(Core); 63 }; 64 65 NonBlockingPushClient::Core::Core( 66 const scoped_refptr<base::SingleThreadTaskRunner>& delegate_task_runner, 67 const base::WeakPtr<NonBlockingPushClient>& parent_push_client) 68 : parent_task_runner_(base::MessageLoopProxy::current()), 69 delegate_task_runner_(delegate_task_runner), 70 parent_push_client_(parent_push_client) {} 71 72 NonBlockingPushClient::Core::~Core() { 73 DCHECK(parent_task_runner_->BelongsToCurrentThread() || 74 delegate_task_runner_->BelongsToCurrentThread()); 75 DCHECK(!delegate_push_client_.get()); 76 } 77 78 void NonBlockingPushClient::Core::CreateOnDelegateThread( 79 const CreateBlockingPushClientCallback& 80 create_blocking_push_client_callback) { 81 DCHECK(delegate_task_runner_->BelongsToCurrentThread()); 82 DCHECK(!delegate_push_client_.get()); 83 delegate_push_client_ = create_blocking_push_client_callback.Run(); 84 delegate_push_client_->AddObserver(this); 85 } 86 87 void NonBlockingPushClient::Core::DestroyOnDelegateThread() { 88 DCHECK(delegate_task_runner_->BelongsToCurrentThread()); 89 DCHECK(delegate_push_client_.get()); 90 delegate_push_client_->RemoveObserver(this); 91 delegate_push_client_.reset(); 92 } 93 94 void NonBlockingPushClient::Core::UpdateSubscriptions( 95 const SubscriptionList& subscriptions) { 96 DCHECK(delegate_task_runner_->BelongsToCurrentThread()); 97 DCHECK(delegate_push_client_.get()); 98 delegate_push_client_->UpdateSubscriptions(subscriptions); 99 } 100 101 void NonBlockingPushClient::Core::UpdateCredentials( 102 const std::string& email, const std::string& token) { 103 DCHECK(delegate_task_runner_->BelongsToCurrentThread()); 104 DCHECK(delegate_push_client_.get()); 105 delegate_push_client_->UpdateCredentials(email, token); 106 } 107 108 void NonBlockingPushClient::Core::SendNotification( 109 const Notification& notification) { 110 DCHECK(delegate_task_runner_->BelongsToCurrentThread()); 111 DCHECK(delegate_push_client_.get()); 112 delegate_push_client_->SendNotification(notification); 113 } 114 115 void NonBlockingPushClient::Core::SendPing() { 116 DCHECK(delegate_task_runner_->BelongsToCurrentThread()); 117 DCHECK(delegate_push_client_.get()); 118 delegate_push_client_->SendPing(); 119 } 120 121 void NonBlockingPushClient::Core::OnNotificationsEnabled() { 122 DCHECK(delegate_task_runner_->BelongsToCurrentThread()); 123 parent_task_runner_->PostTask( 124 FROM_HERE, 125 base::Bind(&NonBlockingPushClient::OnNotificationsEnabled, 126 parent_push_client_)); 127 } 128 129 void NonBlockingPushClient::Core::OnNotificationsDisabled( 130 NotificationsDisabledReason reason) { 131 DCHECK(delegate_task_runner_->BelongsToCurrentThread()); 132 parent_task_runner_->PostTask( 133 FROM_HERE, 134 base::Bind(&NonBlockingPushClient::OnNotificationsDisabled, 135 parent_push_client_, reason)); 136 } 137 138 void NonBlockingPushClient::Core::OnIncomingNotification( 139 const Notification& notification) { 140 DCHECK(delegate_task_runner_->BelongsToCurrentThread()); 141 parent_task_runner_->PostTask( 142 FROM_HERE, 143 base::Bind(&NonBlockingPushClient::OnIncomingNotification, 144 parent_push_client_, notification)); 145 } 146 147 void NonBlockingPushClient::Core::OnPingResponse() { 148 DCHECK(delegate_task_runner_->BelongsToCurrentThread()); 149 parent_task_runner_->PostTask( 150 FROM_HERE, 151 base::Bind(&NonBlockingPushClient::OnPingResponse, 152 parent_push_client_)); 153 } 154 155 NonBlockingPushClient::NonBlockingPushClient( 156 const scoped_refptr<base::SingleThreadTaskRunner>& delegate_task_runner, 157 const CreateBlockingPushClientCallback& 158 create_blocking_push_client_callback) 159 : delegate_task_runner_(delegate_task_runner), 160 weak_ptr_factory_(this) { 161 core_ = new Core(delegate_task_runner_, weak_ptr_factory_.GetWeakPtr()); 162 delegate_task_runner_->PostTask( 163 FROM_HERE, 164 base::Bind(&NonBlockingPushClient::Core::CreateOnDelegateThread, 165 core_.get(), create_blocking_push_client_callback)); 166 } 167 168 NonBlockingPushClient::~NonBlockingPushClient() { 169 DCHECK(thread_checker_.CalledOnValidThread()); 170 delegate_task_runner_->PostTask( 171 FROM_HERE, 172 base::Bind(&NonBlockingPushClient::Core::DestroyOnDelegateThread, 173 core_.get())); 174 } 175 176 void NonBlockingPushClient::AddObserver(PushClientObserver* observer) { 177 DCHECK(thread_checker_.CalledOnValidThread()); 178 observers_.AddObserver(observer); 179 } 180 181 void NonBlockingPushClient::RemoveObserver(PushClientObserver* observer) { 182 DCHECK(thread_checker_.CalledOnValidThread()); 183 observers_.RemoveObserver(observer); 184 } 185 186 void NonBlockingPushClient::UpdateSubscriptions( 187 const SubscriptionList& subscriptions) { 188 DCHECK(thread_checker_.CalledOnValidThread()); 189 delegate_task_runner_->PostTask( 190 FROM_HERE, 191 base::Bind(&NonBlockingPushClient::Core::UpdateSubscriptions, 192 core_.get(), subscriptions)); 193 } 194 195 void NonBlockingPushClient::UpdateCredentials( 196 const std::string& email, const std::string& token) { 197 DCHECK(thread_checker_.CalledOnValidThread()); 198 delegate_task_runner_->PostTask( 199 FROM_HERE, 200 base::Bind(&NonBlockingPushClient::Core::UpdateCredentials, 201 core_.get(), email, token)); 202 } 203 204 void NonBlockingPushClient::SendNotification( 205 const Notification& notification) { 206 DCHECK(thread_checker_.CalledOnValidThread()); 207 delegate_task_runner_->PostTask( 208 FROM_HERE, 209 base::Bind(&NonBlockingPushClient::Core::SendNotification, core_.get(), 210 notification)); 211 } 212 213 void NonBlockingPushClient::SendPing() { 214 DCHECK(thread_checker_.CalledOnValidThread()); 215 delegate_task_runner_->PostTask( 216 FROM_HERE, 217 base::Bind(&NonBlockingPushClient::Core::SendPing, core_.get())); 218 } 219 220 void NonBlockingPushClient::OnNotificationsEnabled() { 221 DCHECK(thread_checker_.CalledOnValidThread()); 222 FOR_EACH_OBSERVER(PushClientObserver, observers_, 223 OnNotificationsEnabled()); 224 } 225 226 void NonBlockingPushClient::OnNotificationsDisabled( 227 NotificationsDisabledReason reason) { 228 DCHECK(thread_checker_.CalledOnValidThread()); 229 FOR_EACH_OBSERVER(PushClientObserver, observers_, 230 OnNotificationsDisabled(reason)); 231 } 232 233 void NonBlockingPushClient::OnIncomingNotification( 234 const Notification& notification) { 235 DCHECK(thread_checker_.CalledOnValidThread()); 236 FOR_EACH_OBSERVER(PushClientObserver, observers_, 237 OnIncomingNotification(notification)); 238 } 239 240 void NonBlockingPushClient::OnPingResponse() { 241 DCHECK(thread_checker_.CalledOnValidThread()); 242 FOR_EACH_OBSERVER(PushClientObserver, observers_, OnPingResponse()); 243 } 244 245 } // namespace notifier 246