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"
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"
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
{
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
);
40 friend class base::RefCounted
<GetOrDownloadState
>;
41 virtual ~GetOrDownloadState();
43 // If all attachment requests completed then post callback to consumer with
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()) {
63 attachment_ids
.begin(),
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();
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(
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
,
115 : attachment_store_(attachment_store
.Pass()),
116 attachment_uploader_(attachment_uploader
.Pass()),
117 attachment_downloader_(attachment_downloader
.Pass()),
119 weak_ptr_factory_(this) {
120 DCHECK(CalledOnValidThread());
121 DCHECK(attachment_store_
);
124 AttachmentServiceImpl::~AttachmentServiceImpl() {
125 DCHECK(CalledOnValidThread());
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(),
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(),
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(),
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(),
173 if (attachment_uploader_
.get()) {
174 for (AttachmentList::const_iterator iter
= attachments
.begin();
175 iter
!= attachments
.end();
177 attachment_uploader_
->UploadAttachment(
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();
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(
204 base::Bind(&AttachmentServiceImpl::DownloadDone
,
205 weak_ptr_factory_
.GetWeakPtr(),
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
)
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());
260 state
->AddUnavailableAttachmentId(attachment_id
);
264 } // namespace syncer