mirror of
https://github.com/swift-project/pilotclient.git
synced 2026-04-14 08:45:36 +08:00
refs #442 Add CPluginManager class
This commit is contained in:
committed by
Mathew Sutcliffe
parent
25cdff54f3
commit
2c55fe2306
@@ -13,6 +13,7 @@
|
|||||||
#include "context_settings.h"
|
#include "context_settings.h"
|
||||||
#include "context_application.h"
|
#include "context_application.h"
|
||||||
#include "context_network_impl.h"
|
#include "context_network_impl.h"
|
||||||
|
#include "plugin_manager.h"
|
||||||
#include "context_runtime.h"
|
#include "context_runtime.h"
|
||||||
#include "blackcore/blackcorefreefunctions.h"
|
#include "blackcore/blackcorefreefunctions.h"
|
||||||
#include "blackmisc/propertyindexvariantmap.h"
|
#include "blackmisc/propertyindexvariantmap.h"
|
||||||
@@ -53,21 +54,12 @@ namespace BlackCore
|
|||||||
|
|
||||||
if (!plugin->factory)
|
if (!plugin->factory)
|
||||||
{
|
{
|
||||||
QPluginLoader loader(plugin->fileName);
|
CPluginManager *pm = CPluginManager::getInstance();
|
||||||
QObject *instance = loader.instance();
|
ISimulatorFactory *factory = qobject_cast<ISimulatorFactory *>(pm->getPluginById(plugin->identifier));
|
||||||
if (instance)
|
if (factory)
|
||||||
{
|
{
|
||||||
ISimulatorFactory *factory = qobject_cast<ISimulatorFactory *>(instance);
|
plugin->factory = factory;
|
||||||
if (factory)
|
CLogMessage(this).info("Loaded driver: %1") << plugin->info.toQString();
|
||||||
{
|
|
||||||
plugin->factory = factory;
|
|
||||||
CLogMessage(this).info("Loaded driver: %1") << plugin->info.toQString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
QString errorMsg = loader.errorString().append(" ").append("Also check if required dll/libs of plugin exists");
|
|
||||||
CLogMessage(this).error(errorMsg);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -692,39 +684,25 @@ namespace BlackCore
|
|||||||
|
|
||||||
void CContextSimulator::findSimulatorPlugins()
|
void CContextSimulator::findSimulatorPlugins()
|
||||||
{
|
{
|
||||||
const QString path = qApp->applicationDirPath().append("/plugins/simulator");
|
CPluginManager *pm = CPluginManager::getInstance();
|
||||||
m_pluginsDir = QDir(path);
|
auto plugins = pm->plugins("org.swift-project.blackcore.simulatorinterface");
|
||||||
if (!m_pluginsDir.exists())
|
|
||||||
{
|
|
||||||
CLogMessage(this).error("No plugin directory: %1") << m_pluginsDir.currentPath();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
QStringList fileNames = m_pluginsDir.entryList(QDir::Files);
|
std::for_each(plugins.begin(), plugins.end(), [this](const QJsonObject &json)
|
||||||
fileNames.sort(Qt::CaseInsensitive); // give a certain order, rather than random file order
|
|
||||||
for (const auto &fileName : fileNames)
|
|
||||||
{
|
{
|
||||||
if (!QLibrary::isLibrary(fileName))
|
QString identifier = json.value("MetaData").toObject().value("identifier").toString();
|
||||||
|
Q_ASSERT(!identifier.isEmpty());
|
||||||
|
CSimulatorPluginInfo info;
|
||||||
|
info.convertFromJson(json);
|
||||||
|
if (info.isValid())
|
||||||
{
|
{
|
||||||
continue;
|
m_simulatorPlugins << PluginData { info, nullptr, nullptr, nullptr, identifier };
|
||||||
}
|
CLogMessage(this).debug() << "Found simulator driver: " << info.toQString();
|
||||||
|
|
||||||
CLogMessage(this).debug() << "Try to load plugin: " << fileName;
|
|
||||||
QString pluginPath = m_pluginsDir.absoluteFilePath(fileName);
|
|
||||||
QPluginLoader loader(pluginPath);
|
|
||||||
QJsonObject json = loader.metaData();
|
|
||||||
CSimulatorPluginInfo simulatorPluginInfo;
|
|
||||||
simulatorPluginInfo.convertFromJson(json);
|
|
||||||
if (simulatorPluginInfo.isValid())
|
|
||||||
{
|
|
||||||
m_simulatorPlugins << PluginData { simulatorPluginInfo, nullptr, nullptr, nullptr, pluginPath};
|
|
||||||
CLogMessage(this).debug() << "Found simulator driver: " << simulatorPluginInfo.toQString();
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
CLogMessage(this).warning("Simulator driver in %1 is invalid") << pluginPath;
|
CLogMessage(this).warning("Simulator driver in %1 is invalid") << identifier;
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void CContextSimulator::stopSimulatorListeners()
|
void CContextSimulator::stopSimulatorListeners()
|
||||||
|
|||||||
@@ -182,14 +182,14 @@ namespace BlackCore
|
|||||||
//! \todo Would we want to use m_member style here?
|
//! \todo Would we want to use m_member style here?
|
||||||
struct PluginData
|
struct PluginData
|
||||||
{
|
{
|
||||||
PluginData(const BlackMisc::Simulation::CSimulatorPluginInfo &info, ISimulatorFactory *factory, ISimulatorListener *listener, ISimulator *simulator, const QString &fileName) :
|
PluginData(const BlackMisc::Simulation::CSimulatorPluginInfo &info, ISimulatorFactory *factory, ISimulatorListener *listener, ISimulator *simulator, const QString &identifier) :
|
||||||
info(info), factory(factory), listener(listener), simulator(simulator), fileName(fileName) {}
|
info(info), factory(factory), listener(listener), simulator(simulator), identifier(identifier) {}
|
||||||
|
|
||||||
BlackMisc::Simulation::CSimulatorPluginInfo info;
|
BlackMisc::Simulation::CSimulatorPluginInfo info;
|
||||||
ISimulatorFactory *factory = nullptr; //!< Lazy-loaded, nullptr by default
|
ISimulatorFactory *factory = nullptr; //!< Lazy-loaded, nullptr by default
|
||||||
ISimulatorListener *listener = nullptr; //!< Listener instance, nullptr by default
|
ISimulatorListener *listener = nullptr; //!< Listener instance, nullptr by default
|
||||||
ISimulator *simulator = nullptr; //!< The simulator itself (always nullptr unless it is the currently working one)
|
ISimulator *simulator = nullptr; //!< The simulator itself (always nullptr unless it is the currently working one)
|
||||||
QString fileName; //!< Plugin file name (relative to plugins/simulator)
|
QString identifier = QString(); //!< The plugin identifier
|
||||||
QHash<QString, BlackMisc::CVariant> m_storage; //!< Permanent plugin storage - data stored here will be kept even when plugin is unloaded
|
QHash<QString, BlackMisc::CVariant> m_storage; //!< Permanent plugin storage - data stored here will be kept even when plugin is unloaded
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
131
src/blackcore/plugin_manager.cpp
Normal file
131
src/blackcore/plugin_manager.cpp
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
/* Copyright (C) 2013
|
||||||
|
* swift Project Community / Contributors
|
||||||
|
*
|
||||||
|
* This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level
|
||||||
|
* directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project,
|
||||||
|
* including this file, may be copied, modified, propagated, or distributed except according to the terms
|
||||||
|
* contained in the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "plugin_manager.h"
|
||||||
|
#include "blackmisc/logmessage.h"
|
||||||
|
#include "blackmisc/loghandler.h"
|
||||||
|
#include <QCoreApplication>
|
||||||
|
#include <QDir>
|
||||||
|
#include <QDirIterator>
|
||||||
|
#include <QLibrary>
|
||||||
|
|
||||||
|
using namespace BlackMisc;
|
||||||
|
|
||||||
|
namespace BlackCore {
|
||||||
|
|
||||||
|
BlackMisc::CSequence<QJsonObject> CPluginManager::plugins(const QString &iid) const
|
||||||
|
{
|
||||||
|
return m_metadatas.values(iid);
|
||||||
|
}
|
||||||
|
|
||||||
|
QObject *CPluginManager::getPluginById(const QString &identifier)
|
||||||
|
{
|
||||||
|
if (m_instances.contains(identifier))
|
||||||
|
{
|
||||||
|
return m_instances.value(identifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_paths.contains(identifier))
|
||||||
|
{
|
||||||
|
CLogMessage(this).warning("Plugin with id %1 does not exist") << identifier;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString path = m_paths.value(identifier);
|
||||||
|
QPluginLoader loader(path);
|
||||||
|
QObject *instance = loader.instance();
|
||||||
|
if (instance)
|
||||||
|
{
|
||||||
|
m_instances.insert(identifier, instance);
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CLogMessage(this).error(loader.errorString());
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CPluginManager *CPluginManager::getInstance()
|
||||||
|
{
|
||||||
|
static CPluginManager *instance = nullptr;
|
||||||
|
if (!instance)
|
||||||
|
{
|
||||||
|
instance = new CPluginManager();
|
||||||
|
}
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
CPluginManager::CPluginManager(QObject *parent) : QObject(parent)
|
||||||
|
{
|
||||||
|
collectPlugins();
|
||||||
|
|
||||||
|
connect(qApp, &QCoreApplication::aboutToQuit, this, &CPluginManager::deleteLater);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CPluginManager::collectPlugins()
|
||||||
|
{
|
||||||
|
QDir pluginDir(qApp->applicationDirPath().append("/plugins"));
|
||||||
|
if (!pluginDir.exists())
|
||||||
|
{
|
||||||
|
CLogMessage(this).warning("No plugins directory: %1") << pluginDir.path();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QDirIterator it(pluginDir, QDirIterator::Subdirectories);
|
||||||
|
while (it.hasNext())
|
||||||
|
{
|
||||||
|
if (!QLibrary::isLibrary(it.next()))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
CLogMessage(this).debug() << "Loading plugin: " << it.filePath();
|
||||||
|
QPluginLoader loader(it.filePath());
|
||||||
|
QJsonObject json = loader.metaData();
|
||||||
|
QString identifier = pluginIdentifier(json);
|
||||||
|
if (identifier.isEmpty())
|
||||||
|
{
|
||||||
|
CLogMessage(this).warning("Plugin %1 invalid, not loading it") << it.filePath();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_paths.insert(identifier, it.filePath());
|
||||||
|
m_metadatas.insert(json["IID"].toString(), json);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QString CPluginManager::pluginIdentifier(const QJsonObject &metadata)
|
||||||
|
{
|
||||||
|
if (!metadata.contains("IID") || !metadata["IID"].isString())
|
||||||
|
{
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!metadata["MetaData"].isObject())
|
||||||
|
{
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonObject data = metadata["MetaData"].toObject();
|
||||||
|
if (!data.contains("identifier"))
|
||||||
|
{
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonValue identifier = data["identifier"];
|
||||||
|
if (!identifier.isString())
|
||||||
|
{
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
|
||||||
|
return identifier.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
65
src/blackcore/plugin_manager.h
Normal file
65
src/blackcore/plugin_manager.h
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
/* Copyright (C) 2013
|
||||||
|
* swift Project Community / Contributors
|
||||||
|
*
|
||||||
|
* This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level
|
||||||
|
* directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project,
|
||||||
|
* including this file, may be copied, modified, propagated, or distributed except according to the terms
|
||||||
|
* contained in the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
//! \file
|
||||||
|
|
||||||
|
#ifndef CPLUGINMANAGER_H
|
||||||
|
#define CPLUGINMANAGER_H
|
||||||
|
|
||||||
|
#include "blackmisc/sequence.h"
|
||||||
|
#include <QObject>
|
||||||
|
#include <QMultiMap>
|
||||||
|
#include <QJsonObject>
|
||||||
|
|
||||||
|
namespace BlackCore
|
||||||
|
{
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Manages all installed plugins, provides easy access to all of them.
|
||||||
|
* Plugin loading works as follows:
|
||||||
|
* 1. Collect all interesting plugins by their IID (\ref plugins());
|
||||||
|
* all plugins are guaranteed to be valid, i.e. they have valid IID and identifier.
|
||||||
|
* 2. Load specified plugin (\ref getPluginById()).
|
||||||
|
*/
|
||||||
|
class CPluginManager : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
//! Retrieves plugin metadata list for the given IID.
|
||||||
|
//! If no implementations are found, the empty list is returned.
|
||||||
|
BlackMisc::CSequence<QJsonObject> plugins(const QString &iid) const;
|
||||||
|
|
||||||
|
//! Loads the given plugin (if necessary) and returns its instance.
|
||||||
|
//! Returns _nullptr_ on failure.
|
||||||
|
QObject *getPluginById(const QString &identifier);
|
||||||
|
|
||||||
|
//! Gets the singleton
|
||||||
|
static CPluginManager *getInstance();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
//! Constructor
|
||||||
|
explicit CPluginManager(QObject *parent = nullptr);
|
||||||
|
|
||||||
|
private:
|
||||||
|
//! Looks (recursively) for all installed plugins
|
||||||
|
void collectPlugins();
|
||||||
|
|
||||||
|
//! Checks whether the provided metadata is valid
|
||||||
|
//! \return The plugin identifier
|
||||||
|
QString pluginIdentifier(const QJsonObject &metadata);
|
||||||
|
|
||||||
|
QMultiMap<QString, QJsonObject> m_metadatas; //!< IID <-> metadata pairs
|
||||||
|
QMap<QString, QString> m_paths; //!< identifier <-> file path pairs
|
||||||
|
QMap<QString, QObject*> m_instances; //!< identifier <-> instance pairs
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // CPLUGINMANAGER_H
|
||||||
Reference in New Issue
Block a user