Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / sync / internal_api / attachments / attachment_service_impl.cc
blob61fb1c663c9af0eae41eb681d173238a8601fefd
1 // Copyright 2014 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 "sync/internal_api/public/attachments/attachment_service_impl.h"
7 #include "base/bind.h"
8 #include "base/message_loop/message_loop.h"
9 #include "base/thread_task_runner_handle.h"
10 #include "sync/api/attachments/attachment.h"
11 #include "sync/api/attachments/fake_attachment_store.h"
12 #include "sync/internal_api/public/attachments/fake_attachment_downloader.h"
13 #include "sync/internal_api/public/attachments/fake_attachment_uploader.h"
15 namespace syncer {
17 // GetOrDownloadAttachments starts multiple parallel DownloadAttachment calls.
18 // GetOrDownloadState tracks completion of these calls and posts callback for
19 // consumer once all attachments are either retrieved or reported unavailable.
20 class AttachmentServiceImpl::GetOrDownloadState
21 : public base::RefCounted<GetOrDownloadState>,
22 public base::NonThreadSafe {
23 public:
24 // GetOrDownloadState gets parameter from values passed to
25 // AttachmentService::GetOrDownloadAttachments.
26 // |attachment_ids| is a list of attachmens to retrieve.
27 // |callback| will be posted on current thread when all attachments retrieved
28 // or confirmed unavailable.
29 GetOrDownloadState(const AttachmentIdList& attachment_ids,
30 const GetOrDownloadCallback& callback);
32 // Attachment was just retrieved. Add it to retrieved attachments.
33 void AddAttachment(const Attachment& attachment);
35 // Both reading from local store and downloading attachment failed.
36 // Add it to unavailable set.
37 void AddUnavailableAttachmentId(const AttachmentId& attachment_id);
39 private:
40 friend class base::RefCounted<GetOrDownloadState>;
41 virtual ~GetOrDownloadState();
43 // If all attachment requests completed then post callback to consumer with
44 // results.
45 void PostResultIfAllRequestsCompleted();
47 GetOrDownloadCallback callback_;
49 // Requests for these attachments are still in progress.
50 AttachmentIdSet in_progress_attachments_;
52 AttachmentIdSet unavailable_attachments_;
53 scoped_ptr<AttachmentMap> retrieved_attachments_;
55 DISALLOW_COPY_AND_ASSIGN(GetOrDownloadState);
58 AttachmentServiceImpl::GetOrDownloadState::GetOrDownloadState(
59 const AttachmentIdList& attachment_ids,
60 const GetOrDownloadCallback& callback)
61 : callback_(callback), retrieved_attachments_(new AttachmentMap()) {
62 std::copy(
63 attachment_ids.begin(),
64 attachment_ids.end(),
65 std::inserter(in_progress_attachments_, in_progress_attachments_.end()));
66 PostResultIfAllRequestsCompleted();
69 AttachmentServiceImpl::GetOrDownloadState::~GetOrDownloadState() {
70 DCHECK(CalledOnValidThread());
73 void AttachmentServiceImpl::GetOrDownloadState::AddAttachment(
74 const Attachment& attachment) {
75 DCHECK(CalledOnValidThread());
76 DCHECK(retrieved_attachments_->find(attachment.GetId()) ==
77 retrieved_attachments_->end());
78 retrieved_attachments_->insert(
79 std::make_pair(attachment.GetId(), attachment));
80 DCHECK(in_progress_attachments_.find(attachment.GetId()) !=
81 in_progress_attachments_.end());
82 in_progress_attachments_.erase(attachment.GetId());
83 PostResultIfAllRequestsCompleted();
86 void AttachmentServiceImpl::GetOrDownloadState::AddUnavailableAttachmentId(
87 const AttachmentId& attachment_id) {
88 DCHECK(CalledOnValidThread());
89 DCHECK(unavailable_attachments_.find(attachment_id) ==
90 unavailable_attachments_.end());
91 unavailable_attachments_.insert(attachment_id);
92 DCHECK(in_progress_attachments_.find(attachment_id) !=
93 in_progress_attachments_.end());
94 in_progress_attachments_.erase(attachment_id);
95 PostResultIfAllRequestsCompleted();
98 void
99 AttachmentServiceImpl::GetOrDownloadState::PostResultIfAllRequestsCompleted() {
100 if (in_progress_attachments_.empty()) {
101 // All requests completed. Let's notify consumer.
102 GetOrDownloadResult result =
103 unavailable_attachments_.empty() ? GET_SUCCESS : GET_UNSPECIFIED_ERROR;
104 base::MessageLoop::current()->PostTask(
105 FROM_HERE,
106 base::Bind(callback_, result, base::Passed(&retrieved_attachments_)));
110 AttachmentServiceImpl::AttachmentServiceImpl(
111 scoped_ptr<AttachmentStore> attachment_store,
112 scoped_ptr<AttachmentUploader> attachment_uploader,
113 scoped_ptr<AttachmentDownloader> attachment_downloader,
114 Delegate* delegate)
115 : attachment_store_(attachment_store.Pass()),
116 attachment_uploader_(attachment_uploader.Pass()),
117 attachment_downloader_(attachment_downloader.Pass()),
118 delegate_(delegate),
119 weak_ptr_factory_(this) {
120 DCHECK(CalledOnValidThread());
121 DCHECK(attachment_store_);
124 AttachmentServiceImpl::~AttachmentServiceImpl() {
125 DCHECK(CalledOnValidThread());
128 // Static.
129 scoped_ptr<syncer::AttachmentService> AttachmentServiceImpl::CreateForTest() {
130 scoped_ptr<syncer::AttachmentStore> attachment_store(
131 new syncer::FakeAttachmentStore(base::ThreadTaskRunnerHandle::Get()));
132 scoped_ptr<AttachmentUploader> attachment_uploader(
133 new FakeAttachmentUploader);
134 scoped_ptr<AttachmentDownloader> attachment_downloader(
135 new FakeAttachmentDownloader());
136 scoped_ptr<syncer::AttachmentService> attachment_service(
137 new syncer::AttachmentServiceImpl(attachment_store.Pass(),
138 attachment_uploader.Pass(),
139 attachment_downloader.Pass(),
140 NULL));
141 return attachment_service.Pass();
144 void AttachmentServiceImpl::GetOrDownloadAttachments(
145 const AttachmentIdList& attachment_ids,
146 const GetOrDownloadCallback& callback) {
147 DCHECK(CalledOnValidThread());
148 scoped_refptr<GetOrDownloadState> state(
149 new GetOrDownloadState(attachment_ids, callback));
150 attachment_store_->Read(attachment_ids,
151 base::Bind(&AttachmentServiceImpl::ReadDone,
152 weak_ptr_factory_.GetWeakPtr(),
153 state));
156 void AttachmentServiceImpl::DropAttachments(
157 const AttachmentIdList& attachment_ids,
158 const DropCallback& callback) {
159 DCHECK(CalledOnValidThread());
160 attachment_store_->Drop(attachment_ids,
161 base::Bind(&AttachmentServiceImpl::DropDone,
162 weak_ptr_factory_.GetWeakPtr(),
163 callback));
166 void AttachmentServiceImpl::StoreAttachments(const AttachmentList& attachments,
167 const StoreCallback& callback) {
168 DCHECK(CalledOnValidThread());
169 attachment_store_->Write(attachments,
170 base::Bind(&AttachmentServiceImpl::WriteDone,
171 weak_ptr_factory_.GetWeakPtr(),
172 callback));
173 if (attachment_uploader_.get()) {
174 for (AttachmentList::const_iterator iter = attachments.begin();
175 iter != attachments.end();
176 ++iter) {
177 attachment_uploader_->UploadAttachment(
178 *iter,
179 base::Bind(&AttachmentServiceImpl::UploadDone,
180 weak_ptr_factory_.GetWeakPtr()));
185 void AttachmentServiceImpl::ReadDone(
186 const scoped_refptr<GetOrDownloadState>& state,
187 const AttachmentStore::Result& result,
188 scoped_ptr<AttachmentMap> attachments,
189 scoped_ptr<AttachmentIdList> unavailable_attachment_ids) {
190 // Add read attachments to result.
191 for (AttachmentMap::const_iterator iter = attachments->begin();
192 iter != attachments->end();
193 ++iter) {
194 state->AddAttachment(iter->second);
197 AttachmentIdList::const_iterator iter = unavailable_attachment_ids->begin();
198 AttachmentIdList::const_iterator end = unavailable_attachment_ids->end();
199 if (attachment_downloader_.get()) {
200 // Try to download locally unavailable attachments.
201 for (; iter != end; ++iter) {
202 attachment_downloader_->DownloadAttachment(
203 *iter,
204 base::Bind(&AttachmentServiceImpl::DownloadDone,
205 weak_ptr_factory_.GetWeakPtr(),
206 state,
207 *iter));
209 } else {
210 // No downloader so all locally unavailable attachments are unavailable.
211 for (; iter != end; ++iter) {
212 state->AddUnavailableAttachmentId(*iter);
217 void AttachmentServiceImpl::DropDone(const DropCallback& callback,
218 const AttachmentStore::Result& result) {
219 AttachmentService::DropResult drop_result =
220 AttachmentService::DROP_UNSPECIFIED_ERROR;
221 if (result == AttachmentStore::SUCCESS) {
222 drop_result = AttachmentService::DROP_SUCCESS;
224 // TODO(maniscalco): Deal with case where an error occurred (bug 361251).
225 base::MessageLoop::current()->PostTask(FROM_HERE,
226 base::Bind(callback, drop_result));
229 void AttachmentServiceImpl::WriteDone(const StoreCallback& callback,
230 const AttachmentStore::Result& result) {
231 AttachmentService::StoreResult store_result =
232 AttachmentService::STORE_UNSPECIFIED_ERROR;
233 if (result == AttachmentStore::SUCCESS) {
234 store_result = AttachmentService::STORE_SUCCESS;
236 // TODO(maniscalco): Deal with case where an error occurred (bug 361251).
237 base::MessageLoop::current()->PostTask(FROM_HERE,
238 base::Bind(callback, store_result));
241 void AttachmentServiceImpl::UploadDone(
242 const AttachmentUploader::UploadResult& result,
243 const AttachmentId& attachment_id) {
244 // TODO(pavely): crbug/372622: Deal with UploadAttachment failures.
245 if (result != AttachmentUploader::UPLOAD_SUCCESS)
246 return;
247 if (delegate_) {
248 delegate_->OnAttachmentUploaded(attachment_id);
252 void AttachmentServiceImpl::DownloadDone(
253 const scoped_refptr<GetOrDownloadState>& state,
254 const AttachmentId& attachment_id,
255 const AttachmentDownloader::DownloadResult& result,
256 scoped_ptr<Attachment> attachment) {
257 if (result == AttachmentDownloader::DOWNLOAD_SUCCESS) {
258 state->AddAttachment(*attachment.get());
259 } else {
260 state->AddUnavailableAttachmentId(attachment_id);
264 } // namespace syncer