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_data_service_backend.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_database.h"
11#include "components/webdata/common/web_database_table.h"
12
13using base::Bind;
14using base::FilePath;
15
16WebDataServiceBackend::WebDataServiceBackend(
17    const FilePath& path,
18    Delegate* delegate,
19    const scoped_refptr<base::MessageLoopProxy>& db_thread)
20    : base::RefCountedDeleteOnMessageLoop<WebDataServiceBackend>(db_thread),
21      db_path_(path),
22      request_manager_(new WebDataRequestManager()),
23      init_status_(sql::INIT_FAILURE),
24      init_complete_(false),
25      delegate_(delegate) {
26}
27
28void WebDataServiceBackend::AddTable(scoped_ptr<WebDatabaseTable> table) {
29  DCHECK(!db_.get());
30  tables_.push_back(table.release());
31}
32
33void WebDataServiceBackend::InitDatabase() {
34  LoadDatabaseIfNecessary();
35  if (delegate_) {
36    delegate_->DBLoaded(init_status_);
37  }
38}
39
40sql::InitStatus WebDataServiceBackend::LoadDatabaseIfNecessary() {
41  if (init_complete_ || db_path_.empty()) {
42    return init_status_;
43  }
44  init_complete_ = true;
45  db_.reset(new WebDatabase());
46
47  for (ScopedVector<WebDatabaseTable>::iterator it = tables_.begin();
48       it != tables_.end(); ++it) {
49    db_->AddTable(*it);
50  }
51
52  init_status_ = db_->Init(db_path_);
53  if (init_status_ != sql::INIT_OK) {
54    LOG(ERROR) << "Cannot initialize the web database: " << init_status_;
55    db_.reset(NULL);
56    return init_status_;
57  }
58
59  db_->BeginTransaction();
60  return init_status_;
61}
62
63void WebDataServiceBackend::ShutdownDatabase() {
64  if (db_ && init_status_ == sql::INIT_OK)
65    db_->CommitTransaction();
66  db_.reset(NULL);
67  init_complete_ = true;  // Ensures the init sequence is not re-run.
68  init_status_ = sql::INIT_FAILURE;
69}
70
71void WebDataServiceBackend::DBWriteTaskWrapper(
72    const WebDatabaseService::WriteTask& task,
73    scoped_ptr<WebDataRequest> request) {
74  if (request->IsCancelled())
75    return;
76
77  ExecuteWriteTask(task);
78  request_manager_->RequestCompleted(request.Pass());
79}
80
81void WebDataServiceBackend::ExecuteWriteTask(
82    const WebDatabaseService::WriteTask& task) {
83  LoadDatabaseIfNecessary();
84  if (db_ && init_status_ == sql::INIT_OK) {
85    WebDatabase::State state = task.Run(db_.get());
86    if (state == WebDatabase::COMMIT_NEEDED)
87      Commit();
88  }
89}
90
91void WebDataServiceBackend::DBReadTaskWrapper(
92    const WebDatabaseService::ReadTask& task,
93    scoped_ptr<WebDataRequest> request) {
94  if (request->IsCancelled())
95    return;
96
97  request->SetResult(ExecuteReadTask(task).Pass());
98  request_manager_->RequestCompleted(request.Pass());
99}
100
101scoped_ptr<WDTypedResult> WebDataServiceBackend::ExecuteReadTask(
102    const WebDatabaseService::ReadTask& task) {
103  LoadDatabaseIfNecessary();
104  if (db_ && init_status_ == sql::INIT_OK) {
105    return task.Run(db_.get());
106  }
107  return scoped_ptr<WDTypedResult>();
108}
109
110WebDataServiceBackend::~WebDataServiceBackend() {
111  ShutdownDatabase();
112}
113
114void WebDataServiceBackend::Commit() {
115  DCHECK(db_);
116  DCHECK_EQ(sql::INIT_OK, init_status_);
117  db_->CommitTransaction();
118  db_->BeginTransaction();
119}
120