blob: e630a095f3f3e319ba11b8c0cb131336126668c5 [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/history/in_memory_history_backend.h"
#include <set>
#include <vector>
#include "base/command_line.h"
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/history/history_notifications.h"
#include "chrome/browser/profiles/profile.h"
#include "components/history/core/browser/in_memory_database.h"
#include "components/history/core/browser/url_database.h"
#include "content/public/browser/notification_details.h"
#include "content/public/browser/notification_source.h"
namespace history {
InMemoryHistoryBackend::InMemoryHistoryBackend()
: profile_(NULL) {
}
InMemoryHistoryBackend::~InMemoryHistoryBackend() {}
bool InMemoryHistoryBackend::Init(const base::FilePath& history_filename) {
db_.reset(new InMemoryDatabase);
return db_->InitFromDisk(history_filename);
}
void InMemoryHistoryBackend::AttachToHistoryService(Profile* profile) {
if (!db_) {
NOTREACHED();
return;
}
profile_ = profile;
// TODO(evanm): this is currently necessitated by generate_profile, which
// runs without a browser process. generate_profile should really create
// a browser process, at which point this check can then be nuked.
if (!g_browser_process)
return;
// Register for the notifications we care about.
// We only want notifications for the associated profile.
content::Source<Profile> source(profile_);
registrar_.Add(this, chrome::NOTIFICATION_HISTORY_URL_VISITED, source);
registrar_.Add(this, chrome::NOTIFICATION_HISTORY_URLS_MODIFIED, source);
registrar_.Add(this, chrome::NOTIFICATION_HISTORY_URLS_DELETED, source);
registrar_.Add(
this, chrome::NOTIFICATION_HISTORY_KEYWORD_SEARCH_TERM_UPDATED, source);
registrar_.Add(
this, chrome::NOTIFICATION_HISTORY_KEYWORD_SEARCH_TERM_DELETED, source);
}
void InMemoryHistoryBackend::DeleteAllSearchTermsForKeyword(
KeywordID keyword_id) {
// For simplicity, this will not remove the corresponding URLRows, but
// this is okay, as the main database does not do so either.
db_->DeleteAllSearchTermsForKeyword(keyword_id);
}
void InMemoryHistoryBackend::Observe(
int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) {
switch (type) {
case chrome::NOTIFICATION_HISTORY_URL_VISITED:
OnURLVisitedOrModified(content::Details<URLVisitedDetails>(details)->row);
break;
case chrome::NOTIFICATION_HISTORY_KEYWORD_SEARCH_TERM_UPDATED:
OnKeywordSearchTermUpdated(
*content::Details<KeywordSearchUpdatedDetails>(details).ptr());
break;
case chrome::NOTIFICATION_HISTORY_KEYWORD_SEARCH_TERM_DELETED:
OnKeywordSearchTermDeleted(
*content::Details<KeywordSearchDeletedDetails>(details).ptr());
break;
case chrome::NOTIFICATION_HISTORY_URLS_MODIFIED: {
const URLsModifiedDetails* modified_details =
content::Details<URLsModifiedDetails>(details).ptr();
URLRows::const_iterator it;
for (it = modified_details->changed_urls.begin();
it != modified_details->changed_urls.end(); ++it) {
OnURLVisitedOrModified(*it);
}
break;
}
case chrome::NOTIFICATION_HISTORY_URLS_DELETED:
OnURLsDeleted(*content::Details<URLsDeletedDetails>(details).ptr());
break;
default:
// For simplicity, the unit tests send us all notifications, even when
// we haven't registered for them, so don't assert here.
break;
}
}
void InMemoryHistoryBackend::OnURLVisitedOrModified(const URLRow& url_row) {
DCHECK(db_);
DCHECK(url_row.id());
if (url_row.typed_count() || db_->GetKeywordSearchTermRow(url_row.id(), NULL))
db_->InsertOrUpdateURLRowByID(url_row);
else
db_->DeleteURLRow(url_row.id());
}
void InMemoryHistoryBackend::OnURLsDeleted(const URLsDeletedDetails& details) {
DCHECK(db_);
if (details.all_history) {
// When all history is deleted, the individual URLs won't be listed. Just
// create a new database to quickly clear everything out.
db_.reset(new InMemoryDatabase);
if (!db_->InitFromScratch())
db_.reset();
return;
}
// Delete all matching URLs in our database.
for (URLRows::const_iterator row = details.rows.begin();
row != details.rows.end(); ++row) {
// This will also delete the corresponding keyword search term.
// Ignore errors, as we typically only cache a subset of URLRows.
db_->DeleteURLRow(row->id());
}
}
void InMemoryHistoryBackend::OnKeywordSearchTermUpdated(
const KeywordSearchUpdatedDetails& details) {
DCHECK(details.url_row.id());
db_->InsertOrUpdateURLRowByID(details.url_row);
db_->SetKeywordSearchTermsForURL(
details.url_row.id(), details.keyword_id, details.term);
}
void InMemoryHistoryBackend::OnKeywordSearchTermDeleted(
const KeywordSearchDeletedDetails& details) {
// For simplicity, this will not remove the corresponding URLRow, but this is
// okay, as the main database does not do so either.
db_->DeleteKeywordSearchTermForURL(details.url_row_id);
}
} // namespace history