// 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 <iterator>
#include <utility>
#include "base/logging.h"
#include "sync/notifier/object_id_invalidation_map.h"
namespace syncer {
InvalidatorRegistrar::InvalidatorRegistrar()
: state_(DEFAULT_INVALIDATION_ERROR) {}
InvalidatorRegistrar::~InvalidatorRegistrar() {
DCHECK(thread_checker_.CalledOnValidThread());
CHECK(!handlers_.might_have_observers());
CHECK(handler_to_ids_map_.empty());
}
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));
for (HandlerIdsMap::const_iterator it = handler_to_ids_map_.begin();
it != handler_to_ids_map_.end(); ++it) {
if (it->first == handler) {
continue;
}
std::vector<invalidation::ObjectId> intersection;
std::set_intersection(
it->second.begin(), it->second.end(),
ids.begin(), ids.end(),
std::inserter(intersection, intersection.end()),
ObjectIdLessThan());
CHECK(intersection.empty())
<< "Duplicate registration: trying to register "
<< ObjectIdToString(*intersection.begin()) << " for "
<< handler << " when it's already registered for "
<< it->first;
}
if (ids.empty()) {
handler_to_ids_map_.erase(handler);
} else {
handler_to_ids_map_[handler] = ids;
}
}
void InvalidatorRegistrar::UnregisterHandler(InvalidationHandler* handler) {
DCHECK(thread_checker_.CalledOnValidThread());
CHECK(handler);
CHECK(handlers_.HasObserver(handler));
handlers_.RemoveObserver(handler);
handler_to_ids_map_.erase(handler);
}
ObjectIdSet InvalidatorRegistrar::GetRegisteredIds(
InvalidationHandler* handler) const {
DCHECK(thread_checker_.CalledOnValidThread());
HandlerIdsMap::const_iterator lookup = handler_to_ids_map_.find(handler);
if (lookup != handler_to_ids_map_.end()) {
return lookup->second;
} else {
return ObjectIdSet();
}
}
ObjectIdSet InvalidatorRegistrar::GetAllRegisteredIds() const {
DCHECK(thread_checker_.CalledOnValidThread());
ObjectIdSet registered_ids;
for (HandlerIdsMap::const_iterator it = handler_to_ids_map_.begin();
it != handler_to_ids_map_.end(); ++it) {
registered_ids.insert(it->second.begin(), it->second.end());
}
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;
}
for (HandlerIdsMap::iterator it = handler_to_ids_map_.begin();
it != handler_to_ids_map_.end(); ++it) {
ObjectIdInvalidationMap to_emit =
invalidation_map.GetSubsetWithObjectIds(it->second);
if (!to_emit.Empty()) {
it->first->OnIncomingInvalidation(to_emit);
}
}
}
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();
}
} // namespace syncer