/* **************************************************************************** * Copyright 2019 Open Systems Development BV * * * * 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 OR COPYRIGHT HOLDERS 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 "pluginmanager.h" #include #include #include #include "log.h" #include "dcxmlconfig.h" #include "iplugin.h" #include namespace osdev { namespace components { using namespace osdev::caelus; std::unique_ptr PluginManager::s_instance( nullptr ); PluginManager& PluginManager::Instance() { if ( nullptr == s_instance ) { s_instance = std::unique_ptr( new PluginManager() ); } return *s_instance; } bool PluginManager::addLibrary( const QString& pluginName ) { bool bResult = false; if( m_pluginHash.contains( pluginName ) ) { bResult = false; } else { Plugin* l_plugin = new Plugin( pluginName ); if( nullptr != l_plugin ) { m_pluginHash.insert( pluginName, l_plugin ); bResult = true; LogInfo( m_className, QString( "Library : %1 was added to the library list." ).arg( pluginName ) ) } } return bResult; } bool PluginManager::loadPlugin(const QString& pluginName) { bool bStatus = false; LogInfo( m_className, QString( "Load plugin %1" ).arg( pluginName ) ) QPluginLoader loader( pluginName ); QObject *plugin = loader.instance(); if ( plugin ) { LogInfo( m_className, "plugin was loaded..." ) IPlugin *iPlugin = qobject_cast( plugin ); if ( iPlugin ) { LogInfo( m_className, QString( "%1 implements the IPlugin interface.." ).arg( pluginName ) ) // Call initialization function on plugin iPlugin->initialise(); // Get the path of the just loaded plugin QString pluginPath = QFileInfo(loader.fileName()).path(); LogInfo( m_className, QString("Plugin name : %1").arg( iPlugin->getName() ) ) LogInfo( m_className, QString("Plugin uuid : %1").arg( iPlugin->getId().toString() ) ) LogInfo( m_className, QString("Plugin description : %1").arg( iPlugin->getDescription() ) ) LogInfo( m_className, QString("Plugin path : %1").arg( pluginPath ) ) // Set the created id to the pluginHash. Plugin *ptrPlugin = m_pluginHash.value( pluginName, nullptr ); if ( ptrPlugin ) { // Retrieve the correct pointer and adjust the values. ptrPlugin->setName( iPlugin->getName() ); ptrPlugin->setFileName( pluginName ); ptrPlugin->setUuid( iPlugin->getId() ); ptrPlugin->setPath( pluginPath ); ptrPlugin->setPlugin( plugin ); } else { // The plugin just loaded doesn't exist. Create it and add it to the hash. ptrPlugin = new Plugin( iPlugin->getName(), pluginName, pluginPath, QString(), iPlugin->getId(), plugin ); m_pluginHash.insert(iPlugin->getName(), ptrPlugin); } // Load successfull bStatus = true; } else { LogError( m_className, QString( "Ignoring plugin %1 because it does not support the IPlugin interface." ).arg( pluginName ) ) } } else { LogError( m_className, QString( "Loading of plugin %1 failed....." ).arg( pluginName ) ) LogError( m_className, QString( "PluginLoader reported : %1" ).arg( loader.errorString() ) ) LogError( m_className, QString( "LibraryPaths : %1 " ).arg( QCoreApplication::libraryPaths().join( "\n" ) ) ) } return bStatus; } bool PluginManager::loadPlugins(const QStringList& pluginNames) { bool bStatus = false; LogDebug( m_className, QString("Adding %1 to the Hash.").arg( pluginNames.join(" ") ) ) buildLibraryList(); LogDebug( m_className, QString("Looking for plugins in : %1").arg( QCoreApplication::libraryPaths().join(":") ) ) for( const QString& pluginName : pluginNames ) { bStatus &= loadPlugin( pluginName ); } return bStatus; } bool PluginManager::loadPlugins() { bool bStatus = false; auto l_pluginNames = m_pluginHash.keys(); for( const QString& l_pluginName : l_pluginNames ) { bStatus &= loadPlugin( l_pluginName ); } return bStatus; } bool PluginManager::unloadPlugin( const QString& pluginName ) { bool bStatus = false; QPluginLoader loader( pluginName ); if ( loader.unload() ) { LogInfo(m_className, QString("Plugin %1 successfully unloaded.").arg(pluginName)) LogInfo(m_className, QString("Removing Plugin %1 form the hashtable.").arg(pluginName)) Plugin *ptr_plugin = m_pluginHash.take( pluginName ); delete ptr_plugin; bStatus = true; } else { LogError( m_className, QString("Unloading of plugin %1 failed.").arg(pluginName) ) LogError( m_className, QString("Last PluginError : %1").arg(loader.errorString() ) ) } return bStatus; } void PluginManager::addLibraryPaths(const QStringList& paths) { for( const QString& libPath : paths ) { QCoreApplication::addLibraryPath( libPath ); } } void PluginManager::addLibraryPath(const QString& path) { QCoreApplication::addLibraryPath( path ); } QObject* PluginManager::getPlugin(const QUuid &id) const { QObject *l_plugin = nullptr; for(auto it = m_pluginHash.begin(); it != m_pluginHash.end(); ++it) { if ( id == it.value()->uuid() ) { l_plugin = it.value()->plugin(); } } return l_plugin; } QList PluginManager::getPlugins(const QString& i_interface) const { QList l_pObjectList; for(auto it = m_pluginHash.begin(); it != m_pluginHash.end(); ++it ) { QObject *l_plugin = it.value()->plugin(); if( l_plugin && l_plugin->qt_metacast( i_interface.toUtf8().data() ) ) { // We've found a plugin with this interface l_pObjectList.push_back( l_plugin ); } } return l_pObjectList; } PluginManager::PluginManager() : m_pluginHash() , m_libraryList() , m_className("PluginManager :: ") { QCoreApplication::addLibraryPath( "." ); } void PluginManager::buildLibraryList() { // Get the config object and get the plugins and librarypaths... DCXmlConfig& l_config = DCXmlConfig::Instance(); // Get all the plugins and create their representing objects.. QStringList l_plugins = l_config.getPlugins(); for(const QString& pluginName : l_plugins) { Plugin* plugin = new Plugin( pluginName ); if (nullptr != plugin) { m_pluginHash.insert(pluginName, plugin); qDebug() << m_pluginHash; } } } QString PluginManager::getLibrary( const QString& pluginName ) const { /// @TODO this should find the actual file name corresponding to the plugin. QFileInfo should be constructed with the actual filename. /// We are looking for that name so this is not working as intended. LogDebug( m_className, QString( "Plugin Name looking for : %1" ).arg( pluginName ) ) for( const QString& library : m_pluginHash.keys() ) { LogDebug( m_className, QString( "Library = %1" ).arg( library ) ) QFileInfo info( library ); LogDebug( m_className, QString( "Library base of : %1" ).arg( info.baseName() ) ) if ( pluginName == info.baseName() ) { // First found can be returned return library; } } // Nothing found return QString(); } bool PluginManager::isLoaded( const QString& pluginName ) const { return m_pluginHash.contains( pluginName ); } QUuid PluginManager::getPluginId( const QString& pluginName ) const { if( isLoaded( pluginName ) ) { return m_pluginHash.value( pluginName )->uuid(); } return QUuid(); } QUuid PluginManager::getPluginIdByInterfaceId( const QString &interface_id ) { for(auto it = m_pluginHash.begin(); it != m_pluginHash.end(); ++it ) { QObject *l_plugin = it.value()->plugin(); if( l_plugin && l_plugin->qt_metacast( interface_id.toUtf8().data() ) ) { // We've found a plugin with this interface IPlugin *iPlugin = qobject_cast( it.value()->plugin() ); if( iPlugin ) { return iPlugin->getId(); } else LogInfo( "[PluginManager::getPluginIdByInterfaceId]", QString( "No plugin found with interface : " + interface_id ) ); } } return QUuid(); } QString PluginManager::getPluginNameByUuid( const QUuid &uuid ) { for( const auto& key : m_pluginHash.keys() ) { Plugin *ptr_plugin = m_pluginHash.value( key, nullptr ); if( nullptr != ptr_plugin ) { if( ptr_plugin->uuid() == uuid ) { return ptr_plugin->name(); } } } return QString(); } QUuid PluginManager::getPluginUuidByName( const QString &name ) { for( const auto& key : m_pluginHash.keys() ) { Plugin *ptr_plugin = m_pluginHash.value( key, nullptr ); if( nullptr != ptr_plugin ) { if( ptr_plugin->name() == name ) { return ptr_plugin->uuid(); } } } return QUuid(); } void PluginManager::slotConfigChanged( const QString& fileName ) { LogInfo(m_className, QString( "Configurationfile %1 was changed. Reread the configuration and plugins." ).arg( fileName ) ) } } // End namespace components } // End namespace osdev