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 
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 ware
74  @tparam SignatureType class defining the container for ware signature only
75  @tparam ItemType class defining the container for ware signature and body
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 ItemType, typename SignatureProc, typename BodyProc>
81 {
82  private:
83 
84  QLibrary* loadPluginLibrary(const std::string& FullFilePath)
85  {
86  std::string PluginFileName = QFileInfo(QString::fromStdString(FullFilePath)).fileName().toStdString();
87 
88  if (m_LoadedPluginsLibraries.find(PluginFileName) == m_LoadedPluginsLibraries.end())
89  {
90  m_LoadedPluginsLibraries[PluginFileName] = std::make_unique<QLibrary>(QString::fromStdString(FullFilePath));
91  }
92 
93  return m_LoadedPluginsLibraries[PluginFileName].get();
94  }
95 
96 
97  // =====================================================================
98  // =====================================================================
99 
100 
101  ItemType* buildWareContainerWithSignatureOnly(const std::string& ID)
102  {
103  std::string PluginFilename = ID+getPluginFilenameSuffix()+openfluid::config::PLUGINS_EXT;
104  std::string PluginFullPath = getPluginFullPath(PluginFilename);
105  ItemType* WareItem = nullptr;
106 
107  QLibrary* PlugLib = loadPluginLibrary(PluginFullPath);
108 
109  // library loading
110  if (PlugLib && PlugLib->load())
111  {
112  WareItem = new ItemType();
113  WareItem->FileFullPath = PluginFullPath;
114 
115  GetWareABIVersionProc ABIVersionProc = (GetWareABIVersionProc)PlugLib->resolve(WAREABIVERSION_PROC_NAME);
116 
117  if (ABIVersionProc)
118  {
119  WareItem->Verified =
120  (openfluid::tools::compareVersions(openfluid::config::VERSION_FULL,ABIVersionProc(),false) == 0);
121  }
122  else
123  {
124  WareItem->Verified = false;
125  }
126 
127 
128  if (WareItem->Verified)
129  {
130  BodyProc BProc = (BodyProc)PlugLib->resolve(WAREBODY_PROC_NAME);
131  SignatureProc SProc = (SignatureProc)PlugLib->resolve(WARESIGNATURE_PROC_NAME);
132 
133  // checks if the handle procs exist
134  if (SProc && BProc)
135  {
136  WareItem->Signature = SProc();
137 
138  if (WareItem->Signature == nullptr)
139  throw openfluid::base::FrameworkException(OPENFLUID_CODE_LOCATION,
140  "Signature from plugin file " + PluginFilename +
141  " cannot be instanciated");
142 
143  WareItem->Verified = (WareItem->Signature->ID == ID);
144 
145  WareItem->Body = 0;
146 
147  GetWareLinkUIDProc LinkUIDProc = (GetWareLinkUIDProc)PlugLib->resolve(WARELINKUID_PROC_NAME);
148 
149  if (LinkUIDProc)
150  WareItem->LinkUID = LinkUIDProc();
151  }
152  else
153  {
154  throw openfluid::base::FrameworkException(OPENFLUID_CODE_LOCATION,
155  "Format error in plugin file " + PluginFilename);
156  }
157  }
158  else
159  {
160  throw openfluid::base::FrameworkException(OPENFLUID_CODE_LOCATION,
161  "Compatibility version mismatch for plugin file " + PluginFilename);
162  }
163  }
164  else
165  {
166  throw openfluid::base::FrameworkException(OPENFLUID_CODE_LOCATION,
167  "Unable to load plugin from file " + PluginFilename);
168  }
169 
170  return WareItem;
171  }
172 
173 
174  // =====================================================================
175  // =====================================================================
176 
177 
178  SignatureType* getWareSignature(const std::string& PluginFilename)
179  {
180  std::string PluginFullPath = getPluginFullPath(PluginFilename);
181  SignatureType* Sign = nullptr;
182 
185  .addInfos({{"pluginfullpath",PluginFullPath},{"pluginfilename",PluginFilename}});
186 
187  // library loading
188  QLibrary* PlugLib = loadPluginLibrary(PluginFullPath);
189 
190 
191  if (PlugLib)
192  {
193  if (PlugLib->load())
194  {
195  Sign = new SignatureType();
196  Sign->FileFullPath = PluginFullPath;
197 
198  GetWareABIVersionProc ABIVersionProc = (GetWareABIVersionProc)PlugLib->resolve(WAREABIVERSION_PROC_NAME);
199 
200  if (ABIVersionProc)
201  {
202  Sign->Verified =
203  (openfluid::tools::compareVersions(openfluid::config::VERSION_FULL,ABIVersionProc(),false) == 0);
204  }
205  else
206  {
207  Sign->Verified = false;
208  }
209 
210  if (Sign->Verified)
211  {
212  BodyProc BProc = (BodyProc)PlugLib->resolve(WAREBODY_PROC_NAME);
213  SignatureProc SProc = (SignatureProc)PlugLib->resolve(WARESIGNATURE_PROC_NAME);
214 
215  // checks if the handle procs exist
216  if (SProc && BProc)
217  {
218  try
219  {
220  Sign->Signature = SProc();
221  }
223  {
225  }
226 
227  if (Sign->Signature == nullptr)
228  {
229  throw openfluid::base::FrameworkException(ECtxt,"Signature cannot be instanciated from plugin file");
230  }
231 
232  Sign->Verified =
233  QString::fromStdString(PluginFilename).startsWith(QString::fromStdString(Sign->Signature->ID));
234 
235  GetWareLinkUIDProc LinkUIDProc = (GetWareLinkUIDProc)PlugLib->resolve(WARELINKUID_PROC_NAME);
236 
237  if (LinkUIDProc)
238  Sign->LinkUID = LinkUIDProc();
239  }
240  else
241  {
242  throw openfluid::base::FrameworkException(ECtxt,"Format error in plugin file");
243  }
244  }
245  }
246  else
247  {
248  throw openfluid::base::FrameworkException(ECtxt,PlugLib->errorString().toStdString());
249  }
250  }
251  else
252  {
253  throw openfluid::base::FrameworkException(ECtxt,"Unable to find plugin file");
254  }
255 
256  return Sign;
257  }
258 
259 
260  // =====================================================================
261  // =====================================================================
262 
263 
264  protected:
265 
266  std::map<std::string,std::unique_ptr<QLibrary>> m_LoadedPluginsLibraries;
267 
268 
270  {
272  }
273 
274 
275  // =====================================================================
276  // =====================================================================
277 
278 
279  public:
280 
282  {
283  public:
284 
285  std::vector<SignatureType*> AvailablePlugins;
286 
287  std::map<std::string,std::string> ErroredFiles;
288  };
289 
290 
292  {
293 
294  }
295 
296 
297  // =====================================================================
298  // =====================================================================
299 
300 
301  virtual std::string getPluginFullPath(const std::string& Filename) const = 0;
302 
303 
304  // =====================================================================
305  // =====================================================================
306 
307 
308  virtual std::vector<std::string> getPluginsSearchPaths() const = 0;
309 
310 
311  // =====================================================================
312  // =====================================================================
313 
314 
315  virtual std::string getPluginFilenameSuffix() const = 0;
316 
317 
318  // =====================================================================
319  // =====================================================================
320 
321 
322  /**
323  Lists available wares
324  */
325  PluginsSearchResults getAvailableWaresSignatures(const std::string& Pattern = "")
326  {
327  PluginsSearchResults SearchResults;
328  std::vector<std::string> PluginsPaths = getPluginsSearchPaths();
329  std::vector<std::string> PluginFiles;
330  std::vector<std::string> TmpFiles;
331  unsigned int i,j;
332 
333 
334  for (i=0;i<PluginsPaths.size();i++)
335  {
336  TmpFiles = openfluid::tools::findFilesBySuffixAndExtension(PluginsPaths[i],
337  getPluginFilenameSuffix(),
338  openfluid::config::PLUGINS_EXT,false,true);
339 
340  for (j=0;j<TmpFiles.size();j++)
341  PluginFiles.push_back(TmpFiles[j]);
342  }
343 
344 
345  SignatureType* CurrentPlug = nullptr;
346 
347  for (i=0;i<PluginFiles.size();i++)
348  {
349  try
350  {
351  CurrentPlug = getWareSignature(PluginFiles[i]);
352 
353  if (CurrentPlug && CurrentPlug->Verified)
354  {
355  if (Pattern.empty())
356  {
357  SearchResults.AvailablePlugins.push_back(CurrentPlug);
358  }
359  else if (openfluid::tools::matchWithWildcard(Pattern,CurrentPlug->Signature->ID))
360  {
361  SearchResults.AvailablePlugins.push_back(CurrentPlug);
362  }
363  }
364  }
366  {
367  SearchResults.ErroredFiles[E.getContext().at("pluginfullpath")] = E.getMessage();
368  }
369  }
370 
371  return SearchResults;
372  }
373 
374 
375  // =====================================================================
376  // =====================================================================
377 
378 
379  ItemType* loadWareSignatureOnly(const std::string& ID)
380  {
381  ItemType* WareItem = buildWareContainerWithSignatureOnly(ID);
382 
383  if (WareItem != nullptr && WareItem->Verified)
384  {
385  return WareItem;
386  }
387 
388  return nullptr;
389  }
390 
391 
392  // =====================================================================
393  // =====================================================================
394 
395 
396  void completeSignatureWithWareBody(ItemType* WareItem)
397  {
398  std::string PluginFullPath = WareItem->FileFullPath;
399 
400  QLibrary* PlugLib = loadPluginLibrary(PluginFullPath);
401 
402  // library loading
403  if (PlugLib && PlugLib->load())
404  {
405  BodyProc BProc = (BodyProc)PlugLib->resolve(WAREBODY_PROC_NAME);
406 
407  // checks if the handle proc exists
408  if (BProc)
409  {
410  WareItem->Body.reset(BProc());
411 
412  if (WareItem->Body == nullptr)
413  {
414  throw openfluid::base::FrameworkException(OPENFLUID_CODE_LOCATION,
415  "Ware from plugin file " + PluginFullPath +
416  " cannot be instanciated");
417  }
418 
419  }
420  else
421  {
422  throw openfluid::base::FrameworkException(OPENFLUID_CODE_LOCATION,
423  "Format error in plugin file " + PluginFullPath);
424  }
425  }
426  else
427  {
428  throw openfluid::base::FrameworkException(OPENFLUID_CODE_LOCATION,
429  "Unable to find plugin file " + PluginFullPath);
430  }
431  }
432 
433 
434  // =====================================================================
435  // =====================================================================
436 
437 
439  {
440  for (auto it=m_LoadedPluginsLibraries.begin();it != m_LoadedPluginsLibraries.end(); ++it)
441  {
442  it->second.get()->unload();
443  }
444 
445  m_LoadedPluginsLibraries.clear();
446  }
447 
448 };
449 
450 
451 } } //namespaces
452 
453 
454 #endif /* __OPENFLUID_MACHINE_WAREPLUGINSMANAGER_HPP__ */
std::string(* GetWareABIVersionProc)()
Definition: WarePluginsManager.hpp:63
std::vector< SignatureType * > AvailablePlugins
Definition: WarePluginsManager.hpp:285
Definition: WarePluginsManager.hpp:80
void completeSignatureWithWareBody(ItemType *WareItem)
Definition: WarePluginsManager.hpp:396
std::map< std::string, std::string > ErroredFiles
Definition: WarePluginsManager.hpp:287
#define WAREBODY_PROC_NAME
Definition: PluggableWare.hpp:56
#define WARESIGNATURE_PROC_NAME
Definition: PluggableWare.hpp:62
const ExceptionContext getContext() const
Definition: Exception.hpp:121
#define WARELINKUID_PROC_NAME
Definition: PluggableWare.hpp:75
int OPENFLUID_API compareVersions(const std::string &VersionA, const std::string &VersionB, bool Strict=true)
Definition: ExceptionContext.hpp:53
std::string(* GetWareLinkUIDProc)()
Definition: WarePluginsManager.hpp:65
static ExceptionContext computeContext()
Definition: FrameworkException.hpp:101
ItemType * loadWareSignatureOnly(const std::string &ID)
Definition: WarePluginsManager.hpp:379
const std::string getMessage() const
Definition: Exception.hpp:101
Definition: FrameworkException.hpp:50
Definition: ApplicationException.hpp:47
PluginsSearchResults getAvailableWaresSignatures(const std::string &Pattern="")
Definition: WarePluginsManager.hpp:325
void unloadAllWares()
Definition: WarePluginsManager.hpp:438
#define WAREABIVERSION_PROC_NAME
Definition: PluggableWare.hpp:68
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)
ExceptionContext & addInfos(const std::map< std::string, std::string > &Infos)
Definition: ExceptionContext.hpp:70
std::map< std::string, std::unique_ptr< QLibrary > > m_LoadedPluginsLibraries
Definition: WarePluginsManager.hpp:266
#define OPENFLUID_API
Definition: dllexport.hpp:86
WarePluginsManager()
Definition: WarePluginsManager.hpp:269
virtual ~WarePluginsManager()
Definition: WarePluginsManager.hpp:291
bool OPENFLUID_API matchWithWildcard(const std::string &Pattern, const std::string &Str)