1// Copyright (c) 2011 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#pragma once
8
9#include <map>
10#include <set>
11#include <string>
12
13#include "base/basictypes.h"
14#include "base/task.h"
15#include "chrome/browser/sync/unrecoverable_error_handler.h"
16#include "chrome/browser/sync/glue/model_associator.h"
17
18class BookmarkModel;
19class BookmarkNode;
20
21namespace sync_api {
22class BaseNode;
23class BaseTransaction;
24class ReadNode;
25struct UserShare;
26}
27
28namespace browser_sync {
29
30class BookmarkChangeProcessor;
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 PerDataTypeAssociatorInterface<BookmarkNode, int64> {
38 public:
39  static syncable::ModelType model_type() { return syncable::BOOKMARKS; }
40  BookmarkModelAssociator(
41      BookmarkModel* bookmark_model,
42      sync_api::UserShare* user_share,
43      UnrecoverableErrorHandler* unrecoverable_error_handler);
44  virtual ~BookmarkModelAssociator();
45
46  // AssociatorInterface implementation.
47  //
48  // AssociateModels iterates through both the sync and the browser
49  // bookmark model, looking for matched pairs of items.  For any pairs it
50  // finds, it will call AssociateSyncID.  For any unmatched items,
51  // MergeAndAssociateModels will try to repair the match, e.g. by adding a new
52  // node.  After successful completion, the models should be identical and
53  // corresponding. Returns true on success.  On failure of this step, we
54  // should abort the sync operation and report an error to the user.
55  virtual bool AssociateModels();
56
57  virtual bool DisassociateModels();
58
59  // The has_nodes out param is true if the sync model has nodes other
60  // than the permanent tagged nodes.
61  virtual bool SyncModelHasUserCreatedNodes(bool* has_nodes);
62
63  // Returns sync id for the given bookmark node id.
64  // Returns sync_api::kInvalidId if the sync node is not found for the given
65  // bookmark node id.
66  virtual int64 GetSyncIdFromChromeId(const int64& node_id);
67
68  // Returns the bookmark node for the given sync id.
69  // Returns NULL if no bookmark node is found for the given sync id.
70  virtual const BookmarkNode* GetChromeNodeFromSyncId(int64 sync_id);
71
72  // Initializes the given sync node from the given bookmark node id.
73  // Returns false if no sync node was found for the given bookmark node id or
74  // if the initialization of sync node fails.
75  virtual bool InitSyncNodeFromChromeId(const int64& node_id,
76                                        sync_api::BaseNode* sync_node);
77
78  // Associates the given bookmark node with the given sync id.
79  virtual void Associate(const BookmarkNode* node, int64 sync_id);
80  // Remove the association that corresponds to the given sync id.
81  virtual void Disassociate(int64 sync_id);
82
83  virtual void AbortAssociation() {
84    // No implementation needed, this associator runs on the main
85    // thread.
86  }
87
88  // See ModelAssociator interface.
89  virtual bool CryptoReadyIfNecessary();
90
91 protected:
92  // Stores the id of the node with the given tag in |sync_id|.
93  // Returns of that node was found successfully.
94  // Tests override this.
95  virtual bool GetSyncIdForTaggedNode(const std::string& tag, int64* sync_id);
96
97 private:
98  typedef std::map<int64, int64> BookmarkIdToSyncIdMap;
99  typedef std::map<int64, const BookmarkNode*> SyncIdToBookmarkNodeMap;
100  typedef std::set<int64> DirtyAssociationsSyncIds;
101
102  // Posts a task to persist dirty associations.
103  void PostPersistAssociationsTask();
104  // Persists all dirty associations.
105  void PersistAssociations();
106
107  // Loads the persisted associations into in-memory maps.
108  // If the persisted associations are out-of-date due to some reason, returns
109  // false; otherwise returns true.
110  bool LoadAssociations();
111
112  // Matches up the bookmark model and the sync model to build model
113  // associations.
114  bool BuildAssociations();
115
116  // Associate a top-level node of the bookmark model with a permanent node in
117  // the sync domain.  Such permanent nodes are identified by a tag that is
118  // well known to the server and the client, and is unique within a particular
119  // user's share.  For example, "other_bookmarks" is the tag for the Other
120  // Bookmarks folder.  The sync nodes are server-created.
121  bool AssociateTaggedPermanentNode(const BookmarkNode* permanent_node,
122                                    const std::string& tag);
123
124  // Compare the properties of a pair of nodes from either domain.
125  bool NodesMatch(const BookmarkNode* bookmark,
126                  const sync_api::BaseNode* sync_node) const;
127
128  BookmarkModel* bookmark_model_;
129  sync_api::UserShare* user_share_;
130  UnrecoverableErrorHandler* unrecoverable_error_handler_;
131  BookmarkIdToSyncIdMap id_map_;
132  SyncIdToBookmarkNodeMap id_map_inverse_;
133  // Stores sync ids for dirty associations.
134  DirtyAssociationsSyncIds dirty_associations_sync_ids_;
135
136  // Used to post PersistAssociation tasks to the current message loop and
137  // guarantees no invocations can occur if |this| has been deleted. (This
138  // allows this class to be non-refcounted).
139  ScopedRunnableMethodFactory<BookmarkModelAssociator> persist_associations_;
140
141  int number_of_new_sync_nodes_created_at_association_;
142
143  DISALLOW_COPY_AND_ASSIGN(BookmarkModelAssociator);
144};
145
146}  // namespace browser_sync
147
148#endif  // CHROME_BROWSER_SYNC_GLUE_BOOKMARK_MODEL_ASSOCIATOR_H_
149