From 8d629ca48e9b5530416127e2e52c945fe1f9ee52 Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Mon, 23 Feb 2009 22:20:10 +0100 Subject: Verarbeitung von XML-Paketen --- src/Common/Makefile.am | 4 +- src/Common/Makefile.in | 9 +- src/Common/RequestHandlers/Makefile.in | 2 + src/Common/RequestManager.cpp | 120 ++++++++- src/Common/RequestManager.h | 42 ++++ src/Common/Requests/Makefile.in | 2 + src/Common/XmlPacket.cpp | 239 ++++++++++++++++++ src/Common/XmlPacket.h | 437 +++++++++++++++++++++++++++++++++ src/Common/XmlRequest.h | 92 +++++++ src/Common/XmlRequestBase.h | 39 +++ src/Common/XmlRequestHandler.h | 60 +++++ 11 files changed, 1037 insertions(+), 9 deletions(-) create mode 100644 src/Common/XmlPacket.cpp create mode 100644 src/Common/XmlPacket.h create mode 100644 src/Common/XmlRequest.h create mode 100644 src/Common/XmlRequestBase.h create mode 100644 src/Common/XmlRequestHandler.h (limited to 'src/Common') diff --git a/src/Common/Makefile.am b/src/Common/Makefile.am index 665c21a..2fd4edb 100644 --- a/src/Common/Makefile.am +++ b/src/Common/Makefile.am @@ -3,10 +3,10 @@ SUBDIRS = Requests RequestHandlers noinst_LTLIBRARIES = libcommon.la libcommon_la_SOURCES = ActionManager.cpp ConfigEntry.cpp ConfigManager.cpp Exception.cpp Initializable.cpp \ Logger.cpp LogManager.cpp ModuleManager.cpp RequestManager.cpp \ - SystemBackend.cpp Tokenizer.cpp + SystemBackend.cpp Tokenizer.cpp XmlPacket.cpp libcommon_la_LIBADD = Requests/librequests.la RequestHandlers/librequesthandlers.la noinst_HEADERS = ActionManager.h ConfigEntry.h ConfigManager.h Configurable.h Exception.h HostInfo.h \ Initializable.h Logger.h LoggerBase.h LogManager.h ModuleManager.h \ RemoteLogger.h Request.h RequestBase.h RequestHandler.h RequestManager.h \ - SystemBackend.h Tokenizer.h UserInfo.h + SystemBackend.h Tokenizer.h UserInfo.h XmlPacket.h XmlRequestHandler.h diff --git a/src/Common/Makefile.in b/src/Common/Makefile.in index 2fb869f..3638371 100644 --- a/src/Common/Makefile.in +++ b/src/Common/Makefile.in @@ -54,7 +54,7 @@ libcommon_la_DEPENDENCIES = Requests/librequests.la \ am_libcommon_la_OBJECTS = ActionManager.lo ConfigEntry.lo \ ConfigManager.lo Exception.lo Initializable.lo Logger.lo \ LogManager.lo ModuleManager.lo RequestManager.lo \ - SystemBackend.lo Tokenizer.lo + SystemBackend.lo Tokenizer.lo XmlPacket.lo libcommon_la_OBJECTS = $(am_libcommon_la_OBJECTS) DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/config/depcomp @@ -204,6 +204,8 @@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ +libxml2_CFLAGS = @libxml2_CFLAGS@ +libxml2_LIBS = @libxml2_LIBS@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ @@ -231,13 +233,13 @@ SUBDIRS = Requests RequestHandlers noinst_LTLIBRARIES = libcommon.la libcommon_la_SOURCES = ActionManager.cpp ConfigEntry.cpp ConfigManager.cpp Exception.cpp Initializable.cpp \ Logger.cpp LogManager.cpp ModuleManager.cpp RequestManager.cpp \ - SystemBackend.cpp Tokenizer.cpp + SystemBackend.cpp Tokenizer.cpp XmlPacket.cpp libcommon_la_LIBADD = Requests/librequests.la RequestHandlers/librequesthandlers.la noinst_HEADERS = ActionManager.h ConfigEntry.h ConfigManager.h Configurable.h Exception.h HostInfo.h \ Initializable.h Logger.h LoggerBase.h LogManager.h ModuleManager.h \ RemoteLogger.h Request.h RequestBase.h RequestHandler.h RequestManager.h \ - SystemBackend.h Tokenizer.h UserInfo.h + SystemBackend.h Tokenizer.h UserInfo.h XmlPacket.h XmlRequestHandler.h all: all-recursive @@ -301,6 +303,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/RequestManager.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SystemBackend.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Tokenizer.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/XmlPacket.Plo@am__quote@ .cpp.o: @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< diff --git a/src/Common/RequestHandlers/Makefile.in b/src/Common/RequestHandlers/Makefile.in index dc292e3..ccf87b4 100644 --- a/src/Common/RequestHandlers/Makefile.in +++ b/src/Common/RequestHandlers/Makefile.in @@ -191,6 +191,8 @@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ +libxml2_CFLAGS = @libxml2_CFLAGS@ +libxml2_LIBS = @libxml2_LIBS@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ diff --git a/src/Common/RequestManager.cpp b/src/Common/RequestManager.cpp index d852f5d..94b3da9 100644 --- a/src/Common/RequestManager.cpp +++ b/src/Common/RequestManager.cpp @@ -19,6 +19,8 @@ #include "RequestManager.h" #include "Request.h" +#include "XmlRequest.h" +#include "XmlPacket.h" #include "RequestHandlers/DisconnectRequestHandler.h" #include "Logger.h" @@ -67,6 +69,40 @@ bool RequestManager::RequestMap::deleteRequest(uint16_t id) { } +RequestManager::XmlRequestMap::~XmlRequestMap() { + for(iterator it = begin(); it != end(); ++it) + delete it->second; +} + +bool RequestManager::XmlRequestMap::addRequest(uint16_t id, XmlRequestHandler *info) { + if(!insert(std::make_pair(id, info)).second) + return false; + + info->signalFinished().connect(sigc::hide_return(sigc::bind(sigc::mem_fun(this, &RequestManager::XmlRequestMap::deleteRequest), id))); + + return true; +} + +XmlRequestHandler* RequestManager::XmlRequestMap::findRequest(uint16_t id) { + iterator it = find(id); + if(it == end()) + return 0; + + return it->second; +} + +bool RequestManager::XmlRequestMap::deleteRequest(uint16_t id) { + iterator it = find(id); + if(it == end()) + return false; + + delete it->second; + + erase(it); + return true; +} + + void RequestManager::receiveHandler(Net::Connection *connection, const Net::Packet &packet) { std::map::iterator it = requestMaps.find(connection); @@ -86,6 +122,37 @@ void RequestManager::receiveHandler(Net::Connection *connection, const Net::Pack return; } + std::map::iterator it2 = xmlRequestMaps.find(connection); + if(it2 == xmlRequestMaps.end()) { + // TODO: Error + Logger::log(Logger::ERROR, "Received a packet from an unregistered connection."); + + return; + } + + XmlRequestMap *xmlRequestMap = it2->second; + XmlRequestHandler *xmlRequest = xmlRequestMap->findRequest(packet.getRequestId()); + + if(xmlRequest) { + XmlPacket xmlPacket(packet); + xmlRequest->handlePacket(connection, xmlPacket); + + return; + } + + if(packet.getType() == Net::Packet::XML) { + XmlPacket xmlPacket(packet); + + std::map::iterator factoryIt = xmlRequestHandlerFactories.find(xmlPacket.getType()); + if(factoryIt != xmlRequestHandlerFactories.end()) { + xmlRequest = factoryIt->second->createRequestHandler(); + xmlRequestMap->addRequest(packet.getRequestId(), xmlRequest); + xmlRequest->handlePacket(connection, xmlPacket); + + return; + } + } + std::map::iterator factoryIt = requestHandlerFactories.find(packet.getType()); if(factoryIt != requestHandlerFactories.end()) { request = factoryIt->second->createRequestHandler(); @@ -121,8 +188,31 @@ bool RequestManager::sendRequest(Net::Connection *connection, std::auto_ptr request) { + std::map::iterator it = xmlRequestMaps.find(connection); + + if(it == xmlRequestMaps.end()) { + Logger::log(Logger::CRITICAL, "Trying to send a request over an unregistered connecion."); + return false; + } + + XmlRequestMap *requestMap = it->second; + + uint16_t id; + do { + id = getRequestId(); + } while(requestMap->findRequest(id)); + + request->sendRequest(connection, id); + + requestMap->addRequest(id, request.release()); + + return true; +} + void RequestManager::registerConnection(Net::Connection *connection) { requestMaps.insert(std::make_pair(connection, new RequestMap())); + xmlRequestMaps.insert(std::make_pair(connection, new XmlRequestMap())); connection->signalReceive().connect(sigc::mem_fun(this, &RequestManager::receiveHandler)); } @@ -130,12 +220,17 @@ void RequestManager::registerConnection(Net::Connection *connection) { void RequestManager::unregisterConnection(Net::Connection *connection) { std::map::iterator it = requestMaps.find(connection); - if(it == requestMaps.end()) - return; + if(it != requestMaps.end()) { + delete it->second; + requestMaps.erase(it); + } - delete it->second; + std::map::iterator it2 = xmlRequestMaps.find(connection); - requestMaps.erase(it); + if(it2 != xmlRequestMaps.end()) { + delete it2->second; + xmlRequestMaps.erase(it2); + } } void RequestManager::unregisterPacketType(Net::Packet::Type type) { @@ -149,6 +244,17 @@ void RequestManager::unregisterPacketType(Net::Packet::Type type) { requestHandlerFactories.erase(it); } +void RequestManager::unregisterPacketType(const std::string &type) { + std::map::iterator it = xmlRequestHandlerFactories.find(type); + + if(it == xmlRequestHandlerFactories.end()) + return; + + delete it->second; + + xmlRequestHandlerFactories.erase(it); +} + RequestManager::RequestManager() : core(false), requestId(-1) { registerPacketType(Net::Packet::DISCONNECT); } @@ -159,8 +265,14 @@ RequestManager::~RequestManager() { for(std::map::iterator it = requestMaps.begin(); it != requestMaps.end(); ++it) delete it->second; + for(std::map::iterator it = xmlRequestMaps.begin(); it != xmlRequestMaps.end(); ++it) + delete it->second; + for(std::map::iterator it = requestHandlerFactories.begin(); it != requestHandlerFactories.end(); ++it) delete it->second; + + for(std::map::iterator it = xmlRequestHandlerFactories.begin(); it != xmlRequestHandlerFactories.end(); ++it) + delete it->second; } } diff --git a/src/Common/RequestManager.h b/src/Common/RequestManager.h index c2f58d2..00d940d 100644 --- a/src/Common/RequestManager.h +++ b/src/Common/RequestManager.h @@ -30,6 +30,8 @@ namespace Common { class RequestBase; class RequestHandler; +class XmlRequestBase; +class XmlRequestHandler; class RequestManager { private: @@ -48,6 +50,21 @@ class RequestManager { bool deleteRequest(uint16_t id); }; + class XmlRequestMap : private std::map { + private: + // Prevent shallow copy + XmlRequestMap(const XmlRequestMap &o); + XmlRequestMap& operator=(const XmlRequestMap &o); + + public: + XmlRequestMap() {} + ~XmlRequestMap(); + + bool addRequest(uint16_t id, XmlRequestHandler *info); + XmlRequestHandler* findRequest(uint16_t id); + bool deleteRequest(uint16_t id); + }; + class RequestHandlerFactory { protected: RequestHandlerFactory() {} @@ -64,13 +81,31 @@ class RequestManager { } }; + class XmlRequestHandlerFactory { + protected: + XmlRequestHandlerFactory() {} + + public: + virtual XmlRequestHandler* createRequestHandler() = 0; + virtual ~XmlRequestHandlerFactory() {} + }; + + template class SpecificXmlRequestHandlerFactory : public XmlRequestHandlerFactory { + public: + virtual XmlRequestHandler* createRequestHandler() { + return new T(); + } + }; + static RequestManager requestManager; std::map requestMaps; + std::map xmlRequestMaps; bool core; uint16_t requestId; std::map requestHandlerFactories; + std::map xmlRequestHandlerFactories; uint16_t getRequestId() { return requestId+=2; @@ -108,7 +143,14 @@ class RequestManager { void unregisterPacketType(Net::Packet::Type type); + template void registerPacketType(const std::string &type) { + xmlRequestHandlerFactories.insert(std::make_pair(type, new SpecificXmlRequestHandlerFactory())); + } + + void unregisterPacketType(const std::string &type); + bool sendRequest(Net::Connection *connection, std::auto_ptr request); + bool sendRequest(Net::Connection *connection, std::auto_ptr request); virtual ~RequestManager(); }; diff --git a/src/Common/Requests/Makefile.in b/src/Common/Requests/Makefile.in index 2c363eb..768a8a6 100644 --- a/src/Common/Requests/Makefile.in +++ b/src/Common/Requests/Makefile.in @@ -191,6 +191,8 @@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ +libxml2_CFLAGS = @libxml2_CFLAGS@ +libxml2_LIBS = @libxml2_LIBS@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ diff --git a/src/Common/XmlPacket.cpp b/src/Common/XmlPacket.cpp new file mode 100644 index 0000000..8da861c --- /dev/null +++ b/src/Common/XmlPacket.cpp @@ -0,0 +1,239 @@ +/* + * XmlProcessor.cpp + * + * Copyright (C) 2009 Matthias Schiffer + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include "XmlPacket.h" +#include + +namespace Mad { +namespace Common { + +XmlPacket::Entry XmlPacket::Element::nilEntry(0); +XmlPacket::Element XmlPacket::Entry::nilElement(0); + +void XmlPacket::Element::updateStr() { + if(type == NONE || type == LIST) + return; + + if(type != STRING) { + std::ostringstream buf; + + switch(type) { + case INT: + buf << value.var_int; + break; + case UINT: + buf << value.var_uint; + break; + case INT64: + buf << value.var_int64; + break; + case UINT64: + buf << value.var_uint64; + break; + case FLOAT: + buf << value.var_float; + break; + case DOUBLE: + buf << value.var_double; + break; + case LONGDOUBLE: + buf << value.var_ldouble; + default: + break; + + } + + str = buf.str(); + } + + xmlNodePtr newNode = xmlNewText((xmlChar*)str.c_str()); + xmlNodePtr oldNode = elementNode->children; + + xmlReplaceNode(oldNode, newNode); + xmlFreeNode(oldNode); +} + +XmlPacket::Element::Element(xmlNodePtr node) : elementNode(node), type(NONE) { + if(!node) + return; + + xmlChar *typestr = xmlGetProp(node, (xmlChar*)"type"); + if(!typestr) + return; + + xmlChar *content = xmlNodeGetContent(node->children); + if(!content) { + xmlFree(typestr); + return; + } + + str = (char*)content; + + if(!xmlStrcmp(typestr, (xmlChar*)"int")) { + type = INT; + value.var_int = std::strtol((char*)content, 0, 10); + } + else if(!xmlStrcmp(typestr, (xmlChar*)"uint")) { + type = UINT; + value.var_uint = std::strtoul((char*)content, 0, 10); + } + else if(!xmlStrcmp(typestr, (xmlChar*)"int64")) { + type = INT64; + value.var_int64 = std::strtoll((char*)content, 0, 10); + } + else if(!xmlStrcmp(typestr, (xmlChar*)"uint64")) { + type = UINT64; + value.var_uint64 = std::strtoull((char*)content, 0, 10); + } + else if(!xmlStrcmp(typestr, (xmlChar*)"float")) { + type = FLOAT; + value.var_float = std::strtof((char*)content, 0); + } + else if(!xmlStrcmp(typestr, (xmlChar*)"double")) { + type = DOUBLE; + value.var_double = std::strtod((char*)content, 0); + } + else if(!xmlStrcmp(typestr, (xmlChar*)"longdouble")) { + type = LONGDOUBLE; + value.var_ldouble = std::strtold((char*)content, 0); + } + else if(!xmlStrcmp(typestr, (xmlChar*)"string")) { + type = STRING; + } + + xmlFree(typestr); + xmlFree(content); + + updateStr(); +} + +XmlPacket::Entry::Entry(xmlNodePtr node) : entryNode(node) { + if(!node) + return; + + for(xmlNodePtr element = node->children; element != 0; element = element->next) { + if(element->type != XML_ELEMENT_NODE) + continue; + + xmlChar *name = xmlGetProp(element, (xmlChar*)"name"); + + if(!xmlStrcmp(element->name, (xmlChar*)"list")) + lists.insert(std::make_pair(std::string((char*)name), List(element))); + else if(!xmlStrcmp(element->name, (xmlChar*)"value")) + elements.insert(std::make_pair(std::string((char*)name), Element(element))); + + xmlFree(name); + } +} + +XmlPacket::Element& XmlPacket::Entry::operator[](const std::string &name) { + std::map::iterator it = elements.find(name); + if(it != elements.end()) + return it->second; + + std::map::iterator it2 = lists.find(name); + if(it2 != lists.end()) + return it2->second; + + return nilElement; +} + +const XmlPacket::Element& XmlPacket::Entry::operator[](const std::string &name) const { + std::map::const_iterator it = elements.find(name); + if(it != elements.end()) + return it->second; + + std::map::const_iterator it2 = lists.find(name); + if(it2 != lists.end()) + return it2->second; + + return nilElement; +} + +XmlPacket::List::List(xmlNodePtr node) : Element(node, LIST) { + for(xmlNodePtr entry = node->children; entry != 0; entry = entry->next) { + if(entry->type != XML_ELEMENT_NODE || xmlStrcmp(entry->name, (xmlChar*)"entry")) + continue; + + entries.push_back(Entry(entry)); + } +} + + +XmlPacket::XmlPacket() { + doc = xmlNewDoc((xmlChar*)"1.0"); + + packetNode = xmlNewNode(0, (xmlChar*)"packet"); + xmlDocSetRootElement(doc, packetNode); + + entry = new Entry(packetNode); +} + +XmlPacket::XmlPacket(const XmlPacket &o) { + doc = xmlCopyDoc(o.doc, 1); + packetNode = xmlDocGetRootElement(doc); + entry = new Entry(packetNode); +} + +XmlPacket::XmlPacket(const Net::Packet &packet) { + doc = xmlParseMemory((const char*)packet.getData(), packet.getLength()); + packetNode = xmlDocGetRootElement(doc); + entry = new Entry(packetNode); +} + +XmlPacket& XmlPacket::operator=(const XmlPacket &o) { + delete entry; + xmlFreeDoc(doc); + + doc = xmlCopyDoc(o.doc, 1); + packetNode = xmlDocGetRootElement(doc); + entry = new Entry(packetNode); + + return *this; +} + +std::string XmlPacket::getType() const { + xmlChar *type = xmlGetProp(packetNode, (xmlChar*)"type"); + + std::string ret(type ? (char*)type : ""); + + xmlFree(type); + + return ret; +} + +void XmlPacket::setType(const std::string &type) { + xmlSetProp(packetNode, (xmlChar*)"type", (xmlChar*)type.c_str()); +} + +Net::Packet XmlPacket::encode(uint16_t requestId) { + xmlChar *buf; + int length; + + xmlDocDumpMemory(doc, &buf, &length); + + Net::Packet packet(Net::Packet::XML, requestId, buf, length); + + xmlFree(buf); + + return packet; +} + +} +} diff --git a/src/Common/XmlPacket.h b/src/Common/XmlPacket.h new file mode 100644 index 0000000..007404a --- /dev/null +++ b/src/Common/XmlPacket.h @@ -0,0 +1,437 @@ +/* + * XmlProcessor.h + * + * Copyright (C) 2009 Matthias Schiffer + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#ifndef MAD_COMMON_XMLPACKET_H_ +#define MAD_COMMON_XMLPACKET_H_ + +#include + +#include +#include +#include +#include + +#include + +namespace Mad { +namespace Common { + +class XmlPacket { + public: + class Entry; + class List; + + private: + xmlDocPtr doc; + xmlNodePtr packetNode; + Entry *entry; + + public: + + class Element { + public: + enum Type { + NONE, LIST, + INT, UINT, INT64, UINT64, + FLOAT, DOUBLE, LONGDOUBLE, STRING + }; + + protected: + friend class Entry; + + xmlNodePtr elementNode; + + private: + std::string str; + + Type type; + union Variant { + int var_int; + unsigned int var_uint; + + long long var_int64; + unsigned long long var_uint64; + + float var_float; + double var_double; + long double var_ldouble; + } value; + + static Entry nilEntry; + + template + void set(T val) { + switch(type) { + case INT: + value.var_int = static_cast(val); + break; + case UINT: + value.var_uint = static_cast(val); + break; + case INT64: + value.var_int64 = static_cast(val); + break; + case UINT64: + value.var_uint64 = static_cast(val); + break; + case FLOAT: + value.var_float = static_cast(val); + break; + case DOUBLE: + value.var_double = static_cast(val); + break; + case LONGDOUBLE: + value.var_ldouble = static_cast(val); + break; + default: + break; + } + + updateStr(); + } + + void updateStr(); + + protected: + Element(xmlNodePtr node, Type type0) : elementNode(node), type(type0) {} + + public: + Element(xmlNodePtr node); + + Type getType() const { + return type; + } + + virtual size_t getSize() const { + return 0; + } + + virtual Entry& operator[](size_t) { + return nilEntry; + } + + virtual const Entry& operator[](size_t) const { + return nilEntry; + } + + virtual bool insertEntry(size_t) {return false;} + virtual bool addEntry() {return false;} + virtual bool removeEntry(size_t) {return false;} + + template + operator T() { + switch(type) { + case INT: + return static_cast(value.var_int); + case UINT: + return static_cast(value.var_uint); + case INT64: + return static_cast(value.var_int64); + case UINT64: + return static_cast(value.var_uint64); + case FLOAT: + return static_cast(value.var_float); + case DOUBLE: + return static_cast(value.var_double); + case LONGDOUBLE: + return static_cast(value.var_ldouble); + default: + return static_cast(0); + } + } + + operator std::string() { + return str; + } + + const Element& operator=(int val) { + set(val); + return *this; + } + + const Element& operator=(unsigned int val) { + set(val); + return *this; + } + + const Element& operator=(long long val) { + set(val); + return *this; + } + + const Element& operator=(unsigned long long val) { + set(val); + return *this; + } + + const Element& operator=(float val) { + set(val); + return *this; + } + + const Element& operator=(double val) { + set(val); + return *this; + } + + const Element& operator=(long double val) { + set(val); + return *this; + } + + const Element& operator=(const std::string &val) { + if(type == STRING) { + str = val; + updateStr(); + } + + return *this; + } + }; + + class Entry { + private: + friend class List; + + xmlNodePtr entryNode; + + std::map elements; + std::map lists; + + static Element nilElement; + + private: + bool add(const std::string &name, const std::string &value, const char *type) { + if(!entryNode) + return false; + + if(lists.find(name) != lists.end() || elements.find(name) != elements.end()) + return false; + + xmlNodePtr newNode = xmlNewTextChild(entryNode, 0, (xmlChar*)"value", (xmlChar*)value.c_str()); + xmlSetProp(newNode, (xmlChar*)"name", (xmlChar*)name.c_str()); + xmlSetProp(newNode, (xmlChar*)"type", (xmlChar*)type); + + if(!elements.insert(std::make_pair(name, Element(newNode))).second) { + xmlUnlinkNode(newNode); + xmlFreeNode(newNode); + + return false; + } + + return true; + } + + public: + Entry(xmlNodePtr node); + + Element& operator[](const std::string &name); + const Element& operator[](const std::string &name) const; + + bool add(const std::string &name, int val) { + std::ostringstream buf; + buf << val; + + return add(name, buf.str(), "int"); + } + + bool add(const std::string &name, unsigned int val) { + std::ostringstream buf; + buf << val; + + return add(name, buf.str(), "uint"); + } + + bool add(const std::string &name, long long val) { + std::ostringstream buf; + buf << val; + + return add(name, buf.str(), "int64"); + } + + bool add(const std::string &name, unsigned long long val) { + std::ostringstream buf; + buf << val; + + return add(name, buf.str(), "uint64"); + } + + bool add(const std::string &name, float val) { + std::ostringstream buf; + buf << val; + + return add(name, buf.str(), "float"); + } + + bool add(const std::string &name, double val) { + std::ostringstream buf; + buf << val; + + return add(name, buf.str(), "double"); + } + + bool add(const std::string &name, long double val) { + std::ostringstream buf; + buf << val; + + return add(name, buf.str(), "longdouble"); + } + + bool add(const std::string &name, const std::string &val) { + return add(name, val, "string"); + } + + bool addList(const std::string &name) { + if(!entryNode) + return false; + + if(elements.find(name) != elements.end() || lists.find(name) != lists.end()) + return false; + + xmlNodePtr newNode = xmlNewChild(entryNode, 0, (xmlChar*)"list", 0); + xmlSetProp(newNode, (xmlChar*)"name", (xmlChar*)name.c_str()); + + if(!lists.insert(std::make_pair(name, List(newNode))).second) { + xmlUnlinkNode(newNode); + xmlFreeNode(newNode); + + return false; + } + + return true; + } + + bool remove(const std::string &name) { + std::map::iterator element = elements.find(name); + + if(element != elements.end()) { + xmlUnlinkNode(element->second.elementNode); + xmlFreeNode(element->second.elementNode); + + elements.erase(element); + + return true; + } + + std::map::iterator list = lists.find(name); + + if(list != lists.end()) { + xmlUnlinkNode(list->second.elementNode); + xmlFreeNode(list->second.elementNode); + + lists.erase(list); + + return true; + } + + return false; + } + }; + + class List : public Element { + private: + std::vector entries; + + public: + List(xmlNodePtr node); + + virtual size_t getSize() const { + return entries.size(); + } + + virtual Entry& operator[](size_t i) { + return entries[i]; + } + + virtual const Entry& operator[](size_t i) const { + return entries[i]; + } + + virtual bool insertEntry(size_t i) { + if(i > getSize()) + return false; + + xmlNodePtr newNode = xmlNewNode(0, (xmlChar*)"entry"); + xmlAddChild(elementNode, newNode); + + entries.insert(entries.begin()+i, Entry(newNode)); + + return true; + } + + virtual bool addEntry() { + return insertEntry(getSize()); + } + + virtual bool removeEntry(size_t i) { + if(i >= getSize()) + return false; + + xmlUnlinkNode(entries[i].entryNode); + xmlFreeNode(entries[i].entryNode); + + entries.erase(entries.begin()+i); + + return true; + } + }; + + XmlPacket(); + XmlPacket(const XmlPacket &o); + XmlPacket(const Net::Packet &packet); + + XmlPacket& operator=(const XmlPacket &o); + + virtual ~XmlPacket() { + delete entry; + + xmlFreeDoc(doc); + } + + std::string getType() const; + void setType(const std::string &type); + + Element& operator[](const std::string &name) { + return entry->operator[](name); + } + + const Element& operator[](const std::string &name) const { + return entry->operator[](name); + } + + template + bool add(const std::string &name, T val) { + return entry->add(name, val); + } + + bool addList(const std::string &name) { + return entry->addList(name); + } + + bool remove(const std::string &name) { + return entry->remove(name); + } + + Net::Packet encode(uint16_t requestId); +}; + +} +} + +#endif /* MAD_COMMON_XMLPACKET_H_ */ diff --git a/src/Common/XmlRequest.h b/src/Common/XmlRequest.h new file mode 100644 index 0000000..0de0291 --- /dev/null +++ b/src/Common/XmlRequest.h @@ -0,0 +1,92 @@ +/* + * Request.h + * + * Copyright (C) 2008 Matthias Schiffer + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#ifndef MAD_COMMON_XMLREQUEST_H_ +#define MAD_COMMON_XMLREQUEST_H_ + +#include "XmlRequestBase.h" +#include "Exception.h" + +#include +#include + +namespace Mad { +namespace Common { + +template class XmlRequest : public XmlRequestBase { + private: + sigc::signal&> finished; + + std::auto_ptr res; + Exception exp; + + public: + typedef sigc::slot&> slot_type; + + protected: + XmlRequest(slot_type slot) : exp(Exception::NOT_FINISHED) { + finished.connect(slot); + finished.connect(sigc::hide(signalFinished().make_slot())); + } + + void finish(std::auto_ptr result) {res = result; finished(*this);} + void finish(const T& result) {res.reset(new T(result)); finished(*this);} + void finishWithError(const Exception &e) {exp = e; finished(*this);} + + public: + const T& getResult() const throw(Exception) { + if(res.get()) + return *res; + + throw exp; + } +}; + +template<> class XmlRequest : public XmlRequestBase { + private: + sigc::signal&> finished; + + bool isFinished; + Exception exp; + + public: + typedef sigc::slot&> slot_type; + + protected: + XmlRequest(slot_type slot) : isFinished(false), exp(Exception::NOT_FINISHED) { + finished.connect(slot); + finished.connect(sigc::hide(signalFinished().make_slot())); + } + + void finish() {isFinished = true; finished(*this);} + void finishWithError(const Exception &e) {exp = e; finished(*this);} + + public: + void getResult() const throw(Exception) { + if(isFinished) + return; + + throw exp; + } +}; + +} +} + +#endif /* MAD_COMMON_XMLREQUEST_H_ */ diff --git a/src/Common/XmlRequestBase.h b/src/Common/XmlRequestBase.h new file mode 100644 index 0000000..fbecc71 --- /dev/null +++ b/src/Common/XmlRequestBase.h @@ -0,0 +1,39 @@ +/* + * RequestBase.h + * + * Copyright (C) 2008 Matthias Schiffer + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#ifndef MAD_COMMON_XMLREQUESTBASE_H_ +#define MAD_COMMON_XMLREQUESTBASE_H_ + +#include "XmlRequestHandler.h" +#include + +namespace Mad { +namespace Common { + +class XmlRequestBase : public XmlRequestHandler { + protected: + virtual void sendRequest(Net::Connection *connection, uint16_t requestId) = 0; + + friend class RequestManager; +}; + +} +} + +#endif /* MAD_COMMON_XMLREQUESTBASE_H_ */ diff --git a/src/Common/XmlRequestHandler.h b/src/Common/XmlRequestHandler.h new file mode 100644 index 0000000..e04e5b9 --- /dev/null +++ b/src/Common/XmlRequestHandler.h @@ -0,0 +1,60 @@ +/* + * RequestHandler.h + * + * Copyright (C) 2008 Matthias Schiffer + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#ifndef MAD_COMMON_XMLREQUESTHANDLER_H_ +#define MAD_COMMON_XMLREQUESTHANDLER_H_ + +#include + +namespace Mad { + +namespace Net { +class Connection; +} + +namespace Common { + +class RequestManager; +class XmlPacket; + +class XmlRequestHandler { + private: + sigc::signal finished; + + // Prevent shallow copy + XmlRequestHandler(const XmlRequestHandler &o); + XmlRequestHandler& operator=(const XmlRequestHandler &o); + + protected: + XmlRequestHandler() {} + + sigc::signal signalFinished() {return finished;} + + virtual void handlePacket(Net::Connection *connection, const XmlPacket &packet) = 0; + + public: + virtual ~XmlRequestHandler() {} + + friend class RequestManager; +}; + +} +} + +#endif /* MAD_COMMON_XMLREQUESTHANDLER_H_ */ -- cgit v1.2.3