// 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.
#ifndef CHROME_BROWSER_SYNC_GLUE_AUTOFILL_MODEL_ASSOCIATOR_H_
#define CHROME_BROWSER_SYNC_GLUE_AUTOFILL_MODEL_ASSOCIATOR_H_
#pragma once
#include <map>
#include <set>
#include <string>
#include <vector>
#include "base/basictypes.h"
#include "base/memory/ref_counted.h"
#include "base/synchronization/lock.h"
#include "chrome/browser/autofill/personal_data_manager.h"
#include "chrome/browser/sync/engine/syncapi.h"
#include "chrome/browser/sync/glue/model_associator.h"
#include "chrome/browser/sync/protocol/autofill_specifics.pb.h"
#include "chrome/browser/webdata/autofill_entry.h"
class AutofillProfile;
class ProfileSyncService;
class WebDatabase;
namespace sync_api {
class WriteTransaction;
}
namespace browser_sync {
class AutofillChangeProcessor;
class UnrecoverableErrorHandler;
extern const char kAutofillTag[];
extern const char kAutofillProfileNamespaceTag[];
extern const char kAutofillEntryNamespaceTag[];
// Contains all model association related logic:
// * Algorithm to associate autofill model and sync model.
// We do not check if we have local data before this run; we always
// merge and sync.
class AutofillModelAssociator
: public PerDataTypeAssociatorInterface<std::string, std::string> {
public:
static syncable::ModelType model_type() { return syncable::AUTOFILL; }
AutofillModelAssociator(ProfileSyncService* sync_service,
WebDatabase* web_database,
PersonalDataManager* data_manager);
virtual ~AutofillModelAssociator();
// PerDataTypeAssociatorInterface implementation.
//
// Iterates through the sync model looking for matched pairs of items.
virtual bool AssociateModels();
// Clears all associations.
virtual bool DisassociateModels();
// The has_nodes out param is true if the sync model has nodes other
// than the permanent tagged nodes.
virtual bool SyncModelHasUserCreatedNodes(bool* has_nodes);
// See ModelAssociator interface.
virtual void AbortAssociation();
// See ModelAssociator interface.
virtual bool CryptoReadyIfNecessary();
// Not implemented.
virtual const std::string* GetChromeNodeFromSyncId(int64 sync_id);
// Not implemented.
virtual bool InitSyncNodeFromChromeId(const std::string& node_id,
sync_api::BaseNode* sync_node);
// Returns the sync id for the given autofill name, or sync_api::kInvalidId
// if the autofill name is not associated to any sync id.
virtual int64 GetSyncIdFromChromeId(const std::string& node_id);
// Associates the given autofill name with the given sync id.
virtual void Associate(const std::string* node, int64 sync_id);
// Remove the association that corresponds to the given sync id.
virtual void Disassociate(int64 sync_id);
// Returns whether a node with the given permanent tag was found and update
// |sync_id| with that node's id.
virtual bool GetSyncIdForTaggedNode(const std::string& tag, int64* sync_id);
static std::string KeyToTag(const string16& name, const string16& value);
static bool MergeTimestamps(const sync_pb::AutofillSpecifics& autofill,
const std::vector<base::Time>& timestamps,
std::vector<base::Time>* new_timestamps);
static bool FillProfileWithServerData(
AutofillProfile* merge_into,
const sync_pb::AutofillProfileSpecifics& specifics);
// TODO(georgey) : add the same processing for CC info (already in protocol
// buffers).
// Is called to determine if we need to upgrade to the new
// autofillprofile2 data type. If so we need to sync up autofillprofile
// first to the latest available changes on the server and then upgrade
// to autofillprofile2.
virtual bool HasNotMigratedYet(const sync_api::BaseTransaction* trans);
protected:
// Given a profile from sync db it tries to match the profile against
// one in web db. it ignores the guid and compares the actual data.
AutofillProfile* FindCorrespondingNodeFromWebDB(
const sync_pb::AutofillProfileSpecifics& profile,
const std::vector<AutofillProfile*>& all_profiles_from_db);
private:
typedef std::map<std::string, int64> AutofillToSyncIdMap;
typedef std::map<int64, std::string> SyncIdToAutofillMap;
// A convenience wrapper of a bunch of state we pass around while associating
// models, and send to the WebDatabase for persistence.
struct DataBundle;
// Helper to query WebDatabase for the current autofill state.
bool LoadAutofillData(std::vector<AutofillEntry>* entries,
std::vector<AutofillProfile*>* profiles);
// We split up model association first by autofill sub-type (entries, and
// profiles. There is a Traverse* method for each of these.
bool TraverseAndAssociateChromeAutofillEntries(
sync_api::WriteTransaction* write_trans,
const sync_api::ReadNode& autofill_root,
const std::vector<AutofillEntry>& all_entries_from_db,
std::set<AutofillKey>* current_entries,
std::vector<AutofillEntry>* new_entries);
bool TraverseAndAssociateChromeAutofillProfiles(
sync_api::WriteTransaction* write_trans,
const sync_api::ReadNode& autofill_root,
const std::vector<AutofillProfile*>& all_profiles_from_db,
std::set<string16>* current_profiles,
std::vector<AutofillProfile*>* updated_profiles);
// Once the above traversals are complete, we traverse the sync model to
// associate all remaining nodes.
bool TraverseAndAssociateAllSyncNodes(
sync_api::WriteTransaction* write_trans,
const sync_api::ReadNode& autofill_root,
DataBundle* bundle,
const std::vector<AutofillProfile*>& all_profiles_from_db);
// Helper to persist any changes that occured during model association to
// the WebDatabase.
bool SaveChangesToWebData(const DataBundle& bundle);
// Helper to insert an AutofillEntry into the WebDatabase (e.g. in response
// to encountering a sync node that doesn't exist yet locally).
void AddNativeEntryIfNeeded(const sync_pb::AutofillSpecifics& autofill,
DataBundle* bundle,
const sync_api::ReadNode& node);
// Helper to insert an AutofillProfile into the WebDatabase (e.g. in response
// to encountering a sync node that doesn't exist yet locally).
void AddNativeProfileIfNeeded(
const sync_pb::AutofillProfileSpecifics& profile,
DataBundle* bundle,
const sync_api::ReadNode& node,
const std::vector<AutofillProfile*>& all_profiles_from_db);
// Called at various points in model association to determine if the
// user requested an abort.
bool IsAbortPending();
ProfileSyncService* sync_service_;
WebDatabase* web_database_;
PersonalDataManager* personal_data_;
int64 autofill_node_id_;
AutofillToSyncIdMap id_map_;
SyncIdToAutofillMap id_map_inverse_;
// Abort association pending flag and lock. If this is set to true
// (via the AbortAssociation method), return from the
// AssociateModels method as soon as possible.
base::Lock abort_association_pending_lock_;
bool abort_association_pending_;
int number_of_entries_created_;
DISALLOW_COPY_AND_ASSIGN(AutofillModelAssociator);
};
} // namespace browser_sync
#endif // CHROME_BROWSER_SYNC_GLUE_AUTOFILL_MODEL_ASSOCIATOR_H_