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. 4 5 #include "components/dom_distiller/core/dom_distiller_model.h" 6 7 #include <utility> 8 9 using syncer::SyncChange; 10 using syncer::SyncChangeList; 11 using syncer::SyncData; 12 using syncer::SyncDataList; 13 14 namespace dom_distiller { 15 16 DomDistillerModel::DomDistillerModel() 17 : next_key_(1) {} 18 19 DomDistillerModel::DomDistillerModel( 20 const std::vector<ArticleEntry>& initial_data) 21 : next_key_(1) { 22 for (size_t i = 0; i < initial_data.size(); ++i) { 23 AddEntry(initial_data[i]); 24 } 25 } 26 27 DomDistillerModel::~DomDistillerModel() {} 28 29 bool DomDistillerModel::GetEntryById(const std::string& entry_id, 30 ArticleEntry* entry) const { 31 KeyType key = 0; 32 if (!GetKeyById(entry_id, &key)) { 33 return false; 34 } 35 GetEntryByKey(key, entry); 36 return true; 37 } 38 39 bool DomDistillerModel::GetEntryByUrl(const GURL& url, 40 ArticleEntry* entry) const { 41 KeyType key = 0; 42 if (!GetKeyByUrl(url, &key)) { 43 return false; 44 } 45 GetEntryByKey(key, entry); 46 return true; 47 } 48 49 bool DomDistillerModel::GetKeyById(const std::string& entry_id, 50 KeyType* key) const { 51 StringToKeyMap::const_iterator it = entry_id_to_key_map_.find(entry_id); 52 if (it == entry_id_to_key_map_.end()) { 53 return false; 54 } 55 if (key != NULL) { 56 *key = it->second; 57 } 58 return true; 59 } 60 61 bool DomDistillerModel::GetKeyByUrl(const GURL& url, KeyType* key) const { 62 StringToKeyMap::const_iterator it = url_to_key_map_.find(url.spec()); 63 if (it == url_to_key_map_.end()) { 64 return false; 65 } 66 if (key != NULL) { 67 *key = it->second; 68 } 69 return true; 70 } 71 72 void DomDistillerModel::GetEntryByKey(KeyType key, ArticleEntry* entry) const { 73 if (entry != NULL) { 74 EntryMap::const_iterator it = entries_.find(key); 75 DCHECK(it != entries_.end()); 76 *entry = it->second; 77 } 78 } 79 80 size_t DomDistillerModel::GetNumEntries() const { 81 return entries_.size(); 82 } 83 84 std::vector<ArticleEntry> DomDistillerModel::GetEntries() const { 85 std::vector<ArticleEntry> entries_list; 86 for (EntryMap::const_iterator it = entries_.begin(); it != entries_.end(); 87 ++it) { 88 entries_list.push_back(it->second); 89 } 90 return entries_list; 91 } 92 93 SyncDataList DomDistillerModel::GetAllSyncData() const { 94 SyncDataList data; 95 for (EntryMap::const_iterator it = entries_.begin(); it != entries_.end(); 96 ++it) { 97 data.push_back(CreateLocalData(it->second)); 98 } 99 return data; 100 } 101 102 void DomDistillerModel::CalculateChangesForMerge( 103 const SyncDataList& data, 104 SyncChangeList* changes_to_apply, 105 SyncChangeList* changes_missing) { 106 typedef base::hash_set<std::string> StringSet; 107 StringSet entries_to_change; 108 for (SyncDataList::const_iterator it = data.begin(); it != data.end(); ++it) { 109 std::string entry_id = GetEntryIdFromSyncData(*it); 110 std::pair<StringSet::iterator, bool> insert_result = 111 entries_to_change.insert(entry_id); 112 113 DCHECK(insert_result.second); 114 115 SyncChange::SyncChangeType change_type = SyncChange::ACTION_ADD; 116 if (GetEntryById(entry_id, NULL)) { 117 change_type = SyncChange::ACTION_UPDATE; 118 } 119 changes_to_apply->push_back(SyncChange(FROM_HERE, change_type, *it)); 120 } 121 122 for (EntryMap::const_iterator it = entries_.begin(); it != entries_.end(); 123 ++it) { 124 if (entries_to_change.find(it->second.entry_id()) == 125 entries_to_change.end()) { 126 changes_missing->push_back(SyncChange( 127 FROM_HERE, SyncChange::ACTION_ADD, CreateLocalData(it->second))); 128 } 129 } 130 } 131 132 void DomDistillerModel::ApplyChangesToModel( 133 const SyncChangeList& changes, 134 SyncChangeList* changes_applied, 135 SyncChangeList* changes_missing) { 136 DCHECK(changes_applied); 137 DCHECK(changes_missing); 138 139 for (SyncChangeList::const_iterator it = changes.begin(); it != changes.end(); 140 ++it) { 141 ApplyChangeToModel(*it, changes_applied, changes_missing); 142 } 143 } 144 145 void DomDistillerModel::AddEntry(const ArticleEntry& entry) { 146 const std::string& entry_id = entry.entry_id(); 147 KeyType key = next_key_++; 148 DCHECK(!GetKeyById(entry_id, NULL)); 149 entries_.insert(std::make_pair(key, entry)); 150 entry_id_to_key_map_.insert(std::make_pair(entry_id, key)); 151 for (int i = 0; i < entry.pages_size(); ++i) { 152 url_to_key_map_.insert(std::make_pair(entry.pages(i).url(), key)); 153 } 154 } 155 156 void DomDistillerModel::RemoveEntry(const ArticleEntry& entry) { 157 const std::string& entry_id = entry.entry_id(); 158 KeyType key = 0; 159 bool success = GetKeyById(entry_id, &key); 160 DCHECK(success); 161 162 entries_.erase(key); 163 entry_id_to_key_map_.erase(entry_id); 164 for (int i = 0; i < entry.pages_size(); ++i) { 165 url_to_key_map_.erase(entry.pages(i).url()); 166 } 167 } 168 169 void DomDistillerModel::ApplyChangeToModel( 170 const SyncChange& change, 171 SyncChangeList* changes_applied, 172 SyncChangeList* changes_missing) { 173 DCHECK(change.IsValid()); 174 DCHECK(changes_applied); 175 DCHECK(changes_missing); 176 177 const std::string& entry_id = GetEntryIdFromSyncData(change.sync_data()); 178 179 if (change.change_type() == SyncChange::ACTION_DELETE) { 180 ArticleEntry current_entry; 181 if (GetEntryById(entry_id, ¤t_entry)) { 182 RemoveEntry(current_entry); 183 changes_applied->push_back(SyncChange( 184 change.location(), SyncChange::ACTION_DELETE, change.sync_data())); 185 } 186 // If we couldn't find in sync db, we were deleting anyway so swallow the 187 // error. 188 return; 189 } 190 191 ArticleEntry entry = GetEntryFromChange(change); 192 ArticleEntry current_entry; 193 if (!GetEntryById(entry_id, ¤t_entry)) { 194 AddEntry(entry); 195 changes_applied->push_back(SyncChange( 196 change.location(), SyncChange::ACTION_ADD, change.sync_data())); 197 } else { 198 if (!AreEntriesEqual(current_entry, entry)) { 199 // Currently, conflicts are simply resolved by accepting the last one to 200 // arrive. 201 RemoveEntry(current_entry); 202 AddEntry(entry); 203 changes_applied->push_back(SyncChange( 204 change.location(), SyncChange::ACTION_UPDATE, change.sync_data())); 205 } 206 } 207 } 208 209 } // namespace dom_distiller 210