/*************************************************************************** * Copyright (C) 2004 - 2005 by Raphael Langerhorst * * raphael-langerhorst@gmx.at * * * * Permission is hereby granted, free of charge, to any person obtaining * * a copy of this software and associated documentation files (the * * "Software"), to deal in the Software without restriction, including * * without limitation the rights to use, copy, modify, merge, publish, * * distribute, sublicense, and/or sell copies of the Software, and to * * permit persons to whom the Software is furnished to do so, subject to * * the following conditions: * * * * The above copyright notice and this permission notice shall be * * included in all copies or substantial portions of the Software. * * * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.* * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR * * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * * OTHER DEALINGS IN THE SOFTWARE. * ***************************************************************************/ #ifndef GXMLDATACONTROLLER_H #define GXMLDATACONTROLLER_H #include "GDataController.h" #include #include #include #include #include #include namespace GWE { class GCoreXmlSerializer; class GStorage; class GXmlNetwork; /** * \Class GXmlDataController GXmlDataController.h * \brief Implements XML based data management. * @author Raphael Langerhorst * * The XML Data Controller uses GXmlNetwork based network implementations * and GXmlStorage based data storage backends to accomplish its task. * * Since the GXmlDataController also includes a network capabilities * different elements are managed by different GWE Servers. To differentiate * between elements that this server is responsible for and elements * that other servers are managing, the concept of primary and secondary * elements is introduced. All known elements are stored in the same * storage, but the GXmlDataController keeps track of which elements * are primary and which are secondary. * * The difference in handling primary and secondary elements is that * influences radiated from secondary elements are not transported * to other GWE Servers while influences from primary elements are * transported to every affected GWE Server. * * For the XML protocol, please look at the technical documentation. * * @todo keep track of online and offline GWE Servers (presence) * @todo proper shutdown (persistent storage,...) * @todo move most of the QMaps into the database, as soon as available */ class GXmlDataController : public GDataController { Q_OBJECT protected: /** * The serializer is used to actually convert all data between * C++ objects and XML documents */ GCoreXmlSerializer* Serializer; /** * The storage that is used by the data controller, most likely * a database backend. */ GStorage* Storage; /** * The GXmlDataController class is able to handle distributed * world management. * * For the communication between all GWE Server instances, a * network class is used. */ GXmlNetwork* Network; /** * The GWE Server that is one level higher in the network hierarchy. * If it is an empty string it means that THIS server is the highest in the * hierarchy. * * If a master server is given on initialization, then it is contacted * after a successfull network initialization. */ QString MasterServer; /** * Contains a list of GWE Servers one level ower in the network hierarchy. * * These need to be contacted if this server goes down for example. */ // QStringList ChildServers; /** * When receiving element data through the network, the sender * server is stored together with the received element ID in this * mapping. * * This mapping can then be used to contact the correct servers for * updates or for sending influences. * * Remember that all elements in this map must be secondary elements. */ // QMap ElementServerMapping; /** * Holds a list of element IDs which are primary elements on this server. * * @todo IMPORTANT for persistance: GXmlStorage should keep primary and secondary elements separate */ // QValueList PrimaryElements; /** * Holds a list of element IDs which are secondary elements on this server. * * @todo IMPORTANT for persistance: GXmlStorage should keep primary and secondary elements separate */ // QValueList SecondaryElements; /** * Includes all open elements. */ QMap OpenElements; /** * Holds the values of last propagations of elements. * This is used to avoid resending frequently changing * elements too often. * This is used for "general syndication to all known servers". * @see syndicateElementData(), PendingSyndication */ QMap LastSyndicationTime; /** * Holds all elements that will be syndicated, but * are delayed because of too frequent syndication requests. * This is used for "general syndication to all known servers". * @see syndicateElementData(), processAgentChanged(), postSyndication(), LastSyndicationTime */ QValueList PendingSyndication; public: /** * Constructor. * @param master_server should hold the network id of a server which is * part of the already existing network, empty if this * server is the first of the whole infrastructure. */ GXmlDataController(GStorage* storage, GXmlNetwork* network, const QString& MasterServer="", QObject *parent = 0, const char *name = 0); /** * Virtual Destructor. */ virtual ~GXmlDataController(); // GDataController implementation // virtual const GCS::GElement* read(const GCS::GElementID& ) const; virtual QValueList getChildren(const GCS::GElementID& parent) const; virtual GCS::GElement* open(const GCS::GElementID& ); virtual GCS::GElement* getOpenElement(const GCS::GElementID& ); virtual const QValueList getListOfOpenElements(); virtual const QValueList getListOfAllElements(); public slots: /** * This method adds a primary element. An added element * is open by default. * @see GDataController::add() */ virtual bool add(GCS::GElement* ); virtual bool writeOpenElementToStorage(const GCS::GElementID& ); virtual bool close(const GCS::GElementID& ); virtual bool postDelete(const GCS::GElementID& ); public: /** * @return true if this GWE Server is the master server of a network. */ bool isMasterServer(); /** * This method uses the ElementServerMapping. * @return the server, if known, of the given Element ID, otherwise an empty string. */ QString getManagingServerOfElement(const GCS::GElementID&) const; /** * @return all known servers, including the master server without duplicated entries. */ QStringList getAllKnownServers() const; protected slots: /** * Called when the application exits, * properly unregisters from master server and * shuts down network connection. */ virtual void shutdown(); /** * Registers this GWE Server at the master GWE Server, * usually after a successfull network initialization. */ virtual void registerWithMaster(); /** * This actually sends an unregister message to the * master server, it is automatically called when * the application is about to quit. */ virtual void unregisterFromMaster(); /** * Sends an unregister message to all known servers, * including the master server. */ virtual void unregisterFromAllKnownServers(); /** * Basically just checks the amount of left IDs and eventually * calls requestFreeIDs() */ virtual void checkFreeIDs(); /** * Generates a requestfreeids message and sends * it to the master server. */ virtual void requestFreeIDs(unsigned long amount); /** * Sends given amount of free GElementIDs to given server. */ virtual void sendFreeIDs(QString server, unsigned long amount); /** * Adds given element to list of pending syndications. * @see PendingSyndication */ virtual void postSyndication(const GCS::GElementID& id); /** * Basically checks if there are elements that * still need to be syndicated and syndicates them * if enough time has elapsed since last syndication. * @see PendingSyndication */ virtual void checkElementsForSyndication(); /** * Propagates given element to given server. */ virtual void syndicateElementDataToServer(const GCS::GElementID& id,const QString& server); /** * Forces propagation of element data to the master server * and all child servers. * * Element data is not propagated to the owner (managing server) * of given element. */ virtual void syndicateElementData(const GCS::GElementID& id); /** * Propagates all known element data to given server. * This is useful for servers that just get online for example. */ virtual void syndicateAllElementDataToServer(const QString& server); /** * Updates server presence. * Usually connected to presenceChanged() signals from XML Network. */ virtual void updateServerPresence(QString server, bool available); //BEGIN ELEMENT OBSERVATION /** * Called for every opened element, connects some signals and slots, * registers the element in the OpenElements map. */ virtual void prepareOpenedElement(GCS::GElement* element); /** * When an element is reparented, other servers and elements need to be notified about it. * This slot generates the appropriate messages. It is connected to open elements by default, * also to elements that just got "added". * * @todo Currently only messages are generated for servers managing the old and new parent, * but it might occur that this server holds a parent that detects a child moving out * of itself (if the parent gets smaller). In such a case the reparented element as such * is not located on this server although the reparenting was detected here and the * managing server of the reparented element needs to be notified as well (receive data * handles all three cases). */ virtual void processReparenting(GCS::GElement* element, const GCS::GElementID& oldParent, const GCS::GElementID& newParent, const GCS::GMatrix44& transformation); /** * When an element is influenced and this server is not the managing * server of the affected element the influence is transported to the * managing server. * * This slot is usually connected to the influenceReceived() signal from * elements. */ virtual void processInfluencing(const GCS::GElementInfluence& influence); /** * Listens to agentChanged() signals of open elements and * requests a global syndication of this element. * @see PendingSyndication */ virtual void processAgentChanged(const GCS::GAgent& agent); /** * Unregisters given server from this server and does all * required postprocessing such an event requires. */ virtual void processUnregister(const QString& server); public slots: /** * Connected to the XML network for receiving data. * This implements the XML protocol used for GWE communication. */ virtual void receiveData(QDomElement data, const QString& sender); // /** // * This data controller differentiates between primary and secondary // * elements in order to know which are managed on this server and // * which elements are the responsibility of other GWE Servers. // * // * An added secondary element is open by default after it is added. // * // * Use this slot to insert a secondary element. The add() slot // * inserts a primary element. // */ // virtual void addSecondary(GCS::GElement*); /** * Checks complete storage consistency. The return value is * stored in the ok parameter. * @param ok the return value is stored here as well. * @return TRUE when storage is fully consistent, otherwise FALSE. */ virtual bool checkConsistency(bool& ok); //BEGIN SLOTS / SIGNALS FOR USER INTERACTION public slots: /** * Sends a user message to given destination. * @see userMessageReceived() */ void sendUserMessage(QString message, QString destination); signals: /** * Emitted when a user message (a "pure" XMPP message tag with text * content) is received, this can be used in the user interface of a * client for example. * @param internal is true when the message comes from inside the G Universe */ void userMessageReceived(QString message, QString sender, bool internal); /** * Emitted when a server presence state changes. * This signal is used even when a * server changes from external to internal state, which happens * when registering - it first gets available as an external server, * then registers and becomes an internal server. * @param internal is true when the server is inside the G Universe */ void serverPresenceChanged(QString server, bool available, bool internal); //END SLOTS / SIGNALS FOR USER INTERACTION }; } #endif //GXMLDATACONTROLLER_H