Home | History | Annotate | Download | only in history
      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.
      4 
      5 #include "chrome/browser/history/in_memory_history_backend.h"
      6 
      7 #include <set>
      8 #include <vector>
      9 
     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/profiles/profile.h"
     17 #include "components/history/core/browser/in_memory_database.h"
     18 #include "components/history/core/browser/url_database.h"
     19 #include "content/public/browser/notification_details.h"
     20 #include "content/public/browser/notification_source.h"
     21 
     22 namespace history {
     23 
     24 InMemoryHistoryBackend::InMemoryHistoryBackend()
     25     : profile_(NULL) {
     26 }
     27 
     28 InMemoryHistoryBackend::~InMemoryHistoryBackend() {}
     29 
     30 bool InMemoryHistoryBackend::Init(const base::FilePath& history_filename) {
     31   db_.reset(new InMemoryDatabase);
     32   return db_->InitFromDisk(history_filename);
     33 }
     34 
     35 void InMemoryHistoryBackend::AttachToHistoryService(Profile* profile) {
     36   if (!db_) {
     37     NOTREACHED();
     38     return;
     39   }
     40 
     41   profile_ = profile;
     42 
     43   // TODO(evanm): this is currently necessitated by generate_profile, which
     44   // runs without a browser process. generate_profile should really create
     45   // a browser process, at which point this check can then be nuked.
     46   if (!g_browser_process)
     47     return;
     48 
     49   // Register for the notifications we care about.
     50   // We only want notifications for the associated profile.
     51   content::Source<Profile> source(profile_);
     52   registrar_.Add(this, chrome::NOTIFICATION_HISTORY_URL_VISITED, source);
     53   registrar_.Add(this, chrome::NOTIFICATION_HISTORY_URLS_MODIFIED, source);
     54   registrar_.Add(this, chrome::NOTIFICATION_HISTORY_URLS_DELETED, source);
     55   registrar_.Add(
     56       this, chrome::NOTIFICATION_HISTORY_KEYWORD_SEARCH_TERM_UPDATED, source);
     57   registrar_.Add(
     58       this, chrome::NOTIFICATION_HISTORY_KEYWORD_SEARCH_TERM_DELETED, source);
     59 }
     60 
     61 void InMemoryHistoryBackend::DeleteAllSearchTermsForKeyword(
     62     KeywordID keyword_id) {
     63   // For simplicity, this will not remove the corresponding URLRows, but
     64   // this is okay, as the main database does not do so either.
     65   db_->DeleteAllSearchTermsForKeyword(keyword_id);
     66 }
     67 
     68 void InMemoryHistoryBackend::Observe(
     69     int type,
     70     const content::NotificationSource& source,
     71     const content::NotificationDetails& details) {
     72   switch (type) {
     73     case chrome::NOTIFICATION_HISTORY_URL_VISITED:
     74       OnURLVisitedOrModified(content::Details<URLVisitedDetails>(details)->row);
     75       break;
     76     case chrome::NOTIFICATION_HISTORY_KEYWORD_SEARCH_TERM_UPDATED:
     77       OnKeywordSearchTermUpdated(
     78           *content::Details<KeywordSearchUpdatedDetails>(details).ptr());
     79       break;
     80     case chrome::NOTIFICATION_HISTORY_KEYWORD_SEARCH_TERM_DELETED:
     81       OnKeywordSearchTermDeleted(
     82           *content::Details<KeywordSearchDeletedDetails>(details).ptr());
     83       break;
     84     case chrome::NOTIFICATION_HISTORY_URLS_MODIFIED: {
     85       const URLsModifiedDetails* modified_details =
     86           content::Details<URLsModifiedDetails>(details).ptr();
     87       URLRows::const_iterator it;
     88       for (it = modified_details->changed_urls.begin();
     89            it != modified_details->changed_urls.end(); ++it) {
     90         OnURLVisitedOrModified(*it);
     91       }
     92       break;
     93     }
     94     case chrome::NOTIFICATION_HISTORY_URLS_DELETED:
     95       OnURLsDeleted(*content::Details<URLsDeletedDetails>(details).ptr());
     96       break;
     97     default:
     98       // For simplicity, the unit tests send us all notifications, even when
     99       // we haven't registered for them, so don't assert here.
    100       break;
    101   }
    102 }
    103 
    104 void InMemoryHistoryBackend::OnURLVisitedOrModified(const URLRow& url_row) {
    105   DCHECK(db_);
    106   DCHECK(url_row.id());
    107   if (url_row.typed_count() || db_->GetKeywordSearchTermRow(url_row.id(), NULL))
    108     db_->InsertOrUpdateURLRowByID(url_row);
    109   else
    110     db_->DeleteURLRow(url_row.id());
    111 }
    112 
    113 void InMemoryHistoryBackend::OnURLsDeleted(const URLsDeletedDetails& details) {
    114   DCHECK(db_);
    115 
    116   if (details.all_history) {
    117     // When all history is deleted, the individual URLs won't be listed. Just
    118     // create a new database to quickly clear everything out.
    119     db_.reset(new InMemoryDatabase);
    120     if (!db_->InitFromScratch())
    121       db_.reset();
    122     return;
    123   }
    124 
    125   // Delete all matching URLs in our database.
    126   for (URLRows::const_iterator row = details.rows.begin();
    127        row != details.rows.end(); ++row) {
    128     // This will also delete the corresponding keyword search term.
    129     // Ignore errors, as we typically only cache a subset of URLRows.
    130     db_->DeleteURLRow(row->id());
    131   }
    132 }
    133 
    134 void InMemoryHistoryBackend::OnKeywordSearchTermUpdated(
    135     const KeywordSearchUpdatedDetails& details) {
    136   DCHECK(details.url_row.id());
    137   db_->InsertOrUpdateURLRowByID(details.url_row);
    138   db_->SetKeywordSearchTermsForURL(
    139       details.url_row.id(), details.keyword_id, details.term);
    140 }
    141 
    142 void InMemoryHistoryBackend::OnKeywordSearchTermDeleted(
    143     const KeywordSearchDeletedDetails& details) {
    144   // For simplicity, this will not remove the corresponding URLRow, but this is
    145   // okay, as the main database does not do so either.
    146   db_->DeleteKeywordSearchTermForURL(details.url_row_id);
    147 }
    148 
    149 }  // namespace history
    150