summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
authorsatorux@chromium.org <satorux@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-08-01 19:30:12 +0000
committersatorux@chromium.org <satorux@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-08-01 19:30:12 +0000
commit991206b5f57758d935387c26eadff6ce3261fab2 (patch)
treee89043827391f48d1eef3382e4bfd62cf23b02cc /chrome
parent3173c2cf6b9ebf4ec99237168da0804c7881045c (diff)
downloadchromium_src-991206b5f57758d935387c26eadff6ce3261fab2.zip
chromium_src-991206b5f57758d935387c26eadff6ce3261fab2.tar.gz
chromium_src-991206b5f57758d935387c26eadff6ce3261fab2.tar.bz2
gdata: Move GDataWapiFeedParser to a set of new files
This change reduces ~400 lines from gdata_file_system.cc BUG=130669 TEST=none; just move code around. should not change the behaviors TBR=ben@chromium.org for chrome_browser.gypi Review URL: https://chromiumcodereview.appspot.com/10829118 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@149462 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r--chrome/browser/chromeos/gdata/gdata_file_system.cc386
-rw-r--r--chrome/browser/chromeos/gdata/gdata_file_system.h8
-rw-r--r--chrome/browser/chromeos/gdata/gdata_wapi_feed_processor.cc331
-rw-r--r--chrome/browser/chromeos/gdata/gdata_wapi_feed_processor.h111
-rw-r--r--chrome/chrome_browser.gypi2
5 files changed, 447 insertions, 391 deletions
diff --git a/chrome/browser/chromeos/gdata/gdata_file_system.cc b/chrome/browser/chromeos/gdata/gdata_file_system.cc
index b43da66..a13efb2 100644
--- a/chrome/browser/chromeos/gdata/gdata_file_system.cc
+++ b/chrome/browser/chromeos/gdata/gdata_file_system.cc
@@ -137,23 +137,6 @@ GDataFileError GDataToGDataFileError(GDataErrorCode status) {
//================================ Helper functions ============================
-// Recursively extracts the paths set of all sub-directories of |entry|.
-void GetChildDirectoryPaths(GDataEntry* entry,
- std::set<FilePath>* changed_dirs) {
- GDataDirectory* dir = entry->AsGDataDirectory();
- if (!dir)
- return;
-
- for (GDataDirectoryCollection::const_iterator it =
- dir->child_directories().begin();
- it != dir->child_directories().end(); ++it) {
- GDataDirectory* child_dir = it->second;
- changed_dirs->insert(child_dir->GetFilePath());
- GetChildDirectoryPaths(child_dir, changed_dirs);
- }
-}
-
-
// Invoked upon completion of TransferRegularFile initiated by Copy.
//
// |callback| is run on the thread represented by |relay_proxy|.
@@ -575,95 +558,6 @@ void RunGetEntryInfoWithFilePathCallback(
} // namespace
-// Struct used to record UMA stats with FeedToFileResourceMap().
-//
-// TODO(satorux): Move this to a new file. crbug.com/130669
-struct FeedToFileResourceMapUmaStats {
- FeedToFileResourceMapUmaStats()
- : num_regular_files(0),
- num_hosted_documents(0) {}
-
- typedef std::map<DocumentEntry::EntryKind, int> EntryKindToCountMap;
- int num_regular_files;
- int num_hosted_documents;
- EntryKindToCountMap num_files_with_entry_kind;
-};
-
-// GDataWapiFeedProcessor is used to process feeds from WAPI (codename for
-// Documents List API).
-//
-// TODO(satorux): Move this into a new file. crbug.com/130669
-class GDataWapiFeedProcessor {
- public:
- explicit GDataWapiFeedProcessor(GDataDirectoryService* directory_service)
- : directory_service_(directory_service) {
- }
-
- // Applies the documents feeds to the file system using |directory_service_|.
- //
- // |start_changestamp| determines the type of feed to process. The value is
- // set to zero for the root feeds, every other value is for the delta feeds.
- //
- // In the case of processing the root feeds |root_feed_changestamp| is used
- // as its initial changestamp value. The value comes from
- // AccountMetadataFeed.
- GDataFileError ApplyFeeds(const std::vector<DocumentFeed*>& feed_list,
- int start_changestamp,
- int root_feed_changestamp,
- std::set<FilePath>* changed_dirs);
-
- // Converts list of document feeds from collected feeds into
- // FileResourceIdMap.
- GDataFileError FeedToFileResourceMap(
- const std::vector<DocumentFeed*>& feed_list,
- FileResourceIdMap* file_map,
- int* feed_changestamp,
- FeedToFileResourceMapUmaStats* uma_stats);
-
- private:
- // Updates UMA histograms about file counts.
- void UpdateFileCountUmaHistograms(
- const FeedToFileResourceMapUmaStats& uma_stats) const;
-
- // Applies the pre-processed feed from |file_map| map onto the file system.
- // All entries in |file_map| will be erased (i.e. the map becomes empty),
- // and values are deleted.
- void ApplyFeedFromFileUrlMap(bool is_delta_feed,
- int feed_changestamp,
- FileResourceIdMap* file_map,
- std::set<FilePath>* changed_dirs);
-
- // Helper function for adding new |file| from the feed into |directory|. It
- // checks the type of file and updates |changed_dirs| if this file adding
- // operation needs to raise directory notification update. If file is being
- // added to |orphaned_dir_service| such notifications are not raised since
- // we ignore such files and don't add them to the file system now.
- static void AddEntryToDirectoryAndCollectChangedDirectories(
- GDataEntry* entry,
- GDataDirectory* directory,
- GDataDirectoryService* orphaned_dir_service,
- std::set<FilePath>* changed_dirs);
-
- // Helper function for removing |entry| from |directory|. If |entry| is a
- // directory too, it will collect all its children file paths into
- // |changed_dirs| as well.
- static void RemoveEntryFromDirectoryAndCollectChangedDirectories(
- GDataDirectory* directory,
- GDataEntry* entry,
- std::set<FilePath>* changed_dirs);
-
- // Finds directory where new |file| should be added to during feed processing.
- // |orphaned_entries_dir| collects files/dirs that don't have a parent in
- // either locally cached file system or in this new feed.
- GDataDirectory* FindDirectoryForNewEntry(
- GDataEntry* new_entry,
- const FileResourceIdMap& file_map,
- GDataDirectoryService* orphaned_dir_service);
-
- GDataDirectoryService* directory_service_;
- DISALLOW_COPY_AND_ASSIGN(GDataWapiFeedProcessor);
-};
-
// GDataFileSystem::GetDocumentsParams struct implementation.
struct GDataFileSystem::GetDocumentsParams {
GetDocumentsParams(int start_changestamp,
@@ -3391,179 +3285,6 @@ GDataFileError GDataFileSystem::UpdateFromFeed(
return error;
}
-GDataFileError GDataWapiFeedProcessor::ApplyFeeds(
- const std::vector<DocumentFeed*>& feed_list,
- int start_changestamp,
- int root_feed_changestamp,
- std::set<FilePath>* changed_dirs) {
- bool is_delta_feed = start_changestamp != 0;
-
- directory_service_->set_origin(FROM_SERVER);
-
- int delta_feed_changestamp = 0;
- FeedToFileResourceMapUmaStats uma_stats;
- FileResourceIdMap file_map;
- GDataFileError error = FeedToFileResourceMap(feed_list,
- &file_map,
- &delta_feed_changestamp,
- &uma_stats);
- if (error != GDATA_FILE_OK)
- return error;
-
- ApplyFeedFromFileUrlMap(
- is_delta_feed,
- is_delta_feed ? delta_feed_changestamp : root_feed_changestamp,
- &file_map,
- changed_dirs);
-
- // Shouldn't record histograms when processing delta feeds.
- if (!is_delta_feed)
- UpdateFileCountUmaHistograms(uma_stats);
-
- return GDATA_FILE_OK;
-}
-
-void GDataWapiFeedProcessor::UpdateFileCountUmaHistograms(
- const FeedToFileResourceMapUmaStats& uma_stats) const {
- const int num_total_files =
- uma_stats.num_hosted_documents + uma_stats.num_regular_files;
- UMA_HISTOGRAM_COUNTS("GData.NumberOfRegularFiles",
- uma_stats.num_regular_files);
- UMA_HISTOGRAM_COUNTS("GData.NumberOfHostedDocuments",
- uma_stats.num_hosted_documents);
- UMA_HISTOGRAM_COUNTS("GData.NumberOfTotalFiles", num_total_files);
- const std::vector<int> all_entry_kinds = DocumentEntry::GetAllEntryKinds();
- for (FeedToFileResourceMapUmaStats::EntryKindToCountMap::const_iterator iter =
- uma_stats.num_files_with_entry_kind.begin();
- iter != uma_stats.num_files_with_entry_kind.end();
- ++iter) {
- const DocumentEntry::EntryKind kind = iter->first;
- const int count = iter->second;
- for (int i = 0; i < count; ++i) {
- UMA_HISTOGRAM_CUSTOM_ENUMERATION(
- "GData.EntryKind", kind, all_entry_kinds);
- }
- }
-}
-
-void GDataWapiFeedProcessor::ApplyFeedFromFileUrlMap(
- bool is_delta_feed,
- int feed_changestamp,
- FileResourceIdMap* file_map,
- std::set<FilePath>* changed_dirs) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- DCHECK(changed_dirs);
-
- if (!is_delta_feed) { // Full update.
- directory_service_->root()->RemoveChildren();
- changed_dirs->insert(directory_service_->root()->GetFilePath());
- }
- directory_service_->set_largest_changestamp(feed_changestamp);
-
- scoped_ptr<GDataDirectoryService> orphaned_dir_service(
- new GDataDirectoryService);
- // Go through all entries generated by the feed and apply them to the local
- // snapshot of the file system.
- for (FileResourceIdMap::iterator it = file_map->begin();
- it != file_map->end();) {
- // Ensure that the entry is deleted, unless the ownership is explicitly
- // transferred by entry.release().
- scoped_ptr<GDataEntry> entry(it->second);
- DCHECK_EQ(it->first, entry->resource_id());
- // Erase the entry so the deleted entry won't be referenced.
- file_map->erase(it++);
-
- GDataEntry* old_entry =
- directory_service_->GetEntryByResourceId(entry->resource_id());
- GDataDirectory* dest_dir = NULL;
- if (entry->is_deleted()) { // Deleted file/directory.
- DVLOG(1) << "Removing file " << entry->base_name();
- if (!old_entry)
- continue;
-
- dest_dir = old_entry->parent();
- if (!dest_dir) {
- NOTREACHED();
- continue;
- }
- RemoveEntryFromDirectoryAndCollectChangedDirectories(
- dest_dir, old_entry, changed_dirs);
- } else if (old_entry) { // Change or move of existing entry.
- // Please note that entry rename is just a special case of change here
- // since name is just one of the properties that can change.
- DVLOG(1) << "Changed file " << entry->base_name();
- dest_dir = old_entry->parent();
- if (!dest_dir) {
- NOTREACHED();
- continue;
- }
- // Move children files over if we are dealing with directories.
- if (old_entry->AsGDataDirectory() && entry->AsGDataDirectory()) {
- entry->AsGDataDirectory()->TakeOverEntries(
- old_entry->AsGDataDirectory());
- }
- // Remove the old instance of this entry.
- RemoveEntryFromDirectoryAndCollectChangedDirectories(
- dest_dir, old_entry, changed_dirs);
- // Did we actually move the new file to another directory?
- if (dest_dir->resource_id() != entry->parent_resource_id()) {
- changed_dirs->insert(dest_dir->GetFilePath());
- dest_dir = FindDirectoryForNewEntry(entry.get(),
- *file_map,
- orphaned_dir_service.get());
- }
- DCHECK(dest_dir);
- AddEntryToDirectoryAndCollectChangedDirectories(
- entry.release(),
- dest_dir,
- orphaned_dir_service.get(),
- changed_dirs);
- } else { // Adding a new file.
- dest_dir = FindDirectoryForNewEntry(entry.get(),
- *file_map,
- orphaned_dir_service.get());
- DCHECK(dest_dir);
- AddEntryToDirectoryAndCollectChangedDirectories(
- entry.release(),
- dest_dir,
- orphaned_dir_service.get(),
- changed_dirs);
- }
-
- // Record changed directory if this was a delta feed and the parent
- // directory is already properly rooted within its parent.
- if (dest_dir && (dest_dir->parent() ||
- dest_dir == directory_service_->root()) &&
- dest_dir != orphaned_dir_service->root() && is_delta_feed) {
- changed_dirs->insert(dest_dir->GetFilePath());
- }
- }
- // All entry must be erased from the map.
- DCHECK(file_map->empty());
-}
-
-// static
-void GDataWapiFeedProcessor::AddEntryToDirectoryAndCollectChangedDirectories(
- GDataEntry* entry,
- GDataDirectory* directory,
- GDataDirectoryService* orphaned_dir_service,
- std::set<FilePath>* changed_dirs) {
- directory->AddEntry(entry);
- if (entry->AsGDataDirectory() && directory != orphaned_dir_service->root())
- changed_dirs->insert(entry->GetFilePath());
-}
-
-// static
-void GDataWapiFeedProcessor::
-RemoveEntryFromDirectoryAndCollectChangedDirectories(
- GDataDirectory* directory,
- GDataEntry* entry,
- std::set<FilePath>* changed_dirs) {
- // Get the list of all sub-directory paths, so we can notify their listeners
- // that they are smoked.
- GetChildDirectoryPaths(entry, changed_dirs);
- directory->RemoveEntry(entry);
-}
// static
void GDataFileSystem::RemoveStaleEntryOnUpload(const std::string& resource_id,
@@ -3578,113 +3299,6 @@ void GDataFileSystem::RemoveStaleEntryOnUpload(const std::string& resource_id,
}
}
-GDataDirectory* GDataWapiFeedProcessor::FindDirectoryForNewEntry(
- GDataEntry* new_entry,
- const FileResourceIdMap& file_map,
- GDataDirectoryService* orphaned_dir_service) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- GDataDirectory* dir = NULL;
- // Added file.
- const std::string& parent_id = new_entry->parent_resource_id();
- if (parent_id.empty()) {
- dir = directory_service_->root();
- DVLOG(1) << "Root parent for " << new_entry->base_name();
- } else {
- GDataEntry* entry = directory_service_->GetEntryByResourceId(parent_id);
- dir = entry ? entry->AsGDataDirectory() : NULL;
- if (!dir) {
- // The parent directory was also added with this set of feeds.
- FileResourceIdMap::const_iterator find_iter =
- file_map.find(parent_id);
- dir = (find_iter != file_map.end() &&
- find_iter->second) ?
- find_iter->second->AsGDataDirectory() : NULL;
- if (dir) {
- DVLOG(1) << "Found parent for " << new_entry->base_name()
- << " in file_map " << parent_id;
- } else {
- DVLOG(1) << "Adding orphan " << new_entry->GetFilePath().value();
- dir = orphaned_dir_service->root();
- }
- }
- }
- return dir;
-}
-
-GDataFileError GDataWapiFeedProcessor::FeedToFileResourceMap(
- const std::vector<DocumentFeed*>& feed_list,
- FileResourceIdMap* file_map,
- int* feed_changestamp,
- FeedToFileResourceMapUmaStats* uma_stats) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- DCHECK(uma_stats);
-
- GDataFileError error = GDATA_FILE_OK;
- uma_stats->num_regular_files = 0;
- uma_stats->num_hosted_documents = 0;
- uma_stats->num_files_with_entry_kind.clear();
- for (size_t i = 0; i < feed_list.size(); ++i) {
- const DocumentFeed* feed = feed_list[i];
-
- // Get upload url from the root feed. Links for all other collections will
- // be handled in GDatadirectory::FromDocumentEntry();
- if (i == 0) {
- const Link* root_feed_upload_link =
- feed->GetLinkByType(Link::RESUMABLE_CREATE_MEDIA);
- if (root_feed_upload_link)
- directory_service_->root()->set_upload_url(
- root_feed_upload_link->href());
- *feed_changestamp = feed->largest_changestamp();
- DCHECK_GE(*feed_changestamp, 0);
- }
-
- for (ScopedVector<DocumentEntry>::const_iterator iter =
- feed->entries().begin();
- iter != feed->entries().end(); ++iter) {
- DocumentEntry* doc = *iter;
- GDataEntry* entry = GDataEntry::FromDocumentEntry(
- NULL, doc, directory_service_);
- // Some document entries don't map into files (i.e. sites).
- if (!entry)
- continue;
- // Count the number of files.
- GDataFile* as_file = entry->AsGDataFile();
- if (as_file) {
- if (as_file->is_hosted_document())
- ++uma_stats->num_hosted_documents;
- else
- ++uma_stats->num_regular_files;
- ++uma_stats->num_files_with_entry_kind[as_file->kind()];
- }
-
- FileResourceIdMap::iterator map_entry =
- file_map->find(entry->resource_id());
-
- // An entry with the same self link may already exist, so we need to
- // release the existing GDataEntry instance before overwriting the
- // entry with another GDataEntry instance.
- if (map_entry != file_map->end()) {
- LOG(WARNING) << "Found duplicate file "
- << map_entry->second->base_name();
-
- delete map_entry->second;
- file_map->erase(map_entry);
- }
- file_map->insert(
- std::pair<std::string, GDataEntry*>(entry->resource_id(), entry));
- }
- }
-
- if (error != GDATA_FILE_OK) {
- // If the code above fails to parse a feed, any GDataEntry instance
- // added to |file_by_url| is not managed by a GDataDirectory instance,
- // so we need to explicitly release them here.
- STLDeleteValues(file_map);
- }
-
- return error;
-}
-
void GDataFileSystem::NotifyDirectoryChanged(const FilePath& directory_path) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
diff --git a/chrome/browser/chromeos/gdata/gdata_file_system.h b/chrome/browser/chromeos/gdata/gdata_file_system.h
index 705dacc..f4d3719 100644
--- a/chrome/browser/chromeos/gdata/gdata_file_system.h
+++ b/chrome/browser/chromeos/gdata/gdata_file_system.h
@@ -19,6 +19,7 @@
#include "chrome/browser/chromeos/gdata/gdata_file_system_interface.h"
#include "chrome/browser/chromeos/gdata/gdata_errorcode.h"
#include "chrome/browser/chromeos/gdata/gdata_files.h"
+#include "chrome/browser/chromeos/gdata/gdata_wapi_feed_processor.h"
#include "chrome/browser/prefs/pref_change_registrar.h"
#include "content/public/browser/notification_observer.h"
@@ -38,10 +39,6 @@ namespace {
struct LoadRootFeedParams;
} // namespace
-// TODO(satorux): Move this into a new file. crbug.com/130669
-typedef std::map<std::string /* resource_id */, GDataEntry*>
- FileResourceIdMap;
-
// The production implementation of GDataFileSystemInterface.
class GDataFileSystem : public GDataFileSystemInterface,
public content::NotificationObserver {
@@ -799,7 +796,8 @@ class GDataFileSystem : public GDataFileSystemInterface,
const FilePath& file_path);
void OnRequestDirectoryRefresh(GetDocumentsParams* params,
GDataFileError error);
- void RequestDirectoryRefreshByEntry(const FilePath& directory_path,
+ void RequestDirectoryRefreshByEntry(
+ const FilePath& directory_path,
const std::string& directory_resource_id,
const FileResourceIdMap& file_map,
GDataEntry* directory_entry);
diff --git a/chrome/browser/chromeos/gdata/gdata_wapi_feed_processor.cc b/chrome/browser/chromeos/gdata/gdata_wapi_feed_processor.cc
new file mode 100644
index 0000000..b349f93
--- /dev/null
+++ b/chrome/browser/chromeos/gdata/gdata_wapi_feed_processor.cc
@@ -0,0 +1,331 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/metrics/histogram.h"
+#include "chrome/browser/chromeos/gdata/gdata_files.h"
+#include "chrome/browser/chromeos/gdata/gdata_wapi_feed_processor.h"
+#include "content/public/browser/browser_thread.h"
+
+using content::BrowserThread;
+
+namespace gdata {
+
+namespace {
+
+// Recursively extracts the paths set of all sub-directories of |entry|.
+void GetChildDirectoryPaths(GDataEntry* entry,
+ std::set<FilePath>* changed_dirs) {
+ GDataDirectory* dir = entry->AsGDataDirectory();
+ if (!dir)
+ return;
+
+ for (GDataDirectoryCollection::const_iterator it =
+ dir->child_directories().begin();
+ it != dir->child_directories().end(); ++it) {
+ GDataDirectory* child_dir = it->second;
+ changed_dirs->insert(child_dir->GetFilePath());
+ GetChildDirectoryPaths(child_dir, changed_dirs);
+ }
+}
+
+} // namespace
+
+FeedToFileResourceMapUmaStats::FeedToFileResourceMapUmaStats()
+ : num_regular_files(0),
+ num_hosted_documents(0) {
+}
+
+FeedToFileResourceMapUmaStats::~FeedToFileResourceMapUmaStats() {
+}
+
+GDataWapiFeedProcessor::GDataWapiFeedProcessor(
+ GDataDirectoryService* directory_service)
+ : directory_service_(directory_service) {
+}
+
+GDataWapiFeedProcessor::~GDataWapiFeedProcessor() {
+}
+
+GDataFileError GDataWapiFeedProcessor::ApplyFeeds(
+ const std::vector<DocumentFeed*>& feed_list,
+ int start_changestamp,
+ int root_feed_changestamp,
+ std::set<FilePath>* changed_dirs) {
+ bool is_delta_feed = start_changestamp != 0;
+
+ directory_service_->set_origin(FROM_SERVER);
+
+ int delta_feed_changestamp = 0;
+ FeedToFileResourceMapUmaStats uma_stats;
+ FileResourceIdMap file_map;
+ GDataFileError error = FeedToFileResourceMap(feed_list,
+ &file_map,
+ &delta_feed_changestamp,
+ &uma_stats);
+ if (error != GDATA_FILE_OK)
+ return error;
+
+ ApplyFeedFromFileUrlMap(
+ is_delta_feed,
+ is_delta_feed ? delta_feed_changestamp : root_feed_changestamp,
+ &file_map,
+ changed_dirs);
+
+ // Shouldn't record histograms when processing delta feeds.
+ if (!is_delta_feed)
+ UpdateFileCountUmaHistograms(uma_stats);
+
+ return GDATA_FILE_OK;
+}
+
+void GDataWapiFeedProcessor::UpdateFileCountUmaHistograms(
+ const FeedToFileResourceMapUmaStats& uma_stats) const {
+ const int num_total_files =
+ uma_stats.num_hosted_documents + uma_stats.num_regular_files;
+ UMA_HISTOGRAM_COUNTS("GData.NumberOfRegularFiles",
+ uma_stats.num_regular_files);
+ UMA_HISTOGRAM_COUNTS("GData.NumberOfHostedDocuments",
+ uma_stats.num_hosted_documents);
+ UMA_HISTOGRAM_COUNTS("GData.NumberOfTotalFiles", num_total_files);
+ const std::vector<int> all_entry_kinds = DocumentEntry::GetAllEntryKinds();
+ for (FeedToFileResourceMapUmaStats::EntryKindToCountMap::const_iterator iter =
+ uma_stats.num_files_with_entry_kind.begin();
+ iter != uma_stats.num_files_with_entry_kind.end();
+ ++iter) {
+ const DocumentEntry::EntryKind kind = iter->first;
+ const int count = iter->second;
+ for (int i = 0; i < count; ++i) {
+ UMA_HISTOGRAM_CUSTOM_ENUMERATION(
+ "GData.EntryKind", kind, all_entry_kinds);
+ }
+ }
+}
+
+void GDataWapiFeedProcessor::ApplyFeedFromFileUrlMap(
+ bool is_delta_feed,
+ int feed_changestamp,
+ FileResourceIdMap* file_map,
+ std::set<FilePath>* changed_dirs) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK(changed_dirs);
+
+ if (!is_delta_feed) { // Full update.
+ directory_service_->root()->RemoveChildren();
+ changed_dirs->insert(directory_service_->root()->GetFilePath());
+ }
+ directory_service_->set_largest_changestamp(feed_changestamp);
+
+ scoped_ptr<GDataDirectoryService> orphaned_dir_service(
+ new GDataDirectoryService);
+ // Go through all entries generated by the feed and apply them to the local
+ // snapshot of the file system.
+ for (FileResourceIdMap::iterator it = file_map->begin();
+ it != file_map->end();) {
+ // Ensure that the entry is deleted, unless the ownership is explicitly
+ // transferred by entry.release().
+ scoped_ptr<GDataEntry> entry(it->second);
+ DCHECK_EQ(it->first, entry->resource_id());
+ // Erase the entry so the deleted entry won't be referenced.
+ file_map->erase(it++);
+
+ GDataEntry* old_entry =
+ directory_service_->GetEntryByResourceId(entry->resource_id());
+ GDataDirectory* dest_dir = NULL;
+ if (entry->is_deleted()) { // Deleted file/directory.
+ DVLOG(1) << "Removing file " << entry->base_name();
+ if (!old_entry)
+ continue;
+
+ dest_dir = old_entry->parent();
+ if (!dest_dir) {
+ NOTREACHED();
+ continue;
+ }
+ RemoveEntryFromDirectoryAndCollectChangedDirectories(
+ dest_dir, old_entry, changed_dirs);
+ } else if (old_entry) { // Change or move of existing entry.
+ // Please note that entry rename is just a special case of change here
+ // since name is just one of the properties that can change.
+ DVLOG(1) << "Changed file " << entry->base_name();
+ dest_dir = old_entry->parent();
+ if (!dest_dir) {
+ NOTREACHED();
+ continue;
+ }
+ // Move children files over if we are dealing with directories.
+ if (old_entry->AsGDataDirectory() && entry->AsGDataDirectory()) {
+ entry->AsGDataDirectory()->TakeOverEntries(
+ old_entry->AsGDataDirectory());
+ }
+ // Remove the old instance of this entry.
+ RemoveEntryFromDirectoryAndCollectChangedDirectories(
+ dest_dir, old_entry, changed_dirs);
+ // Did we actually move the new file to another directory?
+ if (dest_dir->resource_id() != entry->parent_resource_id()) {
+ changed_dirs->insert(dest_dir->GetFilePath());
+ dest_dir = FindDirectoryForNewEntry(entry.get(),
+ *file_map,
+ orphaned_dir_service.get());
+ }
+ DCHECK(dest_dir);
+ AddEntryToDirectoryAndCollectChangedDirectories(
+ entry.release(),
+ dest_dir,
+ orphaned_dir_service.get(),
+ changed_dirs);
+ } else { // Adding a new file.
+ dest_dir = FindDirectoryForNewEntry(entry.get(),
+ *file_map,
+ orphaned_dir_service.get());
+ DCHECK(dest_dir);
+ AddEntryToDirectoryAndCollectChangedDirectories(
+ entry.release(),
+ dest_dir,
+ orphaned_dir_service.get(),
+ changed_dirs);
+ }
+
+ // Record changed directory if this was a delta feed and the parent
+ // directory is already properly rooted within its parent.
+ if (dest_dir && (dest_dir->parent() ||
+ dest_dir == directory_service_->root()) &&
+ dest_dir != orphaned_dir_service->root() && is_delta_feed) {
+ changed_dirs->insert(dest_dir->GetFilePath());
+ }
+ }
+ // All entry must be erased from the map.
+ DCHECK(file_map->empty());
+}
+
+// static
+void GDataWapiFeedProcessor::AddEntryToDirectoryAndCollectChangedDirectories(
+ GDataEntry* entry,
+ GDataDirectory* directory,
+ GDataDirectoryService* orphaned_dir_service,
+ std::set<FilePath>* changed_dirs) {
+ directory->AddEntry(entry);
+ if (entry->AsGDataDirectory() && directory != orphaned_dir_service->root())
+ changed_dirs->insert(entry->GetFilePath());
+}
+
+// static
+void GDataWapiFeedProcessor::
+RemoveEntryFromDirectoryAndCollectChangedDirectories(
+ GDataDirectory* directory,
+ GDataEntry* entry,
+ std::set<FilePath>* changed_dirs) {
+ // Get the list of all sub-directory paths, so we can notify their listeners
+ // that they are smoked.
+ GetChildDirectoryPaths(entry, changed_dirs);
+ directory->RemoveEntry(entry);
+}
+
+GDataDirectory* GDataWapiFeedProcessor::FindDirectoryForNewEntry(
+ GDataEntry* new_entry,
+ const FileResourceIdMap& file_map,
+ GDataDirectoryService* orphaned_dir_service) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ GDataDirectory* dir = NULL;
+ // Added file.
+ const std::string& parent_id = new_entry->parent_resource_id();
+ if (parent_id.empty()) {
+ dir = directory_service_->root();
+ DVLOG(1) << "Root parent for " << new_entry->base_name();
+ } else {
+ GDataEntry* entry = directory_service_->GetEntryByResourceId(parent_id);
+ dir = entry ? entry->AsGDataDirectory() : NULL;
+ if (!dir) {
+ // The parent directory was also added with this set of feeds.
+ FileResourceIdMap::const_iterator find_iter =
+ file_map.find(parent_id);
+ dir = (find_iter != file_map.end() &&
+ find_iter->second) ?
+ find_iter->second->AsGDataDirectory() : NULL;
+ if (dir) {
+ DVLOG(1) << "Found parent for " << new_entry->base_name()
+ << " in file_map " << parent_id;
+ } else {
+ DVLOG(1) << "Adding orphan " << new_entry->GetFilePath().value();
+ dir = orphaned_dir_service->root();
+ }
+ }
+ }
+ return dir;
+}
+
+GDataFileError GDataWapiFeedProcessor::FeedToFileResourceMap(
+ const std::vector<DocumentFeed*>& feed_list,
+ FileResourceIdMap* file_map,
+ int* feed_changestamp,
+ FeedToFileResourceMapUmaStats* uma_stats) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK(uma_stats);
+
+ GDataFileError error = GDATA_FILE_OK;
+ uma_stats->num_regular_files = 0;
+ uma_stats->num_hosted_documents = 0;
+ uma_stats->num_files_with_entry_kind.clear();
+ for (size_t i = 0; i < feed_list.size(); ++i) {
+ const DocumentFeed* feed = feed_list[i];
+
+ // Get upload url from the root feed. Links for all other collections will
+ // be handled in GDatadirectory::FromDocumentEntry();
+ if (i == 0) {
+ const Link* root_feed_upload_link =
+ feed->GetLinkByType(Link::RESUMABLE_CREATE_MEDIA);
+ if (root_feed_upload_link)
+ directory_service_->root()->set_upload_url(
+ root_feed_upload_link->href());
+ *feed_changestamp = feed->largest_changestamp();
+ DCHECK_GE(*feed_changestamp, 0);
+ }
+
+ for (ScopedVector<DocumentEntry>::const_iterator iter =
+ feed->entries().begin();
+ iter != feed->entries().end(); ++iter) {
+ DocumentEntry* doc = *iter;
+ GDataEntry* entry = GDataEntry::FromDocumentEntry(
+ NULL, doc, directory_service_);
+ // Some document entries don't map into files (i.e. sites).
+ if (!entry)
+ continue;
+ // Count the number of files.
+ GDataFile* as_file = entry->AsGDataFile();
+ if (as_file) {
+ if (as_file->is_hosted_document())
+ ++uma_stats->num_hosted_documents;
+ else
+ ++uma_stats->num_regular_files;
+ ++uma_stats->num_files_with_entry_kind[as_file->kind()];
+ }
+
+ FileResourceIdMap::iterator map_entry =
+ file_map->find(entry->resource_id());
+
+ // An entry with the same self link may already exist, so we need to
+ // release the existing GDataEntry instance before overwriting the
+ // entry with another GDataEntry instance.
+ if (map_entry != file_map->end()) {
+ LOG(WARNING) << "Found duplicate file "
+ << map_entry->second->base_name();
+
+ delete map_entry->second;
+ file_map->erase(map_entry);
+ }
+ file_map->insert(
+ std::pair<std::string, GDataEntry*>(entry->resource_id(), entry));
+ }
+ }
+
+ if (error != GDATA_FILE_OK) {
+ // If the code above fails to parse a feed, any GDataEntry instance
+ // added to |file_by_url| is not managed by a GDataDirectory instance,
+ // so we need to explicitly release them here.
+ STLDeleteValues(file_map);
+ }
+
+ return error;
+}
+
+} // namespace gdata
diff --git a/chrome/browser/chromeos/gdata/gdata_wapi_feed_processor.h b/chrome/browser/chromeos/gdata/gdata_wapi_feed_processor.h
new file mode 100644
index 0000000..9bb8465
--- /dev/null
+++ b/chrome/browser/chromeos/gdata/gdata_wapi_feed_processor.h
@@ -0,0 +1,111 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_GDATA_GDATA_WAPI_FEED_PROCESSOR_H_
+#define CHROME_BROWSER_CHROMEOS_GDATA_GDATA_WAPI_FEED_PROCESSOR_H_
+
+#include <map>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "base/file_path.h"
+#include "chrome/browser/chromeos/gdata/gdata_errorcode.h"
+#include "chrome/browser/chromeos/gdata/gdata_wapi_parser.h"
+
+namespace gdata {
+
+class GDataDirectory;
+class GDataDirectoryService;
+class GDataEntry;
+
+typedef std::map<std::string /* resource_id */, GDataEntry*>
+FileResourceIdMap;
+
+// Struct used to record UMA stats with FeedToFileResourceMap().
+struct FeedToFileResourceMapUmaStats {
+ FeedToFileResourceMapUmaStats();
+ ~FeedToFileResourceMapUmaStats();
+
+ typedef std::map<DocumentEntry::EntryKind, int> EntryKindToCountMap;
+ int num_regular_files;
+ int num_hosted_documents;
+ EntryKindToCountMap num_files_with_entry_kind;
+};
+
+// GDataWapiFeedProcessor is used to process feeds from WAPI (codename for
+// Documents List API).
+class GDataWapiFeedProcessor {
+ public:
+ explicit GDataWapiFeedProcessor(GDataDirectoryService* directory_service);
+ ~GDataWapiFeedProcessor();
+
+ // Applies the documents feeds to the file system using |directory_service_|.
+ //
+ // |start_changestamp| determines the type of feed to process. The value is
+ // set to zero for the root feeds, every other value is for the delta feeds.
+ //
+ // In the case of processing the root feeds |root_feed_changestamp| is used
+ // as its initial changestamp value. The value comes from
+ // AccountMetadataFeed.
+ GDataFileError ApplyFeeds(const std::vector<DocumentFeed*>& feed_list,
+ int start_changestamp,
+ int root_feed_changestamp,
+ std::set<FilePath>* changed_dirs);
+
+ // Converts list of document feeds from collected feeds into
+ // FileResourceIdMap.
+ GDataFileError FeedToFileResourceMap(
+ const std::vector<DocumentFeed*>& feed_list,
+ FileResourceIdMap* file_map,
+ int* feed_changestamp,
+ FeedToFileResourceMapUmaStats* uma_stats);
+
+ private:
+ // Updates UMA histograms about file counts.
+ void UpdateFileCountUmaHistograms(
+ const FeedToFileResourceMapUmaStats& uma_stats) const;
+
+ // Applies the pre-processed feed from |file_map| map onto the file system.
+ // All entries in |file_map| will be erased (i.e. the map becomes empty),
+ // and values are deleted.
+ void ApplyFeedFromFileUrlMap(bool is_delta_feed,
+ int feed_changestamp,
+ FileResourceIdMap* file_map,
+ std::set<FilePath>* changed_dirs);
+
+ // Helper function for adding new |file| from the feed into |directory|. It
+ // checks the type of file and updates |changed_dirs| if this file adding
+ // operation needs to raise directory notification update. If file is being
+ // added to |orphaned_dir_service| such notifications are not raised since
+ // we ignore such files and don't add them to the file system now.
+ static void AddEntryToDirectoryAndCollectChangedDirectories(
+ GDataEntry* entry,
+ GDataDirectory* directory,
+ GDataDirectoryService* orphaned_dir_service,
+ std::set<FilePath>* changed_dirs);
+
+ // Helper function for removing |entry| from |directory|. If |entry| is a
+ // directory too, it will collect all its children file paths into
+ // |changed_dirs| as well.
+ static void RemoveEntryFromDirectoryAndCollectChangedDirectories(
+ GDataDirectory* directory,
+ GDataEntry* entry,
+ std::set<FilePath>* changed_dirs);
+
+ // Finds directory where new |file| should be added to during feed processing.
+ // |orphaned_entries_dir| collects files/dirs that don't have a parent in
+ // either locally cached file system or in this new feed.
+ GDataDirectory* FindDirectoryForNewEntry(
+ GDataEntry* new_entry,
+ const FileResourceIdMap& file_map,
+ GDataDirectoryService* orphaned_dir_service);
+
+ GDataDirectoryService* directory_service_; // Not owned by the class.
+ DISALLOW_COPY_AND_ASSIGN(GDataWapiFeedProcessor);
+};
+
+} // namespace gdata
+
+#endif // CHROME_BROWSER_CHROMEOS_GDATA_GDATA_WAPI_FEED_PROCESSOR_H_
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index b5a0882..c5afe43 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -585,6 +585,8 @@
'browser/chromeos/gdata/gdata_uploader.h',
'browser/chromeos/gdata/gdata_util.cc',
'browser/chromeos/gdata/gdata_util.h',
+ 'browser/chromeos/gdata/gdata_wapi_feed_processor.cc',
+ 'browser/chromeos/gdata/gdata_wapi_feed_processor.h',
'browser/chromeos/gdata/gdata_wapi_parser.cc',
'browser/chromeos/gdata/gdata_wapi_parser.h',
'browser/chromeos/gdata/operations_base.cc',