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