summaryrefslogtreecommitdiffstats
path: root/components
diff options
context:
space:
mode:
authorshashishekhar@chromium.org <shashishekhar@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-12-10 07:43:37 +0000
committershashishekhar@chromium.org <shashishekhar@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-12-10 07:43:37 +0000
commit83bfe12526275b95775024d77940d56dc0484939 (patch)
treeb3f9fb0ab7c07839aff7a3286b8859f79f4d4e8a /components
parentd30312c50388d4eb51a34c5e168f7abf5feb257c (diff)
downloadchromium_src-83bfe12526275b95775024d77940d56dc0484939.zip
chromium_src-83bfe12526275b95775024d77940d56dc0484939.tar.gz
chromium_src-83bfe12526275b95775024d77940d56dc0484939.tar.bz2
Add an observer for article updates.
Define an observer that allows clients to listen to article updates. In a subsequent CL, I will hook the webui to observe article changes. BUG=288015 Review URL: https://codereview.chromium.org/100463005 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@239703 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'components')
-rw-r--r--components/dom_distiller.gypi1
-rw-r--r--components/dom_distiller/core/dom_distiller_observer.h39
-rw-r--r--components/dom_distiller/core/dom_distiller_service.cc10
-rw-r--r--components/dom_distiller/core/dom_distiller_service.h6
-rw-r--r--components/dom_distiller/core/dom_distiller_service_unittest.cc3
-rw-r--r--components/dom_distiller/core/dom_distiller_store.cc42
-rw-r--r--components/dom_distiller/core/dom_distiller_store.h12
-rw-r--r--components/dom_distiller/core/dom_distiller_store_unittest.cc89
8 files changed, 199 insertions, 3 deletions
diff --git a/components/dom_distiller.gypi b/components/dom_distiller.gypi
index ddc7b2e..1b6e6b4 100644
--- a/components/dom_distiller.gypi
+++ b/components/dom_distiller.gypi
@@ -76,6 +76,7 @@
'dom_distiller/core/dom_distiller_database.h',
'dom_distiller/core/dom_distiller_model.cc',
'dom_distiller/core/dom_distiller_model.h',
+ 'dom_distiller/core/dom_distiller_observer.h',
'dom_distiller/core/dom_distiller_service.cc',
'dom_distiller/core/dom_distiller_service.h',
'dom_distiller/core/dom_distiller_store.cc',
diff --git a/components/dom_distiller/core/dom_distiller_observer.h b/components/dom_distiller/core/dom_distiller_observer.h
new file mode 100644
index 0000000..4a99f69
--- /dev/null
+++ b/components/dom_distiller/core/dom_distiller_observer.h
@@ -0,0 +1,39 @@
+// Copyright 2013 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.
+
+#ifndef COMPONENTS_DOM_DISTILLER_CORE_DOM_DISTILLER_OBSERVER_H_
+#define COMPONENTS_DOM_DISTILLER_CORE_DOM_DISTILLER_OBSERVER_H_
+
+#include <vector>
+#include "components/dom_distiller/core/article_entry.h"
+
+namespace dom_distiller {
+
+// Provides notifications for any mutations to entries of the reading list.
+class DomDistillerObserver {
+ public:
+ // An update to an article entry.
+ struct ArticleUpdate {
+ enum UpdateType {
+ ADD,
+ UPDATE,
+ REMOVE
+ };
+ std::string entry_id;
+ UpdateType update_type;
+ };
+
+ virtual void ArticleEntriesUpdated(
+ const std::vector<ArticleUpdate>& updates) = 0;
+
+ protected:
+ DomDistillerObserver() {}
+ virtual ~DomDistillerObserver() {}
+
+ DISALLOW_COPY_AND_ASSIGN(DomDistillerObserver);
+};
+
+} // namespace dom_distiller
+
+#endif // COMPONENTS_DOM_DISTILLER_CORE_DOM_DISTILLER_OBSERVER_H_
diff --git a/components/dom_distiller/core/dom_distiller_service.cc b/components/dom_distiller/core/dom_distiller_service.cc
index fb2b380..35f8203 100644
--- a/components/dom_distiller/core/dom_distiller_service.cc
+++ b/components/dom_distiller/core/dom_distiller_service.cc
@@ -144,4 +144,14 @@ void DomDistillerService::AddDistilledPageToList(const ArticleEntry& entry,
store_->AddEntry(entry);
}
+void DomDistillerService::AddObserver(DomDistillerObserver* observer) {
+ DCHECK(observer);
+ store_->AddObserver(observer);
+}
+
+void DomDistillerService::RemoveObserver(DomDistillerObserver* observer) {
+ DCHECK(observer);
+ store_->RemoveObserver(observer);
+}
+
} // namespace dom_distiller
diff --git a/components/dom_distiller/core/dom_distiller_service.h b/components/dom_distiller/core/dom_distiller_service.h
index a75ba70..fc27d35 100644
--- a/components/dom_distiller/core/dom_distiller_service.h
+++ b/components/dom_distiller/core/dom_distiller_service.h
@@ -20,10 +20,11 @@ namespace dom_distiller {
class DistilledPageProto;
class DistillerFactory;
+class DomDistillerObserver;
class DomDistillerStoreInterface;
class TaskTracker;
-class ViewRequestDelegate;
class ViewerHandle;
+class ViewRequestDelegate;
// Provide a view of the article list and ways of interacting with it.
class DomDistillerService {
@@ -55,6 +56,9 @@ class DomDistillerService {
scoped_ptr<ViewerHandle> ViewUrl(ViewRequestDelegate* delegate,
const GURL& url);
+ void AddObserver(DomDistillerObserver* observer);
+ void RemoveObserver(DomDistillerObserver* observer);
+
private:
void CancelTask(TaskTracker* task);
void AddDistilledPageToList(const ArticleEntry& entry,
diff --git a/components/dom_distiller/core/dom_distiller_service_unittest.cc b/components/dom_distiller/core/dom_distiller_service_unittest.cc
index 6770b3f..a017eab 100644
--- a/components/dom_distiller/core/dom_distiller_service_unittest.cc
+++ b/components/dom_distiller/core/dom_distiller_service_unittest.cc
@@ -91,6 +91,9 @@ class FakeDomDistillerStore : public DomDistillerStoreInterface {
return NULL;
}
+ virtual void AddObserver(DomDistillerObserver* observer) OVERRIDE {}
+ virtual void RemoveObserver(DomDistillerObserver* observer) OVERRIDE {}
+
private:
DomDistillerModel model_;
};
diff --git a/components/dom_distiller/core/dom_distiller_store.cc b/components/dom_distiller/core/dom_distiller_store.cc
index 72d2470..ef585d0 100644
--- a/components/dom_distiller/core/dom_distiller_store.cc
+++ b/components/dom_distiller/core/dom_distiller_store.cc
@@ -121,6 +121,14 @@ bool DomDistillerStore::RemoveEntry(const ArticleEntry& entry) {
return true;
}
+void DomDistillerStore::AddObserver(DomDistillerObserver* observer) {
+ observers_.AddObserver(observer);
+}
+
+void DomDistillerStore::RemoveObserver(DomDistillerObserver* observer) {
+ observers_.RemoveObserver(observer);
+}
+
std::vector<ArticleEntry> DomDistillerStore::GetEntries() const {
return model_.GetEntries();
}
@@ -168,11 +176,45 @@ SyncError DomDistillerStore::ProcessSyncChanges(
return SyncError();
}
+void DomDistillerStore::NotifyObservers(const syncer::SyncChangeList& changes) {
+ if (observers_.might_have_observers() && changes.size() > 0) {
+ std::vector<DomDistillerObserver::ArticleUpdate> article_changes;
+ for (SyncChangeList::const_iterator it = changes.begin();
+ it != changes.end();
+ ++it) {
+ DomDistillerObserver::ArticleUpdate article_update;
+ switch (it->change_type()) {
+ case SyncChange::ACTION_ADD:
+ article_update.update_type = DomDistillerObserver::ArticleUpdate::ADD;
+ break;
+ case SyncChange::ACTION_UPDATE:
+ article_update.update_type =
+ DomDistillerObserver::ArticleUpdate::UPDATE;
+ break;
+ case SyncChange::ACTION_DELETE:
+ article_update.update_type =
+ DomDistillerObserver::ArticleUpdate::REMOVE;
+ break;
+ case SyncChange::ACTION_INVALID:
+ NOTREACHED();
+ break;
+ }
+ const ArticleEntry& entry = GetEntryFromChange(*it);
+ article_update.entry_id = entry.entry_id();
+ article_changes.push_back(article_update);
+ }
+ FOR_EACH_OBSERVER(DomDistillerObserver,
+ observers_,
+ ArticleEntriesUpdated(article_changes));
+ }
+}
+
void DomDistillerStore::ApplyChangesToModel(
const SyncChangeList& changes,
SyncChangeList* changes_applied,
SyncChangeList* changes_missing) {
model_.ApplyChangesToModel(changes, changes_applied, changes_missing);
+ NotifyObservers(*changes_applied);
}
void DomDistillerStore::OnDatabaseInit(bool success) {
diff --git a/components/dom_distiller/core/dom_distiller_store.h b/components/dom_distiller/core/dom_distiller_store.h
index d61b451..4328853 100644
--- a/components/dom_distiller/core/dom_distiller_store.h
+++ b/components/dom_distiller/core/dom_distiller_store.h
@@ -9,9 +9,11 @@
#include "base/containers/hash_tables.h"
#include "base/memory/weak_ptr.h"
+#include "base/observer_list.h"
#include "components/dom_distiller/core/article_entry.h"
#include "components/dom_distiller/core/dom_distiller_database.h"
#include "components/dom_distiller/core/dom_distiller_model.h"
+#include "components/dom_distiller/core/dom_distiller_observer.h"
#include "sync/api/sync_change.h"
#include "sync/api/sync_data.h"
#include "sync/api/sync_error.h"
@@ -47,8 +49,9 @@ class DomDistillerStoreInterface {
// Gets a copy of all the current entries.
virtual std::vector<ArticleEntry> GetEntries() const = 0;
- // TODO(cjhopman): This should have a way to observe changes to the underlying
- // model.
+ virtual void AddObserver(DomDistillerObserver* observer) = 0;
+
+ virtual void RemoveObserver(DomDistillerObserver* observer) = 0;
};
// Implements syncing/storing of DomDistiller entries. This keeps three
@@ -91,6 +94,8 @@ class DomDistillerStore : public syncer::SyncableService,
ArticleEntry* entry) OVERRIDE;
virtual bool GetEntryByUrl(const GURL& url, ArticleEntry* entry) OVERRIDE;
virtual std::vector<ArticleEntry> GetEntries() const OVERRIDE;
+ virtual void AddObserver(DomDistillerObserver* observer) OVERRIDE;
+ virtual void RemoveObserver(DomDistillerObserver* observer) OVERRIDE;
// syncer::SyncableService implementation.
virtual syncer::SyncMergeResult MergeDataAndStartSyncing(
@@ -131,10 +136,13 @@ class DomDistillerStore : public syncer::SyncableService,
syncer::SyncChangeList* changes_applied,
syncer::SyncChangeList* changes_missing);
+ void NotifyObservers(const syncer::SyncChangeList& changes);
+
scoped_ptr<syncer::SyncChangeProcessor> sync_processor_;
scoped_ptr<syncer::SyncErrorFactory> error_factory_;
scoped_ptr<DomDistillerDatabaseInterface> database_;
bool database_loaded_;
+ ObserverList<DomDistillerObserver> observers_;
DomDistillerModel model_;
diff --git a/components/dom_distiller/core/dom_distiller_store_unittest.cc b/components/dom_distiller/core/dom_distiller_store_unittest.cc
index b1da8a0..09ea61b 100644
--- a/components/dom_distiller/core/dom_distiller_store_unittest.cc
+++ b/components/dom_distiller/core/dom_distiller_store_unittest.cc
@@ -192,6 +192,35 @@ ArticleEntry GetSampleEntry(int id) {
return entries[id % 9];
}
+class FakeDistillerObserver : public DomDistillerObserver {
+ public:
+ MOCK_METHOD1(ArticleEntriesUpdated, void(const std::vector<ArticleUpdate>&));
+ virtual ~FakeDistillerObserver() {}
+};
+
+MATCHER_P(AreUpdatesEqual, expected_updates, "") {
+ if (arg.size() != expected_updates.size())
+ return false;
+ std::vector<DomDistillerObserver::ArticleUpdate>::const_iterator expected,
+ actual;
+ for (expected = expected_updates.begin(), actual = arg.begin();
+ expected != expected_updates.end();
+ ++expected, ++actual) {
+ if (expected->entry_id != actual->entry_id) {
+ *result_listener << " Mismatched entry id. Expected: "
+ << expected->entry_id << " actual: " << actual->entry_id;
+ return false;
+ }
+ if (expected->update_type != actual->update_type) {
+ *result_listener << " Mismatched update. Expected: "
+ << expected->update_type
+ << " actual: " << actual->update_type;
+ return false;
+ }
+ }
+ return true;
+}
+
} // namespace
class DomDistillerStoreTest : public testing::Test {
@@ -488,4 +517,64 @@ TEST_F(DomDistillerStoreTest, TestSyncMergeWithSecondDomDistillerStore) {
EXPECT_TRUE(AreEntriesEqual(other_store->GetEntries(), expected_model));
}
+TEST_F(DomDistillerStoreTest, TestObserver) {
+ CreateStore();
+ FakeDistillerObserver observer;
+ store_->AddObserver(&observer);
+ fake_db_->InitCallback(true);
+ fake_db_->LoadCallback(true);
+ std::vector<DomDistillerObserver::ArticleUpdate> expected_updates;
+ DomDistillerObserver::ArticleUpdate update;
+ update.entry_id = GetSampleEntry(0).entry_id();
+ update.update_type = DomDistillerObserver::ArticleUpdate::ADD;
+ expected_updates.push_back(update);
+ EXPECT_CALL(observer,
+ ArticleEntriesUpdated(AreUpdatesEqual(expected_updates)));
+ store_->AddEntry(GetSampleEntry(0));
+
+ expected_updates.clear();
+ update.entry_id = GetSampleEntry(1).entry_id();
+ update.update_type = DomDistillerObserver::ArticleUpdate::ADD;
+ expected_updates.push_back(update);
+ EXPECT_CALL(observer,
+ ArticleEntriesUpdated(AreUpdatesEqual(expected_updates)));
+ store_->AddEntry(GetSampleEntry(1));
+
+ expected_updates.clear();
+ update.entry_id = GetSampleEntry(0).entry_id();
+ update.update_type = DomDistillerObserver::ArticleUpdate::REMOVE;
+ expected_updates.clear();
+ expected_updates.push_back(update);
+ EXPECT_CALL(observer,
+ ArticleEntriesUpdated(AreUpdatesEqual(expected_updates)));
+ store_->RemoveEntry(GetSampleEntry(0));
+
+ // Add entry_id = 3 and update entry_id = 1.
+ expected_updates.clear();
+ SyncDataList change_data;
+ change_data.push_back(CreateSyncData(GetSampleEntry(3)));
+ ArticleEntry updated_entry(GetSampleEntry(1));
+ updated_entry.set_title("changed_title");
+ change_data.push_back(CreateSyncData(updated_entry));
+ update.entry_id = GetSampleEntry(3).entry_id();
+ update.update_type = DomDistillerObserver::ArticleUpdate::ADD;
+ expected_updates.push_back(update);
+ update.entry_id = GetSampleEntry(1).entry_id();
+ update.update_type = DomDistillerObserver::ArticleUpdate::UPDATE;
+ expected_updates.push_back(update);
+
+ EXPECT_CALL(observer,
+ ArticleEntriesUpdated(AreUpdatesEqual(expected_updates)));
+
+ FakeSyncErrorFactory* fake_error_factory = new FakeSyncErrorFactory();
+ EntryMap fake_model;
+ FakeSyncChangeProcessor* fake_sync_change_processor =
+ new FakeSyncChangeProcessor(&fake_model);
+ store_->MergeDataAndStartSyncing(
+ kDomDistillerModelType,
+ change_data,
+ make_scoped_ptr<SyncChangeProcessor>(fake_sync_change_processor),
+ make_scoped_ptr<SyncErrorFactory>(fake_error_factory));
+}
+
} // namespace dom_distiller