Add abhijeet.k@samsung.com to AUTHORS list.
[chromium-blink-merge.git] / components / dom_distiller / core / task_tracker.cc
blobd9eb43afbef0e3266fc481b244078d47daf89fc2
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.
5 #include "components/dom_distiller/core/task_tracker.h"
7 #include "base/auto_reset.h"
8 #include "base/message_loop/message_loop.h"
9 #include "components/dom_distiller/core/distilled_content_store.h"
10 #include "components/dom_distiller/core/proto/distilled_article.pb.h"
11 #include "components/dom_distiller/core/proto/distilled_page.pb.h"
13 namespace dom_distiller {
15 ViewerHandle::ViewerHandle(CancelCallback callback)
16 : cancel_callback_(callback) {}
18 ViewerHandle::~ViewerHandle() {
19 if (!cancel_callback_.is_null()) {
20 cancel_callback_.Run();
24 TaskTracker::TaskTracker(const ArticleEntry& entry,
25 CancelCallback callback,
26 DistilledContentStore* content_store)
27 : cancel_callback_(callback),
28 content_store_(content_store),
29 blob_fetcher_running_(false),
30 entry_(entry),
31 distilled_article_(),
32 content_ready_(false),
33 destruction_allowed_(true),
34 weak_ptr_factory_(this) {}
36 TaskTracker::~TaskTracker() {
37 DCHECK(destruction_allowed_);
38 DCHECK(viewers_.empty());
41 void TaskTracker::StartDistiller(DistillerFactory* factory,
42 scoped_ptr<DistillerPage> distiller_page) {
43 if (distiller_) {
44 return;
46 if (entry_.pages_size() == 0) {
47 return;
49 GURL url(entry_.pages(0).url());
50 DCHECK(url.is_valid());
52 distiller_ = factory->CreateDistillerForUrl(url);
53 distiller_->DistillPage(url,
54 distiller_page.Pass(),
55 base::Bind(&TaskTracker::OnDistillerFinished,
56 weak_ptr_factory_.GetWeakPtr()),
57 base::Bind(&TaskTracker::OnArticleDistillationUpdated,
58 weak_ptr_factory_.GetWeakPtr()));
61 void TaskTracker::StartBlobFetcher() {
62 if (content_store_) {
63 blob_fetcher_running_ = true;
64 content_store_->LoadContent(entry_,
65 base::Bind(&TaskTracker::OnBlobFetched,
66 weak_ptr_factory_.GetWeakPtr()));
70 void TaskTracker::AddSaveCallback(const SaveCallback& callback) {
71 DCHECK(!callback.is_null());
72 save_callbacks_.push_back(callback);
73 if (content_ready_) {
74 // Distillation for this task has already completed, and so it can be
75 // immediately saved.
76 ScheduleSaveCallbacks(true);
80 scoped_ptr<ViewerHandle> TaskTracker::AddViewer(ViewRequestDelegate* delegate) {
81 viewers_.push_back(delegate);
82 if (content_ready_) {
83 // Distillation for this task has already completed, and so the delegate can
84 // be immediately told of the result.
85 base::MessageLoop::current()->PostTask(
86 FROM_HERE,
87 base::Bind(&TaskTracker::NotifyViewer,
88 weak_ptr_factory_.GetWeakPtr(),
89 delegate));
91 return scoped_ptr<ViewerHandle>(new ViewerHandle(base::Bind(
92 &TaskTracker::RemoveViewer, weak_ptr_factory_.GetWeakPtr(), delegate)));
95 const std::string& TaskTracker::GetEntryId() const { return entry_.entry_id(); }
97 bool TaskTracker::HasEntryId(const std::string& entry_id) const {
98 return entry_.entry_id() == entry_id;
101 bool TaskTracker::HasUrl(const GURL& url) const {
102 for (int i = 0; i < entry_.pages_size(); ++i) {
103 if (entry_.pages(i).url() == url.spec()) {
104 return true;
107 return false;
110 void TaskTracker::RemoveViewer(ViewRequestDelegate* delegate) {
111 viewers_.erase(std::remove(viewers_.begin(), viewers_.end(), delegate));
112 if (viewers_.empty()) {
113 MaybeCancel();
117 void TaskTracker::MaybeCancel() {
118 if (!save_callbacks_.empty() || !viewers_.empty()) {
119 // There's still work to be done.
120 return;
123 CancelPendingSources();
125 base::AutoReset<bool> dont_delete_this_in_callback(&destruction_allowed_,
126 false);
127 cancel_callback_.Run(this);
130 void TaskTracker::CancelSaveCallbacks() { ScheduleSaveCallbacks(false); }
132 void TaskTracker::ScheduleSaveCallbacks(bool distillation_succeeded) {
133 base::MessageLoop::current()->PostTask(
134 FROM_HERE,
135 base::Bind(&TaskTracker::DoSaveCallbacks,
136 weak_ptr_factory_.GetWeakPtr(),
137 distillation_succeeded));
140 void TaskTracker::OnDistillerFinished(
141 scoped_ptr<DistilledArticleProto> distilled_article) {
142 if (content_ready_) {
143 return;
146 DistilledArticleReady(distilled_article.Pass());
147 if (content_ready_) {
148 AddDistilledContentToStore(*distilled_article_);
151 // 'distiller_ != null' is used as a signal that distillation is in progress,
152 // so it needs to be released so that we know distillation is done.
153 base::MessageLoop::current()->DeleteSoon(FROM_HERE, distiller_.release());
155 ContentSourceFinished();
158 void TaskTracker::CancelPendingSources() {
159 if (distiller_) {
160 base::MessageLoop::current()->DeleteSoon(FROM_HERE, distiller_.release());
164 void TaskTracker::OnBlobFetched(
165 bool success,
166 scoped_ptr<DistilledArticleProto> distilled_article) {
167 blob_fetcher_running_ = false;
169 if (content_ready_) {
170 return;
173 DistilledArticleReady(distilled_article.Pass());
175 ContentSourceFinished();
178 bool TaskTracker::IsAnySourceRunning() const {
179 return distiller_ || blob_fetcher_running_;
182 void TaskTracker::ContentSourceFinished() {
183 if (content_ready_) {
184 CancelPendingSources();
185 } else if (!IsAnySourceRunning()) {
186 distilled_article_.reset(new DistilledArticleProto());
187 NotifyViewersAndCallbacks();
191 void TaskTracker::DistilledArticleReady(
192 scoped_ptr<DistilledArticleProto> distilled_article) {
193 DCHECK(!content_ready_);
195 if (distilled_article->pages_size() == 0) {
196 return;
199 content_ready_ = true;
201 distilled_article_ = distilled_article.Pass();
202 entry_.set_title(distilled_article_->title());
203 entry_.clear_pages();
204 for (int i = 0; i < distilled_article_->pages_size(); ++i) {
205 sync_pb::ArticlePage* page = entry_.add_pages();
206 page->set_url(distilled_article_->pages(i).url());
209 NotifyViewersAndCallbacks();
212 void TaskTracker::NotifyViewersAndCallbacks() {
213 for (size_t i = 0; i < viewers_.size(); ++i) {
214 NotifyViewer(viewers_[i]);
217 // Already inside a callback run SaveCallbacks directly.
218 DoSaveCallbacks(content_ready_);
221 void TaskTracker::NotifyViewer(ViewRequestDelegate* delegate) {
222 delegate->OnArticleReady(distilled_article_.get());
225 void TaskTracker::DoSaveCallbacks(bool success) {
226 if (!save_callbacks_.empty()) {
227 for (size_t i = 0; i < save_callbacks_.size(); ++i) {
228 DCHECK(!save_callbacks_[i].is_null());
229 save_callbacks_[i].Run(
230 entry_, distilled_article_.get(), success);
233 save_callbacks_.clear();
234 MaybeCancel();
238 void TaskTracker::OnArticleDistillationUpdated(
239 const ArticleDistillationUpdate& article_update) {
240 for (size_t i = 0; i < viewers_.size(); ++i) {
241 viewers_[i]->OnArticleUpdated(article_update);
245 void TaskTracker::AddDistilledContentToStore(
246 const DistilledArticleProto& content) {
247 if (content_store_) {
248 content_store_->SaveContent(
249 entry_, content, DistilledContentStore::SaveCallback());
254 } // namespace dom_distiller