1 // Copyright (c) 2012 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 "chrome/browser/history/in_memory_history_backend.h"
10 #include "base/command_line.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "base/time/time.h"
13 #include "chrome/browser/browser_process.h"
14 #include "chrome/browser/chrome_notification_types.h"
15 #include "chrome/browser/history/history_notifications.h"
16 #include "chrome/browser/history/history_service.h"
17 #include "chrome/browser/profiles/profile.h"
18 #include "components/history/core/browser/in_memory_database.h"
19 #include "components/history/core/browser/url_database.h"
20 #include "content/public/browser/notification_details.h"
21 #include "content/public/browser/notification_source.h"
25 InMemoryHistoryBackend::InMemoryHistoryBackend()
26 : profile_(nullptr), history_service_(nullptr) {
29 InMemoryHistoryBackend::~InMemoryHistoryBackend() {
31 history_service_->RemoveObserver(this);
34 bool InMemoryHistoryBackend::Init(const base::FilePath& history_filename) {
35 db_.reset(new InMemoryDatabase);
36 return db_->InitFromDisk(history_filename);
39 void InMemoryHistoryBackend::AttachToHistoryService(
41 HistoryService* history_service) {
47 DCHECK(history_service);
48 history_service_ = history_service;
49 history_service_->AddObserver(this);
53 // TODO(evanm): this is currently necessitated by generate_profile, which
54 // runs without a browser process. generate_profile should really create
55 // a browser process, at which point this check can then be nuked.
56 if (!g_browser_process)
59 // Register for the notifications we care about.
60 // We only want notifications for the associated profile.
61 content::Source<Profile> source(profile_);
62 registrar_.Add(this, chrome::NOTIFICATION_HISTORY_URLS_MODIFIED, source);
63 registrar_.Add(this, chrome::NOTIFICATION_HISTORY_URLS_DELETED, source);
65 this, chrome::NOTIFICATION_HISTORY_KEYWORD_SEARCH_TERM_UPDATED, source);
67 this, chrome::NOTIFICATION_HISTORY_KEYWORD_SEARCH_TERM_DELETED, source);
70 void InMemoryHistoryBackend::DeleteAllSearchTermsForKeyword(
71 KeywordID keyword_id) {
72 // For simplicity, this will not remove the corresponding URLRows, but
73 // this is okay, as the main database does not do so either.
74 db_->DeleteAllSearchTermsForKeyword(keyword_id);
77 void InMemoryHistoryBackend::OnURLVisited(HistoryService* history_service,
78 ui::PageTransition transition,
80 const RedirectList& redirects,
81 base::Time visit_time) {
82 OnURLVisitedOrModified(row);
85 void InMemoryHistoryBackend::Observe(
87 const content::NotificationSource& source,
88 const content::NotificationDetails& details) {
90 case chrome::NOTIFICATION_HISTORY_KEYWORD_SEARCH_TERM_UPDATED:
91 OnKeywordSearchTermUpdated(
92 *content::Details<KeywordSearchUpdatedDetails>(details).ptr());
94 case chrome::NOTIFICATION_HISTORY_KEYWORD_SEARCH_TERM_DELETED:
95 OnKeywordSearchTermDeleted(
96 *content::Details<KeywordSearchDeletedDetails>(details).ptr());
98 case chrome::NOTIFICATION_HISTORY_URLS_MODIFIED: {
99 const URLsModifiedDetails* modified_details =
100 content::Details<URLsModifiedDetails>(details).ptr();
101 URLRows::const_iterator it;
102 for (it = modified_details->changed_urls.begin();
103 it != modified_details->changed_urls.end(); ++it) {
104 OnURLVisitedOrModified(*it);
108 case chrome::NOTIFICATION_HISTORY_URLS_DELETED:
109 OnURLsDeleted(*content::Details<URLsDeletedDetails>(details).ptr());
112 // For simplicity, the unit tests send us all notifications, even when
113 // we haven't registered for them, so don't assert here.
118 void InMemoryHistoryBackend::OnURLVisitedOrModified(const URLRow& url_row) {
120 DCHECK(url_row.id());
121 if (url_row.typed_count() || db_->GetKeywordSearchTermRow(url_row.id(), NULL))
122 db_->InsertOrUpdateURLRowByID(url_row);
124 db_->DeleteURLRow(url_row.id());
127 void InMemoryHistoryBackend::OnURLsDeleted(const URLsDeletedDetails& details) {
130 if (details.all_history) {
131 // When all history is deleted, the individual URLs won't be listed. Just
132 // create a new database to quickly clear everything out.
133 db_.reset(new InMemoryDatabase);
134 if (!db_->InitFromScratch())
139 // Delete all matching URLs in our database.
140 for (URLRows::const_iterator row = details.rows.begin();
141 row != details.rows.end(); ++row) {
142 // This will also delete the corresponding keyword search term.
143 // Ignore errors, as we typically only cache a subset of URLRows.
144 db_->DeleteURLRow(row->id());
148 void InMemoryHistoryBackend::OnKeywordSearchTermUpdated(
149 const KeywordSearchUpdatedDetails& details) {
150 DCHECK(details.url_row.id());
151 db_->InsertOrUpdateURLRowByID(details.url_row);
152 db_->SetKeywordSearchTermsForURL(
153 details.url_row.id(), details.keyword_id, details.term);
156 void InMemoryHistoryBackend::OnKeywordSearchTermDeleted(
157 const KeywordSearchDeletedDetails& details) {
158 // For simplicity, this will not remove the corresponding URLRow, but this is
159 // okay, as the main database does not do so either.
160 db_->DeleteKeywordSearchTermForURL(details.url_row_id);
163 } // namespace history