Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / sync_file_system / drive_backend / sync_engine_initializer.cc
blobb28e94194336f33b7384da7eddbadfaeecfe406b
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"
7 #include "base/bind.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 {
23 namespace {
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)
43 continue;
44 if (drive::util::ExtractResourceIdFromUrl(link.href()) == parent_id)
45 return true;
47 return false;
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
56 // listing anymore.
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) {
62 GURL next_url;
63 if (!resource_list.GetNextFeedURL(&next_url))
64 return false;
66 *cancel_callback = api_service->GetRemainingFileList(next_url, callback);
67 return true;
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 =
78 entries.begin();
79 itr != entries.end();
80 ++itr) {
81 resources.push_back(
82 drive::util::ConvertResourceEntryToFileResource(
83 **itr).release());
85 return resources.Pass();
88 // Functions above are for wrapping the access to legacy GData WAPI classes.
89 ////////////////////////////////////////////////////////////////////////////////
91 } // namespace
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) {
105 DCHECK(task_runner);
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);
122 return;
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);
143 return;
146 DCHECK(instance);
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);
152 return;
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);
177 return;
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);
193 return;
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(),
202 callback));
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);
216 return;
219 if (!resource_list) {
220 NOTREACHED();
221 util::Log(logging::LOG_VERBOSE, FROM_HERE,
222 "[Initialize] Got invalid resource list.");
223 callback.Run(SYNC_STATUS_FAILED);
224 return;
227 ScopedVector<google_apis::ResourceEntry>* entries =
228 resource_list->mutable_entries();
229 for (ScopedVector<google_apis::ResourceEntry>::iterator itr =
230 entries->begin();
231 itr != entries->end(); ++itr) {
232 google_apis::ResourceEntry* entry = *itr;
234 // Ignore deleted folder.
235 if (IsDeleted(*entry))
236 continue;
238 // Pick an orphaned folder or a direct child of the root folder and
239 // ignore others.
240 DCHECK(!root_folder_id_.empty());
241 if (!HasNoParents(*entry) && !HasFolderAsParent(*entry, root_folder_id_))
242 continue;
244 if (!sync_root_folder_ || LessOnCreationTime(*entry, *sync_root_folder_)) {
245 sync_root_folder_.reset(entry);
246 *itr = NULL;
250 set_used_network(true);
251 // If there are more results, retrieve them.
252 if (GetRemainingFileList(
253 &cancel_callback_,
254 drive_service_, *resource_list,
255 base::Bind(&SyncEngineInitializer::DidFindSyncRoot,
256 weak_ptr_factory_.GetWeakPtr(),
257 callback)))
258 return;
260 if (!sync_root_folder_) {
261 CreateSyncRoot(callback);
262 return;
265 if (!HasNoParents(*sync_root_folder_)) {
266 DetachSyncRoot(callback);
267 return;
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(),
280 callback));
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);
295 return;
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(),
308 callback));
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);
321 return;
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(),
335 callback));
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);
349 return;
352 if (!resource_list) {
353 NOTREACHED();
354 util::Log(logging::LOG_VERBOSE, FROM_HERE,
355 "[Initialize] Got invalid initial app-root list.");
356 callback.Run(SYNC_STATUS_FAILED);
357 return;
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(
368 &cancel_callback_,
369 drive_service_,
370 *resource_list,
371 base::Bind(&SyncEngineInitializer::DidListAppRootFolders,
372 weak_ptr_factory_.GetWeakPtr(), callback)))
373 return;
375 PopulateDatabase(callback);
378 void SyncEngineInitializer::PopulateDatabase(
379 const SyncStatusCallback& callback) {
380 DCHECK(sync_root_folder_);
381 metadata_database_->PopulateInitialData(
382 largest_change_id_,
383 *drive::util::ConvertResourceEntryToFileResource(
384 *sync_root_folder_),
385 ConvertResourceEntriesToFileResources(app_root_folders_),
386 base::Bind(&SyncEngineInitializer::DidPopulateDatabase,
387 weak_ptr_factory_.GetWeakPtr(),
388 callback));
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);
399 return;
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