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