Manual for OpenFLUID 2.1.10

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