// Copyright (c) 2012 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. #ifndef CHROME_BROWSER_WEBDATA_AUTOFILL_PROFILE_SYNCABLE_SERVICE_H_ #define CHROME_BROWSER_WEBDATA_AUTOFILL_PROFILE_SYNCABLE_SERVICE_H_ #include #include #include #include "base/basictypes.h" #include "base/memory/scoped_vector.h" #include "base/synchronization/lock.h" #include "base/threading/non_thread_safe.h" #include "chrome/browser/autofill/autofill_type.h" #include "chrome/browser/webdata/autofill_change.h" #include "chrome/browser/webdata/autofill_entry.h" #include "content/public/browser/notification_observer.h" #include "content/public/browser/notification_registrar.h" #include "content/public/browser/notification_types.h" #include "sync/api/sync_change.h" #include "sync/api/sync_data.h" #include "sync/api/sync_error.h" #include "sync/api/syncable_service.h" #include "sync/protocol/autofill_specifics.pb.h" class AutofillProfile; class AutofillTable; class FormGroup; class ProfileSyncServiceAutofillTest; class WebDataService; extern const char kAutofillProfileTag[]; // The sync implementation for AutofillProfiles. // MergeDataAndStartSyncing() called first, it does cloud->local and // local->cloud syncs. Then for each cloud change we receive // ProcessSyncChanges() and for each local change Observe() is called. class AutofillProfileSyncableService : public syncer::SyncableService, public content::NotificationObserver, public base::NonThreadSafe { public: explicit AutofillProfileSyncableService(WebDataService* web_data_service); virtual ~AutofillProfileSyncableService(); static syncer::ModelType model_type() { return syncer::AUTOFILL_PROFILE; } // syncer::SyncableService implementation. virtual syncer::SyncMergeResult MergeDataAndStartSyncing( syncer::ModelType type, const syncer::SyncDataList& initial_sync_data, scoped_ptr sync_processor, scoped_ptr sync_error_factory) OVERRIDE; virtual void StopSyncing(syncer::ModelType type) OVERRIDE; virtual syncer::SyncDataList GetAllSyncData( syncer::ModelType type) const OVERRIDE; virtual syncer::SyncError ProcessSyncChanges( const tracked_objects::Location& from_here, const syncer::SyncChangeList& change_list) OVERRIDE; // content::NotificationObserver implementation. virtual void Observe(int type, const content::NotificationSource& source, const content::NotificationDetails& details) OVERRIDE; protected: // A convenience wrapper of a bunch of state we pass around while // associating models, and send to the WebDatabase for persistence. // We do this so we hold the write lock for only a small period. // When storing the web db we are out of the write lock. struct DataBundle; // Helper to query WebDatabase for the current autofill state. // Made virtual for ease of mocking in the unit-test. // Caller owns returned |profiles|. virtual bool LoadAutofillData(std::vector* profiles); // Helper to persist any changes that occured during model association to // the WebDatabase. // Made virtual for ease of mocking in the unit-test. virtual bool SaveChangesToWebData(const DataBundle& bundle); private: friend class ProfileSyncServiceAutofillTest; friend class MockAutofillProfileSyncableService; FRIEND_TEST_ALL_PREFIXES(AutofillProfileSyncableServiceTest, MergeDataAndStartSyncing); FRIEND_TEST_ALL_PREFIXES(AutofillProfileSyncableServiceTest, GetAllSyncData); FRIEND_TEST_ALL_PREFIXES(AutofillProfileSyncableServiceTest, ProcessSyncChanges); FRIEND_TEST_ALL_PREFIXES(AutofillProfileSyncableServiceTest, ActOnChange); FRIEND_TEST_ALL_PREFIXES(AutofillProfileSyncableServiceTest, UpdateField); FRIEND_TEST_ALL_PREFIXES(AutofillProfileSyncableServiceTest, UpdateMultivaluedField); FRIEND_TEST_ALL_PREFIXES(AutofillProfileSyncableServiceTest, MergeProfile); // The map of the guid to profiles owned by the |profiles_| vector. typedef std::map GUIDToProfileMap; // Helper function that overwrites |profile| with data from proto-buffer // |specifics|. static bool OverwriteProfileWithServerData( const sync_pb::AutofillProfileSpecifics& specifics, AutofillProfile* profile); // Writes |profile| data into supplied |profile_specifics|. static void WriteAutofillProfile(const AutofillProfile& profile, sync_pb::EntitySpecifics* profile_specifics); // Creates |profile_map| from the supplied |profiles| vector. Necessary for // fast processing of the changes. void CreateGUIDToProfileMap(const std::vector& profiles, GUIDToProfileMap* profile_map); // Creates or updates a profile based on |data|. Looks at the guid of the data // and if a profile with such guid is present in |profile_map| updates it. If // not, searches through it for similar profiles. If similar profile is // found substitutes it for the new one, otherwise adds a new profile. Returns // iterator pointing to added/updated profile. GUIDToProfileMap::iterator CreateOrUpdateProfile( const syncer::SyncData& data, GUIDToProfileMap* profile_map, DataBundle* bundle); // Syncs |change| to the cloud. void ActOnChange(const AutofillProfileChange& change); // Creates syncer::SyncData based on supplied |profile|. static syncer::SyncData CreateData(const AutofillProfile& profile); AutofillTable* GetAutofillTable() const; // Helper to compare the local value and cloud value of a field, copy into // the local value if they differ, and return whether the change happened. static bool UpdateField(AutofillFieldType field_type, const std::string& new_value, AutofillProfile* autofill_profile); // The same as |UpdateField|, but for multi-valued fields. static bool UpdateMultivaluedField( AutofillFieldType field_type, const ::google::protobuf::RepeatedPtrField& new_value, AutofillProfile* autofill_profile); // Calls merge_into->OverwriteWithOrAddTo() and then checks if the // |merge_into| has extra data. Returns |true| if |merge_into| posseses some // multi-valued field values that are not in |merge_from|, false otherwise. static bool MergeProfile(const AutofillProfile& merge_from, AutofillProfile* merge_into); // For unit-tests. AutofillProfileSyncableService(); void set_sync_processor(syncer::SyncChangeProcessor* sync_processor) { sync_processor_.reset(sync_processor); } WebDataService* web_data_service_; // WEAK content::NotificationRegistrar notification_registrar_; // Cached Autofill profiles. *Warning* deleted profiles are still in the // vector - use the |profiles_map_| to iterate through actual profiles. ScopedVector profiles_; GUIDToProfileMap profiles_map_; scoped_ptr sync_processor_; scoped_ptr sync_error_factory_; DISALLOW_COPY_AND_ASSIGN(AutofillProfileSyncableService); }; // This object is used in unit-tests as well, so it defined here. struct AutofillProfileSyncableService::DataBundle { DataBundle(); ~DataBundle(); std::vector profiles_to_delete; std::vector profiles_to_update; std::vector profiles_to_add; // When we go through sync we find profiles that are similar but unmatched. // Merge such profiles. GUIDToProfileMap candidates_to_merge; // Profiles that have multi-valued fields that are not in sync. std::vector profiles_to_sync_back; }; #endif // CHROME_BROWSER_WEBDATA_AUTOFILL_PROFILE_SYNCABLE_SERVICE_H_