register_app_task.cc revision 4e180b6a0b4720a9b8e9e959a882386f690f08ff
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/google_apis/drive_api_parser.h"
12#include "chrome/browser/google_apis/gdata_wapi_parser.h"
13#include "chrome/browser/sync_file_system/drive_backend/drive_backend_constants.h"
14#include "chrome/browser/sync_file_system/drive_backend/metadata_database.h"
15#include "chrome/browser/sync_file_system/drive_backend/metadata_database.pb.h"
16#include "chrome/browser/sync_file_system/drive_backend/sync_engine_context.h"
17#include "chrome/browser/sync_file_system/drive_backend/tracker_set.h"
18#include "chrome/browser/sync_file_system/syncable_file_system_util.h"
19
20namespace sync_file_system {
21namespace drive_backend {
22
23namespace {
24
25bool CompareOnCTime(const FileTracker& left,
26                    const FileTracker& right) {
27  return left.synced_details().creation_time() <
28      right.synced_details().creation_time();
29}
30
31}  // namespace
32
33RegisterAppTask::RegisterAppTask(SyncEngineContext* sync_context,
34                                 const std::string& app_id)
35    : sync_context_(sync_context),
36      create_folder_retry_count_(0),
37      app_id_(app_id),
38      weak_ptr_factory_(this) {
39}
40
41RegisterAppTask::~RegisterAppTask() {
42}
43
44void RegisterAppTask::Run(const SyncStatusCallback& callback) {
45  if (create_folder_retry_count_++ >= kMaxRetry) {
46    callback.Run(SYNC_STATUS_FAILED);
47    return;
48  }
49
50  if (!metadata_database() || !drive_service()) {
51    callback.Run(SYNC_STATUS_FAILED);
52    return;
53  }
54
55  int64 sync_root = metadata_database()->GetSyncRootTrackerID();
56  TrackerSet trackers;
57  if (!metadata_database()->FindTrackersByParentAndTitle(
58          sync_root, app_id_, &trackers)) {
59    CreateAppRootFolder(callback);
60    return;
61  }
62
63  FileTracker candidate;
64  if (!FilterCandidates(trackers, &candidate)) {
65    CreateAppRootFolder(callback);
66    return;
67  }
68
69  if (candidate.active()) {
70    RunSoon(FROM_HERE, base::Bind(callback, SYNC_STATUS_OK));
71    return;
72  }
73
74  RegisterAppIntoDatabase(candidate, callback);
75}
76
77void RegisterAppTask::CreateAppRootFolder(const SyncStatusCallback& callback) {
78  int64 sync_root_tracker_id = metadata_database()->GetSyncRootTrackerID();
79  FileTracker sync_root_tracker;
80  bool should_success = metadata_database()->FindTrackerByTrackerID(
81      sync_root_tracker_id,
82      &sync_root_tracker);
83  DCHECK(should_success);
84
85  drive_service()->AddNewDirectory(
86      sync_root_tracker.file_id(),
87      app_id_,
88      base::Bind(&RegisterAppTask::DidCreateAppRootFolder,
89                 weak_ptr_factory_.GetWeakPtr(),
90                 callback,
91                 metadata_database()->GetLargestChangeID()));
92}
93
94void RegisterAppTask::DidCreateAppRootFolder(
95    const SyncStatusCallback& callback,
96    int64 change_id,
97    google_apis::GDataErrorCode error,
98    scoped_ptr<google_apis::ResourceEntry> entry) {
99  if (error != google_apis::HTTP_SUCCESS &&
100      error != google_apis::HTTP_CREATED) {
101    callback.Run(SYNC_STATUS_FAILED);
102    return;
103  }
104
105  DCHECK(entry);
106  scoped_ptr<google_apis::FileResource> resource(
107      drive::util::ConvertResourceEntryToFileResource(*entry));
108  sync_context_->GetMetadataDatabase()->UpdateByFileResource(
109      change_id,
110      *resource,
111      base::Bind(&RegisterAppTask::DidUpdateDatabase,
112                 weak_ptr_factory_.GetWeakPtr(),
113                 callback,
114                 resource->file_id()));
115}
116
117void RegisterAppTask::DidUpdateDatabase(const SyncStatusCallback& callback,
118                                        const std::string& file_id,
119                                        SyncStatusCode status) {
120  if (status != SYNC_STATUS_OK) {
121    callback.Run(SYNC_STATUS_FAILED);
122    return;
123  }
124
125  FileMetadata file;
126  bool should_success = metadata_database()->FindFileByFileID(
127      file_id, &file);
128  DCHECK(should_success);
129
130  TrackerSet trackers;
131  should_success = metadata_database()->FindTrackersByFileID(
132      file_id, &trackers);
133  DCHECK(should_success);
134
135  DCHECK_EQ(1u, trackers.tracker_set().size());
136  FileTracker tracker = **trackers.begin();
137  DCHECK_EQ(metadata_database()->GetSyncRootTrackerID(),
138            tracker.parent_tracker_id());
139
140  metadata_database()->UpdateTracker(
141      tracker.tracker_id(),
142      file.details(),
143      base::Bind(&RegisterAppTask::DidPrepareForRegister,
144                 weak_ptr_factory_.GetWeakPtr(),
145                 callback));
146}
147
148void RegisterAppTask::DidPrepareForRegister(const SyncStatusCallback& callback,
149                                            SyncStatusCode status) {
150  if (status != SYNC_STATUS_OK) {
151    callback.Run(SYNC_STATUS_FAILED);
152    return;
153  }
154
155  // TODO(tzik): Ensure the file didn't make create-create conflict by listing
156  // the same title folders.
157
158  Run(callback);
159}
160
161bool RegisterAppTask::FilterCandidates(const TrackerSet& trackers,
162                                       FileTracker* candidate) {
163  DCHECK(candidate);
164  if (trackers.has_active()) {
165    *candidate = *trackers.active_tracker();
166    return true;
167  }
168
169  FileTracker* oldest_tracker = NULL;
170  for (TrackerSet::const_iterator itr = trackers.begin();
171       itr != trackers.end(); ++itr) {
172    FileTracker* tracker = *itr;
173    DCHECK(!tracker->active());
174    DCHECK(tracker->has_synced_details());
175    if (tracker->synced_details().file_kind() != FILE_KIND_FOLDER)
176      continue;
177
178    if (tracker->synced_details().deleted())
179      continue;
180
181    if (oldest_tracker && CompareOnCTime(*oldest_tracker, *tracker))
182      continue;
183
184    oldest_tracker = tracker;
185  }
186
187  if (!oldest_tracker)
188    return false;
189
190  *candidate = *oldest_tracker;
191  return true;
192}
193
194void RegisterAppTask::RegisterAppIntoDatabase(
195    const FileTracker& tracker,
196    const SyncStatusCallback& callback) {
197  sync_context_->GetMetadataDatabase()->RegisterApp(
198      app_id_, tracker.file_id(), callback);
199}
200
201MetadataDatabase* RegisterAppTask::metadata_database() {
202  return sync_context_->GetMetadataDatabase();
203}
204
205drive::DriveServiceInterface* RegisterAppTask::drive_service() {
206  return sync_context_->GetDriveService();
207}
208
209}  // namespace drive_backend
210}  // namespace sync_file_system
211