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/web_database.h" | |
20 #include "chrome/browser/webdata/autofill_change.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 web_database_(web_database), | |
36 personal_data_(personal_data_manager), | |
37 observing_(false) { | |
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::ScopedObserver::ScopedObserver( | |
48 AutofillProfileChangeProcessor* processor) { | |
49 processor_ = processor; | |
50 processor_->StopObserving(); | |
51 } | |
52 | |
53 AutofillProfileChangeProcessor::ScopedObserver::~ScopedObserver() { | |
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 ScopedObserver 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 | |
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 DCHECK_EQ(type.value, NotificationType::AUTOFILL_PROFILE_CHANGED_GUID); | |
lipalani
2010/12/08 21:37:46
put the dcheck right at the top.
| |
120 | |
121 AutofillProfileChangeGUID* change = | |
122 Details<AutofillProfileChangeGUID>(details).ptr(); | |
123 | |
124 ActOnChange(change, &trans, autofill_root); | |
125 } | |
126 | |
127 void AutofillProfileChangeProcessor::ActOnChange( | |
128 AutofillProfileChangeGUID* change, | |
129 sync_api::WriteTransaction* trans, | |
130 sync_api::ReadNode& autofill_root) { | |
131 | |
132 DCHECK(change->profile()); | |
133 switch(change->type()) { | |
134 case AutofillProfileChangeGUID::ADD: { | |
135 AddAutofillProfileSyncNode(trans, autofill_root, *(change->profile())); | |
136 break; | |
137 } | |
138 case AutofillProfileChangeGUID::UPDATE: { | |
139 int64 sync_id = model_associator_->GetSyncIdFromChromeId(change->key()); | |
140 if(sync_api::kInvalidId == sync_id) { | |
141 LOG(ERROR) << "Sync id is not found for " << change->key(); | |
142 break; | |
143 } | |
144 sync_api::WriteNode node(trans); | |
145 if(!node.InitByIdLookup(sync_id)) { | |
146 LOG(ERROR) << "Could not find sync node for id " << sync_id; | |
147 break; | |
148 } | |
149 | |
150 WriteAutofillProfile(*(change->profile()), &node); | |
151 break; | |
152 } | |
153 case AutofillProfileChangeGUID::REMOVE: { | |
154 int64 sync_id = model_associator_->GetSyncIdFromChromeId(change->key()); | |
155 if(sync_api::kInvalidId == sync_id) { | |
156 LOG(ERROR) << "Sync id is not found for " << change->key(); | |
157 break; | |
158 } | |
159 sync_api::WriteNode node(trans); | |
160 if(!node.InitByIdLookup(sync_id)) { | |
161 LOG(ERROR) << "Could not find sync node for id " << sync_id; | |
162 break; | |
163 } | |
164 node.Remove(); | |
165 model_associator_->Disassociate(sync_id); | |
166 break; | |
167 } | |
168 default: | |
169 NOTREACHED(); | |
170 } | |
171 } | |
172 | |
173 void AutofillProfileChangeProcessor::CommitChangesFromSyncModel() { | |
174 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); | |
175 | |
176 if(!running()) | |
177 return; | |
178 | |
179 ScopedObserver observer(this); | |
180 | |
181 for(unsigned int i = 0;i < autofill_changes_.size(); ++i) { | |
182 if(sync_api::SyncManager::ChangeRecord::ACTION_DELETE == | |
183 autofill_changes_[i].action_) { | |
184 if(!web_database_->RemoveAutoFillProfile( | |
185 autofill_changes_[i].profile_specifics_.guid())) { | |
186 LOG(ERROR) << "could not delete the profile " << | |
187 autofill_changes_[i].profile_specifics_.guid(); | |
188 continue; | |
189 } | |
190 continue; | |
191 } | |
192 | |
193 // Now for updates and adds. | |
194 ApplyAutofillProfileChange(autofill_changes_[i].action_, | |
195 autofill_changes_[i].profile_specifics_, | |
196 autofill_changes_[i].id_); | |
197 } | |
198 | |
199 autofill_changes_.clear(); | |
200 | |
201 PostOptimisticRefreshTask(); | |
202 } | |
203 | |
204 void AutofillProfileChangeProcessor::PostOptimisticRefreshTask() { | |
205 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | |
206 new DoOptimisticRefreshTask( | |
207 personal_data_)); | |
208 } | |
209 | |
210 void AutofillProfileChangeProcessor::ApplyAutofillProfileChange( | |
211 sync_api::SyncManager::ChangeRecord::Action action, | |
212 const sync_pb::AutofillProfileSpecifics& profile_specifics, | |
213 int64 sync_id) { | |
214 | |
215 DCHECK_NE(sync_api::SyncManager::ChangeRecord::ACTION_DELETE, action); | |
216 switch (action) { | |
217 case sync_api::SyncManager::ChangeRecord::ACTION_ADD: { | |
218 AutoFillProfile p(profile_specifics.guid()); | |
219 AutofillProfileModelAssociator::OverwriteProfileWithServerData(&p, | |
220 profile_specifics); | |
lipalani
2010/12/08 21:37:46
make sure David is ok with this.
| |
221 if (!web_database_->AddAutoFillProfile(p)) { | |
222 LOG(ERROR) << "could not add autofill profile for guid " << p.guid(); | |
223 break; | |
224 } | |
225 | |
226 // Now that the node has been succesfully created we can associate it. | |
227 model_associator_->Associate(&(p.guid()), sync_id); | |
228 break; | |
229 } | |
230 case sync_api::SyncManager::ChangeRecord::ACTION_UPDATE: { | |
231 AutoFillProfile *p; | |
lipalani
2010/12/08 21:37:46
see if you can move P into a scope.
| |
232 if (!web_database_->GetAutoFillProfileForGUID( | |
233 profile_specifics.guid(), &p)) { | |
234 LOG(ERROR) << "Could not find the autofill profile to update for " << | |
235 profile_specifics.guid(); | |
236 break; | |
237 } | |
238 scoped_ptr<AutoFillProfile> autofill_pointer(p); | |
239 p = NULL; | |
240 AutofillProfileModelAssociator::OverwriteProfileWithServerData( | |
241 autofill_pointer.get(), | |
242 profile_specifics); | |
243 | |
244 if (!web_database_->UpdateAutoFillProfile(*(autofill_pointer.get()))) { | |
245 LOG(ERROR) << "Could not update autofill profile for " << | |
246 profile_specifics.guid(); | |
247 break; | |
248 } | |
249 break; | |
250 } | |
251 default: { | |
252 NOTREACHED(); | |
253 break; | |
254 } | |
255 } | |
256 } | |
257 | |
258 void AutofillProfileChangeProcessor::RemoveSyncNode(const std::string& guid, | |
259 sync_api::WriteTransaction* trans) { | |
260 sync_api::WriteNode node(trans); | |
261 int64 sync_id = model_associator_->GetSyncIdFromChromeId(guid); | |
262 if (sync_api::kInvalidId == sync_id) { | |
263 LOG(ERROR) << "Could not find the node in associator " << guid; | |
264 return; | |
265 } | |
266 | |
267 if (!node.InitByIdLookup(sync_id)) { | |
268 LOG(ERROR) << "Could not find the sync node for " << guid; | |
269 return; | |
270 } | |
271 | |
272 model_associator_->Disassociate(sync_id); | |
273 node.Remove(); | |
274 } | |
275 | |
276 void AutofillProfileChangeProcessor::AddAutofillProfileSyncNode( | |
277 sync_api::WriteTransaction* trans, | |
278 sync_api::BaseNode& autofill_profile_root, | |
279 const AutoFillProfile& profile) { | |
280 sync_api::WriteNode node(trans); | |
281 if (!node.InitUniqueByCreation(syncable::AUTOFILL_PROFILE, | |
282 autofill_profile_root, | |
283 profile.guid())) { | |
284 LOG(ERROR) << "could not create a sync node "; | |
285 return; | |
286 } | |
287 | |
288 node.SetTitle(UTF8ToWide(profile.guid())); | |
289 | |
290 WriteAutofillProfile(profile, &node); | |
291 } | |
292 | |
293 void AutofillProfileChangeProcessor::StartObserving() { | |
294 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); | |
295 notification_registrar_.Add(this, | |
296 NotificationType::AUTOFILL_PROFILE_CHANGED_GUID, | |
297 NotificationService::AllSources()); | |
298 } | |
299 | |
300 void AutofillProfileChangeProcessor::StopObserving() { | |
301 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); | |
302 notification_registrar_.RemoveAll(); | |
303 } | |
304 | |
305 void AutofillProfileChangeProcessor::WriteAutofillProfile( | |
306 const AutoFillProfile& profile, | |
307 sync_api::WriteNode* node) { | |
308 sync_pb::AutofillProfileSpecifics specifics; | |
309 specifics.set_guid(profile.guid()); | |
310 specifics.set_name_first(UTF16ToUTF8( | |
311 profile.GetFieldText(AutoFillType(NAME_FIRST)))); | |
312 specifics.set_name_middle(UTF16ToUTF8( | |
313 profile.GetFieldText(AutoFillType(NAME_MIDDLE)))); | |
314 specifics.set_name_last( | |
315 UTF16ToUTF8(profile.GetFieldText(AutoFillType(NAME_LAST)))); | |
316 specifics.set_address_home_line1( | |
317 UTF16ToUTF8(profile.GetFieldText(AutoFillType(ADDRESS_HOME_LINE1)))); | |
318 specifics.set_address_home_line2( | |
319 UTF16ToUTF8(profile.GetFieldText(AutoFillType(ADDRESS_HOME_LINE2)))); | |
320 specifics.set_address_home_city(UTF16ToUTF8(profile.GetFieldText( | |
321 AutoFillType(ADDRESS_HOME_CITY)))); | |
322 specifics.set_address_home_state(UTF16ToUTF8(profile.GetFieldText( | |
323 AutoFillType(ADDRESS_HOME_STATE)))); | |
324 specifics.set_address_home_country(UTF16ToUTF8(profile.GetFieldText( | |
325 AutoFillType(ADDRESS_HOME_COUNTRY)))); | |
326 specifics.set_address_home_zip(UTF16ToUTF8(profile.GetFieldText( | |
327 AutoFillType(ADDRESS_HOME_ZIP)))); | |
328 specifics.set_email_address(UTF16ToUTF8(profile.GetFieldText( | |
329 AutoFillType(EMAIL_ADDRESS)))); | |
330 specifics.set_company_name(UTF16ToUTF8(profile.GetFieldText( | |
331 AutoFillType(COMPANY_NAME)))); | |
332 specifics.set_phone_fax_whole_number(UTF16ToUTF8(profile.GetFieldText( | |
333 AutoFillType(PHONE_FAX_WHOLE_NUMBER)))); | |
334 specifics.set_phone_home_whole_number(UTF16ToUTF8(profile.GetFieldText( | |
335 AutoFillType(PHONE_HOME_WHOLE_NUMBER)))); | |
336 node->SetAutofillProfileSpecifics(specifics); | |
337 } | |
338 | |
339 } // namespace browser_sync | |
340 | |
OLD | NEW |