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