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_backend/register_app_task.h" 6 7 #include "base/bind.h" 8 #include "base/location.h" 9 #include "chrome/browser/drive/drive_api_util.h" 10 #include "chrome/browser/drive/drive_service_interface.h" 11 #include "chrome/browser/sync_file_system/drive_backend/drive_backend_constants.h" 12 #include "chrome/browser/sync_file_system/drive_backend/folder_creator.h" 13 #include "chrome/browser/sync_file_system/drive_backend/metadata_database.h" 14 #include "chrome/browser/sync_file_system/drive_backend/metadata_database.pb.h" 15 #include "chrome/browser/sync_file_system/drive_backend/sync_engine_context.h" 16 #include "chrome/browser/sync_file_system/drive_backend/tracker_id_set.h" 17 #include "chrome/browser/sync_file_system/syncable_file_system_util.h" 18 #include "google_apis/drive/drive_api_parser.h" 19 #include "google_apis/drive/gdata_wapi_parser.h" 20 21 namespace sync_file_system { 22 namespace drive_backend { 23 24 namespace { 25 26 bool CompareOnCTime(const FileTracker& left, 27 const FileTracker& right) { 28 return left.synced_details().creation_time() < 29 right.synced_details().creation_time(); 30 } 31 32 } // namespace 33 34 RegisterAppTask::RegisterAppTask(SyncEngineContext* sync_context, 35 const std::string& app_id) 36 : sync_context_(sync_context), 37 create_folder_retry_count_(0), 38 app_id_(app_id), 39 weak_ptr_factory_(this) { 40 } 41 42 RegisterAppTask::~RegisterAppTask() { 43 } 44 45 bool RegisterAppTask::CanFinishImmediately() { 46 return metadata_database() && 47 metadata_database()->FindAppRootTracker(app_id_, NULL); 48 } 49 50 void RegisterAppTask::RunExclusive(const SyncStatusCallback& callback) { 51 if (create_folder_retry_count_++ >= kMaxRetry) { 52 callback.Run(SYNC_STATUS_FAILED); 53 return; 54 } 55 56 if (!metadata_database() || !drive_service()) { 57 callback.Run(SYNC_STATUS_FAILED); 58 return; 59 } 60 61 int64 sync_root = metadata_database()->GetSyncRootTrackerID(); 62 TrackerIDSet trackers; 63 if (!metadata_database()->FindTrackersByParentAndTitle( 64 sync_root, app_id_, &trackers)) { 65 CreateAppRootFolder(callback); 66 return; 67 } 68 69 FileTracker candidate; 70 if (!FilterCandidates(trackers, &candidate)) { 71 CreateAppRootFolder(callback); 72 return; 73 } 74 75 if (candidate.active()) { 76 DCHECK(candidate.tracker_kind() == TRACKER_KIND_APP_ROOT || 77 candidate.tracker_kind() == TRACKER_KIND_DISABLED_APP_ROOT); 78 callback.Run(SYNC_STATUS_OK); 79 return; 80 } 81 82 RegisterAppIntoDatabase(candidate, callback); 83 } 84 85 void RegisterAppTask::CreateAppRootFolder(const SyncStatusCallback& callback) { 86 int64 sync_root_tracker_id = metadata_database()->GetSyncRootTrackerID(); 87 FileTracker sync_root_tracker; 88 bool should_success = metadata_database()->FindTrackerByTrackerID( 89 sync_root_tracker_id, 90 &sync_root_tracker); 91 DCHECK(should_success); 92 93 DCHECK(!folder_creator_); 94 folder_creator_.reset(new FolderCreator( 95 drive_service(), metadata_database(), 96 sync_root_tracker.file_id(), app_id_)); 97 folder_creator_->Run(base::Bind( 98 &RegisterAppTask::DidCreateAppRootFolder, 99 weak_ptr_factory_.GetWeakPtr(), callback)); 100 } 101 102 void RegisterAppTask::DidCreateAppRootFolder( 103 const SyncStatusCallback& callback, 104 const std::string& folder_id, 105 SyncStatusCode status) { 106 scoped_ptr<FolderCreator> deleter = folder_creator_.Pass(); 107 if (status != SYNC_STATUS_OK) { 108 callback.Run(status); 109 return; 110 } 111 112 RunExclusive(callback); 113 } 114 115 bool RegisterAppTask::FilterCandidates(const TrackerIDSet& trackers, 116 FileTracker* candidate) { 117 DCHECK(candidate); 118 if (trackers.has_active()) { 119 if (metadata_database()->FindTrackerByTrackerID( 120 trackers.active_tracker(), candidate)) { 121 return true; 122 } 123 NOTREACHED(); 124 } 125 126 scoped_ptr<FileTracker> oldest_tracker; 127 for (TrackerIDSet::const_iterator itr = trackers.begin(); 128 itr != trackers.end(); ++itr) { 129 scoped_ptr<FileTracker> tracker(new FileTracker); 130 if (!metadata_database()->FindTrackerByTrackerID( 131 *itr, tracker.get())) { 132 NOTREACHED(); 133 continue; 134 } 135 136 FileMetadata file; 137 DCHECK(!tracker->active()); 138 DCHECK(tracker->has_synced_details()); 139 140 if (!metadata_database()->FindFileByFileID(tracker->file_id(), &file)) { 141 NOTREACHED(); 142 // The parent folder is sync-root, whose contents are fetched in 143 // initialization sequence. 144 // So at this point, direct children of sync-root should have 145 // FileMetadata. 146 continue; 147 } 148 149 if (file.details().file_kind() != FILE_KIND_FOLDER) 150 continue; 151 152 if (file.details().missing()) 153 continue; 154 155 if (oldest_tracker && CompareOnCTime(*oldest_tracker, *tracker)) 156 continue; 157 158 oldest_tracker = tracker.Pass(); 159 } 160 161 if (!oldest_tracker) 162 return false; 163 164 *candidate = *oldest_tracker; 165 return true; 166 } 167 168 void RegisterAppTask::RegisterAppIntoDatabase( 169 const FileTracker& tracker, 170 const SyncStatusCallback& callback) { 171 metadata_database()->RegisterApp( 172 app_id_, tracker.file_id(), callback); 173 } 174 175 MetadataDatabase* RegisterAppTask::metadata_database() { 176 return sync_context_->GetMetadataDatabase(); 177 } 178 179 drive::DriveServiceInterface* RegisterAppTask::drive_service() { 180 return sync_context_->GetDriveService(); 181 } 182 183 } // namespace drive_backend 184 } // namespace sync_file_system 185