diff options
author | tim@chromium.org <tim@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-12-17 19:18:53 +0000 |
---|---|---|
committer | tim@chromium.org <tim@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-12-17 19:18:53 +0000 |
commit | 210007c4ad5225b2b5ca56ee3f009167c9705ac0 (patch) | |
tree | 80c4f0a2376914ec49cffb964408e1173cffd144 /chrome/browser/sync | |
parent | b3300dc30deee1992729a78bc5c053c7a136d6a7 (diff) | |
download | chromium_src-210007c4ad5225b2b5ca56ee3f009167c9705ac0.zip chromium_src-210007c4ad5225b2b5ca56ee3f009167c9705ac0.tar.gz chromium_src-210007c4ad5225b2b5ca56ee3f009167c9705ac0.tar.bz2 |
Generic ModelAssociator based on prototype from earlier CL.
BUG=29831
TEST=ProfileSyncServiceTest
Review URL: http://codereview.chromium.org/507039
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@34857 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/sync')
-rw-r--r-- | chrome/browser/sync/glue/bookmark_change_processor.cc | 33 | ||||
-rw-r--r-- | chrome/browser/sync/glue/bookmark_change_processor.h | 11 | ||||
-rw-r--r-- | chrome/browser/sync/glue/bookmark_model_associator.cc | 33 | ||||
-rw-r--r-- | chrome/browser/sync/glue/bookmark_model_associator.h | 17 | ||||
-rw-r--r-- | chrome/browser/sync/glue/change_processor.h | 2 | ||||
-rw-r--r-- | chrome/browser/sync/glue/model_associator.h | 148 | ||||
-rw-r--r-- | chrome/browser/sync/profile_sync_service.cc | 66 | ||||
-rw-r--r-- | chrome/browser/sync/profile_sync_service.h | 23 | ||||
-rw-r--r-- | chrome/browser/sync/profile_sync_service_unittest.cc | 57 |
9 files changed, 261 insertions, 129 deletions
diff --git a/chrome/browser/sync/glue/bookmark_change_processor.cc b/chrome/browser/sync/glue/bookmark_change_processor.cc index 916669f..a4e2b47 100644 --- a/chrome/browser/sync/glue/bookmark_change_processor.cc +++ b/chrome/browser/sync/glue/bookmark_change_processor.cc @@ -35,6 +35,7 @@ void BookmarkChangeProcessor::StopImpl() { DCHECK(bookmark_model_); bookmark_model_->RemoveObserver(this); bookmark_model_ = NULL; + model_associator_ = NULL; } void BookmarkChangeProcessor::UpdateSyncNodeProperties( @@ -68,7 +69,7 @@ void BookmarkChangeProcessor::EncodeFavicon(const BookmarkNode* src, void BookmarkChangeProcessor::RemoveOneSyncNode( sync_api::WriteTransaction* trans, const BookmarkNode* node) { sync_api::WriteNode sync_node(trans); - if (!model_associator_->InitSyncNodeFromBookmarkId(node->id(), &sync_node)) { + if (!model_associator_->InitSyncNodeFromChromeId(node->id(), &sync_node)) { error_handler()->OnUnrecoverableError(); return; } @@ -132,7 +133,7 @@ void BookmarkChangeProcessor::BookmarkNodeAdded(BookmarkModel* model, // Acquire a scoped write lock via a transaction. sync_api::WriteTransaction trans(share_handle()); - CreateSyncNode(parent, model, index, &trans, model_associator_.get(), + CreateSyncNode(parent, model, index, &trans, model_associator_, error_handler()); } @@ -187,7 +188,7 @@ void BookmarkChangeProcessor::BookmarkNodeChanged(BookmarkModel* model, // Lookup the sync node that's associated with |node|. sync_api::WriteNode sync_node(&trans); - if (!model_associator_->InitSyncNodeFromBookmarkId(node->id(), &sync_node)) { + if (!model_associator_->InitSyncNodeFromChromeId(node->id(), &sync_node)) { error_handler()->OnUnrecoverableError(); return; } @@ -195,7 +196,7 @@ void BookmarkChangeProcessor::BookmarkNodeChanged(BookmarkModel* model, UpdateSyncNodeProperties(node, model, &sync_node); DCHECK_EQ(sync_node.GetIsFolder(), node->is_folder()); - DCHECK_EQ(model_associator_->GetBookmarkNodeFromSyncId( + DCHECK_EQ(model_associator_->GetChromeNodeFromSyncId( sync_node.GetParentId()), node->GetParent()); // This node's index should be one more than the predecessor's index. @@ -221,13 +222,13 @@ void BookmarkChangeProcessor::BookmarkNodeMoved(BookmarkModel* model, // Lookup the sync node that's associated with |child|. sync_api::WriteNode sync_node(&trans); - if (!model_associator_->InitSyncNodeFromBookmarkId(child->id(), &sync_node)) { + if (!model_associator_->InitSyncNodeFromChromeId(child->id(), &sync_node)) { error_handler()->OnUnrecoverableError(); return; } if (!PlaceSyncNode(MOVE, new_parent, new_index, &trans, &sync_node, - model_associator_.get(), error_handler())) { + model_associator_, error_handler())) { error_handler()->OnUnrecoverableError(); return; } @@ -249,16 +250,16 @@ void BookmarkChangeProcessor::BookmarkNodeChildrenReordered( // children of the corresponding sync node. for (int i = 0; i < node->GetChildCount(); ++i) { sync_api::WriteNode sync_child(&trans); - if (!model_associator_->InitSyncNodeFromBookmarkId(node->GetChild(i)->id(), - &sync_child)) { + if (!model_associator_->InitSyncNodeFromChromeId(node->GetChild(i)->id(), + &sync_child)) { error_handler()->OnUnrecoverableError(); return; } DCHECK_EQ(sync_child.GetParentId(), - model_associator_->GetSyncIdFromBookmarkId(node->id())); + model_associator_->GetSyncIdFromChromeId(node->id())); if (!PlaceSyncNode(MOVE, node, i, &trans, &sync_child, - model_associator_.get(), error_handler())) { + model_associator_, error_handler())) { error_handler()->OnUnrecoverableError(); return; } @@ -271,7 +272,7 @@ bool BookmarkChangeProcessor::PlaceSyncNode(MoveOrCreate operation, sync_api::WriteNode* dst, BookmarkModelAssociator* associator, UnrecoverableErrorHandler* error_handler) { sync_api::ReadNode sync_parent(trans); - if (!associator->InitSyncNodeFromBookmarkId(parent->id(), &sync_parent)) { + if (!associator->InitSyncNodeFromChromeId(parent->id(), &sync_parent)) { LOG(WARNING) << "Parent lookup failed"; error_handler->OnUnrecoverableError(); return false; @@ -291,7 +292,7 @@ bool BookmarkChangeProcessor::PlaceSyncNode(MoveOrCreate operation, // Find the bookmark model predecessor, and insert after it. const BookmarkNode* prev = parent->GetChild(index - 1); sync_api::ReadNode sync_prev(trans); - if (!associator->InitSyncNodeFromBookmarkId(prev->id(), &sync_prev)) { + if (!associator->InitSyncNodeFromChromeId(prev->id(), &sync_prev)) { LOG(WARNING) << "Predecessor lookup failed"; return false; } @@ -324,7 +325,7 @@ int BookmarkChangeProcessor::CalculateBookmarkModelInsertionIndex( // Otherwise, insert after the predecessor bookmark node. const BookmarkNode* predecessor = - model_associator_->GetBookmarkNodeFromSyncId(predecessor_id); + model_associator_->GetChromeNodeFromSyncId(predecessor_id); DCHECK(predecessor); DCHECK_EQ(predecessor->GetParent(), parent); return parent->IndexOfChild(predecessor) + 1; @@ -367,7 +368,7 @@ void BookmarkChangeProcessor::ApplyChangesFromSyncModel( const BookmarkNode* foster_parent = NULL; for (int i = 0; i < change_count; ++i) { const BookmarkNode* dst = - model_associator_->GetBookmarkNodeFromSyncId(changes[i].id); + model_associator_->GetChromeNodeFromSyncId(changes[i].id); // Ignore changes to the permanent top-level nodes. We only care about // their children. if ((dst == model->GetBookmarkBarNode()) || (dst == model->other_node())) @@ -429,7 +430,7 @@ const BookmarkNode* BookmarkChangeProcessor::CreateOrUpdateBookmarkNode( sync_api::BaseNode* src, BookmarkModel* model) { const BookmarkNode* parent = - model_associator_->GetBookmarkNodeFromSyncId(src->GetParentId()); + model_associator_->GetChromeNodeFromSyncId(src->GetParentId()); if (!parent) { DLOG(WARNING) << "Could not find parent of node being added/updated." << " Node title: " << src->GetTitle() @@ -437,7 +438,7 @@ const BookmarkNode* BookmarkChangeProcessor::CreateOrUpdateBookmarkNode( return NULL; } int index = CalculateBookmarkModelInsertionIndex(parent, src); - const BookmarkNode* dst = model_associator_->GetBookmarkNodeFromSyncId( + const BookmarkNode* dst = model_associator_->GetChromeNodeFromSyncId( src->GetId()); if (!dst) { dst = CreateBookmarkNode(src, parent, model, index); diff --git a/chrome/browser/sync/glue/bookmark_change_processor.h b/chrome/browser/sync/glue/bookmark_change_processor.h index 496b85f..0847919 100644 --- a/chrome/browser/sync/glue/bookmark_change_processor.h +++ b/chrome/browser/sync/glue/bookmark_change_processor.h @@ -23,16 +23,13 @@ namespace browser_sync { // All operations and use of this class are from the UI thread. // This is currently bookmarks specific. class BookmarkChangeProcessor : public BookmarkModelObserver, - public ChangeProcessor { + public ChangeProcessor { public: explicit BookmarkChangeProcessor(UnrecoverableErrorHandler* error_handler); virtual ~BookmarkChangeProcessor() {} void set_model_associator(BookmarkModelAssociator* model_associator) { - model_associator_.reset(model_associator); - } - virtual ModelAssociator* GetModelAssociator() { - return model_associator_.get(); + model_associator_ = model_associator; } // BookmarkModelObserver implementation. @@ -162,7 +159,9 @@ class BookmarkChangeProcessor : public BookmarkModelObserver, // The bookmark model we are processing changes from. Non-NULL when // |running_| is true. BookmarkModel* bookmark_model_; - scoped_ptr<BookmarkModelAssociator> model_associator_; + + // The two models should be associated according to this ModelAssociator. + BookmarkModelAssociator* model_associator_; DISALLOW_COPY_AND_ASSIGN(BookmarkChangeProcessor); }; diff --git a/chrome/browser/sync/glue/bookmark_model_associator.cc b/chrome/browser/sync/glue/bookmark_model_associator.cc index 7e220bf..d6ad0ab 100644 --- a/chrome/browser/sync/glue/bookmark_model_associator.cc +++ b/chrome/browser/sync/glue/bookmark_model_associator.cc @@ -165,22 +165,22 @@ bool BookmarkModelAssociator::DisassociateModels() { return true; } -int64 BookmarkModelAssociator::GetSyncIdFromBookmarkId(int64 node_id) const { +int64 BookmarkModelAssociator::GetSyncIdFromChromeId(int64 node_id) { BookmarkIdToSyncIdMap::const_iterator iter = id_map_.find(node_id); return iter == id_map_.end() ? sync_api::kInvalidId : iter->second; } -const BookmarkNode* BookmarkModelAssociator::GetBookmarkNodeFromSyncId( +const BookmarkNode* BookmarkModelAssociator::GetChromeNodeFromSyncId( int64 sync_id) { SyncIdToBookmarkNodeMap::const_iterator iter = id_map_inverse_.find(sync_id); return iter == id_map_inverse_.end() ? NULL : iter->second; } -bool BookmarkModelAssociator::InitSyncNodeFromBookmarkId( +bool BookmarkModelAssociator::InitSyncNodeFromChromeId( int64 node_id, sync_api::BaseNode* sync_node) { DCHECK(sync_node); - int64 sync_id = GetSyncIdFromBookmarkId(node_id); + int64 sync_id = GetSyncIdFromChromeId(node_id); if (sync_id == sync_api::kInvalidId) return false; if (!sync_node->InitByIdLookup(sync_id)) @@ -251,8 +251,7 @@ bool BookmarkModelAssociator::SyncModelHasUserCreatedNodes() { } bool BookmarkModelAssociator::NodesMatch(const BookmarkNode* bookmark, - const sync_api::BaseNode* sync_node) - const { + const sync_api::BaseNode* sync_node) const { if (bookmark->GetTitle() != sync_node->GetTitle()) return false; if (bookmark->is_folder() != sync_node->GetIsFolder()) @@ -270,7 +269,7 @@ bool BookmarkModelAssociator::NodesMatch(const BookmarkNode* bookmark, bool BookmarkModelAssociator::AssociateTaggedPermanentNode( const BookmarkNode* permanent_node, const std::string&tag) { // Do nothing if |permanent_node| is already initialized and associated. - int64 sync_id = GetSyncIdFromBookmarkId(permanent_node->id()); + int64 sync_id = GetSyncIdFromChromeId(permanent_node->id()); if (sync_id != sync_api::kInvalidId) return true; if (!GetSyncIdForTaggedNode(tag, &sync_id)) @@ -281,7 +280,7 @@ bool BookmarkModelAssociator::AssociateTaggedPermanentNode( } bool BookmarkModelAssociator::GetSyncIdForTaggedNode(const std::string& tag, - int64* sync_id) { + int64* sync_id) { sync_api::ReadTransaction trans( sync_service_->backend()->GetUserShareHandle()); sync_api::ReadNode sync_node(&trans); @@ -340,10 +339,10 @@ bool BookmarkModelAssociator::BuildAssociations() { << "are running against an out-of-date server?"; return false; } - int64 bookmark_bar_sync_id = GetSyncIdFromBookmarkId( + int64 bookmark_bar_sync_id = GetSyncIdFromChromeId( model->GetBookmarkBarNode()->id()); DCHECK(bookmark_bar_sync_id != sync_api::kInvalidId); - int64 other_bookmarks_sync_id = GetSyncIdFromBookmarkId( + int64 other_bookmarks_sync_id = GetSyncIdFromChromeId( model->other_node()->id()); DCHECK(other_bookmarks_sync_id != sync_api::kInvalidId); @@ -366,7 +365,7 @@ bool BookmarkModelAssociator::BuildAssociations() { // Only folder nodes are pushed on to the stack. DCHECK(sync_parent.GetIsFolder()); - const BookmarkNode* parent_node = GetBookmarkNodeFromSyncId(sync_parent_id); + const BookmarkNode* parent_node = GetChromeNodeFromSyncId(sync_parent_id); DCHECK(parent_node->is_folder()); BookmarkNodeFinder node_finder(parent_node); @@ -385,10 +384,10 @@ bool BookmarkModelAssociator::BuildAssociations() { if (child_node) { model->Move(child_node, parent_node, index); // Set the favicon for bookmark node from sync node or vice versa. - if (BookmarkChangeProcessor::SetBookmarkFavicon(&sync_child_node, - child_node, sync_service_->profile())) { + if (BookmarkChangeProcessor::SetBookmarkFavicon( + &sync_child_node, child_node, sync_service_->profile())) { BookmarkChangeProcessor::SetSyncNodeFavicon(child_node, model, - &sync_child_node); + &sync_child_node); } } else { // Create a new bookmark node for the sync node. @@ -409,8 +408,8 @@ bool BookmarkModelAssociator::BuildAssociations() { // So the children starting from index in the parent bookmark node are the // ones that are not present in the parent sync node. So create them. for (int i = index; i < parent_node->GetChildCount(); ++i) { - sync_child_id = BookmarkChangeProcessor::CreateSyncNode(parent_node, - model, i, &trans, this, sync_service_); + sync_child_id = BookmarkChangeProcessor::CreateSyncNode( + parent_node, model, i, &trans, this, sync_service_); if (parent_node->GetChild(i)->is_folder()) dfs_stack.push(sync_child_id); } @@ -450,7 +449,7 @@ void BookmarkModelAssociator::PersistAssociations() { sync_service_->OnUnrecoverableError(); return; } - const BookmarkNode* node = GetBookmarkNodeFromSyncId(sync_id); + const BookmarkNode* node = GetChromeNodeFromSyncId(sync_id); if (node) sync_node.SetExternalId(node->id()); else diff --git a/chrome/browser/sync/glue/bookmark_model_associator.h b/chrome/browser/sync/glue/bookmark_model_associator.h index d722367..0a4fcb97 100644 --- a/chrome/browser/sync/glue/bookmark_model_associator.h +++ b/chrome/browser/sync/glue/bookmark_model_associator.h @@ -31,11 +31,15 @@ class BookmarkChangeProcessor; // * Algorithm to associate bookmark model and sync model. // * Methods to get a bookmark node for a given sync node and vice versa. // * Persisting model associations and loading them back. -class BookmarkModelAssociator : public ModelAssociator { +class BookmarkModelAssociator + : public PerDataTypeAssociatorInterface<BookmarkNode, int64> { public: + static const ModelType model_type() { return MODEL_TYPE_BOOKMARKS; } explicit BookmarkModelAssociator(ProfileSyncService* sync_service); virtual ~BookmarkModelAssociator() { } + // AssociatorInterface implementation. + // // AssociateModels iterates through both the sync and the browser // bookmark model, looking for matched pairs of items. For any pairs it // finds, it will call AssociateSyncID. For any unmatched items, @@ -60,21 +64,22 @@ class BookmarkModelAssociator : public ModelAssociator { // Returns sync id for the given bookmark node id. // Returns sync_api::kInvalidId if the sync node is not found for the given // bookmark node id. - int64 GetSyncIdFromBookmarkId(int64 node_id) const; + virtual int64 GetSyncIdFromChromeId(int64 node_id); // Returns the bookmark node for the given sync id. // Returns NULL if no bookmark node is found for the given sync id. - const BookmarkNode* GetBookmarkNodeFromSyncId(int64 sync_id); + virtual const BookmarkNode* GetChromeNodeFromSyncId(int64 sync_id); // Initializes the given sync node from the given bookmark node id. // Returns false if no sync node was found for the given bookmark node id or // if the initialization of sync node fails. - bool InitSyncNodeFromBookmarkId(int64 node_id, sync_api::BaseNode* sync_node); + virtual bool InitSyncNodeFromChromeId(int64 node_id, + sync_api::BaseNode* sync_node); // Associates the given bookmark node with the given sync id. - void Associate(const BookmarkNode* node, int64 sync_id); + virtual void Associate(const BookmarkNode* node, int64 sync_id); // Remove the association that corresponds to the given sync id. - void Disassociate(int64 sync_id); + virtual void Disassociate(int64 sync_id); protected: // Stores the id of the node with the given tag in |sync_id|. diff --git a/chrome/browser/sync/glue/change_processor.h b/chrome/browser/sync/glue/change_processor.h index 2537636..21052a7 100644 --- a/chrome/browser/sync/glue/change_processor.h +++ b/chrome/browser/sync/glue/change_processor.h @@ -35,8 +35,6 @@ class ChangeProcessor { void Stop(); bool IsRunning() const { return running_; } - virtual ModelAssociator* GetModelAssociator() = 0; - // Changes have been applied to the backend model and are ready to be // applied to the frontend model. See syncapi.h for detailed instructions on // how to interpret and process |changes|. diff --git a/chrome/browser/sync/glue/model_associator.h b/chrome/browser/sync/glue/model_associator.h index 7e09be2..43de828 100644 --- a/chrome/browser/sync/glue/model_associator.h +++ b/chrome/browser/sync/glue/model_associator.h @@ -5,15 +5,35 @@ #ifndef CHROME_BROWSER_SYNC_GLUE_MODEL_ASSOCIATOR_H_ #define CHROME_BROWSER_SYNC_GLUE_MODEL_ASSOCIATOR_H_ -#include "chrome/browser/sync/engine/syncapi.h" +#include <map> +#include <string> + +#include "base/basictypes.h" +#include "base/logging.h" +#include "base/stl_util-inl.h" + +namespace sync_api { +class BaseNode; +class BaseTransaction; +class ReadNode; +} + +class ProfileSyncService; namespace browser_sync { -// Contains all model association related logic to associate the chrome model -// with the sync model. -class ModelAssociator { +// An enum identifying the various types of browser object models we know how +// to "associate" with the sync engine view of the world. +enum ModelType { + MODEL_TYPE_BOOKMARKS, +}; + +// This represents the fundamental operations used for model association that +// are common to all ModelAssociators and do not depend on types of the models +// being associated. +class AssociatorInterface { public: - virtual ~ModelAssociator() {} + virtual ~AssociatorInterface() {} // Iterates through both the sync and the chrome model looking for matched // pairs of items. After successful completion, the models should be identical @@ -32,6 +52,124 @@ class ModelAssociator { virtual bool ChromeModelHasUserCreatedNodes() = 0; }; +// In addition to the generic methods, association can refer to operations +// that depend on the types of the actual IDs we are associating and the +// underlying node type in the browser. We collect these into a templatized +// interface that encapsulates everything you need to implement to have a model +// associator for a specific data type. +// This template is appropriate for data types where a Node* makes sense for +// referring to a particular item. If we encounter a type that does not fit +// in this world, we may want to have several PerDataType templates. +template <class Node, class IDType> +class PerDataTypeAssociatorInterface : public AssociatorInterface { + public: + virtual ~PerDataTypeAssociatorInterface() {} + // Returns sync id for the given chrome model id. + // Returns sync_api::kInvalidId if the sync node is not found for the given + // chrome id. + virtual int64 GetSyncIdFromChromeId(IDType id) = 0; + + // Returns the chrome node for the given sync id. + // Returns NULL if no node is found for the given sync id. + virtual const Node* GetChromeNodeFromSyncId(int64 sync_id) = 0; + + // Initializes the given sync node from the given chrome node id. + // Returns false if no sync node was found for the given chrome node id or + // if the initialization of sync node fails. + virtual bool InitSyncNodeFromChromeId(IDType node_id, + sync_api::BaseNode* sync_node) = 0; + + // Associates the given chrome node with the given sync id. + virtual void Associate(const Node* node, int64 sync_id) = 0; + + // Remove the association that corresponds to the given sync id. + virtual void Disassociate(int64 sync_id) = 0; +}; + +// Contains all model association related logic to associate the chrome model +// with the sync model. +class ModelAssociator : public AssociatorInterface { + public: + explicit ModelAssociator(ProfileSyncService* sync_service) + : sync_service_(sync_service) { + DCHECK(sync_service); + } + ~ModelAssociator() { CleanupAllAssociators(); } + + // AssociatorInterface implementation. These are aggregated across all known + // data types (for example, if both a Bookmarks and Preferences association + // implementation is registered, AssociateModels() will associate both + // Bookmarks and Preferences with the sync model). + virtual bool AssociateModels() { + bool success = true; + for (ImplMap::iterator i = impl_map_.begin(); i != impl_map_.end(); ++i) + success &= i->second->AssociateModels(); + return success; + } + + virtual bool DisassociateModels() { + bool success = true; + for (ImplMap::iterator i = impl_map_.begin(); i != impl_map_.end(); ++i) + success &= i->second->DisassociateModels(); + return success; + } + + virtual bool SyncModelHasUserCreatedNodes() { + for (ImplMap::iterator i = impl_map_.begin(); i != impl_map_.end(); ++i) { + if (i->second->SyncModelHasUserCreatedNodes()) + return true; + } + return false; + } + + virtual bool ChromeModelHasUserCreatedNodes() { + for (ImplMap::iterator i = impl_map_.begin(); i != impl_map_.end(); ++i) { + if (i->second->ChromeModelHasUserCreatedNodes()) + return true; + } + return false; + } + + // Call to enable model association for a particular data type by registering + // a type specific association implementation. This will unregister any + // previous implementation for the same model type, to enforce only one impl + // for a given type at a time. + template <class Impl> + void CreateAndRegisterPerDataTypeImpl() { + UnregisterPerDataTypeImpl<Impl>(); + impl_map_[Impl::model_type()] = new Impl(sync_service_); + } + + // Call to disable model association for a particular data type by + // unregistering the specific association implementation. + template <class Impl> + void UnregisterPerDataTypeImpl() { + ImplMap::iterator it = impl_map_.find(Impl::model_type()); + if (it == impl_map_.end()) + return; + delete it->second; + impl_map_.erase(it); + } + + template <class Impl> + Impl* GetImpl() { + ImplMap::const_iterator it = impl_map_.find(Impl::model_type()); + // The cast is safe because of the static model_type() pattern. + return reinterpret_cast<Impl*>(it->second); + } + + void CleanupAllAssociators() { + STLDeleteValues(&impl_map_); + } + + private: + ProfileSyncService* sync_service_; + + typedef std::map<ModelType, AssociatorInterface*> ImplMap; + ImplMap impl_map_; + DISALLOW_COPY_AND_ASSIGN(ModelAssociator); +}; + } // namespace browser_sync #endif // CHROME_BROWSER_SYNC_GLUE_MODEL_ASSOCIATOR_H_ diff --git a/chrome/browser/sync/profile_sync_service.cc b/chrome/browser/sync/profile_sync_service.cc index fc5abdd..ae824c28 100644 --- a/chrome/browser/sync/profile_sync_service.cc +++ b/chrome/browser/sync/profile_sync_service.cc @@ -13,7 +13,6 @@ #include "base/file_path.h" #include "base/file_util.h" #include "base/histogram.h" -#include "base/stl_util-inl.h" #include "base/string_util.h" #include "base/time.h" #include "chrome/browser/bookmarks/bookmark_utils.h" @@ -22,6 +21,7 @@ #include "chrome/browser/profile.h" #include "chrome/browser/sync/engine/syncapi.h" #include "chrome/browser/sync/glue/bookmark_change_processor.h" +#include "chrome/browser/sync/glue/bookmark_model_associator.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/notification_service.h" #include "chrome/common/notification_type.h" @@ -35,6 +35,7 @@ using browser_sync::BookmarkChangeProcessor; using browser_sync::BookmarkModelAssociator; using browser_sync::ChangeProcessor; +using browser_sync::ModelAssociator; using browser_sync::SyncBackendHost; typedef GoogleServiceAuthError AuthError; @@ -46,16 +47,21 @@ ProfileSyncService::ProfileSyncService(Profile* profile) : last_auth_error_(AuthError::None()), profile_(profile), sync_service_url_(kSyncServerUrl), + ALLOW_THIS_IN_INITIALIZER_LIST(model_associator_( + new ModelAssociator(this))), backend_initialized_(false), expecting_first_run_auth_needed_event_(false), is_auth_in_progress_(false), ALLOW_THIS_IN_INITIALIZER_LIST(wizard_(this)), unrecoverable_error_detected_(false) { - BookmarkChangeProcessor* processor = new BookmarkChangeProcessor(this); - change_processors_.insert(processor); - // TODO: Move this back to StartUp - BookmarkModelAssociator* associator = new BookmarkModelAssociator(this); - processor->set_model_associator(associator); + + // Register associator impls for all currently synced data types, and hook + // them up to the associated change processors. If you add a new data type + // and want that data type to be synced, call CreateGlue with appropriate + // association and change processing implementations. + + // Bookmarks. + InstallGlue<BookmarkModelAssociator, BookmarkChangeProcessor>(); } ProfileSyncService::~ProfileSyncService() { @@ -63,13 +69,6 @@ ProfileSyncService::~ProfileSyncService() { STLDeleteElements(&change_processors_); } -void ProfileSyncService::set_change_processor( - browser_sync::ChangeProcessor* change_processor) { - STLDeleteElements(&change_processors_); - change_processors_.clear(); - change_processors_.insert(change_processor); -} - void ProfileSyncService::Initialize() { InitSettings(); RegisterPreferences(); @@ -182,10 +181,8 @@ void ProfileSyncService::Shutdown(bool sync_disabled) { backend_.reset(); // Clear all associations and throw away the association manager instance. - for (std::set<ChangeProcessor*>::const_iterator it = - change_processors_.begin(); it != change_processors_.end(); ++it) { - (*it)->GetModelAssociator()->DisassociateModels(); - } + model_associator_->DisassociateModels(); + model_associator_->CleanupAllAssociators(); // Clear various flags. is_auth_in_progress_ = false; @@ -229,13 +226,8 @@ bool ProfileSyncService::MergeAndSyncAcceptanceNeeded() const { if (profile_->GetPrefs()->GetBoolean(prefs::kSyncHasSetupCompleted)) return false; - for (std::set<ChangeProcessor*>::const_iterator it = - change_processors_.begin(); it != change_processors_.end(); ++it) { - if ((*it)->GetModelAssociator()->ChromeModelHasUserCreatedNodes() && - (*it)->GetModelAssociator()->SyncModelHasUserCreatedNodes()) - return true; - } - return false; + return model_associator_->ChromeModelHasUserCreatedNodes() && + model_associator_->SyncModelHasUserCreatedNodes(); } bool ProfileSyncService::HasSyncSetupCompleted() const { @@ -390,17 +382,10 @@ void ProfileSyncService::OnUserSubmittedAuth( void ProfileSyncService::OnUserAcceptedMergeAndSync() { base::TimeTicks start_time = base::TimeTicks::Now(); - bool not_first_run = false; - bool merge_success = true; - for (std::set<ChangeProcessor*>::const_iterator it = - change_processors_.begin(); it != change_processors_.end(); ++it) { - not_first_run |= (*it)->GetModelAssociator()-> - SyncModelHasUserCreatedNodes(); - // TODO(sync): Figure out what do to when a single associator fails. - // http://crbug.com/30038 - merge_success &= (*it)->GetModelAssociator()-> - AssociateModels(); - } + // TODO(sync): Figure out what do to when a single associator fails. + // http://crbug.com/30038 + bool not_first_run = model_associator_->SyncModelHasUserCreatedNodes(); + bool merge_success = model_associator_->AssociateModels(); UMA_HISTOGRAM_MEDIUM_TIMES("Sync.UserPerceivedBookmarkAssociation", base::TimeTicks::Now() - start_time); if (!merge_success) { @@ -453,15 +438,8 @@ void ProfileSyncService::StartProcessingChangesIfReady() { // We're ready to merge the models. base::TimeTicks start_time = base::TimeTicks::Now(); - bool not_first_run = false; - bool merge_success = true; - for (std::set<ChangeProcessor*>::const_iterator it = - change_processors_.begin(); it != change_processors_.end(); ++it) { - not_first_run |= (*it)->GetModelAssociator()-> - SyncModelHasUserCreatedNodes(); - merge_success &= (*it)->GetModelAssociator()-> - AssociateModels(); - } + bool not_first_run = model_associator_->SyncModelHasUserCreatedNodes(); + bool merge_success = model_associator_->AssociateModels(); UMA_HISTOGRAM_TIMES("Sync.BookmarkAssociationTime", base::TimeTicks::Now() - start_time); if (!merge_success) { diff --git a/chrome/browser/sync/profile_sync_service.h b/chrome/browser/sync/profile_sync_service.h index 7a0dab08..794831b 100644 --- a/chrome/browser/sync/profile_sync_service.h +++ b/chrome/browser/sync/profile_sync_service.h @@ -229,8 +229,24 @@ class ProfileSyncService : public NotificationObserver, // Tests need to override this. virtual void InitializeBackend(); - // Tests need this. - void set_change_processor(browser_sync::ChangeProcessor* change_processor); + template <class AssociatorImpl, class ChangeProcessorImpl> + void InstallGlue() { + model_associator_->CreateAndRegisterPerDataTypeImpl<AssociatorImpl>(); + // TODO(tim): Keep a map instead of a set so we can register/unregister + // data type specific ChangeProcessors, once we have more than one. + STLDeleteElements(processors()); + ChangeProcessorImpl* processor = new ChangeProcessorImpl(this); + change_processors_.insert(processor); + processor->set_model_associator( + model_associator_->GetImpl<AssociatorImpl>()); + } + + browser_sync::ModelAssociator* associator() { + return model_associator_.get(); + } + std::set<browser_sync::ChangeProcessor*>* processors() { + return &change_processors_; + } // We keep track of the last auth error observed so we can cover up the first // "expected" auth failure from observers. @@ -281,6 +297,9 @@ class ProfileSyncService : public NotificationObserver, // other threads. scoped_ptr<browser_sync::SyncBackendHost> backend_; + // Model association manager instance. + scoped_ptr<browser_sync::ModelAssociator> model_associator_; + // The change processors that handle the different data types. std::set<browser_sync::ChangeProcessor*> change_processors_; diff --git a/chrome/browser/sync/profile_sync_service_unittest.cc b/chrome/browser/sync/profile_sync_service_unittest.cc index ea575a9..a122053 100644 --- a/chrome/browser/sync/profile_sync_service_unittest.cc +++ b/chrome/browser/sync/profile_sync_service_unittest.cc @@ -95,10 +95,7 @@ class TestProfileSyncService : public ProfileSyncService { } virtual void InitializeBackend() { - change_processor_ = new BookmarkChangeProcessor(this); - model_associator_ = new TestModelAssociator(this); - change_processor_->set_model_associator(model_associator_); - set_change_processor(change_processor_); + InstallGlue<TestModelAssociator, BookmarkChangeProcessor>(); TestHttpBridgeFactory* factory = new TestHttpBridgeFactory(); TestHttpBridgeFactory* factory2 = new TestHttpBridgeFactory(); backend()->InitializeForTestMode(L"testuser", factory, factory2); @@ -120,14 +117,12 @@ class TestProfileSyncService : public ProfileSyncService { } BookmarkChangeProcessor* change_processor() { - return change_processor_; + // TODO(tim): The service should have a way to get specific processors. + return static_cast<BookmarkChangeProcessor*>(*processors()->begin()); } BookmarkModelAssociator* model_associator() { - return model_associator_; + return associator()->GetImpl<BookmarkModelAssociator>(); } - - BookmarkChangeProcessor* change_processor_; - BookmarkModelAssociator* model_associator_; }; // FakeServerChange constructs a list of sync_api::ChangeRecords while modifying @@ -297,12 +292,12 @@ class ProfileSyncServiceTest : public testing::Test { BookmarkModelAssociator* associator() { DCHECK(service_.get()); - return service_->model_associator_; + return service_->model_associator(); } BookmarkChangeProcessor* change_processor() { DCHECK(service_.get()); - return service_->change_processor_; + return service_->change_processor(); } void StartSyncService() { @@ -338,12 +333,12 @@ class ProfileSyncServiceTest : public testing::Test { void ExpectSyncerNodeMatching(sync_api::BaseTransaction* trans, const BookmarkNode* bnode) { sync_api::ReadNode gnode(trans); - EXPECT_TRUE(associator()->InitSyncNodeFromBookmarkId(bnode->id(), &gnode)); + EXPECT_TRUE(associator()->InitSyncNodeFromChromeId(bnode->id(), &gnode)); // Non-root node titles and parents must match. if (bnode != model_->GetBookmarkBarNode() && bnode != model_->other_node()) { EXPECT_EQ(bnode->GetTitle(), gnode.GetTitle()); - EXPECT_EQ(associator()->GetBookmarkNodeFromSyncId(gnode.GetParentId()), + EXPECT_EQ(associator()->GetChromeNodeFromSyncId(gnode.GetParentId()), bnode->GetParent()); } EXPECT_EQ(bnode->is_folder(), gnode.GetIsFolder()); @@ -358,8 +353,8 @@ class ProfileSyncServiceTest : public testing::Test { const BookmarkNode* bprev = bnode->GetParent()->GetChild(browser_index - 1); sync_api::ReadNode gprev(trans); - ASSERT_TRUE(associator()->InitSyncNodeFromBookmarkId(bprev->id(), - &gprev)); + ASSERT_TRUE(associator()->InitSyncNodeFromChromeId(bprev->id(), + &gprev)); EXPECT_EQ(gnode.GetPredecessorId(), gprev.GetId()); EXPECT_EQ(gnode.GetParentId(), gprev.GetParentId()); } @@ -369,8 +364,8 @@ class ProfileSyncServiceTest : public testing::Test { const BookmarkNode* bnext = bnode->GetParent()->GetChild(browser_index + 1); sync_api::ReadNode gnext(trans); - ASSERT_TRUE(associator()->InitSyncNodeFromBookmarkId(bnext->id(), - &gnext)); + ASSERT_TRUE(associator()->InitSyncNodeFromChromeId(bnext->id(), + &gnext)); EXPECT_EQ(gnode.GetSuccessorId(), gnext.GetId()); EXPECT_EQ(gnode.GetParentId(), gnext.GetParentId()); } @@ -388,50 +383,50 @@ class ProfileSyncServiceTest : public testing::Test { int64 sync_id) { EXPECT_TRUE(sync_id); const BookmarkNode* bnode = - associator()->GetBookmarkNodeFromSyncId(sync_id); + associator()->GetChromeNodeFromSyncId(sync_id); ASSERT_TRUE(bnode); - int64 id = associator()->GetSyncIdFromBookmarkId(bnode->id()); + int64 id = associator()->GetSyncIdFromChromeId(bnode->id()); EXPECT_EQ(id, sync_id); ExpectSyncerNodeMatching(trans, bnode); } void ExpectBrowserNodeUnknown(int64 sync_id) { - EXPECT_FALSE(associator()->GetBookmarkNodeFromSyncId(sync_id)); + EXPECT_FALSE(associator()->GetChromeNodeFromSyncId(sync_id)); } void ExpectBrowserNodeKnown(int64 sync_id) { - EXPECT_TRUE(associator()->GetBookmarkNodeFromSyncId(sync_id)); + EXPECT_TRUE(associator()->GetChromeNodeFromSyncId(sync_id)); } void ExpectSyncerNodeKnown(const BookmarkNode* node) { - int64 sync_id = associator()->GetSyncIdFromBookmarkId(node->id()); + int64 sync_id = associator()->GetSyncIdFromChromeId(node->id()); EXPECT_NE(sync_id, sync_api::kInvalidId); } void ExpectSyncerNodeUnknown(const BookmarkNode* node) { - int64 sync_id = associator()->GetSyncIdFromBookmarkId(node->id()); + int64 sync_id = associator()->GetSyncIdFromChromeId(node->id()); EXPECT_EQ(sync_id, sync_api::kInvalidId); } void ExpectBrowserNodeTitle(int64 sync_id, const std::wstring& title) { const BookmarkNode* bnode = - associator()->GetBookmarkNodeFromSyncId(sync_id); + associator()->GetChromeNodeFromSyncId(sync_id); ASSERT_TRUE(bnode); EXPECT_EQ(bnode->GetTitle(), title); } void ExpectBrowserNodeURL(int64 sync_id, const std::string& url) { const BookmarkNode* bnode = - associator()->GetBookmarkNodeFromSyncId(sync_id); + associator()->GetChromeNodeFromSyncId(sync_id); ASSERT_TRUE(bnode); EXPECT_EQ(GURL(url), bnode->GetURL()); } void ExpectBrowserNodeParent(int64 sync_id, int64 parent_sync_id) { - const BookmarkNode* node = associator()->GetBookmarkNodeFromSyncId(sync_id); + const BookmarkNode* node = associator()->GetChromeNodeFromSyncId(sync_id); ASSERT_TRUE(node); const BookmarkNode* parent = - associator()->GetBookmarkNodeFromSyncId(parent_sync_id); + associator()->GetChromeNodeFromSyncId(parent_sync_id); EXPECT_TRUE(parent); EXPECT_EQ(node->GetParent(), parent); } @@ -463,11 +458,11 @@ class ProfileSyncServiceTest : public testing::Test { } int64 other_bookmarks_id() { - return associator()->GetSyncIdFromBookmarkId(model_->other_node()->id()); + return associator()->GetSyncIdFromChromeId(model_->other_node()->id()); } int64 bookmark_bar_id() { - return associator()->GetSyncIdFromBookmarkId( + return associator()->GetSyncIdFromChromeId( model_->GetBookmarkBarNode()->id()); } @@ -834,8 +829,8 @@ TEST_F(ProfileSyncServiceTest, UnrecoverableErrorSuspendsService) { { sync_api::WriteTransaction trans(service_->backend_->GetUserShareHandle()); sync_api::WriteNode sync_node(&trans); - EXPECT_TRUE(associator()->InitSyncNodeFromBookmarkId(node->id(), - &sync_node)); + EXPECT_TRUE(associator()->InitSyncNodeFromChromeId(node->id(), + &sync_node)); sync_node.Remove(); } // The models don't match at this point, but the ProfileSyncService |