| // 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 "sync/notifier/invalidator_registrar.h" |
| |
| #include <cstddef> |
| #include <utility> |
| |
| #include "base/logging.h" |
| |
| namespace syncer { |
| |
| InvalidatorRegistrar::InvalidatorRegistrar() |
| : state_(DEFAULT_INVALIDATION_ERROR) {} |
| |
| InvalidatorRegistrar::~InvalidatorRegistrar() { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| CHECK(!handlers_.might_have_observers()); |
| // |id_to_handler_map_| may be non-empty but that's okay. |
| } |
| |
| void InvalidatorRegistrar::RegisterHandler(InvalidationHandler* handler) { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| CHECK(handler); |
| CHECK(!handlers_.HasObserver(handler)); |
| handlers_.AddObserver(handler); |
| } |
| |
| void InvalidatorRegistrar::UpdateRegisteredIds( |
| InvalidationHandler* handler, |
| const ObjectIdSet& ids) { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| CHECK(handler); |
| CHECK(handlers_.HasObserver(handler)); |
| // Remove all existing entries for |handler|. |
| for (IdHandlerMap::iterator it = id_to_handler_map_.begin(); |
| it != id_to_handler_map_.end(); ) { |
| if (it->second == handler) { |
| IdHandlerMap::iterator erase_it = it; |
| ++it; |
| id_to_handler_map_.erase(erase_it); |
| } else { |
| ++it; |
| } |
| } |
| |
| // Now add the entries for |handler|. We keep track of the last insertion |
| // point so we only traverse the map once to insert all the new entries. |
| IdHandlerMap::iterator insert_it = id_to_handler_map_.begin(); |
| for (ObjectIdSet::const_iterator it = ids.begin(); it != ids.end(); ++it) { |
| insert_it = |
| id_to_handler_map_.insert(insert_it, std::make_pair(*it, handler)); |
| CHECK_EQ(handler, insert_it->second) |
| << "Duplicate registration: trying to register " |
| << ObjectIdToString(insert_it->first) << " for " |
| << handler << " when it's already registered for " |
| << insert_it->second; |
| } |
| } |
| |
| void InvalidatorRegistrar::UnregisterHandler(InvalidationHandler* handler) { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| CHECK(handler); |
| CHECK(handlers_.HasObserver(handler)); |
| handlers_.RemoveObserver(handler); |
| } |
| |
| ObjectIdSet InvalidatorRegistrar::GetRegisteredIds( |
| InvalidationHandler* handler) const { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| ObjectIdSet registered_ids; |
| for (IdHandlerMap::const_iterator it = id_to_handler_map_.begin(); |
| it != id_to_handler_map_.end(); ++it) { |
| if (it->second == handler) { |
| registered_ids.insert(it->first); |
| } |
| } |
| return registered_ids; |
| } |
| |
| ObjectIdSet InvalidatorRegistrar::GetAllRegisteredIds() const { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| ObjectIdSet registered_ids; |
| for (IdHandlerMap::const_iterator it = id_to_handler_map_.begin(); |
| it != id_to_handler_map_.end(); ++it) { |
| registered_ids.insert(it->first); |
| } |
| return registered_ids; |
| } |
| |
| void InvalidatorRegistrar::DispatchInvalidationsToHandlers( |
| const ObjectIdInvalidationMap& invalidation_map) { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| // If we have no handlers, there's nothing to do. |
| if (!handlers_.might_have_observers()) { |
| return; |
| } |
| |
| typedef std::map<InvalidationHandler*, ObjectIdInvalidationMap> DispatchMap; |
| DispatchMap dispatch_map; |
| for (ObjectIdInvalidationMap::const_iterator it = invalidation_map.begin(); |
| it != invalidation_map.end(); ++it) { |
| InvalidationHandler* const handler = ObjectIdToHandler(it->first); |
| // Filter out invalidations for IDs with no handler. |
| if (handler) |
| dispatch_map[handler].insert(*it); |
| } |
| |
| // Emit invalidations only for handlers in |handlers_|. |
| ObserverListBase<InvalidationHandler>::Iterator it(handlers_); |
| InvalidationHandler* handler = NULL; |
| while ((handler = it.GetNext()) != NULL) { |
| DispatchMap::const_iterator dispatch_it = dispatch_map.find(handler); |
| if (dispatch_it != dispatch_map.end()) |
| handler->OnIncomingInvalidation(dispatch_it->second); |
| } |
| } |
| |
| void InvalidatorRegistrar::UpdateInvalidatorState(InvalidatorState state) { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| DVLOG(1) << "New invalidator state: " << InvalidatorStateToString(state_) |
| << " -> " << InvalidatorStateToString(state); |
| state_ = state; |
| FOR_EACH_OBSERVER(InvalidationHandler, handlers_, |
| OnInvalidatorStateChange(state)); |
| } |
| |
| InvalidatorState InvalidatorRegistrar::GetInvalidatorState() const { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| return state_; |
| } |
| |
| bool InvalidatorRegistrar::IsHandlerRegisteredForTest( |
| InvalidationHandler* handler) const { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| return handlers_.HasObserver(handler); |
| } |
| |
| void InvalidatorRegistrar::DetachFromThreadForTest() { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| thread_checker_.DetachFromThread(); |
| } |
| |
| InvalidationHandler* InvalidatorRegistrar::ObjectIdToHandler( |
| const invalidation::ObjectId& id) { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| IdHandlerMap::const_iterator it = id_to_handler_map_.find(id); |
| return (it == id_to_handler_map_.end()) ? NULL : it->second; |
| } |
| |
| } // namespace syncer |