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

Unified Diff: components/offline_items_collection/core/offline_content_aggregator.cc

Issue 2690333002: Initial checkin of OfflineContentProvider. (Closed)
Patch Set: Moved files to components/offline_items_collection. 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 side-by-side diff with in-line comments
Download patch
Index: components/offline_items_collection/core/offline_content_aggregator.cc
diff --git a/components/offline_items_collection/core/offline_content_aggregator.cc b/components/offline_items_collection/core/offline_content_aggregator.cc
new file mode 100644
index 0000000000000000000000000000000000000000..222ffbd0696c82c883f2eb53983f761aa40ab6a0
--- /dev/null
+++ b/components/offline_items_collection/core/offline_content_aggregator.cc
@@ -0,0 +1,255 @@
+// Copyright 2017 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 <algorithm>
+#include <string>
+
+#include "base/bind.h"
+#include "base/memory/ptr_util.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "components/offline_items_collection/core/offline_content_aggregator.h"
+#include "components/offline_items_collection/core/offline_item.h"
+
+namespace offline_items_collection {
+
+namespace {
+
+// Helper method to test whether or not a std::vector contains an item.
+template <typename T>
+bool VectorContains(const std::vector<T>& items, T item) {
+ return std::find(items.cbegin(), items.cend(), item) != items.end();
+}
+
+// Helper method to remove an item from an std::vector.
+// Helper method to remove |observer| from |observers|.
+template <typename T>
+void RemoveFromVector(std::vector<T>& items, T item) {
+ auto it = std::find(items.begin(), items.end(), item);
+ if (it != items.end())
+ items.erase(it);
+}
+
+} // namespace
+
+OfflineContentAggregator::OfflineContentAggregator()
+ : sent_on_items_available_(false), weak_ptr_factory_(this) {}
+
+OfflineContentAggregator::~OfflineContentAggregator() = default;
+
+void OfflineContentAggregator::RegisterProvider(
+ const std::string& name_space,
+ OfflineContentProvider* provider) {
+ // Validate that this is the first OfflineContentProvider registered that is
+ // associated with |name_space|.
+ DCHECK(provider);
qinmin 2017/02/22 07:39:16 nit: not needed, if provider is null, we will cras
David Trainor- moved to gerrit 2017/03/03 00:34:12 Done.
+ DCHECK(providers_.find(name_space) == providers_.end());
+ DCHECK(pending_actions_.find(provider) == pending_actions_.end());
+
+ providers_[name_space] = provider;
+ provider->AddObserver(this);
+}
+
+void OfflineContentAggregator::UnregisterProvider(
+ const std::string& name_space) {
+ auto it = providers_.find(name_space);
+ DCHECK(it != providers_.end());
qinmin 2017/02/22 07:39:16 ditto
David Trainor- moved to gerrit 2017/03/03 00:34:12 Done.
+
+ it->second->RemoveObserver(this);
+ pending_actions_.erase(it->second);
+ providers_.erase(it);
+}
+
+bool OfflineContentAggregator::AreItemsAvailable() {
+ return sent_on_items_available_;
+}
+
+void OfflineContentAggregator::OpenItem(const ContentId& id) {
+ auto it = providers_.find(id.name_space);
qinmin 2017/02/22 07:39:16 lots of redundant code here, maybe a separate func
David Trainor- moved to gerrit 2017/03/03 00:34:12 Yeah I thought about it, but it ended up looking t
+
+ if (it == providers_.end())
+ return;
+
+ RunIfReady(it->second, base::Bind(&OfflineContentProvider::OpenItem,
+ base::Unretained(it->second), id));
+}
+
+void OfflineContentAggregator::RemoveItem(const ContentId& id) {
+ auto it = providers_.find(id.name_space);
+
+ if (it == providers_.end())
+ return;
+
+ RunIfReady(it->second, base::Bind(&OfflineContentProvider::RemoveItem,
+ base::Unretained(it->second), id));
+}
+
+void OfflineContentAggregator::CancelDownload(const ContentId& id) {
+ auto it = providers_.find(id.name_space);
+
+ if (it == providers_.end())
+ return;
+
+ RunIfReady(it->second, base::Bind(&OfflineContentProvider::CancelDownload,
+ base::Unretained(it->second), id));
+}
+
+void OfflineContentAggregator::PauseDownload(const ContentId& id) {
+ auto it = providers_.find(id.name_space);
+
+ if (it == providers_.end())
+ return;
+
+ RunIfReady(it->second, base::Bind(&OfflineContentProvider::PauseDownload,
+ base::Unretained(it->second), id));
+}
+
+void OfflineContentAggregator::ResumeDownload(const ContentId& id) {
+ auto it = providers_.find(id.name_space);
+
+ if (it == providers_.end())
+ return;
+
+ RunIfReady(it->second, base::Bind(&OfflineContentProvider::ResumeDownload,
+ base::Unretained(it->second), id));
+}
+
+const OfflineItem* OfflineContentAggregator::GetItemById(const ContentId& id) {
+ auto it = providers_.find(id.name_space);
+
+ if (it == providers_.end() || !it->second->AreItemsAvailable())
+ return nullptr;
+
+ return it->second->GetItemById(id);
+}
+
+OfflineContentProvider::OfflineItemList
+OfflineContentAggregator::GetAllItems() {
+ OfflineItemList items;
+ for (auto& it : providers_) {
+ if (!it.second->AreItemsAvailable())
+ continue;
+
+ OfflineItemList provider_items = it.second->GetAllItems();
+ items.insert(items.end(), provider_items.begin(), provider_items.end());
+ }
+
+ return items;
+}
+
+void OfflineContentAggregator::AddObserver(
+ OfflineContentProvider::Observer* observer) {
+ DCHECK(observer);
+ if (observers_.HasObserver(observer))
+ return;
+
+ observers_.AddObserver(observer);
+
+ if (sent_on_items_available_) {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::Bind(&OfflineContentAggregator::CheckAndNotifyItemsAvailable,
+ weak_ptr_factory_.GetWeakPtr()));
+ }
+}
+
+void OfflineContentAggregator::RemoveObserver(
+ OfflineContentProvider::Observer* observer) {
+ DCHECK(observer);
+ if (!observers_.HasObserver(observer))
+ return;
+
+ RemoveFromVector(signaled_observers_, observer);
+ observers_.RemoveObserver(observer);
+}
+
+void OfflineContentAggregator::OnItemsAvailable(
+ OfflineContentProvider* provider) {
+ // Flush any pending actions that should be mirrored to the provider.
+ FlushPendingActionsIfReady(provider);
+
+ // Some observers might already be under the impression that this class was
+ // initialized. Just treat this as an OnItemsAdded and notify those observers
+ // of the new items.
+ if (signaled_observers_.size() > 0) {
+ OfflineItemList items = provider->GetAllItems();
+ if (items.size() > 0) {
+ for (auto& observer : signaled_observers_) {
fgorski 2017/02/23 22:18:43 nit: you can drop the {}
David Trainor- moved to gerrit 2017/03/03 00:34:12 Done.
+ observer->OnItemsAdded(items);
+ }
+ }
+ }
+
+ // Check if there were any observers who haven't been told that this class is
+ // initialized yet. If so, notify them now.
+ CheckAndNotifyItemsAvailable();
+}
+
+void OfflineContentAggregator::OnItemsAdded(const OfflineItemList& items) {
+ for (auto& observer : observers_)
+ observer.OnItemsAdded(items);
+}
+
+void OfflineContentAggregator::OnItemRemoved(const ContentId& id) {
+ for (auto& observer : observers_)
+ observer.OnItemRemoved(id);
+}
+
+void OfflineContentAggregator::OnItemUpdated(const OfflineItem& item) {
+ for (auto& observer : observers_)
+ observer.OnItemUpdated(item);
+}
+
+void OfflineContentAggregator::CheckAndNotifyItemsAvailable() {
+ if (providers_.size() == 0)
+ return;
+
+ // If we haven't sent out the initialization message yet, make sure all
+ // underlying OfflineContentProviders are ready before notifying observers
+ // that we're ready to send items.
+ if (!sent_on_items_available_) {
+ for (auto& it : providers_) {
+ if (!it.second->AreItemsAvailable())
+ return;
+ }
+ }
+
+ // Notify all observers who haven't been told about the initialization that we
+ // are initialized. Track the observers so that we don't notify them again.
+ for (auto& observer : observers_) {
+ if (!VectorContains(signaled_observers_, &observer)) {
+ observer.OnItemsAvailable(this);
+ signaled_observers_.push_back(&observer);
+ }
+ }
+
+ // Track that we've told the world that we are initialized.
+ sent_on_items_available_ = true;
+}
+
+void OfflineContentAggregator::FlushPendingActionsIfReady(
+ OfflineContentProvider* provider) {
+ if (!provider->AreItemsAvailable())
+ return;
+
+ CallbackList actions = std::move(pending_actions_[provider]);
+ for (auto& action : actions) {
+ action.Run();
+
+ // Check to see if the OfflineContentProvider was removed during the call to
+ // |action|. If so stop the loop.
+ if (pending_actions_.find(provider) == pending_actions_.end())
fgorski 2017/02/23 22:18:43 did you mean to check in providers_ and not in pen
David Trainor- moved to gerrit 2017/03/03 00:34:12 providers_ is keyed off of the namespace not the O
fgorski 2017/03/03 17:57:47 Acknowledged.
+ return;
+ }
+}
+
+void OfflineContentAggregator::RunIfReady(OfflineContentProvider* provider,
+ const base::Closure& action) {
+ if (provider->AreItemsAvailable()) {
qinmin 2017/02/22 07:39:16 nit: {} not needed
David Trainor- moved to gerrit 2017/03/03 00:34:12 Done.
+ action.Run();
+ } else {
+ pending_actions_[provider].push_back(action);
+ }
+}
+
+} // namespace offline_items_collection

Powered by Google App Engine
This is Rietveld 408576698