Index: chrome/browser/sync/glue/autofill_profile_model_associator.cc |
=================================================================== |
--- chrome/browser/sync/glue/autofill_profile_model_associator.cc (revision 99989) |
+++ chrome/browser/sync/glue/autofill_profile_model_associator.cc (working copy) |
@@ -1,518 +0,0 @@ |
-// Copyright (c) 2011 The Chromium Authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-#include "chrome/browser/sync/glue/autofill_profile_model_associator.h" |
- |
-#include "base/tracked.h" |
-#include "base/utf_string_conversions.h" |
-#include "chrome/browser/sync/api/sync_error.h" |
-#include "chrome/browser/sync/glue/autofill_profile_change_processor.h" |
-#include "chrome/browser/sync/glue/do_optimistic_refresh_task.h" |
-#include "chrome/browser/sync/internal_api/read_node.h" |
-#include "chrome/browser/sync/internal_api/read_transaction.h" |
-#include "chrome/browser/sync/internal_api/write_node.h" |
-#include "chrome/browser/sync/internal_api/write_transaction.h" |
-#include "chrome/browser/sync/profile_sync_service.h" |
-#include "chrome/browser/webdata/autofill_table.h" |
-#include "chrome/browser/webdata/web_database.h" |
-#include "chrome/common/guid.h" |
- |
-using sync_api::ReadNode; |
-namespace browser_sync { |
- |
-const char kAutofillProfileTag[] = "google_chrome_autofill_profiles"; |
- |
-AutofillProfileModelAssociator::AutofillProfileModelAssociator( |
- ProfileSyncService* sync_service, |
- WebDatabase* web_database, |
- PersonalDataManager* personal_data) |
- : sync_service_(sync_service), |
- web_database_(web_database), |
- personal_data_(personal_data), |
- autofill_node_id_(sync_api::kInvalidId), |
- abort_association_pending_(false), |
- number_of_profiles_created_(0) { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); |
- DCHECK(sync_service_); |
- DCHECK(web_database_); |
- DCHECK(personal_data_); |
-} |
- |
-AutofillProfileModelAssociator::~AutofillProfileModelAssociator() { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); |
-} |
- |
-AutofillProfileModelAssociator::AutofillProfileModelAssociator() |
- : sync_service_(NULL), |
- web_database_(NULL), |
- personal_data_(NULL), |
- autofill_node_id_(0), |
- abort_association_pending_(false), |
- number_of_profiles_created_(0) { |
-} |
- |
-bool AutofillProfileModelAssociator::TraverseAndAssociateChromeAutofillProfiles( |
- sync_api::WriteTransaction* write_trans, |
- const sync_api::ReadNode& autofill_root, |
- const std::vector<AutofillProfile*>& all_profiles_from_db, |
- std::set<std::string>* current_profiles, |
- std::vector<AutofillProfile*>* updated_profiles, |
- std::vector<AutofillProfile*>* new_profiles, |
- std::vector<std::string>* profiles_to_delete) { |
- |
- if (VLOG_IS_ON(2)) { |
- VLOG(2) << "[AUTOFILL MIGRATION]" |
- << "Printing profiles from web db"; |
- |
- for (std::vector<AutofillProfile*>::const_iterator ix = |
- all_profiles_from_db.begin(); ix != all_profiles_from_db.end(); ++ix) { |
- AutofillProfile* p = *ix; |
- VLOG(2) << "[AUTOFILL MIGRATION] " |
- << p->GetInfo(NAME_FIRST) |
- << p->GetInfo(NAME_LAST) |
- << p->guid(); |
- } |
- } |
- |
- VLOG(1) << "[AUTOFILL MIGRATION]" |
- << "Looking for the above data in sync db.."; |
- |
- // Alias the all_profiles_from_db so we fit in 80 characters |
- const std::vector<AutofillProfile*>& profiles(all_profiles_from_db); |
- for (std::vector<AutofillProfile*>::const_iterator ix = profiles.begin(); |
- ix != profiles.end(); |
- ++ix) { |
- std::string guid((*ix)->guid()); |
- if (guid::IsValidGUID(guid) == false) { |
- DCHECK(false) << "Guid in the web db is invalid " << guid; |
- continue; |
- } |
- |
- ReadNode node(write_trans); |
- if (node.InitByClientTagLookup(syncable::AUTOFILL_PROFILE, guid) && |
- // The following check is to ensure the given sync node is not already |
- // associated with another profile. That could happen if the user has |
- // the same profile duplicated. |
- current_profiles->find(guid) == current_profiles->end()) { |
- VLOG(2) << "[AUTOFILL MIGRATION]" |
- << " Found in sync db: " |
- << (*ix)->GetInfo(NAME_FIRST) |
- << (*ix)->GetInfo(NAME_LAST) |
- << (*ix)->guid() |
- << " so associating with node id " << node.GetId(); |
- const sync_pb::AutofillProfileSpecifics& autofill( |
- node.GetAutofillProfileSpecifics()); |
- if (OverwriteProfileWithServerData(*ix, autofill)) { |
- updated_profiles->push_back(*ix); |
- } |
- Associate(&guid, node.GetId()); |
- current_profiles->insert(guid); |
- } else { |
- MakeNewAutofillProfileSyncNodeIfNeeded(write_trans, |
- autofill_root, |
- (**ix), |
- new_profiles, |
- current_profiles, |
- profiles_to_delete); |
- } |
- } |
- return true; |
-} |
- |
-bool AutofillProfileModelAssociator::GetSyncIdForTaggedNode( |
- const std::string& tag, |
- int64* sync_id) { |
- sync_api::ReadTransaction trans(FROM_HERE, sync_service_->GetUserShare()); |
- sync_api::ReadNode sync_node(&trans); |
- if (!sync_node.InitByTagLookup(tag.c_str())) |
- return false; |
- *sync_id = sync_node.GetId(); |
- return true; |
-} |
- |
-bool AutofillProfileModelAssociator::LoadAutofillData( |
- std::vector<AutofillProfile*>* profiles) { |
- if (IsAbortPending()) |
- return false; |
- |
- if (!web_database_->GetAutofillTable()->GetAutofillProfiles(profiles)) |
- return false; |
- |
- return true; |
-} |
- |
-bool AutofillProfileModelAssociator::AssociateModels(SyncError* error) { |
- VLOG(1) << "Associating Autofill Models"; |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); |
- { |
- base::AutoLock lock(abort_association_pending_lock_); |
- abort_association_pending_ = false; |
- } |
- |
- ScopedVector<AutofillProfile> profiles; |
- |
- if (!LoadAutofillData(&profiles.get())) { |
- error->Reset(FROM_HERE, |
- "Could not get the autofill data from WebDatabase.", |
- model_type()); |
- return false; |
- } |
- |
- VLOG(1) << "[AUTOFILL MIGRATION]" |
- << " Now associating to the new autofill profile model associator" |
- << " root node"; |
- DataBundle bundle; |
- { |
- // The write transaction lock is held inside this block. |
- // We do all the web db operations outside this block. |
- sync_api::WriteTransaction trans(FROM_HERE, sync_service_->GetUserShare()); |
- |
- sync_api::ReadNode autofill_root(&trans); |
- if (!autofill_root.InitByTagLookup(kAutofillProfileTag)) { |
- error->Reset(FROM_HERE, |
- "Server did not create the top-level autofill node. We " |
- "might be running against an out-of-date server.", |
- model_type()); |
- return false; |
- } |
- |
- if (!TraverseAndAssociateChromeAutofillProfiles(&trans, autofill_root, |
- profiles.get(), &bundle.current_profiles, |
- &bundle.updated_profiles, |
- &bundle.new_profiles, |
- &bundle.profiles_to_delete) || |
- !TraverseAndAssociateAllSyncNodes(&trans, autofill_root, &bundle)) { |
- error->Reset(FROM_HERE, |
- "Failed to associate all sync nodes.", |
- model_type()); |
- return false; |
- } |
- } |
- |
- if (!SaveChangesToWebData(bundle)) { |
- error->Reset(FROM_HERE, "Failed to update webdata.", model_type()); |
- return false; |
- } |
- |
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
- new DoOptimisticRefreshForAutofill(personal_data_)); |
- return true; |
-} |
- |
-bool AutofillProfileModelAssociator::DisassociateModels(SyncError* error) { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); |
- id_map_.clear(); |
- id_map_inverse_.clear(); |
- return true; |
-} |
- |
-// Helper to compare the local value and cloud value of a field, merge into |
-// the local value if they differ, and return whether the merge happened. |
-bool AutofillProfileModelAssociator::MergeField(FormGroup* f, |
- AutofillFieldType t, |
- const std::string& specifics_field) { |
- if (UTF16ToUTF8(f->GetInfo(t)) == specifics_field) |
- return false; |
- f->SetInfo(t, UTF8ToUTF16(specifics_field)); |
- return true; |
-} |
-bool AutofillProfileModelAssociator::SyncModelHasUserCreatedNodes( |
- bool *has_nodes) { |
- CHECK_NE(has_nodes, reinterpret_cast<bool*>(NULL)); |
- sync_api::ReadTransaction trans(FROM_HERE, sync_service_->GetUserShare()); |
- |
- sync_api::ReadNode node(&trans); |
- |
- if (!node.InitByTagLookup(kAutofillProfileTag)) { |
- LOG(ERROR) << "Sever did not create a top level node" |
- << "Out of data server or autofill type not enabled"; |
- return false; |
- } |
- |
- *has_nodes = sync_api::kInvalidId != node.GetFirstChildId(); |
- return true; |
-} |
-// static |
-bool AutofillProfileModelAssociator::OverwriteProfileWithServerData( |
- AutofillProfile* merge_into, |
- const sync_pb::AutofillProfileSpecifics& specifics) { |
- bool diff = false; |
- AutofillProfile* p = merge_into; |
- const sync_pb::AutofillProfileSpecifics& s(specifics); |
- diff = MergeField(p, NAME_FIRST, s.name_first()) || diff; |
- diff = MergeField(p, NAME_LAST, s.name_last()) || diff; |
- diff = MergeField(p, NAME_MIDDLE, s.name_middle()) || diff; |
- diff = MergeField(p, ADDRESS_HOME_LINE1, s.address_home_line1()) || diff; |
- diff = MergeField(p, ADDRESS_HOME_LINE2, s.address_home_line2()) || diff; |
- diff = MergeField(p, ADDRESS_HOME_CITY, s.address_home_city()) || diff; |
- diff = MergeField(p, ADDRESS_HOME_STATE, s.address_home_state()) || diff; |
- diff = MergeField(p, ADDRESS_HOME_COUNTRY, s.address_home_country()) || diff; |
- diff = MergeField(p, ADDRESS_HOME_ZIP, s.address_home_zip()) || diff; |
- diff = MergeField(p, EMAIL_ADDRESS, s.email_address()) || diff; |
- diff = MergeField(p, COMPANY_NAME, s.company_name()) || diff; |
- diff = MergeField(p, PHONE_FAX_WHOLE_NUMBER, s.phone_fax_whole_number()) |
- || diff; |
- diff = MergeField(p, PHONE_HOME_WHOLE_NUMBER, s.phone_home_whole_number()) |
- || diff; |
- return diff; |
-} |
- |
- |
-int64 AutofillProfileModelAssociator::FindSyncNodeWithProfile( |
- sync_api::WriteTransaction* trans, |
- const sync_api::BaseNode& autofill_root, |
- const AutofillProfile& profile_from_db, |
- std::set<std::string>* current_profiles) { |
- int64 sync_child_id = autofill_root.GetFirstChildId(); |
- while (sync_child_id != sync_api::kInvalidId) { |
- ReadNode read_node(trans); |
- AutofillProfile p; |
- if (!read_node.InitByIdLookup(sync_child_id)) { |
- LOG(ERROR) << "unable to find the id given by getfirst child " << |
- sync_child_id; |
- return sync_api::kInvalidId; |
- } |
- const sync_pb::AutofillProfileSpecifics& autofill_specifics( |
- read_node.GetAutofillProfileSpecifics()); |
- |
- // This find should be fast as the set uses tree. |
- if (current_profiles->find(autofill_specifics.guid()) |
- == current_profiles->end()) { |
- OverwriteProfileWithServerData(&p, autofill_specifics); |
- if (p.Compare(profile_from_db) == 0) { |
- return sync_child_id; |
- } |
- } |
- sync_child_id = read_node.GetSuccessorId(); |
- } |
- |
- return sync_api::kInvalidId; |
-} |
-bool AutofillProfileModelAssociator::MakeNewAutofillProfileSyncNodeIfNeeded( |
- sync_api::WriteTransaction* trans, |
- const sync_api::BaseNode& autofill_root, |
- const AutofillProfile& profile, |
- std::vector<AutofillProfile*>* new_profiles, |
- std::set<std::string>* current_profiles, |
- std::vector<std::string>* profiles_to_delete) { |
- |
- int64 sync_node_id = FindSyncNodeWithProfile(trans, |
- autofill_root, |
- profile, |
- current_profiles); |
- if (sync_node_id != sync_api::kInvalidId) { |
- // In case of duplicates throw away the local profile and apply the |
- // server profile.(The only difference between the 2 profiles are the guids) |
- profiles_to_delete->push_back(profile.guid()); |
- sync_api::ReadNode read_node(trans); |
- if (!read_node.InitByIdLookup(sync_node_id)) { |
- LOG(ERROR); |
- return false; |
- } |
- const sync_pb::AutofillProfileSpecifics& autofill_specifics( |
- read_node.GetAutofillProfileSpecifics()); |
- if (guid::IsValidGUID(autofill_specifics.guid()) == false) { |
- NOTREACHED() << "Guid in the web db is invalid " << |
- autofill_specifics.guid(); |
- return false; |
- } |
- AutofillProfile* p = new AutofillProfile(autofill_specifics.guid()); |
- OverwriteProfileWithServerData(p, autofill_specifics); |
- new_profiles->push_back(p); |
- std::string guid = autofill_specifics.guid(); |
- Associate(&guid, sync_node_id); |
- current_profiles->insert(autofill_specifics.guid()); |
- VLOG(2) << "[AUTOFILL MIGRATION]" |
- << "Found in sync db but with a different guid: " |
- << UTF16ToUTF8(profile.GetInfo(NAME_FIRST)) |
- << UTF16ToUTF8(profile.GetInfo(NAME_LAST)) |
- << "New guid " << autofill_specifics.guid() << " sync node id " |
- << sync_node_id << " so associating. Profile to be deleted " |
- << profile.guid(); |
- } else { |
- sync_api::WriteNode node(trans); |
- |
- // The profile.guid() is expected to be a valid guid. The caller is expected |
- // to pass in a valid profile object with a valid guid. Having to check in |
- // 2 places(the caller and here) is not optimal. |
- if (!node.InitUniqueByCreation( |
- syncable::AUTOFILL_PROFILE, autofill_root, profile.guid())) { |
- LOG(ERROR) << "Failed to create autofill sync node."; |
- return false; |
- } |
- node.SetTitle(UTF8ToWide(profile.guid())); |
- VLOG(2) << "[AUTOFILL MIGRATION]" |
- << "NOT Found in sync db " |
- << UTF16ToUTF8(profile.GetInfo(NAME_FIRST)) |
- << UTF16ToUTF8(profile.GetInfo(NAME_LAST)) |
- << profile.guid() |
- << " so creating a new sync node. Sync node id " |
- << node.GetId(); |
- AutofillProfileChangeProcessor::WriteAutofillProfile(profile, &node); |
- current_profiles->insert(profile.guid()); |
- std::string guid = profile.guid(); |
- Associate(&guid, node.GetId()); |
- number_of_profiles_created_++; |
- } |
- return true; |
-} |
- |
-bool AutofillProfileModelAssociator::TraverseAndAssociateAllSyncNodes( |
- sync_api::WriteTransaction* write_trans, |
- const sync_api::ReadNode& autofill_root, |
- DataBundle* bundle) { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); |
- VLOG(1) << "[AUTOFILL MIGRATION] " |
- << " Iterating over sync nodes of autofill profile root node"; |
- |
- int64 sync_child_id = autofill_root.GetFirstChildId(); |
- while (sync_child_id != sync_api::kInvalidId) { |
- ReadNode sync_child(write_trans); |
- if (!sync_child.InitByIdLookup(sync_child_id)) { |
- LOG(ERROR) << "Failed to fetch child node."; |
- return false; |
- } |
- const sync_pb::AutofillProfileSpecifics& autofill( |
- sync_child.GetAutofillProfileSpecifics()); |
- |
- AddNativeProfileIfNeeded(autofill, bundle, sync_child); |
- |
- sync_child_id = sync_child.GetSuccessorId(); |
- } |
- return true; |
-} |
- |
-void AutofillProfileModelAssociator::AddNativeProfileIfNeeded( |
- const sync_pb::AutofillProfileSpecifics& profile, |
- DataBundle* bundle, |
- const sync_api::ReadNode& node) { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); |
- |
- VLOG(2) << "[AUTOFILL MIGRATION] " |
- << "Trying to lookup " |
- << profile.name_first() |
- << " " |
- << profile.name_last() |
- << "sync node id " << node.GetId() |
- << " Guid " << profile.guid() |
- << " in the web db"; |
- |
- if (guid::IsValidGUID(profile.guid()) == false) { |
- DCHECK(false) << "Guid in the sync db is invalid " << profile.guid(); |
- return; |
- } |
- |
- if (bundle->current_profiles.find(profile.guid()) == |
- bundle->current_profiles.end()) { |
- std::string guid(profile.guid()); |
- Associate(&guid, node.GetId()); |
- AutofillProfile* p = new AutofillProfile(profile.guid()); |
- OverwriteProfileWithServerData(p, profile); |
- bundle->new_profiles.push_back(p); |
- VLOG(2) << "[AUTOFILL MIGRATION] " |
- << " Did not find one so creating it on web db"; |
- } else { |
- VLOG(2) << "[AUTOFILL MIGRATION] " |
- << " Found it on web db. Moving on "; |
- } |
-} |
- |
-bool AutofillProfileModelAssociator::SaveChangesToWebData( |
- const DataBundle& bundle) { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); |
- |
- if (IsAbortPending()) |
- return false; |
- |
- for (size_t i = 0; i < bundle.new_profiles.size(); i++) { |
- if (IsAbortPending()) |
- return false; |
- if (!web_database_->GetAutofillTable()->AddAutofillProfile( |
- *bundle.new_profiles[i])) |
- return false; |
- } |
- |
- for (size_t i = 0; i < bundle.updated_profiles.size(); i++) { |
- if (IsAbortPending()) |
- return false; |
- if (!web_database_->GetAutofillTable()->UpdateAutofillProfile( |
- *bundle.updated_profiles[i])) |
- return false; |
- } |
- |
- for (size_t i = 0; i< bundle.profiles_to_delete.size(); ++i) { |
- if (IsAbortPending()) |
- return false; |
- if (!web_database_->GetAutofillTable()->RemoveAutofillProfile( |
- bundle.profiles_to_delete[i])) |
- return false; |
- } |
- return true; |
-} |
- |
-bool AutofillProfileModelAssociator::InitSyncNodeFromChromeId( |
- const std::string& node_id, |
- sync_api::BaseNode* sync_node) { |
- return false; |
-} |
- |
-void AutofillProfileModelAssociator::Associate( |
- const std::string* autofill, |
- int64 sync_id) { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); |
- DCHECK_NE(sync_api::kInvalidId, sync_id); |
- DCHECK(id_map_.find(*autofill) == id_map_.end()); |
- DCHECK(id_map_inverse_.find(sync_id) == id_map_inverse_.end()); |
- id_map_[*autofill] = sync_id; |
- id_map_inverse_[sync_id] = *autofill; |
-} |
- |
-void AutofillProfileModelAssociator::Disassociate(int64 sync_id) { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); |
- SyncIdToAutofillMap::iterator iter = id_map_inverse_.find(sync_id); |
- if (iter == id_map_inverse_.end()) |
- return; |
- CHECK(id_map_.erase(iter->second)); |
- id_map_inverse_.erase(iter); |
-} |
- |
-int64 AutofillProfileModelAssociator::GetSyncIdFromChromeId( |
- const std::string& autofill) { |
- AutofillToSyncIdMap::const_iterator iter = id_map_.find(autofill); |
- return iter == id_map_.end() ? sync_api::kInvalidId : iter->second; |
-} |
- |
-void AutofillProfileModelAssociator::AbortAssociation() { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
- base::AutoLock lock(abort_association_pending_lock_); |
- abort_association_pending_ = true; |
-} |
- |
-const std::string* AutofillProfileModelAssociator::GetChromeNodeFromSyncId( |
- int64 sync_id) { |
- SyncIdToAutofillMap::const_iterator iter = id_map_inverse_.find(sync_id); |
- return iter == id_map_inverse_.end() ? NULL : &(iter->second); |
-} |
- |
-bool AutofillProfileModelAssociator::IsAbortPending() { |
- base::AutoLock lock(abort_association_pending_lock_); |
- return abort_association_pending_; |
-} |
- |
-AutofillProfileModelAssociator::DataBundle::DataBundle() {} |
- |
-AutofillProfileModelAssociator::DataBundle::~DataBundle() { |
- STLDeleteElements(&new_profiles); |
-} |
- |
-bool AutofillProfileModelAssociator::CryptoReadyIfNecessary() { |
- // We only access the cryptographer while holding a transaction. |
- sync_api::ReadTransaction trans(FROM_HERE, sync_service_->GetUserShare()); |
- syncable::ModelTypeSet encrypted_types; |
- encrypted_types = sync_api::GetEncryptedTypes(&trans); |
- return encrypted_types.count(syncable::AUTOFILL_PROFILE) == 0 || |
- sync_service_->IsCryptographerReady(&trans); |
-} |
- |
-} // namespace browser_sync |