changeset 888:d44b845c1c89 plugins

recursive scan for plugins
author Sebastien Jodogne <s.jodogne@gmail.com>
date Sat, 14 Jun 2014 19:47:51 +0200
parents 4066e6f2d134
children d2a393061eb6
files Plugins/Engine/PluginsManager.cpp Plugins/Engine/PluginsManager.h Plugins/OrthancCPlugin/OrthancCPlugin.h Resources/Samples/Plugins/Basic/Plugin.c UnitTestsSources/PluginsTests.cpp
diffstat 5 files changed, 127 insertions(+), 11 deletions(-) [+]
line wrap: on
line diff
--- a/Plugins/Engine/PluginsManager.cpp	Sat Jun 14 19:20:38 2014 +0200
+++ b/Plugins/Engine/PluginsManager.cpp	Sat Jun 14 19:47:51 2014 +0200
@@ -35,6 +35,16 @@
 #include <glog/logging.h>
 #include <cassert>
 #include <memory>
+#include <boost/filesystem.hpp>
+
+#ifdef WIN32
+#define PLUGIN_EXTENSION ".dll"
+#elif defined(__linux)
+#define PLUGIN_EXTENSION ".so"
+#else
+#error Support your platform here
+#endif
+
 
 namespace Orthanc
 {
@@ -79,6 +89,30 @@
   }
 
 
+  static const char* CallGetName(SharedLibrary& plugin)
+  {
+    typedef const char* (*GetName) ();
+
+    GetName getName;
+    *(void **) (&getName) = plugin.GetFunction("OrthancPluginGetName");
+    assert(getName != NULL);
+
+    return getName();
+  }
+
+
+  static const char* CallGetVersion(SharedLibrary& plugin)
+  {
+    typedef const char* (*GetVersion) ();
+
+    GetVersion getVersion;
+    *(void **) (&getVersion) = plugin.GetFunction("OrthancPluginGetVersion");
+    assert(getVersion != NULL);
+
+    return getVersion();
+  }
+
+
   static void LogError(const char* str)
   {
     LOG(ERROR) << str;
@@ -114,32 +148,95 @@
   {
     for (Plugins::iterator it = plugins_.begin(); it != plugins_.end(); it++)
     {
-      if (*it != NULL)
+      if (it->second != NULL)
       {
-        CallFinalize(**it);
-        delete *it;
+        CallFinalize(*(it->second));
+        delete it->second;
       }
     }
   }
 
+
+  static bool IsOrthancPlugin(SharedLibrary& library)
+  {
+    return (library.HasFunction("OrthancPluginInitialize") &&
+            library.HasFunction("OrthancPluginFinalize") &&
+            library.HasFunction("OrthancPluginGetName") &&
+            library.HasFunction("OrthancPluginGetVersion"));
+  }
+
   
   void PluginsManager::RegisterPlugin(const std::string& path)
   {
     std::auto_ptr<SharedLibrary> plugin(new SharedLibrary(path));
 
-    if (!plugin->HasFunction("OrthancPluginInitialize") ||
-        !plugin->HasFunction("OrthancPluginFinalize"))
+    if (!IsOrthancPlugin(*plugin))
     {
       LOG(ERROR) << "Plugin " << plugin->GetPath()
                  << " does not declare the proper entry functions";
       throw OrthancException(ErrorCode_SharedLibrary);
     }
 
-    LOG(WARNING) << "Registering plugin " << path;
+    std::string name(CallGetName(*plugin));
+    if (plugins_.find(name) != plugins_.end())
+    {
+      LOG(ERROR) << "Plugin '" << name << "' already registered";
+      throw OrthancException(ErrorCode_SharedLibrary);
+    }
+
+    LOG(WARNING) << "Registering plugin '" << name
+                 << "' (version " << CallGetVersion(*plugin) << ")";
 
     CallInitialize(*plugin, context_);
 
-    plugins_.push_back(plugin.release());
+    plugins_[name] = plugin.release();
+  }
+
+
+  void PluginsManager::ScanFolderForPlugins(const std::string& path,
+                                            bool isRecursive)
+  {
+    using namespace boost::filesystem;
+
+    if (!exists(path))
+    {
+      return;
+    }
+
+    LOG(INFO) << "Scanning folder " << path << " for plugins";
+
+    directory_iterator end_it; // default construction yields past-the-end
+    for (directory_iterator it(path);
+          it != end_it;
+          ++it)
+    {
+      if (is_directory(it->status()))
+      {
+        if (isRecursive)
+        {
+          ScanFolderForPlugins(it->path().string(), true);
+        }
+      }
+      else
+      {
+        if (boost::filesystem::extension(it->path()) == PLUGIN_EXTENSION)
+        {
+          LOG(INFO) << "Found a shared library: " << it->path();
+
+          try
+          {
+            SharedLibrary plugin(it->path().string());
+            if (IsOrthancPlugin(plugin))
+            {
+              RegisterPlugin(it->path().string());
+            }
+          }
+          catch (OrthancException&)
+          {
+          }
+        }
+      }
+    }
   }
 
 }
--- a/Plugins/Engine/PluginsManager.h	Sat Jun 14 19:20:38 2014 +0200
+++ b/Plugins/Engine/PluginsManager.h	Sat Jun 14 19:47:51 2014 +0200
@@ -35,14 +35,14 @@
 #include "SharedLibrary.h"
 #include "../OrthancCPlugin/OrthancCPlugin.h"
 
-#include <list>
+#include <map>
 
 namespace Orthanc
 {
   class PluginsManager : boost::noncopyable
   {
   private:
-    typedef std::list<SharedLibrary*>  Plugins;
+    typedef std::map<std::string, SharedLibrary*>  Plugins;
 
     OrthancPluginContext  context_;
     Plugins  plugins_;
@@ -53,5 +53,8 @@
     ~PluginsManager();
 
     void RegisterPlugin(const std::string& path);
+
+    void ScanFolderForPlugins(const std::string& path,
+                              bool isRecursive);
   };
 }
--- a/Plugins/OrthancCPlugin/OrthancCPlugin.h	Sat Jun 14 19:20:38 2014 +0200
+++ b/Plugins/OrthancCPlugin/OrthancCPlugin.h	Sat Jun 14 19:47:51 2014 +0200
@@ -78,9 +78,11 @@
 
 
   /**
-     Each plugin must define 2 functions, whose signature is:
+     Each plugin must define 4 functions, whose signature is:
      - int32_t OrthancPluginInitialize(const OrthancPluginContext*);
      - void OrthancPluginFinalize();
+     - const char* OrthancPluginGetName();
+     - const char* OrthancPluginGetVersion();
 
      nm -C -D --defined-only libPluginTest.so
    **/
--- a/Resources/Samples/Plugins/Basic/Plugin.c	Sat Jun 14 19:20:38 2014 +0200
+++ b/Resources/Samples/Plugins/Basic/Plugin.c	Sat Jun 14 19:47:51 2014 +0200
@@ -53,3 +53,14 @@
 }
 
 
+ORTHANC_PLUGINS_API const char* OrthancPluginGetName()
+{
+  return "sample";
+}
+
+
+ORTHANC_PLUGINS_API const char* OrthancPluginGetVersion()
+{
+  return "1.0";
+}
+
--- a/UnitTestsSources/PluginsTests.cpp	Sat Jun 14 19:20:38 2014 +0200
+++ b/UnitTestsSources/PluginsTests.cpp	Sat Jun 14 19:47:51 2014 +0200
@@ -66,7 +66,10 @@
 #error Support your platform here
 
 #elif defined(__linux)
-  manager.RegisterPlugin("./libPluginTest.so");
+  //manager.RegisterPlugin("./libPluginTest.so");
+  //ASSERT_THROW(manager.RegisterPlugin("./libPluginTest.so"), OrthancException);
+
+  manager.ScanFolderForPlugins(".", true);
 
 #else
 #error Support your platform here