Manual for OpenFLUID 2.1.11

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 
50 #include <QLibrary>
51 #include <QFileInfo>
52 
57 #include <openfluid/dllexport.hpp>
58 #include <openfluid/config.hpp>
59 
60 
61 namespace openfluid { namespace machine {
62 
63 
64 typedef std::string* (*GetWareABIVersionProc)();
65 
66 typedef std::string* (*GetWareLinkUIDProc)();
67 
68 
69 // =====================================================================
70 // =====================================================================
71 
72 
73 /**
74  Management class for pluggable wares
75  @tparam SignatureInstanceType class defining the container for ware signature only
76  @tparam ItemInstanceType class defining the container for ware signature and body
77  @tparam SignatureProc procedure definition for instantiation of the signature
78  @tparam BodyProc procedure definition for instantiation of the body
79 */
80 template<class SignatureInstanceType, class ItemInstanceType, typename SignatureProc, typename BodyProc>
82 {
83  private:
84 
85  /**
86  Loads the plugin of a ware from the given file path.
87  The plugin is automatically cached to avoid multiple loadings.
88  @param[in] FullFilePath The path to the plugin file to load
89  @return a QLibrary pointer to the loaded or cached ware
90  */
91  QLibrary* loadPluginLibrary(const std::string& FullFilePath)
92  {
93  std::string PluginFileName = QFileInfo(QString::fromStdString(FullFilePath)).fileName().toStdString();
94 
95  if (m_LoadedPluginsLibraries.find(PluginFileName) == m_LoadedPluginsLibraries.end())
96  {
97  m_LoadedPluginsLibraries[PluginFileName] = std::make_unique<QLibrary>(QString::fromStdString(FullFilePath));
98  }
99 
100  return m_LoadedPluginsLibraries[PluginFileName].get();
101  }
102 
103 
104  // =====================================================================
105  // =====================================================================
106 
107 
108  ItemInstanceType* buildWareContainerWithSignatureOnly(const std::string& ID, bool StrictABICheck = true)
109  {
110  std::string PluginFilename = ID+getPluginFilenameSuffix()+openfluid::config::PLUGINS_EXT;
111  std::string PluginFullPath = getPluginFullPath(PluginFilename);
112  ItemInstanceType* WareItem = nullptr;
113 
114  QLibrary* PlugLib = loadPluginLibrary(PluginFullPath);
115 
116  // library loading
117  if (PlugLib && PlugLib->load())
118  {
119  WareItem = new ItemInstanceType();
120  WareItem->FileFullPath = PluginFullPath;
121 
122  GetWareABIVersionProc ABIVersionProc = (GetWareABIVersionProc)PlugLib->resolve(WAREABIVERSION_PROC_NAME);
123 
124  if (ABIVersionProc)
125  {
126  std::unique_ptr<std::string> StrPtr(ABIVersionProc());
127  WareItem->Verified =
128  (openfluid::tools::compareVersions(openfluid::config::VERSION_FULL,*StrPtr,StrictABICheck) == 0);
129  }
130  else
131  {
132  WareItem->Verified = false;
133  }
134 
135 
136  if (WareItem->Verified)
137  {
138  BodyProc BProc = (BodyProc)PlugLib->resolve(WAREBODY_PROC_NAME);
139  SignatureProc SProc = (SignatureProc)PlugLib->resolve(WARESIGNATURE_PROC_NAME);
140 
141  // checks if the handle procs exist
142  if (SProc && BProc)
143  {
144  WareItem->Signature = SProc();
145 
146  if (WareItem->Signature == nullptr)
147  {
148  throw openfluid::base::FrameworkException(OPENFLUID_CODE_LOCATION,
149  "Signature from plugin file " + PluginFilename +
150  " cannot be instanciated");
151  }
152 
153  WareItem->Verified = (WareItem->Signature->ID == ID);
154 
155  WareItem->Body = 0;
156 
157  GetWareLinkUIDProc LinkUIDProc = (GetWareLinkUIDProc)PlugLib->resolve(WARELINKUID_PROC_NAME);
158 
159  if (LinkUIDProc)
160  {
161  std::unique_ptr<std::string> StrPtr(LinkUIDProc());
162  WareItem->LinkUID = *StrPtr;
163  }
164  }
165  else
166  {
167  throw openfluid::base::FrameworkException(OPENFLUID_CODE_LOCATION,
168  "Format error in plugin file " + PluginFilename);
169  }
170  }
171  else
172  {
173  throw openfluid::base::FrameworkException(OPENFLUID_CODE_LOCATION,
174  "Compatibility version mismatch for plugin file " + PluginFilename);
175  }
176  }
177  else
178  {
179  throw openfluid::base::FrameworkException(OPENFLUID_CODE_LOCATION,
180  "Unable to load plugin from file " + PluginFilename);
181  }
182 
183  return WareItem;
184  }
185 
186 
187  // =====================================================================
188  // =====================================================================
189 
190 
191  SignatureInstanceType* getWareSignature(const std::string& PluginFilename, bool StrictABICheck = true)
192  {
193  std::string PluginFullPath = getPluginFullPath(PluginFilename);
194  SignatureInstanceType* Sign = nullptr;
195 
198  .addInfos({{"pluginfullpath",PluginFullPath},{"pluginfilename",PluginFilename}});
199 
200  // library loading
201  QLibrary* PlugLib = loadPluginLibrary(PluginFullPath);
202 
203 
204  if (PlugLib)
205  {
206  if (PlugLib->load())
207  {
208  Sign = new SignatureInstanceType();
209  Sign->FileFullPath = PluginFullPath;
210 
211  GetWareABIVersionProc ABIVersionProc = (GetWareABIVersionProc)PlugLib->resolve(WAREABIVERSION_PROC_NAME);
212 
213  if (ABIVersionProc)
214  {
215  std::unique_ptr<std::string> StrPtr(ABIVersionProc());
216  Sign->Verified =
217  (openfluid::tools::compareVersions(openfluid::config::VERSION_FULL,*StrPtr,StrictABICheck) == 0);
218  }
219  else
220  {
221  Sign->Verified = false;
222  }
223 
224  if (Sign->Verified)
225  {
226  BodyProc BProc = (BodyProc)PlugLib->resolve(WAREBODY_PROC_NAME);
227  SignatureProc SProc = (SignatureProc)PlugLib->resolve(WARESIGNATURE_PROC_NAME);
228 
229  // checks if the handle procs exist
230  if (SProc && BProc)
231  {
232  try
233  {
234  Sign->Signature = SProc();
235  }
237  {
239  }
240 
241  if (Sign->Signature == nullptr)
242  {
243  throw openfluid::base::FrameworkException(ECtxt,"Signature cannot be instanciated from plugin file");
244  }
245 
246  Sign->Verified =
247  QString::fromStdString(PluginFilename).startsWith(QString::fromStdString(Sign->Signature->ID));
248 
249  GetWareLinkUIDProc LinkUIDProc = (GetWareLinkUIDProc)PlugLib->resolve(WARELINKUID_PROC_NAME);
250 
251  if (LinkUIDProc)
252  {
253  std::unique_ptr<std::string> StrPtr(LinkUIDProc());
254  Sign->LinkUID = *StrPtr;
255  }
256  }
257  else
258  {
259  throw openfluid::base::FrameworkException(ECtxt,"Format error in plugin file");
260  }
261  }
262  }
263  else
264  {
265  throw openfluid::base::FrameworkException(ECtxt,PlugLib->errorString().toStdString());
266  }
267  }
268  else
269  {
270  throw openfluid::base::FrameworkException(ECtxt,"Unable to find plugin file");
271  }
272 
273  return Sign;
274  }
275 
276 
277  // =====================================================================
278  // =====================================================================
279 
280 
281  protected:
282 
283  std::map<std::string,std::unique_ptr<QLibrary>> m_LoadedPluginsLibraries;
284 
285  /**
286  Default constructor
287  */
289  {
291  }
292 
293 
294  // =====================================================================
295  // =====================================================================
296 
297 
298  public:
299 
301 
303  {
304 
305  }
306 
307 
308  // =====================================================================
309  // =====================================================================
310 
311 
312  /**
313  Returns the full path of the plugin from its filename
314  @param[in] Filename The filename of the plugin
315  @return The full path of the plugin, empty if not found
316  */
317  virtual std::string getPluginFullPath(const std::string& Filename) const = 0;
318 
319 
320  // =====================================================================
321  // =====================================================================
322 
323 
324  /**
325  Returns ordered search paths for plugins
326  @return The search paths
327  */
328  virtual std::vector<std::string> getPluginsSearchPaths() const = 0;
329 
330 
331  // =====================================================================
332  // =====================================================================
333 
334 
335  /**
336  Returns the filename suffix for the plugins
337  @return The filename suffix
338  */
339  virtual std::string getPluginFilenameSuffix() const = 0;
340 
341 
342  // =====================================================================
343  // =====================================================================
344 
345 
346  /**
347  Lists available wares
348  @param[in] Pattern if not empty, the list of available wares is filtered using the given pattern
349  based on wildcard matching
350  @return The list of found wares
351  */
352  PluginsSearchResults getAvailableWaresSignatures(const std::string& Pattern = "")
353  {
354  PluginsSearchResults SearchResults;
355  std::vector<std::string> PluginsPaths = getPluginsSearchPaths();
356  std::vector<std::string> PluginFiles;
357  std::vector<std::string> TmpFiles;
358  unsigned int i,j;
359 
360 
361  for (i=0;i<PluginsPaths.size();i++)
362  {
363  TmpFiles = openfluid::tools::findFilesBySuffixAndExtension(PluginsPaths[i],
364  getPluginFilenameSuffix(),
365  openfluid::config::PLUGINS_EXT,false,true);
366 
367  for (j=0;j<TmpFiles.size();j++)
368  {
369  PluginFiles.push_back(TmpFiles[j]);
370  }
371  }
372 
373 
374  SignatureInstanceType* CurrentPlug = nullptr;
375 
376  for (i=0;i<PluginFiles.size();i++)
377  {
378  try
379  {
380  CurrentPlug = getWareSignature(PluginFiles[i]);
381 
382  if (CurrentPlug && CurrentPlug->Verified)
383  {
384  if (Pattern.empty())
385  {
386  SearchResults.appendAvailable(CurrentPlug);
387  }
388  else if (openfluid::tools::matchWithWildcard(Pattern,CurrentPlug->Signature->ID))
389  {
390  SearchResults.appendAvailable(CurrentPlug);
391  }
392  }
393  }
395  {
396  SearchResults.appendErrored(E.getContext().at("pluginfullpath"),E.getMessage());
397  }
398  }
399 
400  return SearchResults;
401  }
402 
403 
404  // =====================================================================
405  // =====================================================================
406 
407 
408  /**
409  Loads only the signature of a ware given by its ID
410  @param[in] ID The ID of the ware to load
411  @return The ware container including the signature
412  */
413  ItemInstanceType* loadWareSignatureOnly(const std::string& ID)
414  {
415  ItemInstanceType* WareItem = buildWareContainerWithSignatureOnly(ID);
416 
417  if (WareItem != nullptr && WareItem->Verified)
418  {
419  return WareItem;
420  }
421 
422  return nullptr;
423  }
424 
425 
426  // =====================================================================
427  // =====================================================================
428 
429 
430  /**
431  Loads only the body of a ware if the signature is already loaded
432  @param[inout] WareItem The ware container to complete which already includes the signature
433  */
434  void completeSignatureWithWareBody(ItemInstanceType* WareItem)
435  {
436  std::string PluginFullPath = WareItem->FileFullPath;
437 
438  QLibrary* PlugLib = loadPluginLibrary(PluginFullPath);
439 
440  // library loading
441  if (PlugLib && PlugLib->load())
442  {
443  BodyProc BProc = (BodyProc)PlugLib->resolve(WAREBODY_PROC_NAME);
444 
445  // checks if the handle proc exists
446  if (BProc)
447  {
448  WareItem->Body.reset(BProc());
449 
450  if (WareItem->Body == nullptr)
451  {
452  throw openfluid::base::FrameworkException(OPENFLUID_CODE_LOCATION,
453  "Ware from plugin file " + PluginFullPath +
454  " cannot be instanciated");
455  }
456 
457  }
458  else
459  {
460  throw openfluid::base::FrameworkException(OPENFLUID_CODE_LOCATION,
461  "Format error in plugin file " + PluginFullPath);
462  }
463  }
464  else
465  {
466  throw openfluid::base::FrameworkException(OPENFLUID_CODE_LOCATION,
467  "Unable to find plugin file " + PluginFullPath);
468  }
469  }
470 
471 
472  // =====================================================================
473  // =====================================================================
474 
475 
476  /**
477  Unloads all already loaded wares and clears the cache
478  */
480  {
481  for (auto it=m_LoadedPluginsLibraries.begin();it != m_LoadedPluginsLibraries.end(); ++it)
482  {
483  it->second.get()->unload();
484  }
485 
486  m_LoadedPluginsLibraries.clear();
487  }
488 
489 };
490 
491 
492 } } //namespaces
493 
494 
495 #endif /* __OPENFLUID_MACHINE_WAREPLUGINSMANAGER_HPP__ */
WARELINKUID_PROC_NAME
#define WARELINKUID_PROC_NAME
Definition: PluggableWare.hpp:75
OPENFLUID_API
#define OPENFLUID_API
Definition: dllexport.hpp:86
WAREABIVERSION_PROC_NAME
#define WAREABIVERSION_PROC_NAME
Definition: PluggableWare.hpp:68
openfluid::machine::WarePluginsManager::loadWareSignatureOnly
ItemInstanceType * loadWareSignatureOnly(const std::string &ID)
Definition: WarePluginsManager.hpp:413
openfluid::machine::WarePluginsManager::~WarePluginsManager
virtual ~WarePluginsManager()
Definition: WarePluginsManager.hpp:302
openfluid::base::FrameworkException::computeContext
static ExceptionContext computeContext()
Definition: FrameworkException.hpp:101
openfluid::tools::compareVersions
int OPENFLUID_API compareVersions(const std::string &VersionA, const std::string &VersionB, bool Strict=true)
openfluid::machine::WarePluginsManager::getAvailableWaresSignatures
PluginsSearchResults getAvailableWaresSignatures(const std::string &Pattern="")
Definition: WarePluginsManager.hpp:352
openfluid::tools::findFilesBySuffixAndExtension
std::vector< std::string > OPENFLUID_API findFilesBySuffixAndExtension(const std::string &Path, const std::string &Suffix, const std::string &Ext, bool WithPath=false, bool ExtIncludeDot=false)
openfluid::machine::WarePluginsSearchResults::appendAvailable
void appendAvailable(SignatureInstanceType *Item)
Definition: WarePluginsSearchResults.hpp:84
openfluid::machine::WarePluginsManager::PluginsSearchResults
WarePluginsSearchResults< SignatureInstanceType > PluginsSearchResults
Definition: WarePluginsManager.hpp:300
openfluid::machine::WarePluginsManager::unloadAllWares
void unloadAllWares()
Definition: WarePluginsManager.hpp:479
WAREBODY_PROC_NAME
#define WAREBODY_PROC_NAME
Definition: PluggableWare.hpp:56
openfluid::machine::GetWareABIVersionProc
std::string *(* GetWareABIVersionProc)()
Definition: WarePluginsManager.hpp:64
openfluid::machine::WarePluginsSearchResults
Definition: WarePluginsSearchResults.hpp:57
openfluid::base::Exception::getMessage
const std::string getMessage() const
Definition: Exception.hpp:101
openfluid::tools::matchWithWildcard
bool OPENFLUID_API matchWithWildcard(const std::string &Pattern, const std::string &Str)
openfluid::machine::WarePluginsManager
Definition: WarePluginsManager.hpp:81
openfluid
Definition: ApplicationException.hpp:47
WARESIGNATURE_PROC_NAME
#define WARESIGNATURE_PROC_NAME
Definition: PluggableWare.hpp:62
openfluid::machine::WarePluginsManager::m_LoadedPluginsLibraries
std::map< std::string, std::unique_ptr< QLibrary > > m_LoadedPluginsLibraries
Definition: WarePluginsManager.hpp:283
openfluid::base::Exception::getContext
const ExceptionContext getContext() const
Definition: Exception.hpp:121
FileHelpers.hpp
PluggableWare.hpp
openfluid::machine::WarePluginsSearchResults::appendErrored
void appendErrored(const std::string &Path, const std::string &Message)
Definition: WarePluginsSearchResults.hpp:95
openfluid::base::ExceptionContext::addInfos
ExceptionContext & addInfos(const std::map< std::string, std::string > &Infos)
Definition: ExceptionContext.hpp:70
openfluid::machine::WarePluginsManager::WarePluginsManager
WarePluginsManager()
Definition: WarePluginsManager.hpp:288
openfluid::base::FrameworkException
Definition: FrameworkException.hpp:50
WarePluginsSearchResults.hpp
dllexport.hpp
openfluid::machine::GetWareLinkUIDProc
std::string *(* GetWareLinkUIDProc)()
Definition: WarePluginsManager.hpp:66
openfluid::base::Environment::init
static void init()
Environment.hpp
openfluid::base::ExceptionContext
Definition: ExceptionContext.hpp:53
openfluid::machine::WarePluginsManager::completeSignatureWithWareBody
void completeSignatureWithWareBody(ItemInstanceType *WareItem)
Definition: WarePluginsManager.hpp:434