// Copyright (c) 2012 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/glue/chrome_sync_notification_bridge.h" #include "base/bind.h" #include "base/location.h" #include "base/logging.h" #include "base/memory/scoped_ptr.h" #include "chrome/common/chrome_notification_types.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/notification_service.h" #include "sync/internal_api/public/base/model_type.h" #include "sync/notifier/invalidation_handler.h" #include "sync/notifier/invalidator_registrar.h" using content::BrowserThread; namespace browser_sync { class ChromeSyncNotificationBridge::Core : public base::RefCountedThreadSafe { public: // Created on UI thread. explicit Core( const scoped_refptr& sync_task_runner); // All member functions below must be called on the sync task runner. void InitializeOnSyncThread(); void CleanupOnSyncThread(); void RegisterHandler(syncer::InvalidationHandler* handler); void UpdateRegisteredIds(syncer::InvalidationHandler* handler, const syncer::ObjectIdSet& ids); void UnregisterHandler(syncer::InvalidationHandler* handler); void EmitInvalidation( const syncer::ObjectIdStateMap& state_map, syncer::IncomingInvalidationSource invalidation_source); bool IsHandlerRegisteredForTest(syncer::InvalidationHandler* handler) const; syncer::ObjectIdSet GetRegisteredIdsForTest( syncer::InvalidationHandler* handler) const; private: friend class base::RefCountedThreadSafe; // Destroyed on the UI thread or on |sync_task_runner_|. ~Core(); const scoped_refptr sync_task_runner_; // Used only on |sync_task_runner_|. scoped_ptr invalidator_registrar_; }; ChromeSyncNotificationBridge::Core::Core( const scoped_refptr& sync_task_runner) : sync_task_runner_(sync_task_runner) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); DCHECK(sync_task_runner_.get()); } ChromeSyncNotificationBridge::Core::~Core() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) || sync_task_runner_->RunsTasksOnCurrentThread()); DCHECK(!invalidator_registrar_.get()); } void ChromeSyncNotificationBridge::Core::InitializeOnSyncThread() { invalidator_registrar_.reset(new syncer::InvalidatorRegistrar()); } void ChromeSyncNotificationBridge::Core::CleanupOnSyncThread() { invalidator_registrar_.reset(); } void ChromeSyncNotificationBridge::Core::RegisterHandler( syncer::InvalidationHandler* handler) { DCHECK(sync_task_runner_->RunsTasksOnCurrentThread()); invalidator_registrar_->RegisterHandler(handler); } void ChromeSyncNotificationBridge::Core::UpdateRegisteredIds( syncer::InvalidationHandler* handler, const syncer::ObjectIdSet& ids) { DCHECK(sync_task_runner_->RunsTasksOnCurrentThread()); invalidator_registrar_->UpdateRegisteredIds(handler, ids); } void ChromeSyncNotificationBridge::Core::UnregisterHandler( syncer::InvalidationHandler* handler) { DCHECK(sync_task_runner_->RunsTasksOnCurrentThread()); invalidator_registrar_->UnregisterHandler(handler); } void ChromeSyncNotificationBridge::Core::EmitInvalidation( const syncer::ObjectIdStateMap& state_map, syncer::IncomingInvalidationSource invalidation_source) { DCHECK(sync_task_runner_->RunsTasksOnCurrentThread()); const syncer::ObjectIdStateMap& effective_state_map = state_map.empty() ? ObjectIdSetToStateMap( invalidator_registrar_->GetAllRegisteredIds(), std::string()) : state_map; invalidator_registrar_->DispatchInvalidationsToHandlers( effective_state_map, invalidation_source); } bool ChromeSyncNotificationBridge::Core::IsHandlerRegisteredForTest( syncer::InvalidationHandler* handler) const { DCHECK(sync_task_runner_->RunsTasksOnCurrentThread()); return invalidator_registrar_->IsHandlerRegisteredForTest(handler); } syncer::ObjectIdSet ChromeSyncNotificationBridge::Core::GetRegisteredIdsForTest( syncer::InvalidationHandler* handler) const { DCHECK(sync_task_runner_->RunsTasksOnCurrentThread()); return invalidator_registrar_->GetRegisteredIds(handler); } ChromeSyncNotificationBridge::ChromeSyncNotificationBridge( const Profile* profile, const scoped_refptr& sync_task_runner) : sync_task_runner_(sync_task_runner), core_(new Core(sync_task_runner_)) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); DCHECK(profile); registrar_.Add(this, chrome::NOTIFICATION_SYNC_REFRESH_LOCAL, content::Source(profile)); registrar_.Add(this, chrome::NOTIFICATION_SYNC_REFRESH_REMOTE, content::Source(profile)); if (!sync_task_runner_->PostTask( FROM_HERE, base::Bind(&Core::InitializeOnSyncThread, core_))) { NOTREACHED(); } } ChromeSyncNotificationBridge::~ChromeSyncNotificationBridge() {} void ChromeSyncNotificationBridge::StopForShutdown() { if (!sync_task_runner_->PostTask( FROM_HERE, base::Bind(&Core::CleanupOnSyncThread, core_))) { NOTREACHED(); } } void ChromeSyncNotificationBridge::RegisterHandler( syncer::InvalidationHandler* handler) { DCHECK(sync_task_runner_->RunsTasksOnCurrentThread()); core_->RegisterHandler(handler); } void ChromeSyncNotificationBridge::UpdateRegisteredIds( syncer::InvalidationHandler* handler, const syncer::ObjectIdSet& ids) { DCHECK(sync_task_runner_->RunsTasksOnCurrentThread()); core_->UpdateRegisteredIds(handler, ids); } void ChromeSyncNotificationBridge::UnregisterHandler( syncer::InvalidationHandler* handler) { DCHECK(sync_task_runner_->RunsTasksOnCurrentThread()); core_->UnregisterHandler(handler); } bool ChromeSyncNotificationBridge::IsHandlerRegisteredForTest( syncer::InvalidationHandler* handler) const { DCHECK(sync_task_runner_->RunsTasksOnCurrentThread()); return core_->IsHandlerRegisteredForTest(handler); } syncer::ObjectIdSet ChromeSyncNotificationBridge::GetRegisteredIdsForTest( syncer::InvalidationHandler* handler) const { DCHECK(sync_task_runner_->RunsTasksOnCurrentThread()); return core_->GetRegisteredIdsForTest(handler); } void ChromeSyncNotificationBridge::Observe( int type, const content::NotificationSource& source, const content::NotificationDetails& details) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); syncer::IncomingInvalidationSource invalidation_source; if (type == chrome::NOTIFICATION_SYNC_REFRESH_LOCAL) { invalidation_source = syncer::LOCAL_INVALIDATION; } else if (type == chrome::NOTIFICATION_SYNC_REFRESH_REMOTE) { invalidation_source = syncer::REMOTE_INVALIDATION; } else { NOTREACHED() << "Unexpected invalidation type: " << type; return; } // TODO(akalin): Use ObjectIdStateMap here instead. We'll have to // make sure all emitters of the relevant notifications also use // ObjectIdStateMap. content::Details state_details(details); const syncer::ModelTypeStateMap& state_map = *(state_details.ptr()); if (!sync_task_runner_->PostTask( FROM_HERE, base::Bind(&Core::EmitInvalidation, core_, ModelTypeStateMapToObjectIdStateMap(state_map), invalidation_source))) { NOTREACHED(); } } } // namespace browser_sync