summaryrefslogtreecommitdiffstats
path: root/chrome/browser/sync
diff options
context:
space:
mode:
authortim@chromium.org <tim@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-12-17 19:18:53 +0000
committertim@chromium.org <tim@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-12-17 19:18:53 +0000
commit210007c4ad5225b2b5ca56ee3f009167c9705ac0 (patch)
tree80c4f0a2376914ec49cffb964408e1173cffd144 /chrome/browser/sync
parentb3300dc30deee1992729a78bc5c053c7a136d6a7 (diff)
downloadchromium_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.cc33
-rw-r--r--chrome/browser/sync/glue/bookmark_change_processor.h11
-rw-r--r--chrome/browser/sync/glue/bookmark_model_associator.cc33
-rw-r--r--chrome/browser/sync/glue/bookmark_model_associator.h17
-rw-r--r--chrome/browser/sync/glue/change_processor.h2
-rw-r--r--chrome/browser/sync/glue/model_associator.h148
-rw-r--r--chrome/browser/sync/profile_sync_service.cc66
-rw-r--r--chrome/browser/sync/profile_sync_service.h23
-rw-r--r--chrome/browser/sync/profile_sync_service_unittest.cc57
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