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