/* **************************************************************************** * 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. * * ***************************************************************************/ #ifndef OSDEV_COMPONENTS_PLUGINMANAGER_H #define OSDEV_COMPONENTS_PLUGINMANAGER_H #include #include #include #include #include #include "plugin.h" #include "globallibexport.h" #include namespace osdev { namespace components { /** * \brief This component is responsible for loading plugins. * * It also has support for supplying interfaces on the loaded pluins. The plugin * manager is a singleton component. *//* * ________________________________________ * / One of the signs of Napoleon's \ * | greatness is the fact that he once had | * | a publisher shot. | * | | * \ -- Siegfried Unseld / * ---------------------------------------- * \ * \ * .--. * |o_o | * |:_/ | * // \ \ * (| | ) * /'\_ _/`\ * \___)=(___/ * */ class GLOBALLIBINTERFACE PluginManager : public QObject { Q_OBJECT public: //! Constructs the plugin manager static PluginManager& Instance(); /// Deleted copy-constructor PluginManager( const PluginManager& ) = delete; /// Deleted assignment operator PluginManager& operator=(const PluginManager&) = delete; /// Deleted move-constructor PluginManager( PluginManager&& ) = delete; /// Deleted move operator PluginManager& operator=( PluginManager&& ) = delete; //! Adds a plugin not listed in the configuration. bool addLibrary( const QString& pluginName ); //! Load the plugin by its name and location bool loadPlugin(const QString& pluginName); //! Loads a list of plugins. Names are resolved against the paths added with addLibraryPaths(). bool loadPlugins(const QStringList& pluginNames); //! Load all plugins set in the staging table. bool loadPlugins(); //! Unloads a plugin and removes it from the manager bool unloadPlugin( const QString& pluginName ); //! Specify where the plugin manager will look for plugins void addLibraryPaths(const QStringList& paths); //! Specify a single plugin path void addLibraryPath(const QString& path); //! Retrieve a loaded plugin with its object ID. QObject* getPlugin(const QUuid &id) const; //! Retrieve all objects that have the specified interface. QList getPlugins(const QString& i_interface) const; //! Check if a specific plugin was already loaded... bool isLoaded( const QString& pluginName ) const; //! Retrieve the uuid of the given plugin by its filename. QUuid getPluginId( const QString& pluginName ) const; //! Retrieve the uuid of the given plugin by its Interface_id QUuid getPluginIdByInterfaceId( const QString &interface_id ); //! Retrieve the name of the given plugin by its uuid QString getPluginNameByUuid( const QUuid &uuid ); //! Retrieve the plugin_id by its systemname. QUuid getPluginUuidByName( const QString &name ); /** * @brief Locate the interface with the specified name * @tparam T Type of interface needed * @param i_interface Name of the interface * @return Interface implementation, or nullptr if no valid interface could * be found */ template T* queryInterface(const QString& i_interface); public slots: /** * @brief Slot called when a configuration file changed * @param fileName Name of the changed file * @todo Implement me! */ void slotConfigChanged( const QString& fileName ); private: //! Constructs the plugin manager (CTor) PluginManager(); /** * @brief Get all the plugins and create their representing objects */ void buildLibraryList(); /** * @brief Find the library associated with a plugin-name * @param pluginName Plugin name to look for * @return Library-name, or an empty string if no library was found */ QString getLibrary(const QString& pluginName) const; // ------------------------------------------------------ //! Contains the only instance of a Pluginmanager static std::unique_ptr s_instance; //! Hash table of all plugins. Loaded or not... QHash m_pluginHash; //! List of all possible libraries that may be loaded by the PM.... QStringList m_libraryList; //! Member holding the classname. QString m_className; }; // ------------------------------------------------------ template T* PluginManager::queryInterface(const QString& i_interface) { // Hash used to store queried interfaces static QHash ifaceCache; T* pInterface = nullptr; if ( ifaceCache.contains(i_interface) ) { pInterface = ifaceCache[i_interface]; } else { QList pPluginList = PluginManager::Instance().getPlugins( i_interface ); if ( !pPluginList.isEmpty() ) { // Return the first plugin with the wanted interface. pInterface = qobject_cast(pPluginList[0]); /// @todo What if we specify the wrong T for this plugin? Q_ASSERT(pInterface); ifaceCache.insert(i_interface, pInterface); } } return pInterface; } } // End namespace components } // End namespace osdev #endif // OSDEV_COMPONENTS_PLUGINMANAGER_H