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

Unified 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 side-by-side diff with in-line comments
Download patch
« 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 »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/browser/sync/glue/session_model_associator.cc
diff --git a/chrome/browser/sync/glue/session_model_associator.cc b/chrome/browser/sync/glue/session_model_associator.cc
new file mode 100644
index 0000000000000000000000000000000000000000..f6a6d1fa0fc50f20dfdb55cd76376159223d8492
--- /dev/null
+++ b/chrome/browser/sync/glue/session_model_associator.cc
@@ -0,0 +1,527 @@
+// 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/session_model_associator.h"
+
+#include <utility>
+
+#include "base/logging.h"
+#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/profile.h"
+#include "chrome/browser/sessions/session_id.h"
+#include "chrome/browser/sync/profile_sync_service.h"
+#include "chrome/browser/sync/syncable/syncable.h"
+#include "chrome/common/notification_details.h"
+#include "chrome/common/notification_service.h"
+#include "chrome/common/url_constants.h"
+
+namespace browser_sync {
+
+namespace {
+
+static const char kNoSessionsFolderError[] =
+ "Server did not create the top-level sessions node. We "
+ "might be running against an out-of-date server.";
+
+} // namespace
+
+SessionModelAssociator::SessionModelAssociator(
+ ProfileSyncService* sync_service) : sync_service_(sync_service) {
+ DCHECK(CalledOnValidThread());
+ DCHECK(sync_service_);
+}
+
+SessionModelAssociator::~SessionModelAssociator() {
+ DCHECK(CalledOnValidThread());
+}
+
+// Sends a notification to ForeignSessionHandler to update the UI, because
+// the session corresponding to the id given has changed state.
+void SessionModelAssociator::Associate(
+ const sync_pb::SessionSpecifics* specifics, int64 sync_id) {
+ DCHECK(CalledOnValidThread());
+ NotificationService::current()->Notify(
+ NotificationType::FOREIGN_SESSION_UPDATED,
+ NotificationService::AllSources(),
+ Details<int64>(&sync_id));
+}
+
+bool SessionModelAssociator::AssociateModels() {
+ DCHECK(CalledOnValidThread());
+ UpdateSyncModelDataFromClient();
+ return true;
+}
+
+bool SessionModelAssociator::ChromeModelHasUserCreatedNodes(
+ bool* has_nodes) {
+ DCHECK(CalledOnValidThread());
+ CHECK(has_nodes);
+ // This is wrong, but this function is unused, anyway.
+ *has_nodes = true;
+ return true;
+}
+
+// Sends a notification to ForeignSessionHandler to update the UI, because
+// the session corresponding to the id given has been deleted.
+void SessionModelAssociator::Disassociate(int64 sync_id) {
+ NotificationService::current()->Notify(
+ NotificationType::FOREIGN_SESSION_DELETED,
+ NotificationService::AllSources(),
+ Details<int64>(&sync_id));
+}
+
+const sync_pb::SessionSpecifics* SessionModelAssociator::
+ GetChromeNodeFromSyncId(int64 sync_id) {
+ sync_api::ReadTransaction trans(
+ sync_service_->backend()->GetUserShareHandle());
+ sync_api::ReadNode node(&trans);
+ if (!node.InitByIdLookup(sync_id))
+ return NULL;
+ return new sync_pb::SessionSpecifics(node.GetSessionSpecifics());
+}
+
+bool SessionModelAssociator::GetSyncIdForTaggedNode(const std::string* tag,
+ int64* sync_id) {
+ sync_api::ReadTransaction trans(
+ sync_service_->backend()->GetUserShareHandle());
+ sync_api::ReadNode node(&trans);
+ if (!node.InitByClientTagLookup(syncable::SESSIONS, *tag))
+ return false;
+ *sync_id = node.GetId();
+ return true;
+}
+
+int64 SessionModelAssociator::GetSyncIdFromChromeId(std::string id) {
+ sync_api::ReadTransaction trans(
+ sync_service_->backend()->GetUserShareHandle());
+ sync_api::ReadNode node(&trans);
+ if (!node.InitByClientTagLookup(syncable::SESSIONS, id))
+ return sync_api::kInvalidId;
+ return node.GetId();
+}
+
+bool SessionModelAssociator::SyncModelHasUserCreatedNodes(bool* has_nodes) {
+ DCHECK(CalledOnValidThread());
+ CHECK(has_nodes);
+ *has_nodes = false;
+ sync_api::ReadTransaction trans(
+ sync_service_->backend()->GetUserShareHandle());
+ sync_api::ReadNode root(&trans);
+ if (!root.InitByTagLookup(kSessionsTag)) {
+ LOG(ERROR) << kNoSessionsFolderError;
+ return false;
+ }
+ // The sync model has user created nodes iff the sessions folder has
+ // any children.
+ *has_nodes = root.GetFirstChildId() != sync_api::kInvalidId;
+ return true;
+}
+
+std::string SessionModelAssociator::GetCurrentMachineTag() {
+ if (current_machine_tag_.empty())
+ InitializeCurrentMachineTag();
+ DCHECK(!current_machine_tag_.empty());
+ return current_machine_tag_;
+}
+
+void SessionModelAssociator::AppendForeignSessionFromSpecifics(
+ const sync_pb::SessionSpecifics* specifics,
+ std::vector<ForeignSession*>* session) {
+ ForeignSession* foreign_session = new ForeignSession();
+ foreign_session->foreign_tession_tag = specifics->session_tag();
+ session->insert(session->end(), foreign_session);
+ for (int i = 0; i < specifics->session_window_size(); i++) {
+ const sync_pb::SessionWindow* window = &specifics->session_window(i);
+ SessionWindow* session_window = new SessionWindow();
+ PopulateSessionWindowFromSpecifics(session_window, window);
+ foreign_session->windows.insert(
+ foreign_session->windows.end(), session_window);
+ }
+}
+
+// Fills the given vector with foreign session windows to restore.
+void SessionModelAssociator::AppendForeignSessionWithID(int64 id,
+ std::vector<ForeignSession*>* session, sync_api::BaseTransaction* trans) {
+ if (id == sync_api::kInvalidId)
+ return;
+ sync_api::ReadNode node(trans);
+ if (!node.InitByIdLookup(id))
+ return;
+ const sync_pb::SessionSpecifics* ref = &node.GetSessionSpecifics();
+ AppendForeignSessionFromSpecifics(ref, session);
+}
+
+void SessionModelAssociator::UpdateSyncModelDataFromClient() {
+ DCHECK(CalledOnValidThread());
+ SessionService::SessionCallback* callback =
+ NewCallback(this, &SessionModelAssociator::OnGotSession);
+ // TODO(jerrica): Stop current race condition, possibly make new method in
+ // session service, which only grabs the windows from memory.
+ GetSessionService()->GetCurrentSession(&consumer_, callback);
+}
+
+bool SessionModelAssociator::GetSessionDataFromSyncModel(
+ std::vector<ForeignSession*>* sessions) {
+ std::vector<const sync_pb::SessionSpecifics*> specifics;
+ DCHECK(CalledOnValidThread());
+ sync_api::ReadTransaction trans(
+ sync_service_->backend()->GetUserShareHandle());
+ sync_api::ReadNode root(&trans);
+ if (!root.InitByTagLookup(kSessionsTag)) {
+ LOG(ERROR) << kNoSessionsFolderError;
+ return false;
+ }
+ sync_api::ReadNode current_machine(&trans);
+ int64 current_id = (current_machine.InitByClientTagLookup(syncable::SESSIONS,
+ GetCurrentMachineTag())) ? current_machine.GetId() : sync_api::kInvalidId;
+ // Iterate through the nodes and populate the session model.
+ int64 id = root.GetFirstChildId();
+ while (id != sync_api::kInvalidId) {
+ sync_api::ReadNode sync_node(&trans);
+ if (!sync_node.InitByIdLookup(id)) {
+ LOG(ERROR) << "Failed to fetch sync node for id " << id;
+ return false;
+ }
+ if (id != current_id) {
+ specifics.insert(specifics.end(), &sync_node.GetSessionSpecifics());
+ }
+ id = sync_node.GetSuccessorId();
+ }
+ for (std::vector<const sync_pb::SessionSpecifics*>::const_iterator i =
+ specifics.begin(); i != specifics.end(); ++i) {
+ AppendForeignSessionFromSpecifics(*i, sessions);
+ }
+ return true;
+}
+
+SessionService* SessionModelAssociator::GetSessionService() {
+ DCHECK(sync_service_);
+ Profile* profile = sync_service_->profile();
+ DCHECK(profile);
+ SessionService* sessions_service = profile->GetSessionService();
+ DCHECK(sessions_service);
+ return sessions_service;
+}
+
+void SessionModelAssociator::InitializeCurrentMachineTag() {
+ sync_api::WriteTransaction trans(sync_service_->backend()->
+ GetUserShareHandle());
+ syncable::Directory* dir =
+ trans.GetWrappedWriteTrans()->directory();
+ current_machine_tag_ = "session_sync" + dir->cache_guid();
+}
+
+// See PopulateSessionSpecificsTab for use. May add functionality that includes
+// the state later.
+void SessionModelAssociator::PopulateSessionSpecificsNavigation(
+ const TabNavigation* navigation, sync_pb::TabNavigation* tab_navigation) {
+ tab_navigation->set_index(navigation->index());
+ tab_navigation->set_virtual_url(navigation->virtual_url().spec());
+ tab_navigation->set_referrer(navigation->referrer().spec());
+ tab_navigation->set_title(UTF16ToUTF8(navigation->title()));
+ switch (navigation->transition()) {
+ case PageTransition::LINK:
+ tab_navigation->set_page_transition(
+ sync_pb::TabNavigation_PageTransition_LINK);
+ break;
+ case PageTransition::TYPED:
+ tab_navigation->set_page_transition(
+ sync_pb::TabNavigation_PageTransition_TYPED);
+ break;
+ case PageTransition::AUTO_BOOKMARK:
+ tab_navigation->set_page_transition(
+ sync_pb::TabNavigation_PageTransition_AUTO_BOOKMARK);
+ break;
+ case PageTransition::AUTO_SUBFRAME:
+ tab_navigation->set_page_transition(
+ sync_pb::TabNavigation_PageTransition_AUTO_SUBFRAME);
+ break;
+ case PageTransition::MANUAL_SUBFRAME:
+ tab_navigation->set_page_transition(
+ sync_pb::TabNavigation_PageTransition_MANUAL_SUBFRAME);
+ break;
+ case PageTransition::GENERATED:
+ tab_navigation->set_page_transition(
+ sync_pb::TabNavigation_PageTransition_GENERATED);
+ break;
+ case PageTransition::START_PAGE:
+ tab_navigation->set_page_transition(
+ sync_pb::TabNavigation_PageTransition_START_PAGE);
+ break;
+ case PageTransition::FORM_SUBMIT:
+ tab_navigation->set_page_transition(
+ sync_pb::TabNavigation_PageTransition_FORM_SUBMIT);
+ break;
+ case PageTransition::RELOAD:
+ tab_navigation->set_page_transition(
+ sync_pb::TabNavigation_PageTransition_RELOAD);
+ break;
+ case PageTransition::KEYWORD:
+ tab_navigation->set_page_transition(
+ sync_pb::TabNavigation_PageTransition_KEYWORD);
+ break;
+ case PageTransition::KEYWORD_GENERATED:
+ tab_navigation->set_page_transition(
+ sync_pb::TabNavigation_PageTransition_KEYWORD_GENERATED);
+ break;
+ case PageTransition::CHAIN_START:
+ tab_navigation->set_page_transition(
+ sync_pb::TabNavigation_PageTransition_CHAIN_START);
+ break;
+ case PageTransition::CHAIN_END:
+ tab_navigation->set_page_transition(
+ sync_pb::TabNavigation_PageTransition_CHAIN_END);
+ break;
+ case PageTransition::CLIENT_REDIRECT:
+ tab_navigation->set_navigation_qualifier(
+ sync_pb::TabNavigation_PageTransitionQualifier_CLIENT_REDIRECT);
+ break;
+ case PageTransition::SERVER_REDIRECT:
+ tab_navigation->set_navigation_qualifier(
+ sync_pb::TabNavigation_PageTransitionQualifier_SERVER_REDIRECT);
+ break;
+ default:
+ tab_navigation->set_page_transition(
+ sync_pb::TabNavigation_PageTransition_TYPED);
+ }
+}
+
+// See PopulateSessionSpecificsWindow for use.
+void SessionModelAssociator::PopulateSessionSpecificsTab(
+ const SessionTab* tab, sync_pb::SessionTab* session_tab) {
+ session_tab->set_tab_visual_index(tab->tab_visual_index);
+ session_tab->set_current_navigation_index(
+ tab->current_navigation_index);
+ session_tab->set_pinned(tab->pinned);
+ session_tab->set_extension_app_id(tab->extension_app_id);
+ for (std::vector<TabNavigation>::const_iterator i3 =
+ tab->navigations.begin(); i3 != tab->navigations.end(); ++i3) {
+ const TabNavigation navigation = *i3;
+ sync_pb::TabNavigation* tab_navigation =
+ session_tab->add_navigation();
+ PopulateSessionSpecificsNavigation(&navigation, tab_navigation);
+ }
+}
+
+// Called when populating session specifics to send to the sync model, called
+// when associating models, or updating the sync model.
+void SessionModelAssociator::PopulateSessionSpecificsWindow(
+ const SessionWindow* window, sync_pb::SessionWindow* session_window) {
+ session_window->set_selected_tab_index(window->selected_tab_index);
+ if (window->type == 1) {
+ session_window->set_browser_type(
+ sync_pb::SessionWindow_BrowserType_TYPE_NORMAL);
+ } else {
+ session_window->set_browser_type(
+ sync_pb::SessionWindow_BrowserType_TYPE_POPUP);
+ }
+ for (std::vector<SessionTab*>::const_iterator i2 = window->tabs.begin();
+ i2 != window->tabs.end(); ++i2) {
+ const SessionTab* tab = *i2;
+ if (tab->navigations.at(tab->current_navigation_index).virtual_url() ==
+ GURL(chrome::kChromeUINewTabURL)) {
+ continue;
+ }
+ sync_pb::SessionTab* session_tab = session_window->add_session_tab();
+ PopulateSessionSpecificsTab(tab, session_tab);
+ }
+}
+
+bool SessionModelAssociator::WindowHasNoTabsToSync(
+ const SessionWindow* window) {
+ int num_populated = 0;
+ for (std::vector<SessionTab*>::const_iterator i = window->tabs.begin();
+ i != window->tabs.end(); ++i) {
+ const SessionTab* tab = *i;
+ if (tab->navigations.at(tab->current_navigation_index).virtual_url() ==
+ GURL(chrome::kChromeUINewTabURL)) {
+ continue;
+ }
+ num_populated++;
+ }
+ if (num_populated == 0)
+ return true;
+ return false;
+}
+
+void SessionModelAssociator::OnGotSession(int handle,
+ std::vector<SessionWindow*>* windows) {
+ sync_pb::SessionSpecifics session;
+ // Set the tag, then iterate through the vector of windows, extracting the
+ // window data, along with the tabs data and tab navigation data to populate
+ // the session specifics.
+ session.set_session_tag(GetCurrentMachineTag());
+ for (std::vector<SessionWindow*>::const_iterator i = windows->begin();
+ i != windows->end(); ++i) {
+ const SessionWindow* window = *i;
+ if (WindowHasNoTabsToSync(window)) {
+ continue;
+ }
+ sync_pb::SessionWindow* session_window = session.add_session_window();
+ PopulateSessionSpecificsWindow(window, session_window);
+ }
+ bool has_nodes = false;
+ if (!SyncModelHasUserCreatedNodes(&has_nodes))
+ return;
+ if (session.session_window_size() == 0 && has_nodes)
+ return;
+ sync_api::WriteTransaction trans(
+ sync_service_->backend()->GetUserShareHandle());
+ sync_api::ReadNode root(&trans);
+ if (!root.InitByTagLookup(kSessionsTag)) {
+ LOG(ERROR) << kNoSessionsFolderError;
+ return;
+ }
+ UpdateSyncModel(&session, &trans, &root);
+}
+
+void SessionModelAssociator::AppendSessionTabNavigation(
+ std::vector<TabNavigation>* navigations,
+ const sync_pb::TabNavigation* navigation) {
+ int index = 0;
+ GURL virtual_url;
+ GURL referrer;
+ string16 title;
+ std::string state;
+ PageTransition::Type transition(PageTransition::LINK);
+ if (navigation->has_index())
+ index = navigation->index();
+ if (navigation->has_virtual_url()) {
+ GURL gurl(navigation->virtual_url());
+ virtual_url = gurl;
+ }
+ if (navigation->has_referrer()) {
+ GURL gurl(navigation->referrer());
+ referrer = gurl;
+ }
+ if (navigation->has_title())
+ title = UTF8ToUTF16(navigation->title());
+ if (navigation->has_page_transition() ||
+ navigation->has_navigation_qualifier()) {
+ switch (navigation->page_transition()) {
+ case sync_pb::TabNavigation_PageTransition_LINK:
+ transition = PageTransition::LINK;
+ break;
+ case sync_pb::TabNavigation_PageTransition_TYPED:
+ transition = PageTransition::TYPED;
+ break;
+ case sync_pb::TabNavigation_PageTransition_AUTO_BOOKMARK:
+ transition = PageTransition::AUTO_BOOKMARK;
+ break;
+ case sync_pb::TabNavigation_PageTransition_AUTO_SUBFRAME:
+ transition = PageTransition::AUTO_SUBFRAME;
+ break;
+ case sync_pb::TabNavigation_PageTransition_MANUAL_SUBFRAME:
+ transition = PageTransition::MANUAL_SUBFRAME;
+ break;
+ case sync_pb::TabNavigation_PageTransition_GENERATED:
+ transition = PageTransition::GENERATED;
+ break;
+ case sync_pb::TabNavigation_PageTransition_START_PAGE:
+ transition = PageTransition::START_PAGE;
+ break;
+ case sync_pb::TabNavigation_PageTransition_FORM_SUBMIT:
+ transition = PageTransition::FORM_SUBMIT;
+ break;
+ case sync_pb::TabNavigation_PageTransition_RELOAD:
+ transition = PageTransition::RELOAD;
+ break;
+ case sync_pb::TabNavigation_PageTransition_KEYWORD:
+ transition = PageTransition::KEYWORD;
+ break;
+ case sync_pb::TabNavigation_PageTransition_KEYWORD_GENERATED:
+ transition = PageTransition::KEYWORD_GENERATED;
+ break;
+ case sync_pb::TabNavigation_PageTransition_CHAIN_START:
+ transition = sync_pb::TabNavigation_PageTransition_CHAIN_START;
+ break;
+ case sync_pb::TabNavigation_PageTransition_CHAIN_END:
+ transition = PageTransition::CHAIN_END;
+ break;
+ default:
+ switch (navigation->navigation_qualifier()) {
+ case sync_pb::
+ TabNavigation_PageTransitionQualifier_CLIENT_REDIRECT:
+ transition = PageTransition::CLIENT_REDIRECT;
+ break;
+ case sync_pb::
+ TabNavigation_PageTransitionQualifier_SERVER_REDIRECT:
+ transition = PageTransition::SERVER_REDIRECT;
+ break;
+ default:
+ transition = PageTransition::TYPED;
+ }
+ }
+ }
+ TabNavigation tab_navigation(index, virtual_url, referrer, title, state,
+ transition);
+ navigations->insert(navigations->end(), tab_navigation);
+}
+
+void SessionModelAssociator::PopulateSessionTabFromSpecifics(
+ SessionTab* session_tab,
+ const sync_pb::SessionTab* tab, SessionID id) {
+ session_tab->window_id = id;
+ SessionID tabID;
+ session_tab->tab_id = tabID;
+ if (tab->has_tab_visual_index())
+ session_tab->tab_visual_index = tab->tab_visual_index();
+ if (tab->has_current_navigation_index()) {
+ session_tab->current_navigation_index =
+ tab->current_navigation_index();
+ }
+ if (tab->has_pinned())
+ session_tab->pinned = tab->pinned();
+ if (tab->has_extension_app_id())
+ session_tab->extension_app_id = tab->extension_app_id();
+ for (int i3 = 0; i3 < tab->navigation_size(); i3++) {
+ const sync_pb::TabNavigation* navigation = &tab->navigation(i3);
+ AppendSessionTabNavigation(&session_tab->navigations, navigation);
+ }
+}
+
+void SessionModelAssociator::PopulateSessionWindowFromSpecifics(
+ SessionWindow* session_window, const sync_pb::SessionWindow* window) {
+ SessionID id;
+ session_window->window_id = id;
+ if (window->has_selected_tab_index())
+ session_window->selected_tab_index = window->selected_tab_index();
+ if (window->has_browser_type()) {
+ if (window->browser_type() ==
+ sync_pb::SessionWindow_BrowserType_TYPE_NORMAL) {
+ session_window->type = 1;
+ } else {
+ session_window->type = 2;
+ }
+ }
+ for (int i = 0; i < window->session_tab_size(); i++) {
+ const sync_pb::SessionTab& tab = window->session_tab(i);
+ SessionTab* session_tab = new SessionTab();
+ PopulateSessionTabFromSpecifics(session_tab, &tab, id);
+ session_window->tabs.insert(session_window->tabs.end(), session_tab);
+ }
+}
+
+bool SessionModelAssociator::UpdateSyncModel(
+ sync_pb::SessionSpecifics* session_data,
+ sync_api::WriteTransaction* trans,
+ const sync_api::ReadNode* root) {
+ const std::string id = session_data->session_tag();
+ sync_api::WriteNode write_node(trans);
+ if (!write_node.InitByClientTagLookup(syncable::SESSIONS, id)) {
+ sync_api::WriteNode create_node(trans);
+ if (!create_node.InitUniqueByCreation(syncable::SESSIONS, *root, id)) {
+ LOG(ERROR) << "Could not create node for session " << id;
+ return false;
+ }
+ create_node.SetSessionSpecifics(*session_data);
+ return true;
+ }
+ write_node.SetSessionSpecifics(*session_data);
+ return true;
+}
+
+} // namespace browser_sync
+
« 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