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

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

Issue 7819002: Migrate AutofillProfile sync to new API. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 9 years, 3 months 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
Property Changes:
Added: svn:eol-style
+ LF
OLDNEW
(Empty)
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 #include "chrome/browser/sync/glue/autofill_profile_syncable_service.h"
6
7 #include "base/logging.h"
8 #include "base/tracked.h"
9 #include "base/utf_string_conversions.h"
10 #include "chrome/browser/profiles/profile.h"
11 #include "chrome/browser/sync/api/sync_error.h"
12 #include "chrome/browser/sync/glue/do_optimistic_refresh_task.h"
13 #include "chrome/browser/webdata/autofill_table.h"
14 #include "chrome/browser/webdata/web_database.h"
15 #include "chrome/common/chrome_notification_types.h"
16 #include "chrome/common/guid.h"
17 #include "content/common/notification_service.h"
18
19 namespace {
20
21 // Helper to compare the local value and cloud value of a field, merge into
22 // the local value if they differ, and return whether the merge happened.
23 bool MergeField(FormGroup* form_group,
24 AutofillFieldType field_type,
25 const std::string& specifics_field) {
26 if (UTF16ToUTF8(form_group->GetInfo(field_type)) == specifics_field)
27 return false;
28 form_group->SetInfo(field_type, UTF8ToUTF16(specifics_field));
29 return true;
30 }
31
32 } // namespace
33
34 namespace browser_sync {
35
36 const char kAutofillProfileTag[] = "google_chrome_autofill_profiles";
37
38 AutofillProfileSyncableService::AutofillProfileSyncableService(
39 WebDatabase* web_database,
40 PersonalDataManager* personal_data,
41 Profile* profile)
42 : web_database_(web_database),
43 personal_data_(personal_data),
44 sync_processor_(NULL) {
45 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
46 DCHECK(web_database_);
47 DCHECK(personal_data_);
48 DCHECK(profile);
49 notification_registrar_.Add(this,
50 chrome::NOTIFICATION_AUTOFILL_PROFILE_CHANGED,
51 Source<WebDataService>(
52 profile->GetWebDataService(Profile::EXPLICIT_ACCESS)));
53 }
54
55 AutofillProfileSyncableService::~AutofillProfileSyncableService() {
56 DCHECK(CalledOnValidThread());
57 }
58
59 AutofillProfileSyncableService::AutofillProfileSyncableService()
60 : web_database_(NULL),
61 personal_data_(NULL),
62 sync_processor_(NULL) {
63 }
64
65 SyncError AutofillProfileSyncableService::MergeDataAndStartSyncing(
66 syncable::ModelType type,
67 const SyncDataList& initial_sync_data,
68 SyncChangeProcessor* sync_processor) {
69 DCHECK(CalledOnValidThread());
70 DCHECK(sync_processor_ == NULL);
71 VLOG(1) << "Associating Autofill: MergeDataAndStartSyncing";
72
73 if (!LoadAutofillData(&profiles_.get())) {
74 return SyncError(
75 FROM_HERE, "Could not get the autofill data from WebDatabase.",
76 model_type());
77 }
78
79 if (VLOG_IS_ON(2)) {
80 VLOG(2) << "[AUTOFILL MIGRATION]"
81 << "Printing profiles from web db";
82
83 for (ScopedVector<AutofillProfile>::const_iterator ix =
84 profiles_.begin(); ix != profiles_.end(); ++ix) {
85 AutofillProfile* p = *ix;
86 VLOG(2) << "[AUTOFILL MIGRATION] "
87 << p->GetInfo(NAME_FIRST)
88 << p->GetInfo(NAME_LAST)
89 << p->guid();
90 }
91 }
92
93 sync_processor_ = sync_processor;
94
95 GUIDToProfileMap remaining_profiles;
96 CreateGUIDToProfileMap(profiles_.get(), &remaining_profiles);
97
98 DataBundle bundle;
99 // Go through and check for all the profiles that sync already knows about.
100 for (SyncDataList::const_iterator sync_iter = initial_sync_data.begin();
101 sync_iter != initial_sync_data.end();
102 ++sync_iter) {
103 GUIDToProfileMap::iterator it =
104 CreateOrUpdateProfile(*sync_iter, &remaining_profiles, &bundle);
105 profiles_map_[it->first] = it->second;
106 remaining_profiles.erase(it);
107 }
108
109 if (!SaveChangesToWebData(bundle))
110 return SyncError(FROM_HERE, "Failed to update webdata.", model_type());
111
112 SyncChangeList new_changes;
113 for (GUIDToProfileMap::iterator i = remaining_profiles.begin();
114 i != remaining_profiles.end(); ++i) {
115 new_changes.push_back(
116 SyncChange(SyncChange::ACTION_ADD,
117 CreateData(*(profiles_[i->second]))));
118 profiles_map_[i->first] = i->second;
119 }
120
121 SyncError error = sync_processor_->ProcessSyncChanges(FROM_HERE, new_changes);
122
123 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
124 new DoOptimisticRefreshForAutofill(personal_data_));
125
126 return error;
127 }
128
129 void AutofillProfileSyncableService::StopSyncing(syncable::ModelType type) {
130 DCHECK(CalledOnValidThread());
131 DCHECK(sync_processor_ != NULL);
132 DCHECK_EQ(type, syncable::AUTOFILL_PROFILE);
133
134 sync_processor_ = NULL;
135 profiles_.reset();
136 profiles_map_.clear();
137 }
138
139 SyncDataList AutofillProfileSyncableService::GetAllSyncData(
140 syncable::ModelType type) const {
141 DCHECK(CalledOnValidThread());
142 DCHECK(sync_processor_ != NULL);
143 DCHECK_EQ(type, syncable::AUTOFILL_PROFILE);
144
145 SyncDataList current_data;
146
147 for (GUIDToProfileMap::const_iterator i = profiles_map_.begin();
148 i != profiles_map_.end(); ++i) {
149 current_data.push_back(CreateData(*(profiles_[i->second])));
150 }
151 return current_data;
152 }
153
154 SyncError AutofillProfileSyncableService::ProcessSyncChanges(
155 const tracked_objects::Location& from_here,
156 const SyncChangeList& change_list) {
157 DCHECK(CalledOnValidThread());
158 DCHECK(sync_processor_ != NULL);
159 if (sync_processor_ == NULL) {
160 SyncError error(FROM_HERE, "Models not yet associated.",
161 syncable::AUTOFILL_PROFILE);
162 return error;
163 }
164
165 DataBundle bundle;
166
167 for (SyncChangeList::const_iterator i = change_list.begin();
168 i != change_list.end(); ++i) {
169 DCHECK(i->IsValid());
170 switch (i->change_type()) {
171 case SyncChange::ACTION_ADD:
172 case SyncChange::ACTION_UPDATE:
173 CreateOrUpdateProfile(i->sync_data(), &profiles_map_, &bundle);
174 break;
175 case SyncChange::ACTION_DELETE: {
176 std::string guid = i->sync_data().GetSpecifics().
177 GetExtension(sync_pb::autofill_profile).guid();
178 bundle.profiles_to_delete.push_back(guid);
179 profiles_map_.erase(guid);
180 } break;
181 default:
182 NOTREACHED() << "Unexpected sync change state.";
183 return SyncError(FROM_HERE, "ProcessSyncChanges failed on ChangeType " +
184 SyncChange::ChangeTypeToString(i->change_type()),
185 syncable::AUTOFILL_PROFILE);
186 }
187 }
188
189 if (!SaveChangesToWebData(bundle))
190 return SyncError(FROM_HERE, "Failed to update webdata.", model_type());
191
192 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
193 new DoOptimisticRefreshForAutofill(personal_data_));
194 return SyncError();
195 }
196
197 void AutofillProfileSyncableService::Observe(int type,
198 const NotificationSource& source,
199 const NotificationDetails& details) {
200 DCHECK_EQ(type, chrome::NOTIFICATION_AUTOFILL_PROFILE_CHANGED);
201 WebDataService* wds = Source<WebDataService>(source).ptr();
202
203 DCHECK(wds && wds->GetDatabase() == web_database_);
204
205 AutofillProfileChange* change = Details<AutofillProfileChange>(details).ptr();
206
207 ActOnChange(*change);
208 }
209
210 bool AutofillProfileSyncableService::LoadAutofillData(
211 std::vector<AutofillProfile*>* profiles) {
212 if (!web_database_->GetAutofillTable()->GetAutofillProfiles(profiles))
213 return false;
214
215 return true;
216 }
217
218 bool AutofillProfileSyncableService::SaveChangesToWebData(
219 const DataBundle& bundle) {
220 DCHECK(CalledOnValidThread());
221
222 for (size_t i = 0; i < bundle.new_profiles.size(); i++) {
223 if (!web_database_->GetAutofillTable()->AddAutofillProfile(
224 *bundle.new_profiles[i]))
225 return false;
226 }
227
228 for (size_t i = 0; i < bundle.updated_profiles.size(); i++) {
229 if (!web_database_->GetAutofillTable()->UpdateAutofillProfile(
230 *bundle.updated_profiles[i]))
231 return false;
232 }
233
234 for (size_t i = 0; i< bundle.profiles_to_delete.size(); ++i) {
235 if (!web_database_->GetAutofillTable()->RemoveAutofillProfile(
236 bundle.profiles_to_delete[i]))
237 return false;
238 }
239 return true;
240 }
241
242 // static
243 bool AutofillProfileSyncableService::OverwriteProfileWithServerData(
244 const sync_pb::AutofillProfileSpecifics& specifics,
245 AutofillProfile* profile) {
246 bool diff = false;
247 diff = MergeField(profile, NAME_FIRST, specifics.name_first()) || diff;
248 diff = MergeField(profile, NAME_LAST, specifics.name_last()) || diff;
249 diff = MergeField(profile, NAME_MIDDLE, specifics.name_middle()) || diff;
250 diff = MergeField(profile, ADDRESS_HOME_LINE1,
251 specifics.address_home_line1()) || diff;
252 diff = MergeField(profile, ADDRESS_HOME_LINE2,
253 specifics.address_home_line2()) || diff;
254 diff = MergeField(profile, ADDRESS_HOME_CITY,
255 specifics.address_home_city()) || diff;
256 diff = MergeField(profile, ADDRESS_HOME_STATE,
257 specifics.address_home_state()) || diff;
258 diff = MergeField(profile, ADDRESS_HOME_COUNTRY,
259 specifics.address_home_country()) || diff;
260 diff = MergeField(profile, ADDRESS_HOME_ZIP,
261 specifics.address_home_zip()) || diff;
262 diff = MergeField(profile, EMAIL_ADDRESS, specifics.email_address()) || diff;
263 diff = MergeField(profile, COMPANY_NAME, specifics.company_name()) || diff;
264 diff = MergeField(profile, PHONE_FAX_WHOLE_NUMBER,
265 specifics.phone_fax_whole_number()) || diff;
266 diff = MergeField(profile, PHONE_HOME_WHOLE_NUMBER,
267 specifics.phone_home_whole_number()) || diff;
268 return diff;
269 }
270
271 // static
272 void AutofillProfileSyncableService::WriteAutofillProfile(
273 const AutofillProfile& profile,
274 sync_pb::EntitySpecifics* profile_specifics) {
275 sync_pb::AutofillProfileSpecifics* specifics =
276 profile_specifics->MutableExtension(sync_pb::autofill_profile);
277
278 DCHECK(guid::IsValidGUID(profile.guid()));
279
280 specifics->set_guid(profile.guid());
281 specifics->set_name_first(UTF16ToUTF8(profile.GetInfo(NAME_FIRST)));
282 specifics->set_name_middle(UTF16ToUTF8(profile.GetInfo(NAME_MIDDLE)));
283 specifics->set_name_last(UTF16ToUTF8(profile.GetInfo(NAME_LAST)));
284 specifics->set_address_home_line1(
285 UTF16ToUTF8(profile.GetInfo(ADDRESS_HOME_LINE1)));
286 specifics->set_address_home_line2(
287 UTF16ToUTF8(profile.GetInfo(ADDRESS_HOME_LINE2)));
288 specifics->set_address_home_city(UTF16ToUTF8(profile.GetInfo(
289 ADDRESS_HOME_CITY)));
290 specifics->set_address_home_state(UTF16ToUTF8(profile.GetInfo(
291 ADDRESS_HOME_STATE)));
292 specifics->set_address_home_country(UTF16ToUTF8(profile.GetInfo(
293 ADDRESS_HOME_COUNTRY)));
294 specifics->set_address_home_zip(UTF16ToUTF8(profile.GetInfo(
295 ADDRESS_HOME_ZIP)));
296 specifics->set_email_address(UTF16ToUTF8(profile.GetInfo(EMAIL_ADDRESS)));
297 specifics->set_company_name(UTF16ToUTF8(profile.GetInfo(COMPANY_NAME)));
298 specifics->set_phone_fax_whole_number(UTF16ToUTF8(profile.GetInfo(
299 PHONE_FAX_WHOLE_NUMBER)));
300 specifics->set_phone_home_whole_number(UTF16ToUTF8(profile.GetInfo(
301 PHONE_HOME_WHOLE_NUMBER)));
302 }
303
304 void AutofillProfileSyncableService::CreateGUIDToProfileMap(
305 const std::vector<AutofillProfile *>& profiles,
Ilya Sherman 2011/09/03 00:10:57 Nit: No space before the "*"
GeorgeY 2011/09/07 00:28:14 Done.
306 GUIDToProfileMap* profile_map) {
307 DCHECK(profile_map);
308 profile_map->clear();
309 for (size_t i = 0; i < profiles.size(); ++i)
310 (*profile_map)[profiles[i]->guid()] = i;
311 }
312
313 AutofillProfileSyncableService::GUIDToProfileMap::iterator
314 AutofillProfileSyncableService::CreateOrUpdateProfile(
315 const SyncData& data, GUIDToProfileMap* profile_map, DataBundle* bundle) {
316 DCHECK(profile_map);
317 DCHECK(bundle);
318
319 DCHECK_EQ(syncable::AUTOFILL_PROFILE, data.GetDataType());
320
321 const sync_pb::EntitySpecifics& specifics = data.GetSpecifics();
322 const sync_pb::AutofillProfileSpecifics& autofill_specifics(
323 specifics.GetExtension(sync_pb::autofill_profile));
324
325 GUIDToProfileMap::iterator it = profile_map->find(
326 autofill_specifics.guid());
327 if (it != profile_map->end()) {
328 // Some profile that already present is synced.
329 if (OverwriteProfileWithServerData(autofill_specifics,
330 profiles_[it->second]))
331 bundle->updated_profiles.push_back(profiles_[it->second]);
332 } else {
333 // New profile synced.
334 AutofillProfile* new_profile(
335 new AutofillProfile(autofill_specifics.guid()));
336 OverwriteProfileWithServerData(autofill_specifics, new_profile);
337
338 // Check if profile appears under a different guid.
339 for (GUIDToProfileMap::iterator i = profile_map->begin();
340 i != profile_map->end(); ++i) {
341 if (profiles_[i->second]->Compare(*new_profile) == 0) {
342 bundle->profiles_to_delete.push_back(profiles_[i->second]->guid());
343 VLOG(2) << "[AUTOFILL SYNC]"
344 << "Found in sync db but with a different guid: "
345 << UTF16ToUTF8(profiles_[it->second]->GetInfo(NAME_FIRST))
346 << UTF16ToUTF8(profiles_[it->second]->GetInfo(NAME_LAST))
347 << "New guid " << new_profile->guid()
348 << ". Profile to be deleted " << profiles_[it->second]->guid();
349 profile_map->erase(i);
350 break;
351 }
352 }
353 profiles_.push_back(new_profile);
354 it = profile_map->insert(
355 std::make_pair(new_profile->guid(), profiles_.size() - 1)).first;
356 bundle->new_profiles.push_back(new_profile);
357 }
358 return it;
359 }
360
361 void AutofillProfileSyncableService::ActOnChange(
362 const AutofillProfileChange& change) {
363 DCHECK(change.type() == AutofillProfileChange::REMOVE || change.profile());
364 DCHECK(sync_processor_);
365 SyncChangeList new_changes;
366 DataBundle bundle;
367 switch (change.type()) {
368 case AutofillProfileChange::ADD:
369 new_changes.push_back(
370 SyncChange(SyncChange::ACTION_ADD, CreateData(*(change.profile()))));
371 DCHECK(profiles_map_.find(change.profile()->guid()) ==
372 profiles_map_.end());
373 profiles_.push_back(new AutofillProfile(*(change.profile())));
374 profiles_map_[change.profile()->guid()] = profiles_.size() - 1;
375 break;
376 case AutofillProfileChange::UPDATE: {
377 GUIDToProfileMap::iterator it = profiles_map_.find(
378 change.profile()->guid());
379 DCHECK(it != profiles_map_.end());
380 *profiles_[it->second] = *(change.profile());
381 new_changes.push_back(
382 SyncChange(SyncChange::ACTION_UPDATE,
383 CreateData(*(change.profile()))));
384 break;
385 }
386 case AutofillProfileChange::REMOVE: {
387 AutofillProfile empty_profile(change.key());
388 new_changes.push_back(SyncChange(SyncChange::ACTION_DELETE,
389 CreateData(empty_profile)));
390 profiles_map_.erase(change.key());
391 break;
392 }
393 default:
394 NOTREACHED();
395 }
396 SyncError error = sync_processor_->ProcessSyncChanges(FROM_HERE, new_changes);
397 if (error.IsSet()) {
398 LOG(WARNING) << "[AUTOFILL SYNC]"
399 << " Failed processing change:"
400 << " Error:" << error.message()
401 << " Guid:" << change.profile()->guid();
402 }
403 }
404
405 SyncData AutofillProfileSyncableService::CreateData(
406 const AutofillProfile& profile) {
407 sync_pb::EntitySpecifics specifics;
408 WriteAutofillProfile(profile, &specifics);
409 return SyncData::CreateLocalData(profile.guid(), profile.guid(), specifics);
410 }
411
412 AutofillProfileSyncableService::DataBundle::DataBundle() {}
413
414 AutofillProfileSyncableService::DataBundle::~DataBundle() {
415 }
416
417 } // namespace browser_sync
418
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698