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