/***************************************************************************
* 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 <qdom.h>
#include <qmap.h>
#include <qvaluelist.h>
#include <qstringlist.h>
#include <GElementID.h>
#include <GElement.h>
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<GCS::GElementID,QString> 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<GCS::GElementID> 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<GCS::GElementID> SecondaryElements;
/**
* Includes all open elements.
*/
QMap<GCS::GElementID,GCS::GElement*> 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<GCS::GElementID,QDateTime> 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<GCS::GElementID> 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<GCS::GElementID> getChildren(const GCS::GElementID& parent) const;
virtual GCS::GElement* open(const GCS::GElementID& );
virtual GCS::GElement* getOpenElement(const GCS::GElementID& );
virtual const QValueList<GCS::GElementID> getListOfOpenElements();
virtual const QValueList<GCS::GElementID> 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
syntax highlighted by Code2HTML, v. 0.9.1