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

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,
dhollowa 2011/09/07 01:48:16 nit: output parameters should follow input paramet
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,
dhollowa 2011/09/07 21:10:24 nit:indent
GeorgeY 2011/09/07 23:26:24 Done.
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,
dhollowa 2011/09/07 21:10:24 nit: indent
GeorgeY 2011/09/07 23:26:24 Done. ?!@ autoformat in VS Editor when I move stuf
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 WebDataService* wds = Source<WebDataService>(source).ptr();
201
202 DCHECK(wds && wds->GetDatabase() == web_database_);
203
204 AutofillProfileChange* change = Details<AutofillProfileChange>(details).ptr();
205
206 ActOnChange(*change);
207 }
208
209 bool AutofillProfileSyncableService::LoadAutofillData(
210 std::vector<AutofillProfile*>* profiles) {
211 if (!web_database_->GetAutofillTable()->GetAutofillProfiles(profiles))
212 return false;
213
214 return true;
215 }
216
217 bool AutofillProfileSyncableService::SaveChangesToWebData(
218 const DataBundle& bundle) {
219 DCHECK(CalledOnValidThread());
220
221 for (size_t i = 0; i < bundle.new_profiles.size(); i++) {
222 if (!web_database_->GetAutofillTable()->AddAutofillProfile(
223 *bundle.new_profiles[i]))
224 return false;
225 }
226
227 for (size_t i = 0; i < bundle.updated_profiles.size(); i++) {
228 if (!web_database_->GetAutofillTable()->UpdateAutofillProfile(
229 *bundle.updated_profiles[i]))
230 return false;
231 }
232
233 for (size_t i = 0; i< bundle.profiles_to_delete.size(); ++i) {
234 if (!web_database_->GetAutofillTable()->RemoveAutofillProfile(
235 bundle.profiles_to_delete[i]))
236 return false;
237 }
238 return true;
239 }
240
241 // static
242 bool AutofillProfileSyncableService::OverwriteProfileWithServerData(
243 const sync_pb::AutofillProfileSpecifics& specifics,
244 AutofillProfile* profile) {
245 bool diff = false;
246 diff = MergeField(profile, NAME_FIRST, specifics.name_first()) || diff;
247 diff = MergeField(profile, NAME_LAST, specifics.name_last()) || diff;
248 diff = MergeField(profile, NAME_MIDDLE, specifics.name_middle()) || diff;
249 diff = MergeField(profile, ADDRESS_HOME_LINE1,
250 specifics.address_home_line1()) || diff;
251 diff = MergeField(profile, ADDRESS_HOME_LINE2,
252 specifics.address_home_line2()) || diff;
253 diff = MergeField(profile, ADDRESS_HOME_CITY,
254 specifics.address_home_city()) || diff;
255 diff = MergeField(profile, ADDRESS_HOME_STATE,
256 specifics.address_home_state()) || diff;
257 diff = MergeField(profile, ADDRESS_HOME_COUNTRY,
258 specifics.address_home_country()) || diff;
259 diff = MergeField(profile, ADDRESS_HOME_ZIP,
260 specifics.address_home_zip()) || diff;
261 diff = MergeField(profile, EMAIL_ADDRESS, specifics.email_address()) || diff;
262 diff = MergeField(profile, COMPANY_NAME, specifics.company_name()) || diff;
263 diff = MergeField(profile, PHONE_FAX_WHOLE_NUMBER,
264 specifics.phone_fax_whole_number()) || diff;
265 diff = MergeField(profile, PHONE_HOME_WHOLE_NUMBER,
266 specifics.phone_home_whole_number()) || diff;
267 return diff;
268 }
269
270 // static
271 void AutofillProfileSyncableService::WriteAutofillProfile(
272 const AutofillProfile& profile,
273 sync_pb::EntitySpecifics* profile_specifics) {
274 sync_pb::AutofillProfileSpecifics* specifics =
275 profile_specifics->MutableExtension(sync_pb::autofill_profile);
276
277 DCHECK(guid::IsValidGUID(profile.guid()));
278
279 specifics->set_guid(profile.guid());
280 specifics->set_name_first(UTF16ToUTF8(profile.GetInfo(NAME_FIRST)));
281 specifics->set_name_middle(UTF16ToUTF8(profile.GetInfo(NAME_MIDDLE)));
282 specifics->set_name_last(UTF16ToUTF8(profile.GetInfo(NAME_LAST)));
283 specifics->set_address_home_line1(
284 UTF16ToUTF8(profile.GetInfo(ADDRESS_HOME_LINE1)));
285 specifics->set_address_home_line2(
286 UTF16ToUTF8(profile.GetInfo(ADDRESS_HOME_LINE2)));
287 specifics->set_address_home_city(UTF16ToUTF8(profile.GetInfo(
288 ADDRESS_HOME_CITY)));
289 specifics->set_address_home_state(UTF16ToUTF8(profile.GetInfo(
290 ADDRESS_HOME_STATE)));
291 specifics->set_address_home_country(UTF16ToUTF8(profile.GetInfo(
292 ADDRESS_HOME_COUNTRY)));
293 specifics->set_address_home_zip(UTF16ToUTF8(profile.GetInfo(
294 ADDRESS_HOME_ZIP)));
295 specifics->set_email_address(UTF16ToUTF8(profile.GetInfo(EMAIL_ADDRESS)));
296 specifics->set_company_name(UTF16ToUTF8(profile.GetInfo(COMPANY_NAME)));
297 specifics->set_phone_fax_whole_number(UTF16ToUTF8(profile.GetInfo(
298 PHONE_FAX_WHOLE_NUMBER)));
299 specifics->set_phone_home_whole_number(UTF16ToUTF8(profile.GetInfo(
300 PHONE_HOME_WHOLE_NUMBER)));
301 }
302
303 void AutofillProfileSyncableService::CreateGUIDToProfileMap(
304 const std::vector<AutofillProfile*>& profiles,
305 GUIDToProfileMap* profile_map) {
306 DCHECK(profile_map);
307 profile_map->clear();
308 for (size_t i = 0; i < profiles.size(); ++i)
309 (*profile_map)[profiles[i]->guid()] = profiles[i];
310 }
311
312 AutofillProfileSyncableService::GUIDToProfileMap::iterator
313 AutofillProfileSyncableService::CreateOrUpdateProfile(
314 const SyncData& data, GUIDToProfileMap* profile_map, DataBundle* bundle) {
315 DCHECK(profile_map);
316 DCHECK(bundle);
317
318 DCHECK_EQ(syncable::AUTOFILL_PROFILE, data.GetDataType());
319
320 const sync_pb::EntitySpecifics& specifics = data.GetSpecifics();
321 const sync_pb::AutofillProfileSpecifics& autofill_specifics(
322 specifics.GetExtension(sync_pb::autofill_profile));
323
324 GUIDToProfileMap::iterator it = profile_map->find(
325 autofill_specifics.guid());
326 if (it != profile_map->end()) {
327 // Some profile that already present is synced.
328 if (OverwriteProfileWithServerData(autofill_specifics, it->second))
329 bundle->updated_profiles.push_back(it->second);
330 } else {
331 // New profile synced.
332 AutofillProfile* new_profile(
333 new AutofillProfile(autofill_specifics.guid()));
334 OverwriteProfileWithServerData(autofill_specifics, new_profile);
335
336 // Check if profile appears under a different guid.
337 for (GUIDToProfileMap::iterator i = profile_map->begin();
338 i != profile_map->end(); ++i) {
339 if (i->second->Compare(*new_profile) == 0) {
340 bundle->profiles_to_delete.push_back(i->second->guid());
341 VLOG(2) << "[AUTOFILL SYNC]"
342 << "Found in sync db but with a different guid: "
343 << UTF16ToUTF8(it->second->GetInfo(NAME_FIRST))
344 << UTF16ToUTF8(it->second->GetInfo(NAME_LAST))
345 << "New guid " << new_profile->guid()
346 << ". Profile to be deleted " << it->second->guid();
347 profile_map->erase(i);
348 break;
349 }
350 }
351 profiles_.push_back(new_profile);
352 it = profile_map->insert(std::make_pair(new_profile->guid(),
353 new_profile)).first;
354 bundle->new_profiles.push_back(new_profile);
355 }
356 return it;
357 }
358
359 void AutofillProfileSyncableService::ActOnChange(
360 const AutofillProfileChange& change) {
361 DCHECK(change.type() == AutofillProfileChange::REMOVE || change.profile());
362 DCHECK(sync_processor_);
363 SyncChangeList new_changes;
364 DataBundle bundle;
365 switch (change.type()) {
366 case AutofillProfileChange::ADD:
367 new_changes.push_back(
368 SyncChange(SyncChange::ACTION_ADD, CreateData(*(change.profile()))));
369 DCHECK(profiles_map_.find(change.profile()->guid()) ==
370 profiles_map_.end());
371 profiles_.push_back(new AutofillProfile(*(change.profile())));
372 profiles_map_[change.profile()->guid()] = profiles_.get().back();
373 break;
374 case AutofillProfileChange::UPDATE: {
375 GUIDToProfileMap::iterator it = profiles_map_.find(
376 change.profile()->guid());
377 DCHECK(it != profiles_map_.end());
378 *(it->second) = *(change.profile());
379 new_changes.push_back(
380 SyncChange(SyncChange::ACTION_UPDATE,
381 CreateData(*(change.profile()))));
382 break;
383 }
384 case AutofillProfileChange::REMOVE: {
385 AutofillProfile empty_profile(change.key());
386 new_changes.push_back(SyncChange(SyncChange::ACTION_DELETE,
387 CreateData(empty_profile)));
388 profiles_map_.erase(change.key());
389 break;
390 }
391 default:
392 NOTREACHED();
393 }
394 SyncError error = sync_processor_->ProcessSyncChanges(FROM_HERE, new_changes);
395 if (error.IsSet()) {
396 LOG(WARNING) << "[AUTOFILL SYNC]"
397 << " Failed processing change:"
398 << " Error:" << error.message()
399 << " Guid:" << change.profile()->guid();
400 }
401 }
402
403 SyncData AutofillProfileSyncableService::CreateData(
404 const AutofillProfile& profile) {
405 sync_pb::EntitySpecifics specifics;
406 WriteAutofillProfile(profile, &specifics);
407 return SyncData::CreateLocalData(profile.guid(), profile.guid(), specifics);
408 }
409
410 AutofillProfileSyncableService::DataBundle::DataBundle() {}
411
412 AutofillProfileSyncableService::DataBundle::~DataBundle() {
413 }
414
415 } // namespace browser_sync
416
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698