1// Copyright (c) 2012 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 "content/browser/webui/url_data_manager.h"
6
7#include <vector>
8
9#include "base/bind.h"
10#include "base/lazy_instance.h"
11#include "base/memory/ref_counted_memory.h"
12#include "base/message_loop/message_loop.h"
13#include "base/strings/string_util.h"
14#include "base/synchronization/lock.h"
15#include "content/browser/resource_context_impl.h"
16#include "content/browser/webui/url_data_manager_backend.h"
17#include "content/browser/webui/url_data_source_impl.h"
18#include "content/browser/webui/web_ui_data_source_impl.h"
19#include "content/public/browser/browser_context.h"
20#include "content/public/browser/browser_thread.h"
21#include "content/public/browser/url_data_source.h"
22
23namespace content {
24namespace {
25
26const char kURLDataManagerKeyName[] = "url_data_manager";
27
28base::LazyInstance<base::Lock>::Leaky g_delete_lock = LAZY_INSTANCE_INITIALIZER;
29
30URLDataManager* GetFromBrowserContext(BrowserContext* context) {
31  if (!context->GetUserData(kURLDataManagerKeyName)) {
32    context->SetUserData(kURLDataManagerKeyName, new URLDataManager(context));
33  }
34  return static_cast<URLDataManager*>(
35      context->GetUserData(kURLDataManagerKeyName));
36}
37
38// Invoked on the IO thread to do the actual adding of the DataSource.
39static void AddDataSourceOnIOThread(
40    ResourceContext* resource_context,
41    scoped_refptr<URLDataSourceImpl> data_source) {
42  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
43  GetURLDataManagerForResourceContext(resource_context)->AddDataSource(
44      data_source.get());
45}
46
47}  // namespace
48
49// static
50URLDataManager::URLDataSources* URLDataManager::data_sources_ = NULL;
51
52URLDataManager::URLDataManager(BrowserContext* browser_context)
53    : browser_context_(browser_context) {
54}
55
56URLDataManager::~URLDataManager() {
57}
58
59void URLDataManager::AddDataSource(URLDataSourceImpl* source) {
60  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
61  BrowserThread::PostTask(
62      BrowserThread::IO, FROM_HERE,
63      base::Bind(&AddDataSourceOnIOThread,
64                 browser_context_->GetResourceContext(),
65                 make_scoped_refptr(source)));
66}
67
68// static
69void URLDataManager::DeleteDataSources() {
70  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
71  URLDataSources sources;
72  {
73    base::AutoLock lock(g_delete_lock.Get());
74    if (!data_sources_)
75      return;
76    data_sources_->swap(sources);
77  }
78  for (size_t i = 0; i < sources.size(); ++i)
79    delete sources[i];
80}
81
82// static
83void URLDataManager::DeleteDataSource(const URLDataSourceImpl* data_source) {
84  // Invoked when a DataSource is no longer referenced and needs to be deleted.
85  if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
86    // We're on the UI thread, delete right away.
87    delete data_source;
88    return;
89  }
90
91  // We're not on the UI thread, add the DataSource to the list of DataSources
92  // to delete.
93  bool schedule_delete = false;
94  {
95    base::AutoLock lock(g_delete_lock.Get());
96    if (!data_sources_)
97      data_sources_ = new URLDataSources();
98    schedule_delete = data_sources_->empty();
99    data_sources_->push_back(data_source);
100  }
101  if (schedule_delete) {
102    // Schedule a task to delete the DataSource back on the UI thread.
103    BrowserThread::PostTask(
104        BrowserThread::UI, FROM_HERE,
105        base::Bind(&URLDataManager::DeleteDataSources));
106  }
107}
108
109// static
110void URLDataManager::AddDataSource(BrowserContext* browser_context,
111                                   URLDataSource* source) {
112  GetFromBrowserContext(browser_context)->
113      AddDataSource(new URLDataSourceImpl(source->GetSource(), source));
114}
115
116// static
117void URLDataManager::AddWebUIDataSource(BrowserContext* browser_context,
118                                        WebUIDataSource* source) {
119  WebUIDataSourceImpl* impl = static_cast<WebUIDataSourceImpl*>(source);
120  GetFromBrowserContext(browser_context)->AddDataSource(impl);
121}
122
123// static
124bool URLDataManager::IsScheduledForDeletion(
125    const URLDataSourceImpl* data_source) {
126  base::AutoLock lock(g_delete_lock.Get());
127  if (!data_sources_)
128    return false;
129  return std::find(data_sources_->begin(), data_sources_->end(), data_source) !=
130      data_sources_->end();
131}
132
133}  // namespace content
134