Documentation for OpenFLUID 2.2.2
Loading...
Searching...
No Matches
WarePluginsManager.hpp
Go to the documentation of this file.
1/*
2
3 This file is part of OpenFLUID software
4 Copyright(c) 2021-2026, INRAE
5
6
7 == GNU General Public License Usage ==
8
9 OpenFLUID is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14 OpenFLUID is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with OpenFLUID. If not, see <http://www.gnu.org/licenses/>.
21
22
23 == Other Usage ==
24
25 Other Usage means a use of OpenFLUID that is inconsistent with the GPL
26 license, and requires a written agreement between You and INRA.
27 Licensees for Other Usage of OpenFLUID may use this file in accordance
28 with the terms contained in the written agreement between You and INRA.
29
30*/
31
32
33/**
34 @file WarePluginsManager.hpp
35
36 @author Jean-Christophe FABRE <jean-christophe.fabre@inra.fr>
37 */
38
39
40#ifndef __OPENFLUID_MACHINE_WAREPLUGINSMANAGER_HPP__
41#define __OPENFLUID_MACHINE_WAREPLUGINSMANAGER_HPP__
42
43
44#include <vector>
45#include <map>
46#include <set>
47#include <string>
48#include <memory>
49
57#include <openfluid/config.hpp>
58
59
60namespace openfluid { namespace machine {
61
62
63typedef std::string* (*GetWareABIVersionProc)();
64
65typedef std::string* (*GetWareLinkUIDProc)();
66
67
68// =====================================================================
69// =====================================================================
70
71
72/**
73 Management class for pluggable wares
74 @tparam SignatureType class defining the signature type for the ware category
75 @tparam BodyType class defining the body type for the ware category
76 @tparam SignatureProc procedure definition for instantiation of the signature
77 @tparam BodyProc procedure definition for instantiation of the body
78*/
79template<class SignatureType, class BodyType, typename SignatureProc, typename BodyProc>
81{
82 private:
83
84 /**
85 Loads the plugin of a ware from the given file path.
86 The plugin is automatically cached to avoid multiple loadings.
87 @param[in] FullFilePath The path to the plugin file to load
88 @return a DynamicLib pointer to the loaded or cached ware
89 */
90 std::unique_ptr<DynamicLib>& loadPluginLibrary(const std::string& FullFilePath)
91 {
92 std::string PluginFileName = openfluid::tools::FilesystemPath(FullFilePath).filename();
93
94 if (m_LoadedPluginsLibraries.find(PluginFileName) == m_LoadedPluginsLibraries.end())
95 {
96 m_LoadedPluginsLibraries[PluginFileName] = std::make_unique<DynamicLib>(FullFilePath);
97 }
98
99 return m_LoadedPluginsLibraries[PluginFileName];
100 }
101
102
103 // =====================================================================
104 // =====================================================================
105
106
107 std::string buildPluginFilename(const openfluid::ware::WareID_t& ID) const
108 {
109 return (ID+getPluginFilenameSuffix()+openfluid::config::PLUGINS_EXT);
110 }
111
112
113 // =====================================================================
114 // =====================================================================
115
116
117 /**
118 Returns a container for the first plugin found with the given filename
119 according to current ware type and search paths
120 @param[in] Filename The plugin filename (only filename, no path)
121 @param[in] StrictABICheck If true, strict checking of ABI version of the plugins is enabled (default).
122 Performs loose checking if false.
123 @return A container corresponding to the found plugin. Container is marked as not valid if no plugin found
124 */
125 WareContainer<SignatureType> buildWareContainerFromFilename(const std::string& Filename,bool StrictABICheck = true)
126 {
127 WareContainer<SignatureType> Container = createContainer();
128 std::string PluginFullPath = getPluginFullPath(Filename);
129
130 if (!PluginFullPath.empty())
131 {
132 auto& PlugLib = loadPluginLibrary(PluginFullPath);
133
134 if (PlugLib)
135 {
136 Container.setPath(PluginFullPath);
137
138 if (PlugLib->isLoaded() || PlugLib->load())
139 {
140 GetWareABIVersionProc ABIVersionProc =
141 PlugLib->template getSymbol<GetWareABIVersionProc>(WAREABIVERSION_PROC_NAME);
142
143 bool Verified = false;
144 if (ABIVersionProc)
145 {
146 std::unique_ptr<std::string> ABIPtr(ABIVersionProc());
147 Verified =
148 (openfluid::tools::compareOpenFLUIDVersions(openfluid::config::VERSION_FULL,*ABIPtr,
149 StrictABICheck) == 0);
150 }
151
152 if (Verified)
153 {
154 bool hasBodyProc = PlugLib->hasSymbol(WAREBODY_PROC_NAME);
155 SignatureProc SProc = PlugLib->template getSymbol<SignatureProc>(WARESIGNATURE_PROC_NAME);
156
157 // checks if the handle procs exist
158 if (SProc && hasBodyProc)
159 {
160 auto SignPtr = SProc();
161
162 if (SignPtr)
163 {
164 Verified = (Filename == buildPluginFilename(SignPtr->ID));
165
166 if (Verified)
167 {
168 Container.setSignature(SignPtr);
169
170 GetWareLinkUIDProc LinkUIDProc =
171 PlugLib->template getSymbol<GetWareLinkUIDProc>(WARELINKUID_PROC_NAME);
172
173 if (LinkUIDProc)
174 {
175 std::unique_ptr<std::string> StrPtr(LinkUIDProc());
176 Container.setLinkUID(*StrPtr);
177 }
178 }
179 else
180 {
181 Container.setMessage("ID mismatch in signature");
182 }
183 }
184 else
185 {
186 Container.setMessage("signature cannot be instanciated");
187 }
188 }
189 else
190 {
191 Container.setMessage("plugin format error");
192 }
193 }
194 else
195 {
196 Container.setMessage("plugin ABI version mismatch");
197 }
198 }
199 else
200 {
201 Container.setMessage(PlugLib->getLatestErrorMsg());
202 }
203
204 Container.validate();
205 }
206 else
207 {
208 throw openfluid::base::FrameworkException(OPENFLUID_CODE_LOCATION,
209 "unable to find plugin file " + Filename);
210 }
211 }
212 else
213 {
214 throw openfluid::base::FrameworkException(OPENFLUID_CODE_LOCATION,
215 "empty path for plugin file " + Filename);
216 }
217
218 return Container;
219 }
220
221
222 // =====================================================================
223 // =====================================================================
224
225
226 /**
227 Returns a container for the first plugin found with the given ID according to current ware type and search paths
228 @param[in] ID The plugin ID
229 @param[in] StrictABICheck If true, strict checking of ABI version of the plugins is enabled (default).
230 Performs loose checking if false.
231 @return A container corresponding to the found plugin. Container is marked as not valid if no plugin found
232 */
233 WareContainer<SignatureType> buildWareContainerFromID(const std::string& ID, bool StrictABICheck = true)
234 {
235 return buildWareContainerFromFilename(buildPluginFilename(ID),StrictABICheck);
236 }
237
238
239 // =====================================================================
240 // =====================================================================
241
242
243 /**
244 Returns an empty built container
245 @return The container
246 */
247 virtual WareContainer<SignatureType> createContainer() const = 0;
248
249
250 // =====================================================================
251 // =====================================================================
252
253
254 protected:
255
256 std::map<std::string,std::unique_ptr<DynamicLib>> m_LoadedPluginsLibraries;
257
258 /**
259 Default constructor
260 */
265
266
267 // =====================================================================
268 // =====================================================================
269
270
271 public:
272
274 { }
275
276
277 // =====================================================================
278 // =====================================================================
279
280
281 /**
282 Returns the full path of the plugin from its filename
283 @param[in] Filename The filename of the plugin
284 @return The full path of the plugin, empty if not found
285 */
286 virtual std::string getPluginFullPath(const std::string& Filename) const = 0;
287
288
289 // =====================================================================
290 // =====================================================================
291
292
293 /**
294 Returns ordered search paths for plugins
295 @return The search paths
296 */
297 virtual std::vector<std::string> getPluginsSearchPaths() const = 0;
298
299
300 // =====================================================================
301 // =====================================================================
302
303
304 /**
305 Returns the filename suffix for the plugins
306 @return The filename suffix
307 */
308 virtual std::string getPluginFilenameSuffix() const = 0;
309
310
311 // =====================================================================
312 // =====================================================================
313
314
315 /**
316 Loads only the signature of a ware given by its ID
317 @param[in] ID The ID of the ware to load
318 @return The ware container including the signature
319 */
321 {
322 try
323 {
324 return buildWareContainerFromID(ID);
325 }
327 {
328 return createContainer();
329 }
330 }
331
332
333 // =====================================================================
334 // =====================================================================
335
336
337 /**
338 Lists available wares
339 @param[in] IDPattern if not empty, the list of available wares is filtered using the given pattern
340 based on wildcard matching
341 @return The list of found wares
342 */
343 std::vector<WareContainer<SignatureType>> loadPlugins(const std::string& IDPattern = "")
344 {
345 std::vector<WareContainer<SignatureType>> Containers;
346 std::vector<std::string> PluginsPaths = getPluginsSearchPaths();
347 std::vector<std::string> PluginFiles;
348 std::vector<std::string> TmpFiles;
349
350 for (const auto& Path: PluginsPaths)
351 {
353 getPluginFilenameSuffix(),
354 openfluid::config::PLUGINS_EXT,
355 false,true);
356
357 for (const auto& File: TmpFiles)
358 {
359 PluginFiles.push_back(File);
360 }
361 }
362
363
364 for (const auto& File: PluginFiles)
365 {
366 try
367 {
368 auto Container = buildWareContainerFromFilename(File);
369
370 if (Container.isValid() &&
371 (IDPattern.empty() || openfluid::tools::matchWithWildcard(IDPattern,Container.signature()->ID)))
372 {
373 Containers.emplace_back(std::move(Container));
374 }
375 else
376 {
377 std::cout << "Invalid container " << Container.signature()->ID << ": " << Container.isValid() << " / " <<
378 IDPattern.empty() << " / " << openfluid::tools::matchWithWildcard(IDPattern,Container.signature()->ID) \
379 << std::endl;
380 }
381 }
383 {
384 throw E;
385 }
386 }
387
388 return Containers;
389 }
390
391
392 // =====================================================================
393 // =====================================================================
394
395
396 /**
397 Loads only the body of a ware if the signature is already loaded
398 @param[in] Container The ware container which already includes the signature
399 @return the instanciated body of the ware
400 */
401 BodyType* getWareBody(const WareContainer<SignatureType>& Container)
402 {
403 std::string PluginFullPath = Container.getPath();
404
405 std::unique_ptr<DynamicLib>& PlugLib = loadPluginLibrary(PluginFullPath);
406
407 if (PlugLib)
408 {
409 if (PlugLib->isLoaded() || PlugLib->load())
410 {
411 BodyProc BProc = PlugLib->template getSymbol<BodyProc>(WAREBODY_PROC_NAME);
412
413 // checks if the handle proc exists
414 if (BProc)
415 {
416 BodyType* Body = BProc();
417 return Body;
418 }
419 else
420 {
421 throw openfluid::base::FrameworkException(OPENFLUID_CODE_LOCATION,
422 "format error in plugin file " + PluginFullPath);
423 }
424 }
425 else
426 {
427 throw openfluid::base::FrameworkException(OPENFLUID_CODE_LOCATION,
428 "unable to load plugin file " + PluginFullPath);
429 }
430 }
431 else
432 {
433 throw openfluid::base::FrameworkException(OPENFLUID_CODE_LOCATION,
434 "unable to find plugin file " + PluginFullPath);
435 }
436 }
437
438
439 // =====================================================================
440 // =====================================================================
441
442
443 /**
444 Unloads all already loaded plugins and clears the cache
445 */
447 {
448 for (const auto& PlugLib : m_LoadedPluginsLibraries)
449 {
450 PlugLib.second->unload();
451 }
452
453 m_LoadedPluginsLibraries.clear();
454 }
455
456};
457
458
459} } //namespaces
460
461
462#endif /* __OPENFLUID_MACHINE_WAREPLUGINSMANAGER_HPP__ */
#define WAREBODY_PROC_NAME
Definition PluggableWare.hpp:56
#define WARELINKUID_PROC_NAME
Definition PluggableWare.hpp:75
#define WARESIGNATURE_PROC_NAME
Definition PluggableWare.hpp:62
#define WAREABIVERSION_PROC_NAME
Definition PluggableWare.hpp:68
Definition FrameworkException.hpp:51
Definition WareContainer.hpp:62
void validate()
Definition WareContainer.hpp:171
std::string getPath() const
Definition WareContainer.hpp:110
void setMessage(const std::string &Message)
Definition WareContainer.hpp:189
void setPath(const std::string &Path)
Definition WareContainer.hpp:120
void setLinkUID(const UUID_t &UID)
Definition WareContainer.hpp:146
void setSignature(SignatureType *Signature)
Definition WareContainer.hpp:217
Definition WarePluginsManager.hpp:81
std::vector< WareContainer< SignatureType > > loadPlugins(const std::string &IDPattern="")
Definition WarePluginsManager.hpp:343
virtual std::string getPluginFullPath(const std::string &Filename) const =0
WarePluginsManager()
Definition WarePluginsManager.hpp:261
virtual std::vector< std::string > getPluginsSearchPaths() const =0
virtual std::string getPluginFilenameSuffix() const =0
std::map< std::string, std::unique_ptr< DynamicLib > > m_LoadedPluginsLibraries
Definition WarePluginsManager.hpp:256
void unloadAll()
Definition WarePluginsManager.hpp:446
BodyType * getWareBody(const WareContainer< SignatureType > &Container)
Definition WarePluginsManager.hpp:401
WareContainer< SignatureType > loadPlugin(const std::string &ID)
Definition WarePluginsManager.hpp:320
virtual ~WarePluginsManager()
Definition WarePluginsManager.hpp:273
Definition FilesystemPath.hpp:62
std::string filename() const
static std::vector< std::string > findFilesBySuffixAndExtension(const std::string &Path, const std::string &Suffix, const std::string &Ext, bool WithPath=false, bool ExtIncludeDot=false)
#define OPENFLUID_API
Definition dllexport.hpp:86
std::string *(* GetWareLinkUIDProc)()
Definition WarePluginsManager.hpp:65
std::string *(* GetWareABIVersionProc)()
Definition WarePluginsManager.hpp:63
bool OPENFLUID_API matchWithWildcard(const std::string &Pattern, const std::string &Str)
int OPENFLUID_API compareOpenFLUIDVersions(const std::string &VersionA, const std::string &VersionB, bool Strict=true)
std::string WareID_t
Definition TypeDefs.hpp:49
Definition ApplicationException.hpp:47