From 29e4e51e21b8902c82456cc85af46fa5f5889f04 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Remko=20Tron=C3=A7on?= <git@el-tramo.be>
Date: Sun, 10 Oct 2010 15:31:39 +0200
Subject: Refactor responders to only start on start().


diff --git a/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoBot5.cpp b/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoBot5.cpp
index b0a76fd..98a63d6 100644
--- a/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoBot5.cpp
+++ b/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoBot5.cpp
@@ -27,12 +27,14 @@ class EchoBot {
 			//...
 			softwareVersionResponder = new SoftwareVersionResponder(
 					"EchoBot", "1.0", client->getIQRouter());
+			softwareVersionResponder->start();
 			//...
 			client->connect();
 			//...
 		}
 
 		~EchoBot() {
+			softwareVersionResponder->stop();
 			delete softwareVersionResponder;
 			//...
 			delete tracer;
diff --git a/Documentation/SwiftenDevelopersGuide/Swiften Developers Guide.xml b/Documentation/SwiftenDevelopersGuide/Swiften Developers Guide.xml
index 1df3781..ab1b796 100644
--- a/Documentation/SwiftenDevelopersGuide/Swiften Developers Guide.xml	
+++ b/Documentation/SwiftenDevelopersGuide/Swiften Developers Guide.xml	
@@ -254,8 +254,9 @@
       <para>
         Using <literal>SoftwareVersionResponder</literal> is pretty 
         straightforward, as can be seen in <xref linkend="Example-EchoBot5"/>: 
-        simply construct the responder with the correct
-        parameters, and it will automatically respond to the incoming 
+        simply construct the responder, set the correct
+        parameters, call <literal>start()</literal>, and it will automatically respond to 
+        the incoming 
         requests. Other <literal>Responder</literal> classes may provide
         signals to notify of incoming requests, or may have some other
         behavior. For a detailed explanation of responders, see 
diff --git a/Swift/Controllers/MainController.cpp b/Swift/Controllers/MainController.cpp
index 41c5581..48cceca 100644
--- a/Swift/Controllers/MainController.cpp
+++ b/Swift/Controllers/MainController.cpp
@@ -196,10 +196,16 @@ void MainController::resetClient() {
 	serverDiscoInfo_ = boost::shared_ptr<DiscoInfo>();
 	delete mucSearchController_;
 	mucSearchController_ = NULL;
-	delete discoResponder_;
-	discoResponder_ = NULL;
-	delete clientVersionResponder_;
-	clientVersionResponder_ = NULL;
+	if (discoResponder_) {
+		discoResponder_->stop();
+		delete discoResponder_;
+		discoResponder_ = NULL;
+	}
+	if (clientVersionResponder_) {
+		clientVersionResponder_->stop();
+		delete clientVersionResponder_;
+		clientVersionResponder_ = NULL;
+	}
 	delete eventWindowController_;
 	eventWindowController_ = NULL;
 	delete xmppRosterController_;
@@ -288,6 +294,7 @@ void MainController::handleConnected() {
 		eventWindowController_ = new EventWindowController(eventController_, eventWindowFactory_);
 
 		clientVersionResponder_ = new SoftwareVersionResponder(CLIENT_NAME, buildVersion, client_->getIQRouter());
+		clientVersionResponder_->start();
 		loginWindow_->morphInto(rosterController_->getWindow());
 
 		DiscoInfo discoInfo;
@@ -299,6 +306,7 @@ void MainController::handleConnected() {
 		discoResponder_ = new DiscoInfoResponder(client_->getIQRouter());
 		discoResponder_->setDiscoInfo(discoInfo);
 		discoResponder_->setDiscoInfo(capsInfo_->getNode() + "#" + capsInfo_->getVersion(), discoInfo);
+		discoResponder_->start();
 		serverDiscoInfo_ = boost::shared_ptr<DiscoInfo>(new DiscoInfo());
 
 		mucSearchController_ = new MUCSearchController(jid_, uiEventStream_, mucSearchWindowFactory_, client_->getIQRouter());
diff --git a/Swiften/Queries/Responder.h b/Swiften/Queries/Responder.h
index b38c3c4..2333b5f 100644
--- a/Swiften/Queries/Responder.h
+++ b/Swiften/Queries/Responder.h
@@ -4,33 +4,78 @@
  * See Documentation/Licenses/GPLv3.txt for more information.
  */
 
-#ifndef SWIFTEN_Responder_H
-#define SWIFTEN_Responder_H
+#pragma once
 
 #include "Swiften/Queries/IQHandler.h"
 #include "Swiften/Queries/IQRouter.h"
 #include "Swiften/Elements/ErrorPayload.h"
 
 namespace Swift {
+	/**
+	 * A class for handling incoming IQ Get and Set requests of a specific payload type.
+	 *
+	 * Concrete subclasses of this class need to implement handleGetRequest() and handleSetRequest() to
+	 * implement the behavior of the responder.
+	 *
+	 * \tparam PAYLOAD_TYPE The type of payload this Responder handles. Only IQ requests containing this
+	 *	payload type will be passed to handleGetRequest() and handleSetRequest()
+	 */
 	template<typename PAYLOAD_TYPE>
 	class Responder : public IQHandler {
 		public:
 			Responder(IQRouter* router) : router_(router) {
-				router_->addHandler(this);
 			}
 
 			~Responder() {
+			}
+
+			/**
+			 * Starts the responder.
+			 *
+			 * After the responder has started, it will start receiving and responding to requests.
+			 *
+			 * \see stop()
+			 */
+			void start() {
+				router_->addHandler(this);
+			}
+
+			/**
+			 * Stops the responder.
+			 *
+			 * When the responder is stopped, it will no longer receive incoming requests.
+			 *
+			 * \see start()
+			 */
+			void stop() {
 				router_->removeHandler(this);
 			}
 
 		protected:
+			/**
+			 * Handle an incoming IQ-Get request containing a payload of class PAYLOAD_TYPE.
+			 *
+			 * This method is implemented in the concrete subclasses.
+			 */
 			virtual bool handleGetRequest(const JID& from, const String& id, boost::shared_ptr<PAYLOAD_TYPE> payload) = 0;
+
+			/**
+			 * Handle an incoming IQ-Set request containing a payload of class PAYLOAD_TYPE.
+			 *
+			 * This method is implemented in the concrete subclasses.
+			 */
 			virtual bool handleSetRequest(const JID& from, const String& id, boost::shared_ptr<PAYLOAD_TYPE> payload) = 0;
 
-			void sendResponse(const JID& to, const String& id, boost::shared_ptr<Payload> payload) {
+			/**
+			 * Convenience function for sending an IQ response.
+			 */
+			void sendResponse(const JID& to, const String& id, boost::shared_ptr<PAYLOAD_TYPE> payload) {
 				router_->sendIQ(IQ::createResult(to, id, payload));
 			}
 
+			/**
+			 * Convenience function for responding with an error.
+			 */
 			void sendError(const JID& to, const String& id, ErrorPayload::Condition condition, ErrorPayload::Type type) {
 				router_->sendIQ(IQ::createError(to, id, condition, type));
 			}
@@ -60,5 +105,3 @@ namespace Swift {
 			IQRouter* router_;
 	};
 }
-
-#endif
diff --git a/Swiften/Queries/Responders/RosterPushResponder.h b/Swiften/Queries/Responders/RosterPushResponder.h
index 8c57fd3..48111a7 100644
--- a/Swiften/Queries/Responders/RosterPushResponder.h
+++ b/Swiften/Queries/Responders/RosterPushResponder.h
@@ -22,7 +22,7 @@ namespace Swift {
 		private:
 			virtual bool handleSetRequest(const JID& from, const String& id, boost::shared_ptr<RosterPayload> payload) {
 				onRosterReceived(payload);
-				sendResponse(from, id, boost::shared_ptr<Payload>());
+				sendResponse(from, id, boost::shared_ptr<RosterPayload>());
 				return true;
 			}
 	};
diff --git a/Swiften/Queries/Responders/UnitTest/DiscoInfoResponderTest.cpp b/Swiften/Queries/Responders/UnitTest/DiscoInfoResponderTest.cpp
index 62d9aca..20fa9ff 100644
--- a/Swiften/Queries/Responders/UnitTest/DiscoInfoResponderTest.cpp
+++ b/Swiften/Queries/Responders/UnitTest/DiscoInfoResponderTest.cpp
@@ -35,7 +35,8 @@ class DiscoInfoResponderTest : public CppUnit::TestFixture {
 		}
 
 		void testHandleRequest_GetToplevelInfo() {
-			DiscoInfoResponder testling(router_); 
+			DiscoInfoResponder testling(router_);
+			testling.start();
 			DiscoInfo discoInfo;
 			discoInfo.addFeature("foo");
 			testling.setDiscoInfo(discoInfo);
@@ -48,10 +49,13 @@ class DiscoInfoResponderTest : public CppUnit::TestFixture {
 			CPPUNIT_ASSERT(payload);
 			CPPUNIT_ASSERT_EQUAL(String(""), payload->getNode());
 			CPPUNIT_ASSERT(payload->hasFeature("foo"));
+
+			testling.stop();
 		}
 
 		void testHandleRequest_GetNodeInfo() {
 			DiscoInfoResponder testling(router_); 
+			testling.start();
 			DiscoInfo discoInfo;
 			discoInfo.addFeature("foo");
 			testling.setDiscoInfo(discoInfo);
@@ -68,6 +72,8 @@ class DiscoInfoResponderTest : public CppUnit::TestFixture {
 			CPPUNIT_ASSERT(payload);
 			CPPUNIT_ASSERT_EQUAL(String("bar-node"), payload->getNode());
 			CPPUNIT_ASSERT(payload->hasFeature("bar"));
+
+			testling.stop();
 		}
 
 		void testHandleRequest_GetInvalidNodeInfo() {
diff --git a/Swiften/Queries/UnitTest/ResponderTest.cpp b/Swiften/Queries/UnitTest/ResponderTest.cpp
index 513c6ac..9824c98 100644
--- a/Swiften/Queries/UnitTest/ResponderTest.cpp
+++ b/Swiften/Queries/UnitTest/ResponderTest.cpp
@@ -20,6 +20,8 @@ class ResponderTest : public CppUnit::TestFixture
 {
 		CPPUNIT_TEST_SUITE(ResponderTest);
 		CPPUNIT_TEST(testConstructor);
+		CPPUNIT_TEST(testStart);
+		CPPUNIT_TEST(testStop);
 		CPPUNIT_TEST(testHandleIQ_Set);
 		CPPUNIT_TEST(testHandleIQ_Get);
 		CPPUNIT_TEST(testHandleIQ_Error);
@@ -46,9 +48,28 @@ class ResponderTest : public CppUnit::TestFixture
 
 			channel_->onIQReceived(createRequest(IQ::Set));
 
+			CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(testling.setPayloads_.size()));
+		}
+
+		void testStart() {
+			MyResponder testling(router_);
+
+			testling.start();
+			channel_->onIQReceived(createRequest(IQ::Set));
+
 			CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(testling.setPayloads_.size()));
 		}
 
+		void testStop() {
+			MyResponder testling(router_);
+
+			testling.start();
+			testling.stop();
+			channel_->onIQReceived(createRequest(IQ::Set));
+
+			CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(testling.setPayloads_.size()));
+		}
+
 		void testHandleIQ_Set() {
 			MyResponder testling(router_);
 
diff --git a/Swiften/Roster/XMPPRosterController.cpp b/Swiften/Roster/XMPPRosterController.cpp
index 7743ec8..feaa7d4 100644
--- a/Swiften/Roster/XMPPRosterController.cpp
+++ b/Swiften/Roster/XMPPRosterController.cpp
@@ -25,6 +25,11 @@ namespace Swift {
  */
 XMPPRosterController::XMPPRosterController(IQRouter* iqRouter, XMPPRoster* xmppRoster) : iqRouter_(iqRouter), rosterPushResponder_(iqRouter), xmppRoster_(xmppRoster) {
 	rosterPushResponder_.onRosterReceived.connect(boost::bind(&XMPPRosterController::handleRosterReceived, this, _1));
+	rosterPushResponder_.start();
+}
+
+XMPPRosterController::~XMPPRosterController() {
+	rosterPushResponder_.stop();
 }
 
 void XMPPRosterController::requestRoster() {
diff --git a/Swiften/Roster/XMPPRosterController.h b/Swiften/Roster/XMPPRosterController.h
index 3ef7795..22a63ad 100644
--- a/Swiften/Roster/XMPPRosterController.h
+++ b/Swiften/Roster/XMPPRosterController.h
@@ -22,6 +22,7 @@ namespace Swift {
 	class XMPPRosterController {
 		public:
 			XMPPRosterController(IQRouter *iqRouter, XMPPRoster* xmppRoster);
+			~XMPPRosterController();
 
 			void requestRoster();
 
-- 
cgit v0.10.2-6-g49f6