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 "chrome/browser/sync_file_system/drive_backend/sync_engine_initializer.h"
8 #include "base/callback.h"
9 #include "base/logging.h"
10 #include "chrome/browser/drive/drive_api_service.h"
11 #include "chrome/browser/drive/drive_api_util.h"
12 #include "chrome/browser/sync_file_system/drive_backend/drive_backend_constants.h"
13 #include "chrome/browser/sync_file_system/drive_backend/drive_backend_util.h"
14 #include "chrome/browser/sync_file_system/drive_backend/metadata_database.h"
15 #include "chrome/browser/sync_file_system/drive_backend/sync_engine_context.h"
16 #include "chrome/browser/sync_file_system/logger.h"
17 #include "google_apis/drive/drive_api_parser.h"
18 #include "google_apis/drive/gdata_wapi_parser.h"
20 namespace sync_file_system {
21 namespace drive_backend {
25 ////////////////////////////////////////////////////////////////////////////////
26 // Functions below are for wrapping the access to legacy GData WAPI classes.
28 bool IsDeleted(const google_apis::ResourceEntry& entry) {
29 return entry.deleted();
32 bool HasNoParents(const google_apis::ResourceEntry& entry) {
33 return !entry.GetLinkByType(google_apis::Link::LINK_PARENT);
36 bool HasFolderAsParent(const google_apis::ResourceEntry& entry,
37 const std::string& parent_id) {
38 const ScopedVector<google_apis::Link>& links = entry.links();
39 for (ScopedVector<google_apis::Link>::const_iterator itr = links.begin();
40 itr != links.end(); ++itr) {
41 const google_apis::Link& link = **itr;
42 if (link.type() != google_apis::Link::LINK_PARENT)
44 if (drive::util::ExtractResourceIdFromUrl(link.href()) == parent_id)
50 bool LessOnCreationTime(const google_apis::ResourceEntry& left,
51 const google_apis::ResourceEntry& right) {
52 return left.published_time() < right.published_time();
55 // Posts a request to continue listing. Returns false if the list doesn't need
57 bool GetRemainingFileList(
58 google_apis::CancelCallback* cancel_callback,
59 drive::DriveServiceInterface* api_service,
60 const google_apis::ResourceList& resource_list,
61 const google_apis::GetResourceListCallback& callback) {
63 if (!resource_list.GetNextFeedURL(&next_url))
66 *cancel_callback = api_service->GetRemainingFileList(next_url, callback);
70 std::string GetID(const google_apis::ResourceEntry& entry) {
71 return entry.resource_id();
74 ScopedVector<google_apis::FileResource> ConvertResourceEntriesToFileResources(
75 const ScopedVector<google_apis::ResourceEntry>& entries) {
76 ScopedVector<google_apis::FileResource> resources;
77 for (ScopedVector<google_apis::ResourceEntry>::const_iterator itr =
82 drive::util::ConvertResourceEntryToFileResource(
85 return resources.Pass();
88 // Functions above are for wrapping the access to legacy GData WAPI classes.
89 ////////////////////////////////////////////////////////////////////////////////
93 SyncEngineInitializer::SyncEngineInitializer(
94 SyncEngineContext* sync_context,
95 base::SequencedTaskRunner* task_runner,
96 drive::DriveServiceInterface* drive_service,
97 const base::FilePath& database_path)
98 : sync_context_(sync_context),
99 task_runner_(task_runner),
100 drive_service_(drive_service),
101 database_path_(database_path),
102 find_sync_root_retry_count_(0),
103 largest_change_id_(0),
104 weak_ptr_factory_(this) {
106 DCHECK(drive_service_);
109 SyncEngineInitializer::~SyncEngineInitializer() {
110 if (!cancel_callback_.is_null())
111 cancel_callback_.Run();
114 void SyncEngineInitializer::Run(const SyncStatusCallback& callback) {
115 util::Log(logging::LOG_VERBOSE, FROM_HERE, "[Initialize] Start.");
117 // The metadata seems to have been already initialized. Just return with OK.
118 if (sync_context_ && sync_context_->GetMetadataDatabase()) {
119 util::Log(logging::LOG_VERBOSE, FROM_HERE,
120 "[Initialize] Already initialized.");
121 callback.Run(SYNC_STATUS_OK);
125 MetadataDatabase::Create(
126 task_runner_.get(), database_path_,
127 base::Bind(&SyncEngineInitializer::DidCreateMetadataDatabase,
128 weak_ptr_factory_.GetWeakPtr(), callback));
131 scoped_ptr<MetadataDatabase> SyncEngineInitializer::PassMetadataDatabase() {
132 return metadata_database_.Pass();
135 void SyncEngineInitializer::DidCreateMetadataDatabase(
136 const SyncStatusCallback& callback,
137 SyncStatusCode status,
138 scoped_ptr<MetadataDatabase> instance) {
139 if (status != SYNC_STATUS_OK) {
140 util::Log(logging::LOG_VERBOSE, FROM_HERE,
141 "[Initialize] Failed to initialize MetadataDatabase.");
142 callback.Run(status);
147 metadata_database_ = instance.Pass();
148 if (metadata_database_->HasSyncRoot()) {
149 util::Log(logging::LOG_VERBOSE, FROM_HERE,
150 "[Initialize] Found local cache of sync-root.");
151 callback.Run(SYNC_STATUS_OK);
155 GetAboutResource(callback);
158 void SyncEngineInitializer::GetAboutResource(
159 const SyncStatusCallback& callback) {
160 set_used_network(true);
161 drive_service_->GetAboutResource(
162 base::Bind(&SyncEngineInitializer::DidGetAboutResource,
163 weak_ptr_factory_.GetWeakPtr(), callback));
166 void SyncEngineInitializer::DidGetAboutResource(
167 const SyncStatusCallback& callback,
168 google_apis::GDataErrorCode error,
169 scoped_ptr<google_apis::AboutResource> about_resource) {
170 cancel_callback_.Reset();
172 SyncStatusCode status = GDataErrorCodeToSyncStatusCode(error);
173 if (status != SYNC_STATUS_OK) {
174 util::Log(logging::LOG_VERBOSE, FROM_HERE,
175 "[Initialize] Failed to get AboutResource.");
176 callback.Run(status);
180 DCHECK(about_resource);
181 root_folder_id_ = about_resource->root_folder_id();
182 largest_change_id_ = about_resource->largest_change_id();
184 DCHECK(!root_folder_id_.empty());
185 FindSyncRoot(callback);
188 void SyncEngineInitializer::FindSyncRoot(const SyncStatusCallback& callback) {
189 if (find_sync_root_retry_count_++ >= kMaxRetry) {
190 util::Log(logging::LOG_VERBOSE, FROM_HERE,
191 "[Initialize] Reached max retry count.");
192 callback.Run(SYNC_STATUS_FAILED);
196 set_used_network(true);
197 cancel_callback_ = drive_service_->SearchByTitle(
198 kSyncRootFolderTitle,
199 std::string(), // parent_folder_id
200 base::Bind(&SyncEngineInitializer::DidFindSyncRoot,
201 weak_ptr_factory_.GetWeakPtr(),
205 void SyncEngineInitializer::DidFindSyncRoot(
206 const SyncStatusCallback& callback,
207 google_apis::GDataErrorCode error,
208 scoped_ptr<google_apis::ResourceList> resource_list) {
209 cancel_callback_.Reset();
211 SyncStatusCode status = GDataErrorCodeToSyncStatusCode(error);
212 if (status != SYNC_STATUS_OK) {
213 util::Log(logging::LOG_VERBOSE, FROM_HERE,
214 "[Initialize] Failed to find sync root.");
215 callback.Run(status);
219 if (!resource_list) {
221 util::Log(logging::LOG_VERBOSE, FROM_HERE,
222 "[Initialize] Got invalid resource list.");
223 callback.Run(SYNC_STATUS_FAILED);
227 ScopedVector<google_apis::ResourceEntry>* entries =
228 resource_list->mutable_entries();
229 for (ScopedVector<google_apis::ResourceEntry>::iterator itr =
231 itr != entries->end(); ++itr) {
232 google_apis::ResourceEntry* entry = *itr;
234 // Ignore deleted folder.
235 if (IsDeleted(*entry))
238 // Pick an orphaned folder or a direct child of the root folder and
240 DCHECK(!root_folder_id_.empty());
241 if (!HasNoParents(*entry) && !HasFolderAsParent(*entry, root_folder_id_))
244 if (!sync_root_folder_ || LessOnCreationTime(*entry, *sync_root_folder_)) {
245 sync_root_folder_.reset(entry);
250 set_used_network(true);
251 // If there are more results, retrieve them.
252 if (GetRemainingFileList(
254 drive_service_, *resource_list,
255 base::Bind(&SyncEngineInitializer::DidFindSyncRoot,
256 weak_ptr_factory_.GetWeakPtr(),
260 if (!sync_root_folder_) {
261 CreateSyncRoot(callback);
265 if (!HasNoParents(*sync_root_folder_)) {
266 DetachSyncRoot(callback);
270 ListAppRootFolders(callback);
273 void SyncEngineInitializer::CreateSyncRoot(const SyncStatusCallback& callback) {
274 DCHECK(!sync_root_folder_);
275 set_used_network(true);
276 cancel_callback_ = drive_service_->AddNewDirectory(
277 root_folder_id_, kSyncRootFolderTitle,
278 base::Bind(&SyncEngineInitializer::DidCreateSyncRoot,
279 weak_ptr_factory_.GetWeakPtr(),
283 void SyncEngineInitializer::DidCreateSyncRoot(
284 const SyncStatusCallback& callback,
285 google_apis::GDataErrorCode error,
286 scoped_ptr<google_apis::ResourceEntry> entry) {
287 DCHECK(!sync_root_folder_);
288 cancel_callback_.Reset();
290 SyncStatusCode status = GDataErrorCodeToSyncStatusCode(error);
291 if (status != SYNC_STATUS_OK) {
292 util::Log(logging::LOG_VERBOSE, FROM_HERE,
293 "[Initialize] Failed to create sync root.");
294 callback.Run(status);
298 FindSyncRoot(callback);
301 void SyncEngineInitializer::DetachSyncRoot(const SyncStatusCallback& callback) {
302 DCHECK(sync_root_folder_);
303 set_used_network(true);
304 cancel_callback_ = drive_service_->RemoveResourceFromDirectory(
305 root_folder_id_, GetID(*sync_root_folder_),
306 base::Bind(&SyncEngineInitializer::DidDetachSyncRoot,
307 weak_ptr_factory_.GetWeakPtr(),
311 void SyncEngineInitializer::DidDetachSyncRoot(
312 const SyncStatusCallback& callback,
313 google_apis::GDataErrorCode error) {
314 cancel_callback_.Reset();
316 SyncStatusCode status = GDataErrorCodeToSyncStatusCode(error);
317 if (status != SYNC_STATUS_OK) {
318 util::Log(logging::LOG_VERBOSE, FROM_HERE,
319 "[Initialize] Failed to detach sync root.");
320 callback.Run(status);
324 ListAppRootFolders(callback);
327 void SyncEngineInitializer::ListAppRootFolders(
328 const SyncStatusCallback& callback) {
329 DCHECK(sync_root_folder_);
330 set_used_network(true);
331 cancel_callback_ = drive_service_->GetResourceListInDirectory(
332 GetID(*sync_root_folder_),
333 base::Bind(&SyncEngineInitializer::DidListAppRootFolders,
334 weak_ptr_factory_.GetWeakPtr(),
338 void SyncEngineInitializer::DidListAppRootFolders(
339 const SyncStatusCallback& callback,
340 google_apis::GDataErrorCode error,
341 scoped_ptr<google_apis::ResourceList> resource_list) {
342 cancel_callback_.Reset();
344 SyncStatusCode status = GDataErrorCodeToSyncStatusCode(error);
345 if (status != SYNC_STATUS_OK) {
346 util::Log(logging::LOG_VERBOSE, FROM_HERE,
347 "[Initialize] Failed to get initial app-root folders.");
348 callback.Run(status);
352 if (!resource_list) {
354 util::Log(logging::LOG_VERBOSE, FROM_HERE,
355 "[Initialize] Got invalid initial app-root list.");
356 callback.Run(SYNC_STATUS_FAILED);
360 ScopedVector<google_apis::ResourceEntry>* new_entries =
361 resource_list->mutable_entries();
362 app_root_folders_.insert(app_root_folders_.end(),
363 new_entries->begin(), new_entries->end());
364 new_entries->weak_clear();
366 set_used_network(true);
367 if (GetRemainingFileList(
371 base::Bind(&SyncEngineInitializer::DidListAppRootFolders,
372 weak_ptr_factory_.GetWeakPtr(), callback)))
375 PopulateDatabase(callback);
378 void SyncEngineInitializer::PopulateDatabase(
379 const SyncStatusCallback& callback) {
380 DCHECK(sync_root_folder_);
381 metadata_database_->PopulateInitialData(
383 *drive::util::ConvertResourceEntryToFileResource(
385 ConvertResourceEntriesToFileResources(app_root_folders_),
386 base::Bind(&SyncEngineInitializer::DidPopulateDatabase,
387 weak_ptr_factory_.GetWeakPtr(),
391 void SyncEngineInitializer::DidPopulateDatabase(
392 const SyncStatusCallback& callback,
393 SyncStatusCode status) {
394 if (status != SYNC_STATUS_OK) {
395 util::Log(logging::LOG_VERBOSE, FROM_HERE,
396 "[Initialize] Failed to populate initial data"
397 " to MetadataDatabase.");
398 callback.Run(status);
402 util::Log(logging::LOG_VERBOSE, FROM_HERE,
403 "[Initialize] Completed successfully.");
404 callback.Run(SYNC_STATUS_OK);
407 } // namespace drive_backend
408 } // namespace sync_file_system