Home | History | Annotate | Download | only in listener
      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     : weak_ptr_factory_(this),
    160       delegate_task_runner_(delegate_task_runner),
    161       core_(new Core(delegate_task_runner_,
    162                      weak_ptr_factory_.GetWeakPtr())) {
    163   delegate_task_runner_->PostTask(
    164       FROM_HERE,
    165       base::Bind(&NonBlockingPushClient::Core::CreateOnDelegateThread,
    166                  core_.get(), create_blocking_push_client_callback));
    167 }
    168 
    169 NonBlockingPushClient::~NonBlockingPushClient() {
    170   DCHECK(thread_checker_.CalledOnValidThread());
    171   delegate_task_runner_->PostTask(
    172       FROM_HERE,
    173       base::Bind(&NonBlockingPushClient::Core::DestroyOnDelegateThread,
    174                  core_.get()));
    175 }
    176 
    177 void NonBlockingPushClient::AddObserver(PushClientObserver* observer) {
    178   DCHECK(thread_checker_.CalledOnValidThread());
    179   observers_.AddObserver(observer);
    180 }
    181 
    182 void NonBlockingPushClient::RemoveObserver(PushClientObserver* observer) {
    183   DCHECK(thread_checker_.CalledOnValidThread());
    184   observers_.RemoveObserver(observer);
    185 }
    186 
    187 void NonBlockingPushClient::UpdateSubscriptions(
    188     const SubscriptionList& subscriptions) {
    189   DCHECK(thread_checker_.CalledOnValidThread());
    190   delegate_task_runner_->PostTask(
    191       FROM_HERE,
    192       base::Bind(&NonBlockingPushClient::Core::UpdateSubscriptions,
    193                  core_.get(), subscriptions));
    194 }
    195 
    196 void NonBlockingPushClient::UpdateCredentials(
    197     const std::string& email, const std::string& token) {
    198   DCHECK(thread_checker_.CalledOnValidThread());
    199   delegate_task_runner_->PostTask(
    200       FROM_HERE,
    201       base::Bind(&NonBlockingPushClient::Core::UpdateCredentials,
    202                  core_.get(), email, token));
    203 }
    204 
    205 void NonBlockingPushClient::SendNotification(
    206     const Notification& notification) {
    207   DCHECK(thread_checker_.CalledOnValidThread());
    208   delegate_task_runner_->PostTask(
    209       FROM_HERE,
    210       base::Bind(&NonBlockingPushClient::Core::SendNotification, core_.get(),
    211                  notification));
    212 }
    213 
    214 void NonBlockingPushClient::SendPing() {
    215   DCHECK(thread_checker_.CalledOnValidThread());
    216   delegate_task_runner_->PostTask(
    217       FROM_HERE,
    218       base::Bind(&NonBlockingPushClient::Core::SendPing, core_.get()));
    219 }
    220 
    221 void NonBlockingPushClient::OnNotificationsEnabled() {
    222   DCHECK(thread_checker_.CalledOnValidThread());
    223   FOR_EACH_OBSERVER(PushClientObserver, observers_,
    224                     OnNotificationsEnabled());
    225 }
    226 
    227 void NonBlockingPushClient::OnNotificationsDisabled(
    228     NotificationsDisabledReason reason) {
    229   DCHECK(thread_checker_.CalledOnValidThread());
    230   FOR_EACH_OBSERVER(PushClientObserver, observers_,
    231                     OnNotificationsDisabled(reason));
    232 }
    233 
    234 void NonBlockingPushClient::OnIncomingNotification(
    235     const Notification& notification) {
    236   DCHECK(thread_checker_.CalledOnValidThread());
    237   FOR_EACH_OBSERVER(PushClientObserver, observers_,
    238                     OnIncomingNotification(notification));
    239 }
    240 
    241 void NonBlockingPushClient::OnPingResponse() {
    242   DCHECK(thread_checker_.CalledOnValidThread());
    243   FOR_EACH_OBSERVER(PushClientObserver, observers_, OnPingResponse());
    244 }
    245 
    246 }  // namespace notifier
    247