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.
5 #include "jingle/notifier/listener/non_blocking_push_client.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"
15 // All methods are called on the delegate thread unless specified
17 class NonBlockingPushClient::Core
18 : public base::RefCountedThreadSafe<NonBlockingPushClient::Core>,
19 public PushClientObserver {
21 // Called on the parent thread.
23 const scoped_refptr<base::SingleThreadTaskRunner>&
25 const base::WeakPtr<NonBlockingPushClient>& parent_push_client);
27 // Must be called after being created.
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);
35 // Must be called before being destroyed.
36 void DestroyOnDelegateThread();
38 void UpdateSubscriptions(const SubscriptionList& subscriptions);
39 void UpdateCredentials(const std::string& email, const std::string& token);
40 void SendNotification(const Notification& data);
43 void OnNotificationsEnabled() override;
44 void OnNotificationsDisabled(NotificationsDisabledReason reason) override;
45 void OnIncomingNotification(const Notification& notification) override;
46 void OnPingResponse() override;
49 friend class base::RefCountedThreadSafe<NonBlockingPushClient::Core>;
51 // Called on either the parent thread or the delegate thread.
54 const scoped_refptr<base::SingleThreadTaskRunner> parent_task_runner_;
55 const scoped_refptr<base::SingleThreadTaskRunner> delegate_task_runner_;
57 const base::WeakPtr<NonBlockingPushClient> parent_push_client_;
58 scoped_ptr<PushClient> delegate_push_client_;
60 DISALLOW_COPY_AND_ASSIGN(Core);
63 NonBlockingPushClient::Core::Core(
64 const scoped_refptr<base::SingleThreadTaskRunner>& delegate_task_runner,
65 const base::WeakPtr<NonBlockingPushClient>& parent_push_client)
66 : parent_task_runner_(base::MessageLoopProxy::current()),
67 delegate_task_runner_(delegate_task_runner),
68 parent_push_client_(parent_push_client) {}
70 NonBlockingPushClient::Core::~Core() {
71 DCHECK(parent_task_runner_->BelongsToCurrentThread() ||
72 delegate_task_runner_->BelongsToCurrentThread());
73 DCHECK(!delegate_push_client_.get());
76 void NonBlockingPushClient::Core::CreateOnDelegateThread(
77 const CreateBlockingPushClientCallback&
78 create_blocking_push_client_callback) {
79 DCHECK(delegate_task_runner_->BelongsToCurrentThread());
80 DCHECK(!delegate_push_client_.get());
81 delegate_push_client_ = create_blocking_push_client_callback.Run();
82 delegate_push_client_->AddObserver(this);
85 void NonBlockingPushClient::Core::DestroyOnDelegateThread() {
86 DCHECK(delegate_task_runner_->BelongsToCurrentThread());
87 DCHECK(delegate_push_client_.get());
88 delegate_push_client_->RemoveObserver(this);
89 delegate_push_client_.reset();
92 void NonBlockingPushClient::Core::UpdateSubscriptions(
93 const SubscriptionList& subscriptions) {
94 DCHECK(delegate_task_runner_->BelongsToCurrentThread());
95 DCHECK(delegate_push_client_.get());
96 delegate_push_client_->UpdateSubscriptions(subscriptions);
99 void NonBlockingPushClient::Core::UpdateCredentials(
100 const std::string& email, const std::string& token) {
101 DCHECK(delegate_task_runner_->BelongsToCurrentThread());
102 DCHECK(delegate_push_client_.get());
103 delegate_push_client_->UpdateCredentials(email, token);
106 void NonBlockingPushClient::Core::SendNotification(
107 const Notification& notification) {
108 DCHECK(delegate_task_runner_->BelongsToCurrentThread());
109 DCHECK(delegate_push_client_.get());
110 delegate_push_client_->SendNotification(notification);
113 void NonBlockingPushClient::Core::SendPing() {
114 DCHECK(delegate_task_runner_->BelongsToCurrentThread());
115 DCHECK(delegate_push_client_.get());
116 delegate_push_client_->SendPing();
119 void NonBlockingPushClient::Core::OnNotificationsEnabled() {
120 DCHECK(delegate_task_runner_->BelongsToCurrentThread());
121 parent_task_runner_->PostTask(
123 base::Bind(&NonBlockingPushClient::OnNotificationsEnabled,
124 parent_push_client_));
127 void NonBlockingPushClient::Core::OnNotificationsDisabled(
128 NotificationsDisabledReason reason) {
129 DCHECK(delegate_task_runner_->BelongsToCurrentThread());
130 parent_task_runner_->PostTask(
132 base::Bind(&NonBlockingPushClient::OnNotificationsDisabled,
133 parent_push_client_, reason));
136 void NonBlockingPushClient::Core::OnIncomingNotification(
137 const Notification& notification) {
138 DCHECK(delegate_task_runner_->BelongsToCurrentThread());
139 parent_task_runner_->PostTask(
141 base::Bind(&NonBlockingPushClient::OnIncomingNotification,
142 parent_push_client_, notification));
145 void NonBlockingPushClient::Core::OnPingResponse() {
146 DCHECK(delegate_task_runner_->BelongsToCurrentThread());
147 parent_task_runner_->PostTask(
149 base::Bind(&NonBlockingPushClient::OnPingResponse,
150 parent_push_client_));
153 NonBlockingPushClient::NonBlockingPushClient(
154 const scoped_refptr<base::SingleThreadTaskRunner>& delegate_task_runner,
155 const CreateBlockingPushClientCallback&
156 create_blocking_push_client_callback)
157 : delegate_task_runner_(delegate_task_runner),
158 weak_ptr_factory_(this) {
159 core_ = new Core(delegate_task_runner_, weak_ptr_factory_.GetWeakPtr());
160 delegate_task_runner_->PostTask(
162 base::Bind(&NonBlockingPushClient::Core::CreateOnDelegateThread,
163 core_.get(), create_blocking_push_client_callback));
166 NonBlockingPushClient::~NonBlockingPushClient() {
167 DCHECK(thread_checker_.CalledOnValidThread());
168 delegate_task_runner_->PostTask(
170 base::Bind(&NonBlockingPushClient::Core::DestroyOnDelegateThread,
174 void NonBlockingPushClient::AddObserver(PushClientObserver* observer) {
175 DCHECK(thread_checker_.CalledOnValidThread());
176 observers_.AddObserver(observer);
179 void NonBlockingPushClient::RemoveObserver(PushClientObserver* observer) {
180 DCHECK(thread_checker_.CalledOnValidThread());
181 observers_.RemoveObserver(observer);
184 void NonBlockingPushClient::UpdateSubscriptions(
185 const SubscriptionList& subscriptions) {
186 DCHECK(thread_checker_.CalledOnValidThread());
187 delegate_task_runner_->PostTask(
189 base::Bind(&NonBlockingPushClient::Core::UpdateSubscriptions,
190 core_.get(), subscriptions));
193 void NonBlockingPushClient::UpdateCredentials(
194 const std::string& email, const std::string& token) {
195 DCHECK(thread_checker_.CalledOnValidThread());
196 delegate_task_runner_->PostTask(
198 base::Bind(&NonBlockingPushClient::Core::UpdateCredentials,
199 core_.get(), email, token));
202 void NonBlockingPushClient::SendNotification(
203 const Notification& notification) {
204 DCHECK(thread_checker_.CalledOnValidThread());
205 delegate_task_runner_->PostTask(
207 base::Bind(&NonBlockingPushClient::Core::SendNotification, core_.get(),
211 void NonBlockingPushClient::SendPing() {
212 DCHECK(thread_checker_.CalledOnValidThread());
213 delegate_task_runner_->PostTask(
215 base::Bind(&NonBlockingPushClient::Core::SendPing, core_.get()));
218 void NonBlockingPushClient::OnNotificationsEnabled() {
219 DCHECK(thread_checker_.CalledOnValidThread());
220 FOR_EACH_OBSERVER(PushClientObserver, observers_,
221 OnNotificationsEnabled());
224 void NonBlockingPushClient::OnNotificationsDisabled(
225 NotificationsDisabledReason reason) {
226 DCHECK(thread_checker_.CalledOnValidThread());
227 FOR_EACH_OBSERVER(PushClientObserver, observers_,
228 OnNotificationsDisabled(reason));
231 void NonBlockingPushClient::OnIncomingNotification(
232 const Notification& notification) {
233 DCHECK(thread_checker_.CalledOnValidThread());
234 FOR_EACH_OBSERVER(PushClientObserver, observers_,
235 OnIncomingNotification(notification));
238 void NonBlockingPushClient::OnPingResponse() {
239 DCHECK(thread_checker_.CalledOnValidThread());
240 FOR_EACH_OBSERVER(PushClientObserver, observers_, OnPingResponse());
243 } // namespace notifier