summaryrefslogtreecommitdiffstats
path: root/chrome/browser/sync/notifier
diff options
context:
space:
mode:
authorakalin@chromium.org <akalin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-03-14 07:13:25 +0000
committerakalin@chromium.org <akalin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-03-14 07:13:25 +0000
commite39ebd7e9922231ff8c1412834d2e9dc59ec7ab1 (patch)
treeb8229b0362b5a9df1a210b89095e8b00a413b9e8 /chrome/browser/sync/notifier
parent79e549faf26611d5ac05bc4f7fefd4a71a23fcb2 (diff)
downloadchromium_src-e39ebd7e9922231ff8c1412834d2e9dc59ec7ab1.zip
chromium_src-e39ebd7e9922231ff8c1412834d2e9dc59ec7ab1.tar.gz
chromium_src-e39ebd7e9922231ff8c1412834d2e9dc59ec7ab1.tar.bz2
Refactor sync notifier out of sync api
We now have a clearly defined interface for notifier. Old p2p notifications are still used by tests. Original patch by nileshagrawal@google.com. BUG=75831 TEST= Review URL: http://codereview.chromium.org/6683015 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@78007 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/sync/notifier')
-rw-r--r--chrome/browser/sync/notifier/sync_notifier.h47
-rw-r--r--chrome/browser/sync/notifier/sync_notifier_factory.cc99
-rw-r--r--chrome/browser/sync/notifier/sync_notifier_factory.h25
-rw-r--r--chrome/browser/sync/notifier/sync_notifier_impl.cc195
-rw-r--r--chrome/browser/sync/notifier/sync_notifier_impl.h70
-rw-r--r--chrome/browser/sync/notifier/sync_notifier_observer.h29
6 files changed, 465 insertions, 0 deletions
diff --git a/chrome/browser/sync/notifier/sync_notifier.h b/chrome/browser/sync/notifier/sync_notifier.h
new file mode 100644
index 0000000..da15259
--- /dev/null
+++ b/chrome/browser/sync/notifier/sync_notifier.h
@@ -0,0 +1,47 @@
+// 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.
+//
+// Interface to the sync notifier, which is an object that receives
+// notifications when updates are available for a set of sync types.
+// All the observers are notified when such an event happens.
+
+#ifndef CHROME_BROWSER_SYNC_NOTIFIER_SYNC_NOTIFIER_H_
+#define CHROME_BROWSER_SYNC_NOTIFIER_SYNC_NOTIFIER_H_
+
+#include <string>
+
+#include "chrome/browser/sync/syncable/model_type.h"
+
+namespace sync_notifier {
+class SyncNotifierObserver;
+
+class SyncNotifier {
+ public:
+ SyncNotifier() {}
+ virtual ~SyncNotifier() {}
+
+ virtual void AddObserver(SyncNotifierObserver* observer) = 0;
+ virtual void RemoveObserver(SyncNotifierObserver* observer) = 0;
+
+ // SetState must be called once, before any call to UpdateCredentials.
+ virtual void SetState(const std::string& state) = 0;
+
+ // The observers won't be notified of any notifications until
+ // UpdateCredentials is called at least once. It can be called more than
+ // once.
+ virtual void UpdateCredentials(
+ const std::string& email, const std::string& token) = 0;
+
+ virtual void UpdateEnabledTypes(const syncable::ModelTypeSet& types) = 0;
+
+ // This is here only to support the old p2p notification implementation,
+ // which is still used by sync integration tests.
+ // TODO(akalin): Remove this once we move the integration tests off p2p
+ // notifications.
+ virtual void SendNotification() = 0;
+};
+} // namespace sync_notifier
+
+#endif // CHROME_BROWSER_SYNC_NOTIFIER_SYNC_NOTIFIER_H_
+
diff --git a/chrome/browser/sync/notifier/sync_notifier_factory.cc b/chrome/browser/sync/notifier/sync_notifier_factory.cc
new file mode 100644
index 0000000..9f2886a
--- /dev/null
+++ b/chrome/browser/sync/notifier/sync_notifier_factory.cc
@@ -0,0 +1,99 @@
+// 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.
+
+#include "chrome/browser/sync/notifier/sync_notifier_factory.h"
+
+#include <string>
+
+#include "base/command_line.h"
+#include "base/string_number_conversions.h"
+#include "base/string_util.h"
+#include "chrome/browser/sync/notifier/sync_notifier.h"
+#include "chrome/browser/sync/notifier/sync_notifier_impl.h"
+#include "chrome/common/chrome_switches.h"
+#include "jingle/notifier/base/notifier_options.h"
+#include "jingle/notifier/communicator/const_communicator.h"
+#include "net/base/host_port_pair.h"
+
+namespace sync_notifier {
+namespace {
+
+// TODO(akalin): Figure out whether this should be a method of
+// HostPortPair.
+net::HostPortPair StringToHostPortPair(const std::string& host_port_str,
+ uint16 default_port) {
+ std::string::size_type colon_index = host_port_str.find(':');
+ if (colon_index == std::string::npos) {
+ return net::HostPortPair(host_port_str, default_port);
+ }
+
+ std::string host = host_port_str.substr(0, colon_index);
+ std::string port_str = host_port_str.substr(colon_index + 1);
+ int port = default_port;
+ if (!base::StringToInt(port_str, &port) ||
+ (port <= 0) || (port > kuint16max)) {
+ LOG(WARNING) << "Could not parse valid port from " << port_str
+ << "; using port " << default_port;
+ return net::HostPortPair(host, default_port);
+ }
+
+ return net::HostPortPair(host, port);
+}
+
+SyncNotifier* CreateDefaultSyncNotifier(const CommandLine& command_line) {
+ // Contains options specific to how sync clients send and listen to
+ // jingle notifications.
+ notifier::NotifierOptions notifier_options;
+
+ // Override the notification server host from the command-line, if provided.
+ if (command_line.HasSwitch(switches::kSyncNotificationHost)) {
+ std::string value(command_line.GetSwitchValueASCII(
+ switches::kSyncNotificationHost));
+ if (!value.empty()) {
+ notifier_options.xmpp_host_port =
+ StringToHostPortPair(value, notifier::kDefaultXmppPort);
+ }
+ VLOG(1) << "Using " << notifier_options.xmpp_host_port.ToString()
+ << " for test sync notification server.";
+ }
+
+ notifier_options.try_ssltcp_first =
+ command_line.HasSwitch(switches::kSyncTrySsltcpFirstForXmpp);
+ if (notifier_options.try_ssltcp_first)
+ VLOG(1) << "Trying SSL/TCP port before XMPP port for notifications.";
+
+ notifier_options.invalidate_xmpp_login =
+ command_line.HasSwitch(switches::kSyncInvalidateXmppLogin);
+ if (notifier_options.invalidate_xmpp_login) {
+ VLOG(1) << "Invalidating sync XMPP login.";
+ }
+
+ notifier_options.allow_insecure_connection =
+ command_line.HasSwitch(switches::kSyncAllowInsecureXmppConnection);
+ if (notifier_options.allow_insecure_connection) {
+ VLOG(1) << "Allowing insecure XMPP connections.";
+ }
+
+ if (command_line.HasSwitch(switches::kSyncNotificationMethod)) {
+ const std::string notification_method_str(
+ command_line.GetSwitchValueASCII(switches::kSyncNotificationMethod));
+ notifier_options.notification_method =
+ notifier::StringToNotificationMethod(notification_method_str);
+ }
+
+ return new SyncNotifierImpl(notifier_options);
+}
+} // namespace
+
+SyncNotifierFactory::SyncNotifierFactory() {
+}
+
+SyncNotifierFactory::~SyncNotifierFactory() {
+}
+
+SyncNotifier* SyncNotifierFactory::CreateSyncNotifier(
+ const CommandLine& command_line) {
+ return CreateDefaultSyncNotifier(command_line);
+}
+} // namespace sync_notifier
diff --git a/chrome/browser/sync/notifier/sync_notifier_factory.h b/chrome/browser/sync/notifier/sync_notifier_factory.h
new file mode 100644
index 0000000..a9da82e
--- /dev/null
+++ b/chrome/browser/sync/notifier/sync_notifier_factory.h
@@ -0,0 +1,25 @@
+// 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_NOTIFIER_SYNC_NOTIFIER_FACTORY_H_
+#define CHROME_BROWSER_SYNC_NOTIFIER_SYNC_NOTIFIER_FACTORY_H_
+
+class CommandLine;
+
+namespace sync_notifier {
+class SyncNotifier;
+
+// Class to instantiate various implementations of the SyncNotifier interface.
+class SyncNotifierFactory {
+ public:
+ SyncNotifierFactory();
+ ~SyncNotifierFactory();
+
+ // Creates the appropriate sync notifier. The caller should take ownership
+ // of the object returned and delete it when no longer used.
+ SyncNotifier* CreateSyncNotifier(const CommandLine& command_line);
+};
+} // namespace sync_notifier
+
+#endif // CHROME_BROWSER_SYNC_NOTIFIER_SYNC_NOTIFIER_FACTORY_H_
diff --git a/chrome/browser/sync/notifier/sync_notifier_impl.cc b/chrome/browser/sync/notifier/sync_notifier_impl.cc
new file mode 100644
index 0000000..d8d7ca6
--- /dev/null
+++ b/chrome/browser/sync/notifier/sync_notifier_impl.cc
@@ -0,0 +1,195 @@
+// 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.
+
+#include "chrome/browser/sync/notifier/sync_notifier_impl.h"
+
+#include "chrome/browser/sync/notifier/server_notifier_thread.h"
+#include "chrome/browser/sync/notifier/sync_notifier_observer.h"
+#include "chrome/browser/sync/protocol/service_constants.h"
+#include "chrome/browser/sync/sessions/session_state.h"
+#include "chrome/browser/sync/sync_constants.h"
+#include "chrome/browser/sync/syncable/model_type.h"
+#include "jingle/notifier/listener/mediator_thread_impl.h"
+#include "jingle/notifier/listener/notification_constants.h"
+
+// TODO(akalin): Split this class into two implementations - one for p2p and
+// one for server issued notifications.
+using notifier::TalkMediator;
+using notifier::TalkMediatorImpl;
+namespace sync_notifier {
+
+SyncNotifierImpl::SyncNotifierImpl(
+ const notifier::NotifierOptions& notifier_options)
+ : notifier_options_(notifier_options),
+ server_notifier_thread_(NULL) { }
+
+SyncNotifierImpl::~SyncNotifierImpl() {
+ scoped_ptr<TalkMediator> talk_mediator(talk_mediator_.release());
+
+ // Shutdown the xmpp buzz connection.
+ if (talk_mediator.get()) {
+ VLOG(1) << "P2P: Mediator logout started.";
+ talk_mediator->Logout();
+ VLOG(1) << "P2P: Mediator logout completed.";
+ talk_mediator.reset();
+
+ // |server_notifier_thread_| is owned by |talk_mediator|. We NULL
+ // it out here so as to not have a dangling pointer.
+ server_notifier_thread_= NULL;
+ VLOG(1) << "P2P: Mediator destroyed.";
+ }
+}
+
+void SyncNotifierImpl::AddObserver(SyncNotifierObserver* observer) {
+ observer_list_.AddObserver(observer);
+}
+
+void SyncNotifierImpl::RemoveObserver(SyncNotifierObserver* observer) {
+ observer_list_.RemoveObserver(observer);
+}
+
+void SyncNotifierImpl::OnNotificationStateChange(bool notifications_enabled) {
+ FOR_EACH_OBSERVER(SyncNotifierObserver, observer_list_,
+ OnNotificationStateChange(notifications_enabled));
+
+ // If using p2p notifications, generate a notification for all enabled types.
+ // Used only for tests.
+ if ((notifier_options_.notification_method !=
+ notifier::NOTIFICATION_SERVER) && notifications_enabled) {
+ browser_sync::sessions::TypePayloadMap model_types_with_payloads =
+ browser_sync::sessions::MakeTypePayloadMapFromBitSet(
+ syncable::ModelTypeBitSetFromSet(enabled_types_), std::string());
+ FOR_EACH_OBSERVER(SyncNotifierObserver, observer_list_,
+ OnIncomingNotification(model_types_with_payloads));
+ }
+}
+
+void SyncNotifierImpl::OnIncomingNotification(
+ const IncomingNotificationData& notification_data) {
+ browser_sync::sessions::TypePayloadMap model_types_with_payloads;
+
+ // Check if the service url is a sync URL. An empty service URL is
+ // treated as a legacy sync notification. If we're listening to
+ // server-issued notifications, no need to check the service_url.
+ if (notifier_options_.notification_method ==
+ notifier::NOTIFICATION_SERVER) {
+ VLOG(1) << "Sync received server notification from " <<
+ notification_data.service_url << ": " <<
+ notification_data.service_specific_data;
+ syncable::ModelTypeBitSet model_types;
+ const std::string& model_type_list = notification_data.service_url;
+ const std::string& notification_payload =
+ notification_data.service_specific_data;
+
+ if (!syncable::ModelTypeBitSetFromString(model_type_list, &model_types)) {
+ LOG(DFATAL) << "Could not extract model types from server data.";
+ model_types.set();
+ }
+
+ model_types_with_payloads =
+ browser_sync::sessions::MakeTypePayloadMapFromBitSet(model_types,
+ notification_payload);
+ } else if (notification_data.service_url.empty() ||
+ (notification_data.service_url ==
+ browser_sync::kSyncLegacyServiceUrl) ||
+ (notification_data.service_url ==
+ browser_sync::kSyncServiceUrl)) {
+ VLOG(1) << "Sync received P2P notification.";
+
+ // Catch for sync integration tests (uses p2p). Just set all enabled
+ // datatypes.
+ model_types_with_payloads =
+ browser_sync::sessions::MakeTypePayloadMapFromBitSet(
+ syncable::ModelTypeBitSetFromSet(enabled_types_), std::string());
+ } else {
+ LOG(WARNING) << "Notification fron unexpected source: "
+ << notification_data.service_url;
+ }
+
+ FOR_EACH_OBSERVER(SyncNotifierObserver, observer_list_,
+ OnIncomingNotification(model_types_with_payloads));
+}
+
+void SyncNotifierImpl::WriteState(const std::string& state) {
+ FOR_EACH_OBSERVER(SyncNotifierObserver, observer_list_,
+ StoreState(state));
+}
+
+void SyncNotifierImpl::UpdateCredentials(
+ const std::string& email, const std::string& token) {
+ // Reset talk_mediator_ before creating ServerNotifierThread/MediatorThread,
+ // to avoid any problems with having two of those threads at the same time.
+ talk_mediator_.reset();
+
+ if (notifier_options_.notification_method ==
+ notifier::NOTIFICATION_SERVER) {
+ // |talk_mediator_| takes ownership of |sync_notifier_thread_|
+ // but it is guaranteed that |sync_notifier_thread_| is destroyed only
+ // when |talk_mediator_| is (see the comments in talk_mediator.h).
+ server_notifier_thread_ = new sync_notifier::ServerNotifierThread(
+ notifier_options_, state_, this);
+ talk_mediator_.reset(
+ new TalkMediatorImpl(server_notifier_thread_,
+ notifier_options_.invalidate_xmpp_login,
+ notifier_options_.allow_insecure_connection));
+
+ // Since we may be initialized more than once, make sure that any
+ // newly created server notifier thread has the latest enabled types.
+ server_notifier_thread_->UpdateEnabledTypes(enabled_types_);
+ } else {
+ notifier::MediatorThread* mediator_thread =
+ new notifier::MediatorThreadImpl(notifier_options_);
+ talk_mediator_.reset(
+ new TalkMediatorImpl(mediator_thread,
+ notifier_options_.invalidate_xmpp_login,
+ notifier_options_.allow_insecure_connection));
+ talk_mediator_->AddSubscribedServiceUrl(browser_sync::kSyncServiceUrl);
+ server_notifier_thread_ = NULL;
+ }
+ talk_mediator_->SetDelegate(this);
+ talk_mediator_->SetAuthToken(email, token, SYNC_SERVICE_NAME);
+ talk_mediator_->Login();
+}
+
+void SyncNotifierImpl::SetState(const std::string& state) {
+ state_ = state;
+}
+
+void SyncNotifierImpl::UpdateEnabledTypes(const syncable::ModelTypeSet& types) {
+ enabled_types_ = types;
+ if (server_notifier_thread_ != NULL) {
+ server_notifier_thread_->UpdateEnabledTypes(types);
+ }
+}
+
+void SyncNotifierImpl::SendNotification() {
+ // Do nothing if we are using server based notifications.
+ if (notifier_options_.notification_method ==
+ notifier::NOTIFICATION_SERVER) {
+ return;
+ }
+
+ if (!talk_mediator_.get()) {
+ NOTREACHED() << "Cannot send notification: talk_mediator_ is NULL";
+ return;
+ }
+
+ VLOG(1) << "Sending XMPP notification...";
+ OutgoingNotificationData notification_data;
+ notification_data.service_id = browser_sync::kSyncServiceId;
+ notification_data.service_url = browser_sync::kSyncServiceUrl;
+ notification_data.send_content = true;
+ notification_data.priority = browser_sync::kSyncPriority;
+ notification_data.write_to_cache_only = true;
+ notification_data.service_specific_data =
+ browser_sync::kSyncServiceSpecificData;
+ notification_data.require_subscription = true;
+ bool success = talk_mediator_->SendNotification(notification_data);
+ if (success) {
+ VLOG(1) << "Sent XMPP notification";
+ } else {
+ VLOG(1) << "Could not send XMPP notification";
+ }
+}
+} // namespace sync_notifier
diff --git a/chrome/browser/sync/notifier/sync_notifier_impl.h b/chrome/browser/sync/notifier/sync_notifier_impl.h
new file mode 100644
index 0000000..ccf8d9c
--- /dev/null
+++ b/chrome/browser/sync/notifier/sync_notifier_impl.h
@@ -0,0 +1,70 @@
+// 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.
+//
+// Talk Mediator based implementation of the sync notifier interface.
+// Initializes the talk mediator and registers itself as the delegate.
+
+#ifndef CHROME_BROWSER_SYNC_NOTIFIER_SYNC_NOTIFIER_IMPL_H_
+#define CHROME_BROWSER_SYNC_NOTIFIER_SYNC_NOTIFIER_IMPL_H_
+
+#include <string>
+
+#include "base/observer_list.h"
+#include "chrome/browser/sync/notifier/state_writer.h"
+#include "chrome/browser/sync/notifier/sync_notifier.h"
+#include "chrome/browser/sync/syncable/model_type.h"
+#include "jingle/notifier/base/notifier_options.h"
+#include "jingle/notifier/listener/talk_mediator.h"
+#include "jingle/notifier/listener/talk_mediator_impl.h"
+
+namespace sync_notifier {
+class ServerNotifierThread;
+
+class SyncNotifierImpl
+ : public SyncNotifier,
+ public sync_notifier::StateWriter,
+ public notifier::TalkMediator::Delegate {
+ public:
+ explicit SyncNotifierImpl(const notifier::NotifierOptions& notifier_options);
+
+ virtual ~SyncNotifierImpl();
+
+ // TalkMediator::Delegate implementation.
+ virtual void OnNotificationStateChange(bool notifications_enabled);
+
+ virtual void OnIncomingNotification(
+ const IncomingNotificationData& notification_data);
+
+ virtual void OnOutgoingNotification() {}
+
+ // sync_notifier::StateWriter implementation.
+ virtual void WriteState(const std::string& state);
+
+ // SyncNotifier implementation
+ virtual void UpdateCredentials(
+ const std::string& email, const std::string& token);
+
+ virtual void SetState(const std::string& state);
+
+ virtual void AddObserver(SyncNotifierObserver* observer);
+ virtual void RemoveObserver(SyncNotifierObserver* observer);
+
+ virtual void UpdateEnabledTypes(const syncable::ModelTypeSet& types);
+ virtual void SendNotification();
+ private:
+ // Login to the talk mediator with the given credentials.
+ void TalkMediatorLogin(
+ const std::string& email, const std::string& token);
+
+ // Notification (xmpp) handler.
+ scoped_ptr<notifier::TalkMediator> talk_mediator_;
+ syncable::ModelTypeSet enabled_types_;
+ std::string state_;
+
+ notifier::NotifierOptions notifier_options_;
+ ServerNotifierThread* server_notifier_thread_;
+ ObserverList<SyncNotifierObserver> observer_list_;
+};
+}
+#endif // CHROME_BROWSER_SYNC_NOTIFIER_SYNC_NOTIFIER_IMPL_H_
diff --git a/chrome/browser/sync/notifier/sync_notifier_observer.h b/chrome/browser/sync/notifier/sync_notifier_observer.h
new file mode 100644
index 0000000..2978d17
--- /dev/null
+++ b/chrome/browser/sync/notifier/sync_notifier_observer.h
@@ -0,0 +1,29 @@
+// 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_NOTIFIER_SYNC_NOTIFIER_OBSERVER_H_
+#define CHROME_BROWSER_SYNC_NOTIFIER_SYNC_NOTIFIER_OBSERVER_H_
+
+#include <string>
+
+#include "chrome/browser/sync/sessions/session_state.h"
+
+namespace sync_notifier {
+
+class SyncNotifierObserver {
+ public:
+ SyncNotifierObserver() {}
+ virtual ~SyncNotifierObserver() {}
+
+ virtual void OnIncomingNotification(
+ const browser_sync::sessions::TypePayloadMap& type_payloads) = 0;
+ virtual void OnNotificationStateChange(bool notifications_enabled) = 0;
+
+ // TODO(nileshagrawal): Find a way to hide state handling inside the
+ // sync notifier implementation.
+ virtual void StoreState(const std::string& state) = 0;
+};
+} // namespace sync_notifier
+#endif // CHROME_BROWSER_SYNC_NOTIFIER_SYNC_NOTIFIER_OBSERVER_H_