Documentation for OpenFLUID 2.2.0
WarePluginsManager.hpp
Go to the documentation of this file.
1 /*
2 
3  This file is part of OpenFLUID software
4  Copyright(c) 2007, INRA - Montpellier SupAgro
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 
56 #include <openfluid/dllexport.hpp>
57 #include <openfluid/config.hpp>
58 
59 
60 namespace openfluid { namespace machine {
61 
62 
63 typedef std::string* (*GetWareABIVersionProc)();
64 
65 typedef 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 */
79 template<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  */
262  {
264  }
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  }
377  {
378  throw E;
379  }
380  }
381 
382  return Containers;
383  }
384 
385 
386  // =====================================================================
387  // =====================================================================
388 
389 
390  /**
391  Loads only the body of a ware if the signature is already loaded
392  @param[in] Container The ware container which already includes the signature
393  @return the instanciated body of the ware
394  */
395  BodyType* getWareBody(const WareContainer<SignatureType>& Container)
396  {
397  std::string PluginFullPath = Container.getPath();
398 
399  std::unique_ptr<DynamicLib>& PlugLib = loadPluginLibrary(PluginFullPath);
400 
401  if (PlugLib)
402  {
403  if (PlugLib->isLoaded() || PlugLib->load())
404  {
405  BodyProc BProc = PlugLib->template getSymbol<BodyProc>(WAREBODY_PROC_NAME);
406 
407  // checks if the handle proc exists
408  if (BProc)
409  {
410  BodyType* Body = BProc();
411  return Body;
412  }
413  else
414  {
415  throw openfluid::base::FrameworkException(OPENFLUID_CODE_LOCATION,
416  "format error in plugin file " + PluginFullPath);
417  }
418  }
419  else
420  {
421  throw openfluid::base::FrameworkException(OPENFLUID_CODE_LOCATION,
422  "unable to load plugin file " + PluginFullPath);
423  }
424  }
425  else
426  {
427  throw openfluid::base::FrameworkException(OPENFLUID_CODE_LOCATION,
428  "unable to find plugin file " + PluginFullPath);
429  }
430  }
431 
432 
433  // =====================================================================
434  // =====================================================================
435 
436 
437  /**
438  Unloads all already loaded plugins and clears the cache
439  */
440  void unloadAll()
441  {
442  for (const auto& PlugLib : m_LoadedPluginsLibraries)
443  {
444  PlugLib.second->unload();
445  }
446 
447  m_LoadedPluginsLibraries.clear();
448  }
449 
450 };
451 
452 
453 } } //namespaces
454 
455 
456 #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
BodyType * getWareBody(const WareContainer< SignatureType > &Container)
Definition: WarePluginsManager.hpp:395
virtual std::string getPluginFullPath(const std::string &Filename) const =0
WarePluginsManager()
Definition: WarePluginsManager.hpp:261
WareContainer< SignatureType > loadPlugin(const std::string &ID)
Definition: WarePluginsManager.hpp:320
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
std::vector< WareContainer< SignatureType > > loadPlugins(const std::string &IDPattern="")
Definition: WarePluginsManager.hpp:343
void unloadAll()
Definition: WarePluginsManager.hpp:440
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 *(* GetWareABIVersionProc)()
Definition: WarePluginsManager.hpp:63
std::string *(* GetWareLinkUIDProc)()
Definition: WarePluginsManager.hpp:65
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)
FilesystemPath Path
Definition: FilesystemPath.hpp:308
std::string WareID_t
Definition: TypeDefs.hpp:49
Definition: ApplicationException.hpp:47