Make sure webrtc::VideoSource is released when WebRtcVideoTrackAdapter is destroyed.
[chromium-blink-merge.git] / components / dom_distiller / core / dom_distiller_store.cc
blobb8d7fbbe6347b5ff509db582201e98b9ca5bb6fe
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"
7 #include "base/bind.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),
43 model_(initial_data),
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() {
54 return this;
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_) {
70 return false;
73 if (model_.GetEntryById(entry.entry_id(), NULL)) {
74 DVLOG(1) << "Already have entry with id " << entry.entry_id() << ".";
75 return false;
78 SyncChangeList changes_to_apply;
79 changes_to_apply.push_back(
80 SyncChange(FROM_HERE, SyncChange::ACTION_ADD, CreateLocalData(entry)));
82 SyncChangeList changes_applied;
83 SyncChangeList changes_missing;
85 ApplyChangesToModel(changes_to_apply, &changes_applied, &changes_missing);
87 DCHECK_EQ(size_t(0), changes_missing.size());
88 DCHECK_EQ(size_t(1), changes_applied.size());
90 ApplyChangesToSync(FROM_HERE, changes_applied);
91 ApplyChangesToDatabase(changes_applied);
93 return true;
96 bool DomDistillerStore::UpdateEntry(const ArticleEntry& entry) {
97 if (!database_loaded_) {
98 return false;
101 if (!model_.GetEntryById(entry.entry_id(), NULL)) {
102 DVLOG(1) << "No entry with id " << entry.entry_id() << " found.";
103 return false;
106 SyncChangeList changes_to_apply;
107 changes_to_apply.push_back(
108 SyncChange(FROM_HERE, SyncChange::ACTION_UPDATE, CreateLocalData(entry)));
110 SyncChangeList changes_applied;
111 SyncChangeList changes_missing;
113 ApplyChangesToModel(changes_to_apply, &changes_applied, &changes_missing);
115 if (changes_applied.size() != 1) {
116 DVLOG(1) << "Failed to update entry with id " << entry.entry_id() << ".";
117 return false;
120 ApplyChangesToSync(FROM_HERE, changes_applied);
121 ApplyChangesToDatabase(changes_applied);
123 return true;
126 bool DomDistillerStore::RemoveEntry(const ArticleEntry& entry) {
127 if (!database_loaded_) {
128 return false;
131 if (!model_.GetEntryById(entry.entry_id(), NULL)) {
132 DVLOG(1) << "No entry with id " << entry.entry_id() << " found.";
133 return false;
136 SyncChangeList changes_to_apply;
137 changes_to_apply.push_back(
138 SyncChange(FROM_HERE, SyncChange::ACTION_DELETE, CreateLocalData(entry)));
140 SyncChangeList changes_applied;
141 SyncChangeList changes_missing;
143 ApplyChangesToModel(changes_to_apply, &changes_applied, &changes_missing);
145 DCHECK_EQ(size_t(0), changes_missing.size());
146 DCHECK_EQ(size_t(1), changes_applied.size());
148 ApplyChangesToSync(FROM_HERE, changes_applied);
149 ApplyChangesToDatabase(changes_applied);
151 return true;
154 void DomDistillerStore::AddObserver(DomDistillerObserver* observer) {
155 observers_.AddObserver(observer);
158 void DomDistillerStore::RemoveObserver(DomDistillerObserver* observer) {
159 observers_.RemoveObserver(observer);
162 std::vector<ArticleEntry> DomDistillerStore::GetEntries() const {
163 return model_.GetEntries();
166 // syncer::SyncableService implementation.
167 SyncMergeResult DomDistillerStore::MergeDataAndStartSyncing(
168 ModelType type,
169 const SyncDataList& initial_sync_data,
170 scoped_ptr<syncer::SyncChangeProcessor> sync_processor,
171 scoped_ptr<syncer::SyncErrorFactory> error_handler) {
172 DCHECK_EQ(syncer::ARTICLES, type);
173 DCHECK(!sync_processor_);
174 DCHECK(!error_factory_);
175 sync_processor_.reset(sync_processor.release());
176 error_factory_.reset(error_handler.release());
178 SyncChangeList database_changes;
179 SyncChangeList sync_changes;
180 SyncMergeResult result =
181 MergeDataWithModel(initial_sync_data, &database_changes, &sync_changes);
182 ApplyChangesToDatabase(database_changes);
183 ApplyChangesToSync(FROM_HERE, sync_changes);
185 return result;
188 void DomDistillerStore::StopSyncing(ModelType type) {
189 sync_processor_.reset();
190 error_factory_.reset();
193 SyncDataList DomDistillerStore::GetAllSyncData(ModelType type) const {
194 return model_.GetAllSyncData();
197 SyncError DomDistillerStore::ProcessSyncChanges(
198 const tracked_objects::Location& from_here,
199 const SyncChangeList& change_list) {
200 DCHECK(database_loaded_);
201 SyncChangeList database_changes;
202 SyncChangeList sync_changes;
203 ApplyChangesToModel(change_list, &database_changes, &sync_changes);
204 ApplyChangesToDatabase(database_changes);
205 DCHECK_EQ(size_t(0), sync_changes.size());
206 return SyncError();
209 void DomDistillerStore::NotifyObservers(const syncer::SyncChangeList& changes) {
210 if (observers_.might_have_observers() && changes.size() > 0) {
211 std::vector<DomDistillerObserver::ArticleUpdate> article_changes;
212 for (SyncChangeList::const_iterator it = changes.begin();
213 it != changes.end();
214 ++it) {
215 DomDistillerObserver::ArticleUpdate article_update;
216 switch (it->change_type()) {
217 case SyncChange::ACTION_ADD:
218 article_update.update_type = DomDistillerObserver::ArticleUpdate::ADD;
219 break;
220 case SyncChange::ACTION_UPDATE:
221 article_update.update_type =
222 DomDistillerObserver::ArticleUpdate::UPDATE;
223 break;
224 case SyncChange::ACTION_DELETE:
225 article_update.update_type =
226 DomDistillerObserver::ArticleUpdate::REMOVE;
227 break;
228 case SyncChange::ACTION_INVALID:
229 NOTREACHED();
230 break;
232 const ArticleEntry& entry = GetEntryFromChange(*it);
233 article_update.entry_id = entry.entry_id();
234 article_changes.push_back(article_update);
236 FOR_EACH_OBSERVER(DomDistillerObserver,
237 observers_,
238 ArticleEntriesUpdated(article_changes));
242 void DomDistillerStore::ApplyChangesToModel(
243 const SyncChangeList& changes,
244 SyncChangeList* changes_applied,
245 SyncChangeList* changes_missing) {
246 model_.ApplyChangesToModel(changes, changes_applied, changes_missing);
247 NotifyObservers(*changes_applied);
250 void DomDistillerStore::OnDatabaseInit(bool success) {
251 if (!success) {
252 DVLOG(1) << "DOM Distiller database init failed.";
253 database_.reset();
254 return;
256 database_->LoadEntries(base::Bind(&DomDistillerStore::OnDatabaseLoad,
257 weak_ptr_factory_.GetWeakPtr()));
260 void DomDistillerStore::OnDatabaseLoad(bool success,
261 scoped_ptr<EntryVector> entries) {
262 if (!success) {
263 DVLOG(1) << "DOM Distiller database load failed.";
264 database_.reset();
265 return;
267 database_loaded_ = true;
269 SyncDataList data;
270 for (EntryVector::iterator it = entries->begin(); it != entries->end();
271 ++it) {
272 data.push_back(CreateLocalData(*it));
274 SyncChangeList changes_applied;
275 SyncChangeList database_changes_needed;
276 MergeDataWithModel(data, &changes_applied, &database_changes_needed);
277 ApplyChangesToDatabase(database_changes_needed);
280 void DomDistillerStore::OnDatabaseSave(bool success) {
281 if (!success) {
282 DVLOG(1) << "DOM Distiller database save failed."
283 << " Disabling modifications and sync.";
284 database_.reset();
285 database_loaded_ = false;
286 StopSyncing(syncer::ARTICLES);
290 bool DomDistillerStore::ApplyChangesToSync(
291 const tracked_objects::Location& from_here,
292 const SyncChangeList& change_list) {
293 if (!sync_processor_) {
294 return false;
296 if (change_list.empty()) {
297 return true;
300 SyncError error = sync_processor_->ProcessSyncChanges(from_here, change_list);
301 if (error.IsSet()) {
302 StopSyncing(syncer::ARTICLES);
303 return false;
305 return true;
308 bool DomDistillerStore::ApplyChangesToDatabase(
309 const SyncChangeList& change_list) {
310 if (!database_loaded_) {
311 return false;
313 if (change_list.empty()) {
314 return true;
316 scoped_ptr<EntryVector> entries_to_save(new EntryVector());
317 scoped_ptr<EntryVector> entries_to_remove(new EntryVector());
319 for (SyncChangeList::const_iterator it = change_list.begin();
320 it != change_list.end();
321 ++it) {
322 if (it->change_type() == SyncChange::ACTION_DELETE)
323 entries_to_remove->push_back(GetEntryFromChange(*it));
324 else
325 entries_to_save->push_back(GetEntryFromChange(*it));
327 database_->UpdateEntries(entries_to_save.Pass(),
328 entries_to_remove.Pass(),
329 base::Bind(&DomDistillerStore::OnDatabaseSave,
330 weak_ptr_factory_.GetWeakPtr()));
331 return true;
334 SyncMergeResult DomDistillerStore::MergeDataWithModel(
335 const SyncDataList& data,
336 SyncChangeList* changes_applied,
337 SyncChangeList* changes_missing) {
338 DCHECK(changes_applied);
339 DCHECK(changes_missing);
341 SyncMergeResult result(syncer::ARTICLES);
342 result.set_num_items_before_association(model_.GetNumEntries());
344 SyncChangeList changes_to_apply;
345 model_.CalculateChangesForMerge(data, &changes_to_apply, changes_missing);
346 SyncError error;
347 ApplyChangesToModel(changes_to_apply, changes_applied, changes_missing);
349 int num_added = 0;
350 int num_modified = 0;
351 for (SyncChangeList::const_iterator it = changes_applied->begin();
352 it != changes_applied->end();
353 ++it) {
354 DCHECK(it->IsValid());
355 switch (it->change_type()) {
356 case SyncChange::ACTION_ADD:
357 num_added++;
358 break;
359 case SyncChange::ACTION_UPDATE:
360 num_modified++;
361 break;
362 default:
363 NOTREACHED();
366 result.set_num_items_added(num_added);
367 result.set_num_items_modified(num_modified);
368 result.set_num_items_deleted(0);
370 result.set_pre_association_version(0);
371 result.set_num_items_after_association(model_.GetNumEntries());
372 result.set_error(error);
374 return result;
377 } // namespace dom_distiller