1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef CHROME_BROWSER_SYNC_GLUE_BOOKMARK_MODEL_ASSOCIATOR_H_
6#define CHROME_BROWSER_SYNC_GLUE_BOOKMARK_MODEL_ASSOCIATOR_H_
7
8#include <map>
9#include <set>
10#include <string>
11
12#include "base/basictypes.h"
13#include "base/compiler_specific.h"
14#include "base/memory/weak_ptr.h"
15#include "components/sync_driver/data_type_controller.h"
16#include "components/sync_driver/data_type_error_handler.h"
17#include "components/sync_driver/model_associator.h"
18#include "sync/internal_api/public/util/unrecoverable_error_handler.h"
19
20class BookmarkModel;
21class BookmarkNode;
22class Profile;
23
24namespace syncer {
25class BaseNode;
26class BaseTransaction;
27struct UserShare;
28}
29
30namespace browser_sync {
31
32// Contains all model association related logic:
33// * Algorithm to associate bookmark model and sync model.
34// * Methods to get a bookmark node for a given sync node and vice versa.
35// * Persisting model associations and loading them back.
36class BookmarkModelAssociator
37    : public sync_driver::PerDataTypeAssociatorInterface<BookmarkNode, int64> {
38 public:
39  static syncer::ModelType model_type() { return syncer::BOOKMARKS; }
40  // |expect_mobile_bookmarks_folder| controls whether or not we
41  // expect the mobile bookmarks permanent folder to be created.
42  // Should be set to true only by mobile clients.
43  BookmarkModelAssociator(
44      BookmarkModel* bookmark_model,
45      Profile* profile_,
46      syncer::UserShare* user_share,
47      sync_driver::DataTypeErrorHandler* unrecoverable_error_handler,
48      bool expect_mobile_bookmarks_folder);
49  virtual ~BookmarkModelAssociator();
50
51  // Updates the visibility of the permanents node in the BookmarkModel.
52  void UpdatePermanentNodeVisibility();
53
54  // AssociatorInterface implementation.
55  //
56  // AssociateModels iterates through both the sync and the browser
57  // bookmark model, looking for matched pairs of items.  For any pairs it
58  // finds, it will call AssociateSyncID.  For any unmatched items,
59  // MergeAndAssociateModels will try to repair the match, e.g. by adding a new
60  // node.  After successful completion, the models should be identical and
61  // corresponding. Returns true on success.  On failure of this step, we
62  // should abort the sync operation and report an error to the user.
63  virtual syncer::SyncError AssociateModels(
64      syncer::SyncMergeResult* local_merge_result,
65      syncer::SyncMergeResult* syncer_merge_result) OVERRIDE;
66
67  virtual syncer::SyncError DisassociateModels() OVERRIDE;
68
69  // The has_nodes out param is true if the sync model has nodes other
70  // than the permanent tagged nodes.
71  virtual bool SyncModelHasUserCreatedNodes(bool* has_nodes) OVERRIDE;
72
73  // Returns sync id for the given bookmark node id.
74  // Returns syncer::kInvalidId if the sync node is not found for the given
75  // bookmark node id.
76  virtual int64 GetSyncIdFromChromeId(const int64& node_id) OVERRIDE;
77
78  // Returns the bookmark node for the given sync id.
79  // Returns NULL if no bookmark node is found for the given sync id.
80  virtual const BookmarkNode* GetChromeNodeFromSyncId(int64 sync_id) OVERRIDE;
81
82  // Initializes the given sync node from the given bookmark node id.
83  // Returns false if no sync node was found for the given bookmark node id or
84  // if the initialization of sync node fails.
85  virtual bool InitSyncNodeFromChromeId(
86      const int64& node_id,
87      syncer::BaseNode* sync_node) OVERRIDE;
88
89  // Associates the given bookmark node with the given sync id.
90  virtual void Associate(const BookmarkNode* node, int64 sync_id) OVERRIDE;
91  // Remove the association that corresponds to the given sync id.
92  virtual void Disassociate(int64 sync_id) OVERRIDE;
93
94  virtual void AbortAssociation() OVERRIDE {
95    // No implementation needed, this associator runs on the main
96    // thread.
97  }
98
99  // See ModelAssociator interface.
100  virtual bool CryptoReadyIfNecessary() OVERRIDE;
101
102 protected:
103  // Stores the id of the node with the given tag in |sync_id|.
104  // Returns of that node was found successfully.
105  // Tests override this.
106  virtual bool GetSyncIdForTaggedNode(const std::string& tag, int64* sync_id);
107
108 private:
109  typedef std::map<int64, int64> BookmarkIdToSyncIdMap;
110  typedef std::map<int64, const BookmarkNode*> SyncIdToBookmarkNodeMap;
111  typedef std::set<int64> DirtyAssociationsSyncIds;
112
113  // Posts a task to persist dirty associations.
114  void PostPersistAssociationsTask();
115  // Persists all dirty associations.
116  void PersistAssociations();
117
118  // Matches up the bookmark model and the sync model to build model
119  // associations.
120  syncer::SyncError BuildAssociations(
121      syncer::SyncMergeResult* local_merge_result,
122      syncer::SyncMergeResult* syncer_merge_result);
123
124  // Removes bookmark nodes whose corresponding sync nodes have been deleted
125  // according to sync delete journals. Return number of deleted bookmarks.
126  int64 ApplyDeletesFromSyncJournal(syncer::BaseTransaction* trans);
127
128  // Associate a top-level node of the bookmark model with a permanent node in
129  // the sync domain.  Such permanent nodes are identified by a tag that is
130  // well known to the server and the client, and is unique within a particular
131  // user's share.  For example, "other_bookmarks" is the tag for the Other
132  // Bookmarks folder.  The sync nodes are server-created.
133  // Returns true on success, false if association failed.
134  bool AssociateTaggedPermanentNode(
135      const BookmarkNode* permanent_node,
136      const std::string& tag) WARN_UNUSED_RESULT;
137
138  // Compare the properties of a pair of nodes from either domain.
139  bool NodesMatch(const BookmarkNode* bookmark,
140                  const syncer::BaseNode* sync_node) const;
141
142  // Check whether bookmark model and sync model are synced by comparing
143  // their transaction versions.
144  // Returns a PERSISTENCE_ERROR if a transaction mismatch was detected where
145  // the native model has a newer transaction verison.
146  syncer::SyncError CheckModelSyncState(
147      syncer::SyncMergeResult* local_merge_result,
148      syncer::SyncMergeResult* syncer_merge_result) const;
149
150  BookmarkModel* bookmark_model_;
151  Profile* profile_;
152  syncer::UserShare* user_share_;
153  sync_driver::DataTypeErrorHandler* unrecoverable_error_handler_;
154  const bool expect_mobile_bookmarks_folder_;
155  BookmarkIdToSyncIdMap id_map_;
156  SyncIdToBookmarkNodeMap id_map_inverse_;
157  // Stores sync ids for dirty associations.
158  DirtyAssociationsSyncIds dirty_associations_sync_ids_;
159
160  // Used to post PersistAssociation tasks to the current message loop and
161  // guarantees no invocations can occur if |this| has been deleted. (This
162  // allows this class to be non-refcounted).
163  base::WeakPtrFactory<BookmarkModelAssociator> weak_factory_;
164
165  DISALLOW_COPY_AND_ASSIGN(BookmarkModelAssociator);
166};
167
168}  // namespace browser_sync
169
170#endif  // CHROME_BROWSER_SYNC_GLUE_BOOKMARK_MODEL_ASSOCIATOR_H_
171