1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved. 2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be 3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file. 4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sync/glue/typed_url_change_processor.h" 6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/string_util.h" 83345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/utf_string_conversions.h" 9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/history/history_backend.h" 10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/history/history_notifications.h" 1121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/profiles/profile.h" 12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sync/glue/typed_url_model_associator.h" 13c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sync/profile_sync_service.h" 14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sync/protocol/typed_url_specifics.pb.h" 15ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/common/notification_service.h" 16ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/common/notification_type.h" 17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 18c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace browser_sync { 19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 20c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTypedUrlChangeProcessor::TypedUrlChangeProcessor( 21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TypedUrlModelAssociator* model_associator, 22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch history::HistoryBackend* history_backend, 23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch UnrecoverableErrorHandler* error_handler) 24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch : ChangeProcessor(error_handler), 25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch model_associator_(model_associator), 26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch history_backend_(history_backend), 27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch observing_(false), 28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch expected_loop_(MessageLoop::current()) { 29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(model_associator); 30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(history_backend); 31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(error_handler); 32731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI)); 33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // When running in unit tests, there is already a NotificationService object. 34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Since only one can exist at a time per thread, check first. 35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!NotificationService::current()) 36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch notification_service_.reset(new NotificationService); 37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch StartObserving(); 38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 40c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTypedUrlChangeProcessor::~TypedUrlChangeProcessor() { 41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(expected_loop_ == MessageLoop::current()); 42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TypedUrlChangeProcessor::Observe(NotificationType type, 45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const NotificationSource& source, 46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const NotificationDetails& details) { 47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(expected_loop_ == MessageLoop::current()); 48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!observing_) 49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 51731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick VLOG(1) << "Observed typed_url change."; 52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(running()); 53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(NotificationType::HISTORY_TYPED_URLS_MODIFIED == type || 54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NotificationType::HISTORY_URLS_DELETED == type || 55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NotificationType::HISTORY_URL_VISITED == type); 56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (type == NotificationType::HISTORY_TYPED_URLS_MODIFIED) { 57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch HandleURLsModified(Details<history::URLsModifiedDetails>(details).ptr()); 58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else if (type == NotificationType::HISTORY_URLS_DELETED) { 59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch HandleURLsDeleted(Details<history::URLsDeletedDetails>(details).ptr()); 60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else if (type == NotificationType::HISTORY_URL_VISITED) { 61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch HandleURLsVisited(Details<history::URLVisitedDetails>(details).ptr()); 62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TypedUrlChangeProcessor::HandleURLsModified( 66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch history::URLsModifiedDetails* details) { 67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Get all the visits. 68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::map<history::URLID, history::VisitVector> visit_vectors; 69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (std::vector<history::URLRow>::iterator url = 70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch details->changed_urls.begin(); url != details->changed_urls.end(); 71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ++url) { 72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!history_backend_->GetVisitsForURL(url->id(), 73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch &(visit_vectors[url->id()]))) { 74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch error_handler()->OnUnrecoverableError(FROM_HERE, 75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "Could not get the url's visits."); 76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(!visit_vectors[url->id()].empty()); 79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch sync_api::WriteTransaction trans(share_handle()); 82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch sync_api::ReadNode typed_url_root(&trans); 84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!typed_url_root.InitByTagLookup(kTypedUrlTag)) { 85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch error_handler()->OnUnrecoverableError(FROM_HERE, 86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "Server did not create the top-level typed_url node. We " 87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "might be running against an out-of-date server."); 88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (std::vector<history::URLRow>::iterator url = 92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch details->changed_urls.begin(); url != details->changed_urls.end(); 93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ++url) { 94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::string tag = url->url().spec(); 95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch history::VisitVector& visits = visit_vectors[url->id()]; 97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(!visits.empty()); 99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(static_cast<size_t>(url->visit_count()) == visits.size()); 101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (static_cast<size_t>(url->visit_count()) != visits.size()) { 102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch error_handler()->OnUnrecoverableError(FROM_HERE, 103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "Visit count does not match."); 104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch sync_api::WriteNode update_node(&trans); 108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (update_node.InitByClientTagLookup(syncable::TYPED_URLS, tag)) { 109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch model_associator_->WriteToSyncNode(*url, visits, &update_node); 110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch sync_api::WriteNode create_node(&trans); 112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!create_node.InitUniqueByCreation(syncable::TYPED_URLS, 113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch typed_url_root, tag)) { 114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch error_handler()->OnUnrecoverableError(FROM_HERE, 115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "Failed to create typed_url sync node."); 116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch create_node.SetTitle(UTF8ToWide(tag)); 120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch model_associator_->WriteToSyncNode(*url, visits, &create_node); 121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch model_associator_->Associate(&tag, create_node.GetId()); 123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TypedUrlChangeProcessor::HandleURLsDeleted( 128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch history::URLsDeletedDetails* details) { 129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch sync_api::WriteTransaction trans(share_handle()); 130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (details->all_history) { 132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!model_associator_->DeleteAllNodes(&trans)) { 133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch error_handler()->OnUnrecoverableError(FROM_HERE, std::string()); 134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (std::set<GURL>::iterator url = details->urls.begin(); 138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch url != details->urls.end(); ++url) { 139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch sync_api::WriteNode sync_node(&trans); 140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int64 sync_id = 141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch model_associator_->GetSyncIdFromChromeId(url->spec()); 142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (sync_api::kInvalidId != sync_id) { 143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!sync_node.InitByIdLookup(sync_id)) { 144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch error_handler()->OnUnrecoverableError(FROM_HERE, 145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "Typed url node lookup failed."); 146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch model_associator_->Disassociate(sync_node.GetId()); 149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch sync_node.Remove(); 150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TypedUrlChangeProcessor::HandleURLsVisited( 156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch history::URLVisitedDetails* details) { 157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!details->row.typed_count()) { 158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We only care about typed urls. 159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch history::VisitVector visits; 162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!history_backend_->GetVisitsForURL(details->row.id(), &visits) || 163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch visits.empty()) { 164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch error_handler()->OnUnrecoverableError(FROM_HERE, 165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "Could not get the url's visits."); 166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(static_cast<size_t>(details->row.visit_count()) == visits.size()); 170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch sync_api::WriteTransaction trans(share_handle()); 172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::string tag = details->row.url().spec(); 173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch sync_api::WriteNode update_node(&trans); 174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!update_node.InitByClientTagLookup(syncable::TYPED_URLS, tag)) { 175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If we don't know about it yet, it will be added later. 176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch sync_pb::TypedUrlSpecifics typed_url(update_node.GetTypedUrlSpecifics()); 179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch typed_url.add_visit(visits.back().visit_time.ToInternalValue()); 180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch update_node.SetTypedUrlSpecifics(typed_url); 181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TypedUrlChangeProcessor::ApplyChangesFromSyncModel( 184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const sync_api::BaseTransaction* trans, 185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const sync_api::SyncManager::ChangeRecord* changes, 186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int change_count) { 187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(expected_loop_ == MessageLoop::current()); 188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!running()) 189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch StopObserving(); 191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch sync_api::ReadNode typed_url_root(trans); 193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!typed_url_root.InitByTagLookup(kTypedUrlTag)) { 194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch error_handler()->OnUnrecoverableError(FROM_HERE, 195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "TypedUrl root node lookup failed."); 196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 197c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TypedUrlModelAssociator::TypedUrlTitleVector titles; 200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TypedUrlModelAssociator::TypedUrlVector new_urls; 201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TypedUrlModelAssociator::TypedUrlVisitVector new_visits; 202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch history::VisitVector deleted_visits; 203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TypedUrlModelAssociator::TypedUrlUpdateVector updated_urls; 204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (int i = 0; i < change_count; ++i) { 206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (sync_api::SyncManager::ChangeRecord::ACTION_DELETE == 207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch changes[i].action) { 208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(changes[i].specifics.HasExtension(sync_pb::typed_url)) << 209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "Typed URL delete change does not have necessary specifics."; 210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GURL url(changes[i].specifics.GetExtension(sync_pb::typed_url).url()); 211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch history_backend_->DeleteURL(url); 212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch continue; 213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 215c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch sync_api::ReadNode sync_node(trans); 216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!sync_node.InitByIdLookup(changes[i].id)) { 217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch error_handler()->OnUnrecoverableError(FROM_HERE, 218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "TypedUrl node lookup failed."); 219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Check that the changed node is a child of the typed_urls folder. 223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(typed_url_root.GetId() == sync_node.GetParentId()); 224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(syncable::TYPED_URLS == sync_node.GetModelType()); 225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const sync_pb::TypedUrlSpecifics& typed_url( 227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch sync_node.GetTypedUrlSpecifics()); 228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GURL url(typed_url.url()); 229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (sync_api::SyncManager::ChangeRecord::ACTION_ADD == changes[i].action) { 231c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(typed_url.visit_size()); 232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!typed_url.visit_size()) { 233c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch continue; 234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 235c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 236c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch history::URLRow new_url(url); 237c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch new_url.set_title(UTF8ToUTF16(typed_url.title())); 238c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // When we add a new url, the last visit is always added, thus we set 240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // the initial visit count to one. This value will be automatically 241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // incremented as visits are added. 242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch new_url.set_visit_count(1); 243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch new_url.set_typed_count(typed_url.typed_count()); 244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch new_url.set_hidden(typed_url.hidden()); 245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch new_url.set_last_visit(base::Time::FromInternalValue( 247c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch typed_url.visit(typed_url.visit_size() - 1))); 248c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 249c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch new_urls.push_back(new_url); 250c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 251c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // The latest visit gets added automatically, so skip it. 252c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::vector<base::Time> added_visits; 253c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (int c = 0; c < typed_url.visit_size() - 1; ++c) { 254c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(typed_url.visit(c) < typed_url.visit(c + 1)); 255c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch added_visits.push_back( 256c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch base::Time::FromInternalValue(typed_url.visit(c))); 257c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 258c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 259c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch new_visits.push_back( 260c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::pair<GURL, std::vector<base::Time> >(url, added_visits)); 261c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 262c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch history::URLRow old_url; 263c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!history_backend_->GetURL(url, &old_url)) { 264c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch error_handler()->OnUnrecoverableError(FROM_HERE, 265c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "TypedUrl db lookup failed."); 266c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 269c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch history::VisitVector visits; 270c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!history_backend_->GetVisitsForURL(old_url.id(), &visits)) { 271c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch error_handler()->OnUnrecoverableError(FROM_HERE, 272c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "Could not get the url's visits."); 273c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 274c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 275c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 276c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch history::URLRow new_url(url); 277c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch new_url.set_title(UTF8ToUTF16(typed_url.title())); 278c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch new_url.set_visit_count(old_url.visit_count()); 279c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch new_url.set_typed_count(typed_url.typed_count()); 280c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch new_url.set_last_visit(old_url.last_visit()); 281c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch new_url.set_hidden(typed_url.hidden()); 282c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 283c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch updated_urls.push_back( 284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::pair<history::URLID, history::URLRow>(old_url.id(), new_url)); 285c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 286c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (old_url.title().compare(new_url.title()) != 0) { 287c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch titles.push_back(std::pair<GURL, string16>(new_url.url(), 288c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch new_url.title())); 289c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 290c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::vector<base::Time> added_visits; 292c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch history::VisitVector removed_visits; 293c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TypedUrlModelAssociator::DiffVisits(visits, typed_url, 294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch &added_visits, &removed_visits); 295c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (added_visits.size()) { 296c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch new_visits.push_back( 297c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::pair<GURL, std::vector<base::Time> >(url, added_visits)); 298c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 299c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (removed_visits.size()) { 300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch deleted_visits.insert(deleted_visits.end(), removed_visits.begin(), 301c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch removed_visits.end()); 302c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 303c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 304c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 305c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!model_associator_->WriteToHistoryBackend(&titles, &new_urls, 306c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch &updated_urls, 307c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch &new_visits, &deleted_visits)) { 308c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch error_handler()->OnUnrecoverableError(FROM_HERE, 309c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "Could not write to the history backend."); 310c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 311c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 312c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 313c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch StartObserving(); 314c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 315c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 316c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TypedUrlChangeProcessor::StartImpl(Profile* profile) { 317c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(expected_loop_ == MessageLoop::current()); 318c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch observing_ = true; 319c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 320c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 321c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TypedUrlChangeProcessor::StopImpl() { 322731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 323c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch observing_ = false; 324c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 325c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 326c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 327c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TypedUrlChangeProcessor::StartObserving() { 328c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(expected_loop_ == MessageLoop::current()); 329c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch notification_registrar_.Add(this, 330c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NotificationType::HISTORY_TYPED_URLS_MODIFIED, 331c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NotificationService::AllSources()); 332c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch notification_registrar_.Add(this, NotificationType::HISTORY_URLS_DELETED, 333c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NotificationService::AllSources()); 334c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch notification_registrar_.Add(this, NotificationType::HISTORY_URL_VISITED, 335c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NotificationService::AllSources()); 336c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 337c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 338c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TypedUrlChangeProcessor::StopObserving() { 339c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(expected_loop_ == MessageLoop::current()); 340c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch notification_registrar_.Remove(this, 341c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NotificationType::HISTORY_TYPED_URLS_MODIFIED, 342c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NotificationService::AllSources()); 343c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch notification_registrar_.Remove(this, 344c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NotificationType::HISTORY_URLS_DELETED, 345c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NotificationService::AllSources()); 346c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch notification_registrar_.Remove(this, 347c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NotificationType::HISTORY_URL_VISITED, 348c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NotificationService::AllSources()); 349c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 350c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 351c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} // namespace browser_sync 352