changeset 898:7000fc86fe62 plugins

improved plugin api
author Sebastien Jodogne <s.jodogne@gmail.com>
date Wed, 18 Jun 2014 09:18:28 +0200
parents bafc9d592632
children bb0a51561016
files Plugins/Engine/IPluginServiceProvider.h Plugins/Engine/PluginsManager.cpp Plugins/Engine/PluginsManager.h Plugins/OrthancCPlugin/OrthancCPlugin.h Resources/Samples/Plugins/Basic/Plugin.c
diffstat 5 files changed, 206 insertions(+), 40 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Engine/IPluginServiceProvider.h	Wed Jun 18 09:18:28 2014 +0200
@@ -0,0 +1,49 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2014 Medical Physics Department, CHU of Liege,
+ * Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * In addition, as a special exception, the copyright holders of this
+ * program give permission to link the code of its release with the
+ * OpenSSL project's "OpenSSL" library (or with modified versions of it
+ * that use the same license as the "OpenSSL" library), and distribute
+ * the linked executables. You must obey the GNU General Public License
+ * in all respects for all of the code used other than "OpenSSL". If you
+ * modify file(s) with this exception, you may extend this exception to
+ * your version of the file(s), but you are not obligated to do so. If
+ * you do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source files
+ * in the program, then also delete it here.
+ * 
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+#pragma once
+
+#include "../OrthancCPlugin/OrthancCPlugin.h"
+
+#include <boost/noncopyable.hpp>
+
+namespace Orthanc
+{
+  class IPluginServiceProvider : boost::noncopyable
+  {
+  public:
+    virtual ~IPluginServiceProvider();
+
+    virtual bool Handle(OrthancPluginService service,
+                        const void* parameters) = 0;
+  };
+}
--- a/Plugins/Engine/PluginsManager.cpp	Tue Jun 17 17:43:39 2014 +0200
+++ b/Plugins/Engine/PluginsManager.cpp	Wed Jun 18 09:18:28 2014 +0200
@@ -132,27 +132,47 @@
   }
 
 
-  static void LogError(const char* str)
+  int32_t PluginsManager::InvokeService(OrthancPluginContext* context,
+                                        OrthancPluginService service, 
+                                        const void* parameters)
   {
-    LOG(ERROR) << str;
+    switch (service)
+    {
+      case OrthancPluginService_LogError:
+        LOG(ERROR) << reinterpret_cast<const char*>(parameters);
+        return 0;
+
+      case OrthancPluginService_LogWarning:
+        LOG(WARNING) << reinterpret_cast<const char*>(parameters);
+        return 0;
+
+      case OrthancPluginService_LogInfo:
+        LOG(INFO) << reinterpret_cast<const char*>(parameters);
+        return 0;
+
+      default:
+        break;
+    }
+
+    PluginsManager* that = reinterpret_cast<PluginsManager*>(context->pluginsManager);
+
+    if (that->HasServiceProvider() &&
+        that->serviceProvider_->Handle(service, parameters))
+    {
+      return 0;
+    }
+
+    LOG(ERROR) << "Plugin invoking unknown service " << service;
+    return -1;
   }
 
-  static void LogWarning(const char* str)
-  {
-    LOG(WARNING) << str;
-  }
-
-  static void LogInfo(const char* str)
-  {
-    LOG(INFO) << str;
-  }
 
   void PluginsManager::RegisterRestCallback(const OrthancPluginContext* context,
                                             const char* pathRegularExpression, 
                                             OrthancPluginRestCallback callback)
   {
     LOG(INFO) << "Plugin has registered a REST callback on: " << pathRegularExpression;
-    PluginsManager* manager = reinterpret_cast<PluginsManager*>(context->pimpl);
+    PluginsManager* manager = reinterpret_cast<PluginsManager*>(context->pluginsManager);
     manager->restCallbacks_.push_back(std::make_pair(pathRegularExpression, callback));
   }
 
@@ -167,15 +187,14 @@
   }
 
 
-  PluginsManager::PluginsManager()
+  PluginsManager::PluginsManager() : 
+    serviceProvider_(NULL)
   {
     memset(&context_, 0, sizeof(context_));
-    context_.pimpl = this;
+    context_.pluginsManager = this;
     context_.orthancVersion = ORTHANC_VERSION;
     context_.FreeBuffer = ::free;
-    context_.LogError = LogError;
-    context_.LogWarning = LogWarning;
-    context_.LogInfo = LogInfo;
+    context_.InvokeService = InvokeService;
     context_.RegisterRestCallback = RegisterRestCallback;
     context_.AnswerBuffer = AnswerBuffer;
   }
@@ -279,4 +298,17 @@
       }
     }
   }
+
+
+  IPluginServiceProvider& PluginsManager::GetServiceProvider() const
+  {
+    if (!HasServiceProvider())
+    {
+      throw OrthancException(ErrorCode_BadRequest);
+    }
+    else
+    {
+      return *serviceProvider_;
+    }
+  }
 }
--- a/Plugins/Engine/PluginsManager.h	Tue Jun 17 17:43:39 2014 +0200
+++ b/Plugins/Engine/PluginsManager.h	Wed Jun 18 09:18:28 2014 +0200
@@ -33,7 +33,7 @@
 #pragma once
 
 #include "SharedLibrary.h"
-#include "../OrthancCPlugin/OrthancCPlugin.h"
+#include "IPluginServiceProvider.h"
 
 #include <map>
 #include <list>
@@ -47,9 +47,15 @@
 
   private:
     typedef std::map<std::string, SharedLibrary*>  Plugins;
+
     OrthancPluginContext  context_;
     Plugins  plugins_;
     RestCallbacks  restCallbacks_;
+    IPluginServiceProvider *serviceProvider_;
+
+    static int32_t InvokeService(OrthancPluginContext* context,
+                                 OrthancPluginService service,
+                                 const void* parameters);
 
     static void RegisterRestCallback(const OrthancPluginContext* context,
                                      const char* path, 
@@ -65,6 +71,18 @@
     void ScanFolderForPlugins(const std::string& path,
                               bool isRecursive);
 
+    void SetServiceProvider(IPluginServiceProvider& provider)
+    {
+      serviceProvider_ = &provider;
+    }
+
+    bool HasServiceProvider() const
+    {
+      return serviceProvider_ != NULL;
+    }
+
+    IPluginServiceProvider& GetServiceProvider() const;
+
     const RestCallbacks& GetRestCallbacks() const
     {
       return restCallbacks_;
--- a/Plugins/OrthancCPlugin/OrthancCPlugin.h	Tue Jun 17 17:43:39 2014 +0200
+++ b/Plugins/OrthancCPlugin/OrthancCPlugin.h	Wed Jun 18 09:18:28 2014 +0200
@@ -33,13 +33,6 @@
 #pragma once
 
 
-#ifdef _MSC_VER
-#include "../../Resources/VisualStudio/stdint.h"
-#else
-#include <stdint.h>
-#endif
-
-
 #ifdef WIN32
 #define ORTHANC_PLUGINS_API __declspec(dllexport)
 #else
@@ -47,9 +40,59 @@
 #endif
 
 
+
+/********************************************************************
+ ** Check that function inlining is properly supported. The use of
+ ** inlining is required, to avoid the duplication of object code
+ ** between two compilation modules that would use the Orthanc Plugin
+ ** API.
+ ********************************************************************/
+
+/* If the auto-detection of the "inline" keyword below does not work
+   automatically and that your compiler is known to properly support
+   inlining, uncomment the following #define and adapt the definition
+   of "static inline". */
+
+/* #define ORTHANC_PLUGIN_INLINE static inline */
+
+#ifndef ORTHANC_PLUGIN_INLINE
+#  if __STDC_VERSION__ >= 199901L
+/*   This is C99 or above: http://predef.sourceforge.net/prestd.html */
+#    define ORTHANC_PLUGIN_INLINE static inline
+#  elif defined(__cplusplus)
+/*   This is C++ */
+#    define ORTHANC_PLUGIN_INLINE static inline
+#  elif defined(__GNUC__)
+/*   This is GCC running in C89 mode */
+#    define ORTHANC_PLUGIN_INLINE static __inline
+#  elif defined(_MSC_VER)
+/*   This is Visual Studio running in C89 mode */
+#    define ORTHANC_PLUGIN_INLINE static __inline
+#  else
+#    error Your compiler is not known to support the "inline" keyword
+#  endif
+#endif
+
+
+
+/********************************************************************
+ ** Inclusion of standard libaries.
+ ********************************************************************/
+
+#ifdef _MSC_VER
+#include "../../Resources/VisualStudio/stdint.h"
+#else
+#include <stdint.h>
+#endif
+
 #include <stdlib.h>
 
 
+
+/********************************************************************
+ ** Definition of the Orthanc Plugin API.
+ ********************************************************************/
+
 #ifdef __cplusplus
 extern "C"
 {
@@ -65,8 +108,12 @@
     OrthancPluginHttpMethod_Delete = 4
   } OrthancPluginHttpMethod;
 
-  typedef int32_t (*OrthancPluginService) (const char* serviceName,
-                                           const void* serviceParameters);
+  typedef enum 
+  {
+    OrthancPluginService_LogInfo = 1,
+    OrthancPluginService_LogWarning = 2,
+    OrthancPluginService_LogError = 3
+  } OrthancPluginService;
 
   typedef int32_t (*OrthancPluginRestCallback) (OrthancPluginRestOutput* output,
                                                 OrthancPluginHttpMethod method,
@@ -78,15 +125,13 @@
 
   typedef struct OrthancPluginContext_t
   {
-    void* pimpl;
+    void* pluginsManager;
 
     const char* orthancVersion;
     void (*FreeBuffer) (void* buffer);
-
-    /* Logging functions */
-    void (*LogError) (const char* str);
-    void (*LogWarning) (const char* str);
-    void (*LogInfo) (const char* str);
+    int32_t (*InvokeService) (struct OrthancPluginContext_t* context,
+                              OrthancPluginService service,
+                              const void* parameters);
 
     /* REST API */
     void (*RegisterRestCallback) (const struct OrthancPluginContext_t* context,
@@ -100,6 +145,28 @@
   } OrthancPluginContext;
 
 
+  ORTHANC_PLUGIN_INLINE void OrthancPluginLogError(OrthancPluginContext* context,
+                                                   const char* str)
+  {
+    context->InvokeService(context, OrthancPluginService_LogError, str);
+  }
+
+
+  ORTHANC_PLUGIN_INLINE void OrthancPluginLogWarning(OrthancPluginContext* context,
+                                                     const char* str)
+  {
+    context->InvokeService(context, OrthancPluginService_LogWarning, str);
+  }
+
+
+  ORTHANC_PLUGIN_INLINE void OrthancPluginLogInfo(OrthancPluginContext* context,
+                                                  const char* str)
+  {
+    context->InvokeService(context, OrthancPluginService_LogInfo, str);
+  }
+
+
+
   /**
      Each plugin must define 4 functions, whose signature are:
      - int32_t OrthancPluginInitialize(const OrthancPluginContext*);
--- a/Resources/Samples/Plugins/Basic/Plugin.c	Tue Jun 17 17:43:39 2014 +0200
+++ b/Resources/Samples/Plugins/Basic/Plugin.c	Wed Jun 18 09:18:28 2014 +0200
@@ -30,7 +30,7 @@
 #include <string.h>
 #include <stdio.h>
 
-static const OrthancPluginContext* context = NULL;
+static OrthancPluginContext* context = NULL;
 
 
 ORTHANC_PLUGINS_API int32_t Callback(OrthancPluginRestOutput* output,
@@ -46,29 +46,29 @@
   uint32_t i;
 
   sprintf(buffer, "Callback on URL [%s] with body [%s]", url, body);
-  context->LogInfo(buffer);
+  OrthancPluginLogInfo(context, buffer);
 
   context->AnswerBuffer(output, buffer, strlen(buffer), "text/plain");
 
   for (i = 0; i < getSize; i++)
   {
     sprintf(buffer, "  [%s] = [%s]", getKeys[i], getValues[i]);
-    context->LogInfo(buffer);    
+    OrthancPluginLogInfo(context, buffer);    
   }
 
   return 1;
 }
 
 
-ORTHANC_PLUGINS_API int32_t OrthancPluginInitialize(const OrthancPluginContext* c)
+ORTHANC_PLUGINS_API int32_t OrthancPluginInitialize(OrthancPluginContext* c)
 {
   char info[1024];
 
   context = c;
-  context->LogWarning("Plugin is initializing");
+  OrthancPluginLogWarning(context, "Plugin is initializing");
 
   sprintf(info, "The version of Orthanc is '%s'", context->orthancVersion);
-  context->LogInfo(info);
+  OrthancPluginLogInfo(context, info);
 
   context->RegisterRestCallback(c, "/plu.*/hello", Callback);
 
@@ -78,7 +78,7 @@
 
 ORTHANC_PLUGINS_API void OrthancPluginFinalize()
 {
-  context->LogWarning("Plugin is finalizing");
+  OrthancPluginLogWarning(context, "Plugin is finalizing");
 }