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

Side by Side Diff: chrome/browser/sync/glue/session_model_associator.cc

Issue 3133022: sync: take two for: "Added classes to enable session sync... (Closed)
Patch Set: Created 10 years, 4 months 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 unified diff | Download patch
OLDNEW
(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/session_model_associator.h"
6
7 #include <utility>
8
9 #include "base/logging.h"
10 #include "base/string_util.h"
11 #include "base/utf_string_conversions.h"
12 #include "chrome/browser/profile.h"
13 #include "chrome/browser/sessions/session_id.h"
14 #include "chrome/browser/sync/profile_sync_service.h"
15 #include "chrome/browser/sync/syncable/syncable.h"
16 #include "chrome/common/notification_details.h"
17 #include "chrome/common/notification_service.h"
18 #include "chrome/common/url_constants.h"
19
20 namespace browser_sync {
21
22 namespace {
23
24 static const char kNoSessionsFolderError[] =
25 "Server did not create the top-level sessions node. We "
26 "might be running against an out-of-date server.";
27
28 } // namespace
29
30 SessionModelAssociator::SessionModelAssociator(
31 ProfileSyncService* sync_service) : sync_service_(sync_service) {
32 DCHECK(CalledOnValidThread());
33 DCHECK(sync_service_);
34 }
35
36 SessionModelAssociator::~SessionModelAssociator() {
37 DCHECK(CalledOnValidThread());
38 }
39
40 // Sends a notification to ForeignSessionHandler to update the UI, because
41 // the session corresponding to the id given has changed state.
42 void SessionModelAssociator::Associate(
43 const sync_pb::SessionSpecifics* specifics, int64 sync_id) {
44 DCHECK(CalledOnValidThread());
45 NotificationService::current()->Notify(
46 NotificationType::FOREIGN_SESSION_UPDATED,
47 NotificationService::AllSources(),
48 Details<int64>(&sync_id));
49 }
50
51 bool SessionModelAssociator::AssociateModels() {
52 DCHECK(CalledOnValidThread());
53 UpdateSyncModelDataFromClient();
54 return true;
55 }
56
57 bool SessionModelAssociator::ChromeModelHasUserCreatedNodes(
58 bool* has_nodes) {
59 DCHECK(CalledOnValidThread());
60 CHECK(has_nodes);
61 // This is wrong, but this function is unused, anyway.
62 *has_nodes = true;
63 return true;
64 }
65
66 // Sends a notification to ForeignSessionHandler to update the UI, because
67 // the session corresponding to the id given has been deleted.
68 void SessionModelAssociator::Disassociate(int64 sync_id) {
69 NotificationService::current()->Notify(
70 NotificationType::FOREIGN_SESSION_DELETED,
71 NotificationService::AllSources(),
72 Details<int64>(&sync_id));
73 }
74
75 const sync_pb::SessionSpecifics* SessionModelAssociator::
76 GetChromeNodeFromSyncId(int64 sync_id) {
77 sync_api::ReadTransaction trans(
78 sync_service_->backend()->GetUserShareHandle());
79 sync_api::ReadNode node(&trans);
80 if (!node.InitByIdLookup(sync_id))
81 return NULL;
82 return new sync_pb::SessionSpecifics(node.GetSessionSpecifics());
83 }
84
85 bool SessionModelAssociator::GetSyncIdForTaggedNode(const std::string* tag,
86 int64* sync_id) {
87 sync_api::ReadTransaction trans(
88 sync_service_->backend()->GetUserShareHandle());
89 sync_api::ReadNode node(&trans);
90 if (!node.InitByClientTagLookup(syncable::SESSIONS, *tag))
91 return false;
92 *sync_id = node.GetId();
93 return true;
94 }
95
96 int64 SessionModelAssociator::GetSyncIdFromChromeId(std::string id) {
97 sync_api::ReadTransaction trans(
98 sync_service_->backend()->GetUserShareHandle());
99 sync_api::ReadNode node(&trans);
100 if (!node.InitByClientTagLookup(syncable::SESSIONS, id))
101 return sync_api::kInvalidId;
102 return node.GetId();
103 }
104
105 bool SessionModelAssociator::SyncModelHasUserCreatedNodes(bool* has_nodes) {
106 DCHECK(CalledOnValidThread());
107 CHECK(has_nodes);
108 *has_nodes = false;
109 sync_api::ReadTransaction trans(
110 sync_service_->backend()->GetUserShareHandle());
111 sync_api::ReadNode root(&trans);
112 if (!root.InitByTagLookup(kSessionsTag)) {
113 LOG(ERROR) << kNoSessionsFolderError;
114 return false;
115 }
116 // The sync model has user created nodes iff the sessions folder has
117 // any children.
118 *has_nodes = root.GetFirstChildId() != sync_api::kInvalidId;
119 return true;
120 }
121
122 std::string SessionModelAssociator::GetCurrentMachineTag() {
123 if (current_machine_tag_.empty())
124 InitializeCurrentMachineTag();
125 DCHECK(!current_machine_tag_.empty());
126 return current_machine_tag_;
127 }
128
129 void SessionModelAssociator::AppendForeignSessionFromSpecifics(
130 const sync_pb::SessionSpecifics* specifics,
131 std::vector<ForeignSession*>* session) {
132 ForeignSession* foreign_session = new ForeignSession();
133 foreign_session->foreign_tession_tag = specifics->session_tag();
134 session->insert(session->end(), foreign_session);
135 for (int i = 0; i < specifics->session_window_size(); i++) {
136 const sync_pb::SessionWindow* window = &specifics->session_window(i);
137 SessionWindow* session_window = new SessionWindow();
138 PopulateSessionWindowFromSpecifics(session_window, window);
139 foreign_session->windows.insert(
140 foreign_session->windows.end(), session_window);
141 }
142 }
143
144 // Fills the given vector with foreign session windows to restore.
145 void SessionModelAssociator::AppendForeignSessionWithID(int64 id,
146 std::vector<ForeignSession*>* session, sync_api::BaseTransaction* trans) {
147 if (id == sync_api::kInvalidId)
148 return;
149 sync_api::ReadNode node(trans);
150 if (!node.InitByIdLookup(id))
151 return;
152 const sync_pb::SessionSpecifics* ref = &node.GetSessionSpecifics();
153 AppendForeignSessionFromSpecifics(ref, session);
154 }
155
156 void SessionModelAssociator::UpdateSyncModelDataFromClient() {
157 DCHECK(CalledOnValidThread());
158 SessionService::SessionCallback* callback =
159 NewCallback(this, &SessionModelAssociator::OnGotSession);
160 // TODO(jerrica): Stop current race condition, possibly make new method in
161 // session service, which only grabs the windows from memory.
162 GetSessionService()->GetCurrentSession(&consumer_, callback);
163 }
164
165 bool SessionModelAssociator::GetSessionDataFromSyncModel(
166 std::vector<ForeignSession*>* sessions) {
167 std::vector<const sync_pb::SessionSpecifics*> specifics;
168 DCHECK(CalledOnValidThread());
169 sync_api::ReadTransaction trans(
170 sync_service_->backend()->GetUserShareHandle());
171 sync_api::ReadNode root(&trans);
172 if (!root.InitByTagLookup(kSessionsTag)) {
173 LOG(ERROR) << kNoSessionsFolderError;
174 return false;
175 }
176 sync_api::ReadNode current_machine(&trans);
177 int64 current_id = (current_machine.InitByClientTagLookup(syncable::SESSIONS,
178 GetCurrentMachineTag())) ? current_machine.GetId() : sync_api::kInvalidId;
179 // Iterate through the nodes and populate the session model.
180 int64 id = root.GetFirstChildId();
181 while (id != sync_api::kInvalidId) {
182 sync_api::ReadNode sync_node(&trans);
183 if (!sync_node.InitByIdLookup(id)) {
184 LOG(ERROR) << "Failed to fetch sync node for id " << id;
185 return false;
186 }
187 if (id != current_id) {
188 specifics.insert(specifics.end(), &sync_node.GetSessionSpecifics());
189 }
190 id = sync_node.GetSuccessorId();
191 }
192 for (std::vector<const sync_pb::SessionSpecifics*>::const_iterator i =
193 specifics.begin(); i != specifics.end(); ++i) {
194 AppendForeignSessionFromSpecifics(*i, sessions);
195 }
196 return true;
197 }
198
199 SessionService* SessionModelAssociator::GetSessionService() {
200 DCHECK(sync_service_);
201 Profile* profile = sync_service_->profile();
202 DCHECK(profile);
203 SessionService* sessions_service = profile->GetSessionService();
204 DCHECK(sessions_service);
205 return sessions_service;
206 }
207
208 void SessionModelAssociator::InitializeCurrentMachineTag() {
209 sync_api::WriteTransaction trans(sync_service_->backend()->
210 GetUserShareHandle());
211 syncable::Directory* dir =
212 trans.GetWrappedWriteTrans()->directory();
213 current_machine_tag_ = "session_sync" + dir->cache_guid();
214 }
215
216 // See PopulateSessionSpecificsTab for use. May add functionality that includes
217 // the state later.
218 void SessionModelAssociator::PopulateSessionSpecificsNavigation(
219 const TabNavigation* navigation, sync_pb::TabNavigation* tab_navigation) {
220 tab_navigation->set_index(navigation->index());
221 tab_navigation->set_virtual_url(navigation->virtual_url().spec());
222 tab_navigation->set_referrer(navigation->referrer().spec());
223 tab_navigation->set_title(UTF16ToUTF8(navigation->title()));
224 switch (navigation->transition()) {
225 case PageTransition::LINK:
226 tab_navigation->set_page_transition(
227 sync_pb::TabNavigation_PageTransition_LINK);
228 break;
229 case PageTransition::TYPED:
230 tab_navigation->set_page_transition(
231 sync_pb::TabNavigation_PageTransition_TYPED);
232 break;
233 case PageTransition::AUTO_BOOKMARK:
234 tab_navigation->set_page_transition(
235 sync_pb::TabNavigation_PageTransition_AUTO_BOOKMARK);
236 break;
237 case PageTransition::AUTO_SUBFRAME:
238 tab_navigation->set_page_transition(
239 sync_pb::TabNavigation_PageTransition_AUTO_SUBFRAME);
240 break;
241 case PageTransition::MANUAL_SUBFRAME:
242 tab_navigation->set_page_transition(
243 sync_pb::TabNavigation_PageTransition_MANUAL_SUBFRAME);
244 break;
245 case PageTransition::GENERATED:
246 tab_navigation->set_page_transition(
247 sync_pb::TabNavigation_PageTransition_GENERATED);
248 break;
249 case PageTransition::START_PAGE:
250 tab_navigation->set_page_transition(
251 sync_pb::TabNavigation_PageTransition_START_PAGE);
252 break;
253 case PageTransition::FORM_SUBMIT:
254 tab_navigation->set_page_transition(
255 sync_pb::TabNavigation_PageTransition_FORM_SUBMIT);
256 break;
257 case PageTransition::RELOAD:
258 tab_navigation->set_page_transition(
259 sync_pb::TabNavigation_PageTransition_RELOAD);
260 break;
261 case PageTransition::KEYWORD:
262 tab_navigation->set_page_transition(
263 sync_pb::TabNavigation_PageTransition_KEYWORD);
264 break;
265 case PageTransition::KEYWORD_GENERATED:
266 tab_navigation->set_page_transition(
267 sync_pb::TabNavigation_PageTransition_KEYWORD_GENERATED);
268 break;
269 case PageTransition::CHAIN_START:
270 tab_navigation->set_page_transition(
271 sync_pb::TabNavigation_PageTransition_CHAIN_START);
272 break;
273 case PageTransition::CHAIN_END:
274 tab_navigation->set_page_transition(
275 sync_pb::TabNavigation_PageTransition_CHAIN_END);
276 break;
277 case PageTransition::CLIENT_REDIRECT:
278 tab_navigation->set_navigation_qualifier(
279 sync_pb::TabNavigation_PageTransitionQualifier_CLIENT_REDIRECT);
280 break;
281 case PageTransition::SERVER_REDIRECT:
282 tab_navigation->set_navigation_qualifier(
283 sync_pb::TabNavigation_PageTransitionQualifier_SERVER_REDIRECT);
284 break;
285 default:
286 tab_navigation->set_page_transition(
287 sync_pb::TabNavigation_PageTransition_TYPED);
288 }
289 }
290
291 // See PopulateSessionSpecificsWindow for use.
292 void SessionModelAssociator::PopulateSessionSpecificsTab(
293 const SessionTab* tab, sync_pb::SessionTab* session_tab) {
294 session_tab->set_tab_visual_index(tab->tab_visual_index);
295 session_tab->set_current_navigation_index(
296 tab->current_navigation_index);
297 session_tab->set_pinned(tab->pinned);
298 session_tab->set_extension_app_id(tab->extension_app_id);
299 for (std::vector<TabNavigation>::const_iterator i3 =
300 tab->navigations.begin(); i3 != tab->navigations.end(); ++i3) {
301 const TabNavigation navigation = *i3;
302 sync_pb::TabNavigation* tab_navigation =
303 session_tab->add_navigation();
304 PopulateSessionSpecificsNavigation(&navigation, tab_navigation);
305 }
306 }
307
308 // Called when populating session specifics to send to the sync model, called
309 // when associating models, or updating the sync model.
310 void SessionModelAssociator::PopulateSessionSpecificsWindow(
311 const SessionWindow* window, sync_pb::SessionWindow* session_window) {
312 session_window->set_selected_tab_index(window->selected_tab_index);
313 if (window->type == 1) {
314 session_window->set_browser_type(
315 sync_pb::SessionWindow_BrowserType_TYPE_NORMAL);
316 } else {
317 session_window->set_browser_type(
318 sync_pb::SessionWindow_BrowserType_TYPE_POPUP);
319 }
320 for (std::vector<SessionTab*>::const_iterator i2 = window->tabs.begin();
321 i2 != window->tabs.end(); ++i2) {
322 const SessionTab* tab = *i2;
323 if (tab->navigations.at(tab->current_navigation_index).virtual_url() ==
324 GURL(chrome::kChromeUINewTabURL)) {
325 continue;
326 }
327 sync_pb::SessionTab* session_tab = session_window->add_session_tab();
328 PopulateSessionSpecificsTab(tab, session_tab);
329 }
330 }
331
332 bool SessionModelAssociator::WindowHasNoTabsToSync(
333 const SessionWindow* window) {
334 int num_populated = 0;
335 for (std::vector<SessionTab*>::const_iterator i = window->tabs.begin();
336 i != window->tabs.end(); ++i) {
337 const SessionTab* tab = *i;
338 if (tab->navigations.at(tab->current_navigation_index).virtual_url() ==
339 GURL(chrome::kChromeUINewTabURL)) {
340 continue;
341 }
342 num_populated++;
343 }
344 if (num_populated == 0)
345 return true;
346 return false;
347 }
348
349 void SessionModelAssociator::OnGotSession(int handle,
350 std::vector<SessionWindow*>* windows) {
351 sync_pb::SessionSpecifics session;
352 // Set the tag, then iterate through the vector of windows, extracting the
353 // window data, along with the tabs data and tab navigation data to populate
354 // the session specifics.
355 session.set_session_tag(GetCurrentMachineTag());
356 for (std::vector<SessionWindow*>::const_iterator i = windows->begin();
357 i != windows->end(); ++i) {
358 const SessionWindow* window = *i;
359 if (WindowHasNoTabsToSync(window)) {
360 continue;
361 }
362 sync_pb::SessionWindow* session_window = session.add_session_window();
363 PopulateSessionSpecificsWindow(window, session_window);
364 }
365 bool has_nodes = false;
366 if (!SyncModelHasUserCreatedNodes(&has_nodes))
367 return;
368 if (session.session_window_size() == 0 && has_nodes)
369 return;
370 sync_api::WriteTransaction trans(
371 sync_service_->backend()->GetUserShareHandle());
372 sync_api::ReadNode root(&trans);
373 if (!root.InitByTagLookup(kSessionsTag)) {
374 LOG(ERROR) << kNoSessionsFolderError;
375 return;
376 }
377 UpdateSyncModel(&session, &trans, &root);
378 }
379
380 void SessionModelAssociator::AppendSessionTabNavigation(
381 std::vector<TabNavigation>* navigations,
382 const sync_pb::TabNavigation* navigation) {
383 int index = 0;
384 GURL virtual_url;
385 GURL referrer;
386 string16 title;
387 std::string state;
388 PageTransition::Type transition(PageTransition::LINK);
389 if (navigation->has_index())
390 index = navigation->index();
391 if (navigation->has_virtual_url()) {
392 GURL gurl(navigation->virtual_url());
393 virtual_url = gurl;
394 }
395 if (navigation->has_referrer()) {
396 GURL gurl(navigation->referrer());
397 referrer = gurl;
398 }
399 if (navigation->has_title())
400 title = UTF8ToUTF16(navigation->title());
401 if (navigation->has_page_transition() ||
402 navigation->has_navigation_qualifier()) {
403 switch (navigation->page_transition()) {
404 case sync_pb::TabNavigation_PageTransition_LINK:
405 transition = PageTransition::LINK;
406 break;
407 case sync_pb::TabNavigation_PageTransition_TYPED:
408 transition = PageTransition::TYPED;
409 break;
410 case sync_pb::TabNavigation_PageTransition_AUTO_BOOKMARK:
411 transition = PageTransition::AUTO_BOOKMARK;
412 break;
413 case sync_pb::TabNavigation_PageTransition_AUTO_SUBFRAME:
414 transition = PageTransition::AUTO_SUBFRAME;
415 break;
416 case sync_pb::TabNavigation_PageTransition_MANUAL_SUBFRAME:
417 transition = PageTransition::MANUAL_SUBFRAME;
418 break;
419 case sync_pb::TabNavigation_PageTransition_GENERATED:
420 transition = PageTransition::GENERATED;
421 break;
422 case sync_pb::TabNavigation_PageTransition_START_PAGE:
423 transition = PageTransition::START_PAGE;
424 break;
425 case sync_pb::TabNavigation_PageTransition_FORM_SUBMIT:
426 transition = PageTransition::FORM_SUBMIT;
427 break;
428 case sync_pb::TabNavigation_PageTransition_RELOAD:
429 transition = PageTransition::RELOAD;
430 break;
431 case sync_pb::TabNavigation_PageTransition_KEYWORD:
432 transition = PageTransition::KEYWORD;
433 break;
434 case sync_pb::TabNavigation_PageTransition_KEYWORD_GENERATED:
435 transition = PageTransition::KEYWORD_GENERATED;
436 break;
437 case sync_pb::TabNavigation_PageTransition_CHAIN_START:
438 transition = sync_pb::TabNavigation_PageTransition_CHAIN_START;
439 break;
440 case sync_pb::TabNavigation_PageTransition_CHAIN_END:
441 transition = PageTransition::CHAIN_END;
442 break;
443 default:
444 switch (navigation->navigation_qualifier()) {
445 case sync_pb::
446 TabNavigation_PageTransitionQualifier_CLIENT_REDIRECT:
447 transition = PageTransition::CLIENT_REDIRECT;
448 break;
449 case sync_pb::
450 TabNavigation_PageTransitionQualifier_SERVER_REDIRECT:
451 transition = PageTransition::SERVER_REDIRECT;
452 break;
453 default:
454 transition = PageTransition::TYPED;
455 }
456 }
457 }
458 TabNavigation tab_navigation(index, virtual_url, referrer, title, state,
459 transition);
460 navigations->insert(navigations->end(), tab_navigation);
461 }
462
463 void SessionModelAssociator::PopulateSessionTabFromSpecifics(
464 SessionTab* session_tab,
465 const sync_pb::SessionTab* tab, SessionID id) {
466 session_tab->window_id = id;
467 SessionID tabID;
468 session_tab->tab_id = tabID;
469 if (tab->has_tab_visual_index())
470 session_tab->tab_visual_index = tab->tab_visual_index();
471 if (tab->has_current_navigation_index()) {
472 session_tab->current_navigation_index =
473 tab->current_navigation_index();
474 }
475 if (tab->has_pinned())
476 session_tab->pinned = tab->pinned();
477 if (tab->has_extension_app_id())
478 session_tab->extension_app_id = tab->extension_app_id();
479 for (int i3 = 0; i3 < tab->navigation_size(); i3++) {
480 const sync_pb::TabNavigation* navigation = &tab->navigation(i3);
481 AppendSessionTabNavigation(&session_tab->navigations, navigation);
482 }
483 }
484
485 void SessionModelAssociator::PopulateSessionWindowFromSpecifics(
486 SessionWindow* session_window, const sync_pb::SessionWindow* window) {
487 SessionID id;
488 session_window->window_id = id;
489 if (window->has_selected_tab_index())
490 session_window->selected_tab_index = window->selected_tab_index();
491 if (window->has_browser_type()) {
492 if (window->browser_type() ==
493 sync_pb::SessionWindow_BrowserType_TYPE_NORMAL) {
494 session_window->type = 1;
495 } else {
496 session_window->type = 2;
497 }
498 }
499 for (int i = 0; i < window->session_tab_size(); i++) {
500 const sync_pb::SessionTab& tab = window->session_tab(i);
501 SessionTab* session_tab = new SessionTab();
502 PopulateSessionTabFromSpecifics(session_tab, &tab, id);
503 session_window->tabs.insert(session_window->tabs.end(), session_tab);
504 }
505 }
506
507 bool SessionModelAssociator::UpdateSyncModel(
508 sync_pb::SessionSpecifics* session_data,
509 sync_api::WriteTransaction* trans,
510 const sync_api::ReadNode* root) {
511 const std::string id = session_data->session_tag();
512 sync_api::WriteNode write_node(trans);
513 if (!write_node.InitByClientTagLookup(syncable::SESSIONS, id)) {
514 sync_api::WriteNode create_node(trans);
515 if (!create_node.InitUniqueByCreation(syncable::SESSIONS, *root, id)) {
516 LOG(ERROR) << "Could not create node for session " << id;
517 return false;
518 }
519 create_node.SetSessionSpecifics(*session_data);
520 return true;
521 }
522 write_node.SetSessionSpecifics(*session_data);
523 return true;
524 }
525
526 } // namespace browser_sync
527
OLDNEW
« no previous file with comments | « chrome/browser/sync/glue/session_model_associator.h ('k') | chrome/browser/sync/profile_sync_factory.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698