source: pacpusframework/trunk/src/PacpusLib/XmlConfigFile.cpp@ 282

Last change on this file since 282 was 280, checked in by Marek Kurdej, 11 years ago

Major: DbiteException uses boost::exception.

  • Property svn:executable set to *
File size: 12.1 KB
Line 
1// %pacpus:license{
2// This file is part of the PACPUS framework distributed under the
3// CECILL-C License, Version 1.0.
4// %pacpus:license}
5/// @version $Id: XmlConfigFile.cpp 76 2013-01-10 17:05:10Z kurdejma $
6
7#include <Pacpus/kernel/XmlConfigFile.h>
8
9#include <Pacpus/kernel/Log.h>
10#include <Pacpus/kernel/PacpusException.h>
11
12#include <cassert>
13#include <QFile>
14#include <QTextStream>
15
16////////////////////////////////////////////////////////////////////////////////
17
18using namespace pacpus;
19using namespace std;
20
21DECLARE_STATIC_LOGGER("pacpus.core.XmlConfigFile");
22
23XmlConfigFile * XmlConfigFile::m_xmlConfigFile = NULL;
24
25static const char * kXmlConfigFilename = "pacpus_config.xml";
26
27static const char * kRootSection = "pacpus";
28
29static const char * kComponentSection = "components";
30static const char * kConnectionSection = "connections";
31static const char * kParameterSection = "parameters";
32static const char * kPluginSection = "plugins";
33
34static const char * kComponentNode = "component";
35static const char * kConnectionNode = "connection";
36static const char * kParameterNode = "parameter";
37static const char * kPluginNode = "plugin";
38
39static const char * kNameAttribute = "name"; // <component name="MyComponent1" type="MyComponentType"/>
40static const char * kLibAttribute = "lib"; // <plugin lib="MyLibrary.dll"/>
41static const char * kExtensionAttribute = "extension"; // <parameter extension=".dll">
42static const char * kPrefixAttribute = "prefix"; // <parameter prefix="lib">
43static const char * kPostfixAttribute = "postfix"; // <parameter postfix="_d">
44
45////////////////////////////////////////////////////////////////////////////////
46// helper method
47QDomNode getNamedItemFromDomDocument(const QDomDocument & document, const char * itemName);
48
49////////////////////////////////////////////////////////////////////////////////
50
51// CTOR/DTOR
52XmlConfigFile::XmlConfigFile()
53 : m_numberOfComponents(0)
54{
55 LOG_TRACE("constructor");
56
57 // create the root of the XML tree
58 m_document.appendChild(m_document.createElement(kRootSection));
59 // create the sections
60 m_document.documentElement().appendChild(m_document.createElement(kParameterSection));
61 m_document.documentElement().appendChild(m_document.createElement(kPluginSection));
62 m_document.documentElement().appendChild(m_document.createElement(kComponentSection));
63 m_document.documentElement().appendChild(m_document.createElement(kConnectionSection));
64 m_file.setFileName(kXmlConfigFilename);
65 bool isOpenedSuccessfully = m_file.open(QIODevice::ReadWrite); // FIXME: ReadOnly ?
66 if (isOpenedSuccessfully) {
67 LOG_INFO("XML document " << kXmlConfigFilename << " was created");
68 } else {
69 LOG_ERROR("cannot open XML document " << kXmlConfigFilename);
70 BOOST_THROW_EXCEPTION(PacpusException("cannot open XML document file"));
71 }
72}
73
74XmlConfigFile::~XmlConfigFile()
75{
76 LOG_TRACE("destructor");
77}
78
79// CREATE/DESTROY
80XmlConfigFile * XmlConfigFile::create()
81{
82 if (NULL ==m_xmlConfigFile) {
83 m_xmlConfigFile = new XmlConfigFile();
84 }
85 return m_xmlConfigFile;
86}
87
88void XmlConfigFile::destroy()
89{
90 delete m_xmlConfigFile;
91 m_xmlConfigFile = NULL;
92}
93
94// COMPONENTS ADD/REMOVE/CREATE
95void XmlConfigFile::addComponent(QDomElement component)
96{
97 QMutexLocker mutexLocker(&m_mutex); // locks mutex, unlocks it in destructor
98 (void) mutexLocker; // unused
99
100 // TODO: change .tagName => .attribute(kPropertyComponentName)
101 QDomNode componentSectionNode = getNamedItemFromDomDocument(m_document, kComponentSection);
102 if (componentSectionNode.namedItem(component.attribute(kNameAttribute)/*.tagName()*/).isNull()) {
103 LOG_WARN("component " << component.attribute(kNameAttribute)/*tagName()*/ << " exists already in the document");
104 } else {
105 QDomNode node = getNamedItemFromDomDocument(m_document, kComponentSection).appendChild(component);
106 ++m_numberOfComponents;
107 LOG_INFO("component " << node.nodeName() << " has been added to the section "
108 << getNamedItemFromDomDocument(m_document, kComponentSection).nodeName());
109 }
110}
111
112void XmlConfigFile::delComponent(QDomElement component)
113{
114 removeComponent(component);
115}
116
117void XmlConfigFile::removeComponent(QDomElement component)
118{
119 QMutexLocker mutexLocker(&m_mutex); // locks mutex, unlocks it in destructor
120 (void) mutexLocker; // unused
121
122 QDomNode node = getNamedItemFromDomDocument(m_document, kComponentSection).removeChild(component);
123 if (node.isNull()) {
124 LOG_WARN("component " << component.attribute(kNameAttribute)/*tagName()*/ << " doesn't exist in the document.");
125 } else {
126 LOG_INFO("component " << node.nodeName() << " has been removed from the section "
127 << getNamedItemFromDomDocument(m_document, kComponentSection).nodeName());
128 --m_numberOfComponents;
129 }
130}
131
132QDomElement XmlConfigFile::createComponent(QString name)
133{
134 LOG_DEBUG("creating component " << name);
135
136 QMutexLocker mutexLocker(&m_mutex); // locks mutex, unlocks it in destructor
137 (void) mutexLocker; // unused
138 return m_document.createElement(name);
139}
140
141// FILE I/O
142void XmlConfigFile::saveFile(QString fileName)
143{
144 QMutexLocker mutexLocker(&m_mutex);
145 (void) mutexLocker; // unused
146
147 m_file.close();
148 assert(!m_file.isOpen());
149 m_file.setFileName(fileName);
150 {
151 // open file
152 bool isOpenedSuccessfully = m_file.open(QIODevice::WriteOnly);
153 if (!isOpenedSuccessfully) {
154 LOG_ERROR("cannot open file '" << m_file.fileName() << "' for writing");
155 return;
156 }
157 QTextStream ts(&m_file);
158 ts << "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n";
159 ts << m_document.toString();
160 m_file.close();
161 }
162 LOG_DEBUG("file \"" << m_file.fileName() << "\" has been saved");
163}
164
165int XmlConfigFile::loadFile(QString fileName)
166{
167 // lock access
168 QMutexLocker mutexLocker(&m_mutex);
169 (void) mutexLocker; // unused
170
171 // check if there are components already
172 if (0 != m_numberOfComponents) {
173 LOG_WARN("XML document contained " << m_numberOfComponents << " components that will be lost!");
174 }
175
176 m_file.close();
177 assert(!m_file.isOpen());
178 m_file.setFileName(fileName);
179 {
180 // open file
181 bool isOpenedSuccessfully = m_file.open(QIODevice::ReadOnly);
182 if (!isOpenedSuccessfully) {
183 LOG_ERROR("cannot open file '" << m_file.fileName() << "' for reading");
184 return 0;
185 }
186 // read and parse input XML file
187 QString errorMsg;
188 int errorLine = 0;
189 int errorColumn = 0;
190 if (!m_document.setContent(&m_file, /*namespaceProcessing=*/true, &errorMsg, &errorLine, &errorColumn)) {
191 LOG_ERROR("cannot parse XML file " << m_file.fileName());
192 LOG_ERROR(errorMsg << " at " << errorLine << ":" << errorColumn << " (line:col)");
193 m_file.close();
194 return 0;
195 }
196 // close file
197 m_file.close();
198 }
199
200 // get the number of components in the loaded tree
201 m_numberOfComponents = getAllComponents().count();
202
203 LOG_INFO("XML file \"" << m_file.fileName() << "\" has been loaded. Number of components = " << m_numberOfComponents);
204 LOG_DEBUG("XML file content:\n"
205 << "BEGIN============================================================================\n"
206 << m_document.toString()
207 << "END==============================================================================\n"
208 );
209
210 return m_numberOfComponents;
211}
212
213// XML
214QDomElement XmlConfigFile::getSection(const char * name) const
215{
216 QDomElement sectionElement = getNamedItemFromDomDocument(m_document, name).toElement();
217 if (sectionElement.isNull()) {
218 LOG_WARN("there is no '" << name << "' section in the XML");
219 return QDomElement();
220 }
221 return sectionElement;
222}
223
224QDomNodeList XmlConfigFile::getNodesInSection(const char * sectionName, const char * nodeName) const
225{
226 QDomElement sectionElement = getSection(sectionName);
227 return sectionElement.elementsByTagName(nodeName);
228}
229
230// COMPONENTS
231QDomNodeList XmlConfigFile::getAllComponents() const
232{
233 return getNodesInSection(kComponentSection, kComponentNode);
234}
235
236QStringList XmlConfigFile::getAllComponentsNames() const
237{
238 // get component nodes
239 QDomNodeList componentNodes = getAllComponents();
240 // get component names
241 QStringList componentNameList;
242 for (int i = 0; i < componentNodes.size(); ++i) {
243 QDomElement componentElement = componentNodes.at(i).toElement();
244 componentNameList.append(componentElement.attribute(kNameAttribute));
245 }
246 return componentNameList;
247}
248
249QDomElement XmlConfigFile::getComponent(QString componentName) const
250{
251 LOG_DEBUG("getting component " << componentName);
252
253 QDomNodeList componentNodes = getAllComponents();
254 for (int i = 0; i < componentNodes.size(); ++i) {
255 QDomElement componentElement = componentNodes.at(i).toElement();
256 if (componentName == componentElement.attribute(kNameAttribute)) {
257 return componentElement;
258 }
259 }
260 LOG_WARN("cannot get component " << componentName << ": document does not contain a component with this name");
261
262 return QDomElement();
263}
264
265// CONNECTIONS
266QDomNodeList XmlConfigFile::getAllConnections() const
267{
268 return getNodesInSection(kConnectionSection, kConnectionNode);
269}
270
271QDomElement XmlConfigFile::getConnection(QString name) const
272{
273 LOG_DEBUG("getting connection " << name);
274
275 QDomNodeList connectionNodes = getAllConnections();
276 for (int i = 0; i < connectionNodes.size(); ++i) {
277 QDomElement connectionElement = connectionNodes.at(i).toElement();
278 // TODO: name by attribute 'name'
279 if (name == connectionElement.attribute(kNameAttribute)) {
280 return connectionElement;
281 }
282 }
283 LOG_WARN("cannot get connection " << name << ": document does not contain a connection with this name");
284
285 return QDomElement();
286}
287
288// PARAMETERS
289QDomNodeList XmlConfigFile::getAllParameters() const
290{
291 return getNodesInSection(kParameterSection, kParameterNode);
292}
293
294// PLUGINS
295QDomNodeList XmlConfigFile::getAllPlugins()
296{
297 // get section
298 QDomElement pluginsElement = getSection(kPluginSection);
299
300 // get attributes
301 m_libraryExtension = pluginsElement.attribute(kExtensionAttribute);
302 if (!m_libraryExtension.isEmpty()) {
303 // prefix with a dot '.' if there is no one
304 if ('.' != m_libraryExtension.at(0)) {
305 m_libraryExtension = '.' + m_libraryExtension;
306 }
307 }
308 m_libraryPrefix = pluginsElement.attribute(kPrefixAttribute);
309 m_libraryPostfix = pluginsElement.attribute(kPostfixAttribute);
310
311 // get nodes
312 return getNodesInSection(kPluginSection, kPluginNode);
313}
314
315QStringList XmlConfigFile::getAllPluginsNames()
316{
317 QDomNodeList pluginList = getAllPlugins();
318 if (0 == pluginList.size()) {
319 LOG_ERROR("no plugins were specified");
320 return QStringList();
321 }
322 LOG_INFO("there are " << pluginList.size() << " plugins");
323
324 // get plugin library paths
325 QStringList pluginLibraryNames;
326 for (int i = 0; i < pluginList.size(); ++i) {
327 QDomElement pluginElement = pluginList.at(i).toElement();
328 QString libraryFileName = libraryPrefix() + pluginElement.attribute(kLibAttribute) + libraryPostfix() + libraryExtension();
329 pluginLibraryNames.append(libraryFileName);
330 }
331 return pluginLibraryNames;
332}
333
334QString XmlConfigFile::libraryExtension() const
335{
336 return m_libraryExtension;
337}
338
339QString XmlConfigFile::libraryPrefix() const
340{
341 return m_libraryPrefix;
342}
343
344QString XmlConfigFile::libraryPostfix() const
345{
346 return m_libraryPostfix;
347}
348
349////////////////////////////////////////////////////////////////////////////////
350// HELPER METHODS
351QDomNode getNamedItemFromDomDocument(const QDomDocument & document, const char * itemName)
352{
353 return document.documentElement().namedItem(itemName);
354}
Note: See TracBrowser for help on using the repository browser.