Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(634)

Side by Side Diff: components/offline_content/core/offline_content_aggregator.cc

Issue 2690333002: Initial checkin of OfflineContentProvider. (Closed)
Patch Set: Addressing initial comments. Will move to new directory next. Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2017 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 <algorithm>
6 #include <string>
7
8 #include "base/bind.h"
9 #include "base/memory/ptr_util.h"
10 #include "base/threading/thread_task_runner_handle.h"
11 #include "components/offline_content/core/offline_content_aggregator.h"
12 #include "components/offline_content/core/offline_item.h"
13
14 namespace offline_content {
15
16 namespace {
17
18 // Helper method to test whether or not a std::vector contains an item.
19 template <typename T>
20 bool VectorContains(const std::vector<T>& items, T item) {
21 return std::find(items.cbegin(), items.cend(), item) != items.end();
22 }
23
24 // Helper method to remove an item from an std::vector.
25 // Helper method to remove |observer| from |observers|.
26 template <typename T>
27 void RemoveFromVector(std::vector<T>& items, T item) {
28 auto it = std::find(items.begin(), items.end(), item);
29 if (it != items.end())
30 items.erase(it);
31 }
32
33 } // namespace
34
35 OfflineContentAggregator::OfflineContentAggregator()
36 : sent_on_items_available_(false), weak_ptr_factory_(this) {}
37
38 OfflineContentAggregator::~OfflineContentAggregator() = default;
39
40 void OfflineContentAggregator::RegisterProvider(
41 const std::string& name_space,
42 OfflineContentProvider* provider) {
43 // Validate that this is the first OfflineContentProvider registered that is
44 // associated with |name_space|.
45 DCHECK(provider);
46 DCHECK(providers_.find(name_space) == providers_.end());
47 DCHECK(pending_actions_.find(provider) == pending_actions_.end());
48
49 providers_[name_space] = provider;
50 provider->AddObserver(this);
51 }
52
53 void OfflineContentAggregator::UnregisterProvider(
54 const std::string& name_space) {
55 auto it = providers_.find(name_space);
56 DCHECK(it != providers_.end());
57
58 it->second->RemoveObserver(this);
59 pending_actions_.erase(it->second);
60 providers_.erase(it);
61 }
62
63 bool OfflineContentAggregator::AreItemsAvailable() {
64 return sent_on_items_available_;
65 }
66
67 void OfflineContentAggregator::OpenItem(const ContentId& id) {
68 auto it = providers_.find(id.name_space);
69
70 if (it == providers_.end())
71 return;
72
73 RunIfReady(it->second, base::Bind(&OfflineContentProvider::OpenItem,
74 base::Unretained(it->second), id));
75 }
76
77 void OfflineContentAggregator::RemoveItem(const ContentId& id) {
78 auto it = providers_.find(id.name_space);
79
80 if (it == providers_.end())
81 return;
82
83 RunIfReady(it->second, base::Bind(&OfflineContentProvider::RemoveItem,
84 base::Unretained(it->second), id));
85 }
86
87 void OfflineContentAggregator::CancelDownload(const ContentId& id) {
88 auto it = providers_.find(id.name_space);
89
90 if (it == providers_.end())
91 return;
92
93 RunIfReady(it->second, base::Bind(&OfflineContentProvider::CancelDownload,
94 base::Unretained(it->second), id));
95 }
96
97 void OfflineContentAggregator::PauseDownload(const ContentId& id) {
98 auto it = providers_.find(id.name_space);
99
100 if (it == providers_.end())
101 return;
102
103 RunIfReady(it->second, base::Bind(&OfflineContentProvider::PauseDownload,
104 base::Unretained(it->second), id));
105 }
106
107 void OfflineContentAggregator::ResumeDownload(const ContentId& id) {
108 auto it = providers_.find(id.name_space);
109
110 if (it == providers_.end())
111 return;
112
113 RunIfReady(it->second, base::Bind(&OfflineContentProvider::ResumeDownload,
114 base::Unretained(it->second), id));
115 }
116
117 const OfflineItem* OfflineContentAggregator::GetItemById(const ContentId& id) {
118 auto it = providers_.find(id.name_space);
119
120 if (it == providers_.end() || !it->second->AreItemsAvailable())
121 return nullptr;
122
123 return it->second->GetItemById(id);
124 }
125
126 OfflineContentProvider::OfflineItemList
127 OfflineContentAggregator::GetAllItems() {
128 OfflineItemList items;
129 for (auto& it : providers_) {
130 if (!it.second->AreItemsAvailable())
131 continue;
132
133 OfflineItemList provider_items = it.second->GetAllItems();
134 items.insert(items.end(), provider_items.begin(), provider_items.end());
135 }
136
137 return items;
138 }
139
140 void OfflineContentAggregator::AddObserver(
141 OfflineContentProvider::Observer* observer) {
142 DCHECK(observer);
143 if (observers_.HasObserver(observer))
144 return;
145
146 observers_.AddObserver(observer);
147
148 if (sent_on_items_available_) {
149 base::ThreadTaskRunnerHandle::Get()->PostTask(
150 FROM_HERE,
151 base::Bind(&OfflineContentAggregator::CheckAndNotifyItemsAvailable,
152 weak_ptr_factory_.GetWeakPtr()));
153 }
154 }
155
156 void OfflineContentAggregator::RemoveObserver(
157 OfflineContentProvider::Observer* observer) {
158 DCHECK(observer);
159 if (!observers_.HasObserver(observer))
160 return;
161
162 RemoveFromVector(signaled_observers_, observer);
163 observers_.RemoveObserver(observer);
164 }
165
166 void OfflineContentAggregator::OnItemsAvailable(
167 OfflineContentProvider* provider) {
168 // Flush any pending actions that should be mirrored to the provider.
169 FlushPendingActionsIfReady(provider);
170
171 // Some observers might already be under the impression that this class was
172 // initialized. Just treat this as an OnItemsAdded and notify those observers
173 // of the new items.
174 if (signaled_observers_.size() > 0) {
175 OfflineItemList items = provider->GetAllItems();
176 if (items.size() > 0) {
177 for (auto& observer : signaled_observers_) {
178 observer->OnItemsAdded(items);
179 }
180 }
181 }
182
183 // Check if there were any observers who haven't been told that this class is
184 // initialized yet. If so, notify them now.
185 CheckAndNotifyItemsAvailable();
186 }
187
188 void OfflineContentAggregator::OnItemsAdded(const OfflineItemList& items) {
189 for (auto& observer : observers_)
190 observer.OnItemsAdded(items);
191 }
192
193 void OfflineContentAggregator::OnItemRemoved(const ContentId& id) {
194 for (auto& observer : observers_)
195 observer.OnItemRemoved(id);
196 }
197
198 void OfflineContentAggregator::OnItemUpdated(const OfflineItem& item) {
199 for (auto& observer : observers_)
200 observer.OnItemUpdated(item);
201 }
202
203 void OfflineContentAggregator::CheckAndNotifyItemsAvailable() {
204 if (providers_.size() == 0)
205 return;
206
207 // If we haven't sent out the initialization message yet, make sure all
208 // underlying OfflineContentProviders are ready before notifying observers
209 // that we're ready to send items.
210 if (!sent_on_items_available_) {
211 for (auto& it : providers_) {
212 if (!it.second->AreItemsAvailable())
213 return;
214 }
215 }
216
217 // Notify all observers who haven't been told about the initialization that we
218 // are initialized. Track the observers so that we don't notify them again.
219 for (auto& observer : observers_) {
220 if (!VectorContains(signaled_observers_, &observer)) {
221 observer.OnItemsAvailable(this);
222 signaled_observers_.push_back(&observer);
223 }
224 }
225
226 // Track that we've told the world that we are initialized.
227 sent_on_items_available_ = true;
228 }
229
230 void OfflineContentAggregator::FlushPendingActionsIfReady(
231 OfflineContentProvider* provider) {
232 if (!provider->AreItemsAvailable())
233 return;
234
235 CallbackList actions = std::move(pending_actions_[provider]);
236 for (auto& action : actions) {
237 action.Run();
238
239 // Check to see if the OfflineContentProvider was removed during the call to
240 // |action|. If so stop the loop.
241 if (pending_actions_.find(provider) == pending_actions_.end())
242 return;
243 }
244 }
245
246 void OfflineContentAggregator::RunIfReady(OfflineContentProvider* provider,
247 const base::Closure& action) {
248 if (provider->AreItemsAvailable()) {
249 action.Run();
250 } else {
251 pending_actions_[provider].push_back(action);
252 }
253 }
254
255 } // namespace offline_content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698