Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1347)

Side by Side Diff: chrome/browser/sync/glue/autofill_profile_model_associator.cc

Issue 4683003: Sending the proto files for review to unblcok the server team Base URL: http://git.chromium.org/git/chromium.git@trunk
Patch Set: Created 10 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2010 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 #include "chrome/browser/sync/glue/autofill_profile_model_associator.h"
6
7 #include "base/utf_string_conversions.h"
8 #include "chrome/browser/sync/profile_sync_service.h"
9 #include "chrome/browser/webdata/web_database.h"
10
11 namespace browser_sync {
12
13 const char kAutofillProfileTag[] = "google_chrome_autofill_profile";
14
15 AutofillProfileModelAssociator::AutofillProfileModelAssociator(
16 ProfileSyncService* sync_service,
17 WebDatabase* web_database,
18 PersonalDataManager* personal_data)
19 : sync_service_(sync_service),
20 web_database_(web_database),
21 personal_data_(personal_data),
22 autofill_node_id_(sync_api::kInvalidId),
23 abort_association_pending_(false),
24 dontCheckThreadOnExit_(false) {
25 DCHECK(EnsureOnThread(BrowserThread::DB));
26 DCHECK(sync_service_);
27 DCHECK(web_database_);
28 DCHECK(personal_data_);
29 }
30
31 AutofillProfileModelAssociator::~AutofillProfileModelAssociator() {
32 DCHECK(EnsureOnThread(BrowserThread::DB));
33 }
34 sync_api::ReadNode* AutofillProfileModelAssociator::GetReadNode(
35 sync_api::WriteTransaction* trans) {
36 return new sync_api::ReadNode(trans);
37 }
38
39 bool AutofillProfileModelAssociator::TraverseAndAssociateChromeAutoFillProfiles(
40 sync_api::WriteTransaction* write_trans,
41 const sync_api::ReadNode& autofill_root,
42 const std::vector<AutoFillProfile*>& all_profiles_from_db,
43 std::set<std::string>* current_profiles,
44 std::vector<AutoFillProfile*>* updated_profiles) {
45 scoped_ptr<sync_api::ReadNode> node(GetReadNode(write_trans));
46
47 // Alias the all_profiles_from_db so we fit in 80 characters
48 const std::vector<AutoFillProfile*>& profiles(all_profiles_from_db);
49 for (std::vector<AutoFillProfile*>::const_iterator ix = profiles.begin();
50 ix != profiles.end();
51 ++ix) {
52 std::string guid((*ix)->guid());
53
54 node->Reset();
55 if (node->InitByClientTagLookup(syncable::AUTOFILL_PROFILE, guid)) {
56 const sync_pb::AutofillProfile2Specifics& autofill(
57 node->GetAutofillProfileSpecifics());
58 if (OverwriteProfileWithServerData(*ix, autofill)){
59 updated_profiles->push_back(*ix);
60 }
61 Associate(&guid, node->GetId());
62 } else {
63 int64 id;
64 if (!MakeNewAutofillProfileSyncNode(write_trans,
65 autofill_root,
66 (**ix),
67 &id))
68 {
69 LOG(ERROR) << "Failed making an autofill item on the sync database";
70 }
71 Associate(&guid, id);
72 }
73 current_profiles->insert(guid);
74 }
75
76 return true;
77 }
78
79 bool AutofillProfileModelAssociator::LoadAutofillData(
80 std::vector<AutoFillProfile*>* profiles) {
81 if (IsAbortPending())
82 return false;
83
84 if (!web_database_->GetAutoFillProfiles(profiles))
85 return false;
86
87 return true;
88 }
89
90 bool AutofillProfileModelAssociator::EnsureOnThread(BrowserThread::ID id) {
91 return dontCheckThreadOnExit_ || BrowserThread::CurrentlyOn(id);
92 }
93
94 bool AutofillProfileModelAssociator::AssociateModels() {
95 VLOG(1) << "Associating Autofill Models";
96 DCHECK(EnsureOnThread(BrowserThread::DB));
97 {
98 AutoLock lock(abort_association_pending_lock_);
99 abort_association_pending_ = false;
100 }
101
102 // TODO(lipalani): Attempt to load the model association from storage.
103 ScopedVector<AutoFillProfile> profiles;
104
105 if (!LoadAutofillData(&profiles.get())) {
106 LOG(ERROR) << "Could not get the autofill data from WebDatabase.";
107 return false;
108 }
109
110 DataBundle bundle;
111 {
112 // The write transaction lock is held inside this block.
113 // We do all the web db operations outside this block.
114 sync_api::WriteTransaction trans(
115 sync_service_->backend()->GetUserShareHandle());
116
117 sync_api::ReadNode autofill_root(&trans);
118 if (!autofill_root.InitByTagLookup(kAutofillProfileTag)) {
119 LOG(ERROR) << "Server did not create the top-level autofill node. We "
120 << "might be running against an out-of-date server.";
121 return false;
122 }
123
124 if (!TraverseAndAssociateChromeAutoFillProfiles(&trans, autofill_root,
125 profiles.get(), &bundle.current_profiles,
126 &bundle.updated_profiles) ||
127 !TraverseAndAssociateAllSyncNodes(&trans, autofill_root, &bundle)) {
128 return false;
129 }
130 }
131
132 if (!SaveChangesToWebData(bundle)) {
133 LOG(ERROR) << "Failed to update autofill entries.";
134 return false;
135 }
136
137 // [TODO] - split out the OptimisticRefreshTask into its own class
138 // from autofill_model_associator
139 // Will be done as part of the autofill_model_associator work.
140 // BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
141 // new DoOptimisticRefreshTask(personal_data_));
142 return true;
143 }
144
145 bool AutofillProfileModelAssociator::DisassociateModels() {
146 id_map_.clear();
147 id_map_inverse_.clear();
148 return true;
149 }
150
151 // Helper to compare the local value and cloud value of a field, merge into
152 // the local value if they differ, and return whether the merge happened.
153 bool AutofillProfileModelAssociator::MergeField(FormGroup* f,
154 AutoFillFieldType t,
155 const std::string& specifics_field) {
156 if (UTF16ToUTF8(f->GetFieldText(AutoFillType(t))) == specifics_field)
157 return false;
158 f->SetInfo(AutoFillType(t), UTF8ToUTF16(specifics_field));
159 return true;
160 }
161 bool AutofillProfileModelAssociator::SyncModelHasUserCreatedNodes(
162 bool *has_nodes)
163 {
164 CHECK(has_nodes != NULL);
165 sync_api::ReadTransaction trans(
166 sync_service_->backend()->GetUserShareHandle());
167
168 sync_api::ReadNode node(&trans);
169
170 if (!node.InitByClientTagLookup(
171 syncable::AUTOFILL_PROFILE,
172 kAutofillProfileTag)) {
173 LOG(ERROR) << "Sever did not create a top level node"
174 << "Out of data server or autofill type not enabled";
175 return false;
176 }
177
178 *has_nodes = sync_api::kInvalidId != node.GetFirstChildId();
179 return true;
180 }
181 // static
182 bool AutofillProfileModelAssociator::OverwriteProfileWithServerData(
183 AutoFillProfile* merge_into,
184 const sync_pb::AutofillProfile2Specifics& specifics) {
185 bool diff = false;
186 AutoFillProfile* p = merge_into;
187 const sync_pb::AutofillProfile2Specifics& s(specifics);
188 diff = MergeField(p, NAME_FIRST, s.name_first()) || diff;
189 diff = MergeField(p, NAME_LAST, s.name_last()) || diff;
190 diff = MergeField(p, NAME_MIDDLE, s.name_middle()) || diff;
191 diff = MergeField(p, ADDRESS_HOME_LINE1, s.address_home_line1()) || diff;
192 diff = MergeField(p, ADDRESS_HOME_LINE2, s.address_home_line2()) || diff;
193 diff = MergeField(p, ADDRESS_HOME_CITY, s.address_home_city()) || diff;
194 diff = MergeField(p, ADDRESS_HOME_STATE, s.address_home_state()) || diff;
195 diff = MergeField(p, ADDRESS_HOME_COUNTRY, s.address_home_country()) || diff;
196 diff = MergeField(p, ADDRESS_HOME_ZIP, s.address_home_zip()) || diff;
197 diff = MergeField(p, EMAIL_ADDRESS, s.email_address()) || diff;
198 diff = MergeField(p, COMPANY_NAME, s.company_name()) || diff;
199 diff = MergeField(p, PHONE_FAX_WHOLE_NUMBER, s.phone_fax_whole_number())
200 || diff;
201 diff = MergeField(p, PHONE_HOME_WHOLE_NUMBER, s.phone_home_whole_number())
202 || diff;
203 return diff;
204 }
205
206 bool AutofillProfileModelAssociator::MakeNewAutofillProfileSyncNode(
207 sync_api::WriteTransaction* trans,
208 const sync_api::BaseNode& autofill_root,
209 const AutoFillProfile& profile,
210 int64* sync_id) {
211 sync_api::WriteNode node(trans);
212 if (!node.InitUniqueByCreation(
213 syncable::AUTOFILL_PROFILE, autofill_root, profile.guid())) {
214 LOG(ERROR) << "Failed to create autofill sync node.";
215 return false;
216 }
217 node.SetTitle(UTF8ToWide(profile.guid()));
218
219 // [TODO] This needs rewriting. This will be tackled
220 // when rewriting autofill change processor.
221 // AutofillChangeProcessor::WriteAutofillProfile(profile, &node);
222 *sync_id = node.GetId();
223 return true;
224 }
225
226 bool AutofillProfileModelAssociator::TraverseAndAssociateAllSyncNodes(
227 sync_api::WriteTransaction* write_trans,
228 const sync_api::ReadNode& autofill_root,
229 DataBundle* bundle) {
230 DCHECK(EnsureOnThread(BrowserThread::DB));
231
232 int64 sync_child_id = autofill_root.GetFirstChildId();
233 scoped_ptr<sync_api::ReadNode> sync_child(GetReadNode(write_trans));
234 while (sync_child_id != sync_api::kInvalidId) {
235 sync_child->Reset();
236 if (!sync_child->InitByIdLookup(sync_child_id)) {
237 LOG(ERROR) << "Failed to fetch child node.";
238 return false;
239 }
240 const sync_pb::AutofillProfile2Specifics& autofill(
241 sync_child->GetAutofillProfileSpecifics());
242
243 AddNativeProfileIfNeeded(autofill, bundle, *sync_child);
244
245 sync_child_id = sync_child->GetSuccessorId();
246 }
247 return true;
248 }
249
250 void AutofillProfileModelAssociator::AddNativeProfileIfNeeded(
251 const sync_pb::AutofillProfile2Specifics& profile,
252 DataBundle* bundle,
253 const sync_api::ReadNode& node) {
254 DCHECK(EnsureOnThread(BrowserThread::DB));
255
256 // [TODO] this looping through is costly. Replace this with a binary tree
257 // at least in case of auto fill entries.
258 if (bundle->current_profiles.find(profile.guid()) ==
259 bundle->current_profiles.end()) {
260 std::string guid(profile.guid());
261 Associate(&guid, node.GetId());
262 AutoFillProfile* p = new AutoFillProfile(profile.guid());
263 OverwriteProfileWithServerData(p, profile);
264 bundle->new_profiles.push_back(p);
265 }
266 }
267
268 bool AutofillProfileModelAssociator::SaveChangesToWebData(
269 const DataBundle& bundle) {
270 DCHECK(EnsureOnThread(BrowserThread::DB));
271
272 if (IsAbortPending())
273 return false;
274
275 for (size_t i = 0; i < bundle.new_profiles.size(); i++) {
276 if (IsAbortPending())
277 return false;
278 if (!web_database_->AddAutoFillProfile(*bundle.new_profiles[i]))
279 return false;
280 }
281
282 for (size_t i = 0; i < bundle.updated_profiles.size(); i++) {
283 if (IsAbortPending())
284 return false;
285 if (!web_database_->UpdateAutoFillProfile(*bundle.updated_profiles[i]))
286 return false;
287 }
288 return true;
289 }
290
291 void AutofillProfileModelAssociator::Associate(
292 const std::string* autofill,
293 int64 sync_id) {
294 DCHECK(EnsureOnThread(BrowserThread::DB));
295 DCHECK_NE(sync_api::kInvalidId, sync_id);
296 DCHECK(id_map_.find(*autofill) == id_map_.end());
297 DCHECK(id_map_inverse_.find(sync_id) == id_map_inverse_.end());
298 id_map_[*autofill] = sync_id;
299 id_map_inverse_[sync_id] = *autofill;
300 }
301
302 void AutofillProfileModelAssociator::Disassociate(int64 sync_id) {
303 DCHECK(EnsureOnThread(BrowserThread::DB));
304 SyncIdToAutofillMap::iterator iter = id_map_inverse_.find(sync_id);
305 if (iter == id_map_inverse_.end())
306 return;
307 CHECK(id_map_.erase(iter->second));
308 id_map_inverse_.erase(iter);
309 }
310
311 int64 AutofillProfileModelAssociator::GetSyncIdFromChromeId(
312 const std::string autofill) {
313 AutofillToSyncIdMap::const_iterator iter = id_map_.find(autofill);
314 return iter == id_map_.end() ? sync_api::kInvalidId : iter->second;
315 }
316
317 void AutofillProfileModelAssociator::AbortAssociation() {
318 DCHECK(EnsureOnThread(BrowserThread::UI));
319 AutoLock lock(abort_association_pending_lock_);
320 abort_association_pending_ = true;
321 }
322
323 bool AutofillProfileModelAssociator::IsAbortPending() {
324 AutoLock lock(abort_association_pending_lock_);
325 return abort_association_pending_;
326 }
327
328 } // namespace browser_sync
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698