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     : 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