OLD | NEW |
(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_change_processor.h" |
| 6 |
| 7 #include <string> |
| 8 #include <vector> |
| 9 |
| 10 #include "base/string_util.h" |
| 11 #include "base/utf_string_conversions.h" |
| 12 #include "chrome/browser/autofill/autofill_profile.h" |
| 13 #include "chrome/browser/autofill/personal_data_manager.h" |
| 14 #include "chrome/browser/sync/engine/syncapi.h" |
| 15 #include "chrome/browser/sync/glue/autofill_profile_model_associator.h" |
| 16 #include "chrome/browser/sync/glue/change_processor.h" |
| 17 #include "chrome/browser/sync/glue/do_optimistic_refresh_task.h" |
| 18 #include "chrome/browser/sync/unrecoverable_error_handler.h" |
| 19 #include "chrome/browser/webdata/autofill_change.h" |
| 20 #include "chrome/browser/webdata/web_database.h" |
| 21 #include "chrome/common/notification_observer.h" |
| 22 #include "chrome/common/notification_registrar.h" |
| 23 #include "chrome/common/notification_service.h" |
| 24 #include "chrome/common/notification_type.h" |
| 25 |
| 26 namespace browser_sync { |
| 27 |
| 28 AutofillProfileChangeProcessor::AutofillProfileChangeProcessor( |
| 29 AutofillProfileModelAssociator *model_associator, |
| 30 WebDatabase* web_database, |
| 31 PersonalDataManager* personal_data_manager, |
| 32 UnrecoverableErrorHandler* error_handler) |
| 33 : ChangeProcessor(error_handler), |
| 34 model_associator_(model_associator), |
| 35 observing_(false), |
| 36 web_database_(web_database), |
| 37 personal_data_(personal_data_manager) { |
| 38 DCHECK(model_associator); |
| 39 DCHECK(web_database); |
| 40 DCHECK(error_handler); |
| 41 DCHECK(personal_data_manager); |
| 42 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); |
| 43 |
| 44 StartObserving(); |
| 45 } |
| 46 |
| 47 AutofillProfileChangeProcessor::ScopedStopObserving::ScopedStopObserving( |
| 48 AutofillProfileChangeProcessor* processor) { |
| 49 processor_ = processor; |
| 50 processor_->StopObserving(); |
| 51 } |
| 52 |
| 53 AutofillProfileChangeProcessor::ScopedStopObserving::~ScopedStopObserving() { |
| 54 processor_->StartObserving(); |
| 55 } |
| 56 |
| 57 void AutofillProfileChangeProcessor::ApplyChangesFromSyncModel( |
| 58 const sync_api::BaseTransaction *write_trans, |
| 59 const sync_api::SyncManager::ChangeRecord* changes, |
| 60 int change_count) { |
| 61 |
| 62 ScopedStopObserving observer(this); |
| 63 |
| 64 sync_api::ReadNode autofill_profile_root(write_trans); |
| 65 if (!autofill_profile_root.InitByTagLookup(kAutofillProfileTag)) { |
| 66 error_handler()->OnUnrecoverableError(FROM_HERE, |
| 67 "Autofill Profile root node lookup failed"); |
| 68 return; |
| 69 } |
| 70 |
| 71 for (int i = 0; i < change_count; ++i) { |
| 72 if (sync_api::SyncManager::ChangeRecord::ACTION_DELETE == |
| 73 changes[i].action) { |
| 74 DCHECK(changes[i].specifics.HasExtension( |
| 75 sync_pb::autofill_profile)); |
| 76 |
| 77 const sync_pb::AutofillProfileSpecifics& specifics = |
| 78 changes[i].specifics.GetExtension(sync_pb::autofill_profile); |
| 79 |
| 80 autofill_changes_.push_back(AutofillProfileChangeRecord(changes[i].action, |
| 81 changes[i].id, |
| 82 specifics)); |
| 83 continue; |
| 84 } |
| 85 |
| 86 // If it is not a delete. |
| 87 sync_api::ReadNode sync_node(write_trans); |
| 88 if (!sync_node.InitByIdLookup(changes[i].id)) { |
| 89 LOG(ERROR) << "Could not find the id in sync db " << changes[i].id; |
| 90 continue; |
| 91 } |
| 92 |
| 93 const sync_pb::AutofillProfileSpecifics& autofill( |
| 94 sync_node.GetAutofillProfileSpecifics()); |
| 95 |
| 96 autofill_changes_.push_back(AutofillProfileChangeRecord(changes[i].action, |
| 97 changes[i].id, |
| 98 autofill)); |
| 99 } |
| 100 } |
| 101 |
| 102 void AutofillProfileChangeProcessor::Observe(NotificationType type, |
| 103 const NotificationSource& source, |
| 104 const NotificationDetails& details) { |
| 105 DCHECK_EQ(type.value, NotificationType::AUTOFILL_PROFILE_CHANGED_GUID); |
| 106 WebDataService* wds = Source<WebDataService>(source).ptr(); |
| 107 |
| 108 if (!wds || wds->GetDatabase() != web_database_) |
| 109 return; |
| 110 |
| 111 sync_api::WriteTransaction trans(share_handle()); |
| 112 sync_api::ReadNode autofill_root(&trans); |
| 113 if (!autofill_root.InitByTagLookup(kAutofillProfileTag)) { |
| 114 error_handler()->OnUnrecoverableError(FROM_HERE, |
| 115 "Server did not create a tolp level node"); |
| 116 return; |
| 117 } |
| 118 |
| 119 AutofillProfileChangeGUID* change = |
| 120 Details<AutofillProfileChangeGUID>(details).ptr(); |
| 121 |
| 122 ActOnChange(change, &trans, autofill_root); |
| 123 } |
| 124 |
| 125 void AutofillProfileChangeProcessor::ActOnChange( |
| 126 AutofillProfileChangeGUID* change, |
| 127 sync_api::WriteTransaction* trans, |
| 128 sync_api::ReadNode& autofill_root) { |
| 129 DCHECK(change->type() == AutofillProfileChangeGUID::REMOVE || |
| 130 change->profile()); |
| 131 switch (change->type()) { |
| 132 case AutofillProfileChangeGUID::ADD: { |
| 133 AddAutofillProfileSyncNode(trans, autofill_root, *(change->profile())); |
| 134 break; |
| 135 } |
| 136 case AutofillProfileChangeGUID::UPDATE: { |
| 137 int64 sync_id = model_associator_->GetSyncIdFromChromeId(change->key()); |
| 138 if (sync_api::kInvalidId == sync_id) { |
| 139 LOG(ERROR) << "Sync id is not found for " << change->key(); |
| 140 break; |
| 141 } |
| 142 sync_api::WriteNode node(trans); |
| 143 if (!node.InitByIdLookup(sync_id)) { |
| 144 LOG(ERROR) << "Could not find sync node for id " << sync_id; |
| 145 break; |
| 146 } |
| 147 |
| 148 WriteAutofillProfile(*(change->profile()), &node); |
| 149 break; |
| 150 } |
| 151 case AutofillProfileChangeGUID::REMOVE: { |
| 152 int64 sync_id = model_associator_->GetSyncIdFromChromeId(change->key()); |
| 153 if (sync_api::kInvalidId == sync_id) { |
| 154 LOG(ERROR) << "Sync id is not found for " << change->key(); |
| 155 break; |
| 156 } |
| 157 sync_api::WriteNode node(trans); |
| 158 if (!node.InitByIdLookup(sync_id)) { |
| 159 LOG(ERROR) << "Could not find sync node for id " << sync_id; |
| 160 break; |
| 161 } |
| 162 node.Remove(); |
| 163 model_associator_->Disassociate(sync_id); |
| 164 break; |
| 165 } |
| 166 default: |
| 167 NOTREACHED(); |
| 168 } |
| 169 } |
| 170 |
| 171 void AutofillProfileChangeProcessor::CommitChangesFromSyncModel() { |
| 172 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); |
| 173 |
| 174 if (!running()) |
| 175 return; |
| 176 |
| 177 ScopedStopObserving observer(this); |
| 178 |
| 179 for (unsigned int i = 0;i < autofill_changes_.size(); ++i) { |
| 180 if (sync_api::SyncManager::ChangeRecord::ACTION_DELETE == |
| 181 autofill_changes_[i].action_) { |
| 182 if (!web_database_->RemoveAutoFillProfile( |
| 183 autofill_changes_[i].profile_specifics_.guid())) { |
| 184 LOG(ERROR) << "could not delete the profile " << |
| 185 autofill_changes_[i].profile_specifics_.guid(); |
| 186 continue; |
| 187 } |
| 188 continue; |
| 189 } |
| 190 |
| 191 // Now for updates and adds. |
| 192 ApplyAutofillProfileChange(autofill_changes_[i].action_, |
| 193 autofill_changes_[i].profile_specifics_, |
| 194 autofill_changes_[i].id_); |
| 195 } |
| 196 |
| 197 autofill_changes_.clear(); |
| 198 |
| 199 PostOptimisticRefreshTask(); |
| 200 } |
| 201 |
| 202 void AutofillProfileChangeProcessor::PostOptimisticRefreshTask() { |
| 203 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
| 204 new DoOptimisticRefreshForAutofill( |
| 205 personal_data_)); |
| 206 } |
| 207 |
| 208 void AutofillProfileChangeProcessor::ApplyAutofillProfileChange( |
| 209 sync_api::SyncManager::ChangeRecord::Action action, |
| 210 const sync_pb::AutofillProfileSpecifics& profile_specifics, |
| 211 int64 sync_id) { |
| 212 |
| 213 DCHECK_NE(sync_api::SyncManager::ChangeRecord::ACTION_DELETE, action); |
| 214 switch (action) { |
| 215 case sync_api::SyncManager::ChangeRecord::ACTION_ADD: { |
| 216 AutoFillProfile p(profile_specifics.guid()); |
| 217 AutofillProfileModelAssociator::OverwriteProfileWithServerData(&p, |
| 218 profile_specifics); |
| 219 if (!web_database_->AddAutoFillProfile(p)) { |
| 220 LOG(ERROR) << "could not add autofill profile for guid " << p.guid(); |
| 221 break; |
| 222 } |
| 223 |
| 224 // Now that the node has been succesfully created we can associate it. |
| 225 std::string guid = p.guid(); |
| 226 model_associator_->Associate(&guid, sync_id); |
| 227 break; |
| 228 } |
| 229 case sync_api::SyncManager::ChangeRecord::ACTION_UPDATE: { |
| 230 AutoFillProfile *p; |
| 231 if (!web_database_->GetAutoFillProfileForGUID( |
| 232 profile_specifics.guid(), &p)) { |
| 233 LOG(ERROR) << "Could not find the autofill profile to update for " << |
| 234 profile_specifics.guid(); |
| 235 break; |
| 236 } |
| 237 scoped_ptr<AutoFillProfile> autofill_pointer(p); |
| 238 AutofillProfileModelAssociator::OverwriteProfileWithServerData( |
| 239 autofill_pointer.get(), |
| 240 profile_specifics); |
| 241 |
| 242 if (!web_database_->UpdateAutoFillProfile(*(autofill_pointer.get()))) { |
| 243 LOG(ERROR) << "Could not update autofill profile for " << |
| 244 profile_specifics.guid(); |
| 245 break; |
| 246 } |
| 247 break; |
| 248 } |
| 249 default: { |
| 250 NOTREACHED(); |
| 251 break; |
| 252 } |
| 253 } |
| 254 } |
| 255 |
| 256 void AutofillProfileChangeProcessor::RemoveSyncNode(const std::string& guid, |
| 257 sync_api::WriteTransaction* trans) { |
| 258 sync_api::WriteNode node(trans); |
| 259 int64 sync_id = model_associator_->GetSyncIdFromChromeId(guid); |
| 260 if (sync_api::kInvalidId == sync_id) { |
| 261 LOG(ERROR) << "Could not find the node in associator " << guid; |
| 262 return; |
| 263 } |
| 264 |
| 265 if (!node.InitByIdLookup(sync_id)) { |
| 266 LOG(ERROR) << "Could not find the sync node for " << guid; |
| 267 return; |
| 268 } |
| 269 |
| 270 model_associator_->Disassociate(sync_id); |
| 271 node.Remove(); |
| 272 } |
| 273 |
| 274 void AutofillProfileChangeProcessor::AddAutofillProfileSyncNode( |
| 275 sync_api::WriteTransaction* trans, |
| 276 sync_api::BaseNode& autofill_profile_root, |
| 277 const AutoFillProfile& profile) { |
| 278 sync_api::WriteNode node(trans); |
| 279 if (!node.InitUniqueByCreation(syncable::AUTOFILL_PROFILE, |
| 280 autofill_profile_root, |
| 281 profile.guid())) { |
| 282 LOG(ERROR) << "could not create a sync node "; |
| 283 return; |
| 284 } |
| 285 |
| 286 node.SetTitle(UTF8ToWide(profile.guid())); |
| 287 |
| 288 WriteAutofillProfile(profile, &node); |
| 289 } |
| 290 |
| 291 void AutofillProfileChangeProcessor::StartObserving() { |
| 292 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); |
| 293 notification_registrar_.Add(this, |
| 294 NotificationType::AUTOFILL_PROFILE_CHANGED_GUID, |
| 295 NotificationService::AllSources()); |
| 296 } |
| 297 |
| 298 void AutofillProfileChangeProcessor::StopObserving() { |
| 299 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); |
| 300 notification_registrar_.RemoveAll(); |
| 301 } |
| 302 |
| 303 void AutofillProfileChangeProcessor::WriteAutofillProfile( |
| 304 const AutoFillProfile& profile, |
| 305 sync_api::WriteNode* node) { |
| 306 sync_pb::AutofillProfileSpecifics specifics; |
| 307 specifics.set_guid(profile.guid()); |
| 308 specifics.set_name_first(UTF16ToUTF8( |
| 309 profile.GetFieldText(AutoFillType(NAME_FIRST)))); |
| 310 specifics.set_name_middle(UTF16ToUTF8( |
| 311 profile.GetFieldText(AutoFillType(NAME_MIDDLE)))); |
| 312 specifics.set_name_last( |
| 313 UTF16ToUTF8(profile.GetFieldText(AutoFillType(NAME_LAST)))); |
| 314 specifics.set_address_home_line1( |
| 315 UTF16ToUTF8(profile.GetFieldText(AutoFillType(ADDRESS_HOME_LINE1)))); |
| 316 specifics.set_address_home_line2( |
| 317 UTF16ToUTF8(profile.GetFieldText(AutoFillType(ADDRESS_HOME_LINE2)))); |
| 318 specifics.set_address_home_city(UTF16ToUTF8(profile.GetFieldText( |
| 319 AutoFillType(ADDRESS_HOME_CITY)))); |
| 320 specifics.set_address_home_state(UTF16ToUTF8(profile.GetFieldText( |
| 321 AutoFillType(ADDRESS_HOME_STATE)))); |
| 322 specifics.set_address_home_country(UTF16ToUTF8(profile.GetFieldText( |
| 323 AutoFillType(ADDRESS_HOME_COUNTRY)))); |
| 324 specifics.set_address_home_zip(UTF16ToUTF8(profile.GetFieldText( |
| 325 AutoFillType(ADDRESS_HOME_ZIP)))); |
| 326 specifics.set_email_address(UTF16ToUTF8(profile.GetFieldText( |
| 327 AutoFillType(EMAIL_ADDRESS)))); |
| 328 specifics.set_company_name(UTF16ToUTF8(profile.GetFieldText( |
| 329 AutoFillType(COMPANY_NAME)))); |
| 330 specifics.set_phone_fax_whole_number(UTF16ToUTF8(profile.GetFieldText( |
| 331 AutoFillType(PHONE_FAX_WHOLE_NUMBER)))); |
| 332 specifics.set_phone_home_whole_number(UTF16ToUTF8(profile.GetFieldText( |
| 333 AutoFillType(PHONE_HOME_WHOLE_NUMBER)))); |
| 334 node->SetAutofillProfileSpecifics(specifics); |
| 335 } |
| 336 |
| 337 } // namespace browser_sync |
| 338 |
OLD | NEW |