1 // Object Viewer Qt - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2011 Dzmitry KAMIAHIN (dnk-88) <dnk-88@tut.by>
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2010 Winch Gate Property Limited
6 // Copyright (C) 2014 Laszlo KIS-ADAM (dfighter) <dfighter1985@gmail.com>
8 // This program is free software: you can redistribute it and/or modify
9 // it under the terms of the GNU Affero General Public License as
10 // published by the Free Software Foundation, either version 3 of the
11 // License, or (at your option) any later version.
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU Affero General Public License for more details.
18 // You should have received a copy of the GNU Affero General Public License
19 // along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "plugin_spec.h"
24 #include "iplugin_manager.h"
26 #include "nel/misc/app_context.h"
27 #include "nel/misc/debug.h"
30 #include <QtCore/QList>
31 #include <QtCore/QFile>
32 #include <QtCore/QFileInfo>
33 #include <QtCore/QPluginLoader>
34 #include <QtCore/QCoreApplication>
40 #ifdef HAVE_OVQT_CONFIG_H
41 #include "ovqt_config.h"
44 namespace ExtensionSystem
46 const char *const PLUGIN_SPEC_NAME
= "name";
47 const char *const PLUGIN_SPEC_VENDOR
= "vendor";
48 const char *const PLUGIN_SPEC_VERSION
= "version";
49 const char *const PLUGIN_SPEC_LIBRARY_NAME
= "library-name";
50 const char *const PLUGIN_SPEC_DESCRIPTION
= "description";
51 const char *const PLUGIN_SPEC_DEPENDENCIES
= "dependencies";
52 const char *const PLUGIN_SPEC_DEPENDENCY
= "dependency";
53 const char *const PLUGIN_SPEC_DEPENDENCY_NAME
= "plugin-name";
54 const char *const PLUGIN_SPEC_DEPENDENCY_VERSION
= "version";
56 PluginSpec::PluginSpec()
66 m_state(State::Invalid
),
68 m_enabledStartup(true),
74 // Compilation mode specific suffixes
76 # if defined(NL_DEBUG)
78 # elif defined(NL_RELEASE)
81 # error "Unknown compilation mode, can't build suffix"
83 #elif defined (NL_OS_UNIX)
87 # error "You must define the lib suffix for your platform"
92 PluginSpec::~PluginSpec()
98 QString
PluginSpec::name() const
103 QString
PluginSpec::version() const
108 QString
PluginSpec::vendor() const
113 QString
PluginSpec::description() const
115 return m_description
;
118 QString
PluginSpec::location() const
123 QString
PluginSpec::filePath() const
128 QString
PluginSpec::fileName() const
133 IPlugin
*PluginSpec::plugin() const
138 int PluginSpec::state() const
143 bool PluginSpec::hasError() const
148 QString
PluginSpec::errorString() const
150 return m_errorString
;
153 QList
<PluginSpec
*> PluginSpec::dependencySpecs() const
155 return m_dependencySpecs
;
158 bool PluginSpec::setFileName(const QString
&fileName
)
160 m_fileName
= m_prefix
+ fileName
+ m_suffix
;
161 m_filePath
= m_location
+ "/" + m_fileName
;
164 file
.setFileName(m_filePath
);
166 bool exists
= file
.exists();
173 // if plugin can't be found in the same directory as spec file,
174 // looks for it in PLUGINS_DIR
175 m_filePath
= QString("%1/%2").arg(PLUGINS_DIR
).arg(m_fileName
);
177 file
.setFileName(m_filePath
);
179 exists
= file
.exists();
186 // if plugin can't be found in the same directory as spec file or PLUGINS_DIR,
187 // looks for it in NL_LIB_PREFIX
188 m_filePath
= QString("%1/%2").arg(NL_LIB_PREFIX
).arg(m_fileName
);
190 file
.setFileName(m_filePath
);
192 exists
= file
.exists();
198 nlinfo(m_filePath
.toUtf8().constData());
201 return reportError(QCoreApplication::translate("PluginSpec", "File does not exist: %1").arg(file
.fileName()));
202 if (!file
.open(QIODevice::ReadOnly
))
203 return reportError(QCoreApplication::translate("PluginSpec", "Could not open file for read: %1").arg(file
.fileName()));
207 bool PluginSpec::setSpecFileName(const QString
&specFileName
)
209 m_nameSpecFile
= specFileName
;
211 QFile
file(specFileName
);
213 return reportError(QCoreApplication::translate("PluginSpec", "Spec file does not exist: %1").arg(file
.fileName()));
215 QFileInfo
fileInfo(file
);
216 m_location
= fileInfo
.absolutePath();
221 bool PluginSpec::readSpec()
223 QFile
file(m_nameSpecFile
);
224 if (!file
.open(QIODevice::ReadOnly
| QIODevice::Text
))
225 return reportError(QCoreApplication::translate("PluginSpec", "Could not open spec file for read: %1").arg(file
.fileName()));
227 QXmlStreamReader
reader(&file
);
228 while (!reader
.atEnd())
230 if (reader
.isStartElement())
234 if (reader
.hasError())
235 return reportError(QCoreApplication::translate("PluginSpec", "Error parsing file %1: %2, at line %3, column %4")
236 .arg(file
.fileName())
237 .arg(reader
.errorString())
238 .arg(reader
.lineNumber())
239 .arg(reader
.columnNumber()));
240 m_state
= State::Read
;
244 void PluginSpec::parseSpec(QXmlStreamReader
&reader
)
246 QString elemName
= reader
.name().toString();
248 if (reader
.isCharacters())
250 QString elemText
= reader
.text().toString();
251 if (elemName
== PLUGIN_SPEC_LIBRARY_NAME
)
252 setFileName(elemText
);
253 if (elemName
== PLUGIN_SPEC_NAME
)
255 if (elemName
== PLUGIN_SPEC_VERSION
)
256 m_version
= elemText
;
257 if (elemName
== PLUGIN_SPEC_VENDOR
)
259 if (elemName
== PLUGIN_SPEC_DESCRIPTION
)
260 m_description
= elemText
;
261 if (elemName
== PLUGIN_SPEC_DEPENDENCIES
)
262 parseDependency(reader
);
266 void PluginSpec::parseDependency(QXmlStreamReader
&reader
)
269 while (!reader
.atEnd() && (elemName
!= PLUGIN_SPEC_DEPENDENCIES
))
272 elemName
= reader
.name().toString();
273 if (reader
.isStartElement() && (elemName
== PLUGIN_SPEC_DEPENDENCY
))
275 // Read name dependency plugin
276 QString dependencyName
= reader
.attributes().value(PLUGIN_SPEC_DEPENDENCY_NAME
).toString();
277 if (dependencyName
.isEmpty())
279 reader
.raiseError(QCoreApplication::translate("CPluginSpec", "'%1' misses attribute '%2'")
280 .arg(PLUGIN_SPEC_DEPENDENCY
)
281 .arg(PLUGIN_SPEC_DEPENDENCY_NAME
));
284 // TODO: Read version dependency plugin
285 QString dependencyVersion
= reader
.attributes().value(PLUGIN_SPEC_DEPENDENCY_VERSION
).toString();
287 m_dependencies
.push_back(dependencyName
);
292 void PluginSpec::setEnabled(bool enabled
)
297 bool PluginSpec::isEnabled() const
302 bool PluginSpec::loadLibrary()
304 nlassert( loader
== NULL
);
308 if (m_state
!= State::Resolved
)
310 if (m_state
== State::Loaded
)
312 return reportError(QCoreApplication::translate("PluginSpec", "Loading the library failed because state != Resolved"));
315 loader
= new QPluginLoader( m_filePath
);
317 return reportError(loader
->errorString());
319 IPlugin
*pluginObject
= qobject_cast
<IPlugin
*>(loader
->instance());
325 return reportError(QCoreApplication::translate("PluginSpec", "Plugin is not valid (does not derive from IPlugin)"));
328 pluginObject
->setNelContext(&NLMISC::INelContext::getInstance());
330 m_state
= State::Loaded
;
331 m_plugin
= pluginObject
;
335 bool PluginSpec::resolveDependencies(const QList
<PluginSpec
*> &specs
)
339 if (m_state
!= State::Read
)
341 m_errorString
= QCoreApplication::translate("PluginSpec", "Resolving dependencies failed because state != Read");
345 QList
<PluginSpec
*> resolvedDependencies
;
346 Q_FOREACH(const QString
&dependency
, m_dependencies
)
348 PluginSpec
*found
= 0;
350 Q_FOREACH(PluginSpec
*spec
, specs
)
352 if (QString::compare(dependency
, spec
->name(), Qt::CaseInsensitive
) == 0)
361 if (!m_errorString
.isEmpty())
362 m_errorString
.append(QLatin1Char('\n'));
363 m_errorString
.append(QCoreApplication::translate("PluginSpec", "Could not resolve dependency '%1'")
367 resolvedDependencies
.append(found
);
372 m_dependencySpecs
= resolvedDependencies
;
373 m_state
= State::Resolved
;
377 bool PluginSpec::initializePlugin()
381 if (m_state
!= State::Loaded
)
383 if (m_state
== State::Initialized
)
385 return reportError(QCoreApplication::translate("PluginSpec", "Initializing the plugin failed because state != Loaded)"));
388 return reportError(QCoreApplication::translate("PluginSpec", "Internal error: have no plugin instance to initialize"));
391 if (!m_plugin
->initialize(m_pluginManager
, &err
))
392 return reportError(QCoreApplication::translate("PluginSpec", "Plugin initialization failed: %1").arg(err
));
394 m_state
= State::Initialized
;
398 bool PluginSpec::initializeExtensions()
402 if (m_state
!= State::Initialized
)
404 if (m_state
== State::Running
)
406 return reportError(QCoreApplication::translate("PluginSpec", "Cannot perform extensionsInitialized because state != Initialized"));
409 return reportError(QCoreApplication::translate("PluginSpec", "Internal error: have no plugin instance to perform extensionsInitialized"));
411 m_plugin
->extensionsInitialized();
412 m_state
= State::Running
;
416 void PluginSpec::stop()
420 m_plugin
->shutdown();
421 m_state
= State::Stopped
;
424 void PluginSpec::kill()
429 bool b
= loader
->unload();
432 nlinfo( "Plugin %s couldn't be unloaded.", this->m_name
.toAscii().data() );
439 m_state
= State::Deleted
;
442 void PluginSpec::setEnabledStartup(bool enabled
)
444 m_enabledStartup
= enabled
;
447 bool PluginSpec::isEnabledStartup() const
449 return m_enabledStartup
;
452 bool PluginSpec::reportError(const QString
&err
)
459 } // namespace ExtensionSystem