diff options
author | akalin@chromium.org <akalin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-06-01 21:10:01 +0000 |
---|---|---|
committer | akalin@chromium.org <akalin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-06-01 21:10:01 +0000 |
commit | 9117d0e975e1a752fbea68e3a8741b23cb688807 (patch) | |
tree | c7591c5c04077a19d9a323d843f9a2187703e6fc /chrome/common/net | |
parent | f97d7f638e2c076b4646a09a663b372493009594 (diff) | |
download | chromium_src-9117d0e975e1a752fbea68e3a8741b23cb688807.zip chromium_src-9117d0e975e1a752fbea68e3a8741b23cb688807.tar.gz chromium_src-9117d0e975e1a752fbea68e3a8741b23cb688807.tar.bz2 |
Converted MediatorThread to use a delegate instead of sigslots.
Simplified handling of MediatorThread events and fixed locking.
BUG=none
TEST=unittests + manual testing of notifications
Review URL: http://codereview.chromium.org/2260009
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@48659 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/common/net')
7 files changed, 179 insertions, 195 deletions
diff --git a/chrome/common/net/notifier/listener/mediator_thread.h b/chrome/common/net/notifier/listener/mediator_thread.h index 5c460a0f..f90a199 100644 --- a/chrome/common/net/notifier/listener/mediator_thread.h +++ b/chrome/common/net/notifier/listener/mediator_thread.h @@ -11,25 +11,36 @@ #include <string> #include <vector> -#include "base/logging.h" #include "chrome/common/net/notifier/listener/notification_defines.h" -#include "talk/base/sigslot.h" -#include "talk/xmpp/xmppclientsettings.h" + +namespace buzz { +class XmppClientSettings; +} // namespace buzz namespace notifier { class MediatorThread { public: - enum MediatorMessage { - MSG_LOGGED_IN, - MSG_LOGGED_OUT, - MSG_SUBSCRIPTION_SUCCESS, - MSG_SUBSCRIPTION_FAILURE, - MSG_NOTIFICATION_SENT - }; - virtual ~MediatorThread() {} + class Delegate { + public: + virtual ~Delegate() {} + + virtual void OnConnectionStateChange(bool logged_in) = 0; + + virtual void OnSubscriptionStateChange(bool subscribed) = 0; + + virtual void OnIncomingNotification( + const IncomingNotificationData& notification_data) = 0; + + virtual void OnOutgoingNotification() = 0; + }; + + // |delegate| can be NULL if we're shutting down. + // TODO(akalin): Handle messages during shutdown gracefully so that + // we don't have to deal with NULL delegates. + virtual void SetDelegate(Delegate* delegate) = 0; virtual void Login(const buzz::XmppClientSettings& settings) = 0; virtual void Logout() = 0; virtual void Start() = 0; @@ -37,17 +48,6 @@ class MediatorThread { const std::vector<std::string>& subscribed_services_list) = 0; virtual void ListenForUpdates() = 0; virtual void SendNotification(const OutgoingNotificationData& data) = 0; - - // Connect to this for messages about talk events (except notifications). - sigslot::signal1<MediatorMessage> SignalStateChange; - // Connect to this for notifications - sigslot::signal1<const IncomingNotificationData&> SignalNotificationReceived; - - protected: - MediatorThread() {} - - private: - DISALLOW_COPY_AND_ASSIGN(MediatorThread); }; } // namespace notifier diff --git a/chrome/common/net/notifier/listener/mediator_thread_impl.cc b/chrome/common/net/notifier/listener/mediator_thread_impl.cc index ae834fd..f13dd25 100644 --- a/chrome/common/net/notifier/listener/mediator_thread_impl.cc +++ b/chrome/common/net/notifier/listener/mediator_thread_impl.cc @@ -28,13 +28,18 @@ namespace notifier { MediatorThreadImpl::MediatorThreadImpl( chrome_common_net::NetworkChangeNotifierThread* network_change_notifier_thread) - : network_change_notifier_thread_(network_change_notifier_thread) { + : delegate_(NULL), + network_change_notifier_thread_(network_change_notifier_thread) { DCHECK(network_change_notifier_thread_); } MediatorThreadImpl::~MediatorThreadImpl() { } +void MediatorThreadImpl::SetDelegate(Delegate* delegate) { + delegate_ = delegate; +} + void MediatorThreadImpl::Start() { talk_base::Thread::Start(); } @@ -249,35 +254,45 @@ void MediatorThreadImpl::DoSendNotification( void MediatorThreadImpl::OnUpdateListenerMessage( const IncomingNotificationData& notification_data) { - SignalNotificationReceived(notification_data); + if (delegate_) { + delegate_->OnIncomingNotification(notification_data); + } } void MediatorThreadImpl::OnUpdateNotificationSent(bool success) { - if (success) { - SignalStateChange(MSG_NOTIFICATION_SENT); + if (delegate_ && success) { + delegate_->OnOutgoingNotification(); } } void MediatorThreadImpl::OnLoginFailureMessage( const notifier::LoginFailure& failure) { - SignalStateChange(MSG_LOGGED_OUT); + if (delegate_) { + delegate_->OnConnectionStateChange(false); + } } void MediatorThreadImpl::OnClientStateChangeMessage( LoginConnectionState state) { switch (state) { case STATE_CLOSED: - SignalStateChange(MSG_LOGGED_OUT); + if (delegate_) { + delegate_->OnConnectionStateChange(false); + } break; case STATE_RETRYING: case STATE_OPENING: LOG(INFO) << "P2P: Thread trying to connect."; // Maybe first time logon, maybe intermediate network disruption. Assume // the server went down, and lost our subscription for updates. - SignalStateChange(MSG_SUBSCRIPTION_FAILURE); + if (delegate_) { + delegate_->OnSubscriptionStateChange(false); + } break; case STATE_OPENED: - SignalStateChange(MSG_LOGGED_IN); + if (delegate_) { + delegate_->OnConnectionStateChange(true); + } break; default: LOG(WARNING) << "P2P: Unknown client state change."; @@ -286,10 +301,8 @@ void MediatorThreadImpl::OnClientStateChangeMessage( } void MediatorThreadImpl::OnSubscriptionStateChange(bool success) { - if (success) { - SignalStateChange(MSG_SUBSCRIPTION_SUCCESS); - } else { - SignalStateChange(MSG_SUBSCRIPTION_FAILURE); + if (delegate_) { + delegate_->OnSubscriptionStateChange(success); } } diff --git a/chrome/common/net/notifier/listener/mediator_thread_impl.h b/chrome/common/net/notifier/listener/mediator_thread_impl.h index 962f1a4..0a35051 100644 --- a/chrome/common/net/notifier/listener/mediator_thread_impl.h +++ b/chrome/common/net/notifier/listener/mediator_thread_impl.h @@ -110,6 +110,8 @@ class MediatorThreadImpl network_change_notifier_thread); virtual ~MediatorThreadImpl(); + virtual void SetDelegate(Delegate* delegate); + // Start the thread. virtual void Start(); virtual void Stop(); @@ -150,6 +152,7 @@ class MediatorThreadImpl buzz::XmppClient* xmpp_client(); + Delegate* delegate_; chrome_common_net::NetworkChangeNotifierThread* network_change_notifier_thread_; scoped_ptr<net::NetworkChangeNotifier> network_change_notifier_; diff --git a/chrome/common/net/notifier/listener/mediator_thread_mock.h b/chrome/common/net/notifier/listener/mediator_thread_mock.h index 4df36df..62d739e 100644 --- a/chrome/common/net/notifier/listener/mediator_thread_mock.h +++ b/chrome/common/net/notifier/listener/mediator_thread_mock.h @@ -19,10 +19,11 @@ namespace notifier { class MockMediatorThread : public MediatorThread { public: - MockMediatorThread() : MediatorThread() { + MockMediatorThread() : delegate_(NULL) { Reset(); } - ~MockMediatorThread() {} + + virtual ~MockMediatorThread() {} void Reset() { login_calls = 0; @@ -33,22 +34,35 @@ class MockMediatorThread : public MediatorThread { send_calls = 0; } + virtual void SetDelegate(Delegate* delegate) { + delegate_ = delegate; + } + // Overridden from MediatorThread - void Login(const buzz::XmppClientSettings& settings) { + virtual void Login(const buzz::XmppClientSettings& settings) { login_calls++; + if (delegate_) { + delegate_->OnConnectionStateChange(true); + } } - void Logout() { + virtual void Logout() { logout_calls++; + if (delegate_) { + delegate_->OnConnectionStateChange(false); + } } - void Start() { + virtual void Start() { start_calls++; } virtual void SubscribeForUpdates( const std::vector<std::string>& subscribed_services_list) { subscribe_calls++; + if (delegate_) { + delegate_->OnSubscriptionStateChange(true); + } } virtual void ListenForUpdates() { @@ -57,16 +71,18 @@ class MockMediatorThread : public MediatorThread { virtual void SendNotification(const OutgoingNotificationData &) { send_calls++; + if (delegate_) { + delegate_->OnOutgoingNotification(); + } } - // Callback control - void ChangeState(MediatorThread::MediatorMessage message) { - SignalStateChange(message); - } - void Notify(const IncomingNotificationData& data) { - SignalNotificationReceived(data); + void ReceiveNotification(const IncomingNotificationData& data) { + if (delegate_) { + delegate_->OnIncomingNotification(data); + } } + Delegate* delegate_; // Intneral State int login_calls; int logout_calls; diff --git a/chrome/common/net/notifier/listener/talk_mediator_impl.cc b/chrome/common/net/notifier/listener/talk_mediator_impl.cc index ff5c62c..fbf9da7 100644 --- a/chrome/common/net/notifier/listener/talk_mediator_impl.cc +++ b/chrome/common/net/notifier/listener/talk_mediator_impl.cc @@ -63,12 +63,7 @@ TalkMediatorImpl::TalkMediatorImpl(MediatorThread *thread) void TalkMediatorImpl::TalkMediatorInitialization(bool should_connect) { if (should_connect) { - mediator_thread_->SignalStateChange.connect( - this, - &TalkMediatorImpl::MediatorThreadMessageHandler); - mediator_thread_->SignalNotificationReceived.connect( - this, - &TalkMediatorImpl::MediatorThreadNotificationHandler); + mediator_thread_->SetDelegate(this); state_.connected = 1; } mediator_thread_->Start(); @@ -82,55 +77,63 @@ TalkMediatorImpl::~TalkMediatorImpl() { } bool TalkMediatorImpl::Login() { - AutoLock lock(mutex_); - // Connect to the mediator thread and start processing messages. - if (!state_.connected) { - mediator_thread_->SignalStateChange.connect( - this, - &TalkMediatorImpl::MediatorThreadMessageHandler); - mediator_thread_->SignalNotificationReceived.connect( - this, - &TalkMediatorImpl::MediatorThreadNotificationHandler); - state_.connected = 1; + bool should_log_in = false; + buzz::XmppClientSettings xmpp_settings; + { + AutoLock lock(mutex_); + // Connect to the mediator thread and start processing messages. + if (!state_.connected) { + mediator_thread_->SetDelegate(this); + state_.connected = 1; + } + should_log_in = + state_.initialized && !state_.logging_in && !state_.logged_in; + state_.logging_in = should_log_in; + xmpp_settings = xmpp_settings_; } - if (state_.initialized && !state_.logging_in) { - mediator_thread_->Login(xmpp_settings_); - state_.logging_in = 1; - return true; + if (should_log_in) { + mediator_thread_->Login(xmpp_settings); } - return false; + return should_log_in; } bool TalkMediatorImpl::Logout() { - AutoLock lock(mutex_); - // We do not want to be called back during logout since we may be closing. - if (state_.connected) { - mediator_thread_->SignalStateChange.disconnect(this); - mediator_thread_->SignalNotificationReceived.disconnect(this); - state_.connected = 0; - } - if (state_.started) { + bool logging_out = false; + { + AutoLock lock(mutex_); + if (state_.connected) { + state_.connected = 0; + } + logging_out = state_.started; + if (logging_out) { + state_.started = 0; + state_.logging_in = 0; + state_.logged_in = 0; + state_.subscribed = 0; + } + } + if (logging_out) { + // We do not want to be called back during logout since we may be + // closing. + mediator_thread_->SetDelegate(NULL); mediator_thread_->Logout(); - state_.started = 0; - state_.logging_in = 0; - state_.logged_in = 0; - state_.subscribed = 0; - return true; } - return false; + return logging_out; } bool TalkMediatorImpl::SendNotification(const OutgoingNotificationData& data) { - AutoLock lock(mutex_); - if (state_.logged_in && state_.subscribed) { + bool can_send_notification = false; + { + AutoLock lock(mutex_); + can_send_notification = state_.logged_in && state_.subscribed; + } + if (can_send_notification) { mediator_thread_->SendNotification(data); - return true; } - return false; + return can_send_notification; } -void TalkMediatorImpl::SetDelegate(Delegate* delegate) { - AutoLock lock(mutex_); +void TalkMediatorImpl::SetDelegate(TalkMediator::Delegate* delegate) { delegate_ = delegate; } @@ -160,98 +163,60 @@ bool TalkMediatorImpl::SetAuthToken(const std::string& email, void TalkMediatorImpl::AddSubscribedServiceUrl( const std::string& service_url) { - subscribed_services_list_.push_back(service_url); - if (state_.logged_in) { + bool logged_in = false; + { + AutoLock lock(mutex_); + subscribed_services_list_.push_back(service_url); + logged_in = state_.logged_in; + } + if (logged_in) { LOG(INFO) << "Resubscribing for updates, a new service got added"; mediator_thread_->SubscribeForUpdates(subscribed_services_list_); } } -void TalkMediatorImpl::MediatorThreadMessageHandler( - MediatorThread::MediatorMessage message) { - LOG(INFO) << "P2P: MediatorThread has passed a message"; - switch (message) { - case MediatorThread::MSG_LOGGED_IN: - OnLogin(); - break; - case MediatorThread::MSG_LOGGED_OUT: - OnLogout(); - break; - case MediatorThread::MSG_SUBSCRIPTION_SUCCESS: - OnSubscriptionSuccess(); - break; - case MediatorThread::MSG_SUBSCRIPTION_FAILURE: - OnSubscriptionFailure(); - break; - case MediatorThread::MSG_NOTIFICATION_SENT: - OnNotificationSent(); - break; - default: - LOG(WARNING) << "P2P: Unknown message returned from mediator thread."; - break; - } -} - -void TalkMediatorImpl::MediatorThreadNotificationHandler( - const IncomingNotificationData& notification_data) { - LOG(INFO) << "P2P: Updates are available on the server."; - AutoLock lock(mutex_); - if (delegate_) { - delegate_->OnIncomingNotification(notification_data); +void TalkMediatorImpl::OnConnectionStateChange(bool logged_in) { + { + AutoLock lock(mutex_); + state_.logging_in = 0; + state_.logged_in = logged_in; + } + if (logged_in) { + LOG(INFO) << "P2P: Logged in."; + // ListenForUpdates enables the ListenTask. This is done before + // SubscribeForUpdates. + mediator_thread_->ListenForUpdates(); + // Now subscribe for updates to all the services we are interested in + mediator_thread_->SubscribeForUpdates(subscribed_services_list_); + } else { + LOG(INFO) << "P2P: Logged off."; + OnSubscriptionStateChange(false); } } - -void TalkMediatorImpl::OnLogin() { - LOG(INFO) << "P2P: Logged in."; - AutoLock lock(mutex_); - state_.logging_in = 0; - state_.logged_in = 1; - // ListenForUpdates enables the ListenTask. This is done before - // SubscribeForUpdates. - mediator_thread_->ListenForUpdates(); - // Now subscribe for updates to all the services we are interested in - mediator_thread_->SubscribeForUpdates(subscribed_services_list_); -} - -void TalkMediatorImpl::OnLogout() { - LOG(INFO) << "P2P: Logged off."; - OnSubscriptionFailure(); - AutoLock lock(mutex_); - state_.logging_in = 0; - state_.logged_in = 0; -} - -void TalkMediatorImpl::OnSubscriptionSuccess() { - LOG(INFO) << "P2P: Update subscription active."; +void TalkMediatorImpl::OnSubscriptionStateChange(bool subscribed) { { AutoLock lock(mutex_); - state_.subscribed = 1; + state_.subscribed = subscribed; } - // The above scope exists so that we can release the lock before - // notifying listeners. In theory we should do this for all methods. - // Notifying listeners with a lock held can cause the lock to be - // recursively taken if the listener decides to call back into us - // in the event handler. + LOG(INFO) << "P2P: " << (subscribed ? "subscribed" : "unsubscribed"); if (delegate_) { - delegate_->OnNotificationStateChange(true); + delegate_->OnNotificationStateChange(subscribed); } } -void TalkMediatorImpl::OnSubscriptionFailure() { - LOG(INFO) << "P2P: Update subscription failure."; - AutoLock lock(mutex_); - state_.subscribed = 0; +void TalkMediatorImpl::OnIncomingNotification( + const IncomingNotificationData& notification_data) { + LOG(INFO) << "P2P: Updates are available on the server."; if (delegate_) { - delegate_->OnNotificationStateChange(false); + delegate_->OnIncomingNotification(notification_data); } } -void TalkMediatorImpl::OnNotificationSent() { +void TalkMediatorImpl::OnOutgoingNotification() { LOG(INFO) << "P2P: Peers were notified that updates are available on the server."; - AutoLock lock(mutex_); if (delegate_) { delegate_->OnOutgoingNotification(); } diff --git a/chrome/common/net/notifier/listener/talk_mediator_impl.h b/chrome/common/net/notifier/listener/talk_mediator_impl.h index de28fc5..4ff4681 100644 --- a/chrome/common/net/notifier/listener/talk_mediator_impl.h +++ b/chrome/common/net/notifier/listener/talk_mediator_impl.h @@ -27,8 +27,7 @@ class NetworkChangeNotifierThread; namespace notifier { class TalkMediatorImpl - : public TalkMediator, - public sigslot::has_slots<> { + : public TalkMediator, public MediatorThread::Delegate { public: TalkMediatorImpl( chrome_common_net::NetworkChangeNotifierThread* @@ -37,9 +36,9 @@ class TalkMediatorImpl explicit TalkMediatorImpl(MediatorThread* thread); virtual ~TalkMediatorImpl(); - // Overriden from TalkMediator. + // TalkMediator implementation. - virtual void SetDelegate(Delegate* delegate); + virtual void SetDelegate(TalkMediator::Delegate* delegate); virtual bool SetAuthToken(const std::string& email, const std::string& token, @@ -51,6 +50,17 @@ class TalkMediatorImpl virtual void AddSubscribedServiceUrl(const std::string& service_url); + // MediatorThread::Delegate implementation. + + virtual void OnConnectionStateChange(bool logged_in); + + virtual void OnSubscriptionStateChange(bool subscribed); + + virtual void OnIncomingNotification( + const IncomingNotificationData& notification_data); + + virtual void OnOutgoingNotification(); + private: struct TalkMediatorState { TalkMediatorState() @@ -72,26 +82,14 @@ class TalkMediatorImpl // mediator thread's SignalStateChange object. void TalkMediatorInitialization(bool should_connect); - // Callbacks for the mediator thread. - void MediatorThreadMessageHandler(MediatorThread::MediatorMessage message); - void MediatorThreadNotificationHandler( - const IncomingNotificationData& notification_data); - - // Responses to messages from the MediatorThread. - void OnNotificationSent(); - void OnLogin(); - void OnLogout(); - void OnSubscriptionFailure(); - void OnSubscriptionSuccess(); - - // Mutex for synchronizing event access. This class listens to events - // from MediatorThread. It can also be called by through the - // TalkMediatorInteface. All these access points are serialized by - // this mutex. + // Protects state_, xmpp_settings_, and subscribed_services_list_. + // + // TODO(akalin): Remove this once we use this class from one thread + // only. Lock mutex_; - // Delegate. May be NULL. - Delegate* delegate_; + // Delegate, which we don't own. May be NULL. + TalkMediator::Delegate* delegate_; // Internal state. TalkMediatorState state_; @@ -102,7 +100,7 @@ class TalkMediatorImpl // The worker thread through which talk events are posted and received. scoped_ptr<MediatorThread> mediator_thread_; - bool invalidate_xmpp_auth_token_; + const bool invalidate_xmpp_auth_token_; std::vector<std::string> subscribed_services_list_; diff --git a/chrome/common/net/notifier/listener/talk_mediator_unittest.cc b/chrome/common/net/notifier/listener/talk_mediator_unittest.cc index 621e688..1a8b0b4 100644 --- a/chrome/common/net/notifier/listener/talk_mediator_unittest.cc +++ b/chrome/common/net/notifier/listener/talk_mediator_unittest.cc @@ -128,15 +128,10 @@ TEST_F(TalkMediatorImplTest, SendNotification) { EXPECT_TRUE(talk1->SetAuthToken("chromium@gmail.com", "token", "fake_service")); EXPECT_TRUE(talk1->Login()); - talk1->OnLogin(); + talk1->OnConnectionStateChange(true); EXPECT_EQ(1, mock->login_calls); - // Failure due to not being subscribed. - EXPECT_FALSE(talk1->SendNotification(data)); - EXPECT_EQ(0, mock->send_calls); - - // Fake subscription - talk1->OnSubscriptionSuccess(); + // Should be subscribed now. EXPECT_TRUE(talk1->state_.subscribed); EXPECT_TRUE(talk1->SendNotification(data)); EXPECT_EQ(1, mock->send_calls); @@ -168,30 +163,24 @@ TEST_F(TalkMediatorImplTest, MediatorThreadCallbacks) { EXPECT_TRUE(talk1->Login()); EXPECT_EQ(1, mock->login_calls); - mock->ChangeState(MediatorThread::MSG_LOGGED_IN); - // The message triggers calls to listen and subscribe. EXPECT_EQ(1, mock->listen_calls); EXPECT_EQ(1, mock->subscribe_calls); - EXPECT_FALSE(talk1->state_.subscribed); - - mock->ChangeState(MediatorThread::MSG_SUBSCRIPTION_SUCCESS); EXPECT_TRUE(talk1->state_.subscribed); // After subscription success is receieved, the talk mediator will allow // sending of notifications. OutgoingNotificationData outgoing_data; EXPECT_TRUE(talk1->SendNotification(outgoing_data)); - // TODO(akalin): Fix locking issues issues and move this into - // MediatorThreadMock. - mock->ChangeState(MediatorThread::MSG_NOTIFICATION_SENT); EXPECT_EQ(1, mock->send_calls); IncomingNotificationData incoming_data; incoming_data.service_url = "service_url"; incoming_data.service_specific_data = "service_data"; - mock->Notify(incoming_data); + mock->ReceiveNotification(incoming_data); + // Shouldn't trigger a call to the delegate since we disconnect + // it before we logout. talk1.reset(); EXPECT_EQ(1, mock->logout_calls); } |