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 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 55 WebDatabaseService::~WebDatabaseService() { 56 } 57 58 void WebDatabaseService::AddTable(scoped_ptr<WebDatabaseTable> table) { 59 if (!wds_backend_) { 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_); 69 db_thread_->PostTask( 70 FROM_HERE, 71 Bind(&WebDataServiceBackend::InitDatabase, wds_backend_)); 72 } 73 74 void WebDatabaseService::ShutdownDatabase() { 75 db_loaded_ = false; 76 loaded_callbacks_.clear(); 77 error_callbacks_.clear(); 78 weak_ptr_factory_.InvalidateWeakPtrs(); 79 if (!wds_backend_) 80 return; 81 db_thread_->PostTask( 82 FROM_HERE, Bind(&WebDataServiceBackend::ShutdownDatabase, wds_backend_)); 83 } 84 85 WebDatabase* WebDatabaseService::GetDatabaseOnDB() const { 86 DCHECK(db_thread_->BelongsToCurrentThread()); 87 return wds_backend_ ? wds_backend_->database() : NULL; 88 } 89 90 scoped_refptr<WebDataServiceBackend> WebDatabaseService::GetBackend() const { 91 return wds_backend_; 92 } 93 94 void WebDatabaseService::ScheduleDBTask( 95 const tracked_objects::Location& from_here, 96 const WriteTask& task) { 97 DCHECK(wds_backend_); 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 105 WebDataServiceBase::Handle WebDatabaseService::ScheduleDBTaskWithResult( 106 const tracked_objects::Location& from_here, 107 const ReadTask& task, 108 WebDataServiceConsumer* consumer) { 109 DCHECK(consumer); 110 DCHECK(wds_backend_); 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 120 void WebDatabaseService::CancelRequest(WebDataServiceBase::Handle h) { 121 if (!wds_backend_) 122 return; 123 wds_backend_->request_manager()->CancelRequest(h); 124 } 125 126 void WebDatabaseService::RegisterDBLoadedCallback( 127 const DBLoadedCallback& callback) { 128 loaded_callbacks_.push_back(callback); 129 } 130 131 void WebDatabaseService::RegisterDBErrorCallback( 132 const DBLoadErrorCallback& callback) { 133 error_callbacks_.push_back(callback); 134 } 135 136 void 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