summaryrefslogtreecommitdiffstats
path: root/chrome/browser/sync/glue/autofill_model_associator.h
blob: 4de5894870e84c2ffab25bbd1324fb634936a778 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
// Copyright (c) 2010 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_SYNC_GLUE_AUTOFILL_MODEL_ASSOCIATOR_H_
#define CHROME_BROWSER_SYNC_GLUE_AUTOFILL_MODEL_ASSOCIATOR_H_

#include <map>
#include <set>
#include <string>
#include <vector>

#include "base/basictypes.h"
#include "base/lock.h"
#include "base/scoped_ptr.h"
#include "chrome/browser/autofill/personal_data_manager.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/sync/engine/syncapi.h"
#include "chrome/browser/sync/glue/model_associator.h"
#include "chrome/browser/sync/protocol/autofill_specifics.pb.h"
#include "chrome/browser/webdata/autofill_entry.h"

class AutoFillProfile;

class ProfileSyncService;
class WebDatabase;

namespace sync_api {
class WriteTransaction;
}

namespace browser_sync {

class AutofillChangeProcessor;
class UnrecoverableErrorHandler;

extern const char kAutofillTag[];
extern const char kAutofillProfileNamespaceTag[];
extern const char kAutofillEntryNamespaceTag[];

// Contains all model association related logic:
// * Algorithm to associate autofill model and sync model.
// We do not check if we have local data before this run; we always
// merge and sync.
class AutofillModelAssociator
    : public PerDataTypeAssociatorInterface<std::string, std::string> {
 public:
  static syncable::ModelType model_type() { return syncable::AUTOFILL; }
  AutofillModelAssociator(ProfileSyncService* sync_service,
                          WebDatabase* web_database,
                          PersonalDataManager* data_manager,
                          UnrecoverableErrorHandler* error_handler);
  virtual ~AutofillModelAssociator();

  // A task used by this class and the change processor to inform the
  // PersonalDataManager living on the UI thread that it needs to refresh.
  class DoOptimisticRefreshTask : public Task {
   public:
    explicit DoOptimisticRefreshTask(PersonalDataManager* pdm) : pdm_(pdm) {}
    virtual void Run() {
      DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
      pdm_->Refresh();
    }
   private:
    PersonalDataManager* pdm_;
  };

  // PerDataTypeAssociatorInterface implementation.
  //
  // Iterates through the sync model looking for matched pairs of items.
  virtual bool AssociateModels();

  // Clears all associations.
  virtual bool DisassociateModels();

  // The has_nodes out param is true if the sync model has nodes other
  // than the permanent tagged nodes.
  virtual bool SyncModelHasUserCreatedNodes(bool* has_nodes);

  // The has_nodes out param is true if the autofill model has any
  // user-defined autofill entries.
  virtual bool ChromeModelHasUserCreatedNodes(bool* has_nodes);

  // See ModelAssociator interface.
  virtual void AbortAssociation();

  // Not implemented.
  virtual const std::string* GetChromeNodeFromSyncId(int64 sync_id) {
    return NULL;
  }

  // Not implemented.
  virtual bool InitSyncNodeFromChromeId(std::string node_id,
                                        sync_api::BaseNode* sync_node) {
    return false;
  }

  // Returns the sync id for the given autofill name, or sync_api::kInvalidId
  // if the autofill name is not associated to any sync id.
  virtual int64 GetSyncIdFromChromeId(std::string node_id);

  // Associates the given autofill name with the given sync id.
  virtual void Associate(const std::string* node, int64 sync_id);

  // Remove the association that corresponds to the given sync id.
  virtual void Disassociate(int64 sync_id);

  // Returns whether a node with the given permanent tag was found and update
  // |sync_id| with that node's id.
  virtual bool GetSyncIdForTaggedNode(const std::string& tag, int64* sync_id);

  static std::string KeyToTag(const string16& name, const string16& value);
  static std::string ProfileLabelToTag(const string16& label);

  static bool MergeTimestamps(const sync_pb::AutofillSpecifics& autofill,
                              const std::vector<base::Time>& timestamps,
                              std::vector<base::Time>* new_timestamps);
  static bool OverwriteProfileWithServerData(
      AutoFillProfile* merge_into,
      const sync_pb::AutofillProfileSpecifics& specifics);

  // TODO(georgey) : add the same processing for CC info (already in protocol
  // buffers).

  // Returns sync service instance.
  ProfileSyncService* sync_service() { return sync_service_; }

  static string16 MakeUniqueLabel(const string16& non_unique_label,
                                  sync_api::BaseTransaction* trans);

 private:
  typedef std::map<std::string, int64> AutofillToSyncIdMap;
  typedef std::map<int64, std::string> SyncIdToAutofillMap;

  // A convenience wrapper of a bunch of state we pass around while associating
  // models, and send to the WebDatabase for persistence.
  struct DataBundle {
    std::set<AutofillKey> current_entries;
    std::vector<AutofillEntry> new_entries;
    std::set<string16> current_profiles;
    std::vector<AutoFillProfile*> updated_profiles;
    std::vector<AutoFillProfile*> new_profiles;  // We own these pointers.
    ~DataBundle() { STLDeleteElements(&new_profiles); }
  };

  // Helper to query WebDatabase for the current autofill state.
  bool LoadAutofillData(std::vector<AutofillEntry>* entries,
                        std::vector<AutoFillProfile*>* profiles);

  // We split up model association first by autofill sub-type (entries, and
  // profiles.  There is a Traverse* method for each of these.
  bool TraverseAndAssociateChromeAutofillEntries(
      sync_api::WriteTransaction* write_trans,
      const sync_api::ReadNode& autofill_root,
      const std::vector<AutofillEntry>& all_entries_from_db,
      std::set<AutofillKey>* current_entries,
      std::vector<AutofillEntry>* new_entries);
  bool TraverseAndAssociateChromeAutoFillProfiles(
      sync_api::WriteTransaction* write_trans,
      const sync_api::ReadNode& autofill_root,
      const std::vector<AutoFillProfile*>& all_profiles_from_db,
      std::set<string16>* current_profiles,
      std::vector<AutoFillProfile*>* updated_profiles);

  // Once the above traversals are complete, we traverse the sync model to
  // associate all remaining nodes.
  bool TraverseAndAssociateAllSyncNodes(
      sync_api::WriteTransaction* write_trans,
      const sync_api::ReadNode& autofill_root,
      DataBundle* bundle);

  // Helper to persist any changes that occured during model association to
  // the WebDatabase.
  bool SaveChangesToWebData(const DataBundle& bundle);

  // Helper to insert an AutofillEntry into the WebDatabase (e.g. in response
  // to encountering a sync node that doesn't exist yet locally).
  void AddNativeEntryIfNeeded(const sync_pb::AutofillSpecifics& autofill,
                              DataBundle* bundle,
                              const sync_api::ReadNode& node);

  // Helper to insert an AutoFillProfile into the WebDatabase (e.g. in response
  // to encountering a sync node that doesn't exist yet locally).
  void AddNativeProfileIfNeeded(
      const sync_pb::AutofillProfileSpecifics& profile,
      DataBundle* bundle,
      const sync_api::ReadNode& node);

  // Helper to insert a sync node for the given AutoFillProfile (e.g. in
  // response to encountering a native profile that doesn't exist yet in the
  // cloud).
  bool MakeNewAutofillProfileSyncNode(
      sync_api::WriteTransaction* trans,
      const sync_api::BaseNode& autofill_root,
      const std::string& tag,
      const AutoFillProfile& profile,
      int64* sync_id);

  // Called at various points in model association to determine if the
  // user requested an abort.
  bool IsAbortPending();

  ProfileSyncService* sync_service_;
  WebDatabase* web_database_;
  PersonalDataManager* personal_data_;
  UnrecoverableErrorHandler* error_handler_;
  int64 autofill_node_id_;

  AutofillToSyncIdMap id_map_;
  SyncIdToAutofillMap id_map_inverse_;

  // Abort association pending flag and lock.  If this is set to true
  // (via the AbortAssociation method), return from the
  // AssociateModels method as soon as possible.
  Lock abort_association_pending_lock_;
  bool abort_association_pending_;

  DISALLOW_COPY_AND_ASSIGN(AutofillModelAssociator);
};

}  // namespace browser_sync

#endif  // CHROME_BROWSER_SYNC_GLUE_AUTOFILL_MODEL_ASSOCIATOR_H_