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 "sync/notifier/invalidator_registrar.h"
6
7#include <cstddef>
8#include <iterator>
9#include <utility>
10
11#include "base/logging.h"
12#include "sync/notifier/object_id_invalidation_map.h"
13
14namespace syncer {
15
16InvalidatorRegistrar::InvalidatorRegistrar()
17    : state_(DEFAULT_INVALIDATION_ERROR) {}
18
19InvalidatorRegistrar::~InvalidatorRegistrar() {
20  DCHECK(thread_checker_.CalledOnValidThread());
21  CHECK(!handlers_.might_have_observers());
22  CHECK(handler_to_ids_map_.empty());
23}
24
25void InvalidatorRegistrar::RegisterHandler(InvalidationHandler* handler) {
26  DCHECK(thread_checker_.CalledOnValidThread());
27  CHECK(handler);
28  CHECK(!handlers_.HasObserver(handler));
29  handlers_.AddObserver(handler);
30}
31
32void InvalidatorRegistrar::UpdateRegisteredIds(
33    InvalidationHandler* handler,
34    const ObjectIdSet& ids) {
35  DCHECK(thread_checker_.CalledOnValidThread());
36  CHECK(handler);
37  CHECK(handlers_.HasObserver(handler));
38
39  for (HandlerIdsMap::const_iterator it = handler_to_ids_map_.begin();
40       it != handler_to_ids_map_.end(); ++it) {
41    if (it->first == handler) {
42      continue;
43    }
44
45    std::vector<invalidation::ObjectId> intersection;
46    std::set_intersection(
47        it->second.begin(), it->second.end(),
48        ids.begin(), ids.end(),
49        std::inserter(intersection, intersection.end()),
50        ObjectIdLessThan());
51    CHECK(intersection.empty())
52        << "Duplicate registration: trying to register "
53        << ObjectIdToString(*intersection.begin()) << " for "
54        << handler << " when it's already registered for "
55        << it->first;
56  }
57
58  if (ids.empty()) {
59    handler_to_ids_map_.erase(handler);
60  } else {
61    handler_to_ids_map_[handler] = ids;
62  }
63}
64
65void InvalidatorRegistrar::UnregisterHandler(InvalidationHandler* handler) {
66  DCHECK(thread_checker_.CalledOnValidThread());
67  CHECK(handler);
68  CHECK(handlers_.HasObserver(handler));
69  handlers_.RemoveObserver(handler);
70  handler_to_ids_map_.erase(handler);
71}
72
73ObjectIdSet InvalidatorRegistrar::GetRegisteredIds(
74    InvalidationHandler* handler) const {
75  DCHECK(thread_checker_.CalledOnValidThread());
76  HandlerIdsMap::const_iterator lookup = handler_to_ids_map_.find(handler);
77  if (lookup != handler_to_ids_map_.end()) {
78    return lookup->second;
79  } else {
80    return ObjectIdSet();
81  }
82}
83
84ObjectIdSet InvalidatorRegistrar::GetAllRegisteredIds() const {
85  DCHECK(thread_checker_.CalledOnValidThread());
86  ObjectIdSet registered_ids;
87  for (HandlerIdsMap::const_iterator it = handler_to_ids_map_.begin();
88       it != handler_to_ids_map_.end(); ++it) {
89    registered_ids.insert(it->second.begin(), it->second.end());
90  }
91  return registered_ids;
92}
93
94void InvalidatorRegistrar::DispatchInvalidationsToHandlers(
95    const ObjectIdInvalidationMap& invalidation_map) {
96  DCHECK(thread_checker_.CalledOnValidThread());
97  // If we have no handlers, there's nothing to do.
98  if (!handlers_.might_have_observers()) {
99    return;
100  }
101
102  for (HandlerIdsMap::iterator it = handler_to_ids_map_.begin();
103       it != handler_to_ids_map_.end(); ++it) {
104    ObjectIdInvalidationMap to_emit =
105        invalidation_map.GetSubsetWithObjectIds(it->second);
106    if (!to_emit.Empty()) {
107      it->first->OnIncomingInvalidation(to_emit);
108    }
109  }
110}
111
112void InvalidatorRegistrar::UpdateInvalidatorState(InvalidatorState state) {
113  DCHECK(thread_checker_.CalledOnValidThread());
114  DVLOG(1) << "New invalidator state: " << InvalidatorStateToString(state_)
115      << " -> " << InvalidatorStateToString(state);
116  state_ = state;
117  FOR_EACH_OBSERVER(InvalidationHandler, handlers_,
118                    OnInvalidatorStateChange(state));
119}
120
121InvalidatorState InvalidatorRegistrar::GetInvalidatorState() const {
122  DCHECK(thread_checker_.CalledOnValidThread());
123  return state_;
124}
125
126bool InvalidatorRegistrar::IsHandlerRegisteredForTest(
127    InvalidationHandler* handler) const {
128  DCHECK(thread_checker_.CalledOnValidThread());
129  return handlers_.HasObserver(handler);
130}
131
132void InvalidatorRegistrar::DetachFromThreadForTest() {
133  DCHECK(thread_checker_.CalledOnValidThread());
134  thread_checker_.DetachFromThread();
135}
136
137}  // namespace syncer
138