/*************************************************************************** * Copyright (C) 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. * ***************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include namespace GWE { // see GweFactoryOption in GWorldEngineFactory.h for details class FactoryOptionServerType : public GweFactoryOption { protected: QStringList PredefinedValues; public: FactoryOptionServerType(const QString& value = "advanced"); //virtual destructor can be empty, just needs to be present and virtual virtual ~FactoryOptionServerType(); virtual QStringList getPredefinedValues() const; virtual void updateTree(); }; FactoryOptionServerType::FactoryOptionServerType(const QString& value) : GweFactoryOption("gwe_controller",value,"The types of controller differ in the way they store the data and the communication between elements is implemented. All controllers should have the same logical behaviour though, so it doesn't make much difference in terms of elements behaviour which controller is chosen. But it will make a difference for the server infrastructure you want to use. The simple controller implements just a local GWE without any network or database capabilities. You also don't get persistent storage. The advanced controller on the other hand implements network communication and persistent data storage with a DBMS backend, it is thus suggested for larger simulations.") { PredefinedValues.append("simple"); PredefinedValues.append("advanced"); } FactoryOptionServerType::~FactoryOptionServerType() { } QStringList FactoryOptionServerType::getPredefinedValues() const { return PredefinedValues; } void FactoryOptionServerType::updateTree() { //@todo we should implement a removeAllExcept(QStringList options); QString v = getValue(); if (v == "simple") { this->deleteAllSubOptions(); //no further options } else if (v == "advanced") { if (!this->SubOptions.contains("xmpp_jid")) { this->SubOptions.insert("xmpp_jid",new GweFactoryOption( "xmpp_jid","user@universe.g-system.at","Set the JID (Jabber ID). The XML data controller uses the XMPP protocol and acts as a client to the XMPP/Jabber network. See http://www.xmpp.org and http://www.jabber.org for details. You have to register a JID with a Jabber client before using it here in the configuration.")); } if (!this->SubOptions.contains("xmpp_password")) { this->SubOptions.insert("xmpp_password",new GweFactoryOption( "xmpp_password","","Set the password for the selected XMPP JID.")); } if (!this->SubOptions.contains("init_network")) { this->SubOptions.insert("init_network",new GweFactoryOption( "init_network","yes","Whether to initialize network on GWE initialization or leave it for later. Possible values: yes, no.")); } if (!this->SubOptions.contains("master_server_jid")) { this->SubOptions.insert("master_server_jid",new GweFactoryOption( "master_server_jid","home@universe.g-system.at","The JID of any existing GWE Server of the server network. If it is empty then this server will act as a master server.")); } if (!this->SubOptions.contains("db_driver")) { bool no_drivers = false; QStringList drivers = QSqlDatabase::drivers(); QString used_driver = "NONE"; if (drivers.isEmpty()) no_drivers = true; else { if (drivers.contains("QSQLITE")) used_driver = "QSQLITE"; else used_driver = drivers.first(); } QString drivers_string; QStringList::iterator it; for (it = drivers.begin(); it != drivers.end(); ++it) { if (it != drivers.begin()) drivers_string.append(", "); drivers_string.append(*it); } this->SubOptions.insert("db_driver",new GweFactoryOption("db_driver",used_driver,QString("Available drivers: %1.").arg(drivers_string))); } if (!this->SubOptions.contains("db_name")) { QString default_db_name; if (this->getValueOfSubOption("db_driver") == "QSQLITE") { default_db_name = ":memory:"; } this->SubOptions.insert("db_name",new GweFactoryOption("db_name",default_db_name,"Database name. You can have pure in-memory DBs with QSQLITE driver and \":memory:\" as DB name.")); } if (!this->SubOptions.contains("db_host")) { this->SubOptions.insert("db_host",new GweFactoryOption("db_host","","The host on which the DBMS is running, leave empty for local connections.")); } if (!this->SubOptions.contains("db_port")) { this->SubOptions.insert("db_port",new GweFactoryOption("db_port","","The port on which the DBMS is listening, leave empty or set to 0 for default port.")); } if (!this->SubOptions.contains("db_username")) { this->SubOptions.insert("db_username",new GweFactoryOption("db_username","","Set the username to connect with to the selected database.")); } if (!this->SubOptions.contains("db_password")) { this->SubOptions.insert("db_password",new GweFactoryOption("db_password","","Set the password to connect with to the selected database. This password must fit to the user of course.")); } } qDebug(QString("gwe_controller option updated to ") + v); } //BEGIN GweFactoryOption void GweFactoryOption::deleteSubOption(const QString& option_name) { GweFactoryOption* option = SubOptions[option_name]; if (option) { SubOptions.remove(option_name); delete option; } } void GweFactoryOption::deleteAllSubOptions() { QMap::iterator it; for (it = SubOptions.begin(); it != SubOptions.end(); ++it) { delete (*it); } SubOptions.clear(); } GweFactoryOption::GweFactoryOption(const QString& option_name, const QString& value, const QString& description) : OptionName(option_name), Description(description), Value(value) { } GweFactoryOption::~GweFactoryOption() { deleteAllSubOptions(); } QString GweFactoryOption::getOptionName() const { return this->OptionName; } QString GweFactoryOption::getDescription() const { return this->Description; } QString GweFactoryOption::getValue() const { return this->Value; } QValueList GweFactoryOption::getSubOptions() const { return this->SubOptions.values(); } GweFactoryOption* GweFactoryOption::getSubOption(const QString& option_name) { return this->SubOptions[option_name]; } QString GweFactoryOption::getValueOfSubOption(const QString& option_name) { GweFactoryOption* o = this->getSubOption(option_name); if (o) return o->getValue(); return ""; } bool GweFactoryOption::hasPredefinedValues() const { return false; } QStringList GweFactoryOption::getPredefinedValues() const { return QStringList(); } void GweFactoryOption::updateTree() { } void GweFactoryOption::setValue(const QString& value) { this->Value = value; } void GweFactoryOption::setDescription(const QString& description) { this->Description = description; } void GweFactoryOption::loadFromXml(const QDomElement& options) { QString v; //used as value for XML tag names and attributes if (options.isElement()) { // never change the tag name // v = options.tagName(); // if (!v.isNull()) // this->OptionName = v; v = options.attribute("value",""); if (!v.isNull()) this->Value = v; v = options.attribute("desc",""); if (!v.isNull()) this->Description = v; } //We DO need to update the tree according to the value we have BECAUSE //we might have specialised sub options (missing suboptions are always //created as GweFactoryOption in this load routine) this->updateTree(); QDomElement child = options.firstChild().toElement(); GweFactoryOption* sub_option = NULL; while (!child.isNull() && child.isElement()) { v = child.tagName(); if (SubOptions.contains(v)) { sub_option = SubOptions[v]; } else { //actually, the question is whether we even want suboptions that are not present in the first place(?) qWarning(QString("Suboption ") + v + " is not present in factory option " + this->OptionName + " by default!"); sub_option = new GweFactoryOption(v); if (sub_option) this->SubOptions.insert(sub_option->getOptionName(),sub_option); } Q_CHECK_PTR(sub_option); sub_option->loadFromXml(child); child = child.nextSibling().toElement(); } } void GweFactoryOption::saveToXml(QDomElement storage) { storage.setTagName(this->OptionName); storage.setAttribute("value",this->Value); storage.setAttribute("desc",this->Description); if (!this->SubOptions.isEmpty()) { QMap::iterator it; QDomDocument doc = storage.ownerDocument(); for ( it = this->SubOptions.begin(); it != this->SubOptions.end(); ++it) { GweFactoryOption* sub_option = (*it); Q_CHECK_PTR(sub_option); QDomElement e = doc.createElement(sub_option->getOptionName()); e.setAttribute("value",sub_option->getValue()); e.setAttribute("desc",sub_option->getDescription()); storage.appendChild(e); sub_option->saveToXml(e); } } } void GweFactoryOption::setValueOfSubOption(const QString& sub_option_name, const QString& value) { GweFactoryOption* option = this->getSubOption(sub_option_name); if (option) option->setValue(value); } //END GweFactoryOption //BEGIN GWorldEngineFactory GWorldEngineFactory::GWorldEngineFactory(QObject *parent, const char *name) : QObject(parent, name), RootOption(new FactoryOptionServerType()) { } GWorldEngineFactory::~GWorldEngineFactory() { delete this->RootOption; } void GWorldEngineFactory::setDeleteControllersInDestructor(bool delete_in_destructor) { this->GweControllers.setAutoDelete(delete_in_destructor); } bool GWorldEngineFactory::getDeleteControllersInDestructor() const { return this->GweControllers.autoDelete(); } QPtrList GWorldEngineFactory::getInitializedControllers() { return this->GweControllers; } GweFactoryOption* GWorldEngineFactory::getRootOption() { return this->RootOption; } const GweFactoryOption* GWorldEngineFactory::getRootOption() const { return this->RootOption; } GweController* GWorldEngineFactory::init() { QMutexLocker lock(this); GweController* controller = NULL; QString controller_name = this->RootOption->getValue(); if (controller_name.isEmpty()) { QString msg = "No Controller name given, please set the \"gwe_controller\" option."; qWarning(msg); emit initFailed(msg); } else if (controller_name == "simple") { qDebug("factory: simple controller"); controller = new GweSimpleController(); Q_CHECK_PTR(controller); if (controller) { this->GweControllers.append(controller); qDebug("init of simple controller succeeded"); emit this->initSucceeded(controller); } else { QString msg = "Could not create GweSimpleController."; qWarning(msg); emit this->initFailed(msg); } } else if (controller_name == "advanced") { qDebug("factory: advanced controller"); QString jid = this->RootOption->getValueOfSubOption("xmpp_jid"); if (jid.isEmpty()) { QString msg = "XMPP network requires the xmpp_jid option to be set."; qWarning(msg); emit this->initFailed(msg); } else { GStorage* storage = new GStorage(); Q_CHECK_PTR(storage); QString db_driver = this->RootOption->getValueOfSubOption("db_driver"); QString db_name = this->RootOption->getValueOfSubOption("db_name"); QString db_host = this->RootOption->getValueOfSubOption("db_host"); int db_port = this->RootOption->getValueOfSubOption("db_port").toInt(); QString db_username = this->RootOption->getValueOfSubOption("db_username"); QString db_password = this->RootOption->getValueOfSubOption("db_password"); storage->setDatabase(db_driver,db_name,db_username,db_password,db_host,db_port); qDebug("Initializing database."); qDebug(QString(" Using database driver %1").arg(db_driver)); if (storage->connectDatabase()) { if (storage->initializeDatabase()) { qDebug("Database succesfully initialized."); qDebug("Creating network layer..."); qDebug(QString("factory: JID is set to %1").arg(jid)); if (!jid.contains("/")) { qWarning("JID does not contain a resource, adding standard resource \"GWE\"."); jid.append("/GWE"); } GXmlNetwork* network = new GXmppNetwork(jid); network->setPassword(this->RootOption->getValueOfSubOption("xmpp_password")); Q_CHECK_PTR(network); QString master = this->RootOption->getValueOfSubOption("master_server_jid"); if (!master.isEmpty() && !master.contains("/")) { qWarning("Master server JID does not contain a resource, adding resource \"GWE\"."); master.append("/GWE"); } qDebug("Creating data controller..."); GDataController* datacontroller = new GXmlDataController(storage,network,master); Q_CHECK_PTR(datacontroller); if (datacontroller) { controller = new GweAdvancedController(datacontroller); Q_CHECK_PTR(controller); if (controller) { this->GweControllers.append(controller); QString networkinit = this->RootOption->getValueOfSubOption("init_network"); if (networkinit == "yes") { qDebug("using single shot timer to initialize network shortly after setup"); QTimer::singleShot(100,network,SLOT(initNetwork())); qDebug("init of advanced controller with network succeeded, network init still pending"); emit this->initSucceeded(controller); } else { qDebug("init without network succeeded"); emit this->initSucceeded(controller); } } else { delete datacontroller; QString msg = "Could not create GweAdvancedController."; qWarning(msg); emit this->initFailed(msg); } } else { delete network; delete storage; QString msg = "Could not create GXmlDataController."; qWarning(msg); emit this->initFailed(msg); } } else { qWarning("Could not initialize database:"); QString error = storage->getLastDatabaseError(); qWarning(error); delete storage; storage=NULL; emit this->initFailed(error); } } else { qWarning("Could not connect database:"); QString error = storage->getLastDatabaseError(); qWarning(error); delete storage; storage=NULL; emit this->initFailed(error); } } } else { QString msg("Unknown controller name: "); msg.append(controller_name); qWarning(msg); emit this->initFailed(msg); } return controller; } GweController* GWorldEngineFactory::initDefault() { QMutexLocker lock(this); GweController* controller = new GweSimpleController(); Q_CHECK_PTR(controller); if (controller) { this->GweControllers.append(controller); qDebug("init with default settings succeeded"); emit this->initSucceeded(controller); } else { QString msg = "Could not create a GweSimpleController object!"; qWarning(msg); emit this->initFailed(msg); } return controller; } //END GWorldEngineFactory };