Home | History | Annotate | Download | only in drive
      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 <map>
      9 #include <string>
     10 #include <vector>
     11 
     12 #include "base/callback.h"
     13 #include "base/memory/ref_counted.h"
     14 #include "base/memory/scoped_ptr.h"
     15 #include "base/memory/scoped_vector.h"
     16 #include "base/observer_list.h"
     17 #include "base/time/time.h"
     18 #include "chrome/browser/chromeos/drive/file_errors.h"
     19 #include "chrome/browser/google_apis/gdata_errorcode.h"
     20 
     21 class GURL;
     22 
     23 namespace base {
     24 class SequencedTaskRunner;
     25 }  // namespace base
     26 
     27 namespace google_apis {
     28 class AboutResource;
     29 class ResourceList;
     30 }  // namespace google_apis
     31 
     32 namespace drive {
     33 
     34 class DirectoryFetchInfo;
     35 class JobScheduler;
     36 class ResourceEntry;
     37 
     38 namespace internal {
     39 
     40 class ChangeList;
     41 class ChangeListLoaderObserver;
     42 class ChangeListProcessor;
     43 class ResourceMetadata;
     44 
     45 // Callback run as a response to SearchFromServer.
     46 typedef base::Callback<void(ScopedVector<ChangeList> change_lists,
     47                             FileError error)> LoadChangeListCallback;
     48 
     49 // ChangeListLoader is used to load the change list, the full resource list,
     50 // and directory contents, from WAPI (codename for Documents List API)
     51 // or Google Drive API.  The class also updates the resource metadata with
     52 // the change list loaded from the server.
     53 //
     54 // Note that the difference between "resource list" and "change list" is
     55 // subtle hence the two words are often used interchangeably. To be precise,
     56 // "resource list" refers to metadata from the server when fetching the full
     57 // resource metadata, or fetching directory contents, whereas "change list"
     58 // refers to metadata from the server when fetching changes (delta).
     59 class ChangeListLoader {
     60  public:
     61   ChangeListLoader(base::SequencedTaskRunner* blocking_task_runner,
     62                    ResourceMetadata* resource_metadata,
     63                    JobScheduler* scheduler);
     64   ~ChangeListLoader();
     65 
     66   // Indicates whether there is a request for full resource list or change
     67   // list fetching is in flight (i.e. directory contents fetching does not
     68   // count).
     69   bool IsRefreshing() const;
     70 
     71   // Adds and removes the observer.
     72   void AddObserver(ChangeListLoaderObserver* observer);
     73   void RemoveObserver(ChangeListLoaderObserver* observer);
     74 
     75   // Checks for updates on the server. Does nothing if the change list is now
     76   // being loaded or refreshed. |callback| must not be null.
     77   // Note: |callback| will be called if the check for updates actually
     78   // runs, i.e. it may NOT be called if the checking is ignored.
     79   void CheckForUpdates(const FileOperationCallback& callback);
     80 
     81   // Starts the change list loading first from the cache. If loading from the
     82   // cache is successful, runs |callback| immediately and starts checking
     83   // server for updates in background. If loading from the cache is
     84   // unsuccessful, starts loading from the server, and runs |callback| to tell
     85   // the result to the caller when it is finished.
     86   //
     87   // If |directory_fetch_info| is not empty, the directory will be fetched
     88   // first from the server, so the UI can show the directory contents
     89   // instantly before the entire change list loading is complete.
     90   //
     91   // |callback| must not be null.
     92   void LoadIfNeeded(const DirectoryFetchInfo& directory_fetch_info,
     93                     const FileOperationCallback& callback);
     94 
     95   // Loads the directory content from the server, without comparing the
     96   // changestamps. The purpose of this function is to update thumbnail URLs
     97   // in the directory which can stale over time.
     98   void LoadDirectoryFromServer(const std::string& directory_resource_id,
     99                                const FileOperationCallback& callback);
    100 
    101  private:
    102   // Starts the resource metadata loading and calls |callback| when it's
    103   // done. |directory_fetch_info| is used for fast fetch. If there is already
    104   // a loading job in-flight for |directory_fetch_info|, just append the
    105   // |callback| to the callback queue of the already running job.
    106   void Load(const DirectoryFetchInfo& directory_fetch_info,
    107             const FileOperationCallback& callback);
    108 
    109   // Part of Load(). DoInitialLoad() is called if it is the first time to Load.
    110   // Otherwise DoUpdateLoad() is used. The difference of two cases are:
    111   // - When we could load from cache, DoInitialLoad runs callback immediately
    112   //   and further operations (check changestamp and load from server if needed)
    113   //   in background.
    114   // - Even when |directory_fetch_info| is set, DoInitialLoad runs change list
    115   //   loading after directory loading is finished.
    116   void DoInitialLoad(const DirectoryFetchInfo& directory_fetch_info,
    117                      int64 local_changestamp);
    118   void DoUpdateLoad(const DirectoryFetchInfo& directory_fetch_info,
    119                     int64 local_changestamp);
    120 
    121   // Part of Load().
    122   // This function should be called when the change list load is complete.
    123   // Flushes the callbacks for change list loading and all directory loading.
    124   void OnChangeListLoadComplete(FileError error);
    125 
    126   // Part of Load().
    127   // This function should be called when the directory load is complete.
    128   // Flushes the callbacks waiting for the directory to be loaded.
    129   void OnDirectoryLoadComplete(const DirectoryFetchInfo& directory_fetch_info,
    130                                FileError error);
    131 
    132   // ================= Implementation for change list loading =================
    133 
    134   // Initiates the change list loading from the server when |local_changestamp|
    135   // is older than the server changestamp. If |directory_fetch_info| is set,
    136   // do directory loading before change list loading.
    137   void LoadFromServerIfNeeded(const DirectoryFetchInfo& directory_fetch_info,
    138                               int64 local_changestamp);
    139 
    140   // Part of LoadFromServerIfNeeded().
    141   // Called after GetAboutResource() for getting remote changestamp is complete.
    142   void LoadFromServerIfNeededAfterGetAbout(
    143       const DirectoryFetchInfo& directory_fetch_info,
    144       int64 local_changestamp,
    145       google_apis::GDataErrorCode status,
    146       scoped_ptr<google_apis::AboutResource> about_resource);
    147 
    148   // Part of LoadFromServerIfNeeded().
    149   // When LoadFromServerIfNeeded is called with |directory_fetch_info| for a
    150   // specific directory, it tries to load the directory before loading the
    151   // content of full filesystem. This method is called after directory loading
    152   // is finished, and proceeds to the normal pass: LoadChangeListServer.
    153   void LoadFromServerIfNeededAfterLoadDirectory(
    154       const DirectoryFetchInfo& directory_fetch_info,
    155       scoped_ptr<google_apis::AboutResource> about_resource,
    156       int64 start_changestamp,
    157       FileError error);
    158 
    159   // Part of LoadFromServerIfNeeded().
    160   // Starts loading the change list since |start_changestamp|, or the full
    161   // resource list if |start_changestamp| is zero. For full update, the
    162   // largest_change_id and root_folder_id from |about_resource| will be used.
    163   void LoadChangeListFromServer(
    164       scoped_ptr<google_apis::AboutResource> about_resource,
    165       int64 start_changestamp);
    166 
    167   // Part of LoadChangeListFromServer().
    168   // Called when the entire change list is loaded.
    169   void LoadChangeListFromServerAfterLoadChangeList(
    170       scoped_ptr<google_apis::AboutResource> about_resource,
    171       bool is_delta_update,
    172       ScopedVector<ChangeList> change_lists,
    173       FileError error);
    174 
    175   // Part of LoadChangeListFromServer().
    176   // Called when the resource metadata is updated.
    177   void LoadChangeListFromServerAfterUpdate();
    178 
    179   // ================= Implementation for directory loading =================
    180 
    181   // Part of LoadDirectoryFromServer(), called after the current remote
    182   // changestamp is obtained as |about_resource|.
    183   void LoadDirectoryFromServerAfterGetAbout(
    184       const std::string& directory_resource_id,
    185       const FileOperationCallback& callback,
    186       google_apis::GDataErrorCode status,
    187       scoped_ptr<google_apis::AboutResource> about_resource);
    188 
    189   // Compares the directory's changestamp and |last_known_remote_changestamp_|.
    190   // Starts DoLoadDirectoryFromServer() if the local data is old and runs
    191   // |callback| when finished. If it is up to date, calls back immediately.
    192   void CheckChangestampAndLoadDirectoryIfNeeded(
    193       const DirectoryFetchInfo& directory_fetch_info,
    194       int64 local_changestamp,
    195       const FileOperationCallback& callback);
    196 
    197   // Loads the directory contents from server, and updates the local metadata.
    198   // Runs |callback| when it is finished.
    199   void DoLoadDirectoryFromServer(const DirectoryFetchInfo& directory_fetch_info,
    200                                  const FileOperationCallback& callback);
    201 
    202   // Part of DoLoadDirectoryFromServer() for the grand root ("/drive").
    203   void DoLoadGrandRootDirectoryFromServerAfterGetResourceEntryByPath(
    204       const DirectoryFetchInfo& directory_fetch_info,
    205       const FileOperationCallback& callback,
    206       FileError error,
    207       scoped_ptr<ResourceEntry> entry);
    208 
    209   // Part of DoLoadDirectoryFromServer() for the grand root ("/drive").
    210   void DoLoadGrandRootDirectoryFromServerAfterGetAboutResource(
    211       const DirectoryFetchInfo& directory_fetch_info,
    212       const FileOperationCallback& callback,
    213       google_apis::GDataErrorCode status,
    214       scoped_ptr<google_apis::AboutResource> about_resource);
    215 
    216   // Part of DoLoadDirectoryFromServer() for a normal directory.
    217   void DoLoadDirectoryFromServerAfterLoad(
    218       const DirectoryFetchInfo& directory_fetch_info,
    219       const FileOperationCallback& callback,
    220       ScopedVector<ChangeList> change_lists,
    221       FileError error);
    222 
    223   // Part of DoLoadDirectoryFromServer().
    224   void DoLoadDirectoryFromServerAfterRefresh(
    225       const DirectoryFetchInfo& directory_fetch_info,
    226       const FileOperationCallback& callback,
    227       FileError error,
    228       const base::FilePath& directory_path);
    229 
    230   // ================= Implementation for other stuff =================
    231 
    232   // This function is used to handle pagenation for the result from
    233   // JobScheduler::GetChangeList/GetAllResourceList/ContinueGetResourceList/
    234   // GetResourceListInDirectory().
    235   //
    236   // After all the change lists are fetched, |callback| will be invoked with
    237   // the collected change lists.
    238   void OnGetChangeList(ScopedVector<ChangeList> change_lists,
    239                        const LoadChangeListCallback& callback,
    240                        base::TimeTicks start_time,
    241                        google_apis::GDataErrorCode status,
    242                        scoped_ptr<google_apis::ResourceList> resource_list);
    243 
    244   // Updates from the whole change list collected in |change_lists|.
    245   // Record file statistics as UMA histograms.
    246   //
    247   // See comments at ChangeListProcessor::Apply() for
    248   // |about_resource| and |is_delta_update|.
    249   // |callback| must not be null.
    250   void UpdateFromChangeList(
    251       scoped_ptr<google_apis::AboutResource> about_resource,
    252       ScopedVector<ChangeList> change_lists,
    253       bool is_delta_update,
    254       const base::Closure& callback);
    255 
    256   // Part of UpdateFromChangeList().
    257   // Called when ChangeListProcessor::Apply() is complete.
    258   // Notifies directory changes per the result of the change list processing.
    259   void UpdateFromChangeListAfterApply(
    260       ChangeListProcessor* change_list_processor,
    261       bool should_notify,
    262       base::Time start_time,
    263       const base::Closure& callback);
    264 
    265   scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
    266   ResourceMetadata* resource_metadata_;  // Not owned.
    267   JobScheduler* scheduler_;  // Not owned.
    268   ObserverList<ChangeListLoaderObserver> observers_;
    269   typedef std::map<std::string, std::vector<FileOperationCallback> >
    270       LoadCallbackMap;
    271   LoadCallbackMap pending_load_callback_;
    272   FileOperationCallback pending_update_check_callback_;
    273 
    274   // The last known remote changestamp. Used to check if a directory
    275   // changestamp is up-to-date for fast fetch.
    276   int64 last_known_remote_changestamp_;
    277 
    278   // True if the full resource list is loaded (i.e. the resource metadata is
    279   // stored locally).
    280   bool loaded_;
    281 
    282   // Note: This should remain the last member so it'll be destroyed and
    283   // invalidate its weak pointers before any other members are destroyed.
    284   base::WeakPtrFactory<ChangeListLoader> weak_ptr_factory_;
    285   DISALLOW_COPY_AND_ASSIGN(ChangeListLoader);
    286 };
    287 
    288 }  // namespace internal
    289 }  // namespace drive
    290 
    291 #endif  // CHROME_BROWSER_CHROMEOS_DRIVE_CHANGE_LIST_LOADER_H_
    292