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