1// Copyright (c) 2012 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#ifndef CHROME_BROWSER_CHROMEOS_DRIVE_CHANGE_LIST_LOADER_H_
6#define CHROME_BROWSER_CHROMEOS_DRIVE_CHANGE_LIST_LOADER_H_
7
8#include <string>
9#include <vector>
10
11#include "base/callback.h"
12#include "base/memory/ref_counted.h"
13#include "base/memory/scoped_ptr.h"
14#include "base/memory/scoped_vector.h"
15#include "base/observer_list.h"
16#include "chrome/browser/chromeos/drive/file_errors.h"
17#include "google_apis/drive/drive_common_callbacks.h"
18#include "google_apis/drive/gdata_errorcode.h"
19
20class GURL;
21
22namespace base {
23class ScopedClosureRunner;
24class SequencedTaskRunner;
25class Time;
26}  // namespace base
27
28namespace google_apis {
29class AboutResource;
30class ResourceList;
31}  // namespace google_apis
32
33namespace drive {
34
35class EventLogger;
36class JobScheduler;
37class ResourceEntry;
38
39namespace internal {
40
41class ChangeList;
42class ChangeListLoaderObserver;
43class ChangeListProcessor;
44class DirectoryLoader;
45class ResourceMetadata;
46
47// Delays execution of tasks as long as more than one lock is alive.
48// Used to ensure that ChangeListLoader does not cause race condition by adding
49// new entries created by sync tasks before they do.
50// All code which may add entries found on the server to the local metadata
51// should use this class.
52class LoaderController {
53 public:
54  LoaderController();
55  ~LoaderController();
56
57  // Increments the lock count and returns an object which decrements the count
58  // on its destruction.
59  // While the lock count is positive, tasks will be pending.
60  scoped_ptr<base::ScopedClosureRunner> GetLock();
61
62  // Runs the task if the lock count is 0, otherwise it will be pending.
63  void ScheduleRun(const base::Closure& task);
64
65 private:
66  // Decrements the lock count.
67  void Unlock();
68
69  int lock_count_;
70  std::vector<base::Closure> pending_tasks_;
71
72  base::WeakPtrFactory<LoaderController> weak_ptr_factory_;
73  DISALLOW_COPY_AND_ASSIGN(LoaderController);
74};
75
76// This class is responsible to load AboutResource from the server and cache it.
77class AboutResourceLoader {
78 public:
79  explicit AboutResourceLoader(JobScheduler* scheduler);
80  ~AboutResourceLoader();
81
82  // Returns the cached about resource.
83  // NULL is returned if the cache is not available.
84  const google_apis::AboutResource* cached_about_resource() const {
85    return cached_about_resource_.get();
86  }
87
88  // Gets the 'latest' about resource and asynchronously runs |callback|. I.e.,
89  // 1) If the last call to UpdateAboutResource call is in-flight, wait for it.
90  // 2) Otherwise, if the resource is cached, just returns the cached value.
91  // 3) If neither of the above hold, queries the API server by calling
92  //   |UpdateAboutResource|.
93  void GetAboutResource(const google_apis::AboutResourceCallback& callback);
94
95  // Gets the about resource from the server, and caches it if successful. This
96  // function calls JobScheduler::GetAboutResource internally. The cache will be
97  // used in |GetAboutResource|.
98  void UpdateAboutResource(const google_apis::AboutResourceCallback& callback);
99
100 private:
101  // Part of UpdateAboutResource().
102  // This function should be called when the latest about resource is being
103  // fetched from the server. The retrieved about resource is cloned, and one is
104  // cached and the other is passed to callbacks associated with |task_id|.
105  void UpdateAboutResourceAfterGetAbout(
106      int task_id,
107      google_apis::GDataErrorCode status,
108      scoped_ptr<google_apis::AboutResource> about_resource);
109
110  JobScheduler* scheduler_;
111  scoped_ptr<google_apis::AboutResource> cached_about_resource_;
112
113  // Identifier to denote the latest UpdateAboutResource call.
114  int current_update_task_id_;
115  // Mapping from each UpdateAboutResource task ID to the corresponding
116  // callbacks. Note that there will be multiple callbacks for a single task
117  // when GetAboutResource is called before the task completes.
118  std::map<int, std::vector<google_apis::AboutResourceCallback> >
119      pending_callbacks_;
120
121  base::WeakPtrFactory<AboutResourceLoader> weak_ptr_factory_;
122  DISALLOW_COPY_AND_ASSIGN(AboutResourceLoader);
123};
124
125// ChangeListLoader is used to load the change list, the full resource list,
126// and directory contents, from Google Drive API.  The class also updates the
127// resource metadata with the change list loaded from the server.
128//
129// Note that the difference between "resource list" and "change list" is
130// subtle hence the two words are often used interchangeably. To be precise,
131// "resource list" refers to metadata from the server when fetching the full
132// resource metadata, or fetching directory contents, whereas "change list"
133// refers to metadata from the server when fetching changes (delta).
134class ChangeListLoader {
135 public:
136  // Resource feed fetcher from the server.
137  class FeedFetcher;
138
139  ChangeListLoader(EventLogger* logger,
140                   base::SequencedTaskRunner* blocking_task_runner,
141                   ResourceMetadata* resource_metadata,
142                   JobScheduler* scheduler,
143                   AboutResourceLoader* about_resource_loader,
144                   LoaderController* apply_task_controller);
145  ~ChangeListLoader();
146
147  // Indicates whether there is a request for full resource list or change
148  // list fetching is in flight (i.e. directory contents fetching does not
149  // count).
150  bool IsRefreshing() const;
151
152  // Adds and removes the observer.
153  void AddObserver(ChangeListLoaderObserver* observer);
154  void RemoveObserver(ChangeListLoaderObserver* observer);
155
156  // Checks for updates on the server. Does nothing if the change list is now
157  // being loaded or refreshed. |callback| must not be null.
158  // Note: |callback| will be called if the check for updates actually
159  // runs, i.e. it may NOT be called if the checking is ignored.
160  void CheckForUpdates(const FileOperationCallback& callback);
161
162  // Starts the change list loading if needed. If the locally stored metadata is
163  // available, runs |callback| immediately and starts checking server for
164  // updates in background. If the locally stored metadata is not available,
165  // starts loading from the server, and runs |callback| to tell the result to
166  // the caller when it is finished.
167  //
168  // |callback| must not be null.
169  void LoadIfNeeded(const FileOperationCallback& callback);
170
171 private:
172  // Starts the resource metadata loading and calls |callback| when it's done.
173  void Load(const FileOperationCallback& callback);
174  void LoadAfterGetLargestChangestamp(bool is_initial_load,
175                                      const int64* local_changestamp,
176                                      FileError error);
177  void LoadAfterGetAboutResource(
178      int64 local_changestamp,
179      google_apis::GDataErrorCode status,
180      scoped_ptr<google_apis::AboutResource> about_resource);
181
182  // Part of Load().
183  // This function should be called when the change list load is complete.
184  // Flushes the callbacks for change list loading and all directory loading.
185  void OnChangeListLoadComplete(FileError error);
186
187  // Called when the loading about_resource_loader_->UpdateAboutResource is
188  // completed.
189  void OnAboutResourceUpdated(google_apis::GDataErrorCode error,
190                              scoped_ptr<google_apis::AboutResource> resource);
191
192  // ================= Implementation for change list loading =================
193
194  // Part of LoadFromServerIfNeeded().
195  // Starts loading the change list since |start_changestamp|, or the full
196  // resource list if |start_changestamp| is zero.
197  void LoadChangeListFromServer(int64 start_changestamp);
198
199  // Part of LoadChangeListFromServer().
200  // Called when the entire change list is loaded.
201  void LoadChangeListFromServerAfterLoadChangeList(
202      scoped_ptr<google_apis::AboutResource> about_resource,
203      bool is_delta_update,
204      FileError error,
205      ScopedVector<ChangeList> change_lists);
206
207  // Part of LoadChangeListFromServer().
208  // Called when the resource metadata is updated.
209  void LoadChangeListFromServerAfterUpdate(
210      ChangeListProcessor* change_list_processor,
211      bool should_notify_changed_directories,
212      const base::Time& start_time,
213      FileError error);
214
215  EventLogger* logger_;  // Not owned.
216  scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
217  ResourceMetadata* resource_metadata_;  // Not owned.
218  JobScheduler* scheduler_;  // Not owned.
219  AboutResourceLoader* about_resource_loader_;  // Not owned.
220  LoaderController* loader_controller_;  // Not owned.
221  ObserverList<ChangeListLoaderObserver> observers_;
222  std::vector<FileOperationCallback> pending_load_callback_;
223  FileOperationCallback pending_update_check_callback_;
224
225  // Running feed fetcher.
226  scoped_ptr<FeedFetcher> change_feed_fetcher_;
227
228  // True if the full resource list is loaded (i.e. the resource metadata is
229  // stored locally).
230  bool loaded_;
231
232  // Note: This should remain the last member so it'll be destroyed and
233  // invalidate its weak pointers before any other members are destroyed.
234  base::WeakPtrFactory<ChangeListLoader> weak_ptr_factory_;
235  DISALLOW_COPY_AND_ASSIGN(ChangeListLoader);
236};
237
238}  // namespace internal
239}  // namespace drive
240
241#endif  // CHROME_BROWSER_CHROMEOS_DRIVE_CHANGE_LIST_LOADER_H_
242