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 14using base::Bind; 15using base::FilePath; 16 17// Receives messages from the backend on the DB thread, posts them to 18// WebDatabaseService on the UI thread. 19class 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 40WebDatabaseService::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 db_loaded_(false), 47 db_thread_(db_thread), 48 weak_ptr_factory_(this) { 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 55WebDatabaseService::~WebDatabaseService() { 56} 57 58void 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 67void WebDatabaseService::LoadDatabase() { 68 DCHECK(wds_backend_.get()); 69 db_thread_->PostTask( 70 FROM_HERE, 71 Bind(&WebDataServiceBackend::InitDatabase, wds_backend_)); 72} 73 74void WebDatabaseService::ShutdownDatabase() { 75 db_loaded_ = false; 76 loaded_callbacks_.clear(); 77 error_callbacks_.clear(); 78 weak_ptr_factory_.InvalidateWeakPtrs(); 79 if (!wds_backend_.get()) 80 return; 81 db_thread_->PostTask( 82 FROM_HERE, Bind(&WebDataServiceBackend::ShutdownDatabase, wds_backend_)); 83} 84 85WebDatabase* WebDatabaseService::GetDatabaseOnDB() const { 86 DCHECK(db_thread_->BelongsToCurrentThread()); 87 return wds_backend_.get() ? wds_backend_->database() : NULL; 88} 89 90scoped_refptr<WebDataServiceBackend> WebDatabaseService::GetBackend() const { 91 return wds_backend_; 92} 93 94void WebDatabaseService::ScheduleDBTask( 95 const tracked_objects::Location& from_here, 96 const WriteTask& task) { 97 DCHECK(wds_backend_.get()); 98 scoped_ptr<WebDataRequest> request( 99 new WebDataRequest(NULL, wds_backend_->request_manager().get())); 100 db_thread_->PostTask(from_here, 101 Bind(&WebDataServiceBackend::DBWriteTaskWrapper, 102 wds_backend_, task, base::Passed(&request))); 103} 104 105WebDataServiceBase::Handle WebDatabaseService::ScheduleDBTaskWithResult( 106 const tracked_objects::Location& from_here, 107 const ReadTask& task, 108 WebDataServiceConsumer* consumer) { 109 DCHECK(consumer); 110 DCHECK(wds_backend_.get()); 111 scoped_ptr<WebDataRequest> request( 112 new WebDataRequest(consumer, wds_backend_->request_manager().get())); 113 WebDataServiceBase::Handle handle = request->GetHandle(); 114 db_thread_->PostTask(from_here, 115 Bind(&WebDataServiceBackend::DBReadTaskWrapper, 116 wds_backend_, task, base::Passed(&request))); 117 return handle; 118} 119 120void WebDatabaseService::CancelRequest(WebDataServiceBase::Handle h) { 121 if (!wds_backend_.get()) 122 return; 123 wds_backend_->request_manager()->CancelRequest(h); 124} 125 126void WebDatabaseService::RegisterDBLoadedCallback( 127 const DBLoadedCallback& callback) { 128 loaded_callbacks_.push_back(callback); 129} 130 131void WebDatabaseService::RegisterDBErrorCallback( 132 const DBLoadErrorCallback& callback) { 133 error_callbacks_.push_back(callback); 134} 135 136void WebDatabaseService::OnDatabaseLoadDone(sql::InitStatus status) { 137 if (status == sql::INIT_OK) { 138 db_loaded_ = true; 139 140 for (size_t i = 0; i < loaded_callbacks_.size(); i++) { 141 if (!loaded_callbacks_[i].is_null()) 142 loaded_callbacks_[i].Run(); 143 } 144 145 loaded_callbacks_.clear(); 146 } else { 147 // Notify that the database load failed. 148 for (size_t i = 0; i < error_callbacks_.size(); i++) { 149 if (!error_callbacks_[i].is_null()) 150 error_callbacks_[i].Run(status); 151 } 152 153 error_callbacks_.clear(); 154 } 155} 156