// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/sync/notifier/non_blocking_invalidation_notifier.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop.h"
#include "base/observer_list_threadsafe.h"
#include "base/threading/thread.h"
#include "chrome/browser/sync/notifier/invalidation_notifier.h"
#include "chrome/browser/sync/notifier/sync_notifier_observer.h"
namespace sync_notifier {
class NonBlockingInvalidationNotifier::Core
: public base::RefCountedThreadSafe<NonBlockingInvalidationNotifier::Core>,
public SyncNotifierObserver {
public:
// Called on parent thread.
Core();
// Called on parent thread.
void AddObserver(SyncNotifierObserver* observer);
void RemoveObserver(SyncNotifierObserver* observer);
// Helpers called on I/O thread.
void Initialize(const notifier::NotifierOptions& notifier_options,
const std::string& client_info);
void Teardown();
void SetState(const std::string& state);
void UpdateCredentials(const std::string& email, const std::string& token);
void UpdateEnabledTypes(const syncable::ModelTypeSet& types);
void SendNotification();
// SyncNotifierObserver implementation (all called on I/O thread).
virtual void OnIncomingNotification(
const syncable::ModelTypePayloadMap& type_payloads);
virtual void OnNotificationStateChange(bool notifications_enabled);
virtual void StoreState(const std::string& state);
private:
friend class
base::RefCountedThreadSafe<NonBlockingInvalidationNotifier::Core>;
// Called on parent or I/O thread.
~Core();
scoped_ptr<InvalidationNotifier> invalidation_notifier_;
scoped_refptr<base::MessageLoopProxy> io_message_loop_proxy_;
scoped_refptr<ObserverListThreadSafe<SyncNotifierObserver> > observers_;
DISALLOW_COPY_AND_ASSIGN(Core);
};
NonBlockingInvalidationNotifier::Core::Core()
: observers_(new ObserverListThreadSafe<SyncNotifierObserver>()) {
}
NonBlockingInvalidationNotifier::Core::~Core() {
}
void NonBlockingInvalidationNotifier::Core::Initialize(
const notifier::NotifierOptions& notifier_options,
const std::string& client_info) {
DCHECK(notifier_options.request_context_getter);
DCHECK_EQ(notifier::NOTIFICATION_SERVER,
notifier_options.notification_method);
io_message_loop_proxy_ = notifier_options.request_context_getter->
GetIOMessageLoopProxy();
DCHECK(io_message_loop_proxy_->BelongsToCurrentThread());
invalidation_notifier_.reset(
new InvalidationNotifier(notifier_options, client_info));
invalidation_notifier_->AddObserver(this);
}
void NonBlockingInvalidationNotifier::Core::Teardown() {
DCHECK(io_message_loop_proxy_->BelongsToCurrentThread());
invalidation_notifier_->RemoveObserver(this);
invalidation_notifier_.reset();
io_message_loop_proxy_ = NULL;
}
void NonBlockingInvalidationNotifier::Core::AddObserver(
SyncNotifierObserver* observer) {
observers_->AddObserver(observer);
}
void NonBlockingInvalidationNotifier::Core::RemoveObserver(
SyncNotifierObserver* observer) {
observers_->RemoveObserver(observer);
}
void NonBlockingInvalidationNotifier::Core::SetState(
const std::string& state) {
DCHECK(io_message_loop_proxy_->BelongsToCurrentThread());
invalidation_notifier_->SetState(state);
}
void NonBlockingInvalidationNotifier::Core::UpdateCredentials(
const std::string& email, const std::string& token) {
DCHECK(io_message_loop_proxy_->BelongsToCurrentThread());
invalidation_notifier_->UpdateCredentials(email, token);
}
void NonBlockingInvalidationNotifier::Core::UpdateEnabledTypes(
const syncable::ModelTypeSet& types) {
DCHECK(io_message_loop_proxy_->BelongsToCurrentThread());
invalidation_notifier_->UpdateEnabledTypes(types);
}
void NonBlockingInvalidationNotifier::Core::OnIncomingNotification(
const syncable::ModelTypePayloadMap& type_payloads) {
DCHECK(io_message_loop_proxy_->BelongsToCurrentThread());
observers_->Notify(&SyncNotifierObserver::OnIncomingNotification,
type_payloads);
}
void NonBlockingInvalidationNotifier::Core::OnNotificationStateChange(
bool notifications_enabled) {
DCHECK(io_message_loop_proxy_->BelongsToCurrentThread());
observers_->Notify(&SyncNotifierObserver::OnNotificationStateChange,
notifications_enabled);
}
void NonBlockingInvalidationNotifier::Core::StoreState(
const std::string& state) {
DCHECK(io_message_loop_proxy_->BelongsToCurrentThread());
observers_->Notify(&SyncNotifierObserver::StoreState, state);
}
NonBlockingInvalidationNotifier::NonBlockingInvalidationNotifier(
const notifier::NotifierOptions& notifier_options,
const std::string& client_info)
: core_(new Core),
construction_message_loop_proxy_(
base::MessageLoopProxy::CreateForCurrentThread()),
io_message_loop_proxy_(notifier_options.request_context_getter->
GetIOMessageLoopProxy()) {
io_message_loop_proxy_->PostTask(
FROM_HERE,
NewRunnableMethod(
core_.get(),
&NonBlockingInvalidationNotifier::Core::Initialize,
notifier_options, client_info));
}
NonBlockingInvalidationNotifier::~NonBlockingInvalidationNotifier() {
DCHECK(construction_message_loop_proxy_->BelongsToCurrentThread());
io_message_loop_proxy_->PostTask(
FROM_HERE,
NewRunnableMethod(
core_.get(),
&NonBlockingInvalidationNotifier::Core::Teardown));
}
void NonBlockingInvalidationNotifier::AddObserver(
SyncNotifierObserver* observer) {
CheckOrSetValidThread();
core_->AddObserver(observer);
}
void NonBlockingInvalidationNotifier::RemoveObserver(
SyncNotifierObserver* observer) {
CheckOrSetValidThread();
core_->RemoveObserver(observer);
}
void NonBlockingInvalidationNotifier::SetState(const std::string& state) {
CheckOrSetValidThread();
io_message_loop_proxy_->PostTask(
FROM_HERE,
NewRunnableMethod(
core_.get(),
&NonBlockingInvalidationNotifier::Core::SetState,
state));
}
void NonBlockingInvalidationNotifier::UpdateCredentials(
const std::string& email, const std::string& token) {
CheckOrSetValidThread();
io_message_loop_proxy_->PostTask(
FROM_HERE,
NewRunnableMethod(
core_.get(),
&NonBlockingInvalidationNotifier::Core::UpdateCredentials,
email, token));
}
void NonBlockingInvalidationNotifier::UpdateEnabledTypes(
const syncable::ModelTypeSet& types) {
CheckOrSetValidThread();
io_message_loop_proxy_->PostTask(
FROM_HERE,
NewRunnableMethod(
core_.get(),
&NonBlockingInvalidationNotifier::Core::UpdateEnabledTypes,
types));
}
void NonBlockingInvalidationNotifier::SendNotification() {
CheckOrSetValidThread();
// InvalidationClient doesn't implement SendNotification(), so no
// need to forward on the call.
}
void NonBlockingInvalidationNotifier::CheckOrSetValidThread() {
if (method_message_loop_proxy_) {
DCHECK(method_message_loop_proxy_->BelongsToCurrentThread());
} else {
method_message_loop_proxy_ =
base::MessageLoopProxy::CreateForCurrentThread();
}
}
} // namespace sync_notifier