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
Core()55 NonBlockingInvalidationNotifier::Core::Core()
56 : observers_(new ObserverListThreadSafe<SyncNotifierObserver>()) {
57 }
58
~Core()59 NonBlockingInvalidationNotifier::Core::~Core() {
60 }
61
Initialize(const notifier::NotifierOptions & notifier_options,const std::string & client_info)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
Teardown()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
AddObserver(SyncNotifierObserver * observer)84 void NonBlockingInvalidationNotifier::Core::AddObserver(
85 SyncNotifierObserver* observer) {
86 observers_->AddObserver(observer);
87 }
88
RemoveObserver(SyncNotifierObserver * observer)89 void NonBlockingInvalidationNotifier::Core::RemoveObserver(
90 SyncNotifierObserver* observer) {
91 observers_->RemoveObserver(observer);
92 }
93
SetState(const std::string & state)94 void NonBlockingInvalidationNotifier::Core::SetState(
95 const std::string& state) {
96 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread());
97 invalidation_notifier_->SetState(state);
98 }
99
UpdateCredentials(const std::string & email,const std::string & token)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
UpdateEnabledTypes(const syncable::ModelTypeSet & types)106 void NonBlockingInvalidationNotifier::Core::UpdateEnabledTypes(
107 const syncable::ModelTypeSet& types) {
108 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread());
109 invalidation_notifier_->UpdateEnabledTypes(types);
110 }
111
OnIncomingNotification(const syncable::ModelTypePayloadMap & type_payloads)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
OnNotificationStateChange(bool notifications_enabled)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
StoreState(const std::string & state)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
NonBlockingInvalidationNotifier(const notifier::NotifierOptions & notifier_options,const std::string & client_info)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
~NonBlockingInvalidationNotifier()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
AddObserver(SyncNotifierObserver * observer)157 void NonBlockingInvalidationNotifier::AddObserver(
158 SyncNotifierObserver* observer) {
159 CheckOrSetValidThread();
160 core_->AddObserver(observer);
161 }
162
RemoveObserver(SyncNotifierObserver * observer)163 void NonBlockingInvalidationNotifier::RemoveObserver(
164 SyncNotifierObserver* observer) {
165 CheckOrSetValidThread();
166 core_->RemoveObserver(observer);
167 }
168
SetState(const std::string & state)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
UpdateCredentials(const std::string & email,const std::string & token)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
UpdateEnabledTypes(const syncable::ModelTypeSet & types)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
SendNotification()201 void NonBlockingInvalidationNotifier::SendNotification() {
202 CheckOrSetValidThread();
203 // InvalidationClient doesn't implement SendNotification(), so no
204 // need to forward on the call.
205 }
206
CheckOrSetValidThread()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