diff options
author | Remko Tronçon <git@el-tramo.be> | 2010-12-04 12:43:57 (GMT) |
---|---|---|
committer | Remko Tronçon <git@el-tramo.be> | 2010-12-04 13:24:48 (GMT) |
commit | bbf8a5fcb47d649bdcee1b2122eaa76f2c914ef7 (patch) | |
tree | 3cef6ffab06f263ad6f5dc3df5d7ba065223f84e /Documentation/SwiftenDevelopersGuide | |
parent | ebd2b8b8a2f1ad2812543c5350c0acf0a5b8c188 (diff) | |
download | swift-contrib-bbf8a5fcb47d649bdcee1b2122eaa76f2c914ef7.zip swift-contrib-bbf8a5fcb47d649bdcee1b2122eaa76f2c914ef7.tar.bz2 |
Added EchoPayload parserialement.
Diffstat (limited to 'Documentation/SwiftenDevelopersGuide')
14 files changed, 296 insertions, 10 deletions
diff --git a/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/.gitignore b/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/.gitignore index 81f2be3..91c939b 100644 --- a/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/.gitignore +++ b/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/.gitignore @@ -1,3 +1,4 @@ EchoBot? *.cpp.xml +*.h.xml EchoComponent diff --git a/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoBot1.cpp b/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoBot1.cpp index e545801..f5268ef 100644 --- a/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoBot1.cpp +++ b/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoBot1.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Swiften.h" +#include <Swiften/Swiften.h> using namespace Swift; diff --git a/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoBot2.cpp b/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoBot2.cpp index 810307c..99efdf9 100644 --- a/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoBot2.cpp +++ b/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoBot2.cpp @@ -7,7 +7,7 @@ #include <iostream> #include <boost/bind.hpp> -#include "Swiften/Swiften.h" +#include <Swiften/Swiften.h> using namespace Swift; using namespace boost; diff --git a/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoBot3.cpp b/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoBot3.cpp index bca00af..3404c2a 100644 --- a/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoBot3.cpp +++ b/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoBot3.cpp @@ -7,7 +7,7 @@ #include <iostream> #include <boost/bind.hpp> -#include "Swiften/Swiften.h" +#include <Swiften/Swiften.h> using namespace Swift; using namespace boost; diff --git a/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoBot4.cpp b/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoBot4.cpp index 9b2277b..0309768 100644 --- a/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoBot4.cpp +++ b/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoBot4.cpp @@ -8,7 +8,7 @@ #include <iostream> #include <boost/bind.hpp> -#include "Swiften/Swiften.h" +#include <Swiften/Swiften.h> using namespace Swift; using namespace boost; diff --git a/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoBot5.cpp b/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoBot5.cpp index 47cbe1f..4c09e1b 100644 --- a/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoBot5.cpp +++ b/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoBot5.cpp @@ -8,7 +8,7 @@ #include <iostream> #include <boost/bind.hpp> -#include "Swiften/Swiften.h" +#include <Swiften/Swiften.h> using namespace Swift; using namespace boost; diff --git a/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoBot6.cpp b/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoBot6.cpp new file mode 100644 index 0000000..4c96f6b --- /dev/null +++ b/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoBot6.cpp @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +//... +#include <iostream> +#include <boost/bind.hpp> + +#include <Swiften/Swiften.h> + +using namespace Swift; +using namespace boost; +//... +#include "EchoPayload.h" +#include "EchoPayloadParserFactory.h" +#include "EchoPayloadSerializer.h" + +class EchoBot { + public: + EchoBot(EventLoop* eventLoop, NetworkFactories* networkFactories) { + //... + client = new Client(eventLoop, networkFactories, JID("echobot@wonderland.lit"), "mypass"); + client->onConnected.connect(bind(&EchoBot::handleConnected, this)); + client->onMessageReceived.connect( + bind(&EchoBot::handleMessageReceived, this, _1)); + client->onPresenceReceived.connect( + bind(&EchoBot::handlePresenceReceived, this, _1)); + tracer = new ClientXMLTracer(client); + + softwareVersionResponder = new SoftwareVersionResponder(client->getIQRouter()); + softwareVersionResponder->setVersion("EchoBot", "1.0"); + softwareVersionResponder->start(); + //... + client->addPayloadParserFactory(&echoPayloadParserFactory); + client->addPayloadSerializer(&echoPayloadSerializer); + //... + client->connect(); + //... + } + + ~EchoBot() { + client->removePayloadSerializer(&echoPayloadSerializer); + client->removePayloadParserFactory(&echoPayloadParserFactory); + //... + softwareVersionResponder->stop(); + delete softwareVersionResponder; + delete tracer; + delete client; + //... + } + //... + + private: + void handlePresenceReceived(Presence::ref presence) { + // Automatically approve subscription requests + if (presence->getType() == Presence::Subscribe) { + Presence::ref response = Presence::create(); + response->setTo(presence->getFrom()); + response->setType(Presence::Subscribed); + client->sendPresence(response); + } + } + + void handleConnected() { + // Request the roster + GetRosterRequest::ref rosterRequest = + GetRosterRequest::create(client->getIQRouter()); + rosterRequest->onResponse.connect( + bind(&EchoBot::handleRosterReceived, this, _2)); + rosterRequest->send(); + } + + void handleRosterReceived(ErrorPayload::ref error) { + if (error) { + std::cerr << "Error receiving roster. Continuing anyway."; + } + // Send initial available presence + client->sendPresence(Presence::create("Send me a message")); + } + + //... + void handleMessageReceived(Message::ref message) { + //... + // Echo back the incoming message + message->setTo(message->getFrom()); + message->setFrom(JID()); + //... + if (!message->getPayload<EchoPayload>()) { + boost::shared_ptr<EchoPayload> echoPayload(new EchoPayload()); + echoPayload->setMessage("This is an echoed message"); + message->addPayload(echoPayload); + client->sendMessage(message); + } + } + //... + + //... + private: + //... + Client* client; + ClientXMLTracer* tracer; + SoftwareVersionResponder* softwareVersionResponder; + //... + EchoPayloadParserFactory echoPayloadParserFactory; + EchoPayloadSerializer echoPayloadSerializer; +}; +//... + +int main(int, char**) { + SimpleEventLoop eventLoop; + BoostNetworkFactories networkFactories(&eventLoop); + + EchoBot bot(&eventLoop, &networkFactories); + + eventLoop.run(); + return 0; +} +//... diff --git a/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoComponent.cpp b/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoComponent.cpp index 0a856f9..a4155be 100644 --- a/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoComponent.cpp +++ b/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoComponent.cpp @@ -7,7 +7,7 @@ #include <iostream> #include <boost/bind.hpp> -#include "Swiften/Swiften.h" +#include <Swiften/Swiften.h> using namespace Swift; using namespace boost; diff --git a/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoPayload.h b/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoPayload.h new file mode 100644 index 0000000..1354ebf --- /dev/null +++ b/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoPayload.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ +//... +#pragma once + +#include <Swiften/Swiften.h> + +using namespace Swift; +//... +class EchoPayload : public Payload { + public: + EchoPayload() {} + + const String& getMessage() const { + return message; + } + + void setMessage(const String& message) { + this->message = message; + } + + private: + String message; +}; diff --git a/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoPayloadParserFactory.h b/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoPayloadParserFactory.h new file mode 100644 index 0000000..3af616c --- /dev/null +++ b/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoPayloadParserFactory.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Swiften.h> +#include "EchoPayload.h" + +using namespace Swift; + +class EchoPayloadParser : public GenericPayloadParser<EchoPayload> { + public: + EchoPayloadParser() : currentDepth(0) {} + + void handleStartElement( + const String& /* element */, const String& /* ns */, const AttributeMap&) { + currentDepth++; + } + + void handleEndElement(const String& /* element */, const String& /* ns */) { + currentDepth--; + if (currentDepth == 0) { + getPayloadInternal()->setMessage(currentText); + } + } + + void handleCharacterData(const String& data) { + currentText += data; + } + + private: + int currentDepth; + String currentText; +}; + +class EchoPayloadParserFactory : public GenericPayloadParserFactory<EchoPayloadParser> { + public: + EchoPayloadParserFactory() : + GenericPayloadParserFactory<EchoPayloadParser>("echo", "http://swift.im/echo") {} +}; diff --git a/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoPayloadSerializer.h b/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoPayloadSerializer.h new file mode 100644 index 0000000..1b18be4 --- /dev/null +++ b/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoPayloadSerializer.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Swiften.h> +#include "EchoPayload.h" + +using namespace Swift; + +class EchoPayloadSerializer : public GenericPayloadSerializer<EchoPayload> { + public: + String serializePayload(boost::shared_ptr<EchoPayload> payload) const { + XMLElement element("echo", "http://swift.im/protocol/echo"); + element.addNode(XMLTextNode::ref(new XMLTextNode(payload->getMessage()))); + return element.serialize(); + } +}; diff --git a/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/SConscript b/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/SConscript index 2ccfb7e..1e410cf 100644 --- a/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/SConscript +++ b/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/SConscript @@ -4,6 +4,6 @@ example_env = env.Clone() example_env.MergeFlags(example_env["SWIFTEN_FLAGS"]) example_env.MergeFlags(example_env["SWIFTEN_DEP_FLAGS"]) -for i in range(1,6) : +for i in range(1,7) : example_env.Program("EchoBot" + str(i), ["EchoBot" + str(i) + ".cpp"]) example_env.Program("EchoComponent", "EchoComponent.cpp") diff --git a/Documentation/SwiftenDevelopersGuide/SConscript b/Documentation/SwiftenDevelopersGuide/SConscript index dc00ab4..54a3ad2 100644 --- a/Documentation/SwiftenDevelopersGuide/SConscript +++ b/Documentation/SwiftenDevelopersGuide/SConscript @@ -84,8 +84,11 @@ def generateDocBookCode(env, target, source) : if "doc" in ARGUMENTS : env.DocBook("Swiften Developers Guide.xml") -for i in range(1, 6) : - source = "Examples/EchoBot/EchoBot" + str(i) + ".cpp" +sources = [] +for i in range(1, 7) : + sources.append("Examples/EchoBot/EchoBot" + str(i) + ".cpp") +sources += ["Examples/EchoBot/" + i for i in ["EchoPayloadParserFactory.h", "EchoPayloadSerializer.h", "EchoPayload.h"]] +for source in sources : env.Command(source + ".xml", source, Action(generateDocBookCode, cmdstr = "$GENCOMSTR")) SConscript(dirs = ["Examples"]) diff --git a/Documentation/SwiftenDevelopersGuide/Swiften Developers Guide.xml b/Documentation/SwiftenDevelopersGuide/Swiften Developers Guide.xml index 52af24e..ea4ccd4 100644 --- a/Documentation/SwiftenDevelopersGuide/Swiften Developers Guide.xml +++ b/Documentation/SwiftenDevelopersGuide/Swiften Developers Guide.xml @@ -301,7 +301,78 @@ <literal>RosterPayload</literal>. </para> - <remark>TODO</remark> + <para> + If you want to extend Swiften with your own XMPP extension, you will first + need to create a payload for this extension. For example, suppose we want to + reate an extension for use in our Echo bot that contains a special textual + message, and add this to all our outgoing messages, + we create the <literal>EchoPayload</literal> illustrated in + <xref linkend="Example-EchoPayload"/>. We can then append or retrieve this + payload from the stanzas using <literal>Stanza::getPayload()</literal> and + <literal>Stanza::addPayload()</literal>. For example, the version of our + bot in <xref linkend="Example-EchoBot6"/> checks whether an incoming + message contains the <literal>EchoPayload</literal>, and if not, + echoes back the message, and adds an extension to the message with a + descriptive text. + </para> + + <example id="Example-EchoPayload"> + <title>Extending Swiften with a new payload: <literal>EchoPayload</literal></title> + <include xmlns="http://www.w3.org/2001/XInclude" href="Examples/EchoBot/EchoPayload.h.xml" xpointer="xpointer(//programlisting|//calloutlist)"/> + </example> + + <example id="Example-EchoBot6"> + <title>Adding a custom extension: Using a custom element, and registering a parser (factory) and serializer for the element.</title> + <include xmlns="http://www.w3.org/2001/XInclude" href="Examples/EchoBot/EchoBot6.cpp.xml" xpointer="xpointer(//programlisting|//calloutlist)"/> + </example> + + <para> + However, having the element is not enough; Swiften also needs to know how to + extract this payload from the incoming stanzas, and know how to send it on + outgoing stanzas. In order to do this, Swiften uses XML parsers and serializers + for the payload. We therefore need to create a parser and serializer for our + new payload, and register it with <literal>Client</literal>. Serializers are + implemented as subclasses from <literal>PayloadSerializer</literal>, and provide + the basic methods <literal>canSerialize()</literal> and + <literal>serialize()</literal>. The serializer + is registered using <literal>Client::addPayloadSerializer()</literal> + (and unregistered using <literal>Client::removePayloadSerializer()</literal>). + Parsers consist of 2 parts: a subclass of <literal>PayloadParser</literal>, which + parses incoming XML in an event-driven way and builds up the payload, and + a subclass of <literal>PayloadParserFactory</literal>, which is responsible + for detecting whether a given parser can parse an incoming element, and + creates a parser. The parser factory is registered with the client using + <literal>Client::addPayloadParserFactory()</literal> (and unregistered + using <literal>Client::removePayloadParserFactory()</literal>). + </para> + + <para> + Although you can subclass the base classes for parsers and serializers + directly, Swiften comes with utility classes that contain common + functionality for parsers and serializers. For example, for our EchoBot, + the parser and serializer using these utility classes is shown in + <xref linkend="Example-EchoPayloadParser"/> and + <xref linkend="Example-EchoPayloadSerializer"/> respectively. Registration + of the parser and serializer is shown in the constructor of our EchoBot in + <xref linkend="Example-EchoBot6"/>. + </para> + + <example id="Example-EchoPayloadParser"> + <title>The parser and parser factory for <literal>EchoPayload</literal></title> + <include xmlns="http://www.w3.org/2001/XInclude" href="Examples/EchoBot/EchoPayloadParserFactory.h.xml" xpointer="xpointer(//programlisting|//calloutlist)"/> + </example> + + <example id="Example-EchoPayloadSerializer"> + <title>The serializer for <literal>EchoPayload</literal></title> + <include xmlns="http://www.w3.org/2001/XInclude" href="Examples/EchoBot/EchoPayloadSerializer.h.xml" xpointer="xpointer(//programlisting|//calloutlist)"/> + </example> + + <para> + If you want to create your own parser and serializers, you can look at the + built-in parsers and serializers in the Swiften library, located in + <literal>Swiften/Parser/PayloadParsers</literal> and <literal>Swiften/Serializer/PayloadSerializers</literal>. + </para> + </sect1> <sect1 id="Section-CustomQueries"> |