Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(25)

Side by Side Diff: chrome/browser/sync_file_system/drive/local_change_processor_delegate.cc

Issue 14977008: [SyncFileSystem] Separate out ApplyLocalChange from DriveFileSyncService. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: style fix Created 7 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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.
4
5 #include "chrome/browser/sync_file_system/drive/local_change_processor_delegate. h"
6
7 #include "base/bind.h"
8 #include "base/callback.h"
9 #include "chrome/browser/sync_file_system/drive/api_util.h"
10 #include "chrome/browser/sync_file_system/drive_file_sync_service.h"
11 #include "chrome/browser/sync_file_system/drive_metadata_store.h"
12 #include "webkit/fileapi/syncable/syncable_file_system_util.h"
13
14 namespace sync_file_system {
15 namespace drive {
16
17 LocalChangeProcessorDelegate::LocalChangeProcessorDelegate(
18 base::WeakPtr<DriveFileSyncService> sync_service,
19 const FileChange& local_change,
20 const base::FilePath& local_path,
21 const SyncFileMetadata& local_metadata,
22 const fileapi::FileSystemURL& url)
23 : sync_service_(sync_service),
24 url_(url),
25 local_change_(local_change),
26 local_path_(local_path),
27 local_metadata_(local_metadata),
28 has_drive_metadata_(false),
29 has_remote_change_(false),
30 weak_factory_(this) {}
31
32 LocalChangeProcessorDelegate::~LocalChangeProcessorDelegate() {}
33
34 void LocalChangeProcessorDelegate::Run(const SyncStatusCallback& callback) {
35 if (!sync_service_)
36 return;
37
38 // TODO(nhiroki): support directory operations (http://crbug.com/161442).
39 DCHECK(IsSyncDirectoryOperationEnabled() || !local_change_.IsDirectory());
40
41 has_drive_metadata_ =
42 metadata_store()->ReadEntry(url_, &drive_metadata_) == SYNC_STATUS_OK;
43
44 if (!has_drive_metadata_)
45 drive_metadata_.set_md5_checksum(std::string());
46
47 sync_service_->EnsureOriginRootDirectory(
48 url_.origin(),
49 base::Bind(&LocalChangeProcessorDelegate::DidGetOriginRoot,
50 weak_factory_.GetWeakPtr(),
51 callback));
52 }
53
54 void LocalChangeProcessorDelegate::DidGetOriginRoot(
55 const SyncStatusCallback& callback,
56 SyncStatusCode status,
57 const std::string& origin_resource_id) {
58 if (!sync_service_)
59 return;
60
61 if (status != SYNC_STATUS_OK) {
62 callback.Run(status);
63 return;
64 }
65
66 origin_resource_id_ = origin_resource_id;
67
68 has_remote_change_ =
69 remote_change_handler()->GetChangeForURL(url_, &remote_change_);
70 if (has_remote_change_ && drive_metadata_.resource_id().empty())
71 drive_metadata_.set_resource_id(remote_change_.resource_id);
72
73 LocalSyncOperationType operation = LocalSyncOperationResolver::Resolve(
74 local_change_,
75 has_remote_change_ ? &remote_change_.change : NULL,
76 has_drive_metadata_ ? &drive_metadata_ : NULL);
77
78 DVLOG(1) << "ApplyLocalChange for " << url_.DebugString()
79 << " local_change:" << local_change_.DebugString()
80 << " ==> operation:" << operation;
81
82 switch (operation) {
83 case LOCAL_SYNC_OPERATION_ADD_FILE:
84 UploadNewFile(callback);
85 return;
86 case LOCAL_SYNC_OPERATION_ADD_DIRECTORY:
87 CreateDirectory(callback);
88 return;
89 case LOCAL_SYNC_OPERATION_UPDATE_FILE:
90 UploadExistingFile(callback);
91 return;
92 case LOCAL_SYNC_OPERATION_DELETE_FILE:
93 DeleteFile(callback);
94 return;
95 case LOCAL_SYNC_OPERATION_DELETE_DIRECTORY:
96 DeleteDirectory(callback);
97 return;
98 case LOCAL_SYNC_OPERATION_NONE:
99 callback.Run(SYNC_STATUS_OK);
100 return;
101 case LOCAL_SYNC_OPERATION_CONFLICT:
102 HandleConflict(callback);
103 return;
104 case LOCAL_SYNC_OPERATION_RESOLVE_TO_LOCAL:
105 ResolveToLocal(callback);
106 return;
107 case LOCAL_SYNC_OPERATION_RESOLVE_TO_REMOTE:
108 ResolveToRemote(callback);
109 return;
110 case LOCAL_SYNC_OPERATION_DELETE_METADATA:
111 DeleteMetadata(base::Bind(
112 &LocalChangeProcessorDelegate::DidApplyLocalChange,
113 weak_factory_.GetWeakPtr(), callback, google_apis::HTTP_SUCCESS));
114 return;
115 case LOCAL_SYNC_OPERATION_FAIL: {
116 callback.Run(SYNC_STATUS_FAILED);
117 return;
118 }
119 }
120 NOTREACHED();
121 callback.Run(SYNC_STATUS_FAILED);
122 }
123
124 void LocalChangeProcessorDelegate::UploadNewFile(
125 const SyncStatusCallback& callback) {
126 if (!sync_service_)
127 return;
128
129 api_util()->UploadNewFile(
130 origin_resource_id_,
131 local_path_,
132 DriveFileSyncService::PathToTitle(url_.path()),
133 base::Bind(&LocalChangeProcessorDelegate::DidUploadNewFile,
134 weak_factory_.GetWeakPtr(), callback));
135 }
136
137 void LocalChangeProcessorDelegate::DidUploadNewFile(
138 const SyncStatusCallback& callback,
139 google_apis::GDataErrorCode error,
140 const std::string& resource_id,
141 const std::string& md5) {
142 if (!sync_service_)
143 return;
144
145 switch (error) {
146 case google_apis::HTTP_CREATED:
147 UpdateMetadata(
148 resource_id, md5, DriveMetadata::RESOURCE_TYPE_FILE,
149 base::Bind(&LocalChangeProcessorDelegate::DidApplyLocalChange,
150 weak_factory_.GetWeakPtr(), callback, error));
151 sync_service_->NotifyObserversFileStatusChanged(
152 url_,
153 SYNC_FILE_STATUS_SYNCED,
154 SYNC_ACTION_ADDED,
155 SYNC_DIRECTION_LOCAL_TO_REMOTE);
156 return;
157 case google_apis::HTTP_CONFLICT:
158 HandleCreationConflict(resource_id, DriveMetadata::RESOURCE_TYPE_FILE,
159 callback);
160 return;
161 default:
162 callback.Run(GDataErrorCodeToSyncStatusCodeWrapper(error));
163 }
164 }
165
166 void LocalChangeProcessorDelegate::CreateDirectory(
167 const SyncStatusCallback& callback) {
168 if (!sync_service_)
169 return;
170
171 DCHECK(IsSyncDirectoryOperationEnabled());
172 api_util()->CreateDirectory(
173 origin_resource_id_,
174 DriveFileSyncService::PathToTitle(url_.path()),
175 base::Bind(&LocalChangeProcessorDelegate::DidCreateDirectory,
176 weak_factory_.GetWeakPtr(), callback));
177 }
178
179 void LocalChangeProcessorDelegate::DidCreateDirectory(
180 const SyncStatusCallback& callback,
181 google_apis::GDataErrorCode error,
182 const std::string& resource_id) {
183 if (!sync_service_)
184 return;
185
186 switch (error) {
187 case google_apis::HTTP_SUCCESS:
188 case google_apis::HTTP_CREATED: {
189 UpdateMetadata(
190 resource_id, std::string(), DriveMetadata::RESOURCE_TYPE_FOLDER,
191 base::Bind(&LocalChangeProcessorDelegate::DidApplyLocalChange,
192 weak_factory_.GetWeakPtr(), callback, error));
193 sync_service_->NotifyObserversFileStatusChanged(
194 url_,
195 SYNC_FILE_STATUS_SYNCED,
196 SYNC_ACTION_ADDED,
197 SYNC_DIRECTION_LOCAL_TO_REMOTE);
198 return;
199 }
200
201 case google_apis::HTTP_CONFLICT:
202 // There were conflicts and a file was left.
203 // TODO(kinuko): Handle the latter case (http://crbug.com/237090).
204 // Fall-through
205
206 default:
207 callback.Run(GDataErrorCodeToSyncStatusCodeWrapper(error));
208 }
209 }
210
211 void LocalChangeProcessorDelegate::UploadExistingFile(
212 const SyncStatusCallback& callback) {
213 if (!sync_service_)
214 return;
215
216 DCHECK(has_drive_metadata_);
217 api_util()->UploadExistingFile(
218 drive_metadata_.resource_id(),
219 drive_metadata_.md5_checksum(),
220 local_path_,
221 base::Bind(&LocalChangeProcessorDelegate::DidUploadExistingFile,
222 weak_factory_.GetWeakPtr(), callback));
223 }
224
225 void LocalChangeProcessorDelegate::DidUploadExistingFile(
226 const SyncStatusCallback& callback,
227 google_apis::GDataErrorCode error,
228 const std::string& resource_id,
229 const std::string& md5) {
230 if (!sync_service_)
231 return;
232
233 DCHECK(has_drive_metadata_);
234 switch (error) {
235 case google_apis::HTTP_SUCCESS:
236 UpdateMetadata(
237 resource_id, md5, DriveMetadata::RESOURCE_TYPE_FILE,
238 base::Bind(&LocalChangeProcessorDelegate::DidApplyLocalChange,
239 weak_factory_.GetWeakPtr(), callback, error));
240 sync_service_->NotifyObserversFileStatusChanged(
241 url_,
242 SYNC_FILE_STATUS_SYNCED,
243 SYNC_ACTION_UPDATED,
244 SYNC_DIRECTION_LOCAL_TO_REMOTE);
245 return;
246 case google_apis::HTTP_CONFLICT: {
247 HandleConflict(callback);
248 return;
249 }
250 case google_apis::HTTP_NOT_MODIFIED: {
251 DidApplyLocalChange(callback,
252 google_apis::HTTP_SUCCESS, SYNC_STATUS_OK);
253 return;
254 }
255 case google_apis::HTTP_NOT_FOUND: {
256 UploadNewFile(callback);
257 return;
258 }
259 default: {
260 const SyncStatusCode status =
261 GDataErrorCodeToSyncStatusCodeWrapper(error);
262 DCHECK_NE(SYNC_STATUS_OK, status);
263 callback.Run(status);
264 return;
265 }
266 }
267 }
268
269 void LocalChangeProcessorDelegate::DeleteFile(
270 const SyncStatusCallback& callback) {
271 if (!sync_service_)
272 return;
273
274 DCHECK(has_drive_metadata_);
275 api_util()->DeleteFile(
276 drive_metadata_.resource_id(),
277 drive_metadata_.md5_checksum(),
278 base::Bind(&LocalChangeProcessorDelegate::DidDeleteFile,
279 weak_factory_.GetWeakPtr(), callback));
280 }
281
282 void LocalChangeProcessorDelegate::DeleteDirectory(
283 const SyncStatusCallback& callback) {
284 if (!sync_service_)
285 return;
286
287 DCHECK(IsSyncDirectoryOperationEnabled());
288 DCHECK(has_drive_metadata_);
289 // This does not handle recursive directory deletion
290 // (which should not happen other than after a restart).
291 api_util()->DeleteFile(
292 drive_metadata_.resource_id(),
293 std::string(), // empty md5
294 base::Bind(&LocalChangeProcessorDelegate::DidDeleteFile,
295 weak_factory_.GetWeakPtr(), callback));
296 }
297
298 void LocalChangeProcessorDelegate::DidDeleteFile(
299 const SyncStatusCallback& callback,
300 google_apis::GDataErrorCode error) {
301 if (!sync_service_)
302 return;
303
304 DCHECK(has_drive_metadata_);
305
306 switch (error) {
307 // Regardless of whether the deletion has succeeded (HTTP_SUCCESS) or
308 // has failed with ETag conflict error (HTTP_PRECONDITION or HTTP_CONFLICT)
309 // we should just delete the drive_metadata.
310 // In the former case the file should be just gone now, and
311 // in the latter case the remote change will be applied in a future
312 // remote sync.
313 case google_apis::HTTP_SUCCESS:
314 case google_apis::HTTP_PRECONDITION:
315 case google_apis::HTTP_CONFLICT:
316 DeleteMetadata(base::Bind(
317 &LocalChangeProcessorDelegate::DidApplyLocalChange,
318 weak_factory_.GetWeakPtr(), callback, error));
319 sync_service_->NotifyObserversFileStatusChanged(
320 url_,
321 SYNC_FILE_STATUS_SYNCED,
322 SYNC_ACTION_DELETED,
323 SYNC_DIRECTION_LOCAL_TO_REMOTE);
324 return;
325 case google_apis::HTTP_NOT_FOUND:
326 DidApplyLocalChange(callback,
327 google_apis::HTTP_SUCCESS, SYNC_STATUS_OK);
328 return;
329 default: {
330 const SyncStatusCode status =
331 GDataErrorCodeToSyncStatusCodeWrapper(error);
332 DCHECK_NE(SYNC_STATUS_OK, status);
333 callback.Run(status);
334 return;
335 }
336 }
337 }
338
339 void LocalChangeProcessorDelegate::ResolveToLocal(
340 const SyncStatusCallback& callback) {
341 if (!sync_service_)
342 return;
343
344 api_util()->DeleteFile(
345 drive_metadata_.resource_id(),
346 drive_metadata_.md5_checksum(),
347 base::Bind(
348 &LocalChangeProcessorDelegate::DidDeleteFileToResolveToLocal,
349 weak_factory_.GetWeakPtr(), callback));
350 }
351
352 void LocalChangeProcessorDelegate::DidDeleteFileToResolveToLocal(
353 const SyncStatusCallback& callback,
354 google_apis::GDataErrorCode error) {
355 if (!sync_service_)
356 return;
357
358 if (error != google_apis::HTTP_SUCCESS &&
359 error != google_apis::HTTP_NOT_FOUND) {
360 remote_change_handler()->RemoveChangeForURL(url_);
361 callback.Run(GDataErrorCodeToSyncStatusCodeWrapper(error));
362 return;
363 }
364
365 DCHECK_NE(SYNC_FILE_TYPE_UNKNOWN, local_metadata_.file_type);
366 if (local_metadata_.file_type == SYNC_FILE_TYPE_FILE) {
367 UploadNewFile(callback);
368 return;
369 }
370
371 DCHECK(IsSyncDirectoryOperationEnabled());
372 DCHECK_EQ(SYNC_FILE_TYPE_DIRECTORY, local_metadata_.file_type);
373 CreateDirectory(callback);
374 }
375
376 void LocalChangeProcessorDelegate::ResolveToRemote(
377 const SyncStatusCallback& callback) {
378 if (!sync_service_)
379 return;
380
381 // Mark the file as to-be-fetched.
382 DCHECK(!drive_metadata_.resource_id().empty());
383
384 SyncFileType type = remote_change_.change.file_type();
385 SetMetadataToBeFetched(
386 DriveFileSyncService::SyncFileTypeToDriveMetadataResourceType(type),
387 base::Bind(&LocalChangeProcessorDelegate::DidResolveToRemote,
388 weak_factory_.GetWeakPtr(), callback));
389 // The synced notification will be dispatched when the remote file is
390 // downloaded.
391 }
392
393 void LocalChangeProcessorDelegate::DidResolveToRemote(
394 const SyncStatusCallback& callback,
395 SyncStatusCode status) {
396 if (!sync_service_)
397 return;
398
399 DCHECK(has_drive_metadata_);
400 if (status != SYNC_STATUS_OK) {
401 callback.Run(status);
402 return;
403 }
404
405 SyncFileType file_type = SYNC_FILE_TYPE_FILE;
406 if (drive_metadata_.type() == DriveMetadata::RESOURCE_TYPE_FOLDER)
407 file_type = SYNC_FILE_TYPE_DIRECTORY;
408 sync_service_->AppendFetchChange(
409 url_.origin(), url_.path(), drive_metadata_.resource_id(), file_type);
410 callback.Run(status);
411 }
412
413 void LocalChangeProcessorDelegate::DidApplyLocalChange(
414 const SyncStatusCallback& callback,
415 const google_apis::GDataErrorCode error,
416 SyncStatusCode status) {
417 if (!sync_service_)
418 return;
419
420 if (status == SYNC_STATUS_OK) {
421 remote_change_handler()->RemoveChangeForURL(url_);
422 status = GDataErrorCodeToSyncStatusCodeWrapper(error);
423 }
424 callback.Run(status);
425 }
426
427 void LocalChangeProcessorDelegate::UpdateMetadata(
428 const std::string& resource_id,
429 const std::string& md5,
430 DriveMetadata::ResourceType type,
431 const SyncStatusCallback& callback) {
432 if (!sync_service_)
433 return;
434
435 drive_metadata_.set_resource_id(resource_id);
436 drive_metadata_.set_md5_checksum(md5);
437 drive_metadata_.set_conflicted(false);
438 drive_metadata_.set_to_be_fetched(false);
439 drive_metadata_.set_type(type);
440 metadata_store()->UpdateEntry(url_, drive_metadata_, callback);
441 }
442
443 void LocalChangeProcessorDelegate::ResetMetadataMD5(
444 const SyncStatusCallback& callback) {
445 if (!sync_service_)
446 return;
447
448 drive_metadata_.set_md5_checksum(std::string());
449 metadata_store()->UpdateEntry(url_, drive_metadata_, callback);
450 }
451
452 void LocalChangeProcessorDelegate::SetMetadataToBeFetched(
453 DriveMetadata::ResourceType type,
454 const SyncStatusCallback& callback) {
455 if (!sync_service_)
456 return;
457
458 drive_metadata_.set_md5_checksum(std::string());
459 drive_metadata_.set_conflicted(false);
460 drive_metadata_.set_to_be_fetched(true);
461 drive_metadata_.set_type(type);
462 metadata_store()->UpdateEntry(url_, drive_metadata_, callback);
463 }
464
465 void LocalChangeProcessorDelegate::SetMetadataConflict(
466 const SyncStatusCallback& callback) {
467 if (!sync_service_)
468 return;
469
470 drive_metadata_.set_conflicted(true);
471 drive_metadata_.set_to_be_fetched(false);
472 metadata_store()->UpdateEntry(url_, drive_metadata_, callback);
473 }
474
475 void LocalChangeProcessorDelegate::DeleteMetadata(
476 const SyncStatusCallback& callback) {
477 metadata_store()->DeleteEntry(url_, callback);
478 }
479
480 void LocalChangeProcessorDelegate::HandleCreationConflict(
481 const std::string& resource_id,
482 DriveMetadata::ResourceType type,
483 const SyncStatusCallback& callback) {
484 if (!sync_service_)
485 return;
486
487 // File-file conflict is found.
488 // Populates a fake drive_metadata and set has_drive_metadata = true.
489 // In HandleConflictLocalSync:
490 // - If conflict_resolution is manual, we'll change conflicted to true
491 // and save the metadata.
492 // - Otherwise we'll save the metadata with empty md5 and will start
493 // over local sync as UploadExistingFile.
494 drive_metadata_.set_resource_id(resource_id);
495 drive_metadata_.set_md5_checksum(std::string());
496 drive_metadata_.set_conflicted(false);
497 drive_metadata_.set_to_be_fetched(false);
498 drive_metadata_.set_type(type);
499 has_drive_metadata_ = true;
500 HandleConflict(callback);
501 }
502
503 void LocalChangeProcessorDelegate::HandleConflict(
504 const SyncStatusCallback& callback) {
505 if (!sync_service_)
506 return;
507
508 DCHECK(!drive_metadata_.resource_id().empty());
509 api_util()->GetResourceEntry(
510 drive_metadata_.resource_id(),
511 base::Bind(
512 &LocalChangeProcessorDelegate::DidGetEntryForConflictResolution,
513 weak_factory_.GetWeakPtr(), callback));
514 }
515
516 void LocalChangeProcessorDelegate::DidGetEntryForConflictResolution(
517 const SyncStatusCallback& callback,
518 google_apis::GDataErrorCode error,
519 scoped_ptr<google_apis::ResourceEntry> entry) {
520 if (!sync_service_)
521 return;
522
523 SyncFileType local_file_type = local_metadata_.file_type;
524 base::Time local_modification_time = local_metadata_.last_modified;
525
526 SyncFileType remote_file_type;
527 base::Time remote_modification_time = entry->updated_time();
528 if (entry->is_file())
529 remote_file_type = SYNC_FILE_TYPE_FILE;
530 else if (entry->is_folder())
531 remote_file_type = SYNC_FILE_TYPE_DIRECTORY;
532 else
533 remote_file_type = SYNC_FILE_TYPE_UNKNOWN;
534
535 DriveFileSyncService::ConflictResolutionResult resolution =
536 sync_service_->ResolveConflictForLocalSync(
537 local_file_type, local_modification_time,
538 remote_file_type, remote_modification_time);
539 switch (resolution) {
540 case DriveFileSyncService::CONFLICT_RESOLUTION_MARK_CONFLICT:
541 HandleManualResolutionCase(callback);
542 return;
543 case DriveFileSyncService::CONFLICT_RESOLUTION_LOCAL_WIN:
544 HandleLocalWinCase(callback);
545 return;
546 case DriveFileSyncService::CONFLICT_RESOLUTION_REMOTE_WIN:
547 HandleRemoteWinCase(callback);
548 return;
549 }
550 NOTREACHED();
551 callback.Run(SYNC_STATUS_FAILED);
552 }
553
554 void LocalChangeProcessorDelegate::HandleManualResolutionCase(
555 const SyncStatusCallback& callback) {
556 if (drive_metadata_.conflicted()) {
557 callback.Run(SYNC_STATUS_HAS_CONFLICT);
558 return;
559 }
560
561 SetMetadataConflict(
562 base::Bind(&LocalChangeProcessorDelegate::DidApplyLocalChange,
563 weak_factory_.GetWeakPtr(), callback,
564 google_apis::HTTP_CONFLICT));
565 }
566
567 void LocalChangeProcessorDelegate::HandleLocalWinCase(
568 const SyncStatusCallback& callback) {
569 DVLOG(1) << "Resolving conflict for local sync:"
570 << url_.DebugString() << ": LOCAL WIN";
571
572 DCHECK(!drive_metadata_.resource_id().empty());
573 if (!has_drive_metadata_) {
574 StartOver(callback, SYNC_STATUS_OK);
575 return;
576 }
577
578 ResetMetadataMD5(base::Bind(&LocalChangeProcessorDelegate::StartOver,
579 weak_factory_.GetWeakPtr(), callback));
580 }
581
582 void LocalChangeProcessorDelegate::HandleRemoteWinCase(
583 const SyncStatusCallback& callback) {
584 DVLOG(1) << "Resolving conflict for local sync:"
585 << url_.DebugString() << ": REMOTE WIN";
586 ResolveToRemote(callback);
587 }
588
589 void LocalChangeProcessorDelegate::StartOver(const SyncStatusCallback& callback,
590 SyncStatusCode status) {
591 if (status != SYNC_STATUS_OK) {
592 callback.Run(status);
593 return;
594 }
595
596 remote_change_handler()->RemoveChangeForURL(url_);
597 Run(callback);
598 }
599
600 SyncStatusCode
601 LocalChangeProcessorDelegate::GDataErrorCodeToSyncStatusCodeWrapper(
602 google_apis::GDataErrorCode error) {
603 return sync_service_->GDataErrorCodeToSyncStatusCodeWrapper(error);
604 }
605
606 DriveMetadataStore* LocalChangeProcessorDelegate::metadata_store() {
607 return sync_service_->metadata_store_.get();
608 }
609
610 APIUtilInterface* LocalChangeProcessorDelegate::api_util() {
611 return sync_service_->api_util_.get();
612 }
613
614 RemoteChangeHandler* LocalChangeProcessorDelegate::remote_change_handler() {
615 return &sync_service_->remote_change_handler_;
616 }
617
618 } // namespace drive
619 } // namespace sync_file_system
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698