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:
BackendDelegate(const base::WeakPtr<WebDatabaseService> & web_database_service)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
DBLoaded(sql::InitStatus status)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
WebDatabaseService(const base::FilePath & path,const scoped_refptr<base::MessageLoopProxy> & ui_thread,const scoped_refptr<base::MessageLoopProxy> & db_thread)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
~WebDatabaseService()55 WebDatabaseService::~WebDatabaseService() {
56 }
57
AddTable(scoped_ptr<WebDatabaseTable> table)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
LoadDatabase()67 void WebDatabaseService::LoadDatabase() {
68 DCHECK(wds_backend_.get());
69 db_thread_->PostTask(
70 FROM_HERE,
71 Bind(&WebDataServiceBackend::InitDatabase, wds_backend_));
72 }
73
ShutdownDatabase()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_.get())
80 return;
81 db_thread_->PostTask(
82 FROM_HERE, Bind(&WebDataServiceBackend::ShutdownDatabase, wds_backend_));
83 }
84
GetDatabaseOnDB() const85 WebDatabase* WebDatabaseService::GetDatabaseOnDB() const {
86 DCHECK(db_thread_->BelongsToCurrentThread());
87 return wds_backend_.get() ? wds_backend_->database() : NULL;
88 }
89
GetBackend() const90 scoped_refptr<WebDataServiceBackend> WebDatabaseService::GetBackend() const {
91 return wds_backend_;
92 }
93
ScheduleDBTask(const tracked_objects::Location & from_here,const WriteTask & task)94 void 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
ScheduleDBTaskWithResult(const tracked_objects::Location & from_here,const ReadTask & task,WebDataServiceConsumer * consumer)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_.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
CancelRequest(WebDataServiceBase::Handle h)120 void WebDatabaseService::CancelRequest(WebDataServiceBase::Handle h) {
121 if (!wds_backend_.get())
122 return;
123 wds_backend_->request_manager()->CancelRequest(h);
124 }
125
RegisterDBLoadedCallback(const DBLoadedCallback & callback)126 void WebDatabaseService::RegisterDBLoadedCallback(
127 const DBLoadedCallback& callback) {
128 loaded_callbacks_.push_back(callback);
129 }
130
RegisterDBErrorCallback(const DBLoadErrorCallback & callback)131 void WebDatabaseService::RegisterDBErrorCallback(
132 const DBLoadErrorCallback& callback) {
133 error_callbacks_.push_back(callback);
134 }
135
OnDatabaseLoadDone(sql::InitStatus status)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