1 // Copyright 2013 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.
5 #include "components/dom_distiller/core/dom_distiller_store.h"
8 #include "base/logging.h"
9 #include "components/dom_distiller/core/article_entry.h"
10 #include "sync/api/sync_change.h"
11 #include "sync/protocol/article_specifics.pb.h"
12 #include "sync/protocol/sync.pb.h"
14 using sync_pb::ArticleSpecifics;
15 using sync_pb::EntitySpecifics;
16 using syncer::ModelType;
17 using syncer::SyncChange;
18 using syncer::SyncChangeList;
19 using syncer::SyncData;
20 using syncer::SyncDataList;
21 using syncer::SyncError;
22 using syncer::SyncMergeResult;
24 namespace dom_distiller {
26 DomDistillerStore::DomDistillerStore(
27 scoped_ptr<DomDistillerDatabaseInterface> database,
28 const base::FilePath& database_dir)
29 : database_(database.Pass()),
30 database_loaded_(false),
31 weak_ptr_factory_(this) {
32 database_->Init(database_dir,
33 base::Bind(&DomDistillerStore::OnDatabaseInit,
34 weak_ptr_factory_.GetWeakPtr()));
37 DomDistillerStore::DomDistillerStore(
38 scoped_ptr<DomDistillerDatabaseInterface> database,
39 const std::vector<ArticleEntry>& initial_data,
40 const base::FilePath& database_dir)
41 : database_(database.Pass()),
42 database_loaded_(false),
44 weak_ptr_factory_(this) {
45 database_->Init(database_dir,
46 base::Bind(&DomDistillerStore::OnDatabaseInit,
47 weak_ptr_factory_.GetWeakPtr()));
50 DomDistillerStore::~DomDistillerStore() {}
52 // DomDistillerStoreInterface implementation.
53 syncer::SyncableService* DomDistillerStore::GetSyncableService() {
57 bool DomDistillerStore::GetEntryById(const std::string& entry_id,
58 ArticleEntry* entry) {
59 return model_.GetEntryById(entry_id, entry);
62 bool DomDistillerStore::GetEntryByUrl(const GURL& url,
63 ArticleEntry* entry) {
64 return model_.GetEntryByUrl(url, entry);
68 bool DomDistillerStore::AddEntry(const ArticleEntry& entry) {
69 if (!database_loaded_) {
73 if (model_.GetEntryById(entry.entry_id(), NULL)) {
77 SyncChangeList changes_to_apply;
78 changes_to_apply.push_back(
79 SyncChange(FROM_HERE, SyncChange::ACTION_ADD, CreateLocalData(entry)));
81 SyncChangeList changes_applied;
82 SyncChangeList changes_missing;
84 if (!ApplyChangesToModel(
85 changes_to_apply, &changes_applied, &changes_missing)) {
89 DCHECK_EQ(size_t(0), changes_missing.size());
90 DCHECK_EQ(size_t(1), changes_applied.size());
92 ApplyChangesToSync(FROM_HERE, changes_applied);
93 ApplyChangesToDatabase(changes_applied);
98 std::vector<ArticleEntry> DomDistillerStore::GetEntries() const {
99 return model_.GetEntries();
102 // syncer::SyncableService implementation.
103 SyncMergeResult DomDistillerStore::MergeDataAndStartSyncing(
105 const SyncDataList& initial_sync_data,
106 scoped_ptr<syncer::SyncChangeProcessor> sync_processor,
107 scoped_ptr<syncer::SyncErrorFactory> error_handler) {
108 DCHECK_EQ(syncer::ARTICLES, type);
109 DCHECK(!sync_processor_);
110 DCHECK(!error_factory_);
111 sync_processor_.reset(sync_processor.release());
112 error_factory_.reset(error_handler.release());
114 SyncChangeList database_changes;
115 SyncChangeList sync_changes;
116 SyncMergeResult result =
117 MergeDataWithModel(initial_sync_data, &database_changes, &sync_changes);
118 ApplyChangesToDatabase(database_changes);
119 ApplyChangesToSync(FROM_HERE, sync_changes);
124 void DomDistillerStore::StopSyncing(ModelType type) {
125 sync_processor_.reset();
126 error_factory_.reset();
129 SyncDataList DomDistillerStore::GetAllSyncData(ModelType type) const {
130 return model_.GetAllSyncData();
133 SyncError DomDistillerStore::ProcessSyncChanges(
134 const tracked_objects::Location& from_here,
135 const SyncChangeList& change_list) {
136 DCHECK(database_loaded_);
137 SyncChangeList database_changes;
138 SyncChangeList sync_changes;
139 if (!ApplyChangesToModel(change_list, &database_changes, &sync_changes)) {
140 return SyncError(FROM_HERE,
141 SyncError::DATATYPE_ERROR,
142 "Applying changes to the DOM distiller model failed",
145 ApplyChangesToDatabase(database_changes);
146 DCHECK_EQ(size_t(0), sync_changes.size());
150 bool DomDistillerStore::ApplyChangesToModel(
151 const SyncChangeList& changes,
152 SyncChangeList* changes_applied,
153 SyncChangeList* changes_missing) {
154 DomDistillerModel::ChangeResult change_result =
155 model_.ApplyChangesToModel(changes, changes_applied, changes_missing);
156 if (change_result == DomDistillerModel::SUCCESS) {
160 LOG(WARNING) << "Applying changes to DOM distiller model failed with error "
164 database_loaded_ = false;
165 StopSyncing(syncer::ARTICLES);
169 void DomDistillerStore::OnDatabaseInit(bool success) {
171 LOG(INFO) << "DOM Distiller database init failed.";
175 database_->LoadEntries(base::Bind(&DomDistillerStore::OnDatabaseLoad,
176 weak_ptr_factory_.GetWeakPtr()));
179 void DomDistillerStore::OnDatabaseLoad(bool success,
180 scoped_ptr<EntryVector> entries) {
182 LOG(INFO) << "DOM Distiller database load failed.";
186 database_loaded_ = true;
189 for (EntryVector::iterator it = entries->begin(); it != entries->end();
191 data.push_back(CreateLocalData(*it));
193 SyncChangeList changes_applied;
194 SyncChangeList database_changes_needed;
195 MergeDataWithModel(data, &changes_applied, &database_changes_needed);
196 ApplyChangesToDatabase(database_changes_needed);
199 void DomDistillerStore::OnDatabaseSave(bool success) {
201 LOG(INFO) << "DOM Distiller database save failed."
202 << " Disabling modifications and sync.";
204 database_loaded_ = false;
205 StopSyncing(syncer::ARTICLES);
209 bool DomDistillerStore::ApplyChangesToSync(
210 const tracked_objects::Location& from_here,
211 const SyncChangeList& change_list) {
212 if (!sync_processor_) {
215 if (change_list.empty()) {
219 SyncError error = sync_processor_->ProcessSyncChanges(from_here, change_list);
221 StopSyncing(syncer::ARTICLES);
227 bool DomDistillerStore::ApplyChangesToDatabase(
228 const SyncChangeList& change_list) {
229 if (!database_loaded_) {
232 if (change_list.empty()) {
235 scoped_ptr<EntryVector> entries_to_save(new EntryVector());
237 for (SyncChangeList::const_iterator it = change_list.begin();
238 it != change_list.end();
240 entries_to_save->push_back(GetEntryFromChange(*it));
242 database_->SaveEntries(entries_to_save.Pass(),
243 base::Bind(&DomDistillerStore::OnDatabaseSave,
244 weak_ptr_factory_.GetWeakPtr()));
248 SyncMergeResult DomDistillerStore::MergeDataWithModel(
249 const SyncDataList& data,
250 SyncChangeList* changes_applied,
251 SyncChangeList* changes_missing) {
252 DCHECK(changes_applied);
253 DCHECK(changes_missing);
255 SyncMergeResult result(syncer::ARTICLES);
256 result.set_num_items_before_association(model_.GetNumEntries());
258 SyncChangeList changes_to_apply;
259 model_.CalculateChangesForMerge(data, &changes_to_apply, changes_missing);
261 if (!ApplyChangesToModel(
262 changes_to_apply, changes_applied, changes_missing)) {
263 error = SyncError(FROM_HERE,
264 SyncError::DATATYPE_ERROR,
265 "Applying changes to the DOM distiller model failed",
270 int num_modified = 0;
271 for (SyncChangeList::const_iterator it = changes_applied->begin();
272 it != changes_applied->end();
274 DCHECK(it->IsValid());
275 switch (it->change_type()) {
276 case SyncChange::ACTION_ADD:
279 case SyncChange::ACTION_UPDATE:
286 result.set_num_items_added(num_added);
287 result.set_num_items_modified(num_modified);
288 result.set_num_items_deleted(0);
290 result.set_pre_association_version(0);
291 result.set_num_items_after_association(model_.GetNumEntries());
292 result.set_error(error);
297 } // namespace dom_distiller