change_list_loader.h revision 8bcbed890bc3ce4d7a057a8f32cab53fa534672e
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 <set> 10#include <string> 11#include <vector> 12 13#include "base/callback.h" 14#include "base/memory/ref_counted.h" 15#include "base/memory/scoped_ptr.h" 16#include "base/memory/scoped_vector.h" 17#include "base/observer_list.h" 18#include "base/time/time.h" 19#include "chrome/browser/chromeos/drive/file_errors.h" 20#include "chrome/browser/google_apis/gdata_errorcode.h" 21 22class GURL; 23 24namespace base { 25class SequencedTaskRunner; 26} // namespace base 27 28namespace google_apis { 29class AboutResource; 30class ResourceList; 31} // namespace google_apis 32 33namespace drive { 34 35class DriveServiceInterface; 36class JobScheduler; 37class ResourceEntry; 38 39namespace internal { 40 41class ChangeList; 42class ChangeListLoaderObserver; 43class ChangeListProcessor; 44class DirectoryFetchInfo; 45class ResourceMetadata; 46 47// Callback run as a response to SearchFromServer. 48typedef base::Callback<void(ScopedVector<ChangeList> change_lists, 49 FileError error)> LoadChangeListCallback; 50 51// ChangeListLoader is used to load the change list, the full resource list, 52// and directory contents, from WAPI (codename for Documents List API) 53// or Google Drive API. The class also updates the resource metadata with 54// the change list loaded from the server. 55// 56// Note that the difference between "resource list" and "change list" is 57// subtle hence the two words are often used interchangeably. To be precise, 58// "resource list" refers to metadata from the server when fetching the full 59// resource metadata, or fetching directory contents, whereas "change list" 60// refers to metadata from the server when fetching changes (delta). 61class ChangeListLoader { 62 public: 63 // Resource feed fetcher from the server. 64 class FeedFetcher; 65 66 ChangeListLoader(base::SequencedTaskRunner* blocking_task_runner, 67 ResourceMetadata* resource_metadata, 68 JobScheduler* scheduler, 69 DriveServiceInterface* drive_service); 70 ~ChangeListLoader(); 71 72 // Indicates whether there is a request for full resource list or change 73 // list fetching is in flight (i.e. directory contents fetching does not 74 // count). 75 bool IsRefreshing() const; 76 77 // Adds and removes the observer. 78 void AddObserver(ChangeListLoaderObserver* observer); 79 void RemoveObserver(ChangeListLoaderObserver* observer); 80 81 // Checks for updates on the server. Does nothing if the change list is now 82 // being loaded or refreshed. |callback| must not be null. 83 // Note: |callback| will be called if the check for updates actually 84 // runs, i.e. it may NOT be called if the checking is ignored. 85 void CheckForUpdates(const FileOperationCallback& callback); 86 87 // Starts the change list loading first from the cache. If loading from the 88 // cache is successful, runs |callback| immediately and starts checking 89 // server for updates in background. If loading from the cache is 90 // unsuccessful, starts loading from the server, and runs |callback| to tell 91 // the result to the caller when it is finished. 92 // 93 // If |directory_fetch_info| is not empty, the directory will be fetched 94 // first from the server, so the UI can show the directory contents 95 // instantly before the entire change list loading is complete. 96 // 97 // |callback| must not be null. 98 void LoadIfNeeded(const DirectoryFetchInfo& directory_fetch_info, 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 FileError error, 173 ScopedVector<ChangeList> change_lists); 174 175 // Part of LoadChangeListFromServer(). 176 // Called when the resource metadata is updated. 177 void LoadChangeListFromServerAfterUpdate(); 178 179 // ================= Implementation for directory loading ================= 180 181 // Compares the directory's changestamp and |last_known_remote_changestamp_|. 182 // Starts DoLoadDirectoryFromServer() if the local data is old and runs 183 // |callback| when finished. If it is up to date, calls back immediately. 184 void CheckChangestampAndLoadDirectoryIfNeeded( 185 const DirectoryFetchInfo& directory_fetch_info, 186 int64 local_changestamp, 187 const FileOperationCallback& callback); 188 189 // Loads the directory contents from server, and updates the local metadata. 190 // Runs |callback| when it is finished. 191 void DoLoadDirectoryFromServer(const DirectoryFetchInfo& directory_fetch_info, 192 const FileOperationCallback& callback); 193 194 // Part of DoLoadDirectoryFromServer() for the grand root ("/drive"). 195 void DoLoadGrandRootDirectoryFromServerAfterGetResourceEntryByPath( 196 const DirectoryFetchInfo& directory_fetch_info, 197 const FileOperationCallback& callback, 198 FileError error, 199 scoped_ptr<ResourceEntry> entry); 200 201 // Part of DoLoadDirectoryFromServer() for the grand root ("/drive"). 202 void DoLoadGrandRootDirectoryFromServerAfterGetAboutResource( 203 const DirectoryFetchInfo& directory_fetch_info, 204 const FileOperationCallback& callback, 205 google_apis::GDataErrorCode status, 206 scoped_ptr<google_apis::AboutResource> about_resource); 207 208 // Part of DoLoadDirectoryFromServer() for the grand root ("/drive"). 209 void DoLoadDirectoryFromServerAfterAddMyDrive( 210 const DirectoryFetchInfo& directory_fetch_info, 211 const FileOperationCallback& callback, 212 std::string* local_id, 213 FileError error); 214 215 // Part of DoLoadDirectoryFromServer() for a normal directory. 216 void DoLoadDirectoryFromServerAfterLoad( 217 const DirectoryFetchInfo& directory_fetch_info, 218 const FileOperationCallback& callback, 219 FeedFetcher* fetcher, 220 FileError error, 221 ScopedVector<ChangeList> change_lists); 222 223 // Part of DoLoadDirectoryFromServer(). 224 void DoLoadDirectoryFromServerAfterRefresh( 225 const DirectoryFetchInfo& directory_fetch_info, 226 const FileOperationCallback& callback, 227 const base::FilePath* directory_path, 228 FileError error); 229 230 // ================= Implementation for other stuff ================= 231 232 // Updates from the whole change list collected in |change_lists|. 233 // Record file statistics as UMA histograms. 234 // 235 // See comments at ChangeListProcessor::Apply() for 236 // |about_resource| and |is_delta_update|. 237 // |callback| must not be null. 238 void UpdateFromChangeList( 239 scoped_ptr<google_apis::AboutResource> about_resource, 240 ScopedVector<ChangeList> change_lists, 241 bool is_delta_update, 242 const base::Closure& callback); 243 244 // Part of UpdateFromChangeList(). 245 // Called when ChangeListProcessor::Apply() is complete. 246 // Notifies directory changes per the result of the change list processing. 247 void UpdateFromChangeListAfterApply( 248 ChangeListProcessor* change_list_processor, 249 bool should_notify, 250 base::Time start_time, 251 const base::Closure& callback, 252 FileError error); 253 254 scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_; 255 ResourceMetadata* resource_metadata_; // Not owned. 256 JobScheduler* scheduler_; // Not owned. 257 DriveServiceInterface* drive_service_; // Not owned. 258 ObserverList<ChangeListLoaderObserver> observers_; 259 typedef std::map<std::string, std::vector<FileOperationCallback> > 260 LoadCallbackMap; 261 LoadCallbackMap pending_load_callback_; 262 FileOperationCallback pending_update_check_callback_; 263 264 // Running feed fetcher. 265 scoped_ptr<FeedFetcher> change_feed_fetcher_; 266 267 // Set of the running feed fetcher for the fast fetch. 268 std::set<FeedFetcher*> fast_fetch_feed_fetcher_set_; 269 270 // The last known remote changestamp. Used to check if a directory 271 // changestamp is up-to-date for fast fetch. 272 int64 last_known_remote_changestamp_; 273 274 // The cache of the root_folder_id. 275 std::string root_folder_id_; 276 277 // True if the full resource list is loaded (i.e. the resource metadata is 278 // stored locally). 279 bool loaded_; 280 281 // Note: This should remain the last member so it'll be destroyed and 282 // invalidate its weak pointers before any other members are destroyed. 283 base::WeakPtrFactory<ChangeListLoader> weak_ptr_factory_; 284 DISALLOW_COPY_AND_ASSIGN(ChangeListLoader); 285}; 286 287} // namespace internal 288} // namespace drive 289 290#endif // CHROME_BROWSER_CHROMEOS_DRIVE_CHANGE_LIST_LOADER_H_ 291