15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/history/in_memory_history_backend.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <set>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <vector>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/command_line.h"
11868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
12eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/time/time.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/browser_process.h"
147dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "chrome/browser/chrome_notification_types.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/history/history_notifications.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/profiles/profile.h"
17116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "components/history/core/browser/in_memory_database.h"
18116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "components/history/core/browser/url_database.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/notification_details.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/notification_source.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace history {
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)InMemoryHistoryBackend::InMemoryHistoryBackend()
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : profile_(NULL) {
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)InMemoryHistoryBackend::~InMemoryHistoryBackend() {}
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
30116680a4aac90f2aa7413d9095a592090648e557Ben Murdochbool InMemoryHistoryBackend::Init(const base::FilePath& history_filename) {
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_.reset(new InMemoryDatabase);
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return db_->InitFromDisk(history_filename);
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void InMemoryHistoryBackend::AttachToHistoryService(Profile* profile) {
36b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!db_) {
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  profile_ = profile;
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(evanm): this is currently necessitated by generate_profile, which
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // runs without a browser process. generate_profile should really create
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // a browser process, at which point this check can then be nuked.
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!g_browser_process)
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Register for the notifications we care about.
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We only want notifications for the associated profile.
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  content::Source<Profile> source(profile_);
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  registrar_.Add(this, chrome::NOTIFICATION_HISTORY_URL_VISITED, source);
530529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  registrar_.Add(this, chrome::NOTIFICATION_HISTORY_URLS_MODIFIED, source);
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  registrar_.Add(this, chrome::NOTIFICATION_HISTORY_URLS_DELETED, source);
550f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  registrar_.Add(
560f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      this, chrome::NOTIFICATION_HISTORY_KEYWORD_SEARCH_TERM_UPDATED, source);
570f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  registrar_.Add(
580f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      this, chrome::NOTIFICATION_HISTORY_KEYWORD_SEARCH_TERM_DELETED, source);
59116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
60116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
61116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid InMemoryHistoryBackend::DeleteAllSearchTermsForKeyword(
62116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    KeywordID keyword_id) {
63116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // For simplicity, this will not remove the corresponding URLRows, but
64116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // this is okay, as the main database does not do so either.
65116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  db_->DeleteAllSearchTermsForKeyword(keyword_id);
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void InMemoryHistoryBackend::Observe(
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int type,
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const content::NotificationSource& source,
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const content::NotificationDetails& details) {
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (type) {
730529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    case chrome::NOTIFICATION_HISTORY_URL_VISITED:
740529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      OnURLVisitedOrModified(content::Details<URLVisitedDetails>(details)->row);
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case chrome::NOTIFICATION_HISTORY_KEYWORD_SEARCH_TERM_UPDATED:
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      OnKeywordSearchTermUpdated(
780529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch          *content::Details<KeywordSearchUpdatedDetails>(details).ptr());
790f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      break;
800f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    case chrome::NOTIFICATION_HISTORY_KEYWORD_SEARCH_TERM_DELETED:
810f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      OnKeywordSearchTermDeleted(
820529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch          *content::Details<KeywordSearchDeletedDetails>(details).ptr());
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
840529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    case chrome::NOTIFICATION_HISTORY_URLS_MODIFIED: {
850529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      const URLsModifiedDetails* modified_details =
860529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch          content::Details<URLsModifiedDetails>(details).ptr();
870529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      URLRows::const_iterator it;
880529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      for (it = modified_details->changed_urls.begin();
890529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch           it != modified_details->changed_urls.end(); ++it) {
900529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        OnURLVisitedOrModified(*it);
910529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      }
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
930529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    }
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case chrome::NOTIFICATION_HISTORY_URLS_DELETED:
950529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      OnURLsDeleted(*content::Details<URLsDeletedDetails>(details).ptr());
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // For simplicity, the unit tests send us all notifications, even when
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // we haven't registered for them, so don't assert here.
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1040529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochvoid InMemoryHistoryBackend::OnURLVisitedOrModified(const URLRow& url_row) {
105b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  DCHECK(db_);
1060529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  DCHECK(url_row.id());
1070529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (url_row.typed_count() || db_->GetKeywordSearchTermRow(url_row.id(), NULL))
1080529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    db_->InsertOrUpdateURLRowByID(url_row);
1090529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  else
1100529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    db_->DeleteURLRow(url_row.id());
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void InMemoryHistoryBackend::OnURLsDeleted(const URLsDeletedDetails& details) {
114b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  DCHECK(db_);
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (details.all_history) {
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // When all history is deleted, the individual URLs won't be listed. Just
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // create a new database to quickly clear everything out.
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    db_.reset(new InMemoryDatabase);
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!db_->InitFromScratch())
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      db_.reset();
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Delete all matching URLs in our database.
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (URLRows::const_iterator row = details.rows.begin();
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       row != details.rows.end(); ++row) {
1280529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    // This will also delete the corresponding keyword search term.
1290529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    // Ignore errors, as we typically only cache a subset of URLRows.
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    db_->DeleteURLRow(row->id());
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void InMemoryHistoryBackend::OnKeywordSearchTermUpdated(
1350f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    const KeywordSearchUpdatedDetails& details) {
1360529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  DCHECK(details.url_row.id());
1370529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  db_->InsertOrUpdateURLRowByID(details.url_row);
1380529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  db_->SetKeywordSearchTermsForURL(
1390529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      details.url_row.id(), details.keyword_id, details.term);
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1420f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)void InMemoryHistoryBackend::OnKeywordSearchTermDeleted(
1430f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    const KeywordSearchDeletedDetails& details) {
1440529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // For simplicity, this will not remove the corresponding URLRow, but this is
1450529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // okay, as the main database does not do so either.
1460529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  db_->DeleteKeywordSearchTermForURL(details.url_row_id);
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace history
150