// %pacpus:license{ // This file is part of the PACPUS framework distributed under the // CECILL-C License, Version 1.0. // %pacpus:license} /// @version $Id: XmlConfigFile.cpp 76 2013-01-10 17:05:10Z kurdejma $ #include #include #include #include //////////////////////////////////////////////////////////////////////////////// using namespace pacpus; using namespace std; DECLARE_STATIC_LOGGER("pacpus.core.XmlConfigFile"); XmlConfigFile * XmlConfigFile::m_xmlConfigFile = NULL; static const char * kXmlConfigFilename = "pacpus_config.xml"; static const char * kRootSection = "pacpus"; static const char * kComponentSection = "components"; static const char * kConnectionSection = "connections"; static const char * kParameterSection = "parameters"; static const char * kComponentNode = "component"; static const char * kConnectionNode = "connection"; static const char * kPluginNode = "plugin"; static const char * kNameAttribute = "name"; // static const char * kLibAttribute = "lib"; // static const char * kExtensionAttribute = "extension"; // static const char * kPrefixAttribute = "prefix"; // static const char * kPostfixAttribute = "postfix"; // //////////////////////////////////////////////////////////////////////////////// // helper method QDomNode getNamedItemFromDomDocument(const QDomDocument & document, const char * itemName); //////////////////////////////////////////////////////////////////////////////// // CTOR/DTOR XmlConfigFile::XmlConfigFile() : m_numberOfComponents(0) { LOG_TRACE("constructor"); // create the root of the XML tree m_document.appendChild(m_document.createElement(kRootSection)); // create the sections m_document.documentElement().appendChild(m_document.createElement(kParameterSection)); m_document.documentElement().appendChild(m_document.createElement(kComponentSection)); m_document.documentElement().appendChild(m_document.createElement(kConnectionSection)); m_file.setFileName(kXmlConfigFilename); bool isOpenedSuccessfully = m_file.open(QIODevice::ReadWrite); // FIXME: ReadOnly ? if (isOpenedSuccessfully) { LOG_INFO("XML document " << kXmlConfigFilename << " was created"); } else { LOG_ERROR("cannot open XML document " << kXmlConfigFilename); throw "cannot open XML document file"; } } XmlConfigFile::~XmlConfigFile() { LOG_TRACE("destructor"); } // CREATE/DESTROY XmlConfigFile * XmlConfigFile::create() { if (NULL ==m_xmlConfigFile) { m_xmlConfigFile = new XmlConfigFile(); } return m_xmlConfigFile; } void XmlConfigFile::destroy() { delete m_xmlConfigFile; m_xmlConfigFile = NULL; } // COMPONENTS ADD/REMOVE/CREATE void XmlConfigFile::addComponent(QDomElement component) { QMutexLocker mutexLocker(&m_mutex); // locks mutex, unlocks it in destructor (void) mutexLocker; // unused // TODO: change .tagName => .attribute(kPropertyComponentName.c_str()) QDomNode componentSectionNode = getNamedItemFromDomDocument(m_document, kComponentSection); if (componentSectionNode.namedItem(component.attribute(kNameAttribute)/*.tagName()*/).isNull()) { LOG_WARN("component " << component.attribute(kNameAttribute)/*tagName()*/ << " exists already in the document"); } else { QDomNode node = getNamedItemFromDomDocument(m_document, kComponentSection).appendChild(component); ++m_numberOfComponents; LOG_INFO("component " << node.nodeName() << " has been added to the section " << getNamedItemFromDomDocument(m_document, kComponentSection).nodeName()); } } void XmlConfigFile::delComponent(QDomElement component) { removeComponent(component); } void XmlConfigFile::removeComponent(QDomElement component) { QMutexLocker mutexLocker(&m_mutex); // locks mutex, unlocks it in destructor (void) mutexLocker; // unused QDomNode node = getNamedItemFromDomDocument(m_document, kComponentSection).removeChild(component); if (node.isNull()) { LOG_WARN("component " << component.attribute(kNameAttribute)/*tagName()*/ << " doesn't exist in the document."); } else { LOG_INFO("component " << node.nodeName() << " has been removed from the section " << getNamedItemFromDomDocument(m_document, kComponentSection).nodeName()); --m_numberOfComponents; } } QDomElement XmlConfigFile::createComponent(QString name) { LOG_DEBUG("creating component " << name); QMutexLocker mutexLocker(&m_mutex); // locks mutex, unlocks it in destructor (void) mutexLocker; // unused return m_document.createElement(name); } // FILE I/O void XmlConfigFile::saveFile(QString fileName) { QMutexLocker mutexLocker(&m_mutex); (void) mutexLocker; // unused m_file.close(); assert(!m_file.isOpen()); m_file.setFileName(fileName); { // open file bool isOpenedSuccessfully = m_file.open(QIODevice::WriteOnly); if (!isOpenedSuccessfully) { LOG_ERROR("cannot open file '" << m_file.fileName() << "' for writing"); return; } QTextStream ts(&m_file); ts << "\n"; ts << m_document.toString(); m_file.close(); } LOG_DEBUG("file \"" << m_file.fileName() << "\" has been saved"); } int XmlConfigFile::loadFile(QString fileName) { // lock access QMutexLocker mutexLocker(&m_mutex); (void) mutexLocker; // unused // check if there are components already if (0 != m_numberOfComponents) { LOG_WARN("XML document contained " << m_numberOfComponents << " components that will be lost!"); } m_file.close(); assert(!m_file.isOpen()); m_file.setFileName(fileName); { // open file bool isOpenedSuccessfully = m_file.open(QIODevice::ReadOnly); if (!isOpenedSuccessfully) { LOG_ERROR("cannot open file '" << m_file.fileName() << "' for reading"); return 0; } // read and parse input XML file QString errorMsg; int errorLine = 0; int errorColumn = 0; if (!m_document.setContent(&m_file, /*namespaceProcessing=*/true, &errorMsg, &errorLine, &errorColumn)) { LOG_ERROR("cannot parse XML file " << m_file.fileName()); LOG_ERROR(errorMsg << " at " << errorLine << ":" << errorColumn << " (line:col)"); m_file.close(); return 0; } // close file m_file.close(); } // get the number of components in the loaded tree m_numberOfComponents = getAllComponents().count(); LOG_INFO("XML file \"" << m_file.fileName() << "\" has been loaded. Number of components = " << m_numberOfComponents); LOG_DEBUG("XML file content:\n" << "BEGIN============================================================================\n" << m_document.toString() << "END==============================================================================\n" ); return m_numberOfComponents; } // COMPONENTS QDomNodeList XmlConfigFile::getAllComponents() const { // get components section QDomElement componentsElement = getNamedItemFromDomDocument(m_document, kComponentSection).toElement(); if (componentsElement.isNull()) { LOG_WARN("there is no '" << kComponentSection << "' section in the XML"); return QDomNodeList(); } // get component nodes return componentsElement.elementsByTagName(kComponentNode); } QStringList XmlConfigFile::getAllComponentsNames() const { // get component nodes QDomNodeList componentNodes = getAllComponents(); // get component names QStringList componentNameList; for (int i = 0; i < componentNodes.size(); ++i) { QDomElement componentElement = componentNodes.at(i).toElement(); componentNameList.append(componentElement.attribute(kNameAttribute)); } return componentNameList; } QDomElement XmlConfigFile::getComponent(QString componentName) const { LOG_DEBUG("getting component " << componentName); QDomNodeList componentNodes = getAllComponents(); for (int i = 0; i < componentNodes.size(); ++i) { QDomElement componentElement = componentNodes.at(i).toElement(); if (componentName == componentElement.attribute(kNameAttribute)) { return componentElement; } } LOG_WARN("cannot get component " << componentName << ": document does not contain a component with this name"); return QDomElement(); } // CONNECTIONS QDomNodeList XmlConfigFile::getAllConnections() const { // get connections section QDomElement connectionsElement = getNamedItemFromDomDocument(m_document, kParameterSection).toElement(); if (connectionsElement.isNull()) { LOG_WARN("there is no '" << kParameterSection << "' section in the XML"); return QDomNodeList(); } // get connection nodes //return connectionsElement.elementsByTagName(kConnectionNode); return getNamedItemFromDomDocument(m_document, kConnectionSection).childNodes(); } QDomElement XmlConfigFile::getConnection(QString name) const { LOG_DEBUG("getting connection " << name); QDomNodeList connectionNodes = getAllConnections(); for (int i = 0; i < connectionNodes.size(); ++i) { QDomElement connectionElement = connectionNodes.at(i).toElement(); // TODO: name by attribute 'name' if (name == connectionElement.attribute(kNameAttribute)) { return connectionElement; } } LOG_WARN("cannot get connection " << name << ": document does not contain a connection with this name"); return QDomElement(); } // PLUGINS QDomNodeList XmlConfigFile::getAllPlugins() { // get parameters section QDomElement parametersElement = getNamedItemFromDomDocument(m_document, kParameterSection).toElement(); if (parametersElement.isNull()) { LOG_WARN("there is no '" << kParameterSection << "' section in the XML"); return QDomNodeList(); } // get attributes m_libraryExtension = parametersElement.attribute(kExtensionAttribute); if (!m_libraryExtension.isEmpty()) { // prefix with a dot '.' if there is no one if ('.' != m_libraryExtension.at(0)) { m_libraryExtension = '.' + m_libraryExtension; } } m_libraryPrefix = parametersElement.attribute(kPrefixAttribute); m_libraryPostfix = parametersElement.attribute(kPostfixAttribute); // get plugin nodes return parametersElement.elementsByTagName(kPluginNode); } QStringList XmlConfigFile::getAllPluginsNames() { QDomNodeList pluginList = getAllPlugins(); if (0 == pluginList.size()) { LOG_ERROR("no plugins were specified"); return QStringList(); } // get plugin library paths QStringList pluginLibraryNames; for (int i = 0; i < pluginList.size(); ++i) { QDomElement pluginElement = pluginList.at(i).toElement(); QString libraryFileName = libraryPrefix() + pluginElement.attribute(kLibAttribute) + libraryPostfix() + libraryExtension(); pluginLibraryNames.append(libraryFileName); } return pluginLibraryNames; } QString XmlConfigFile::libraryExtension() const { return m_libraryExtension; } QString XmlConfigFile::libraryPrefix() const { return m_libraryPrefix; } QString XmlConfigFile::libraryPostfix() const { return m_libraryPostfix; } //////////////////////////////////////////////////////////////////////////////// // HELPER METHODS QDomNode getNamedItemFromDomDocument(const QDomDocument & document, const char * itemName) { return document.documentElement().namedItem(itemName); }