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

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, CreateData(*(i->second))));
117 profiles_map_[i->first] = i->second;
118 }
119
120 SyncError error = sync_processor_->ProcessSyncChanges(FROM_HERE, new_changes);
121
122 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
123 new DoOptimisticRefreshForAutofill(personal_data_));
124
125 return error;
126 }
127
128 void AutofillProfileSyncableService::StopSyncing(syncable::ModelType type) {
129 DCHECK(CalledOnValidThread());
130 DCHECK(sync_processor_ != NULL);
131 DCHECK_EQ(type, syncable::AUTOFILL_PROFILE);
132
133 sync_processor_ = NULL;
134 profiles_.reset();
135 profiles_map_.clear();
136 }
137
138 SyncDataList AutofillProfileSyncableService::GetAllSyncData(
139 syncable::ModelType type) const {
140 DCHECK(CalledOnValidThread());
141 DCHECK(sync_processor_ != NULL);
142 DCHECK_EQ(type, syncable::AUTOFILL_PROFILE);
143
144 SyncDataList current_data;
145
146 for (GUIDToProfileMap::const_iterator i = profiles_map_.begin();
147 i != profiles_map_.end(); ++i) {
148 current_data.push_back(CreateData(*(i->second)));
149 }
150 return current_data;
151 }
152
153 SyncError AutofillProfileSyncableService::ProcessSyncChanges(
154 const tracked_objects::Location& from_here,
155 const SyncChangeList& change_list) {
156 DCHECK(CalledOnValidThread());
157 DCHECK(sync_processor_ != NULL);
158 if (sync_processor_ == NULL) {
159 SyncError error(FROM_HERE, "Models not yet associated.",
160 syncable::AUTOFILL_PROFILE);
161 return error;
162 }
163
164 DataBundle bundle;
165
166 for (SyncChangeList::const_iterator i = change_list.begin();
167 i != change_list.end(); ++i) {
168 DCHECK(i->IsValid());
169 switch (i->change_type()) {
170 case SyncChange::ACTION_ADD:
171 case SyncChange::ACTION_UPDATE:
172 CreateOrUpdateProfile(i->sync_data(), &profiles_map_, &bundle);
173 break;
174 case SyncChange::ACTION_DELETE: {
175 std::string guid = i->sync_data().GetSpecifics().
176 GetExtension(sync_pb::autofill_profile).guid();
177 bundle.profiles_to_delete.push_back(guid);
178 profiles_map_.erase(guid);
179 } break;
180 default:
181 NOTREACHED() << "Unexpected sync change state.";
182 return SyncError(FROM_HERE, "ProcessSyncChanges failed on ChangeType " +
183 SyncChange::ChangeTypeToString(i->change_type()),
184 syncable::AUTOFILL_PROFILE);
185 }
186 }
187
188 if (!SaveChangesToWebData(bundle))
189 return SyncError(FROM_HERE, "Failed to update webdata.", model_type());
190
191 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
192 new DoOptimisticRefreshForAutofill(personal_data_));
193 return SyncError();
194 }
195
196 void AutofillProfileSyncableService::Observe(int type,
197 const NotificationSource& source,
198 const NotificationDetails& details) {
199 DCHECK_EQ(type, chrome::NOTIFICATION_AUTOFILL_PROFILE_CHANGED);
200 // Check if sync is on. If we receive notification prior to the sync being set
201 // up we are going to process all when MergeData..() is called. If we receive
202 // notification after the sync exited, it will be sinced next time Chrome
203 // starts.
204 if (!sync_processor_)
205 return;
206 WebDataService* wds = Source<WebDataService>(source).ptr();
207
208 DCHECK(wds && wds->GetDatabase() == web_database_);
209
210 AutofillProfileChange* change = Details<AutofillProfileChange>(details).ptr();
211
212 ActOnChange(*change);
213 }
214
215 bool AutofillProfileSyncableService::LoadAutofillData(
216 std::vector<AutofillProfile*>* profiles) {
217 return web_database_->GetAutofillTable()->GetAutofillProfiles(profiles);
218 }
219
220 bool AutofillProfileSyncableService::SaveChangesToWebData(
221 const DataBundle& bundle) {
222 DCHECK(CalledOnValidThread());
223
224 for (size_t i = 0; i < bundle.profiles_to_add.size(); i++) {
225 if (!web_database_->GetAutofillTable()->AddAutofillProfile(
226 *bundle.profiles_to_add[i]))
227 return false;
228 }
229
230 for (size_t i = 0; i < bundle.profiles_to_update.size(); i++) {
231 if (!web_database_->GetAutofillTable()->UpdateAutofillProfile(
232 *bundle.profiles_to_update[i]))
233 return false;
234 }
235
236 for (size_t i = 0; i< bundle.profiles_to_delete.size(); ++i) {
237 if (!web_database_->GetAutofillTable()->RemoveAutofillProfile(
238 bundle.profiles_to_delete[i]))
239 return false;
240 }
241 return true;
242 }
243
244 // static
245 bool AutofillProfileSyncableService::OverwriteProfileWithServerData(
246 const sync_pb::AutofillProfileSpecifics& specifics,
247 AutofillProfile* profile) {
248 bool diff = false;
249 diff = MergeField(profile, NAME_FIRST, specifics.name_first()) || diff;
250 diff = MergeField(profile, NAME_LAST, specifics.name_last()) || diff;
251 diff = MergeField(profile, NAME_MIDDLE, specifics.name_middle()) || diff;
252 diff = MergeField(profile, ADDRESS_HOME_LINE1,
253 specifics.address_home_line1()) || diff;
254 diff = MergeField(profile, ADDRESS_HOME_LINE2,
255 specifics.address_home_line2()) || diff;
256 diff = MergeField(profile, ADDRESS_HOME_CITY,
257 specifics.address_home_city()) || diff;
258 diff = MergeField(profile, ADDRESS_HOME_STATE,
259 specifics.address_home_state()) || diff;
260 diff = MergeField(profile, ADDRESS_HOME_COUNTRY,
261 specifics.address_home_country()) || diff;
262 diff = MergeField(profile, ADDRESS_HOME_ZIP,
263 specifics.address_home_zip()) || diff;
264 diff = MergeField(profile, EMAIL_ADDRESS, specifics.email_address()) || diff;
265 diff = MergeField(profile, COMPANY_NAME, specifics.company_name()) || diff;
266 diff = MergeField(profile, PHONE_FAX_WHOLE_NUMBER,
267 specifics.phone_fax_whole_number()) || diff;
268 diff = MergeField(profile, PHONE_HOME_WHOLE_NUMBER,
269 specifics.phone_home_whole_number()) || diff;
270 return diff;
271 }
272
273 // static
274 void AutofillProfileSyncableService::WriteAutofillProfile(
275 const AutofillProfile& profile,
276 sync_pb::EntitySpecifics* profile_specifics) {
277 sync_pb::AutofillProfileSpecifics* specifics =
278 profile_specifics->MutableExtension(sync_pb::autofill_profile);
279
280 DCHECK(guid::IsValidGUID(profile.guid()));
281
282 specifics->set_guid(profile.guid());
283 specifics->set_name_first(UTF16ToUTF8(profile.GetInfo(NAME_FIRST)));
284 specifics->set_name_middle(UTF16ToUTF8(profile.GetInfo(NAME_MIDDLE)));
285 specifics->set_name_last(UTF16ToUTF8(profile.GetInfo(NAME_LAST)));
286 specifics->set_address_home_line1(
287 UTF16ToUTF8(profile.GetInfo(ADDRESS_HOME_LINE1)));
288 specifics->set_address_home_line2(
289 UTF16ToUTF8(profile.GetInfo(ADDRESS_HOME_LINE2)));
290 specifics->set_address_home_city(UTF16ToUTF8(profile.GetInfo(
291 ADDRESS_HOME_CITY)));
292 specifics->set_address_home_state(UTF16ToUTF8(profile.GetInfo(
293 ADDRESS_HOME_STATE)));
294 specifics->set_address_home_country(UTF16ToUTF8(profile.GetInfo(
295 ADDRESS_HOME_COUNTRY)));
296 specifics->set_address_home_zip(UTF16ToUTF8(profile.GetInfo(
297 ADDRESS_HOME_ZIP)));
298 specifics->set_email_address(UTF16ToUTF8(profile.GetInfo(EMAIL_ADDRESS)));
299 specifics->set_company_name(UTF16ToUTF8(profile.GetInfo(COMPANY_NAME)));
300 specifics->set_phone_fax_whole_number(UTF16ToUTF8(profile.GetInfo(
301 PHONE_FAX_WHOLE_NUMBER)));
302 specifics->set_phone_home_whole_number(UTF16ToUTF8(profile.GetInfo(
303 PHONE_HOME_WHOLE_NUMBER)));
304 }
305
306 void AutofillProfileSyncableService::CreateGUIDToProfileMap(
307 const std::vector<AutofillProfile*>& profiles,
308 GUIDToProfileMap* profile_map) {
309 DCHECK(profile_map);
310 profile_map->clear();
311 for (size_t i = 0; i < profiles.size(); ++i)
312 (*profile_map)[profiles[i]->guid()] = profiles[i];
313 }
314
315 AutofillProfileSyncableService::GUIDToProfileMap::iterator
316 AutofillProfileSyncableService::CreateOrUpdateProfile(
317 const SyncData& data, GUIDToProfileMap* profile_map, DataBundle* bundle) {
318 DCHECK(profile_map);
319 DCHECK(bundle);
320
321 DCHECK_EQ(syncable::AUTOFILL_PROFILE, data.GetDataType());
322
323 const sync_pb::EntitySpecifics& specifics = data.GetSpecifics();
324 const sync_pb::AutofillProfileSpecifics& autofill_specifics(
325 specifics.GetExtension(sync_pb::autofill_profile));
326
327 GUIDToProfileMap::iterator it = profile_map->find(
328 autofill_specifics.guid());
329 if (it != profile_map->end()) {
330 // Some profile that already present is synced.
331 if (OverwriteProfileWithServerData(autofill_specifics, it->second))
332 bundle->profiles_to_update.push_back(it->second);
333 } else {
334 // New profile synced.
335 AutofillProfile* new_profile(
336 new AutofillProfile(autofill_specifics.guid()));
337 OverwriteProfileWithServerData(autofill_specifics, new_profile);
338
339 // Check if profile appears under a different guid.
340 for (GUIDToProfileMap::iterator i = profile_map->begin();
341 i != profile_map->end(); ++i) {
342 if (i->second->Compare(*new_profile) == 0) {
343 bundle->profiles_to_delete.push_back(i->second->guid());
344 VLOG(2) << "[AUTOFILL SYNC]"
345 << "Found in sync db but with a different guid: "
346 << UTF16ToUTF8(it->second->GetInfo(NAME_FIRST))
347 << UTF16ToUTF8(it->second->GetInfo(NAME_LAST))
348 << "New guid " << new_profile->guid()
349 << ". Profile to be deleted " << it->second->guid();
350 profile_map->erase(i);
351 break;
352 }
353 }
354 profiles_.push_back(new_profile);
355 it = profile_map->insert(std::make_pair(new_profile->guid(),
356 new_profile)).first;
357 bundle->profiles_to_add.push_back(new_profile);
358 }
359 return it;
360 }
361
362 void AutofillProfileSyncableService::ActOnChange(
363 const AutofillProfileChange& change) {
364 DCHECK((change.type() == AutofillProfileChange::REMOVE &&
365 !change.profile()) ||
366 (change.type() != AutofillProfileChange::REMOVE && change.profile()));
367 DCHECK(sync_processor_);
368 SyncChangeList new_changes;
369 DataBundle bundle;
370 switch (change.type()) {
371 case AutofillProfileChange::ADD:
372 new_changes.push_back(
373 SyncChange(SyncChange::ACTION_ADD, CreateData(*(change.profile()))));
374 DCHECK(profiles_map_.find(change.profile()->guid()) ==
375 profiles_map_.end());
376 profiles_.push_back(new AutofillProfile(*(change.profile())));
377 profiles_map_[change.profile()->guid()] = profiles_.get().back();
378 break;
379 case AutofillProfileChange::UPDATE: {
380 GUIDToProfileMap::iterator it = profiles_map_.find(
381 change.profile()->guid());
382 DCHECK(it != profiles_map_.end());
383 *(it->second) = *(change.profile());
384 new_changes.push_back(
385 SyncChange(SyncChange::ACTION_UPDATE,
386 CreateData(*(change.profile()))));
387 break;
388 }
389 case AutofillProfileChange::REMOVE: {
390 AutofillProfile empty_profile(change.key());
391 new_changes.push_back(SyncChange(SyncChange::ACTION_DELETE,
392 CreateData(empty_profile)));
393 profiles_map_.erase(change.key());
394 break;
395 }
396 default:
397 NOTREACHED();
398 }
399 SyncError error = sync_processor_->ProcessSyncChanges(FROM_HERE, new_changes);
400 if (error.IsSet()) {
401 LOG(WARNING) << "[AUTOFILL SYNC]"
402 << " Failed processing change:"
403 << " Error:" << error.message()
404 << " Guid:" << change.profile()->guid();
405 }
406 }
407
408 SyncData AutofillProfileSyncableService::CreateData(
409 const AutofillProfile& profile) {
410 sync_pb::EntitySpecifics specifics;
411 WriteAutofillProfile(profile, &specifics);
412 return SyncData::CreateLocalData(profile.guid(), profile.guid(), specifics);
413 }
414
415 AutofillProfileSyncableService::DataBundle::DataBundle() {}
416
417 AutofillProfileSyncableService::DataBundle::~DataBundle() {
418 }
419
420 } // namespace browser_sync
421
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698