├── .gitignore
├── LICENSE
├── README.md
├── code
├── CMakeLists.txt
├── cmake
│ ├── CodeCoverage.cmake
│ └── CppPluginFrameworkConfig.cmake
├── inc
│ └── CppPluginFramework
│ │ ├── AbstractPlugin.hpp
│ │ ├── IPlugin.hpp
│ │ ├── IPluginFactory.hpp
│ │ ├── LoggingCategories.hpp
│ │ ├── Plugin.hpp
│ │ ├── PluginConfig.hpp
│ │ ├── PluginFactoryTemplate.hpp
│ │ ├── PluginInstanceConfig.hpp
│ │ ├── PluginManager.hpp
│ │ ├── PluginManagerConfig.hpp
│ │ ├── Validation.hpp
│ │ └── VersionInfo.hpp
├── src
│ ├── AbstractPlugin.cpp
│ ├── LoggingCategories.cpp
│ ├── Plugin.cpp
│ ├── PluginConfig.cpp
│ ├── PluginInstanceConfig.cpp
│ ├── PluginManager.cpp
│ ├── PluginManagerConfig.cpp
│ ├── Validation.cpp
│ └── VersionInfo.cpp
└── tests
│ ├── CMakeLists.txt
│ ├── integration
│ ├── CMakeLists.txt
│ ├── Plugin
│ │ ├── CMakeLists.txt
│ │ └── testPlugin.cpp
│ ├── PluginManager
│ │ ├── CMakeLists.txt
│ │ ├── TestData.qrc
│ │ ├── TestData
│ │ │ ├── AppConfig.json
│ │ │ ├── AppConfigWithInvalidStartupOrder.json
│ │ │ └── InvalidConfigWithUnsupportedDependency.json
│ │ └── testPluginManager.cpp
│ └── TestPlugins
│ │ ├── CMakeLists.txt
│ │ ├── ITestPlugin1.hpp
│ │ ├── ITestPlugin2.hpp
│ │ ├── TestPlugin1.cpp
│ │ ├── TestPlugin1.hpp
│ │ ├── TestPlugin2.cpp
│ │ └── TestPlugin2.hpp
│ └── unit
│ ├── CMakeLists.txt
│ ├── PluginConfig
│ ├── CMakeLists.txt
│ └── testPluginConfig.cpp
│ ├── PluginInstanceConfig
│ ├── CMakeLists.txt
│ └── testPluginInstanceConfig.cpp
│ ├── PluginManagerConfig
│ ├── CMakeLists.txt
│ ├── TestData.qrc
│ ├── TestData
│ │ ├── dummyPlugin1
│ │ └── dummyPlugin2
│ └── testPluginManagerConfig.cpp
│ ├── Validation
│ ├── CMakeLists.txt
│ ├── TestData.qrc
│ ├── TestData
│ │ ├── file
│ │ ├── file.ext
│ │ ├── file.txt
│ │ └── somePath
│ │ │ ├── file
│ │ │ ├── file.ext
│ │ │ └── file.txt
│ └── testValidation.cpp
│ └── VersionInfo
│ ├── CMakeLists.txt
│ └── testVersionInfo.cpp
└── docs
├── Design.md
├── Diagrams
├── ClassDiagrams.plantuml
├── ClassDiagrams
│ ├── Plugin.svg
│ ├── PluginFactory.svg
│ ├── PluginManager.svg
│ └── PluginManagerConfig.svg
├── FlowCharts.plantuml
└── FlowCharts
│ ├── ShutdownWorkflow.svg
│ └── StartupWorkflow.svg
└── Requirements.md
/.gitignore:
--------------------------------------------------------------------------------
1 | # C++ objects and libs
2 |
3 | *.slo
4 | *.lo
5 | *.o
6 | *.a
7 | *.la
8 | *.lai
9 | *.so
10 | *.dll
11 | *.dylib
12 |
13 | # Qt-es
14 |
15 | /.qmake.cache
16 | /.qmake.stash
17 | *.pro.user
18 | *.pro.user.*
19 | *.qbs.user
20 | *.qbs.user.*
21 | *.moc
22 | moc_*.cpp
23 | moc_*.h
24 | qrc_*.cpp
25 | ui_*.h
26 | Makefile*
27 | *build-*
28 |
29 | # QtCreator
30 |
31 | *.autosave
32 |
33 | # QtCtreator Qml
34 | *.qmlproject.user
35 | *.qmlproject.user.*
36 |
37 | # QtCtreator CMake
38 | CMakeLists.txt.user*
39 |
40 | # Visual Studio Code
41 | .vscode
42 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU LESSER GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 |
9 | This version of the GNU Lesser General Public License incorporates
10 | the terms and conditions of version 3 of the GNU General Public
11 | License, supplemented by the additional permissions listed below.
12 |
13 | 0. Additional Definitions.
14 |
15 | As used herein, "this License" refers to version 3 of the GNU Lesser
16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU
17 | General Public License.
18 |
19 | "The Library" refers to a covered work governed by this License,
20 | other than an Application or a Combined Work as defined below.
21 |
22 | An "Application" is any work that makes use of an interface provided
23 | by the Library, but which is not otherwise based on the Library.
24 | Defining a subclass of a class defined by the Library is deemed a mode
25 | of using an interface provided by the Library.
26 |
27 | A "Combined Work" is a work produced by combining or linking an
28 | Application with the Library. The particular version of the Library
29 | with which the Combined Work was made is also called the "Linked
30 | Version".
31 |
32 | The "Minimal Corresponding Source" for a Combined Work means the
33 | Corresponding Source for the Combined Work, excluding any source code
34 | for portions of the Combined Work that, considered in isolation, are
35 | based on the Application, and not on the Linked Version.
36 |
37 | The "Corresponding Application Code" for a Combined Work means the
38 | object code and/or source code for the Application, including any data
39 | and utility programs needed for reproducing the Combined Work from the
40 | Application, but excluding the System Libraries of the Combined Work.
41 |
42 | 1. Exception to Section 3 of the GNU GPL.
43 |
44 | You may convey a covered work under sections 3 and 4 of this License
45 | without being bound by section 3 of the GNU GPL.
46 |
47 | 2. Conveying Modified Versions.
48 |
49 | If you modify a copy of the Library, and, in your modifications, a
50 | facility refers to a function or data to be supplied by an Application
51 | that uses the facility (other than as an argument passed when the
52 | facility is invoked), then you may convey a copy of the modified
53 | version:
54 |
55 | a) under this License, provided that you make a good faith effort to
56 | ensure that, in the event an Application does not supply the
57 | function or data, the facility still operates, and performs
58 | whatever part of its purpose remains meaningful, or
59 |
60 | b) under the GNU GPL, with none of the additional permissions of
61 | this License applicable to that copy.
62 |
63 | 3. Object Code Incorporating Material from Library Header Files.
64 |
65 | The object code form of an Application may incorporate material from
66 | a header file that is part of the Library. You may convey such object
67 | code under terms of your choice, provided that, if the incorporated
68 | material is not limited to numerical parameters, data structure
69 | layouts and accessors, or small macros, inline functions and templates
70 | (ten or fewer lines in length), you do both of the following:
71 |
72 | a) Give prominent notice with each copy of the object code that the
73 | Library is used in it and that the Library and its use are
74 | covered by this License.
75 |
76 | b) Accompany the object code with a copy of the GNU GPL and this license
77 | document.
78 |
79 | 4. Combined Works.
80 |
81 | You may convey a Combined Work under terms of your choice that,
82 | taken together, effectively do not restrict modification of the
83 | portions of the Library contained in the Combined Work and reverse
84 | engineering for debugging such modifications, if you also do each of
85 | the following:
86 |
87 | a) Give prominent notice with each copy of the Combined Work that
88 | the Library is used in it and that the Library and its use are
89 | covered by this License.
90 |
91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license
92 | document.
93 |
94 | c) For a Combined Work that displays copyright notices during
95 | execution, include the copyright notice for the Library among
96 | these notices, as well as a reference directing the user to the
97 | copies of the GNU GPL and this license document.
98 |
99 | d) Do one of the following:
100 |
101 | 0) Convey the Minimal Corresponding Source under the terms of this
102 | License, and the Corresponding Application Code in a form
103 | suitable for, and under terms that permit, the user to
104 | recombine or relink the Application with a modified version of
105 | the Linked Version to produce a modified Combined Work, in the
106 | manner specified by section 6 of the GNU GPL for conveying
107 | Corresponding Source.
108 |
109 | 1) Use a suitable shared library mechanism for linking with the
110 | Library. A suitable mechanism is one that (a) uses at run time
111 | a copy of the Library already present on the user's computer
112 | system, and (b) will operate properly with a modified version
113 | of the Library that is interface-compatible with the Linked
114 | Version.
115 |
116 | e) Provide Installation Information, but only if you would otherwise
117 | be required to provide such information under section 6 of the
118 | GNU GPL, and only to the extent that such information is
119 | necessary to install and execute a modified version of the
120 | Combined Work produced by recombining or relinking the
121 | Application with a modified version of the Linked Version. (If
122 | you use option 4d0, the Installation Information must accompany
123 | the Minimal Corresponding Source and Corresponding Application
124 | Code. If you use option 4d1, you must provide the Installation
125 | Information in the manner specified by section 6 of the GNU GPL
126 | for conveying Corresponding Source.)
127 |
128 | 5. Combined Libraries.
129 |
130 | You may place library facilities that are a work based on the
131 | Library side by side in a single library together with other library
132 | facilities that are not Applications and are not covered by this
133 | License, and convey such a combined library under terms of your
134 | choice, if you do both of the following:
135 |
136 | a) Accompany the combined library with a copy of the same work based
137 | on the Library, uncombined with any other library facilities,
138 | conveyed under the terms of this License.
139 |
140 | b) Give prominent notice with the combined library that part of it
141 | is a work based on the Library, and explaining where to find the
142 | accompanying uncombined form of the same work.
143 |
144 | 6. Revised Versions of the GNU Lesser General Public License.
145 |
146 | The Free Software Foundation may publish revised and/or new versions
147 | of the GNU Lesser General Public License from time to time. Such new
148 | versions will be similar in spirit to the present version, but may
149 | differ in detail to address new problems or concerns.
150 |
151 | Each version is given a distinguishing version number. If the
152 | Library as you received it specifies that a certain numbered version
153 | of the GNU Lesser General Public License "or any later version"
154 | applies to it, you have the option of following the terms and
155 | conditions either of that published version or of any later version
156 | published by the Free Software Foundation. If the Library as you
157 | received it does not specify a version number of the GNU Lesser
158 | General Public License, you may choose any version of the GNU Lesser
159 | General Public License ever published by the Free Software Foundation.
160 |
161 | If the Library as you received it specifies that a proxy can decide
162 | whether future versions of the GNU Lesser General Public License shall
163 | apply, that proxy's public statement of acceptance of any version is
164 | permanent authorization for you to choose that version for the
165 | Library.
166 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # C++ Plugin Framework
2 |
3 | The purpose of this plugin framework is to simplify creation and loading of C++ plugins.
4 |
5 | The framework can be used to create cross-platform plugins, since it is using only Qt and STL libraries.
6 |
7 | It is recommended to build the C++ plugin framework, the plugins and the application with the same development environment to avoid the problem of ABI incompatibility between compilers and used libraries.
8 |
9 |
10 | ## Requirements
11 |
12 | Requirements document can be found [here](docs/Requirements.md).
13 |
14 |
15 | ## Design
16 |
17 | Design document can be found [here](docs/Design.md).
18 |
19 |
20 | ## Build and deployment
21 |
22 | For building the following requirements are needed:
23 |
24 | * CMake v3.5 or later
25 | * C++14 compliant compiler
26 | * Qt v5.9 or later (only Core and Test modules)
27 | * [Cedar Framework](https://github.com/djurodrljaca/CedarFramework)
28 | * [C++ Config Framework](https://github.com/djurodrljaca/CppConfigFramework)
29 |
30 | If the library needs to be deployed to a custom location you need to set the `CMAKE_INSTALL_PREFIX` variable or if you need to use a custom Qt installation, *CedarFramework*, or *CppConfigFramework* is not deployed to one of the standard locations you need to set the `CMAKE_PREFIX_PATH` variable.
31 |
32 | Example:
33 |
34 | ```
35 | $ cmake -DCMAKE_INSTALL_PREFIX=path/to/install/dir -DCMAKE_PREFIX_PATH="path/to/qt/dir;path/to/CedarFramework/dir;path/to/CppConfigFramework/dir" path/to/source/dir
36 | ```
37 |
38 | Then build and deploy the library:
39 |
40 | ```
41 | $ cmake --build . --target install
42 | ```
43 |
44 |
45 | ## Usage
46 |
47 | ### CMake Integration
48 |
49 | To use this module in a CMake project you need to have a built and deployed *CedarFramework* and *CppConfigFramework* dependencies. Then build and deploy *CppPluginFramework* and add this to your project's CMakeLists.txt:
50 |
51 | ```CMake
52 | find_package(CppPluginFramework REQUIRED)
53 | ```
54 |
55 | And link it to your target:
56 |
57 | ```CMake
58 | target_link_libraries(target_name PUBLIC CppPluginFramework::CppPluginFramework)
59 | ```
60 |
61 |
62 | ### Creating an interface for the plugin
63 |
64 | When creating a plugin it is recommended to split the actual plugin and the interfaces that will be implemented by it to separate targets so that other plugins can depend just on the interfaces (header files) instead of to the plugins.
65 |
66 | ```CMake
67 | # File: CMakeLists.txt
68 |
69 | add_library(ExampleInterface INTERFACE)
70 |
71 | target_link_libraries(ExampleInterface INTERFACE ${LIBS})
72 |
73 | target_include_directories(ExampleInterface INTERFACE
74 | $
75 | $
76 | )
77 |
78 | # Create dummy target so that IDEs show the header files
79 | add_custom_target(ExampleInterface_IDE SOURCES
80 | inc/IExample.hpp
81 | )
82 | ```
83 |
84 | ```C++
85 | // File: IExample.hpp
86 |
87 | class IExample
88 | {
89 | public:
90 | virtual ~IExample() = default;
91 | virtual bool exampleMethod() const = 0;
92 | };
93 | ```
94 |
95 |
96 | ### Creating a plugin
97 |
98 | When the interface targets are available then the plugin can just add them as the target dependencies.
99 |
100 | ```CMake
101 | # File: CMakeLists.txt
102 |
103 | add_library(ExamplePlugin SHARED ${PARAM_SOURCES})
104 |
105 | target_link_libraries(ExamplePlugin PUBLIC
106 | CppPluginFramework::CppPluginFramework
107 | ExampleInterface
108 | )
109 |
110 | # Needed only if custom prefix and/or suffix are needed for the plugin library
111 | set_target_properties(ExamplePlugin PROPERTIES
112 | PREFIX ""
113 | SUFFIX ".plugin"
114 | )
115 | ```
116 |
117 | ```C++
118 | // File: ExamplePlugin.hpp
119 |
120 | class ExamplePlugin : public CppPluginFramework::AbstractPlugin, public IExample
121 | {
122 | public:
123 | ExamplePlugin(const QString &name);
124 | ~ExamplePlugin() override = default;
125 |
126 | bool loadConfig(const CppConfigFramework::ConfigObjectNode &config) override;
127 | bool injectDependency(CppPluginFramework::IPlugin *plugin) override;
128 | void ejectDependencies() override;
129 |
130 | bool exampleMethod() const override;
131 | };
132 |
133 | class Q_DECL_EXPORT ExamplePluginFactory :
134 | public QObject,
135 | public CppPluginFramework::PluginFactoryTemplate
136 | {
137 | Q_OBJECT
138 | Q_PLUGIN_METADATA(IID "CppPluginFramework::IPluginFactory")
139 | Q_INTERFACES(CppPluginFramework::IPluginFactory)
140 |
141 | public:
142 | ~ExamplePluginFactory() override = default;
143 | };
144 | ```
145 |
146 | ```C++
147 | // File: ExamplePlugin.cpp
148 |
149 | ExamplePlugin::ExamplePlugin(const QString &name)
150 | : CppPluginFramework::AbstractPlugin(name,
151 | CppPluginFramework::VersionInfo(1, 0, 0),
152 | "Example plugin",
153 | { "IExample" }),
154 | IExample()
155 | {
156 | }
157 |
158 | bool ExamplePlugin::loadConfig(const CppConfigFramework::ConfigObjectNode &config)
159 | {
160 | return true;
161 | }
162 |
163 | bool ExamplePlugin::injectDependency(CppPluginFramework::IPlugin *plugin)
164 | {
165 | return false;
166 | }
167 |
168 | void ExamplePlugin::ejectDependencies()
169 | {
170 | }
171 |
172 | bool ExamplePlugin::exampleMethod() const
173 | {
174 | return true;
175 | }
176 | ```
177 |
178 |
179 | ### Using a plugin in an application
180 |
181 | To be able to use a plugin you only need access to the *CppPluginFramework* (and its dependencies) and the plugin's interfaces.
182 |
183 | The load the plugins you need to prepare a configuration and load it with the *PluginManager* class.
184 |
185 | ```json
186 | {
187 | "config":
188 | {
189 | "plugins":
190 | {
191 | "example":
192 | {
193 | "$file_path": "${PluginPath}/ExamplePlugin.plugin",
194 | "version": "1.0.0",
195 | "instances":
196 | {
197 | "example":
198 | {
199 | "name": "example_instance"
200 | },
201 | }
202 | }
203 | }
204 | }
205 | }
206 | ```
207 |
208 | ```C++
209 | ConfigReader configReader;
210 | EnvironmentVariables environmentVariables;
211 |
212 | auto config = configReader.read("path/to/config/file",
213 | QDir(QCoreApplication::applicationDirPath()),
214 | ConfigNodePath::ROOT_PATH,
215 | ConfigNodePath::ROOT_PATH,
216 | {},
217 | &environmentVariables);
218 |
219 | PluginManagerConfig pluginManagerConfig;
220 | pluginManagerConfig.loadConfig(*config);
221 |
222 | PluginManager pluginManager;
223 | pluginManager.load(pluginManagerConfig);
224 | pluginManager.start();
225 |
226 | auto example = pluginManager.pluginInstance("example_instance")
227 | bool result = example->exampleMethod();
228 |
229 | pluginManager.stop();
230 | pluginManager.unload();
231 | ```
232 |
--------------------------------------------------------------------------------
/code/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # This file is part of C++ Plugin Framework.
2 | #
3 | # C++ Plugin Framework is free software: you can redistribute it and/or modify it under the terms
4 | # of the GNU Lesser General Public License as published by the Free Software Foundation, either
5 | # version 3 of the License, or (at your option) any later version.
6 | #
7 | # C++ Plugin Framework is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
8 | # without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 | # GNU Lesser General Public License for more details.
10 | #
11 | # You should have received a copy of the GNU Lesser General Public License along with C++ Plugin
12 | # Framework. If not, see .
13 |
14 | cmake_minimum_required(VERSION 3.5.0)
15 |
16 | project(CppPluginFramework VERSION 1.0.0)
17 |
18 | set(CMAKE_AUTOMOC ON)
19 |
20 | find_package(CppConfigFramework REQUIRED)
21 |
22 | # --------------------------------------------------------------------------------------------------
23 | # Code Coverage
24 | # --------------------------------------------------------------------------------------------------
25 | option(CppPluginFramework_CodeCoverage "C++ Plugin Framework Code Coverage" OFF)
26 |
27 | if (CppPluginFramework_CodeCoverage MATCHES ON)
28 | include(cmake/CodeCoverage.cmake)
29 | APPEND_COVERAGE_COMPILER_FLAGS()
30 |
31 | set(excludes_cmake_prefix_path)
32 | foreach(item ${CMAKE_PREFIX_PATH})
33 | get_filename_component(item ${item} ABSOLUTE)
34 | list(APPEND excludes_cmake_prefix_path "'${item}/*'")
35 | endforeach()
36 |
37 | set(CppPluginFramework_CodeCoverage_EXCLUDES
38 | "'/opt/*'"
39 | "'/usr/*'"
40 | ${excludes_cmake_prefix_path}
41 | "'${CMAKE_SOURCE_DIR}/tests/*'"
42 | "'${CMAKE_BINARY_DIR}/*'"
43 | )
44 | endif()
45 |
46 | # --------------------------------------------------------------------------------------------------
47 | # CppPluginFramework library
48 | # --------------------------------------------------------------------------------------------------
49 | add_library(CppPluginFramework SHARED
50 | inc/CppPluginFramework/AbstractPlugin.hpp
51 | inc/CppPluginFramework/IPlugin.hpp
52 | inc/CppPluginFramework/IPluginFactory.hpp
53 | inc/CppPluginFramework/LoggingCategories.hpp
54 | inc/CppPluginFramework/Plugin.hpp
55 | inc/CppPluginFramework/PluginConfig.hpp
56 | inc/CppPluginFramework/PluginFactoryTemplate.hpp
57 | inc/CppPluginFramework/PluginInstanceConfig.hpp
58 | inc/CppPluginFramework/PluginManager.hpp
59 | inc/CppPluginFramework/PluginManagerConfig.hpp
60 | inc/CppPluginFramework/Validation.hpp
61 | inc/CppPluginFramework/VersionInfo.hpp
62 |
63 | src/AbstractPlugin.cpp
64 | src/LoggingCategories.cpp
65 | src/Plugin.cpp
66 | src/PluginConfig.cpp
67 | src/PluginInstanceConfig.cpp
68 | src/PluginManager.cpp
69 | src/PluginManagerConfig.cpp
70 | src/Validation.cpp
71 | src/VersionInfo.cpp
72 | )
73 |
74 | set_target_properties(CppPluginFramework PROPERTIES
75 | VERSION ${PROJECT_VERSION}
76 | SOVERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}")
77 |
78 | include(GenerateExportHeader)
79 | generate_export_header(CppPluginFramework
80 | EXPORT_FILE_NAME exports/CppPluginFramework/CppPluginFrameworkExport.hpp)
81 |
82 | target_include_directories(CppPluginFramework PUBLIC
83 | $
84 | $
85 | $
86 | )
87 |
88 | target_link_libraries(CppPluginFramework PUBLIC
89 | CppConfigFramework::CppConfigFramework
90 | )
91 |
92 | set_target_properties(CppPluginFramework PROPERTIES
93 | CXX_STANDARD 14
94 | CXX_STANDARD_REQUIRED YES
95 | CXX_EXTENSIONS NO
96 | )
97 |
98 | # --------------------------------------------------------------------------------------------------
99 | # Package
100 | # --------------------------------------------------------------------------------------------------
101 | add_library(CppPluginFramework::CppPluginFramework ALIAS CppPluginFramework)
102 |
103 | install(TARGETS CppPluginFramework EXPORT CppPluginFrameworkTargets DESTINATION
104 | LIBRARY DESTINATION lib
105 | ARCHIVE DESTINATION lib
106 | RUNTIME DESTINATION bin
107 | INCLUDES DESTINATION include
108 | )
109 |
110 | install(
111 | DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/inc/CppPluginFramework
112 | DESTINATION include
113 | COMPONENT Devel
114 | )
115 |
116 | install(
117 | DIRECTORY ${PROJECT_BINARY_DIR}/exports/CppPluginFramework
118 | DESTINATION include
119 | COMPONENT Devel
120 | )
121 |
122 | include(CMakePackageConfigHelpers)
123 | write_basic_package_version_file(
124 | "${CMAKE_CURRENT_BINARY_DIR}/CppPluginFramework/CppPluginFrameworkConfigVersion.cmake"
125 | VERSION ${CppPluginFramework_VERSION}
126 | COMPATIBILITY AnyNewerVersion
127 | )
128 |
129 | export(EXPORT CppPluginFrameworkTargets
130 | FILE "${CMAKE_CURRENT_BINARY_DIR}/CppPluginFramework/CppPluginFrameworkTargets.cmake"
131 | NAMESPACE CppPluginFramework::
132 | )
133 |
134 | configure_file(cmake/CppPluginFrameworkConfig.cmake
135 | "${CMAKE_CURRENT_BINARY_DIR}/CppPluginFramework/CppPluginFrameworkConfig.cmake"
136 | COPYONLY
137 | )
138 |
139 | set(ConfigPackageLocation lib/cmake/CppPluginFramework)
140 |
141 | install(
142 | EXPORT CppPluginFrameworkTargets
143 | FILE CppPluginFrameworkTargets.cmake
144 | NAMESPACE CppPluginFramework::
145 | DESTINATION ${ConfigPackageLocation}
146 | )
147 |
148 | install(
149 | FILES
150 | cmake/CppPluginFrameworkConfig.cmake
151 | "${CMAKE_CURRENT_BINARY_DIR}/CppPluginFramework/CppPluginFrameworkConfigVersion.cmake"
152 | DESTINATION ${ConfigPackageLocation}
153 | COMPONENT Devel
154 | )
155 |
156 | # --------------------------------------------------------------------------------------------------
157 | # Tests
158 | # --------------------------------------------------------------------------------------------------
159 | enable_testing()
160 | add_subdirectory(tests)
161 |
--------------------------------------------------------------------------------
/code/cmake/CodeCoverage.cmake:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2012 - 2017, Lars Bilke
2 | # All rights reserved.
3 | #
4 | # Redistribution and use in source and binary forms, with or without modification,
5 | # are permitted provided that the following conditions are met:
6 | #
7 | # 1. Redistributions of source code must retain the above copyright notice, this
8 | # list of conditions and the following disclaimer.
9 | #
10 | # 2. Redistributions in binary form must reproduce the above copyright notice,
11 | # this list of conditions and the following disclaimer in the documentation
12 | # and/or other materials provided with the distribution.
13 | #
14 | # 3. Neither the name of the copyright holder nor the names of its contributors
15 | # may be used to endorse or promote products derived from this software without
16 | # specific prior written permission.
17 | #
18 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 | # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
22 | # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 | # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
25 | # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 | # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 | #
29 | # CHANGES:
30 | #
31 | # 2012-01-31, Lars Bilke
32 | # - Enable Code Coverage
33 | #
34 | # 2013-09-17, Joakim Söderberg
35 | # - Added support for Clang.
36 | # - Some additional usage instructions.
37 | #
38 | # 2016-02-03, Lars Bilke
39 | # - Refactored functions to use named parameters
40 | #
41 | # 2017-06-02, Lars Bilke
42 | # - Merged with modified version from github.com/ufz/ogs
43 | #
44 | #
45 | # USAGE:
46 | #
47 | # 1. Copy this file into your cmake modules path.
48 | #
49 | # 2. Add the following line to your CMakeLists.txt:
50 | # include(CodeCoverage)
51 | #
52 | # 3. Append necessary compiler flags:
53 | # APPEND_COVERAGE_COMPILER_FLAGS()
54 | #
55 | # 4. If you need to exclude additional directories from the report, specify them
56 | # using the COVERAGE_EXCLUDES variable before calling SETUP_TARGET_FOR_COVERAGE.
57 | # Example:
58 | # set(COVERAGE_EXCLUDES 'dir1/*' 'dir2/*')
59 | #
60 | # 5. Use the functions described below to create a custom make target which
61 | # runs your test executable and produces a code coverage report.
62 | #
63 | # 6. Build a Debug build:
64 | # cmake -DCMAKE_BUILD_TYPE=Debug ..
65 | # make
66 | # make my_coverage_target
67 | #
68 |
69 | include(CMakeParseArguments)
70 |
71 | # Check prereqs
72 | find_program( GCOV_PATH gcov )
73 | find_program( LCOV_PATH lcov )
74 | find_program( GENHTML_PATH genhtml )
75 | find_program( GCOVR_PATH gcovr PATHS ${CMAKE_SOURCE_DIR}/scripts/test)
76 | find_program( SIMPLE_PYTHON_EXECUTABLE python )
77 |
78 | if(NOT GCOV_PATH)
79 | message(FATAL_ERROR "gcov not found! Aborting...")
80 | endif() # NOT GCOV_PATH
81 |
82 | if("${CMAKE_CXX_COMPILER_ID}" MATCHES "(Apple)?[Cc]lang")
83 | if("${CMAKE_CXX_COMPILER_VERSION}" VERSION_LESS 3)
84 | message(FATAL_ERROR "Clang version must be 3.0.0 or greater! Aborting...")
85 | endif()
86 | elseif(NOT CMAKE_COMPILER_IS_GNUCXX)
87 | message(FATAL_ERROR "Compiler is not GNU gcc! Aborting...")
88 | endif()
89 |
90 | set(COVERAGE_COMPILER_FLAGS "-g -O0 --coverage -fprofile-arcs -ftest-coverage"
91 | CACHE INTERNAL "")
92 |
93 | set(CMAKE_CXX_FLAGS_COVERAGE
94 | ${COVERAGE_COMPILER_FLAGS}
95 | CACHE STRING "Flags used by the C++ compiler during coverage builds."
96 | FORCE )
97 | set(CMAKE_C_FLAGS_COVERAGE
98 | ${COVERAGE_COMPILER_FLAGS}
99 | CACHE STRING "Flags used by the C compiler during coverage builds."
100 | FORCE )
101 | set(CMAKE_EXE_LINKER_FLAGS_COVERAGE
102 | ""
103 | CACHE STRING "Flags used for linking binaries during coverage builds."
104 | FORCE )
105 | set(CMAKE_SHARED_LINKER_FLAGS_COVERAGE
106 | ""
107 | CACHE STRING "Flags used by the shared libraries linker during coverage builds."
108 | FORCE )
109 | mark_as_advanced(
110 | CMAKE_CXX_FLAGS_COVERAGE
111 | CMAKE_C_FLAGS_COVERAGE
112 | CMAKE_EXE_LINKER_FLAGS_COVERAGE
113 | CMAKE_SHARED_LINKER_FLAGS_COVERAGE )
114 |
115 | if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
116 | message(WARNING "Code coverage results with an optimised (non-Debug) build may be misleading")
117 | endif() # NOT CMAKE_BUILD_TYPE STREQUAL "Debug"
118 |
119 | if(CMAKE_C_COMPILER_ID STREQUAL "GNU")
120 | link_libraries(gcov)
121 | else()
122 | set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --coverage")
123 | endif()
124 |
125 | # Defines a target for running and collection code coverage information
126 | # Builds dependencies, runs the given executable and outputs reports.
127 | # NOTE! The executable should always have a ZERO as exit code otherwise
128 | # the coverage generation will not complete.
129 | #
130 | # SETUP_TARGET_FOR_COVERAGE(
131 | # NAME testrunner_coverage # New target name
132 | # EXECUTABLE testrunner -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR
133 | # DEPENDENCIES testrunner # Dependencies to build first
134 | # PROJECT_PATH /project/path # Project path
135 | # )
136 | function(SETUP_TARGET_FOR_COVERAGE)
137 |
138 | set(options NONE)
139 | set(oneValueArgs NAME PROJECT_PATH)
140 | set(multiValueArgs EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES EXCLUDES)
141 | cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
142 |
143 | if(NOT LCOV_PATH)
144 | message(FATAL_ERROR "lcov not found! Aborting...")
145 | endif() # NOT LCOV_PATH
146 |
147 | if(NOT GENHTML_PATH)
148 | message(FATAL_ERROR "genhtml not found! Aborting...")
149 | endif() # NOT GENHTML_PATH
150 |
151 | # Setup target
152 | if (Coverage_PROJECT_PATH)
153 | set(GENHTML_PREFIX --prefix ${Coverage_PROJECT_PATH})
154 | endif()
155 |
156 | add_custom_target(${Coverage_NAME}
157 |
158 | # Cleanup lcov
159 | COMMAND ${LCOV_PATH} --directory . --zerocounters
160 | # Create baseline to make sure untouched files show up in the report
161 | COMMAND ${LCOV_PATH} -c -i -d . -o ${Coverage_NAME}.base
162 |
163 | # Run tests
164 | COMMAND ${Coverage_EXECUTABLE}
165 |
166 | # Capturing lcov counters and generating report
167 | COMMAND ${LCOV_PATH} --directory . --capture --output-file ${Coverage_NAME}.info
168 |
169 | # add baseline counters
170 | COMMAND ${LCOV_PATH} -a ${Coverage_NAME}.base -a ${Coverage_NAME}.info --output-file ${Coverage_NAME}.total
171 | COMMAND ${LCOV_PATH} --remove ${Coverage_NAME}.total ${Coverage_EXCLUDES} --output-file ${PROJECT_BINARY_DIR}/${Coverage_NAME}.info.cleaned
172 | COMMAND ${GENHTML_PATH} -o ${Coverage_NAME} ${PROJECT_BINARY_DIR}/${Coverage_NAME}.info.cleaned ${GENHTML_PREFIX}
173 | COMMAND ${CMAKE_COMMAND} -E remove ${Coverage_NAME}.base ${Coverage_NAME}.info ${Coverage_NAME}.total ${PROJECT_BINARY_DIR}/${Coverage_NAME}.info.cleaned
174 |
175 | WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
176 | DEPENDS ${Coverage_DEPENDENCIES}
177 | COMMENT "Resetting code coverage counters to zero.\nProcessing code coverage counters and generating report."
178 | )
179 |
180 | # Show info where to find the report
181 | add_custom_command(TARGET ${Coverage_NAME} POST_BUILD
182 | COMMAND ;
183 | COMMENT "Open ./${Coverage_NAME}/index.html in your browser to view the coverage report."
184 | )
185 |
186 | endfunction() # SETUP_TARGET_FOR_COVERAGE
187 |
188 | # Defines a target for running and collection code coverage information
189 | # Builds dependencies, runs the given executable and outputs reports.
190 | # NOTE! The executable should always have a ZERO as exit code otherwise
191 | # the coverage generation will not complete.
192 | #
193 | # SETUP_TARGET_FOR_COVERAGE_COBERTURA(
194 | # NAME ctest_coverage # New target name
195 | # EXECUTABLE ctest -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR
196 | # DEPENDENCIES executable_target # Dependencies to build first
197 | # )
198 | function(SETUP_TARGET_FOR_COVERAGE_COBERTURA)
199 |
200 | set(options NONE)
201 | set(oneValueArgs NAME)
202 | set(multiValueArgs EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES)
203 | cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
204 |
205 | if(NOT SIMPLE_PYTHON_EXECUTABLE)
206 | message(FATAL_ERROR "python not found! Aborting...")
207 | endif() # NOT SIMPLE_PYTHON_EXECUTABLE
208 |
209 | if(NOT GCOVR_PATH)
210 | message(FATAL_ERROR "gcovr not found! Aborting...")
211 | endif() # NOT GCOVR_PATH
212 |
213 | # Combine excludes to several -e arguments
214 | set(COBERTURA_EXCLUDES "")
215 | foreach(EXCLUDE ${COVERAGE_EXCLUDES})
216 | set(COBERTURA_EXCLUDES "-e ${EXCLUDE} ${COBERTURA_EXCLUDES}")
217 | endforeach()
218 |
219 | add_custom_target(${Coverage_NAME}
220 |
221 | # Run tests
222 | ${Coverage_EXECUTABLE}
223 |
224 | # Running gcovr
225 | COMMAND ${GCOVR_PATH} -x -r ${CMAKE_SOURCE_DIR} ${COBERTURA_EXCLUDES}
226 | -o ${Coverage_NAME}.xml
227 | WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
228 | DEPENDS ${Coverage_DEPENDENCIES}
229 | COMMENT "Running gcovr to produce Cobertura code coverage report."
230 | )
231 |
232 | # Show info where to find the report
233 | add_custom_command(TARGET ${Coverage_NAME} POST_BUILD
234 | COMMAND ;
235 | COMMENT "Cobertura code coverage report saved in ${Coverage_NAME}.xml."
236 | )
237 |
238 | endfunction() # SETUP_TARGET_FOR_COVERAGE_COBERTURA
239 |
240 | function(APPEND_COVERAGE_COMPILER_FLAGS)
241 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${COVERAGE_COMPILER_FLAGS}" PARENT_SCOPE)
242 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${COVERAGE_COMPILER_FLAGS}" PARENT_SCOPE)
243 | message(STATUS "Appending code coverage compiler flags: ${COVERAGE_COMPILER_FLAGS}")
244 | endfunction() # APPEND_COVERAGE_COMPILER_FLAGS
245 |
--------------------------------------------------------------------------------
/code/cmake/CppPluginFrameworkConfig.cmake:
--------------------------------------------------------------------------------
1 | include(CMakeFindDependencyMacro)
2 | find_dependency(CppConfigFramework)
3 |
4 | include("${CMAKE_CURRENT_LIST_DIR}/CppPluginFrameworkTargets.cmake")
5 |
--------------------------------------------------------------------------------
/code/inc/CppPluginFramework/AbstractPlugin.hpp:
--------------------------------------------------------------------------------
1 | /* This file is part of C++ Plugin Framework.
2 | *
3 | * C++ Plugin Framework is free software: you can redistribute it and/or modify it under the terms
4 | * of the GNU Lesser General Public License as published by the Free Software Foundation, either
5 | * version 3 of the License, or (at your option) any later version.
6 | *
7 | * C++ Plugin Framework is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
8 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 | * GNU Lesser General Public License for more details.
10 | *
11 | * You should have received a copy of the GNU Lesser General Public License along with C++ Plugin
12 | * Framework. If not, see .
13 | */
14 |
15 | /*!
16 | * \file
17 | *
18 | * Contains a convenience base class for creating plugins
19 | */
20 |
21 | #pragma once
22 |
23 | // C++ Plugin Framework includes
24 | #include
25 |
26 | // Qt includes
27 | #include
28 |
29 | // System includes
30 |
31 | // Forward declarations
32 |
33 | // Macros
34 |
35 | // -------------------------------------------------------------------------------------------------
36 |
37 | namespace CppPluginFramework
38 | {
39 |
40 | /*!
41 | * This is a convenience base class for creating plugins. It provides a common implementation a part
42 | * of the plugin interface.
43 | *
44 | * Derived classes still need to implement the following:
45 | * - Loading of a configuration
46 | * - Injection and ejection of dependencies
47 | *
48 | * Derived classes can also hook to events:
49 | * - Starting plugin
50 | * - Stopping plugin
51 | */
52 | class CPPPLUGINFRAMEWORK_EXPORT AbstractPlugin : public IPlugin
53 | {
54 | public:
55 | /*!
56 | * Constructor
57 | *
58 | * \param name Plugin instance name
59 | * \param version Plugin version
60 | */
61 | AbstractPlugin(const QString &name,
62 | const VersionInfo &version,
63 | const QString &description,
64 | const QSet &exportedInterfaces);
65 |
66 | //! Destructor
67 | ~AbstractPlugin() override = default;
68 |
69 | //! \copydoc CppPluginFramework::IPlugin::name()
70 | QString name() const override final;
71 |
72 | //! \copydoc CppPluginFramework::IPlugin::version()
73 | VersionInfo version() const override final;
74 |
75 | //! \copydoc CppPluginFramework::IPlugin::description()
76 | QString description() const override final;
77 |
78 | //! \copydoc CppPluginFramework::IPlugin::isInterfaceExported()
79 | bool isInterfaceExported(const QString &interface) const override final;
80 |
81 | //! \copydoc CppPluginFramework::IPlugin::exportedInterfaces()
82 | QSet exportedInterfaces() const override final;
83 |
84 | //! \copydoc CppPluginFramework::IPlugin::isStarted()
85 | bool isStarted() const override final;
86 |
87 | //! \copydoc CppPluginFramework::IPlugin::start()
88 | bool start() override final;
89 |
90 | //! \copydoc CppPluginFramework::IPlugin::stop()
91 | void stop() override final;
92 |
93 | private:
94 | /*!
95 | * Executes the startup procedure
96 | *
97 | * \retval true Success
98 | * \retval false Failure
99 | *
100 | * This method is called inside start() method if the plugin is not started yet. Default
101 | * implementation doesn't do anything. This method needs to be overridden if anything needs
102 | * to be done during startup.
103 | */
104 | virtual bool onStart();
105 |
106 | /*!
107 | * Executes the shutdown procedure
108 | *
109 | * This method is called inside stop() method if the plugin is not started yet. Default
110 | * implementation doesn't do anything. This method needs to be overridden if anything needs
111 | * to be done during startup.
112 | */
113 | virtual void onStop();
114 |
115 | private:
116 | //! Enables thread-safe access to the plugin data
117 | mutable QMutex m_mutex;
118 |
119 | //! Holds the name of the plugin instance
120 | QString m_name;
121 |
122 | //! Holds the version of the plugin
123 | VersionInfo m_version;
124 |
125 | //! Holds the description of the plugin
126 | QString m_description;
127 |
128 | //! Holds the list of exported interfaces of the plugin
129 | QSet m_exportedInterfaces;
130 |
131 | //! Holds the "started" flag
132 | bool m_started;
133 | };
134 |
135 | }
136 |
--------------------------------------------------------------------------------
/code/inc/CppPluginFramework/IPlugin.hpp:
--------------------------------------------------------------------------------
1 | /* This file is part of C++ Plugin Framework.
2 | *
3 | * C++ Plugin Framework is free software: you can redistribute it and/or modify it under the terms
4 | * of the GNU Lesser General Public License as published by the Free Software Foundation, either
5 | * version 3 of the License, or (at your option) any later version.
6 | *
7 | * C++ Plugin Framework is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
8 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 | * GNU Lesser General Public License for more details.
10 | *
11 | * You should have received a copy of the GNU Lesser General Public License along with C++ Plugin
12 | * Framework. If not, see .
13 | */
14 |
15 | /*!
16 | * \file
17 | *
18 | * Contains a base class for all plugins
19 | */
20 |
21 | #pragma once
22 |
23 | // C++ Plugin Framework includes
24 | #include
25 |
26 | // C++ Config Framework includes
27 | #include
28 |
29 | // Qt includes
30 |
31 | // System includes
32 |
33 | // Forward declarations
34 |
35 | // Macros
36 |
37 | // -------------------------------------------------------------------------------------------------
38 |
39 | namespace CppPluginFramework
40 | {
41 |
42 | //! This is a base class for all plugins
43 | class CPPPLUGINFRAMEWORK_EXPORT IPlugin
44 | {
45 | public:
46 | //! Destructor
47 | virtual ~IPlugin() = default;
48 |
49 | /*!
50 | * Returns plugin's name
51 | *
52 | * \return Plugin's name
53 | */
54 | virtual QString name() const = 0;
55 |
56 | /*!
57 | * Returns plugin's version
58 | *
59 | * \return Plugin's version
60 | */
61 | virtual VersionInfo version() const = 0;
62 |
63 | /*!
64 | * Returns plugin's description
65 | *
66 | * \return Plugin's description
67 | */
68 | virtual QString description() const = 0;
69 |
70 | /*!
71 | * Checks if the specified interface is exported by this plugin
72 | *
73 | * \param interface Name of the interface to check
74 | *
75 | * \retval true The specified interface is exported
76 | * \retval false The specified interface is not exported
77 | */
78 | virtual bool isInterfaceExported(const QString &interface) const = 0;
79 |
80 | /*!
81 | * Returns a list of all exported interfaces
82 | *
83 | * \return List of all exported interfaces
84 | */
85 | virtual QSet exportedInterfaces() const = 0;
86 |
87 | /*!
88 | * Loads the specified config
89 | *
90 | * \param config Config node
91 | *
92 | * \retval true Success
93 | * \retval false Failure
94 | */
95 | virtual bool loadConfig(const CppConfigFramework::ConfigObjectNode &config) = 0;
96 |
97 | /*!
98 | * Injects all dependencies (interfaces) that can be taken out of the specified plugin instance
99 | *
100 | * \param plugin Plugin
101 | *
102 | * \retval true Success
103 | * \retval false Failure
104 | */
105 | virtual bool injectDependency(IPlugin *plugin) = 0;
106 |
107 | //! Ejects all injected dependencies (interfaces)
108 | virtual void ejectDependencies() = 0;
109 |
110 | /*!
111 | * Checks if plugin is started
112 | *
113 | * \retval true Plugin is started
114 | * \retval false Plugin is not started
115 | */
116 | virtual bool isStarted() const = 0;
117 |
118 | /*!
119 | * Starts the plugin
120 | *
121 | * \retval true Plugin was started
122 | * \retval false Plugin was not started
123 | */
124 | virtual bool start() = 0;
125 |
126 | //! Stops the plugin
127 | virtual void stop() = 0;
128 |
129 | /*!
130 | * Convenience method for casting this plugin to the specified interface
131 | *
132 | * \return Pointer to the specified interface or a null pointer if this plugin does not
133 | * implement the specified interface
134 | */
135 | template
136 | T* interface()
137 | {
138 | return dynamic_cast(this);
139 | }
140 | };
141 |
142 | } // namespace CppPluginFramework
143 |
--------------------------------------------------------------------------------
/code/inc/CppPluginFramework/IPluginFactory.hpp:
--------------------------------------------------------------------------------
1 | /* This file is part of C++ Plugin Framework.
2 | *
3 | * C++ Plugin Framework is free software: you can redistribute it and/or modify it under the terms
4 | * of the GNU Lesser General Public License as published by the Free Software Foundation, either
5 | * version 3 of the License, or (at your option) any later version.
6 | *
7 | * C++ Plugin Framework is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
8 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 | * GNU Lesser General Public License for more details.
10 | *
11 | * You should have received a copy of the GNU Lesser General Public License along with C++ Plugin
12 | * Framework. If not, see .
13 | */
14 |
15 | /*!
16 | * \file
17 | *
18 | * Contains a base class for a factory that shall be able to create instances of a plugin
19 | */
20 |
21 | #pragma once
22 |
23 | // C++ Plugin Framework includes
24 | #include
25 |
26 | // Qt includes
27 |
28 | // System includes
29 |
30 | // Forward declarations
31 |
32 | // Macros
33 |
34 | // -------------------------------------------------------------------------------------------------
35 |
36 | namespace CppPluginFramework
37 | {
38 |
39 | //! This is a base class for a factory that shall be able to create instances of a plugin
40 | class CPPPLUGINFRAMEWORK_EXPORT IPluginFactory
41 | {
42 | public:
43 | //! Destructor
44 | virtual ~IPluginFactory() = default;
45 |
46 | /*!
47 | * Creates a plugin instance
48 | *
49 | * \param instanceName Name of the plugin instance
50 | *
51 | * \return Plugin instance or nullptr if the instance could not be created
52 | */
53 | virtual std::unique_ptr createInstance(const QString &instanceName) const = 0;
54 | };
55 |
56 | } // namespace CppPluginFramework
57 |
58 | //! Maps the class name to its string equivalent
59 | Q_DECLARE_INTERFACE(CppPluginFramework::IPluginFactory, "CppPluginFramework::IPluginFactory")
60 |
--------------------------------------------------------------------------------
/code/inc/CppPluginFramework/LoggingCategories.hpp:
--------------------------------------------------------------------------------
1 | /* This file is part of C++ Plugin Framework.
2 | *
3 | * C++ Plugin Framework is free software: you can redistribute it and/or modify it under the terms
4 | * of the GNU Lesser General Public License as published by the Free Software Foundation, either
5 | * version 3 of the License, or (at your option) any later version.
6 | *
7 | * C++ Plugin Framework is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
8 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 | * GNU Lesser General Public License for more details.
10 | *
11 | * You should have received a copy of the GNU Lesser General Public License along with C++ Plugin
12 | * Framework. If not, see .
13 | */
14 |
15 | /*!
16 | * \file
17 | *
18 | * Contains logging categories
19 | */
20 |
21 | #pragma once
22 |
23 | // C++ Plugin Framework includes
24 | #include
25 |
26 | // Qt includes
27 | #include
28 |
29 | // System includes
30 |
31 | // Forward declarations
32 |
33 | // Macros
34 |
35 | // -------------------------------------------------------------------------------------------------
36 |
37 | namespace CppPluginFramework
38 | {
39 |
40 | namespace LoggingCategory
41 | {
42 |
43 | //! Logging category for plugin config
44 | CPPPLUGINFRAMEWORK_EXPORT extern const QLoggingCategory Config;
45 |
46 | //! Logging category for Plugin
47 | CPPPLUGINFRAMEWORK_EXPORT extern const QLoggingCategory Plugin;
48 |
49 | //! Logging category for PluginManager
50 | CPPPLUGINFRAMEWORK_EXPORT extern const QLoggingCategory PluginManager;
51 |
52 | } // namespace LoggingCategory
53 |
54 | } // namespace CppPluginFramework
55 |
--------------------------------------------------------------------------------
/code/inc/CppPluginFramework/Plugin.hpp:
--------------------------------------------------------------------------------
1 | /* This file is part of C++ Plugin Framework.
2 | *
3 | * C++ Plugin Framework is free software: you can redistribute it and/or modify it under the terms
4 | * of the GNU Lesser General Public License as published by the Free Software Foundation, either
5 | * version 3 of the License, or (at your option) any later version.
6 | *
7 | * C++ Plugin Framework is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
8 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 | * GNU Lesser General Public License for more details.
10 | *
11 | * You should have received a copy of the GNU Lesser General Public License along with C++ Plugin
12 | * Framework. If not, see .
13 | */
14 |
15 | /*!
16 | * \file
17 | *
18 | * Contains a class that is able to load a plugin from a library
19 | */
20 |
21 | #pragma once
22 |
23 | // C++ Plugin Framework includes
24 | #include
25 | #include
26 |
27 | // Qt includes
28 |
29 | // System includes
30 |
31 | // Forward declarations
32 |
33 | // Macros
34 |
35 | // -------------------------------------------------------------------------------------------------
36 |
37 | namespace CppPluginFramework
38 | {
39 |
40 | //! This class enables loading of plugin instances from a library
41 | class CPPPLUGINFRAMEWORK_EXPORT Plugin
42 | {
43 | public:
44 | /*!
45 | * Loads plugin instances from the specified library
46 | *
47 | * \param pluginConfig Plugin config
48 | *
49 | * \return Loaded plugin instances or an empty vector if loading failed
50 | */
51 | static std::vector> loadInstances(const PluginConfig &pluginConfig);
52 |
53 | private:
54 | //! Construction of this class is disabled
55 | Plugin() = delete;
56 |
57 | /*!
58 | * Loads the plugin instance from the specified library and configures it
59 | *
60 | * \param instanceConfig Plugin instance config
61 | *
62 | * \return Loaded plugin instance or nullptr if loading failed
63 | */
64 | static std::unique_ptr loadInstance(const IPluginFactory &pluginFactory,
65 | const PluginInstanceConfig &instanceConfig);
66 |
67 | /*!
68 | * Checks if the version matches the plugin config's version requirements
69 | *
70 | * \param pluginVersion Plugin version
71 | * \param pluginConfig Plugin config
72 | *
73 | * \retval true Success
74 | * \retval false Failure
75 | */
76 | static bool checkVersion(const VersionInfo &pluginVersion, const PluginConfig &pluginConfig);
77 | };
78 |
79 | } // namespace CppPluginFramework
80 |
--------------------------------------------------------------------------------
/code/inc/CppPluginFramework/PluginConfig.hpp:
--------------------------------------------------------------------------------
1 | /* This file is part of C++ Plugin Framework.
2 | *
3 | * C++ Plugin Framework is free software: you can redistribute it and/or modify it under the terms
4 | * of the GNU Lesser General Public License as published by the Free Software Foundation, either
5 | * version 3 of the License, or (at your option) any later version.
6 | *
7 | * C++ Plugin Framework is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
8 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 | * GNU Lesser General Public License for more details.
10 | *
11 | * You should have received a copy of the GNU Lesser General Public License along with C++ Plugin
12 | * Framework. If not, see .
13 | */
14 |
15 | /*!
16 | * \file
17 | *
18 | * Contains a config class for a Plugin
19 | */
20 |
21 | #pragma once
22 |
23 | // C++ Plugin Framework includes
24 | #include
25 | #include
26 |
27 | // Qt includes
28 |
29 | // System includes
30 |
31 | // Forward declarations
32 |
33 | // Macros
34 |
35 | // -------------------------------------------------------------------------------------------------
36 |
37 | namespace CppPluginFramework
38 | {
39 |
40 | //! Config class for a Plugin
41 | class CPPPLUGINFRAMEWORK_EXPORT PluginConfig : public CppConfigFramework::ConfigItem
42 | {
43 | public:
44 | //! Constructor
45 | PluginConfig() = default;
46 |
47 | /*!
48 | * Constructor
49 | *
50 | * \param filePath Path to the plugin's library
51 | * \param version Required plugin version
52 | * \param instanceConfigs List of plugin's instance configs
53 | */
54 | PluginConfig(const QString &filePath,
55 | const VersionInfo &version,
56 | const QList &instanceConfigs);
57 |
58 | /*!
59 | * Constructor
60 | *
61 | * \param filePath Path to the plugin's library
62 | * \param minVersion Minimum required plugin version
63 | * \param maxVersion Maximum required plugin version
64 | * \param instanceConfigs List of plugin's instance configs
65 | */
66 | PluginConfig(const QString &filePath,
67 | const VersionInfo &minVersion,
68 | const VersionInfo &maxVersion,
69 | const QList &instanceConfigs);
70 |
71 | /*!
72 | * Copy constructor
73 | *
74 | * \param other Instance to copy
75 | */
76 | PluginConfig(const PluginConfig &other) = default;
77 |
78 | /*!
79 | * Move constructor
80 | *
81 | * \param other Instance to move
82 | */
83 | PluginConfig(PluginConfig &&other) noexcept = default;
84 |
85 | //! Destructor
86 | ~PluginConfig() override = default;
87 |
88 | /*!
89 | * Copy assignment operator
90 | *
91 | * \param other Instance to copy assign
92 | *
93 | * \return Reference to this instance after the assignment is made
94 | */
95 | PluginConfig &operator=(const PluginConfig &other) = default;
96 |
97 | /*!
98 | * Move assignment operator
99 | *
100 | * \param other Instance to move assign
101 | *
102 | * \return Reference to this instance after the assignment is made
103 | */
104 | PluginConfig &operator=(PluginConfig &&other) noexcept = default;
105 |
106 | /*!
107 | * Checks if plugin config is valid
108 | *
109 | * \retval true Plugin config is valid
110 | * \retval false Plugin config is not valid
111 | */
112 | bool isValid() const;
113 |
114 | /*!
115 | * Checks if a specific version is required
116 | *
117 | * \retval true A specific version is required
118 | * \retval false A version range is allowed
119 | */
120 | bool isExactVersion() const;
121 |
122 | /*!
123 | * Checks if a version range is allowed
124 | *
125 | * \retval true A version range is allowed
126 | * \retval false A specific version is required
127 | */
128 | bool isVersionRange() const;
129 |
130 | /*!
131 | * Returns file path to the plugin's library
132 | *
133 | * \return File path to the plugin's library
134 | */
135 | QString filePath() const;
136 |
137 | /*!
138 | * Sets file path to the plugin's library
139 | *
140 | * \param filePath File path to the plugin's library
141 | */
142 | void setFilePath(const QString &filePath);
143 |
144 | /*!
145 | * Returns plugin's required version
146 | *
147 | * \return Plugin's required version
148 | */
149 | VersionInfo version() const;
150 |
151 | /*!
152 | * Sets plugin's required version
153 | *
154 | * \param version Plugin's required version
155 | */
156 | void setVersion(const VersionInfo &version);
157 |
158 | /*!
159 | * Returns plugin's required minimum version
160 | *
161 | * \return Plugin's required minimum version
162 | */
163 | VersionInfo minVersion() const;
164 |
165 | /*!
166 | * Sets plugin's required minimum version
167 | *
168 | * \param minVersion Plugin's required minimum version
169 | */
170 | void setMinVersion(const VersionInfo &minVersion);
171 |
172 | /*!
173 | * Returns plugin's required maximum version
174 | *
175 | * \return Plugin's required maximum version
176 | */
177 | VersionInfo maxVersion() const;
178 |
179 | /*!
180 | * Sets plugin's required maximum version
181 | *
182 | * \param minVersion Plugin's required maximum version
183 | */
184 | void setMaxVersion(const VersionInfo &maxVersion);
185 |
186 | /*!
187 | * Returns list of plugin's instance configs
188 | *
189 | * \return List of plugin's instance configs
190 | */
191 | const QList &instanceConfigs() const;
192 |
193 | /*!
194 | * Sets list of plugin's instance configs
195 | *
196 | * \param instanceConfigs List of plugin's instance configs
197 | */
198 | void setInstanceConfigs(const QList &instanceConfigs);
199 |
200 | private:
201 | //! \copydoc CppConfigFramework::ConfigItem::loadConfigParameters()
202 | bool loadConfigParameters(const CppConfigFramework::ConfigObjectNode &config) override;
203 |
204 | //! \copydoc CppConfigFramework::ConfigItem::storeConfigParameters()
205 | bool storeConfigParameters(CppConfigFramework::ConfigObjectNode *config) override;
206 |
207 | //! \copydoc CppConfigFramework::ConfigItem::validateConfig()
208 | QString validateConfig() const override;
209 |
210 | private:
211 | //! Holds the path to the plugin's library
212 | QString m_filePath;
213 |
214 | //! Holds the plugin's required version
215 | VersionInfo m_version;
216 |
217 | //! Holds the plugin's minimum required version
218 | VersionInfo m_minVersion;
219 |
220 | //! Holds the plugin's maximum required version
221 | VersionInfo m_maxVersion;
222 |
223 | //! Holds the list of plugin's instance configs
224 | QList m_instanceConfigs;
225 | };
226 |
227 | } // namespace CppPluginFramework
228 |
229 | // -------------------------------------------------------------------------------------------------
230 |
231 | /*!
232 | * Global "equal to" operator for CppPluginFramework::PluginConfig
233 | *
234 | * \param left Plugin config
235 | * \param right Plugin config
236 | *
237 | * \retval true Plugin configs are equal
238 | * \retval false Plugin configs are not equal
239 | */
240 | CPPPLUGINFRAMEWORK_EXPORT bool operator==(const CppPluginFramework::PluginConfig &left,
241 | const CppPluginFramework::PluginConfig &right);
242 |
243 | // -------------------------------------------------------------------------------------------------
244 |
245 | /*!
246 | * Global "not equal to" operator for CppPluginFramework::PluginConfig
247 | *
248 | * \param left Plugin config
249 | * \param right Plugin config
250 | *
251 | * \retval true Plugin configs are not equal
252 | * \retval false Plugin configs are equal
253 | */
254 | CPPPLUGINFRAMEWORK_EXPORT bool operator!=(const CppPluginFramework::PluginConfig &left,
255 | const CppPluginFramework::PluginConfig &right);
256 |
--------------------------------------------------------------------------------
/code/inc/CppPluginFramework/PluginFactoryTemplate.hpp:
--------------------------------------------------------------------------------
1 | /* This file is part of C++ Plugin Framework.
2 | *
3 | * C++ Plugin Framework is free software: you can redistribute it and/or modify it under the terms
4 | * of the GNU Lesser General Public License as published by the Free Software Foundation, either
5 | * version 3 of the License, or (at your option) any later version.
6 | *
7 | * C++ Plugin Framework is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
8 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 | * GNU Lesser General Public License for more details.
10 | *
11 | * You should have received a copy of the GNU Lesser General Public License along with C++ Plugin
12 | * Framework. If not, see .
13 | */
14 |
15 | /*!
16 | * \file
17 | *
18 | * Contains a template class for a factory that shall be able to create instances of a plugin
19 | */
20 |
21 | #pragma once
22 |
23 | // C++ Plugin Framework includes
24 | #include
25 |
26 | // Qt includes
27 | #include
28 |
29 | // System includes
30 |
31 | // Forward declarations
32 |
33 | // Macros
34 |
35 | // -------------------------------------------------------------------------------------------------
36 |
37 | namespace CppPluginFramework
38 | {
39 |
40 | /*!
41 | * This is a template class for a factory that shall be able to create instances of a plugin
42 | *
43 | * \tparam T Plugin class
44 | *
45 | * To create a plugin the following code needs to be put into the header file, preferably directly
46 | * after the declaration of the plugin class:
47 | *
48 | * \code{.cpp}
49 | *
50 | * class Q_DECL_EXPORT PluginFactory :
51 | * public QObject,
52 | * public CppPluginFramework::PluginFactoryTemplate
53 | * {
54 | * Q_OBJECT
55 | * Q_PLUGIN_METADATA(IID "CppPluginFramework::IPluginFactory")
56 | * Q_INTERFACES(CppPluginFramework::IPluginFactory)
57 | *
58 | * public:
59 | * ~PluginFactory() override = default;
60 | * };
61 | *
62 | * \endcode
63 | *
64 | * \note The PLUGIN_CLASS placeholders need to be replaced with the plugin class name
65 | */
66 | template::value, bool> = true>
67 | class PluginFactoryTemplate : public IPluginFactory
68 | {
69 | public:
70 | //! Destructor
71 | ~PluginFactoryTemplate() override = default;
72 |
73 | //! \copydoc IPluginFactory::createPluginInstance()
74 | std::unique_ptr createInstance(const QString &instanceName) const override
75 | {
76 | return std::make_unique(instanceName);
77 | }
78 | };
79 |
80 | } // namespace CppPluginFramework
81 |
--------------------------------------------------------------------------------
/code/inc/CppPluginFramework/PluginInstanceConfig.hpp:
--------------------------------------------------------------------------------
1 | /* This file is part of C++ Plugin Framework.
2 | *
3 | * C++ Plugin Framework is free software: you can redistribute it and/or modify it under the terms
4 | * of the GNU Lesser General Public License as published by the Free Software Foundation, either
5 | * version 3 of the License, or (at your option) any later version.
6 | *
7 | * C++ Plugin Framework is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
8 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 | * GNU Lesser General Public License for more details.
10 | *
11 | * You should have received a copy of the GNU Lesser General Public License along with C++ Plugin
12 | * Framework. If not, see .
13 | */
14 |
15 | /*!
16 | * \file
17 | *
18 | * Contains a config class for a Plugin Instance
19 | */
20 |
21 | #pragma once
22 |
23 | // C++ Plugin Framework includes
24 | #include
25 |
26 | // C++ Config Framework includes
27 | #include
28 |
29 | // Qt includes
30 |
31 | // System includes
32 |
33 | // Forward declarations
34 |
35 | // Macros
36 |
37 | // -------------------------------------------------------------------------------------------------
38 |
39 | namespace CppPluginFramework
40 | {
41 |
42 | //! Config class for a Plugin Instance
43 | class CPPPLUGINFRAMEWORK_EXPORT PluginInstanceConfig : public CppConfigFramework::ConfigItem
44 | {
45 | public:
46 | //! Constructor
47 | PluginInstanceConfig() = default;
48 |
49 | /*!
50 | * Constructor
51 | *
52 | * \param name Name of the plugin instance
53 | * \param config Plugin instance's config
54 | * \param dependencies List of plugin's dependencies
55 | */
56 | PluginInstanceConfig(const QString &name,
57 | const CppConfigFramework::ConfigObjectNode &config = {},
58 | const QSet &dependencies = {});
59 |
60 | /*!
61 | * Copy constructor
62 | *
63 | * \param other Instance to copy
64 | */
65 | PluginInstanceConfig(const PluginInstanceConfig &other);
66 |
67 | /*!
68 | * Move constructor
69 | *
70 | * \param other Instance to move
71 | */
72 | PluginInstanceConfig(PluginInstanceConfig &&other) noexcept = default;
73 |
74 | //! Destructor
75 | ~PluginInstanceConfig() override = default;
76 |
77 | /*!
78 | * Copy assignment operator
79 | *
80 | * \param other Instance to copy assign
81 | *
82 | * \return Reference to this instance after the assignment is made
83 | */
84 | PluginInstanceConfig &operator=(const PluginInstanceConfig &other);
85 |
86 | /*!
87 | * Move assignment operator
88 | *
89 | * \param other Instance to move assign
90 | *
91 | * \return Reference to this instance after the assignment is made
92 | */
93 | PluginInstanceConfig &operator=(PluginInstanceConfig &&other) noexcept = default;
94 |
95 | /*!
96 | * Checks if plugin instance config is valid
97 | *
98 | * \retval true Plugin instance config is valid
99 | * \retval false Plugin instance config is not valid
100 | */
101 | bool isValid() const;
102 |
103 | /*!
104 | * Returns plugin instance's name
105 | *
106 | * \return Plugin instance's name
107 | */
108 | QString name() const;
109 |
110 | /*!
111 | * Sets plugin instance's name
112 | *
113 | * \param name Plugin instance's name
114 | */
115 | void setName(const QString &name);
116 |
117 | /*!
118 | * Returns the plugin instance's config
119 | *
120 | * \return Plugin instance's config
121 | */
122 | const CppConfigFramework::ConfigObjectNode &config() const;
123 |
124 | /*!
125 | * Sets the plugin instance's config
126 | *
127 | * \param config Plugin instance's config
128 | */
129 | void setConfig(const CppConfigFramework::ConfigObjectNode &config);
130 |
131 | /*!
132 | * Returns list of plugin instance's dependencies
133 | *
134 | * \return List of plugin instance's dependencies
135 | */
136 | QSet dependencies() const;
137 |
138 | /*!
139 | * Sets list of plugin instance's dependencies
140 | *
141 | * \param dependencies List of plugin instance's dependencies
142 | */
143 | void setDependencies(const QSet &dependencies);
144 |
145 | private:
146 | //! \copydoc CppConfigFramework::ConfigItem::loadConfigParameters()
147 | bool loadConfigParameters(const CppConfigFramework::ConfigObjectNode &config) override;
148 |
149 | //! \copydoc CppConfigFramework::ConfigItem::storeConfigParameters()
150 | bool storeConfigParameters(CppConfigFramework::ConfigObjectNode *config) override;
151 |
152 | //! \copydoc CppConfigFramework::ConfigItem::validateConfig()
153 | QString validateConfig() const override;
154 |
155 | private:
156 | //! Holds the plugin instance's name
157 | QString m_name;
158 |
159 | //! Holds the (optional) plugin instance's config node
160 | CppConfigFramework::ConfigObjectNode m_config;
161 |
162 | //! Holds the list of plugin instance's dependencies
163 | QSet m_dependencies;
164 | };
165 |
166 | } // namespace CppPluginFramework
167 |
168 | // -------------------------------------------------------------------------------------------------
169 |
170 | /*!
171 | * Global "equal to" operator for CppPluginFramework::PluginInstanceConfig
172 | *
173 | * \param left Instance config
174 | * \param right Instance config
175 | *
176 | * \retval true Instance configs are equal
177 | * \retval false Instance configs are not equal
178 | */
179 | CPPPLUGINFRAMEWORK_EXPORT bool operator==(const CppPluginFramework::PluginInstanceConfig &left,
180 | const CppPluginFramework::PluginInstanceConfig &right);
181 |
182 | // -------------------------------------------------------------------------------------------------
183 |
184 | /*!
185 | * Global "not equal to" operator for CppPluginFramework::PluginInstanceConfig
186 | *
187 | * \param left Instance config
188 | * \param right Instance config
189 | *
190 | * \retval true Instance configs are not equal
191 | * \retval false Instance configs are equal
192 | */
193 | CPPPLUGINFRAMEWORK_EXPORT bool operator!=(const CppPluginFramework::PluginInstanceConfig &left,
194 | const CppPluginFramework::PluginInstanceConfig &right);
195 |
--------------------------------------------------------------------------------
/code/inc/CppPluginFramework/PluginManager.hpp:
--------------------------------------------------------------------------------
1 | /* This file is part of C++ Plugin Framework.
2 | *
3 | * C++ Plugin Framework is free software: you can redistribute it and/or modify it under the terms
4 | * of the GNU Lesser General Public License as published by the Free Software Foundation, either
5 | * version 3 of the License, or (at your option) any later version.
6 | *
7 | * C++ Plugin Framework is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
8 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 | * GNU Lesser General Public License for more details.
10 | *
11 | * You should have received a copy of the GNU Lesser General Public License along with C++ Plugin
12 | * Framework. If not, see .
13 | */
14 |
15 | /*!
16 | * \file
17 | *
18 | * Contains a plugin management class
19 | */
20 |
21 | #pragma once
22 |
23 | // C++ Plugin Framework includes
24 | #include
25 | #include
26 |
27 | // Qt includes
28 |
29 | // System includes
30 |
31 | // Forward declarations
32 |
33 | // Macros
34 |
35 | // -------------------------------------------------------------------------------------------------
36 |
37 | namespace CppPluginFramework
38 | {
39 |
40 | //! This class manages plugins
41 | class CPPPLUGINFRAMEWORK_EXPORT PluginManager
42 | {
43 | public:
44 | //! Destructor
45 | ~PluginManager();
46 |
47 | /*!
48 | * Loads all plugin instances specified in the config
49 | *
50 | * \param pluginManagerConfig Plugin manager configs
51 | *
52 | * \retval true Success
53 | * \retval false Failure
54 | *
55 | * After each plugin is loaded all of its instances get created and configured. When all the
56 | * plugins are loaded the dependencies of each plugin instance are injected into it.
57 | */
58 | bool load(const PluginManagerConfig &pluginManagerConfig);
59 |
60 | /*!
61 | * Unloads all loaded plugin instances
62 | *
63 | * \retval true Success
64 | * \retval false Failure
65 | */
66 | bool unload();
67 |
68 | /*!
69 | * Starts all loaded plugin instances
70 | *
71 | * \retval true Success
72 | * \retval false Failure
73 | */
74 | bool start();
75 |
76 | //! Stops all loaded plugin instances
77 | void stop();
78 |
79 | /*!
80 | * Checks if a plugin instance with the specified name was loaded
81 | *
82 | * \param instanceName Plugin instance name
83 | *
84 | * \retval true Plugin was loaded
85 | * \retval false Plugin was not loaded
86 | */
87 | bool hasPluginInstance(const QString &instanceName) const;
88 |
89 | /*!
90 | * Gets the specified plugin instance
91 | *
92 | * \param instanceName Plugin instance name
93 | *
94 | * \return Plugin instance or nullptr if there is no plugin instance with that name
95 | */
96 | IPlugin *pluginInstance(const QString &instanceName);
97 |
98 | /*!
99 | * Gets names of all loaded plugin instances
100 | *
101 | * \return Names of all loaded plugin instances
102 | */
103 | QStringList pluginInstanceNames() const;
104 |
105 | private:
106 | /*!
107 | * Injects dependencies to all specified plugins
108 | *
109 | * \param pluginConfigs List of plugin configs
110 | *
111 | * \retval true All dependencies were injected
112 | * \retval false Injection of at least one dependency failed
113 | */
114 | bool injectAllDependencies(const QList &pluginConfigs);
115 |
116 | /*!
117 | * Injects dependencies to the specified instance
118 | *
119 | * \param instanceName Name of the plugin instance to inject dependencies to
120 | * \param dependencies Names of the needed dependencies to inject
121 | *
122 | * \retval true Success
123 | * \retval false Failure
124 | */
125 | bool injectDependencies(const QString &instanceName, const QSet &dependencies);
126 |
127 | /*!
128 | * Ejects all injected dependencies
129 | *
130 | * \retval true Success
131 | * \retval false Failure (at least one plugin instance was still running)
132 | */
133 | bool ejectDependencies();
134 |
135 | private:
136 | //! Holds all of the loaded plugins
137 | std::map> m_pluginInstances;
138 |
139 | //! Holds the order in which the plugin instances will be started
140 | QStringList m_pluginStartupOrder;
141 | };
142 |
143 | } // namespace CppPluginFramework
144 |
--------------------------------------------------------------------------------
/code/inc/CppPluginFramework/PluginManagerConfig.hpp:
--------------------------------------------------------------------------------
1 | /* This file is part of C++ Plugin Framework.
2 | *
3 | * C++ Plugin Framework is free software: you can redistribute it and/or modify it under the terms
4 | * of the GNU Lesser General Public License as published by the Free Software Foundation, either
5 | * version 3 of the License, or (at your option) any later version.
6 | *
7 | * C++ Plugin Framework is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
8 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 | * GNU Lesser General Public License for more details.
10 | *
11 | * You should have received a copy of the GNU Lesser General Public License along with C++ Plugin
12 | * Framework. If not, see .
13 | */
14 |
15 | /*!
16 | * \file
17 | *
18 | * Contains a config class for the Plugin Manager
19 | */
20 |
21 | #pragma once
22 |
23 | // C++ Plugin Framework includes
24 | #include
25 |
26 | // Qt includes
27 |
28 | // System includes
29 |
30 | // Forward declarations
31 |
32 | // Macros
33 |
34 | // -------------------------------------------------------------------------------------------------
35 |
36 | namespace CppPluginFramework
37 | {
38 |
39 | //! Config class for the Plugin Manager
40 | class CPPPLUGINFRAMEWORK_EXPORT PluginManagerConfig : public CppConfigFramework::ConfigItem
41 | {
42 | public:
43 | //! Constructor
44 | PluginManagerConfig() = default;
45 |
46 | /*!
47 | * Copy constructor
48 | *
49 | * \param other Instance to copy
50 | */
51 | PluginManagerConfig(const PluginManagerConfig &other) = default;
52 |
53 | /*!
54 | * Move constructor
55 | *
56 | * \param other Instance to move
57 | */
58 | PluginManagerConfig(PluginManagerConfig &&other) noexcept = default;
59 |
60 | //! Destructor
61 | ~PluginManagerConfig() override = default;
62 |
63 | /*!
64 | * Copy assignment operator
65 | *
66 | * \param other Instance to copy assign
67 | *
68 | * \return Reference to this instance after the assignment is made
69 | */
70 | PluginManagerConfig &operator=(const PluginManagerConfig &other) = default;
71 |
72 | /*!
73 | * Move assignment operator
74 | *
75 | * \param other Instance to move assign
76 | *
77 | * \return Reference to this instance after the assignment is made
78 | */
79 | PluginManagerConfig &operator=(PluginManagerConfig &&other) noexcept = default;
80 |
81 | /*!
82 | * Checks if plugin config is valid
83 | *
84 | * \retval true Plugin config is valid
85 | * \retval false Plugin config is not valid
86 | */
87 | bool isValid() const;
88 |
89 | /*!
90 | * Gets plugin configs that were read from the config file
91 | *
92 | * \return Plugin configs
93 | */
94 | const QList &pluginConfigs() const;
95 |
96 | /*!
97 | * Sets list of plugin configs
98 | *
99 | * \param pluginConfigs List of plugin configs
100 | */
101 | void setPluginConfigs(const QList &pluginConfigs);
102 |
103 | /*!
104 | * Gets priorities for starting plugin instances
105 | *
106 | * \return Plugin configs
107 | */
108 | const QStringList &pluginStartupPriorities() const;
109 |
110 | /*!
111 | * Sets priorities for starting plugin instances
112 | *
113 | * \param startupPriorities Priorities for starting plugin instances
114 | */
115 | void setPluginStartupPriorities(const QStringList &startupPriorities);
116 |
117 | private:
118 | //! \copydoc CppConfigFramework::ConfigItem::loadConfigParameters()
119 | bool loadConfigParameters(const CppConfigFramework::ConfigObjectNode &config) override;
120 |
121 | //! \copydoc CppConfigFramework::ConfigItem::storeConfigParameters()
122 | bool storeConfigParameters(CppConfigFramework::ConfigObjectNode *config) override;
123 |
124 | //! \copydoc CppConfigFramework::ConfigItem::validateConfig()
125 | QString validateConfig() const override;
126 |
127 | private:
128 | //! Holds the plugin configs
129 | QList m_pluginConfigs;
130 |
131 | //! Holds the optional order in which the plugin instances need to be started; all unreferenced
132 | //! plugin instances will be started in no particular order
133 | QStringList m_pluginStartupPriorities;
134 | };
135 |
136 | } // namespace CppPluginFramework
137 |
138 | // -------------------------------------------------------------------------------------------------
139 |
140 | /*!
141 | * Global "equal to" operator for CppPluginFramework::PluginManagerConfig
142 | *
143 | * \param left Plugin config
144 | * \param right Plugin config
145 | *
146 | * \retval true Plugin configs are equal
147 | * \retval false Plugin configs are not equal
148 | */
149 | CPPPLUGINFRAMEWORK_EXPORT bool operator==(const CppPluginFramework::PluginManagerConfig &left,
150 | const CppPluginFramework::PluginManagerConfig &right);
151 |
152 | // -------------------------------------------------------------------------------------------------
153 |
154 | /*!
155 | * Global "not equal to" operator for CppPluginFramework::PluginManagerConfig
156 | *
157 | * \param left Plugin config
158 | * \param right Plugin config
159 | *
160 | * \retval true Plugin configs are not equal
161 | * \retval false Plugin configs are equal
162 | */
163 | CPPPLUGINFRAMEWORK_EXPORT bool operator!=(const CppPluginFramework::PluginManagerConfig &left,
164 | const CppPluginFramework::PluginManagerConfig &right);
165 |
--------------------------------------------------------------------------------
/code/inc/CppPluginFramework/Validation.hpp:
--------------------------------------------------------------------------------
1 | /* This file is part of C++ Plugin Framework.
2 | *
3 | * C++ Plugin Framework is free software: you can redistribute it and/or modify it under the terms
4 | * of the GNU Lesser General Public License as published by the Free Software Foundation, either
5 | * version 3 of the License, or (at your option) any later version.
6 | *
7 | * C++ Plugin Framework is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
8 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 | * GNU Lesser General Public License for more details.
10 | *
11 | * You should have received a copy of the GNU Lesser General Public License along with C++ Plugin
12 | * Framework. If not, see .
13 | */
14 |
15 | /*!
16 | * \file
17 | *
18 | * Contains validation methods
19 | */
20 |
21 | #pragma once
22 |
23 | // C++ Plugin Framework includes
24 | #include
25 |
26 | // Qt includes
27 | #include
28 |
29 | // System includes
30 |
31 | // Forward declarations
32 |
33 | // Macros
34 |
35 | // -------------------------------------------------------------------------------------------------
36 |
37 | namespace CppPluginFramework
38 | {
39 |
40 | namespace Validation
41 | {
42 |
43 | /*!
44 | * Validates plugin's instance name
45 | *
46 | * \param name Plugin's instance name
47 | *
48 | * \retval true Plugin's instance name is valid
49 | * \retval false Plugin's instance name is not valid
50 | */
51 | CPPPLUGINFRAMEWORK_EXPORT bool validatePluginInstanceName(const QString &name);
52 |
53 | /*!
54 | * Validates plugin's interface name
55 | *
56 | * \param name Plugin's interface name
57 | *
58 | * \retval true Plugin's interface name is valid
59 | * \retval false Plugin's interface name is not valid
60 | */
61 | CPPPLUGINFRAMEWORK_EXPORT bool validateInterfaceName(const QString &name);
62 |
63 | /*!
64 | * Validates plugin's exported interfaces
65 | *
66 | * \param exportedInterfaces Plugin's exported interface names
67 | *
68 | * \retval true Plugin's exported interfaces are valid
69 | * \retval false Plugin's exported interfaces are not valid
70 | *
71 | * This method checks if at least one interface is exported and if the interface names are valid.
72 | */
73 | CPPPLUGINFRAMEWORK_EXPORT bool validateExportedInterfaces(const QSet &exportedInterfaces);
74 |
75 | /*!
76 | * Validates the environment variable name
77 | *
78 | * \param name Environment variable name
79 | *
80 | * \retval true Valid
81 | * \retval false Invalid
82 | */
83 | CPPPLUGINFRAMEWORK_EXPORT bool validateEnvironmentVariableName(const QString &name);
84 |
85 | /*!
86 | * Validates file path
87 | *
88 | * \param filePath File path to validate
89 | *
90 | * \retval true Valid
91 | * \retval false Invalid
92 | */
93 | CPPPLUGINFRAMEWORK_EXPORT bool validateFilePath(const QString &filePath);
94 |
95 | } // namespace Validation
96 |
97 | } // namespace CppPluginFramework
98 |
--------------------------------------------------------------------------------
/code/inc/CppPluginFramework/VersionInfo.hpp:
--------------------------------------------------------------------------------
1 | /* This file is part of C++ Plugin Framework.
2 | *
3 | * C++ Plugin Framework is free software: you can redistribute it and/or modify it under the terms
4 | * of the GNU Lesser General Public License as published by the Free Software Foundation, either
5 | * version 3 of the License, or (at your option) any later version.
6 | *
7 | * C++ Plugin Framework is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
8 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 | * GNU Lesser General Public License for more details.
10 | *
11 | * You should have received a copy of the GNU Lesser General Public License along with C++ Plugin
12 | * Framework. If not, see .
13 | */
14 |
15 | /*!
16 | * \file
17 | *
18 | * Contains a class that holds version information
19 | */
20 |
21 | #pragma once
22 |
23 | // C++ Plugin Framework includes
24 | #include
25 |
26 | // C++ Config Framework includes
27 |
28 | // Cedar Framework includes
29 | #include
30 |
31 | // Qt includes
32 |
33 | // System includes
34 |
35 | // Forward declarations
36 |
37 | // Macros
38 |
39 | // -------------------------------------------------------------------------------------------------
40 |
41 | namespace CppPluginFramework
42 | {
43 |
44 | /*!
45 | * This class holds version information
46 | */
47 | class CPPPLUGINFRAMEWORK_EXPORT VersionInfo
48 | {
49 | public:
50 | //! Constructor
51 | VersionInfo();
52 |
53 | /*!
54 | * Constructor
55 | *
56 | * \param major Major version number
57 | * \param minor Minor version number
58 | * \param patch Patch version number
59 | * \param dev Optional development version string
60 | */
61 | VersionInfo(const int major, const int minor, const int patch, const QString &dev = {});
62 |
63 | /*!
64 | * Constructor
65 | *
66 | * \param version String representation of the version
67 | */
68 | VersionInfo(const QString &version);
69 |
70 | /*!
71 | * Checks if version information is null (default constructed value)
72 | *
73 | * \retval true Null
74 | * \retval false Not null
75 | */
76 | bool isNull() const;
77 |
78 | /*!
79 | * Checks if version information is valid
80 | *
81 | * \retval true Valid
82 | * \retval false Invalid
83 | */
84 | bool isValid() const;
85 |
86 | /*!
87 | * Returns major version number
88 | *
89 | * \return Major version number
90 | */
91 | int major() const;
92 |
93 | /*!
94 | * Sets major version number
95 | *
96 | * \param major Major version number
97 | */
98 | void setMajor(const int &major);
99 |
100 | /*!
101 | * Returns minor version number
102 | *
103 | * \return Minor version number
104 | */
105 | int minor() const;
106 |
107 | /*!
108 | * Sets minor version number
109 | *
110 | * \param minor Minor version number
111 | */
112 | void setMinor(const int &minor);
113 |
114 | /*!
115 | * Returns patch version number
116 | *
117 | * \return Patch version number
118 | */
119 | int patch() const;
120 |
121 | /*!
122 | * Sets patch version number
123 | *
124 | * \param patch Patch version number
125 | */
126 | void setPatch(const int &patch);
127 |
128 | /*!
129 | * Returns development version string
130 | *
131 | * \return Development version string
132 | */
133 | QString dev() const;
134 |
135 | /*!
136 | * Sets development version string
137 | *
138 | * \param dev Development version string
139 | */
140 | void setDev(const QString &dev);
141 |
142 | /*!
143 | * Generates a string representation of the version
144 | *
145 | * \return String representation of the version
146 | */
147 | QString toString() const;
148 |
149 | /*!
150 | * Checks if version range is valid
151 | *
152 | * \param minVersion Minimum version
153 | * \param maxVersion Maximum version
154 | *
155 | * \retval true Valid
156 | * \retval false Invalid
157 | */
158 | static bool isRangeValid(const VersionInfo &minVersion, const VersionInfo &maxVersion);
159 |
160 | /*!
161 | * Checks if specified version is in version range
162 | *
163 | * \param version Version to check
164 | * \param minVersion Minimum version
165 | * \param maxVersion Maximum version
166 | *
167 | * \retval true Version is in range
168 | * \retval false Version is in not range
169 | */
170 | static bool isVersionInRange(const VersionInfo &version,
171 | const VersionInfo &minVersion,
172 | const VersionInfo &maxVersion);
173 |
174 | private:
175 | //! Major version number
176 | int m_major;
177 |
178 | //! Minor version number
179 | int m_minor;
180 |
181 | //! Patch version number
182 | int m_patch;
183 |
184 | //! Development version number
185 | QString m_dev;
186 | };
187 |
188 | } // namespace CppPluginFramework
189 |
190 | // -------------------------------------------------------------------------------------------------
191 |
192 | /*!
193 | * Global "equal to" operator for CppPluginFramework::VersionInfo
194 | *
195 | * \param left Version
196 | * \param right Version
197 | *
198 | * \retval true Versions are equal
199 | * \retval false Versions are not equal
200 | *
201 | * \note Result of the comparison is valid only if both versions are valid!
202 | */
203 | CPPPLUGINFRAMEWORK_EXPORT bool operator==(const CppPluginFramework::VersionInfo &left,
204 | const CppPluginFramework::VersionInfo &right);
205 |
206 | // -------------------------------------------------------------------------------------------------
207 |
208 | /*!
209 | * Global "not equal to" operator for CppPluginFramework::VersionInfo
210 | *
211 | * \param left Version
212 | * \param right Version
213 | *
214 | * \retval true Versions are not equal
215 | * \retval false Versions are equal
216 | *
217 | * \note Result of the comparison is valid only if both versions are valid!
218 | */
219 | CPPPLUGINFRAMEWORK_EXPORT bool operator!=(const CppPluginFramework::VersionInfo &left,
220 | const CppPluginFramework::VersionInfo &right);
221 |
222 | // -------------------------------------------------------------------------------------------------
223 |
224 | /*!
225 | * Global "less than" operator for CppPluginFramework::VersionInfo
226 | *
227 | * \param left Version
228 | * \param right Version
229 | *
230 | * \retval true Version "left" is smaller than version "right"
231 | * \retval false Version "left" is not smaller than version "right"
232 | *
233 | * \note Result of the comparison is valid only if both versions are valid!
234 | */
235 | CPPPLUGINFRAMEWORK_EXPORT bool operator<(const CppPluginFramework::VersionInfo &left,
236 | const CppPluginFramework::VersionInfo &right);
237 |
238 | // -------------------------------------------------------------------------------------------------
239 |
240 | /*!
241 | * Global "less than or equal to" operator for CppPluginFramework::VersionInfo
242 | *
243 | * \param left Version
244 | * \param right Version
245 | *
246 | * \retval true Version "left" is less than or equal to version "right"
247 | * \retval false Version "left" is not less than or equal to version "right"
248 | *
249 | * \note Result of the comparison is valid only if both versions are valid!
250 | */
251 | CPPPLUGINFRAMEWORK_EXPORT bool operator<=(const CppPluginFramework::VersionInfo &left,
252 | const CppPluginFramework::VersionInfo &right);
253 |
254 | // -------------------------------------------------------------------------------------------------
255 |
256 | /*!
257 | * Global "greater than" operator for CppPluginFramework::VersionInfo
258 | *
259 | * \param left Version
260 | * \param right Version
261 | *
262 | * \retval true Version "left" is greater than version "right"
263 | * \retval false Version "left" is not greater than version "right"
264 | *
265 | * \note Result of the comparison is valid only if both versions are valid!
266 | */
267 | CPPPLUGINFRAMEWORK_EXPORT bool operator>(const CppPluginFramework::VersionInfo &left,
268 | const CppPluginFramework::VersionInfo &right);
269 |
270 | // -------------------------------------------------------------------------------------------------
271 |
272 | /*!
273 | * Global "greater than or equal to" operator for CppPluginFramework::VersionInfo
274 | *
275 | * \param left Version
276 | * \param right Version
277 | *
278 | * \retval true Version "left" is greater than or equal to version "right"
279 | * \retval false Version "left" is not greater than or equal to version "right"
280 | *
281 | * \note Result of the comparison is valid only if both versions are valid!
282 | */
283 | CPPPLUGINFRAMEWORK_EXPORT bool operator>=(const CppPluginFramework::VersionInfo &left,
284 | const CppPluginFramework::VersionInfo &right);
285 |
286 | // -------------------------------------------------------------------------------------------------
287 |
288 | namespace CedarFramework
289 | {
290 |
291 | //! \copydoc CedarFramework::serialize()
292 | template<>
293 | CPPPLUGINFRAMEWORK_EXPORT bool deserialize(const QJsonValue &json,
294 | CppPluginFramework::VersionInfo *value);
295 |
296 | }
297 |
--------------------------------------------------------------------------------
/code/src/AbstractPlugin.cpp:
--------------------------------------------------------------------------------
1 | /* This file is part of C++ Plugin Framework.
2 | *
3 | * C++ Plugin Framework is free software: you can redistribute it and/or modify it under the terms
4 | * of the GNU Lesser General Public License as published by the Free Software Foundation, either
5 | * version 3 of the License, or (at your option) any later version.
6 | *
7 | * C++ Plugin Framework is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
8 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 | * GNU Lesser General Public License for more details.
10 | *
11 | * You should have received a copy of the GNU Lesser General Public License along with C++ Plugin
12 | * Framework. If not, see .
13 | */
14 |
15 | /*!
16 | * \file
17 | *
18 | * Contains a convenience base class for creating plugins
19 | */
20 |
21 | // Own header
22 | #include
23 |
24 | // C++ Plugin Framework includes
25 |
26 | // Qt includes
27 |
28 | // System includes
29 |
30 | // Forward declarations
31 |
32 | // Macros
33 |
34 | // -------------------------------------------------------------------------------------------------
35 |
36 | namespace CppPluginFramework
37 | {
38 |
39 | AbstractPlugin::AbstractPlugin(const QString &name,
40 | const VersionInfo &version,
41 | const QString &description,
42 | const QSet &exportedInterfaces)
43 | : m_name(name),
44 | m_version(version),
45 | m_description(description),
46 | m_exportedInterfaces(exportedInterfaces),
47 | m_started(false)
48 | {
49 | }
50 |
51 | // -------------------------------------------------------------------------------------------------
52 |
53 | QString AbstractPlugin::name() const
54 | {
55 | QMutexLocker locker(&m_mutex);
56 | return m_name;
57 | }
58 |
59 | // -------------------------------------------------------------------------------------------------
60 |
61 | QString AbstractPlugin::description() const
62 | {
63 | QMutexLocker locker(&m_mutex);
64 |
65 | return m_description;
66 | }
67 |
68 | // -------------------------------------------------------------------------------------------------
69 |
70 | VersionInfo AbstractPlugin::version() const
71 | {
72 | QMutexLocker locker(&m_mutex);
73 | return m_version;
74 | }
75 |
76 | // -------------------------------------------------------------------------------------------------
77 |
78 | bool AbstractPlugin::isInterfaceExported(const QString &interface) const
79 | {
80 | QMutexLocker locker(&m_mutex);
81 | return m_exportedInterfaces.contains(interface);
82 | }
83 |
84 | // -------------------------------------------------------------------------------------------------
85 |
86 | QSet AbstractPlugin::exportedInterfaces() const
87 | {
88 | QMutexLocker locker(&m_mutex);
89 | return m_exportedInterfaces;
90 | }
91 |
92 | // -------------------------------------------------------------------------------------------------
93 |
94 | bool AbstractPlugin::isStarted() const
95 | {
96 | QMutexLocker locker(&m_mutex);
97 | return m_started;
98 | }
99 |
100 | // -------------------------------------------------------------------------------------------------
101 |
102 | bool AbstractPlugin::start()
103 | {
104 | // Check if plugin is already started
105 | if (isStarted())
106 | {
107 | // Error, plugin is already started
108 | return false;
109 | }
110 |
111 | // Start the plugin
112 | const bool success = onStart();
113 |
114 | QMutexLocker locker(&m_mutex);
115 | m_started = success;
116 | return success;
117 | }
118 |
119 | // -------------------------------------------------------------------------------------------------
120 |
121 | void AbstractPlugin::stop()
122 | {
123 | // Check if plugin is actually started
124 | if (!isStarted())
125 | {
126 | // Plugin is already stopped
127 | return;
128 | }
129 |
130 | // Stop the plugin
131 | onStop();
132 |
133 | QMutexLocker locker(&m_mutex);
134 | m_started = false;
135 | }
136 |
137 | // -------------------------------------------------------------------------------------------------
138 |
139 | bool AbstractPlugin::onStart()
140 | {
141 | return true;
142 | }
143 |
144 | // -------------------------------------------------------------------------------------------------
145 |
146 | void AbstractPlugin::onStop()
147 | {
148 | }
149 |
150 | } // namespace CppPluginFramework
151 |
--------------------------------------------------------------------------------
/code/src/LoggingCategories.cpp:
--------------------------------------------------------------------------------
1 | /* This file is part of C++ Plugin Framework.
2 | *
3 | * C++ Plugin Framework is free software: you can redistribute it and/or modify it under the terms
4 | * of the GNU Lesser General Public License as published by the Free Software Foundation, either
5 | * version 3 of the License, or (at your option) any later version.
6 | *
7 | * C++ Plugin Framework is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
8 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 | * GNU Lesser General Public License for more details.
10 | *
11 | * You should have received a copy of the GNU Lesser General Public License along with C++ Plugin
12 | * Framework. If not, see .
13 | */
14 |
15 | /*!
16 | * \file
17 | *
18 | * Contains logging categories
19 | */
20 |
21 | // Own header
22 | #include
23 |
24 | // C++ Plugin Framework includes
25 |
26 | // Qt includes
27 |
28 | // System includes
29 |
30 | // Forward declarations
31 |
32 | // Macros
33 |
34 | // -------------------------------------------------------------------------------------------------
35 |
36 | namespace CppPluginFramework
37 | {
38 |
39 | namespace LoggingCategory
40 | {
41 |
42 | const QLoggingCategory Config("CppPluginFramework.Config");
43 | const QLoggingCategory Plugin("CppPluginFramework.Plugin");
44 | const QLoggingCategory PluginManager("CppPluginFramework.PluginManager");
45 |
46 | } // namespace LoggingCategory
47 |
48 | } // namespace CppPluginFramework
49 |
--------------------------------------------------------------------------------
/code/src/Plugin.cpp:
--------------------------------------------------------------------------------
1 | /* This file is part of C++ Plugin Framework.
2 | *
3 | * C++ Plugin Framework is free software: you can redistribute it and/or modify it under the terms
4 | * of the GNU Lesser General Public License as published by the Free Software Foundation, either
5 | * version 3 of the License, or (at your option) any later version.
6 | *
7 | * C++ Plugin Framework is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
8 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 | * GNU Lesser General Public License for more details.
10 | *
11 | * You should have received a copy of the GNU Lesser General Public License along with C++ Plugin
12 | * Framework. If not, see .
13 | */
14 |
15 | /*!
16 | * \file
17 | *
18 | * Contains a class that is able to load a plugin from a library
19 | */
20 |
21 | // Own header
22 | #include
23 |
24 | // C++ Plugin Framework includes
25 | #include
26 | #include
27 | #include
28 |
29 | // Qt includes
30 | #include
31 | #include
32 |
33 | // System includes
34 |
35 | // Forward declarations
36 |
37 | // Macros
38 |
39 | // -------------------------------------------------------------------------------------------------
40 |
41 | namespace CppPluginFramework
42 | {
43 |
44 | std::vector> Plugin::loadInstances(const PluginConfig &pluginConfig)
45 | {
46 | // Check plugin config
47 | if (!pluginConfig.isValid())
48 | {
49 | qCWarning(CppPluginFramework::LoggingCategory::Plugin) << "Plugin config is not valid!";
50 | return {};
51 | }
52 |
53 | // Load plugin from the library and extract the plugin factory interface from it
54 | QPluginLoader loader(pluginConfig.filePath());
55 | auto *loaderInstance = loader.instance();
56 |
57 | if (loaderInstance == nullptr)
58 | {
59 | qCWarning(CppPluginFramework::LoggingCategory::Plugin)
60 | << "Failed to load plugin:" << loader.fileName();
61 | return {};
62 | }
63 |
64 | auto *pluginFactory = qobject_cast(loaderInstance);
65 |
66 | if (pluginFactory == nullptr)
67 | {
68 | qCWarning(CppPluginFramework::LoggingCategory::Plugin)
69 | << QString("Loaded plugin [%1] does not implement the plugin factory interface!")
70 | .arg(loader.fileName());
71 | return {};
72 | }
73 |
74 | // Create plugin instances
75 | std::vector> instances;
76 |
77 | for (const PluginInstanceConfig &instanceConfig : pluginConfig.instanceConfigs())
78 | {
79 | // Create plugin instance
80 | auto instance = loadInstance(*pluginFactory, instanceConfig);
81 |
82 | if (!instance)
83 | {
84 | qCWarning(CppPluginFramework::LoggingCategory::Plugin)
85 | << QString("Failed to load the plugin instance [%1] from the plugin [%2]!")
86 | .arg(instanceConfig.name(), loader.fileName());
87 | return {};
88 | }
89 |
90 | // Check plugin's version
91 | if (!checkVersion(instance->version(), pluginConfig))
92 | {
93 | qCWarning(CppPluginFramework::LoggingCategory::Plugin)
94 | << QString("Plugin instance [%1] from the plugin [%2] has an unsupported "
95 | "version!").arg(instanceConfig.name(), loader.fileName());
96 | return {};
97 | }
98 |
99 | // Add the instance to the container of loaded instances
100 | instances.push_back(std::move(instance));
101 | }
102 |
103 | return instances;
104 | }
105 |
106 | // -------------------------------------------------------------------------------------------------
107 |
108 | std::unique_ptr Plugin::loadInstance(const IPluginFactory &pluginFactory,
109 | const PluginInstanceConfig &instanceConfig)
110 | {
111 | // Create plugin instance
112 | auto instance = pluginFactory.createInstance(instanceConfig.name());
113 |
114 | if (!instance)
115 | {
116 | qCWarning(CppPluginFramework::LoggingCategory::Plugin)
117 | << "Failed to create the plugin instance!";
118 | return {};
119 | }
120 |
121 | // Configure the plugin instance
122 | if (!instance->loadConfig(instanceConfig.config()))
123 | {
124 | qCWarning(CppPluginFramework::LoggingCategory::Plugin)
125 | << "Failed to load the plugin instance's configuration!";
126 | return {};
127 | }
128 |
129 | return instance;
130 | }
131 |
132 | // -------------------------------------------------------------------------------------------------
133 |
134 | bool Plugin::checkVersion(const VersionInfo &pluginVersion, const PluginConfig &pluginConfig)
135 | {
136 | if (pluginConfig.isExactVersion())
137 | {
138 | // Plugin's version must match the exact version
139 | if (pluginVersion != pluginConfig.version())
140 | {
141 | qCWarning(CppPluginFramework::LoggingCategory::Plugin)
142 | << QString("Loaded plugin's version [%1] does not match the expected version "
143 | "[%2]!").arg(pluginVersion.toString(),
144 | pluginConfig.version().toString());
145 | return false;
146 | }
147 | }
148 | else
149 | {
150 | // Plugin's version must be within the version range
151 | if (!VersionInfo::isVersionInRange(pluginVersion,
152 | pluginConfig.minVersion(),
153 | pluginConfig.maxVersion()))
154 | {
155 | qCWarning(CppPluginFramework::LoggingCategory::Plugin)
156 | << QString("Loaded plugin's version [%1] does not match the expected version "
157 | "range: min=[%2], max=[%3]!")
158 | .arg(pluginVersion.toString(),
159 | pluginConfig.minVersion().toString(),
160 | pluginConfig.maxVersion().toString());
161 | return false;
162 | }
163 | }
164 |
165 | return true;
166 | }
167 |
168 | } // namespace CppPluginFramework
169 |
--------------------------------------------------------------------------------
/code/src/PluginConfig.cpp:
--------------------------------------------------------------------------------
1 | /* This file is part of C++ Plugin Framework.
2 | *
3 | * C++ Plugin Framework is free software: you can redistribute it and/or modify it under the terms
4 | * of the GNU Lesser General Public License as published by the Free Software Foundation, either
5 | * version 3 of the License, or (at your option) any later version.
6 | *
7 | * C++ Plugin Framework is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
8 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 | * GNU Lesser General Public License for more details.
10 | *
11 | * You should have received a copy of the GNU Lesser General Public License along with C++ Plugin
12 | * Framework. If not, see .
13 | */
14 |
15 | /*!
16 | * \file
17 | *
18 | * Contains a config class for a Plugin
19 | */
20 |
21 | // Own header
22 | #include
23 |
24 | // C++ Plugin Framework includes
25 | #include
26 | #include
27 |
28 | // Qt includes
29 | #include
30 |
31 | // System includes
32 |
33 | // Forward declarations
34 |
35 | // Macros
36 |
37 | // -------------------------------------------------------------------------------------------------
38 |
39 | namespace CppPluginFramework
40 | {
41 |
42 | PluginConfig::PluginConfig(const QString &filePath,
43 | const VersionInfo &version,
44 | const QList &instanceConfigs)
45 | : m_filePath(filePath),
46 | m_version(version),
47 | m_instanceConfigs(instanceConfigs)
48 | {
49 | }
50 |
51 | // -------------------------------------------------------------------------------------------------
52 |
53 | PluginConfig::PluginConfig(const QString &filePath,
54 | const VersionInfo &minVersion,
55 | const VersionInfo &maxVersion,
56 | const QList &instanceConfigs)
57 | : m_filePath(filePath),
58 | m_minVersion(minVersion),
59 | m_maxVersion(maxVersion),
60 | m_instanceConfigs(instanceConfigs)
61 | {
62 | }
63 |
64 | // -------------------------------------------------------------------------------------------------
65 |
66 | bool PluginConfig::isValid() const
67 | {
68 | return validateConfig().isEmpty();
69 | }
70 |
71 | // -------------------------------------------------------------------------------------------------
72 |
73 | bool PluginConfig::isExactVersion() const
74 | {
75 | return ((!m_version.isNull()) && m_minVersion.isNull() && m_maxVersion.isNull());
76 | }
77 |
78 | // -------------------------------------------------------------------------------------------------
79 |
80 | bool PluginConfig::isVersionRange() const
81 | {
82 | return (m_version.isNull() && (!m_minVersion.isNull()) && (!m_maxVersion.isNull()));
83 | }
84 |
85 | // -------------------------------------------------------------------------------------------------
86 |
87 | QString PluginConfig::filePath() const
88 | {
89 | return m_filePath;
90 | }
91 |
92 | // -------------------------------------------------------------------------------------------------
93 |
94 | void PluginConfig::setFilePath(const QString &filePath)
95 | {
96 | m_filePath = filePath;
97 | }
98 |
99 | // -------------------------------------------------------------------------------------------------
100 |
101 | VersionInfo PluginConfig::version() const
102 | {
103 | return m_version;
104 | }
105 |
106 | // -------------------------------------------------------------------------------------------------
107 |
108 | void PluginConfig::setVersion(const VersionInfo &version)
109 | {
110 | m_version = version;
111 | }
112 |
113 | // -------------------------------------------------------------------------------------------------
114 |
115 | VersionInfo PluginConfig::minVersion() const
116 | {
117 | return m_minVersion;
118 | }
119 |
120 | // -------------------------------------------------------------------------------------------------
121 |
122 | void PluginConfig::setMinVersion(const VersionInfo &minVersion)
123 | {
124 | m_minVersion = minVersion;
125 | }
126 |
127 | // -------------------------------------------------------------------------------------------------
128 |
129 | VersionInfo PluginConfig::maxVersion() const
130 | {
131 | return m_maxVersion;
132 | }
133 |
134 | // -------------------------------------------------------------------------------------------------
135 |
136 | void PluginConfig::setMaxVersion(const VersionInfo &maxVersion)
137 | {
138 | m_maxVersion = maxVersion;
139 | }
140 |
141 | // -------------------------------------------------------------------------------------------------
142 |
143 | const QList &PluginConfig::instanceConfigs() const
144 | {
145 | return m_instanceConfigs;
146 | }
147 |
148 | // -------------------------------------------------------------------------------------------------
149 |
150 | void PluginConfig::setInstanceConfigs(const QList &instanceConfigs)
151 | {
152 | m_instanceConfigs = instanceConfigs;
153 | }
154 |
155 | // -------------------------------------------------------------------------------------------------
156 |
157 | bool PluginConfig::loadConfigParameters(const CppConfigFramework::ConfigObjectNode &config)
158 | {
159 | // Load file path
160 | if (!loadRequiredConfigParameter(&m_filePath, QStringLiteral("file_path"), config))
161 | {
162 | qCWarning(CppPluginFramework::LoggingCategory::Config)
163 | << "Failed to load plugin's file path!";
164 | return false;
165 | }
166 |
167 | // Load version
168 | m_version = VersionInfo();
169 |
170 | if (!loadOptionalConfigParameter(&m_version, QStringLiteral("version"), config))
171 | {
172 | qCWarning(CppPluginFramework::LoggingCategory::Config)
173 | << "Failed to load plugin's version!";
174 | return false;
175 | }
176 |
177 | // Load min version
178 | m_minVersion = VersionInfo();
179 |
180 | if (!loadOptionalConfigParameter(&m_minVersion, QStringLiteral("min_version"), config))
181 | {
182 | qCWarning(CppPluginFramework::LoggingCategory::Config)
183 | << "Failed to load plugin's min version!";
184 | return false;
185 | }
186 |
187 | // Load max version
188 | m_maxVersion = VersionInfo();
189 |
190 | if (!loadOptionalConfigParameter(&m_maxVersion, QStringLiteral("max_version"), config))
191 | {
192 | qCWarning(CppPluginFramework::LoggingCategory::Config)
193 | << "Failed to load plugin's max version";
194 | return false;
195 | }
196 |
197 | // Load instance configs
198 | if (!loadRequiredConfigContainer(&m_instanceConfigs, QStringLiteral("instances"), config))
199 | {
200 | qCWarning(CppPluginFramework::LoggingCategory::Config)
201 | << "Failed to load plugin's instances!";
202 | return false;
203 | }
204 |
205 | return true;
206 | }
207 |
208 | // -------------------------------------------------------------------------------------------------
209 |
210 | bool PluginConfig::storeConfigParameters(CppConfigFramework::ConfigObjectNode *config)
211 | {
212 | // Storing config parameters is currently not supported
213 | Q_UNUSED(config)
214 | return false;
215 | }
216 |
217 | // -------------------------------------------------------------------------------------------------
218 |
219 | QString PluginConfig::validateConfig() const
220 | {
221 | // Check file path
222 | if (!Validation::validateFilePath(m_filePath))
223 | {
224 | return QStringLiteral("File path is not valid: ") % m_filePath;
225 | }
226 |
227 | // Check version info
228 | if (isExactVersion())
229 | {
230 | if (!m_version.isValid())
231 | {
232 | return QStringLiteral("Version is not valid");
233 | }
234 | }
235 | else if (isVersionRange())
236 | {
237 | if (!VersionInfo::isRangeValid(m_minVersion, m_maxVersion))
238 | {
239 | return QStringLiteral("Version range is not valid");
240 | }
241 | }
242 | else
243 | {
244 | return QStringLiteral("Either just the version parameter needs to be set or "
245 | "both min and max version parameters!");
246 | }
247 |
248 | // At least one plugin instance is required
249 | if (m_instanceConfigs.isEmpty())
250 | {
251 | return QStringLiteral("Plugin config does not define any plugin instances");
252 | }
253 |
254 | // Check individual instances are valid and if this plugin config contains duplicate instances
255 | // (instances with the same name)
256 | QStringList instanceNames;
257 |
258 | for (const auto &instanceConfig : m_instanceConfigs)
259 | {
260 | if (!instanceConfig.isValid())
261 | {
262 | return QStringLiteral("Plugin instance config is not valid: ") % instanceConfig.name();
263 | }
264 |
265 | if (instanceNames.contains(instanceConfig.name()))
266 | {
267 | return QStringLiteral("Duplicate plugin instance name: ") % instanceConfig.name();
268 | }
269 |
270 | instanceNames.append(instanceConfig.name());
271 | }
272 |
273 | return QString();
274 | }
275 |
276 | } // namespace CppPluginFramework
277 |
278 | // -------------------------------------------------------------------------------------------------
279 |
280 | bool operator==(const CppPluginFramework::PluginConfig &left,
281 | const CppPluginFramework::PluginConfig &right)
282 | {
283 | if ((left.filePath() != right.filePath()) ||
284 | (left.version() != right.version()) ||
285 | (left.minVersion() != right.minVersion()) ||
286 | (left.maxVersion() != right.maxVersion()))
287 | {
288 | return false;
289 | }
290 |
291 | if (left.instanceConfigs().size() != right.instanceConfigs().size())
292 | {
293 | return false;
294 | }
295 |
296 | for (const auto &item : left.instanceConfigs())
297 | {
298 | if (!right.instanceConfigs().contains(item))
299 | {
300 | return false;
301 | }
302 | }
303 |
304 | return true;
305 | }
306 |
307 | // -------------------------------------------------------------------------------------------------
308 |
309 | bool operator!=(const CppPluginFramework::PluginConfig &left,
310 | const CppPluginFramework::PluginConfig &right)
311 | {
312 | return !(left == right);
313 | }
314 |
--------------------------------------------------------------------------------
/code/src/PluginInstanceConfig.cpp:
--------------------------------------------------------------------------------
1 | /* This file is part of C++ Plugin Framework.
2 | *
3 | * C++ Plugin Framework is free software: you can redistribute it and/or modify it under the terms
4 | * of the GNU Lesser General Public License as published by the Free Software Foundation, either
5 | * version 3 of the License, or (at your option) any later version.
6 | *
7 | * C++ Plugin Framework is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
8 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 | * GNU Lesser General Public License for more details.
10 | *
11 | * You should have received a copy of the GNU Lesser General Public License along with C++ Plugin
12 | * Framework. If not, see .
13 | */
14 |
15 | /*!
16 | * \file
17 | *
18 | * Contains a config class for a Plugin Instance
19 | */
20 |
21 | // Own header
22 | #include
23 |
24 | // C++ Plugin Framework includes
25 | #include
26 | #include
27 |
28 | // Qt includes
29 | #include
30 |
31 | // System includes
32 |
33 | // Forward declarations
34 |
35 | // Macros
36 |
37 | // -------------------------------------------------------------------------------------------------
38 |
39 | namespace CppPluginFramework
40 | {
41 |
42 | PluginInstanceConfig::PluginInstanceConfig(const QString &name,
43 | const CppConfigFramework::ConfigObjectNode &config,
44 | const QSet &dependencies)
45 | : m_name(name),
46 | m_config(std::move(config.clone()->toObject())),
47 | m_dependencies(dependencies)
48 | {
49 | }
50 |
51 | // -------------------------------------------------------------------------------------------------
52 |
53 | PluginInstanceConfig::PluginInstanceConfig(const PluginInstanceConfig &other)
54 | : m_name(other.m_name),
55 | m_config(std::move(other.m_config.clone()->toObject())),
56 | m_dependencies(other.m_dependencies)
57 | {
58 | }
59 |
60 | // -------------------------------------------------------------------------------------------------
61 |
62 | PluginInstanceConfig &PluginInstanceConfig::operator=(const PluginInstanceConfig &other)
63 | {
64 | if (this == &other)
65 | {
66 | return *this;
67 | }
68 |
69 | m_name = other.m_name;
70 | m_config = std::move(other.m_config.clone()->toObject());
71 | m_dependencies = other.m_dependencies;
72 | return *this;
73 | }
74 |
75 | // -------------------------------------------------------------------------------------------------
76 |
77 | bool PluginInstanceConfig::isValid() const
78 | {
79 | return validateConfig().isEmpty();
80 | }
81 |
82 | // -------------------------------------------------------------------------------------------------
83 |
84 | QString PluginInstanceConfig::name() const
85 | {
86 | return m_name;
87 | }
88 |
89 | // -------------------------------------------------------------------------------------------------
90 |
91 | void PluginInstanceConfig::setName(const QString &name)
92 | {
93 | m_name = name;
94 | }
95 |
96 | // -------------------------------------------------------------------------------------------------
97 |
98 | const CppConfigFramework::ConfigObjectNode &PluginInstanceConfig::config() const
99 | {
100 | return m_config;
101 | }
102 |
103 | // -------------------------------------------------------------------------------------------------
104 |
105 | void PluginInstanceConfig::setConfig(const CppConfigFramework::ConfigObjectNode &config)
106 | {
107 | m_config = std::move(config.clone()->toObject());
108 | }
109 |
110 | // -------------------------------------------------------------------------------------------------
111 |
112 | QSet PluginInstanceConfig::dependencies() const
113 | {
114 | return m_dependencies;
115 | }
116 |
117 | // -------------------------------------------------------------------------------------------------
118 |
119 | void PluginInstanceConfig::setDependencies(const QSet &dependencies)
120 | {
121 | m_dependencies = dependencies;
122 | }
123 |
124 | // -------------------------------------------------------------------------------------------------
125 |
126 | bool PluginInstanceConfig::loadConfigParameters(const CppConfigFramework::ConfigObjectNode &config)
127 | {
128 | // Load name
129 | if (!loadRequiredConfigParameter(&m_name, QStringLiteral("name"), config))
130 | {
131 | qCWarning(CppPluginFramework::LoggingCategory::Config)
132 | << "Failed to load plugin instance's name!";
133 | return false;
134 | }
135 |
136 | // Load config
137 | const auto *configMember = config.member(QStringLiteral("config"));
138 |
139 | if (configMember == nullptr)
140 | {
141 | m_config = CppConfigFramework::ConfigObjectNode();
142 | }
143 | else
144 | {
145 | if (!configMember->isObject())
146 | {
147 | qCWarning(CppPluginFramework::LoggingCategory::Config)
148 | << "Plugin instance's config is not an Object! Type:"
149 | << CppConfigFramework::ConfigNode::typeToString(configMember->type());
150 | return false;
151 | }
152 |
153 | m_config = std::move(configMember->clone()->toObject());
154 | }
155 |
156 | // Load dependencies
157 | m_dependencies.clear();
158 |
159 | if (!loadOptionalConfigParameter(&m_dependencies, QStringLiteral("dependencies"), config))
160 | {
161 | qCWarning(CppPluginFramework::LoggingCategory::Config)
162 | << "Failed to load plugin instance's dependencies!";
163 | return false;
164 | }
165 |
166 | return true;
167 | }
168 |
169 | // -------------------------------------------------------------------------------------------------
170 |
171 | bool PluginInstanceConfig::storeConfigParameters(CppConfigFramework::ConfigObjectNode *config)
172 | {
173 | // Storing config parameters is currently not supported
174 | Q_UNUSED(config)
175 | return false;
176 | }
177 |
178 | // -------------------------------------------------------------------------------------------------
179 |
180 | QString PluginInstanceConfig::validateConfig() const
181 | {
182 | // Check name
183 | if (!Validation::validatePluginInstanceName(m_name))
184 | {
185 | return QStringLiteral("Name is not valid: ") % m_name;
186 | }
187 |
188 | // Config is optional
189 |
190 | // Check (optional) dependencies
191 | if (!m_dependencies.isEmpty())
192 | {
193 | // Check individual dependency if it is referencing a valid name
194 | for (const QString &dependency : m_dependencies)
195 | {
196 | if (dependency == m_name)
197 | {
198 | return QStringLiteral("Dependency name is the same as the plugin instance name: ") %
199 | dependency;
200 | }
201 |
202 | if (!Validation::validatePluginInstanceName(dependency))
203 | {
204 | return QStringLiteral("Dependency's name is not valid: ") % dependency;
205 | }
206 | }
207 | }
208 |
209 | return QString();
210 | }
211 |
212 | } // namespace CppPluginFramework
213 |
214 | // -------------------------------------------------------------------------------------------------
215 |
216 | bool operator==(const CppPluginFramework::PluginInstanceConfig &left,
217 | const CppPluginFramework::PluginInstanceConfig &right)
218 | {
219 | return ((left.name() == right.name()) &&
220 | (left.config() == right.config()) &&
221 | (left.dependencies() == right.dependencies()));
222 | }
223 |
224 | // -------------------------------------------------------------------------------------------------
225 |
226 | bool operator!=(const CppPluginFramework::PluginInstanceConfig &left,
227 | const CppPluginFramework::PluginInstanceConfig &right)
228 | {
229 | return !(left == right);
230 | }
231 |
--------------------------------------------------------------------------------
/code/src/PluginManagerConfig.cpp:
--------------------------------------------------------------------------------
1 | /* This file is part of C++ Plugin Framework.
2 | *
3 | * C++ Plugin Framework is free software: you can redistribute it and/or modify it under the terms
4 | * of the GNU Lesser General Public License as published by the Free Software Foundation, either
5 | * version 3 of the License, or (at your option) any later version.
6 | *
7 | * C++ Plugin Framework is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
8 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 | * GNU Lesser General Public License for more details.
10 | *
11 | * You should have received a copy of the GNU Lesser General Public License along with C++ Plugin
12 | * Framework. If not, see .
13 | */
14 |
15 | /*!
16 | * \file
17 | *
18 | * Contains a config class for the Plugin Manager
19 | */
20 |
21 | // Own header
22 | #include
23 |
24 | // C++ Plugin Framework includes
25 | #include
26 |
27 | // Qt includes
28 | #include
29 |
30 | // System includes
31 |
32 | // Forward declarations
33 |
34 | // Macros
35 |
36 | // -------------------------------------------------------------------------------------------------
37 |
38 | namespace CppPluginFramework
39 | {
40 |
41 | bool PluginManagerConfig::isValid() const
42 | {
43 | return validateConfig().isEmpty();
44 | }
45 |
46 | // -------------------------------------------------------------------------------------------------
47 |
48 | const QList &PluginManagerConfig::pluginConfigs() const
49 | {
50 | return m_pluginConfigs;
51 | }
52 |
53 | // -------------------------------------------------------------------------------------------------
54 |
55 | void PluginManagerConfig::setPluginConfigs(const QList &pluginConfigs)
56 | {
57 | m_pluginConfigs = pluginConfigs;
58 | }
59 |
60 | // -------------------------------------------------------------------------------------------------
61 |
62 | const QStringList &PluginManagerConfig::pluginStartupPriorities() const
63 | {
64 | return m_pluginStartupPriorities;
65 | }
66 |
67 | // -------------------------------------------------------------------------------------------------
68 |
69 | void PluginManagerConfig::setPluginStartupPriorities(const QStringList &startupPriorities)
70 | {
71 | m_pluginStartupPriorities = startupPriorities;
72 | }
73 |
74 | // -------------------------------------------------------------------------------------------------
75 |
76 | bool PluginManagerConfig::loadConfigParameters(const CppConfigFramework::ConfigObjectNode &config)
77 | {
78 | // Load plugin configs
79 | if (!loadRequiredConfigContainer(&m_pluginConfigs, QStringLiteral("plugins"), config))
80 | {
81 | qCWarning(CppPluginFramework::LoggingCategory::Config)
82 | << "Failed to load plugin configurations!";
83 | return false;
84 | }
85 |
86 | // Load plugin startup priorities
87 | m_pluginStartupPriorities.clear();
88 |
89 | if (!loadOptionalConfigParameter(&m_pluginStartupPriorities,
90 | QStringLiteral("plugin_startup_priorities"),
91 | config))
92 | {
93 | qCWarning(CppPluginFramework::LoggingCategory::Config)
94 | << "Failed to load plugin's startup priorities!";
95 | return false;
96 | }
97 |
98 | return true;
99 | }
100 |
101 | // -------------------------------------------------------------------------------------------------
102 |
103 | bool PluginManagerConfig::storeConfigParameters(CppConfigFramework::ConfigObjectNode *config)
104 | {
105 | // Storing config parameters is currently not supported
106 | Q_UNUSED(config)
107 | return false;
108 | }
109 |
110 | // -------------------------------------------------------------------------------------------------
111 |
112 | QString PluginManagerConfig::validateConfig() const
113 | {
114 | // Check individual plugins are valid and extract all instance names
115 | QSet plugins;
116 | QSet instanceNames;
117 | QSet dependencies;
118 |
119 | for (const auto &pluginConfig : m_pluginConfigs)
120 | {
121 | // Check individual plugins are valid
122 | if (!pluginConfig.isValid())
123 | {
124 | return QStringLiteral("Plugin config is not valid: ") % pluginConfig.filePath();
125 | }
126 |
127 | // Check for duplicate plugins
128 | if (plugins.contains(pluginConfig.filePath()))
129 | {
130 | return QStringLiteral("Duplicated plugin: [%1]") % pluginConfig.filePath();
131 | }
132 |
133 | plugins.insert(pluginConfig.filePath());
134 |
135 | // Check for plugin instances of this plugin
136 | for (const auto &instanceConfig : pluginConfig.instanceConfigs())
137 | {
138 | // Check for duplicate instance name
139 | if (instanceNames.contains(instanceConfig.name()))
140 | {
141 | return QString("Plugin [%1] has an instance with a duplicated name [%2]!")
142 | .arg(pluginConfig.filePath(),
143 | instanceConfig.name());
144 | }
145 |
146 | instanceNames.insert(instanceConfig.name());
147 |
148 | // Keep track of all dependencies
149 | dependencies.unite(instanceConfig.dependencies());
150 | }
151 | }
152 |
153 | // Check if dependencies reference actual plugin instances
154 | for (const QString &dependency : dependencies)
155 | {
156 | if (!instanceNames.contains(dependency))
157 | {
158 | return QString("Dependency [%1] does not reference an actual plugin instance!")
159 | .arg(dependency);
160 | }
161 | }
162 |
163 | // Check if the startup priorities reference actual plugin instances
164 | for (const QString &instanceName : m_pluginStartupPriorities)
165 | {
166 | if (!instanceNames.contains(instanceName))
167 | {
168 | return QString("Plugin instance [%1] referenced in the startup priorities does not"
169 | "reference an actual plugin instance!")
170 | .arg(instanceName);
171 | }
172 |
173 | if (m_pluginStartupPriorities.count(instanceName) != 1)
174 | {
175 | return QString("Duplicate plugin instance [%1] in the startup priorities!")
176 | .arg(instanceName);
177 | }
178 | }
179 |
180 | return QString();
181 | }
182 |
183 | } // namespace CppPluginFramework
184 |
185 | // -------------------------------------------------------------------------------------------------
186 |
187 | bool operator==(const CppPluginFramework::PluginManagerConfig &left,
188 | const CppPluginFramework::PluginManagerConfig &right)
189 | {
190 | return ((left.pluginConfigs() == right.pluginConfigs()) &&
191 | (left.pluginStartupPriorities() == right.pluginStartupPriorities()));
192 | }
193 |
194 | // -------------------------------------------------------------------------------------------------
195 |
196 | bool operator!=(const CppPluginFramework::PluginManagerConfig &left,
197 | const CppPluginFramework::PluginManagerConfig &right)
198 | {
199 | return !(left == right);
200 | }
201 |
--------------------------------------------------------------------------------
/code/src/Validation.cpp:
--------------------------------------------------------------------------------
1 | /* This file is part of C++ Plugin Framework.
2 | *
3 | * C++ Plugin Framework is free software: you can redistribute it and/or modify it under the terms
4 | * of the GNU Lesser General Public License as published by the Free Software Foundation, either
5 | * version 3 of the License, or (at your option) any later version.
6 | *
7 | * C++ Plugin Framework is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
8 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 | * GNU Lesser General Public License for more details.
10 | *
11 | * You should have received a copy of the GNU Lesser General Public License along with C++ Plugin
12 | * Framework. If not, see .
13 | */
14 |
15 | /*!
16 | * \file
17 | *
18 | * Contains validation methods
19 | */
20 |
21 | // Own header
22 | #include
23 |
24 | // C++ Plugin Framework includes
25 | #include
26 |
27 | // Qt includes
28 | #include
29 | #include
30 |
31 | // System includes
32 |
33 | // Forward declarations
34 |
35 | // Macros
36 |
37 | // -------------------------------------------------------------------------------------------------
38 |
39 | namespace CppPluginFramework
40 | {
41 |
42 | namespace Validation
43 | {
44 |
45 | bool validatePluginInstanceName(const QString &name)
46 | {
47 | QRegularExpression regex("^[a-zA-Z][a-zA-Z0-9\\._-]*$");
48 | auto match = regex.match(name);
49 |
50 | return match.hasMatch();
51 | }
52 |
53 | // -------------------------------------------------------------------------------------------------
54 |
55 | bool validateInterfaceName(const QString &name)
56 | {
57 | QRegularExpression regex("^[a-zA-Z][a-zA-Z0-9]*(::[a-zA-Z][a-zA-Z0-9]*)*$");
58 | auto match = regex.match(name);
59 |
60 | return match.hasMatch();
61 | }
62 |
63 | // -------------------------------------------------------------------------------------------------
64 |
65 | bool validateExportedInterfaces(const QSet &exportedInterfaces)
66 | {
67 | if (exportedInterfaces.isEmpty())
68 | {
69 | return false;
70 | }
71 |
72 | for (const QString &item : exportedInterfaces)
73 | {
74 | if (!validateInterfaceName(item))
75 | {
76 | return false;
77 | }
78 | }
79 |
80 | return true;
81 | }
82 |
83 | // -------------------------------------------------------------------------------------------------
84 |
85 | bool validateEnvironmentVariableName(const QString &name)
86 | {
87 | QRegularExpression regex("^[a-zA-Z_][a-zA-Z0-9_]*$");
88 | auto match = regex.match(name);
89 |
90 | return match.hasMatch();
91 | }
92 |
93 | // -------------------------------------------------------------------------------------------------
94 |
95 | bool validateFilePath(const QString &filePath)
96 | {
97 | return QFileInfo(filePath).isFile();
98 | }
99 |
100 | } // namespace Validation
101 |
102 | } // namespace CppPluginFramework
103 |
--------------------------------------------------------------------------------
/code/tests/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # This file is part of C++ Plugin Framework.
2 | #
3 | # C++ Plugin Framework is free software: you can redistribute it and/or modify it under the terms
4 | # of the GNU Lesser General Public License as published by the Free Software Foundation, either
5 | # version 3 of the License, or (at your option) any later version.
6 | #
7 | # C++ Plugin Framework is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
8 | # without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 | # GNU Lesser General Public License for more details.
10 | #
11 | # You should have received a copy of the GNU Lesser General Public License along with C++ Plugin
12 | # Framework. If not, see .
13 |
14 | set(CMAKE_AUTOMOC ON)
15 | set(CMAKE_AUTORCC ON)
16 |
17 | find_package(Qt5 COMPONENTS Test REQUIRED)
18 |
19 | # --------------------------------------------------------------------------------------------------
20 | # Custom (meta) targets
21 | # --------------------------------------------------------------------------------------------------
22 | add_custom_target(all_tests)
23 |
24 | # --------------------------------------------------------------------------------------------------
25 | # Helper methods
26 | # --------------------------------------------------------------------------------------------------
27 | function(CppPluginFramework_AddTest)
28 | # Function parameters
29 | set(options) # Boolean parameters
30 | set(oneValueParams # Parameters with one value
31 | TEST_NAME
32 | )
33 | set(multiValueParams # Parameters with multiple values
34 | ADDITIONAL_SOURCES
35 | ADDITIONAL_HEADERS
36 | ADDITIONAL_LIBS
37 | LABELS
38 | )
39 |
40 | cmake_parse_arguments(PARAM "${options}" "${oneValueParams}" "${multiValueParams}" ${ARGN})
41 |
42 | # Create test executable
43 | add_executable(${PARAM_TEST_NAME}
44 | ${PARAM_TEST_NAME}.cpp
45 | ${PARAM_ADDITIONAL_SOURCES}
46 | ${PARAM_ADDITIONAL_HEADERS}
47 | )
48 |
49 | target_include_directories(${PARAM_TEST_NAME} PUBLIC
50 | ${CMAKE_CURRENT_BINARY_DIR}
51 | )
52 |
53 | target_link_libraries(${PARAM_TEST_NAME}
54 | PUBLIC CppPluginFramework
55 | PUBLIC Qt5::Test
56 | PUBLIC ${PARAM_ADDITIONAL_LIBS}
57 | )
58 |
59 | add_test(${PARAM_TEST_NAME} ${PARAM_TEST_NAME})
60 |
61 | # Add test to target "all_tests"
62 | add_dependencies(all_tests ${PARAM_TEST_NAME})
63 |
64 | # Set test labels
65 | if (PARAM_LABELS)
66 | set_tests_properties(${PARAM_TEST_NAME} PROPERTIES
67 | LABELS "CPPPLUGINFRAMEWORK;${PARAM_LABELS}"
68 | )
69 | endif()
70 | endfunction()
71 |
72 | # --------------------------------------------------------------------------------------------------
73 | # Tests
74 | # --------------------------------------------------------------------------------------------------
75 | add_subdirectory(unit)
76 | add_subdirectory(integration)
77 |
78 | # --------------------------------------------------------------------------------------------------
79 | # Code Coverage
80 | # --------------------------------------------------------------------------------------------------
81 | if (CppPluginFramework_CodeCoverage MATCHES ON)
82 | # Prepare targets for code coverage
83 | SETUP_TARGET_FOR_COVERAGE(
84 | NAME ctest_coverage_all_tests
85 | EXECUTABLE ctest
86 | DEPENDENCIES all_tests
87 | PROJECT_PATH ${PROJECT_SOURCE_DIR}
88 | EXCLUDES ${CppPluginFramework_CodeCoverage_EXCLUDES}
89 | )
90 | endif()
91 |
--------------------------------------------------------------------------------
/code/tests/integration/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # This file is part of C++ Plugin Framework.
2 | #
3 | # C++ Plugin Framework is free software: you can redistribute it and/or modify it under the terms
4 | # of the GNU Lesser General Public License as published by the Free Software Foundation, either
5 | # version 3 of the License, or (at your option) any later version.
6 | #
7 | # C++ Plugin Framework is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
8 | # without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 | # GNU Lesser General Public License for more details.
10 | #
11 | # You should have received a copy of the GNU Lesser General Public License along with C++ Plugin
12 | # Framework. If not, see .
13 |
14 | # --------------------------------------------------------------------------------------------------
15 | # Custom (meta) targets
16 | # --------------------------------------------------------------------------------------------------
17 | add_custom_target(all_integration_tests)
18 |
19 | # --------------------------------------------------------------------------------------------------
20 | # Helper methods
21 | # --------------------------------------------------------------------------------------------------
22 | function(CppPluginFramework_AddIntegrationTest)
23 | # Function parameters
24 | set(options) # Boolean parameters
25 | set(oneValueParams # Parameters with one value
26 | TEST_NAME
27 | )
28 | set(multiValueParams) # Parameters with multiple values
29 |
30 | cmake_parse_arguments(PARAM "${options}" "${oneValueParams}" "${multiValueParams}" ${ARGN})
31 |
32 | # Add test
33 | CppPluginFramework_AddTest(${ARGN} LABELS CPPPLUGINFRAMEWORK_INTEGRATION_TESTS)
34 |
35 | # Add test to target "all_integration_tests"
36 | add_dependencies(all_integration_tests ${PARAM_TEST_NAME})
37 | endfunction()
38 |
39 | # --------------------------------------------------------------------------------------------------
40 | # Test plugins
41 | # --------------------------------------------------------------------------------------------------
42 | add_subdirectory(TestPlugins)
43 |
44 | # --------------------------------------------------------------------------------------------------
45 | # Integration tests
46 | # --------------------------------------------------------------------------------------------------
47 | add_subdirectory(Plugin)
48 | add_subdirectory(PluginManager)
49 |
50 | # --------------------------------------------------------------------------------------------------
51 | # Code Coverage
52 | # --------------------------------------------------------------------------------------------------
53 | if (CppPluginFramework_CodeCoverage MATCHES ON)
54 | # Prepare targets for code coverage
55 | SETUP_TARGET_FOR_COVERAGE(
56 | NAME ctest_coverage_all_integration_tests
57 | EXECUTABLE ctest -L CPPPLUGINFRAMEWORK_INTEGRATION_TESTS
58 | DEPENDENCIES all_integration_tests
59 | PROJECT_PATH ${PROJECT_SOURCE_DIR}
60 | EXCLUDES ${CppPluginFramework_CodeCoverage_EXCLUDES}
61 | )
62 | endif()
63 |
--------------------------------------------------------------------------------
/code/tests/integration/Plugin/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # This file is part of C++ Plugin Framework.
2 | #
3 | # C++ Plugin Framework is free software: you can redistribute it and/or modify it under the terms
4 | # of the GNU Lesser General Public License as published by the Free Software Foundation, either
5 | # version 3 of the License, or (at your option) any later version.
6 | #
7 | # C++ Plugin Framework is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
8 | # without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 | # GNU Lesser General Public License for more details.
10 | #
11 | # You should have received a copy of the GNU Lesser General Public License along with C++ Plugin
12 | # Framework. If not, see .
13 |
14 | CppPluginFramework_AddIntegrationTest(TEST_NAME testPlugin)
15 |
--------------------------------------------------------------------------------
/code/tests/integration/Plugin/testPlugin.cpp:
--------------------------------------------------------------------------------
1 | /* This file is part of C++ Plugin Framework.
2 | *
3 | * C++ Plugin Framework is free software: you can redistribute it and/or modify it under the terms
4 | * of the GNU Lesser General Public License as published by the Free Software Foundation, either
5 | * version 3 of the License, or (at your option) any later version.
6 | *
7 | * C++ Plugin Framework is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
8 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 | * GNU Lesser General Public License for more details.
10 | *
11 | * You should have received a copy of the GNU Lesser General Public License along with C++ Plugin
12 | * Framework. If not, see .
13 | */
14 |
15 | /*!
16 | * \file
17 | *
18 | * Contains unit tests for Plugin class
19 | */
20 |
21 | // C++ Plugin Framework includes
22 | #include
23 | #include
24 |
25 | // C++ Config Framework includes
26 | #include
27 |
28 | // Qt includes
29 | #include
30 | #include
31 |
32 | // System includes
33 |
34 | // Forward declarations
35 |
36 | // Macros
37 |
38 | // Test class declaration --------------------------------------------------------------------------
39 |
40 | using namespace CppConfigFramework;
41 | using namespace CppPluginFramework;
42 |
43 | Q_DECLARE_METATYPE(PluginConfig)
44 | Q_DECLARE_METATYPE(VersionInfo)
45 |
46 | class TestPlugin : public QObject
47 | {
48 | Q_OBJECT
49 |
50 | private slots:
51 | // Functions executed by QtTest before and after test suite
52 | void initTestCase();
53 | void cleanupTestCase();
54 |
55 | // Functions executed by QtTest before and after each test
56 | void init();
57 | void cleanup();
58 |
59 | // Test functions
60 | void testLoadPlugin();
61 | void testLoadPlugin_data();
62 | };
63 |
64 | // Test Case init/cleanup methods ------------------------------------------------------------------
65 |
66 | void TestPlugin::initTestCase()
67 | {
68 | }
69 |
70 | void TestPlugin::cleanupTestCase()
71 | {
72 | }
73 |
74 | // Test init/cleanup methods -----------------------------------------------------------------------
75 |
76 | void TestPlugin::init()
77 | {
78 | }
79 |
80 | void TestPlugin::cleanup()
81 | {
82 | }
83 |
84 | // Test: loading of plugins ------------------------------------------------------------------------
85 |
86 | void TestPlugin::testLoadPlugin()
87 | {
88 | QFETCH(PluginConfig, config);
89 | QFETCH(QStringList, instanceNames);
90 | QFETCH(VersionInfo, version);
91 | QFETCH(QString, description);
92 | QFETCH(QStringList, exportedInterfaces);
93 | QFETCH(bool, result);
94 |
95 | // Load plugin
96 | auto instances = Plugin::loadInstances(config);
97 | QCOMPARE(instances.size(), static_cast(instanceNames.size()));
98 |
99 | // Check plugin
100 | if (result)
101 | {
102 | QStringList checkedInstances;
103 |
104 | for (const auto &instance : instances)
105 | {
106 | QVERIFY(instance);
107 |
108 | QVERIFY(instanceNames.contains(instance->name()));
109 | QVERIFY(!checkedInstances.contains(instance->name()));
110 | checkedInstances.append(instance->name());
111 |
112 | QCOMPARE(instance->version(), version);
113 | QCOMPARE(instance->description(), description);
114 | #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
115 | QCOMPARE(instance->exportedInterfaces(), QSet::fromList(exportedInterfaces));
116 | #else
117 | QCOMPARE(instance->exportedInterfaces(), QSet(exportedInterfaces.begin(),
118 | exportedInterfaces.end()));
119 | #endif
120 | }
121 |
122 | QCOMPARE(checkedInstances.size(), instanceNames.size());
123 | #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
124 | QCOMPARE(QSet::fromList(checkedInstances), QSet::fromList(instanceNames));
125 | #else
126 | QCOMPARE(QSet(checkedInstances.begin(), checkedInstances.end()),
127 | QSet(instanceNames.begin(), instanceNames.end()));
128 | #endif
129 | }
130 | }
131 |
132 | void TestPlugin::testLoadPlugin_data()
133 | {
134 | QTest::addColumn("config");
135 | QTest::addColumn("instanceNames");
136 | QTest::addColumn("version");
137 | QTest::addColumn("description");
138 | QTest::addColumn("exportedInterfaces");
139 | QTest::addColumn("result");
140 |
141 | QDir testPluginsDir(QCoreApplication::applicationDirPath());
142 | testPluginsDir.cd("../TestPlugins");
143 |
144 | // Loading of test plugin 1
145 | {
146 | ConfigObjectNode instance1Config
147 | {
148 | { "value", ConfigValueNode("value1") }
149 | };
150 |
151 | ConfigObjectNode instance2Config
152 | {
153 | { "value", ConfigValueNode("value2") }
154 | };
155 |
156 | QList instanceConfigs;
157 | instanceConfigs << PluginInstanceConfig("instance1", instance1Config)
158 | << PluginInstanceConfig("instance2", instance2Config);
159 |
160 | PluginConfig config(testPluginsDir.filePath("TestPlugin1.plugin"),
161 | VersionInfo(1, 0, 0),
162 | instanceConfigs);
163 |
164 | QTest::newRow("valid: test plugin 1")
165 | << config
166 | << QStringList { "instance1", "instance2" }
167 | << VersionInfo(1, 0, 0)
168 | << QString("test plugin 1")
169 | << QStringList { "CppPluginFramework::TestPlugins::ITestPlugin1" }
170 | << true;
171 | }
172 |
173 | // Loading of test plugin 2
174 | {
175 | ConfigObjectNode instance3Config
176 | {
177 | { "delimiter", ConfigValueNode(";") }
178 | };
179 |
180 | QList instanceConfigs;
181 | instanceConfigs << PluginInstanceConfig("instance3",
182 | instance3Config,
183 | QSet { "instance1", "instance2"});
184 |
185 | PluginConfig config(testPluginsDir.filePath("TestPlugin2.plugin"),
186 | VersionInfo(1, 0, 0),
187 | VersionInfo(1, 0, 1),
188 | instanceConfigs);
189 |
190 | QTest::newRow("valid: test plugin 2")
191 | << config
192 | << QStringList { "instance3" }
193 | << VersionInfo(1, 0, 0)
194 | << QString("test plugin 2")
195 | << QStringList { "CppPluginFramework::TestPlugins::ITestPlugin2" }
196 | << true;
197 | }
198 |
199 | // Loading of plugin with invalid config
200 | {
201 | ConfigObjectNode instance1Config
202 | {
203 | { "invalid", ConfigValueNode("x") }
204 | };
205 |
206 | QList instanceConfigs;
207 | instanceConfigs << PluginInstanceConfig("instance1", instance1Config);
208 |
209 | PluginConfig config(testPluginsDir.filePath("TestPlugin1.plugin"),
210 | VersionInfo(1, 0, 0),
211 | instanceConfigs);
212 |
213 | QTest::newRow("invalid: config") << config
214 | << QStringList()
215 | << VersionInfo(1, 0, 0)
216 | << QString()
217 | << QStringList()
218 | << false;
219 | }
220 |
221 | // Loading of plugin with invalid plugin config
222 | {
223 | QTest::newRow("invalid: plugin config") << PluginConfig()
224 | << QStringList()
225 | << VersionInfo()
226 | << QString()
227 | << QStringList()
228 | << false;
229 | }
230 |
231 | // Loading of plugin with invalid version
232 | {
233 | ConfigObjectNode instance1Config
234 | {
235 | { "value", ConfigValueNode("value1") }
236 | };
237 |
238 | QList instanceConfigs;
239 | instanceConfigs << PluginInstanceConfig("instance1", instance1Config);
240 |
241 | PluginConfig config(testPluginsDir.filePath("TestPlugin1.plugin"),
242 | VersionInfo(1, 0, 1),
243 | instanceConfigs);
244 |
245 | QTest::newRow("invalid: version 1") << config
246 | << QStringList()
247 | << VersionInfo()
248 | << QString()
249 | << QStringList()
250 | << false;
251 |
252 | config = PluginConfig(testPluginsDir.filePath("TestPlugin1.plugin"),
253 | VersionInfo(1, 0, 1),
254 | VersionInfo(1, 0, 2),
255 | instanceConfigs);
256 |
257 | QTest::newRow("invalid: version 2") << config
258 | << QStringList()
259 | << VersionInfo()
260 | << QString()
261 | << QStringList()
262 | << false;
263 | }
264 | }
265 |
266 | // Main function -----------------------------------------------------------------------------------
267 |
268 | QTEST_MAIN(TestPlugin)
269 | #include "testPlugin.moc"
270 |
--------------------------------------------------------------------------------
/code/tests/integration/PluginManager/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # This file is part of C++ Plugin Framework.
2 | #
3 | # C++ Plugin Framework is free software: you can redistribute it and/or modify it under the terms
4 | # of the GNU Lesser General Public License as published by the Free Software Foundation, either
5 | # version 3 of the License, or (at your option) any later version.
6 | #
7 | # C++ Plugin Framework is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
8 | # without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 | # GNU Lesser General Public License for more details.
10 | #
11 | # You should have received a copy of the GNU Lesser General Public License along with C++ Plugin
12 | # Framework. If not, see .
13 |
14 | CppPluginFramework_AddIntegrationTest(TEST_NAME testPluginManager ADDITIONAL_SOURCES TestData.qrc)
15 |
--------------------------------------------------------------------------------
/code/tests/integration/PluginManager/TestData.qrc:
--------------------------------------------------------------------------------
1 |
2 |
3 | TestData/AppConfig.json
4 | TestData/InvalidConfigWithUnsupportedDependency.json
5 | TestData/AppConfigWithInvalidStartupOrder.json
6 |
7 |
8 |
--------------------------------------------------------------------------------
/code/tests/integration/PluginManager/TestData/AppConfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "environment_variables":
3 | {
4 | "TestPluginsPath": "../TestPlugins"
5 | },
6 |
7 | "config":
8 | {
9 | "plugin_startup_priorities":
10 | [
11 | "instance1",
12 | "instance2"
13 | ],
14 |
15 | "plugins":
16 | {
17 | "test_plugin1":
18 | {
19 | "$file_path": "${TestPluginsPath}/TestPlugin1.plugin",
20 | "version": "1.0.0",
21 | "comment": "test plugin which just returns the configured value",
22 | "instances":
23 | {
24 | "instance1":
25 | {
26 | "name": "instance1",
27 | "config":
28 | {
29 | "value": "value1"
30 | }
31 | },
32 |
33 | "instance2":
34 | {
35 | "name": "instance2",
36 | "config":
37 | {
38 | "value": "value2"
39 | }
40 | }
41 | }
42 | },
43 |
44 | "test_plugin2":
45 | {
46 | "$file_path": "${TestPluginsPath}/TestPlugin2.plugin",
47 | "min_version": "1.0.0",
48 | "max_version": "1.0.1",
49 | "comment": "test plugin which just joins the values it gets from its dependencies",
50 | "instances":
51 | {
52 | "instance3":
53 | {
54 | "name": "instance3",
55 | "config":
56 | {
57 | "delimiter": ";"
58 | },
59 | "dependencies":
60 | [
61 | "instance1",
62 | "instance2"
63 | ]
64 | }
65 | }
66 | }
67 | }
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/code/tests/integration/PluginManager/TestData/AppConfigWithInvalidStartupOrder.json:
--------------------------------------------------------------------------------
1 | {
2 | "includes":
3 | [
4 | {
5 | "file_path": "AppConfig.json"
6 | }
7 | ],
8 |
9 | "config":
10 | {
11 | "plugin_startup_priorities":
12 | [
13 | "instance3"
14 | ]
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/code/tests/integration/PluginManager/TestData/InvalidConfigWithUnsupportedDependency.json:
--------------------------------------------------------------------------------
1 | {
2 | "environment_variables":
3 | {
4 | "TestPluginsPath": "../TestPlugins"
5 | },
6 |
7 | "config":
8 | {
9 | "plugins":
10 | {
11 | "test_plugin1":
12 | {
13 | "$file_path": "${TestPluginsPath}/TestPlugin1.plugin",
14 | "version": "1.0.0",
15 | "instances":
16 | {
17 | "instance1":
18 | {
19 | "name": "instance1",
20 | "config":
21 | {
22 | "value": "value1"
23 | }
24 | },
25 |
26 | "instance2":
27 | {
28 | "name": "instance2",
29 | "config":
30 | {
31 | "value": "value2"
32 | },
33 | "dependencies":
34 | [
35 | "instance1"
36 | ]
37 | }
38 | }
39 | },
40 |
41 | "test_plugin2":
42 | {
43 | "$file_path": "${TestPluginsPath}/TestPlugin2.plugin",
44 | "min_version": "1.0.0",
45 | "max_version": "1.0.1",
46 | "instances":
47 | {
48 | "instance3":
49 | {
50 | "name": "instance3",
51 | "config":
52 | {
53 | "delimiter": ";"
54 | },
55 | "dependencies":
56 | [
57 | "instance1",
58 | "instance2"
59 | ]
60 | }
61 | }
62 | }
63 | }
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/code/tests/integration/PluginManager/testPluginManager.cpp:
--------------------------------------------------------------------------------
1 | /* This file is part of C++ Plugin Framework.
2 | *
3 | * C++ Plugin Framework is free software: you can redistribute it and/or modify it under the terms
4 | * of the GNU Lesser General Public License as published by the Free Software Foundation, either
5 | * version 3 of the License, or (at your option) any later version.
6 | *
7 | * C++ Plugin Framework is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
8 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 | * GNU Lesser General Public License for more details.
10 | *
11 | * You should have received a copy of the GNU Lesser General Public License along with C++ Plugin
12 | * Framework. If not, see .
13 | */
14 |
15 | /*!
16 | * \file
17 | *
18 | * Contains unit tests for PluginManager class
19 | */
20 |
21 | // C++ Plugin Framework includes
22 | #include
23 | #include
24 | #include "../TestPlugins/ITestPlugin1.hpp"
25 | #include "../TestPlugins/ITestPlugin2.hpp"
26 |
27 | // C++ Config Framework includes
28 | #include
29 |
30 | // Qt includes
31 | #include
32 | #include
33 |
34 | // System includes
35 |
36 | // Forward declarations
37 |
38 | // Macros
39 |
40 | // Test class declaration --------------------------------------------------------------------------
41 |
42 | using namespace CppConfigFramework;
43 | using namespace CppPluginFramework;
44 |
45 | class TestPluginManager : public QObject
46 | {
47 | Q_OBJECT
48 |
49 | private slots:
50 | // Functions executed by QtTest before and after test suite
51 | void initTestCase();
52 | void cleanupTestCase();
53 |
54 | // Functions executed by QtTest before and after each test
55 | void init();
56 | void cleanup();
57 |
58 | // Test functions
59 | void testLoad();
60 | void testLoadAfterStart();
61 | void testLoadPluginsWithInvalidConfig();
62 | void testLoadPluginsWithUnsupportedDependency();
63 | void testLoadPluginsWithInvalidStartupOrder();
64 | };
65 |
66 | // Test Case init/cleanup methods ------------------------------------------------------------------
67 |
68 | void TestPluginManager::initTestCase()
69 | {
70 | }
71 |
72 | void TestPluginManager::cleanupTestCase()
73 | {
74 | }
75 |
76 | // Test init/cleanup methods -----------------------------------------------------------------------
77 |
78 | void TestPluginManager::init()
79 | {
80 | }
81 |
82 | void TestPluginManager::cleanup()
83 | {
84 | }
85 |
86 | // Test: loading of plugins ------------------------------------------------------------------------
87 |
88 | void TestPluginManager::testLoad()
89 | {
90 | // First load the config
91 | ConfigReader configReader;
92 | EnvironmentVariables environmentVariables;
93 |
94 | auto config = configReader.read(":/TestData/AppConfig.json",
95 | QDir(QCoreApplication::applicationDirPath()),
96 | ConfigNodePath::ROOT_PATH,
97 | ConfigNodePath::ROOT_PATH,
98 | {},
99 | &environmentVariables);
100 | QVERIFY(config);
101 |
102 | PluginManagerConfig pluginManagerConfig;
103 | QVERIFY(pluginManagerConfig.loadConfig(*config));
104 |
105 | // Load plugins
106 | PluginManager pluginManager;
107 | QVERIFY(pluginManager.load(pluginManagerConfig));
108 |
109 | // Check all instances
110 | const QStringList instanceNames = pluginManager.pluginInstanceNames();
111 | QCOMPARE(instanceNames.count(), 3);
112 |
113 | QVERIFY(instanceNames.contains("instance1"));
114 | QVERIFY(instanceNames.contains("instance2"));
115 | QVERIFY(instanceNames.contains("instance3"));
116 |
117 | QVERIFY(pluginManager.hasPluginInstance("instance1"));
118 | QVERIFY(pluginManager.hasPluginInstance("instance2"));
119 | QVERIFY(pluginManager.hasPluginInstance("instance3"));
120 |
121 | auto instance1 = pluginManager.pluginInstance("instance1");
122 | auto instance2 = pluginManager.pluginInstance("instance2");
123 | auto instance3 = pluginManager.pluginInstance("instance3");
124 |
125 | QVERIFY(instance1 != nullptr);
126 | QVERIFY(instance2 != nullptr);
127 | QVERIFY(instance3 != nullptr);
128 |
129 | // Start plugins
130 | QVERIFY(pluginManager.start());
131 |
132 | // Check if all instances return expected values
133 | QCOMPARE(instance1->interface()->value(), QStringLiteral("value1"));
134 | QCOMPARE(instance2->interface()->value(), QStringLiteral("value2"));
135 | QCOMPARE(instance3->interface()->joinedValues(),
136 | QStringLiteral("value1;value2"));
137 |
138 | // Stop plugins
139 | pluginManager.stop();
140 |
141 | // Unload plugins
142 | QVERIFY(pluginManager.unload());
143 | }
144 |
145 | // Test: loading of plugins after the plugins were already started ---------------------------------
146 |
147 | void TestPluginManager::testLoadAfterStart()
148 | {
149 | // First load the config
150 | ConfigReader configReader;
151 | EnvironmentVariables environmentVariables;
152 |
153 | auto config = configReader.read(":/TestData/AppConfig.json",
154 | QDir(QCoreApplication::applicationDirPath()),
155 | ConfigNodePath::ROOT_PATH,
156 | ConfigNodePath::ROOT_PATH,
157 | std::vector(),
158 | &environmentVariables);
159 | QVERIFY(config);
160 |
161 | PluginManagerConfig pluginManagerConfig;
162 | QVERIFY(pluginManagerConfig.loadConfig(*config));
163 |
164 | // Load plugins
165 | PluginManager pluginManager;
166 | QVERIFY(pluginManager.load(pluginManagerConfig));
167 |
168 | // Start plugins
169 | QVERIFY(pluginManager.start());
170 |
171 | // Load plugins again (must fail)
172 | QVERIFY(!pluginManager.load(pluginManagerConfig));
173 |
174 | // Stop plugins
175 | pluginManager.stop();
176 |
177 | // Unload plugins
178 | QVERIFY(pluginManager.unload());
179 | }
180 |
181 | // Test: loading of plugins with invalid config ----------------------------------------------------
182 |
183 | void TestPluginManager::testLoadPluginsWithInvalidConfig()
184 | {
185 | PluginManagerConfig pluginManagerConfig;
186 | pluginManagerConfig.setPluginConfigs({ PluginConfig() });
187 |
188 | // Load plugins with invalid config
189 | PluginManager pluginManager;
190 | QVERIFY(!pluginManager.load(pluginManagerConfig));
191 | }
192 |
193 | // Test: loading of plugins with an unsupported dependency -----------------------------------------
194 |
195 | void TestPluginManager::testLoadPluginsWithUnsupportedDependency()
196 | {
197 | // First load the config
198 | ConfigReader configReader;
199 | EnvironmentVariables environmentVariables;
200 |
201 | auto config = configReader.read(":/TestData/InvalidConfigWithUnsupportedDependency.json",
202 | QDir(QCoreApplication::applicationDirPath()),
203 | ConfigNodePath::ROOT_PATH,
204 | ConfigNodePath::ROOT_PATH,
205 | std::vector(),
206 | &environmentVariables);
207 | QVERIFY(config);
208 |
209 | PluginManagerConfig pluginManagerConfig;
210 | QVERIFY(pluginManagerConfig.loadConfig(*config));
211 |
212 | PluginManager pluginManager;
213 | QVERIFY(!pluginManager.load(pluginManagerConfig));
214 | }
215 |
216 | // Test: loading of plugins with invalid startup order ---------------------------------------------
217 |
218 | void TestPluginManager::testLoadPluginsWithInvalidStartupOrder()
219 | {
220 | // First load the config
221 | ConfigReader configReader;
222 | EnvironmentVariables environmentVariables;
223 |
224 | auto config = configReader.read(":/TestData/AppConfigWithInvalidStartupOrder.json",
225 | QDir(QCoreApplication::applicationDirPath()),
226 | ConfigNodePath::ROOT_PATH,
227 | ConfigNodePath::ROOT_PATH,
228 | std::vector(),
229 | &environmentVariables);
230 | QVERIFY(config);
231 |
232 | PluginManagerConfig pluginManagerConfig;
233 | QVERIFY(pluginManagerConfig.loadConfig(*config));
234 |
235 | // Load plugins
236 | PluginManager pluginManager;
237 | QVERIFY(pluginManager.load(pluginManagerConfig));
238 |
239 | // Start plugins (must fail)
240 | QVERIFY(!pluginManager.start());
241 | }
242 |
243 | // Main function -----------------------------------------------------------------------------------
244 |
245 | QTEST_MAIN(TestPluginManager)
246 | #include "testPluginManager.moc"
247 |
--------------------------------------------------------------------------------
/code/tests/integration/TestPlugins/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # This file is part of C++ Plugin Framework.
2 | #
3 | # C++ Plugin Framework is free software: you can redistribute it and/or modify it under the terms
4 | # of the GNU Lesser General Public License as published by the Free Software Foundation, either
5 | # version 3 of the License, or (at your option) any later version.
6 | #
7 | # C++ Plugin Framework is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
8 | # without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 | # GNU Lesser General Public License for more details.
10 | #
11 | # You should have received a copy of the GNU Lesser General Public License along with C++ Plugin
12 | # Framework. If not, see .
13 |
14 | # --------------------------------------------------------------------------------------------------
15 | # Test Plugin 1
16 | # --------------------------------------------------------------------------------------------------
17 | add_library(TestPlugin1 SHARED
18 | ITestPlugin1.hpp
19 | TestPlugin1.hpp
20 | TestPlugin1.cpp
21 | )
22 |
23 | target_include_directories(TestPlugin1
24 | PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}
25 | )
26 |
27 | target_link_libraries(TestPlugin1
28 | PUBLIC CppPluginFramework
29 | PUBLIC Qt5::Core
30 | )
31 |
32 | set_target_properties(TestPlugin1 PROPERTIES
33 | PREFIX ""
34 | SUFFIX ".plugin"
35 | )
36 |
37 | # --------------------------------------------------------------------------------------------------
38 | # Test Plugin 2
39 | # --------------------------------------------------------------------------------------------------
40 | add_library(TestPlugin2 SHARED
41 | ITestPlugin2.hpp
42 | TestPlugin2.hpp
43 | TestPlugin2.cpp
44 | )
45 |
46 | target_include_directories(TestPlugin2
47 | PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}
48 | )
49 |
50 | target_link_libraries(TestPlugin2
51 | PUBLIC CppPluginFramework
52 | PUBLIC Qt5::Core
53 | )
54 |
55 | set_target_properties(TestPlugin2 PROPERTIES
56 | PREFIX ""
57 | SUFFIX ".plugin"
58 | )
59 |
--------------------------------------------------------------------------------
/code/tests/integration/TestPlugins/ITestPlugin1.hpp:
--------------------------------------------------------------------------------
1 | /* This file is part of C++ Plugin Framework.
2 | *
3 | * C++ Plugin Framework is free software: you can redistribute it and/or modify it under the terms
4 | * of the GNU Lesser General Public License as published by the Free Software Foundation, either
5 | * version 3 of the License, or (at your option) any later version.
6 | *
7 | * C++ Plugin Framework is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
8 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 | * GNU Lesser General Public License for more details.
10 | *
11 | * You should have received a copy of the GNU Lesser General Public License along with C++ Plugin
12 | * Framework. If not, see .
13 | */
14 |
15 | /*!
16 | * \file
17 | *
18 | * Contains the interface for the "test plugin 1"
19 | */
20 |
21 | #pragma once
22 |
23 | // Qt includes
24 | #include
25 |
26 | // System includes
27 |
28 | // Forward declarations
29 |
30 | // Macros
31 |
32 | // -------------------------------------------------------------------------------------------------
33 |
34 | namespace CppPluginFramework
35 | {
36 | namespace TestPlugins
37 | {
38 |
39 | class ITestPlugin1
40 | {
41 | public:
42 | virtual ~ITestPlugin1() = default;
43 | virtual QString value() const = 0;
44 | };
45 |
46 | } // namespace TestPlugins
47 | } // namespace CppPluginFramework
48 |
--------------------------------------------------------------------------------
/code/tests/integration/TestPlugins/ITestPlugin2.hpp:
--------------------------------------------------------------------------------
1 | /* This file is part of C++ Plugin Framework.
2 | *
3 | * C++ Plugin Framework is free software: you can redistribute it and/or modify it under the terms
4 | * of the GNU Lesser General Public License as published by the Free Software Foundation, either
5 | * version 3 of the License, or (at your option) any later version.
6 | *
7 | * C++ Plugin Framework is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
8 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 | * GNU Lesser General Public License for more details.
10 | *
11 | * You should have received a copy of the GNU Lesser General Public License along with C++ Plugin
12 | * Framework. If not, see .
13 | */
14 |
15 | /*!
16 | * \file
17 | *
18 | * Contains the interface for the "test plugin 2"
19 | */
20 |
21 | #pragma once
22 |
23 | // Qt includes
24 | #include
25 |
26 | // System includes
27 |
28 | // Forward declarations
29 |
30 | // Macros
31 |
32 | // -------------------------------------------------------------------------------------------------
33 |
34 | namespace CppPluginFramework
35 | {
36 | namespace TestPlugins
37 | {
38 |
39 | class ITestPlugin2
40 | {
41 | public:
42 | virtual ~ITestPlugin2() = default;
43 | virtual QString joinedValues() const = 0;
44 | };
45 |
46 | } // namespace TestPlugins
47 | } // namespace CppPluginFramework
48 |
--------------------------------------------------------------------------------
/code/tests/integration/TestPlugins/TestPlugin1.cpp:
--------------------------------------------------------------------------------
1 | /* This file is part of C++ Plugin Framework.
2 | *
3 | * C++ Plugin Framework is free software: you can redistribute it and/or modify it under the terms
4 | * of the GNU Lesser General Public License as published by the Free Software Foundation, either
5 | * version 3 of the License, or (at your option) any later version.
6 | *
7 | * C++ Plugin Framework is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
8 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 | * GNU Lesser General Public License for more details.
10 | *
11 | * You should have received a copy of the GNU Lesser General Public License along with C++ Plugin
12 | * Framework. If not, see .
13 | */
14 |
15 | /*!
16 | * \file
17 | *
18 | * Contains the "test plugin 1"
19 | */
20 |
21 | // C++ Plugin Framework includes
22 | #include "TestPlugin1.hpp"
23 |
24 | // C++ Config Framework includes
25 | #include
26 |
27 | // Cedar Framework includes
28 | #include
29 |
30 | // Qt includes
31 |
32 | // System includes
33 |
34 | // Forward declarations
35 |
36 | // Macros
37 |
38 | // -------------------------------------------------------------------------------------------------
39 |
40 | namespace CppPluginFramework
41 | {
42 | namespace TestPlugins
43 | {
44 |
45 | // -------------------------------------------------------------------------------------------------
46 |
47 | static const VersionInfo s_version("1.0.0");
48 | static const QString s_description("test plugin 1");
49 | static const QSet s_exportedInterfaces
50 | {
51 | "CppPluginFramework::TestPlugins::ITestPlugin1"
52 | };
53 |
54 | // -------------------------------------------------------------------------------------------------
55 |
56 | TestPlugin1::TestPlugin1(const QString &name)
57 | : CppPluginFramework::AbstractPlugin(name, s_version, s_description, s_exportedInterfaces)
58 | {
59 | }
60 |
61 | // -------------------------------------------------------------------------------------------------
62 |
63 | bool TestPlugin1::loadConfig(const CppConfigFramework::ConfigObjectNode &config)
64 | {
65 | const auto jsonValue = CppConfigFramework::ConfigWriter::convertToJsonValue(config);
66 |
67 | if (!jsonValue.isObject())
68 | {
69 | return false;
70 | }
71 |
72 | return CedarFramework::deserializeNode(jsonValue, "value", &m_configuredValue);
73 | }
74 |
75 | // -------------------------------------------------------------------------------------------------
76 |
77 | bool TestPlugin1::injectDependency(IPlugin *plugin)
78 | {
79 | // This plugin doesn't support dependencies!
80 | Q_UNUSED(plugin)
81 | return false;
82 | }
83 |
84 | // -------------------------------------------------------------------------------------------------
85 |
86 | void TestPlugin1::ejectDependencies()
87 | {
88 | }
89 |
90 | // -------------------------------------------------------------------------------------------------
91 |
92 | QString TestPlugin1::value() const
93 | {
94 | return m_configuredValue;
95 | }
96 |
97 | } // namespace TestPlugins
98 | } // namespace CppPluginFramework
99 |
--------------------------------------------------------------------------------
/code/tests/integration/TestPlugins/TestPlugin1.hpp:
--------------------------------------------------------------------------------
1 | /* This file is part of C++ Plugin Framework.
2 | *
3 | * C++ Plugin Framework is free software: you can redistribute it and/or modify it under the terms
4 | * of the GNU Lesser General Public License as published by the Free Software Foundation, either
5 | * version 3 of the License, or (at your option) any later version.
6 | *
7 | * C++ Plugin Framework is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
8 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 | * GNU Lesser General Public License for more details.
10 | *
11 | * You should have received a copy of the GNU Lesser General Public License along with C++ Plugin
12 | * Framework. If not, see .
13 | */
14 |
15 | /*!
16 | * \file
17 | *
18 | * Contains the "test plugin 1"
19 | */
20 |
21 | #pragma once
22 |
23 | // C++ Plugin Framework includes
24 | #include
25 | #include
26 | #include
27 |
28 | // Qt includes
29 |
30 | // System includes
31 |
32 | // Forward declarations
33 |
34 | // Macros
35 |
36 | // -------------------------------------------------------------------------------------------------
37 |
38 | namespace CppPluginFramework
39 | {
40 | namespace TestPlugins
41 | {
42 |
43 | class TestPlugin1 : public CppPluginFramework::AbstractPlugin, public ITestPlugin1
44 | {
45 | public:
46 | TestPlugin1(const QString &name);
47 | ~TestPlugin1() = default;
48 |
49 | bool loadConfig(const CppConfigFramework::ConfigObjectNode &config) override;
50 | bool injectDependency(IPlugin *plugin) override;
51 | void ejectDependencies() override;
52 |
53 | virtual QString value() const override;
54 |
55 | private:
56 | QString m_configuredValue;
57 | };
58 |
59 | // -------------------------------------------------------------------------------------------------
60 |
61 | class Q_DECL_EXPORT PluginFactory : public QObject, public PluginFactoryTemplate
62 | {
63 | Q_OBJECT
64 | Q_PLUGIN_METADATA(IID "CppPluginFramework::IPluginFactory")
65 | Q_INTERFACES(CppPluginFramework::IPluginFactory)
66 |
67 | public:
68 | //! Destructor
69 | ~PluginFactory() override = default;
70 | };
71 |
72 | } // namespace TestPlugins
73 | } // namespace CppPluginFramework
74 |
--------------------------------------------------------------------------------
/code/tests/integration/TestPlugins/TestPlugin2.cpp:
--------------------------------------------------------------------------------
1 | /* This file is part of C++ Plugin Framework.
2 | *
3 | * C++ Plugin Framework is free software: you can redistribute it and/or modify it under the terms
4 | * of the GNU Lesser General Public License as published by the Free Software Foundation, either
5 | * version 3 of the License, or (at your option) any later version.
6 | *
7 | * C++ Plugin Framework is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
8 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 | * GNU Lesser General Public License for more details.
10 | *
11 | * You should have received a copy of the GNU Lesser General Public License along with C++ Plugin
12 | * Framework. If not, see .
13 | */
14 |
15 | /*!
16 | * \file
17 | *
18 | * Contains the "test plugin 2"
19 | */
20 |
21 | // C++ Plugin Framework includes
22 | #include "TestPlugin2.hpp"
23 |
24 | // C++ Config Framework includes
25 | #include
26 |
27 | // Cedar Framework includes
28 | #include
29 |
30 | // Qt includes
31 |
32 | // System includes
33 |
34 | // Forward declarations
35 |
36 | // Macros
37 |
38 | // -------------------------------------------------------------------------------------------------
39 |
40 | namespace CppPluginFramework
41 | {
42 | namespace TestPlugins
43 | {
44 |
45 | // -------------------------------------------------------------------------------------------------
46 |
47 | static const VersionInfo s_version("1.0.0");
48 | static const QString s_description("test plugin 2");
49 | static const QSet s_exportedInterfaces
50 | {
51 | "CppPluginFramework::TestPlugins::ITestPlugin2"
52 | };
53 |
54 | // -------------------------------------------------------------------------------------------------
55 |
56 | TestPlugin2::TestPlugin2(const QString &name)
57 | : CppPluginFramework::AbstractPlugin(name, s_version, s_description, s_exportedInterfaces)
58 | {
59 | }
60 |
61 | // -------------------------------------------------------------------------------------------------
62 |
63 | bool TestPlugin2::loadConfig(const CppConfigFramework::ConfigObjectNode &config)
64 | {
65 | const auto jsonValue = CppConfigFramework::ConfigWriter::convertToJsonValue(config);
66 |
67 | if (!jsonValue.isObject())
68 | {
69 | return false;
70 | }
71 |
72 | return CedarFramework::deserializeNode(jsonValue, "delimiter", &m_configuredDelimiter);
73 | }
74 |
75 | // -------------------------------------------------------------------------------------------------
76 |
77 | bool TestPlugin2::injectDependency(IPlugin *plugin)
78 | {
79 | if (isStarted())
80 | {
81 | return false;
82 | }
83 |
84 | if (!plugin->isInterfaceExported("CppPluginFramework::TestPlugins::ITestPlugin1"))
85 | {
86 | return false;
87 | }
88 |
89 | auto *interface = plugin->interface();
90 |
91 | if (interface == nullptr)
92 | {
93 | return false;
94 | }
95 |
96 | m_dependencies.append(plugin);
97 | return true;
98 | }
99 |
100 | // -------------------------------------------------------------------------------------------------
101 |
102 | void TestPlugin2::ejectDependencies()
103 | {
104 | if (!isStarted())
105 | {
106 | m_dependencies.clear();
107 | }
108 | }
109 |
110 | // -------------------------------------------------------------------------------------------------
111 |
112 | QString TestPlugin2::joinedValues() const
113 | {
114 | QStringList values;
115 |
116 | for (auto *dependency : m_dependencies)
117 | {
118 | auto *interface = dependency->interface();
119 | values.append(interface->value());
120 | }
121 |
122 | values.sort();
123 |
124 | return values.join(m_configuredDelimiter);
125 | }
126 |
127 | // -------------------------------------------------------------------------------------------------
128 |
129 | bool TestPlugin2::onStart()
130 | {
131 | if (m_dependencies.isEmpty())
132 | {
133 | return false;
134 | }
135 |
136 | for (auto *dependency : qAsConst(m_dependencies))
137 | {
138 | if (!dependency->isStarted())
139 | {
140 | return false;
141 | }
142 | }
143 |
144 | return true;
145 | }
146 |
147 | } // namespace TestPlugins
148 | } // namespace CppPluginFramework
149 |
--------------------------------------------------------------------------------
/code/tests/integration/TestPlugins/TestPlugin2.hpp:
--------------------------------------------------------------------------------
1 | /* This file is part of C++ Plugin Framework.
2 | *
3 | * C++ Plugin Framework is free software: you can redistribute it and/or modify it under the terms
4 | * of the GNU Lesser General Public License as published by the Free Software Foundation, either
5 | * version 3 of the License, or (at your option) any later version.
6 | *
7 | * C++ Plugin Framework is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
8 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 | * GNU Lesser General Public License for more details.
10 | *
11 | * You should have received a copy of the GNU Lesser General Public License along with C++ Plugin
12 | * Framework. If not, see .
13 | */
14 |
15 | /*!
16 | * \file
17 | *
18 | * Contains the "test plugin 2"
19 | */
20 |
21 | #pragma once
22 |
23 | // C++ Plugin Framework includes
24 | #include
25 | #include
26 | #include
27 | #include
28 |
29 | // Qt includes
30 |
31 | // System includes
32 |
33 | // Forward declarations
34 |
35 | // Macros
36 |
37 | // -------------------------------------------------------------------------------------------------
38 |
39 | namespace CppPluginFramework
40 | {
41 | namespace TestPlugins
42 | {
43 |
44 | class TestPlugin2 : public CppPluginFramework::AbstractPlugin, public ITestPlugin2
45 | {
46 | public:
47 | TestPlugin2(const QString &name);
48 | virtual ~TestPlugin2() = default;
49 |
50 | virtual bool loadConfig(const CppConfigFramework::ConfigObjectNode &config) override;
51 | virtual bool injectDependency(IPlugin *plugin) override;
52 | virtual void ejectDependencies() override;
53 |
54 | virtual QString joinedValues() const override;
55 |
56 | private:
57 | bool onStart() override;
58 |
59 | private:
60 | QString m_configuredDelimiter;
61 | QList m_dependencies;
62 | };
63 |
64 | // -------------------------------------------------------------------------------------------------
65 |
66 | class Q_DECL_EXPORT PluginFactory : public QObject, public PluginFactoryTemplate
67 | {
68 | Q_OBJECT
69 | Q_PLUGIN_METADATA(IID "CppPluginFramework::IPluginFactory")
70 | Q_INTERFACES(CppPluginFramework::IPluginFactory)
71 |
72 | public:
73 | //! Destructor
74 | ~PluginFactory() override = default;
75 | };
76 |
77 | } // namespace TestPlugins
78 | } // namespace CppPluginFramework
79 |
--------------------------------------------------------------------------------
/code/tests/unit/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # This file is part of C++ Plugin Framework.
2 | #
3 | # C++ Plugin Framework is free software: you can redistribute it and/or modify it under the terms
4 | # of the GNU Lesser General Public License as published by the Free Software Foundation, either
5 | # version 3 of the License, or (at your option) any later version.
6 | #
7 | # C++ Plugin Framework is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
8 | # without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 | # GNU Lesser General Public License for more details.
10 | #
11 | # You should have received a copy of the GNU Lesser General Public License along with C++ Plugin
12 | # Framework. If not, see .
13 |
14 | # --------------------------------------------------------------------------------------------------
15 | # Custom (meta) targets
16 | # --------------------------------------------------------------------------------------------------
17 | add_custom_target(all_unit_tests)
18 |
19 | # --------------------------------------------------------------------------------------------------
20 | # Helper methods
21 | # --------------------------------------------------------------------------------------------------
22 | function(CppPluginFramework_AddUnitTest)
23 | # Function parameters
24 | set(options) # Boolean parameters
25 | set(oneValueParams # Parameters with one value
26 | TEST_NAME
27 | )
28 | set(multiValueParams) # Parameters with multiple values
29 |
30 | cmake_parse_arguments(PARAM "${options}" "${oneValueParams}" "${multiValueParams}" ${ARGN})
31 |
32 | # Add test
33 | CppPluginFramework_AddTest(${ARGN} LABELS CPPPLUGINFRAMEWORK_UNIT_TESTS)
34 |
35 | # Add test to target "all_unit_tests"
36 | add_dependencies(all_unit_tests ${PARAM_TEST_NAME})
37 | endfunction()
38 |
39 | # --------------------------------------------------------------------------------------------------
40 | # Unit tests
41 | # --------------------------------------------------------------------------------------------------
42 | add_subdirectory(PluginConfig)
43 | add_subdirectory(PluginInstanceConfig)
44 | add_subdirectory(PluginManagerConfig)
45 | add_subdirectory(Validation)
46 | add_subdirectory(VersionInfo)
47 |
48 | # --------------------------------------------------------------------------------------------------
49 | # Code Coverage
50 | # --------------------------------------------------------------------------------------------------
51 | if (CppPluginFramework_CodeCoverage MATCHES ON)
52 | # Prepare targets for code coverage
53 | SETUP_TARGET_FOR_COVERAGE(
54 | NAME ctest_coverage_all_unit_tests
55 | EXECUTABLE ctest -L CPPPLUGINFRAMEWORK_UNIT_TESTS
56 | DEPENDENCIES all_unit_tests
57 | PROJECT_PATH ${PROJECT_SOURCE_DIR}
58 | EXCLUDES ${CppPluginFramework_CodeCoverage_EXCLUDES}
59 | )
60 | endif()
61 |
--------------------------------------------------------------------------------
/code/tests/unit/PluginConfig/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # This file is part of C++ Plugin Framework.
2 | #
3 | # C++ Plugin Framework is free software: you can redistribute it and/or modify it under the terms
4 | # of the GNU Lesser General Public License as published by the Free Software Foundation, either
5 | # version 3 of the License, or (at your option) any later version.
6 | #
7 | # C++ Plugin Framework is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
8 | # without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 | # GNU Lesser General Public License for more details.
10 | #
11 | # You should have received a copy of the GNU Lesser General Public License along with C++ Plugin
12 | # Framework. If not, see .
13 |
14 | CppPluginFramework_AddUnitTest(TEST_NAME testPluginConfig)
15 |
--------------------------------------------------------------------------------
/code/tests/unit/PluginInstanceConfig/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # This file is part of C++ Plugin Framework.
2 | #
3 | # C++ Plugin Framework is free software: you can redistribute it and/or modify it under the terms
4 | # of the GNU Lesser General Public License as published by the Free Software Foundation, either
5 | # version 3 of the License, or (at your option) any later version.
6 | #
7 | # C++ Plugin Framework is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
8 | # without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 | # GNU Lesser General Public License for more details.
10 | #
11 | # You should have received a copy of the GNU Lesser General Public License along with C++ Plugin
12 | # Framework. If not, see .
13 |
14 | CppPluginFramework_AddUnitTest(TEST_NAME testPluginInstanceConfig)
15 |
--------------------------------------------------------------------------------
/code/tests/unit/PluginManagerConfig/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # This file is part of C++ Plugin Framework.
2 | #
3 | # C++ Plugin Framework is free software: you can redistribute it and/or modify it under the terms
4 | # of the GNU Lesser General Public License as published by the Free Software Foundation, either
5 | # version 3 of the License, or (at your option) any later version.
6 | #
7 | # C++ Plugin Framework is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
8 | # without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 | # GNU Lesser General Public License for more details.
10 | #
11 | # You should have received a copy of the GNU Lesser General Public License along with C++ Plugin
12 | # Framework. If not, see .
13 |
14 | CppPluginFramework_AddUnitTest(TEST_NAME testPluginManagerConfig ADDITIONAL_SOURCES TestData.qrc)
15 |
--------------------------------------------------------------------------------
/code/tests/unit/PluginManagerConfig/TestData.qrc:
--------------------------------------------------------------------------------
1 |
2 |
3 | TestData/dummyPlugin1
4 | TestData/dummyPlugin2
5 |
6 |
7 |
--------------------------------------------------------------------------------
/code/tests/unit/PluginManagerConfig/TestData/dummyPlugin1:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/code/tests/unit/PluginManagerConfig/TestData/dummyPlugin2:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/code/tests/unit/Validation/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # This file is part of C++ Plugin Framework.
2 | #
3 | # C++ Plugin Framework is free software: you can redistribute it and/or modify it under the terms
4 | # of the GNU Lesser General Public License as published by the Free Software Foundation, either
5 | # version 3 of the License, or (at your option) any later version.
6 | #
7 | # C++ Plugin Framework is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
8 | # without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 | # GNU Lesser General Public License for more details.
10 | #
11 | # You should have received a copy of the GNU Lesser General Public License along with C++ Plugin
12 | # Framework. If not, see .
13 |
14 | CppPluginFramework_AddUnitTest(TEST_NAME testValidation ADDITIONAL_SOURCES TestData.qrc)
15 |
--------------------------------------------------------------------------------
/code/tests/unit/Validation/TestData.qrc:
--------------------------------------------------------------------------------
1 |
2 |
3 | TestData/file
4 | TestData/file.ext
5 | TestData/file.txt
6 | TestData/somePath/file
7 | TestData/somePath/file.ext
8 | TestData/somePath/file.txt
9 |
10 |
11 |
--------------------------------------------------------------------------------
/code/tests/unit/Validation/TestData/file:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/code/tests/unit/Validation/TestData/file.ext:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/code/tests/unit/Validation/TestData/file.txt:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/code/tests/unit/Validation/TestData/somePath/file:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/code/tests/unit/Validation/TestData/somePath/file.ext:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/code/tests/unit/Validation/TestData/somePath/file.txt:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/code/tests/unit/VersionInfo/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # This file is part of C++ Plugin Framework.
2 | #
3 | # C++ Plugin Framework is free software: you can redistribute it and/or modify it under the terms
4 | # of the GNU Lesser General Public License as published by the Free Software Foundation, either
5 | # version 3 of the License, or (at your option) any later version.
6 | #
7 | # C++ Plugin Framework is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
8 | # without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 | # GNU Lesser General Public License for more details.
10 | #
11 | # You should have received a copy of the GNU Lesser General Public License along with C++ Plugin
12 | # Framework. If not, see .
13 |
14 | CppPluginFramework_AddUnitTest(TEST_NAME testVersionInfo)
15 |
--------------------------------------------------------------------------------
/docs/Design.md:
--------------------------------------------------------------------------------
1 | # Design
2 |
3 | The plugin framework has two main uses:
4 |
5 | * Creating plugins
6 | * Plugin management
7 |
8 |
9 | ## Plugins
10 |
11 | Each plugin shall provide the following metadata:
12 |
13 | * Instance Name
14 | * Version
15 | * Description
16 | * Exported Interfaces
17 |
18 | Each plugin shall also provide some management features:
19 |
20 | * Configuration of the plugin
21 | * Injection and ejection of its dependencies
22 | * Stating and stopping of the plugin
23 |
24 | The main purpose of the plugin is to export an interface to a specific functionality. Each exposed interface can be accessed by using the `interface()` method.
25 |
26 | 
27 |
28 |
29 | ### Plugin Implementation
30 |
31 | All plugins shall inherit from the `IPlugin` interface.
32 |
33 | For most plugins it should be sufficient to use the `AbstractPlugin` base class. This class shall provide implementation of the *boilerplate* part of a plugin. The plugins that shall use it shall only need to implement the following:
34 |
35 | * Loading the plugin's configuration (optional feature)
36 | * Management of plugin's dependencies (optional feature)
37 | * Handling of plugin startup and shutdown procedures (for some plugins the default implementation should be good enough)
38 | * Exported interfaces (one or more)
39 |
40 | For more advanced uses it shall be necessary to use the `IPlugin` interface directly.
41 |
42 |
43 | ### Dynamically Linked Library
44 |
45 | A dynamically linked library shall be created for each plugin. This library shall provide a plugin factory with which individual plugin instances can be created.
46 |
47 | 
48 |
49 |
50 | ## Plugin Management
51 |
52 | Applications that want to use plugins need to use `PluginManager` class. Its purpose is to:
53 |
54 | * Load the plugins
55 | * Create and configure plugin instances
56 | * Provide access to the plugin instances
57 | * Inject dependencies into plugin instances
58 | * Start the plugins
59 | * Stop the plugins
60 | * Eject dependencies from plugin instances
61 | * Unload the plugins
62 |
63 | 
64 |
65 |
66 | ### Configuration
67 |
68 | The configuration must be represented in *CppConfigFramework* format.
69 |
70 | 
71 |
72 | Plugin management configuration shall be represented in a three level hierarchy: plugin manager, plugins, and plugin instances.
73 |
74 | The plugin manager shall provide the following information:
75 |
76 | * Plugin configurations
77 | * Plugin startup priorities (optional)
78 |
79 | Each plugin shall provide the following information:
80 |
81 | * Plugin file path
82 | * Version requirements (exact version or version range)
83 | * List of plugin instances (at least one)
84 |
85 | Each plugin instance needs to provide the following information:
86 |
87 | * Plugin instance name
88 | * Configuration (optional)
89 | * List of plugin dependencies (optional)
90 |
91 |
92 | ### Plugin Startup Workflow
93 |
94 | The application shall first load the configuration (from a *CppConfigFramework* file or equivalent *JSON Object*) and then the configured plugins shall be loaded with the plugin manager. Finally the application shall start the plugins.
95 |
96 | The plugins shall be started in the same order as defined in the configuration. First all the plugins from the *plugin startup priorities* shall be started (in the defined order) and then all the others (in no particular order).
97 |
98 | 
99 |
100 |
101 | ### Plugin Shutdown Workflow
102 |
103 | When the application no longer needs the plugins it shall first stop the plugins and then unload them.
104 |
105 | 
106 |
--------------------------------------------------------------------------------
/docs/Diagrams/ClassDiagrams.plantuml:
--------------------------------------------------------------------------------
1 | @startuml Plugin
2 | IPlugin <|-- AbstractPlugin
3 | AbstractPlugin <|-- ExamplePlugin
4 | ExampleInterfaceA <|-- ExamplePlugin
5 | ExampleInterfaceB <|-- ExamplePlugin
6 |
7 | abstract class IPlugin {
8 | {abstract} +name()
9 | {abstract} +version()
10 | {abstract} +description()
11 | {abstract} +isInterfaceExported(interface)
12 | {abstract} +exportedInterfaces()
13 | {abstract} +loadConfig(config)
14 | {abstract} +injectDependency(plugin)
15 | {abstract} +ejectDependencies()
16 | {abstract} +isStarted()
17 | {abstract} +start()
18 | {abstract} +stop()
19 | +interface()
20 | }
21 |
22 | abstract class AbstractPlugin {
23 | +name()
24 | +version()
25 | +description()
26 | +isInterfaceExported(interface)
27 | +exportedInterfaces()
28 | +loadConfig(config)
29 | +injectDependency(plugin)
30 | +ejectDependencies()
31 | +isStarted()
32 | +start()
33 | +stop()
34 | +interface()
35 | {abstract} -onStart()
36 | {abstract} -onStop()
37 | }
38 |
39 | class ExampleInterfaceA {
40 | {abstract} +exampleMethodA()
41 | }
42 |
43 | class ExampleInterfaceB {
44 | {abstract} +exampleMethodB()
45 | }
46 |
47 | class ExamplePlugin {
48 | +injectDependency()
49 | +ejectDependencies()
50 | +exampleMethodA()
51 | +exampleMethodB()
52 | -onStart()
53 | -onStop()
54 | }
55 | @enduml
56 |
57 | @startuml PluginFactory
58 | IPluginFactory <|-- PluginFactory
59 |
60 | abstract class IPluginFactory {
61 | {abstract} +createInstance(instanceName)
62 | }
63 |
64 | class PluginFactory {
65 | +createInstance(instanceName)
66 | }
67 | @enduml
68 |
69 | @startuml PluginManager
70 | PluginManager -- Plugin
71 |
72 | class PluginManager {
73 | +load()
74 | +unload()
75 | +start()
76 | +stop()
77 | +pluginInstance(instanceName)
78 | +pluginInstanceNames()
79 | }
80 |
81 | class Plugin {
82 | +loadInstances(pluginConfig)
83 | -loadInstance(pluginFactory, instanceConfig)
84 | -checkVersion(pluginVersion, pluginConfig)
85 | }
86 |
87 | @startuml PluginManagerConfig
88 | PluginManagerConfig o-- PluginConfig
89 | PluginConfig o-- PluginInstanceConfig
90 |
91 | class PluginManagerConfig {
92 | +isValid()
93 | +pluginConfigs()
94 | +setPluginConfigs(pluginConfigs)
95 | +pluginStartupPriorities()
96 | +setPluginStartupPriorities(startupPriorities)
97 | }
98 |
99 | class PluginConfig {
100 | +isValid()
101 | +isExactVersion()
102 | +isVersionRange()
103 | +filePath()
104 | +setFilePath(filePath)
105 | +version()
106 | +setVersion(version)
107 | +minVersion()
108 | +setMinVersion(minVersion)
109 | +maxVersion()
110 | +setMaxVersion(maxVersion)
111 | +instanceConfigs()
112 | +setInstanceConfigs(instanceConfigs)
113 | }
114 |
115 | class PluginInstanceConfig {
116 | +isValid()
117 | +name()
118 | +setName(name)
119 | +config()
120 | +setConfig(config)
121 | +dependencies()
122 | +setDependencies(dependencies)
123 | }
124 | @enduml
125 |
--------------------------------------------------------------------------------
/docs/Diagrams/ClassDiagrams/PluginFactory.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/docs/Diagrams/ClassDiagrams/PluginManager.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/docs/Diagrams/FlowCharts.plantuml:
--------------------------------------------------------------------------------
1 | @startuml StartupWorkflow
2 | start
3 |
4 | :Load plugin manager configuration;
5 | -> Iterate over plugin configurations;
6 |
7 | repeat
8 | :Load plugin library;
9 | :Get plugin factory;
10 | -> Iterate over plugin instance configurations;
11 |
12 | repeat
13 | :Create plugin instance;
14 | :Configure plugin instance;
15 | :Check plugin instance version;
16 | :Store plugin instance;
17 | repeat while (All plugin instances loaded?) is (No)
18 | -> Yes;
19 | repeat while (All plugins loaded?) is (No)
20 | -> Yes;
21 | :Inject all dependencies;
22 | :Prepare startup order;
23 | :Start all plugin instances;
24 | stop
25 |
26 | @enduml
27 |
28 | @startuml ShutdownWorkflow
29 | start
30 |
31 | :Stop all plugin instances;
32 | :Eject all dependencies;
33 | :Destroy plugin instances;
34 |
35 | stop
36 |
37 | @enduml
38 |
--------------------------------------------------------------------------------
/docs/Diagrams/FlowCharts/ShutdownWorkflow.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/docs/Requirements.md:
--------------------------------------------------------------------------------
1 | # Requirements
2 |
3 |
4 | ## [R1] Plugin metadata
5 |
6 | Each plugin shall expose the following metadata:
7 |
8 | * Instance Name
9 | * Version
10 | * Description
11 | * Exported Interfaces
12 |
13 | For *Instance Name* see [[R2] Plugin instance name](#r2-plugin-instance-name).
14 |
15 | For *Version* see [[R3] Plugin version](#r3-plugin-version).
16 |
17 | *Description* is an optional text that describes the purpose of the plugin and/or any other information about the plugin.
18 |
19 | For *Exported Interfaces* see [[R4] Exported interfaces](#r4-exported-interfaces).
20 |
21 |
22 | ## [R2] Plugin instance name
23 |
24 | Represents the name of plugin instance. Allowed characters are:
25 |
26 | * All letters of the English alphabet (A-Z, a-z)
27 | * Numbers (0-9)
28 | * Period character (U+002E)
29 | * Hyphen character (U+002D)
30 | * Underscore character (U+005F)
31 |
32 | The plugin instance name shall always start with a letter.
33 |
34 |
35 | ## [R3] Plugin version
36 |
37 | Each plugin shall have a version which shall be in one of the following formats:
38 |
39 | * `MAJOR.MINOR.PATCH`
40 | * `MAJOR.MINOR.PATCH-DEV`
41 |
42 |
43 | ### Major version
44 |
45 | `MAJOR` part of the version shall be a non-negative integer. This part of the version shall be incremented every time when there is a significant change in the architecture and/or design of the plugin.
46 |
47 |
48 | ### Minor version
49 |
50 | `MINOR` part of the version shall be a non-negative integer. This part of the version shall be incremented every time when API, ABI, or behavior of the plugin is changed.
51 |
52 |
53 | ### Patch version
54 |
55 | `PATCH` part of the version shall be a non-negative integer. This part of the version shall be incremented every time when a new release is made and the API, ABI, and (intended) behavior of the plugin is not changed.
56 |
57 | This is generally meant for bug fix releases.
58 |
59 |
60 | ### Development version
61 |
62 | `DEV` optional part of the version shall be a string that can be used for example to specify the type of and number of the release (`alpha3`, `beta1`, `RC5`, `bugfix-123`, `IntegrationTest-20180102-1` etc.). All characters are allowed.
63 |
64 |
65 | ## [R4] Exported interfaces
66 |
67 | Each plugin shall export at least one interface. A plugin shall make it possible for its users to query if a specific interface is exported by the plugin.
68 |
69 |
70 | ## [R5] Plugin dependencies
71 |
72 | A plugin shall optionally have dependencies to other plugins. The dependent plugins shall be injected to the plugin before it is started. A dependent plugin shall only be ejected from a plugin when both plugins are stopped.
73 |
74 |
75 | ## [R6] Plugin instance
76 |
77 | A plugin shall enable creation of multiple instances of the same plugin, but only if they have different names!
78 |
79 |
80 | ## [R7] Configuration
81 |
82 | Loading of plugins shall done according to its configuration which shall be stored in *CppConfigFramework* format.
83 |
84 | The configuration shall consist of two parts:
85 |
86 | * Plugin configurations
87 | * Plugin startup priorities
88 |
89 |
90 | ### Plugin configuration
91 |
92 | This part of the configuration shall be used to define which plugins need to be loaded and which instances of these plugins need to be created. It shall contain the following information for each plugin:
93 |
94 | * Plugin file path
95 | * Version requirements
96 | * Comment
97 | * Plugin instances:
98 |
99 | * Plugin instance name
100 | * Configuration
101 | * Comment (optional, it shall not be processed)
102 | * Plugin dependencies
103 |
104 | *Plugin file path* shall point to plugin file (dynamic library). It shall be either an absolute or relative path and it shall be possible to reference environment variables.
105 |
106 | *Version requirements* shall specify either a specific version or a version range of the plugin which needs to be loaded. For more details about versioning see [[R3] Plugin version](#r3-plugin-version).
107 |
108 | *Comment* is optional and it shall not be processed. It can for example be used to explain the purpose of this plugin.
109 |
110 | In case a version range is defined then the following formula shall be used:
111 |
112 | ```
113 | min_version ≤ version < max_version
114 | ```
115 |
116 |
117 | #### Plugin instances
118 |
119 | A plugin shall configure at least one plugin instance to be created.
120 |
121 | *Plugin instance name* shall define the name of the plugin instance. See [[R2] Plugin instance name](#r2-plugin-instance-name).
122 |
123 | *Configuration* shall be optional for a plugin instance and it shall be stored in *CppConfigFramework* format.
124 |
125 | *Comment* is optional and it shall not be processed. It can for example be used to explain the purpose of this plugin instance.
126 |
127 | A plugin instance shall optionally define its dependencies to other plugins. *Plugin instance dependencies* shall contain a list of references (plugin instance names) to another plugin instances.
128 |
129 |
130 | ### Plugin startup priorities
131 |
132 | This is an optional part of the configuration and it shall be used to define the order in which the referenced plugins (by plugin instance names) need to be started.
133 |
134 | All unreferenced plugins shall be started after these plugins in no particular order.
135 |
136 |
137 | ## [R8] Plugin Startup
138 |
139 | The following startup procedure shall be implemented:
140 |
141 | 1. To be able to start the plugins they shall first have to be loaded
142 | 2. For each plugin all of their plugin instances shall be created and configured
143 | 3. Only when all the plugin instances are created it shall be possible to inject the configured dependencies into the plugin instances
144 | 4. At this point the plugins can all be started in the configured startup order
145 | 5. The application shall now be able to use the plugins
146 |
147 |
148 | ## [R9] Plugin Shutdown
149 |
150 | The following shutdown procedure shall be implemented:
151 |
152 | 1. Plugin instances shall be stopped in the reverse order as they were started
153 | 2. All dependencies shall be ejected
154 | 3. All plugin instances shall be destroyed
155 |
--------------------------------------------------------------------------------