- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / sync_file_system / drive_backend / sync_engine_initializer.cc
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/sync_engine_initializer.h"
6
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/google_apis/drive_api_parser.h"
13 #include "chrome/browser/google_apis/gdata_wapi_parser.h"
14 #include "chrome/browser/sync_file_system/drive_backend/drive_backend_constants.h"
15 #include "chrome/browser/sync_file_system/drive_backend/metadata_database.h"
16 #include "chrome/browser/sync_file_system/drive_backend_v1/drive_file_sync_util.h"
17
18 namespace sync_file_system {
19 namespace drive_backend {
20
21 namespace {
22
23 ////////////////////////////////////////////////////////////////////////////////
24 // Functions below are for wrapping the access to legacy GData WAPI classes.
25
26 bool IsDeleted(const google_apis::ResourceEntry& entry) {
27   return entry.deleted();
28 }
29
30 bool HasNoParents(const google_apis::ResourceEntry& entry) {
31   return !entry.GetLinkByType(google_apis::Link::LINK_PARENT);
32 }
33
34 bool HasFolderAsParent(const google_apis::ResourceEntry& entry,
35                        const std::string& parent_id) {
36   const ScopedVector<google_apis::Link>& links = entry.links();
37   for (ScopedVector<google_apis::Link>::const_iterator itr = links.begin();
38        itr != links.end(); ++itr) {
39     const google_apis::Link& link = **itr;
40     if (link.type() != google_apis::Link::LINK_PARENT)
41       continue;
42     if (drive::util::ExtractResourceIdFromUrl(link.href()) == parent_id)
43       return true;
44   }
45   return false;
46 }
47
48 bool LessOnCreationTime(const google_apis::ResourceEntry& left,
49                         const google_apis::ResourceEntry& right) {
50   return left.published_time() < right.published_time();
51 }
52
53 // Posts a request to continue listing.  Returns false if the list doesn't need
54 // listing anymore.
55 bool GetRemainingFileList(
56     google_apis::CancelCallback* cancel_callback,
57     drive::DriveServiceInterface* api_service,
58     const google_apis::ResourceList& resource_list,
59     const google_apis::GetResourceListCallback& callback) {
60   GURL next_url;
61   if (!resource_list.GetNextFeedURL(&next_url))
62     return false;
63
64   *cancel_callback = api_service->GetRemainingFileList(next_url, callback);
65   return true;
66 }
67
68 std::string GetID(const google_apis::ResourceEntry& entry) {
69   return entry.resource_id();
70 }
71
72 ScopedVector<google_apis::FileResource> ConvertResourceEntriesToFileResources(
73     const ScopedVector<google_apis::ResourceEntry>& entries) {
74   ScopedVector<google_apis::FileResource> resources;
75   for (ScopedVector<google_apis::ResourceEntry>::const_iterator itr =
76            entries.begin();
77        itr != entries.end();
78        ++itr) {
79     resources.push_back(
80         drive::util::ConvertResourceEntryToFileResource(
81             **itr).release());
82   }
83   return resources.Pass();
84 }
85
86 // Functions above are for wrapping the access to legacy GData WAPI classes.
87 ////////////////////////////////////////////////////////////////////////////////
88
89 }  // namespace
90
91 SyncEngineInitializer::SyncEngineInitializer(
92     base::SequencedTaskRunner* task_runner,
93     drive::DriveServiceInterface* drive_service,
94     const base::FilePath& database_path)
95     : task_runner_(task_runner),
96       drive_service_(drive_service),
97       database_path_(database_path),
98       find_sync_root_retry_count_(0),
99       largest_change_id_(0),
100       weak_ptr_factory_(this) {
101   DCHECK(task_runner);
102   DCHECK(drive_service_);
103 }
104
105 SyncEngineInitializer::~SyncEngineInitializer() {
106   if (!cancel_callback_.is_null())
107     cancel_callback_.Run();
108 }
109
110 void SyncEngineInitializer::Run(const SyncStatusCallback& callback) {
111   MetadataDatabase::Create(
112       task_runner_.get(), database_path_,
113       base::Bind(&SyncEngineInitializer::DidCreateMetadataDatabase,
114                  weak_ptr_factory_.GetWeakPtr(), callback));
115 }
116
117 scoped_ptr<MetadataDatabase> SyncEngineInitializer::PassMetadataDatabase() {
118   return metadata_database_.Pass();
119 }
120
121 void SyncEngineInitializer::DidCreateMetadataDatabase(
122     const SyncStatusCallback& callback,
123     SyncStatusCode status,
124     scoped_ptr<MetadataDatabase> instance) {
125   if (status != SYNC_STATUS_OK) {
126     callback.Run(status);
127     return;
128   }
129
130   DCHECK(instance);
131   metadata_database_ = instance.Pass();
132   if (metadata_database_->HasSyncRoot()) {
133     callback.Run(SYNC_STATUS_OK);
134     return;
135   }
136
137   GetAboutResource(callback);
138 }
139
140 void SyncEngineInitializer::GetAboutResource(
141     const SyncStatusCallback& callback) {
142   drive_service_->GetAboutResource(
143       base::Bind(&SyncEngineInitializer::DidGetAboutResource,
144                  weak_ptr_factory_.GetWeakPtr(), callback));
145 }
146
147 void SyncEngineInitializer::DidGetAboutResource(
148     const SyncStatusCallback& callback,
149     google_apis::GDataErrorCode error,
150     scoped_ptr<google_apis::AboutResource> about_resource) {
151   cancel_callback_.Reset();
152   if (error != google_apis::HTTP_SUCCESS) {
153     callback.Run(GDataErrorCodeToSyncStatusCode(error));
154     return;
155   }
156
157   DCHECK(about_resource);
158   root_folder_id_ = about_resource->root_folder_id();
159   largest_change_id_ = about_resource->largest_change_id();
160
161   DCHECK(!root_folder_id_.empty());
162   FindSyncRoot(callback);
163 }
164
165 void SyncEngineInitializer::FindSyncRoot(const SyncStatusCallback& callback) {
166   if (find_sync_root_retry_count_++ >= kMaxRetry) {
167     callback.Run(SYNC_STATUS_FAILED);
168     return;
169   }
170
171   cancel_callback_ = drive_service_->SearchByTitle(
172       kSyncRootFolderTitle,
173       std::string(), // parent_folder_id
174       base::Bind(&SyncEngineInitializer::DidFindSyncRoot,
175                  weak_ptr_factory_.GetWeakPtr(),
176                  callback));
177 }
178
179 void SyncEngineInitializer::DidFindSyncRoot(
180     const SyncStatusCallback& callback,
181     google_apis::GDataErrorCode error,
182     scoped_ptr<google_apis::ResourceList> resource_list) {
183   cancel_callback_.Reset();
184   if (error != google_apis::HTTP_SUCCESS) {
185     callback.Run(GDataErrorCodeToSyncStatusCode(error));
186     return;
187   }
188
189   ScopedVector<google_apis::ResourceEntry>* entries =
190       resource_list->mutable_entries();
191   for (ScopedVector<google_apis::ResourceEntry>::iterator itr =
192            entries->begin();
193        itr != entries->end(); ++itr) {
194     google_apis::ResourceEntry* entry = *itr;
195
196     // Ignore deleted folder.
197     if (IsDeleted(*entry))
198       continue;
199
200     // Pick an orphaned folder or a direct child of the root folder and
201     // ignore others.
202     DCHECK(!root_folder_id_.empty());
203     if (!HasNoParents(*entry) && !HasFolderAsParent(*entry, root_folder_id_))
204       continue;
205
206     if (!sync_root_folder_ || LessOnCreationTime(*entry, *sync_root_folder_)) {
207       sync_root_folder_.reset(entry);
208       *itr = NULL;
209     }
210   }
211
212   // If there are more results, retrieve them.
213   if (GetRemainingFileList(
214           &cancel_callback_,
215           drive_service_, *resource_list,
216           base::Bind(&SyncEngineInitializer::DidFindSyncRoot,
217                      weak_ptr_factory_.GetWeakPtr(),
218                      callback)))
219     return;
220
221   if (!sync_root_folder_) {
222     CreateSyncRoot(callback);
223     return;
224   }
225
226   if (!HasNoParents(*sync_root_folder_)) {
227     DetachSyncRoot(callback);
228     return;
229   }
230
231   ListAppRootFolders(callback);
232 }
233
234 void SyncEngineInitializer::CreateSyncRoot(const SyncStatusCallback& callback) {
235   DCHECK(!sync_root_folder_);
236   cancel_callback_ = drive_service_->AddNewDirectory(
237       root_folder_id_, kSyncRootFolderTitle,
238       base::Bind(&SyncEngineInitializer::DidCreateSyncRoot,
239                  weak_ptr_factory_.GetWeakPtr(),
240                  callback));
241 }
242
243 void SyncEngineInitializer::DidCreateSyncRoot(
244     const SyncStatusCallback& callback,
245     google_apis::GDataErrorCode error,
246     scoped_ptr<google_apis::ResourceEntry> entry) {
247   DCHECK(!sync_root_folder_);
248   cancel_callback_.Reset();
249   if (error != google_apis::HTTP_SUCCESS &&
250       error != google_apis::HTTP_CREATED) {
251     callback.Run(GDataErrorCodeToSyncStatusCode(error));
252     return;
253   }
254
255   FindSyncRoot(callback);
256 }
257
258 void SyncEngineInitializer::DetachSyncRoot(const SyncStatusCallback& callback) {
259   DCHECK(sync_root_folder_);
260   cancel_callback_ = drive_service_->RemoveResourceFromDirectory(
261       root_folder_id_, GetID(*sync_root_folder_),
262       base::Bind(&SyncEngineInitializer::DidDetachSyncRoot,
263                  weak_ptr_factory_.GetWeakPtr(),
264                  callback));
265 }
266
267 void SyncEngineInitializer::DidDetachSyncRoot(
268     const SyncStatusCallback& callback,
269     google_apis::GDataErrorCode error) {
270   cancel_callback_.Reset();
271   if (error != google_apis::HTTP_SUCCESS) {
272     callback.Run(GDataErrorCodeToSyncStatusCode(error));
273     return;
274   }
275   ListAppRootFolders(callback);
276 }
277
278 void SyncEngineInitializer::ListAppRootFolders(
279     const SyncStatusCallback& callback) {
280   DCHECK(sync_root_folder_);
281   cancel_callback_ = drive_service_->GetResourceListInDirectory(
282       GetID(*sync_root_folder_),
283       base::Bind(&SyncEngineInitializer::DidListAppRootFolders,
284                  weak_ptr_factory_.GetWeakPtr(),
285                  callback));
286 }
287
288 void SyncEngineInitializer::DidListAppRootFolders(
289     const SyncStatusCallback& callback,
290     google_apis::GDataErrorCode error,
291     scoped_ptr<google_apis::ResourceList> resource_list) {
292   cancel_callback_.Reset();
293   if (error != google_apis::HTTP_SUCCESS) {
294     callback.Run(GDataErrorCodeToSyncStatusCode(error));
295     return;
296   }
297
298   ScopedVector<google_apis::ResourceEntry>* new_entries =
299       resource_list->mutable_entries();
300   app_root_folders_.insert(app_root_folders_.end(),
301                            new_entries->begin(), new_entries->end());
302   new_entries->weak_clear();
303
304   if (GetRemainingFileList(
305           &cancel_callback_,
306           drive_service_,
307           *resource_list,
308           base::Bind(&SyncEngineInitializer::DidListAppRootFolders,
309                      weak_ptr_factory_.GetWeakPtr(), callback)))
310     return;
311
312   PopulateDatabase(callback);
313 }
314
315 void SyncEngineInitializer::PopulateDatabase(
316     const SyncStatusCallback& callback) {
317   DCHECK(sync_root_folder_);
318   metadata_database_->PopulateInitialData(
319       largest_change_id_,
320       *drive::util::ConvertResourceEntryToFileResource(
321           *sync_root_folder_),
322       ConvertResourceEntriesToFileResources(app_root_folders_),
323       base::Bind(&SyncEngineInitializer::DidPopulateDatabase,
324                  weak_ptr_factory_.GetWeakPtr(),
325                  callback));
326 }
327
328 void SyncEngineInitializer::DidPopulateDatabase(
329     const SyncStatusCallback& callback,
330     SyncStatusCode status) {
331   if (status != SYNC_STATUS_OK) {
332     callback.Run(status);
333     return;
334   }
335
336   callback.Run(SYNC_STATUS_OK);
337 }
338
339 }  // namespace drive_backend
340 }  // namespace sync_file_system