Home | History | Annotate | Download | only in common
      1 // Copyright 2013 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 "components/webdata/common/web_database_service.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/location.h"
      9 #include "components/webdata/common/web_data_request_manager.h"
     10 #include "components/webdata/common/web_data_results.h"
     11 #include "components/webdata/common/web_data_service_backend.h"
     12 #include "components/webdata/common/web_data_service_consumer.h"
     13 
     14 using base::Bind;
     15 using base::FilePath;
     16 
     17 // Receives messages from the backend on the DB thread, posts them to
     18 // WebDatabaseService on the UI thread.
     19 class WebDatabaseService::BackendDelegate :
     20     public WebDataServiceBackend::Delegate {
     21  public:
     22   BackendDelegate(
     23       const base::WeakPtr<WebDatabaseService>& web_database_service)
     24       : web_database_service_(web_database_service),
     25         callback_thread_(base::MessageLoopProxy::current()) {
     26   }
     27 
     28   virtual void DBLoaded(sql::InitStatus status) OVERRIDE {
     29     callback_thread_->PostTask(
     30         FROM_HERE,
     31         base::Bind(&WebDatabaseService::OnDatabaseLoadDone,
     32                    web_database_service_,
     33                    status));
     34   }
     35  private:
     36   const base::WeakPtr<WebDatabaseService> web_database_service_;
     37   scoped_refptr<base::MessageLoopProxy> callback_thread_;
     38 };
     39 
     40 WebDatabaseService::WebDatabaseService(
     41     const base::FilePath& path,
     42     const scoped_refptr<base::MessageLoopProxy>& ui_thread,
     43     const scoped_refptr<base::MessageLoopProxy>& db_thread)
     44     : base::RefCountedDeleteOnMessageLoop<WebDatabaseService>(ui_thread),
     45       path_(path),
     46       weak_ptr_factory_(this),
     47       db_loaded_(false),
     48       db_thread_(db_thread) {
     49   // WebDatabaseService should be instantiated on UI thread.
     50   DCHECK(ui_thread->BelongsToCurrentThread());
     51   // WebDatabaseService requires DB thread if instantiated.
     52   DCHECK(db_thread.get());
     53 }
     54 
     55 WebDatabaseService::~WebDatabaseService() {
     56 }
     57 
     58 void WebDatabaseService::AddTable(scoped_ptr<WebDatabaseTable> table) {
     59   if (!wds_backend_.get()) {
     60     wds_backend_ = new WebDataServiceBackend(
     61         path_, new BackendDelegate(weak_ptr_factory_.GetWeakPtr()),
     62         db_thread_);
     63   }
     64   wds_backend_->AddTable(table.Pass());
     65 }
     66 
     67 void WebDatabaseService::LoadDatabase() {
     68   DCHECK(wds_backend_.get());
     69 
     70   db_thread_->PostTask(
     71       FROM_HERE,
     72       Bind(&WebDataServiceBackend::InitDatabase, wds_backend_));
     73 }
     74 
     75 void WebDatabaseService::UnloadDatabase() {
     76   db_loaded_ = false;
     77   if (!wds_backend_.get())
     78     return;
     79   db_thread_->PostTask(FROM_HERE,
     80       Bind(&WebDataServiceBackend::ShutdownDatabase,
     81            wds_backend_, true));
     82 }
     83 
     84 void WebDatabaseService::ShutdownDatabase() {
     85   db_loaded_ = false;
     86   weak_ptr_factory_.InvalidateWeakPtrs();
     87   loaded_callbacks_.clear();
     88   error_callbacks_.clear();
     89   if (!wds_backend_.get())
     90     return;
     91   db_thread_->PostTask(FROM_HERE,
     92       Bind(&WebDataServiceBackend::ShutdownDatabase,
     93            wds_backend_, false));
     94 }
     95 
     96 WebDatabase* WebDatabaseService::GetDatabaseOnDB() const {
     97   DCHECK(db_thread_->BelongsToCurrentThread());
     98   if (!wds_backend_.get())
     99     return NULL;
    100   return wds_backend_->database();
    101 }
    102 
    103 scoped_refptr<WebDataServiceBackend> WebDatabaseService::GetBackend() const {
    104   return wds_backend_;
    105 }
    106 
    107 void WebDatabaseService::ScheduleDBTask(
    108     const tracked_objects::Location& from_here,
    109     const WriteTask& task) {
    110   if (!wds_backend_.get()) {
    111     NOTREACHED() << "Task scheduled after Shutdown()";
    112     return;
    113   }
    114 
    115   scoped_ptr<WebDataRequest> request(
    116       new WebDataRequest(NULL, wds_backend_->request_manager().get()));
    117 
    118   db_thread_->PostTask(from_here,
    119       Bind(&WebDataServiceBackend::DBWriteTaskWrapper, wds_backend_,
    120            task, base::Passed(&request)));
    121 }
    122 
    123 WebDataServiceBase::Handle WebDatabaseService::ScheduleDBTaskWithResult(
    124     const tracked_objects::Location& from_here,
    125     const ReadTask& task,
    126     WebDataServiceConsumer* consumer) {
    127   DCHECK(consumer);
    128   WebDataServiceBase::Handle handle = 0;
    129 
    130   if (!wds_backend_.get()) {
    131     NOTREACHED() << "Task scheduled after Shutdown()";
    132     return handle;
    133   }
    134 
    135   scoped_ptr<WebDataRequest> request(
    136       new WebDataRequest(consumer, wds_backend_->request_manager().get()));
    137   handle = request->GetHandle();
    138 
    139   db_thread_->PostTask(from_here,
    140       Bind(&WebDataServiceBackend::DBReadTaskWrapper, wds_backend_,
    141            task, base::Passed(&request)));
    142 
    143   return handle;
    144 }
    145 
    146 void WebDatabaseService::CancelRequest(WebDataServiceBase::Handle h) {
    147   if (!wds_backend_.get())
    148     return;
    149   wds_backend_->request_manager()->CancelRequest(h);
    150 }
    151 
    152 void WebDatabaseService::RegisterDBLoadedCallback(
    153     const DBLoadedCallback& callback) {
    154   loaded_callbacks_.push_back(callback);
    155 }
    156 
    157 void WebDatabaseService::RegisterDBErrorCallback(
    158     const DBLoadErrorCallback& callback) {
    159   error_callbacks_.push_back(callback);
    160 }
    161 
    162 void WebDatabaseService::OnDatabaseLoadDone(sql::InitStatus status) {
    163   if (status == sql::INIT_OK) {
    164     db_loaded_ = true;
    165 
    166     for (size_t i = 0; i < loaded_callbacks_.size(); i++) {
    167       if (!loaded_callbacks_[i].is_null())
    168         loaded_callbacks_[i].Run();
    169     }
    170 
    171     loaded_callbacks_.clear();
    172   } else {
    173     // Notify that the database load failed.
    174     for (size_t i = 0; i < error_callbacks_.size(); i++) {
    175       if (!error_callbacks_[i].is_null())
    176         error_callbacks_[i].Run(status);
    177     }
    178 
    179     error_callbacks_.clear();
    180   }
    181 }
    182