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

Unified Diff: chrome/browser/sync/glue/autofill_profile_model_associator.cc

Issue 4683003: Sending the proto files for review to unblcok the server team Base URL: http://git.chromium.org/git/chromium.git@trunk
Patch Set: Created 10 years, 1 month 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 side-by-side diff with in-line comments
Download patch
Index: chrome/browser/sync/glue/autofill_profile_model_associator.cc
diff --git a/chrome/browser/sync/glue/autofill_profile_model_associator.cc b/chrome/browser/sync/glue/autofill_profile_model_associator.cc
new file mode 100755
index 0000000000000000000000000000000000000000..e50d25ad421f459525d08e2676e37b308277bf98
--- /dev/null
+++ b/chrome/browser/sync/glue/autofill_profile_model_associator.cc
@@ -0,0 +1,328 @@
+// Copyright (c) 2010 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/utf_string_conversions.h"
+#include "chrome/browser/sync/profile_sync_service.h"
+#include "chrome/browser/webdata/web_database.h"
+
+namespace browser_sync {
+
+const char kAutofillProfileTag[] = "google_chrome_autofill_profile";
+
+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),
+ dontCheckThreadOnExit_(false) {
+ DCHECK(EnsureOnThread(BrowserThread::DB));
+ DCHECK(sync_service_);
+ DCHECK(web_database_);
+ DCHECK(personal_data_);
+}
+
+AutofillProfileModelAssociator::~AutofillProfileModelAssociator() {
+ DCHECK(EnsureOnThread(BrowserThread::DB));
+}
+sync_api::ReadNode* AutofillProfileModelAssociator::GetReadNode(
+ sync_api::WriteTransaction* trans) {
+ return new sync_api::ReadNode(trans);
+}
+
+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) {
+ scoped_ptr<sync_api::ReadNode> node(GetReadNode(write_trans));
+
+ // 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());
+
+ node->Reset();
+ if (node->InitByClientTagLookup(syncable::AUTOFILL_PROFILE, guid)) {
+ const sync_pb::AutofillProfile2Specifics& autofill(
+ node->GetAutofillProfileSpecifics());
+ if (OverwriteProfileWithServerData(*ix, autofill)){
+ updated_profiles->push_back(*ix);
+ }
+ Associate(&guid, node->GetId());
+ } else {
+ int64 id;
+ if (!MakeNewAutofillProfileSyncNode(write_trans,
+ autofill_root,
+ (**ix),
+ &id))
+ {
+ LOG(ERROR) << "Failed making an autofill item on the sync database";
+ }
+ Associate(&guid, id);
+ }
+ current_profiles->insert(guid);
+ }
+
+ return true;
+}
+
+bool AutofillProfileModelAssociator::LoadAutofillData(
+ std::vector<AutoFillProfile*>* profiles) {
+ if (IsAbortPending())
+ return false;
+
+ if (!web_database_->GetAutoFillProfiles(profiles))
+ return false;
+
+ return true;
+}
+
+bool AutofillProfileModelAssociator::EnsureOnThread(BrowserThread::ID id) {
+ return dontCheckThreadOnExit_ || BrowserThread::CurrentlyOn(id);
+}
+
+bool AutofillProfileModelAssociator::AssociateModels() {
+ VLOG(1) << "Associating Autofill Models";
+ DCHECK(EnsureOnThread(BrowserThread::DB));
+ {
+ AutoLock lock(abort_association_pending_lock_);
+ abort_association_pending_ = false;
+ }
+
+ // TODO(lipalani): Attempt to load the model association from storage.
+ ScopedVector<AutoFillProfile> profiles;
+
+ if (!LoadAutofillData(&profiles.get())) {
+ LOG(ERROR) << "Could not get the autofill data from WebDatabase.";
+ return false;
+ }
+
+ 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(
+ sync_service_->backend()->GetUserShareHandle());
+
+ sync_api::ReadNode autofill_root(&trans);
+ if (!autofill_root.InitByTagLookup(kAutofillProfileTag)) {
+ LOG(ERROR) << "Server did not create the top-level autofill node. We "
+ << "might be running against an out-of-date server.";
+ return false;
+ }
+
+ if (!TraverseAndAssociateChromeAutoFillProfiles(&trans, autofill_root,
+ profiles.get(), &bundle.current_profiles,
+ &bundle.updated_profiles) ||
+ !TraverseAndAssociateAllSyncNodes(&trans, autofill_root, &bundle)) {
+ return false;
+ }
+ }
+
+ if (!SaveChangesToWebData(bundle)) {
+ LOG(ERROR) << "Failed to update autofill entries.";
+ return false;
+ }
+
+ // [TODO] - split out the OptimisticRefreshTask into its own class
+ // from autofill_model_associator
+ // Will be done as part of the autofill_model_associator work.
+ // BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+ // new DoOptimisticRefreshTask(personal_data_));
+ return true;
+}
+
+bool AutofillProfileModelAssociator::DisassociateModels() {
+ 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->GetFieldText(AutoFillType(t))) == specifics_field)
+ return false;
+ f->SetInfo(AutoFillType(t), UTF8ToUTF16(specifics_field));
+ return true;
+}
+bool AutofillProfileModelAssociator::SyncModelHasUserCreatedNodes(
+ bool *has_nodes)
+{
+ CHECK(has_nodes != NULL);
+ sync_api::ReadTransaction trans(
+ sync_service_->backend()->GetUserShareHandle());
+
+ sync_api::ReadNode node(&trans);
+
+ if (!node.InitByClientTagLookup(
+ syncable::AUTOFILL_PROFILE,
+ 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::AutofillProfile2Specifics& specifics) {
+ bool diff = false;
+ AutoFillProfile* p = merge_into;
+ const sync_pb::AutofillProfile2Specifics& 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;
+}
+
+bool AutofillProfileModelAssociator::MakeNewAutofillProfileSyncNode(
+ sync_api::WriteTransaction* trans,
+ const sync_api::BaseNode& autofill_root,
+ const AutoFillProfile& profile,
+ int64* sync_id) {
+ sync_api::WriteNode node(trans);
+ 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()));
+
+ // [TODO] This needs rewriting. This will be tackled
+ // when rewriting autofill change processor.
+ // AutofillChangeProcessor::WriteAutofillProfile(profile, &node);
+ *sync_id = node.GetId();
+ return true;
+}
+
+bool AutofillProfileModelAssociator::TraverseAndAssociateAllSyncNodes(
+ sync_api::WriteTransaction* write_trans,
+ const sync_api::ReadNode& autofill_root,
+ DataBundle* bundle) {
+ DCHECK(EnsureOnThread(BrowserThread::DB));
+
+ int64 sync_child_id = autofill_root.GetFirstChildId();
+ scoped_ptr<sync_api::ReadNode> sync_child(GetReadNode(write_trans));
+ while (sync_child_id != sync_api::kInvalidId) {
+ sync_child->Reset();
+ if (!sync_child->InitByIdLookup(sync_child_id)) {
+ LOG(ERROR) << "Failed to fetch child node.";
+ return false;
+ }
+ const sync_pb::AutofillProfile2Specifics& autofill(
+ sync_child->GetAutofillProfileSpecifics());
+
+ AddNativeProfileIfNeeded(autofill, bundle, *sync_child);
+
+ sync_child_id = sync_child->GetSuccessorId();
+ }
+ return true;
+}
+
+void AutofillProfileModelAssociator::AddNativeProfileIfNeeded(
+ const sync_pb::AutofillProfile2Specifics& profile,
+ DataBundle* bundle,
+ const sync_api::ReadNode& node) {
+ DCHECK(EnsureOnThread(BrowserThread::DB));
+
+ // [TODO] this looping through is costly. Replace this with a binary tree
+ // at least in case of auto fill entries.
+ 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);
+ }
+}
+
+bool AutofillProfileModelAssociator::SaveChangesToWebData(
+ const DataBundle& bundle) {
+ DCHECK(EnsureOnThread(BrowserThread::DB));
+
+ if (IsAbortPending())
+ return false;
+
+ for (size_t i = 0; i < bundle.new_profiles.size(); i++) {
+ if (IsAbortPending())
+ return false;
+ if (!web_database_->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_->UpdateAutoFillProfile(*bundle.updated_profiles[i]))
+ return false;
+ }
+ return true;
+}
+
+void AutofillProfileModelAssociator::Associate(
+ const std::string* autofill,
+ int64 sync_id) {
+ DCHECK(EnsureOnThread(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(EnsureOnThread(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(EnsureOnThread(BrowserThread::UI));
+ AutoLock lock(abort_association_pending_lock_);
+ abort_association_pending_ = true;
+}
+
+bool AutofillProfileModelAssociator::IsAbortPending() {
+ AutoLock lock(abort_association_pending_lock_);
+ return abort_association_pending_;
+}
+
+} // namespace browser_sync

Powered by Google App Engine
This is Rietveld 408576698