普通文本  |  182行  |  5.3 KB

// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "components/webdata/common/web_database_service.h"

#include "base/bind.h"
#include "base/location.h"
#include "components/webdata/common/web_data_request_manager.h"
#include "components/webdata/common/web_data_results.h"
#include "components/webdata/common/web_data_service_backend.h"
#include "components/webdata/common/web_data_service_consumer.h"

using base::Bind;
using base::FilePath;

// Receives messages from the backend on the DB thread, posts them to
// WebDatabaseService on the UI thread.
class WebDatabaseService::BackendDelegate :
    public WebDataServiceBackend::Delegate {
 public:
  BackendDelegate(
      const base::WeakPtr<WebDatabaseService>& web_database_service)
      : web_database_service_(web_database_service),
        callback_thread_(base::MessageLoopProxy::current()) {
  }

  virtual void DBLoaded(sql::InitStatus status) OVERRIDE {
    callback_thread_->PostTask(
        FROM_HERE,
        base::Bind(&WebDatabaseService::OnDatabaseLoadDone,
                   web_database_service_,
                   status));
  }
 private:
  const base::WeakPtr<WebDatabaseService> web_database_service_;
  scoped_refptr<base::MessageLoopProxy> callback_thread_;
};

WebDatabaseService::WebDatabaseService(
    const base::FilePath& path,
    const scoped_refptr<base::MessageLoopProxy>& ui_thread,
    const scoped_refptr<base::MessageLoopProxy>& db_thread)
    : base::RefCountedDeleteOnMessageLoop<WebDatabaseService>(ui_thread),
      path_(path),
      weak_ptr_factory_(this),
      db_loaded_(false),
      db_thread_(db_thread) {
  // WebDatabaseService should be instantiated on UI thread.
  DCHECK(ui_thread->BelongsToCurrentThread());
  // WebDatabaseService requires DB thread if instantiated.
  DCHECK(db_thread.get());
}

WebDatabaseService::~WebDatabaseService() {
}

void WebDatabaseService::AddTable(scoped_ptr<WebDatabaseTable> table) {
  if (!wds_backend_.get()) {
    wds_backend_ = new WebDataServiceBackend(
        path_, new BackendDelegate(weak_ptr_factory_.GetWeakPtr()),
        db_thread_);
  }
  wds_backend_->AddTable(table.Pass());
}

void WebDatabaseService::LoadDatabase() {
  DCHECK(wds_backend_.get());

  db_thread_->PostTask(
      FROM_HERE,
      Bind(&WebDataServiceBackend::InitDatabase, wds_backend_));
}

void WebDatabaseService::UnloadDatabase() {
  db_loaded_ = false;
  if (!wds_backend_.get())
    return;
  db_thread_->PostTask(FROM_HERE,
      Bind(&WebDataServiceBackend::ShutdownDatabase,
           wds_backend_, true));
}

void WebDatabaseService::ShutdownDatabase() {
  db_loaded_ = false;
  weak_ptr_factory_.InvalidateWeakPtrs();
  loaded_callbacks_.clear();
  error_callbacks_.clear();
  if (!wds_backend_.get())
    return;
  db_thread_->PostTask(FROM_HERE,
      Bind(&WebDataServiceBackend::ShutdownDatabase,
           wds_backend_, false));
}

WebDatabase* WebDatabaseService::GetDatabaseOnDB() const {
  DCHECK(db_thread_->BelongsToCurrentThread());
  if (!wds_backend_.get())
    return NULL;
  return wds_backend_->database();
}

scoped_refptr<WebDataServiceBackend> WebDatabaseService::GetBackend() const {
  return wds_backend_;
}

void WebDatabaseService::ScheduleDBTask(
    const tracked_objects::Location& from_here,
    const WriteTask& task) {
  if (!wds_backend_.get()) {
    NOTREACHED() << "Task scheduled after Shutdown()";
    return;
  }

  scoped_ptr<WebDataRequest> request(
      new WebDataRequest(NULL, wds_backend_->request_manager().get()));

  db_thread_->PostTask(from_here,
      Bind(&WebDataServiceBackend::DBWriteTaskWrapper, wds_backend_,
           task, base::Passed(&request)));
}

WebDataServiceBase::Handle WebDatabaseService::ScheduleDBTaskWithResult(
    const tracked_objects::Location& from_here,
    const ReadTask& task,
    WebDataServiceConsumer* consumer) {
  DCHECK(consumer);
  WebDataServiceBase::Handle handle = 0;

  if (!wds_backend_.get()) {
    NOTREACHED() << "Task scheduled after Shutdown()";
    return handle;
  }

  scoped_ptr<WebDataRequest> request(
      new WebDataRequest(consumer, wds_backend_->request_manager().get()));
  handle = request->GetHandle();

  db_thread_->PostTask(from_here,
      Bind(&WebDataServiceBackend::DBReadTaskWrapper, wds_backend_,
           task, base::Passed(&request)));

  return handle;
}

void WebDatabaseService::CancelRequest(WebDataServiceBase::Handle h) {
  if (!wds_backend_.get())
    return;
  wds_backend_->request_manager()->CancelRequest(h);
}

void WebDatabaseService::RegisterDBLoadedCallback(
    const DBLoadedCallback& callback) {
  loaded_callbacks_.push_back(callback);
}

void WebDatabaseService::RegisterDBErrorCallback(
    const DBLoadErrorCallback& callback) {
  error_callbacks_.push_back(callback);
}

void WebDatabaseService::OnDatabaseLoadDone(sql::InitStatus status) {
  if (status == sql::INIT_OK) {
    db_loaded_ = true;

    for (size_t i = 0; i < loaded_callbacks_.size(); i++) {
      if (!loaded_callbacks_[i].is_null())
        loaded_callbacks_[i].Run();
    }

    loaded_callbacks_.clear();
  } else {
    // Notify that the database load failed.
    for (size_t i = 0; i < error_callbacks_.size(); i++) {
      if (!error_callbacks_[i].is_null())
        error_callbacks_[i].Run(status);
    }

    error_callbacks_.clear();
  }
}