changeset 240:01e147cf7d5c

More detailed information about errors is provided in the HTTP answers
author Sebastien Jodogne <s.jodogne@gmail.com>
date Tue, 04 Dec 2018 19:08:22 +0100
parents f1d1dd716eaa
children d73e463dd5bc
files CMakeLists.txt NEWS Plugin/Configuration.cpp Plugin/Configuration.h Plugin/Dicom.cpp Plugin/Dicom.h Plugin/DicomResults.cpp Plugin/DicomResults.h Plugin/DicomWebClient.cpp Plugin/DicomWebServers.cpp Plugin/Plugin.cpp Plugin/QidoRs.cpp Plugin/StowRs.cpp Plugin/WadoRs.cpp Plugin/WadoRsRetrieveFrames.cpp Plugin/WadoUri.cpp Resources/Orthanc/DownloadOrthancFramework.cmake
diffstat 17 files changed, 375 insertions(+), 381 deletions(-) [+]
line wrap: on
line diff
--- a/CMakeLists.txt	Fri Nov 09 10:25:02 2018 +0100
+++ b/CMakeLists.txt	Tue Dec 04 19:08:22 2018 +0100
@@ -42,6 +42,7 @@
 # Advanced parameters to fine-tune linking against system libraries
 set(USE_SYSTEM_GDCM ON CACHE BOOL "Use the system version of Grassroot DICOM (GDCM)")
 set(USE_SYSTEM_ORTHANC_SDK ON CACHE BOOL "Use the system version of the Orthanc plugin SDK")
+set(ORTHANC_SDK_VERSION "1.1.0" CACHE STRING "Version of the Orthanc plugin SDK to use, if not using the system version (can be \"1.1.0\", or \"framework\")")
 
 
 
@@ -64,7 +65,13 @@
 
 
 if (STATIC_BUILD OR NOT USE_SYSTEM_ORTHANC_SDK)
-  include_directories(${CMAKE_SOURCE_DIR}/Resources/Orthanc/Sdk-1.1.0)
+  if (ORTHANC_SDK_VERSION STREQUAL "1.1.0")
+    include_directories(${CMAKE_SOURCE_DIR}/Resources/Orthanc/Sdk-1.1.0)
+  elseif (ORTHANC_SDK_VERSION STREQUAL "framework")
+    include_directories(${ORTHANC_ROOT}/Plugins/Include)
+  else()
+    message(FATAL_ERROR "Unsupported version of the Orthanc plugin SDK: ${ORTHANC_SDK_VERSION}")
+  endif()
 else ()
   CHECK_INCLUDE_FILE_CXX(orthanc/OrthancCPlugin.h HAVE_ORTHANC_H)
   if (NOT HAVE_ORTHANC_H)
--- a/NEWS	Fri Nov 09 10:25:02 2018 +0100
+++ b/NEWS	Tue Dec 04 19:08:22 2018 +0100
@@ -3,6 +3,7 @@
 
 * Sending "HttpHeaders" of the "DicomWeb.Servers" configuration to remote DICOMweb servers
 * Improved WADO-RS compatibility if Orthanc is acting as a DICOMweb client
+* More detailed information about errors is provided in the HTTP answers
 
 
 Version 0.5 (2018-04-19)
--- a/Plugin/Configuration.cpp	Fri Nov 09 10:25:02 2018 +0100
+++ b/Plugin/Configuration.cpp	Tue Dec 04 19:08:22 2018 +0100
@@ -29,6 +29,7 @@
 #include "Plugin.h"
 #include "DicomWebServers.h"
 
+#include <Plugins/Samples/Common/OrthancPluginCppWrapper.h>
 #include <Core/Toolbox.h>
 
 namespace OrthancPlugins
@@ -91,7 +92,6 @@
   static void ParseMultipartHeaders(bool& hasLength /* out */,
                                     size_t& length /* out */,
                                     std::string& contentType /* out */,
-                                    OrthancPluginContext* context,
                                     const char* startHeaders,
                                     const char* endHeaders)
   {
@@ -131,7 +131,7 @@
           }
           catch (boost::bad_lexical_cast&)
           {
-            OrthancPluginLogWarning(context, "Unable to parse the Content-Length of a multipart item");
+            LogWarning("Unable to parse the Content-Length of a multipart item");
           }
         }
         else if (key == "content-type")
@@ -144,7 +144,6 @@
 
 
   static const char* ParseMultipartItem(std::vector<MultipartItem>& result,
-                                        OrthancPluginContext* context,
                                         const char* start,
                                         const char* end,
                                         const boost::regex& nextSeparator)
@@ -167,7 +166,7 @@
     bool hasLength;
     size_t length;
     std::string contentType;
-    ParseMultipartHeaders(hasLength, length, contentType, context, startHeaders, endHeaders);
+    ParseMultipartHeaders(hasLength, length, contentType, startHeaders, endHeaders);
 
     boost::cmatch separator;
 
@@ -200,7 +199,6 @@
 
 
   void ParseMultipartBody(std::vector<MultipartItem>& result,
-                          OrthancPluginContext* context,
                           const char* body,
                           const uint64_t bodySize,
                           const std::string& boundary)
@@ -239,7 +237,7 @@
         }
         else
         {
-          current = ParseMultipartItem(result, context, current + 2, end, nextSeparator);
+          current = ParseMultipartItem(result, current + 2, end, nextSeparator);
         }
       }
     }
@@ -252,8 +250,8 @@
   {
     if (value.type() != Json::objectValue)
     {
-      OrthancPlugins::Configuration::LogError("This is not a JSON object");
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat,
+                                      "This is not a JSON object");
     }
 
     if (!value.isMember(key))
@@ -265,9 +263,9 @@
 
     if (tmp.type() != Json::objectValue)
     {
-      OrthancPlugins::Configuration::LogError("The field \"" + key + "\" of a JSON object is "
-                                              "not a JSON associative array as expected");
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat,
+                                      "The field \"" + key + "\" of a JSON object is "
+                                      "not a JSON associative array as expected");
     }
 
     Json::Value::Members names = tmp.getMemberNames();
@@ -276,9 +274,9 @@
     {
       if (tmp[names[i]].type() != Json::stringValue)
       {
-        OrthancPlugins::Configuration::LogError("Some value in the associative array \"" + key + 
-                                                "\" is not a string as expected");
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
+        throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat,
+                                        "Some value in the associative array \"" + key + 
+                                        "\" is not a string as expected");
       }
       else
       {
@@ -292,13 +290,15 @@
   {
     // Assume Latin-1 encoding by default (as in the Orthanc core)
     static Orthanc::Encoding defaultEncoding_ = Orthanc::Encoding_Latin1;
-    static OrthancConfiguration configuration_;
+    static std::auto_ptr<OrthancConfiguration> configuration_;
 
 
-    void Initialize(OrthancPluginContext* context)
-    {      
-      OrthancPlugins::OrthancConfiguration global(context);
-      global.GetSection(configuration_, "DicomWeb");
+    void Initialize()
+    {
+      configuration_.reset(new OrthancConfiguration);
+      
+      OrthancPlugins::OrthancConfiguration global;
+      global.GetSection(*configuration_, "DicomWeb");
 
       std::string s;
       if (global.LookupStringValue(s, "DefaultEncoding"))
@@ -307,41 +307,39 @@
       }
 
       OrthancPlugins::OrthancConfiguration servers;
-      configuration_.GetSection(servers, "Servers");
+      configuration_->GetSection(servers, "Servers");
       OrthancPlugins::DicomWebServers::GetInstance().Load(servers.GetJson());
     }
 
 
-    OrthancPluginContext* GetContext()
-    {
-      return configuration_.GetContext();
-    }
-
-
     std::string GetStringValue(const std::string& key,
                                const std::string& defaultValue)
     {
-      return configuration_.GetStringValue(key, defaultValue);
+      assert(configuration_.get() != NULL);
+      return configuration_->GetStringValue(key, defaultValue);
     }
 
 
     bool GetBooleanValue(const std::string& key,
                          bool defaultValue)
     {
-      return configuration_.GetBooleanValue(key, defaultValue);
+      assert(configuration_.get() != NULL);
+      return configuration_->GetBooleanValue(key, defaultValue);
     }
 
 
     unsigned int GetUnsignedIntegerValue(const std::string& key,
                                          unsigned int defaultValue)
     {
-      return configuration_.GetUnsignedIntegerValue(key, defaultValue);
+      assert(configuration_.get() != NULL);
+      return configuration_->GetUnsignedIntegerValue(key, defaultValue);
     }
 
 
     std::string GetRoot()
     {
-      std::string root = configuration_.GetStringValue("Root", "/dicom-web/");
+      assert(configuration_.get() != NULL);
+      std::string root = configuration_->GetStringValue("Root", "/dicom-web/");
 
       // Make sure the root URI starts and ends with a slash
       if (root.size() == 0 ||
@@ -361,7 +359,8 @@
 
     std::string GetWadoRoot()
     {
-      std::string root = configuration_.GetStringValue("WadoRoot", "/wado/");
+      assert(configuration_.get() != NULL);
+      std::string root = configuration_->GetStringValue("WadoRoot", "/wado/");
 
       // Make sure the root URI starts with a slash
       if (root.size() == 0 ||
@@ -382,8 +381,9 @@
 
     std::string  GetBaseUrl(const OrthancPluginHttpRequest* request)
     {
-      std::string host = configuration_.GetStringValue("Host", "");
-      bool ssl = configuration_.GetBooleanValue("Ssl", false);
+      assert(configuration_.get() != NULL);
+      std::string host = configuration_->GetStringValue("Host", "");
+      bool ssl = configuration_->GetBooleanValue("Ssl", false);
 
       if (host.empty() &&
           !LookupHttpHeader(host, request, "host"))
@@ -418,24 +418,6 @@
     }
 
 
-    void LogError(const std::string& message)
-    {
-      OrthancPluginLogError(GetContext(), message.c_str());
-    }
-
-
-    void LogWarning(const std::string& message)
-    {
-      OrthancPluginLogWarning(GetContext(), message.c_str());
-    }
-
-
-    void LogInfo(const std::string& message)
-    {
-      OrthancPluginLogInfo(GetContext(), message.c_str());
-    }
-
-
     Orthanc::Encoding GetDefaultEncoding()
     {
       return defaultEncoding_;
--- a/Plugin/Configuration.h	Fri Nov 09 10:25:02 2018 +0100
+++ b/Plugin/Configuration.h	Tue Dec 04 19:08:22 2018 +0100
@@ -52,7 +52,6 @@
                         const std::string& header);
 
   void ParseMultipartBody(std::vector<MultipartItem>& result,
-                          OrthancPluginContext* context,
                           const char* body,
                           const uint64_t bodySize,
                           const std::string& boundary);
@@ -63,10 +62,8 @@
 
   namespace Configuration
   {
-    void Initialize(OrthancPluginContext* context);
+    void Initialize();
 
-    OrthancPluginContext* GetContext();
-    
     std::string GetStringValue(const std::string& key,
                                const std::string& defaultValue);
 
@@ -87,12 +84,6 @@
                            const std::string& seriesInstanceUid,
                            const std::string& sopInstanceUid);
 
-    void LogError(const std::string& message);
-
-    void LogWarning(const std::string& message);
-
-    void LogInfo(const std::string& message);
-
     Orthanc::Encoding GetDefaultEncoding();
   }
 }
--- a/Plugin/Dicom.cpp	Fri Nov 09 10:25:02 2018 +0100
+++ b/Plugin/Dicom.cpp	Tue Dec 04 19:08:22 2018 +0100
@@ -218,9 +218,9 @@
 
     if (!reader_.Read())
     {
-      OrthancPlugins::Configuration::LogError("GDCM cannot decode this DICOM instance of length " +
-                                              boost::lexical_cast<std::string>(dicom.size()));
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat,
+                                      "GDCM cannot decode this DICOM instance of length " +
+                                      boost::lexical_cast<std::string>(dicom.size()));
     }
   }
 
@@ -690,8 +690,7 @@
   }
 
 
-  void AnswerDicom(OrthancPluginContext* context,
-                   OrthancPluginRestOutput* output,
+  void AnswerDicom(OrthancPluginRestOutput* output,
                    const std::string& wadoBase,
                    const gdcm::Dict& dictionary,
                    const gdcm::DataSet& dicom,
@@ -700,7 +699,7 @@
   {
     std::string answer;
     GenerateSingleDicomAnswer(answer, wadoBase, dictionary, dicom, isXml, isBulkAccessible);
-    OrthancPluginAnswerBuffer(context, output, answer.c_str(), answer.size(), 
+    OrthancPluginAnswerBuffer(GetGlobalContext(), output, answer.c_str(), answer.size(), 
                               isXml ? "application/dicom+xml" : "application/dicom+json");
   }
 
@@ -738,8 +737,9 @@
   {
     if (key.find('.') != std::string::npos)
     {
-      OrthancPlugins::Configuration::LogError("This DICOMweb plugin does not support hierarchical queries: " + key);
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
+      throw Orthanc::OrthancException(
+        Orthanc::ErrorCode_NotImplemented,
+        "This DICOMweb plugin does not support hierarchical queries: " + key);
     }
 
     if (key.size() == 8 &&  // This is the DICOMweb convention
@@ -778,13 +778,14 @@
       {
         if (key.find('.') != std::string::npos)
         {
-          OrthancPlugins::Configuration::LogError("This QIDO-RS implementation does not support search over sequences: " + key);
-          throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
+          throw Orthanc::OrthancException(
+            Orthanc::ErrorCode_NotImplemented,
+            "This QIDO-RS implementation does not support search over sequences: " + key);
         }
         else
         {
-          OrthancPlugins::Configuration::LogError("Illegal tag name in QIDO-RS: " + key);
-          throw Orthanc::OrthancException(Orthanc::ErrorCode_UnknownDicomTag);
+          throw Orthanc::OrthancException(Orthanc::ErrorCode_UnknownDicomTag,
+                                          "Illegal tag name in QIDO-RS: " + key);
         }
       }
 
--- a/Plugin/Dicom.h	Fri Nov 09 10:25:02 2018 +0100
+++ b/Plugin/Dicom.h	Tue Dec 04 19:08:22 2018 +0100
@@ -116,8 +116,7 @@
                                  bool isXml,
                                  bool isBulkAccessible);
 
-  void AnswerDicom(OrthancPluginContext* context,
-                   OrthancPluginRestOutput* output,
+  void AnswerDicom(OrthancPluginRestOutput* output,
                    const std::string& wadoBase,
                    const gdcm::Dict& dictionary,
                    const gdcm::DataSet& dicom,
--- a/Plugin/DicomResults.cpp	Fri Nov 09 10:25:02 2018 +0100
+++ b/Plugin/DicomResults.cpp	Tue Dec 04 19:08:22 2018 +0100
@@ -31,13 +31,11 @@
 
 namespace OrthancPlugins
 {
-  DicomResults::DicomResults(OrthancPluginContext* context,
-                             OrthancPluginRestOutput* output,
+  DicomResults::DicomResults(OrthancPluginRestOutput* output,
                              const std::string& wadoBase,
                              const gdcm::Dict& dictionary,
                              bool isXml,
                              bool isBulkAccessible) :
-    context_(context),
     output_(output),
     wadoBase_(wadoBase),
     dictionary_(dictionary),
@@ -46,10 +44,11 @@
     isBulkAccessible_(isBulkAccessible)
   {
     if (isXml_ &&
-        OrthancPluginStartMultipartAnswer(context_, output_, "related", "application/dicom+xml") != 0)
+        OrthancPluginStartMultipartAnswer(GetGlobalContext(), output_,
+                                          "related", "application/dicom+xml") != 0)
     {
-      OrthancPlugins::Configuration::LogError("Unable to create a multipart stream of DICOM+XML answers");
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol);
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol,
+                                      "Unable to create a multipart stream of DICOM+XML answers");
     }
 
     jsonWriter_.AddChunk("[\n");
@@ -60,10 +59,10 @@
   {
     if (isXml_)
     {
-      if (OrthancPluginSendMultipartItem(context_, output_, item.c_str(), item.size()) != 0)
+      if (OrthancPluginSendMultipartItem(GetGlobalContext(), output_, item.c_str(), item.size()) != 0)
       {
-        OrthancPlugins::Configuration::LogError("Unable to create a multipart stream of DICOM+XML answers");
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol);
+        throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol,
+                                        "Unable to create a multipart stream of DICOM+XML answers");
       }
     }
     else
@@ -420,7 +419,8 @@
 
       std::string answer;
       jsonWriter_.Flatten(answer);
-      OrthancPluginAnswerBuffer(context_, output_, answer.c_str(), answer.size(), "application/dicom+json");
+      OrthancPluginAnswerBuffer(GetGlobalContext(), output_, answer.c_str(),
+                                answer.size(), "application/dicom+json");
     }
   }
 }
--- a/Plugin/DicomResults.h	Fri Nov 09 10:25:02 2018 +0100
+++ b/Plugin/DicomResults.h	Tue Dec 04 19:08:22 2018 +0100
@@ -34,7 +34,6 @@
   class DicomResults
   {
   private:
-    OrthancPluginContext*     context_;
     OrthancPluginRestOutput*  output_;
     std::string               wadoBase_;
     const gdcm::Dict&         dictionary_;
@@ -48,8 +47,7 @@
     void AddInternal(const gdcm::DataSet& dicom);
 
   public:
-    DicomResults(OrthancPluginContext* context,
-                 OrthancPluginRestOutput* output,
+    DicomResults(OrthancPluginRestOutput* output,
                  const std::string& wadoBase,
                  const gdcm::Dict& dictionary,
                  bool isXml,
--- a/Plugin/DicomWebClient.cpp	Fri Nov 09 10:25:02 2018 +0100
+++ b/Plugin/DicomWebClient.cpp	Tue Dec 04 19:08:22 2018 +0100
@@ -71,9 +71,10 @@
   }
   else if (isMandatory)
   {
-    OrthancPlugins::Configuration::LogError("The STOW-RS JSON response from DICOMweb server " + server + 
-                                            " does not contain the mandatory tag " + upper);
-    throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol);
+    throw Orthanc::OrthancException(
+      Orthanc::ErrorCode_NetworkProtocol,
+      "The STOW-RS JSON response from DICOMweb server " + server + 
+      " does not contain the mandatory tag " + upper);
   }
   else
   {
@@ -84,8 +85,9 @@
       !value->isMember("Value") ||
       (*value) ["Value"].type() != Json::arrayValue)
   {
-    OrthancPlugins::Configuration::LogError("Unable to parse STOW-RS JSON response from DICOMweb server " + server);
-    throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol);
+    throw Orthanc::OrthancException(
+      Orthanc::ErrorCode_NetworkProtocol,
+      "Unable to parse STOW-RS JSON response from DICOMweb server " + server);
   }
 
   result = (*value) ["Value"].size();
@@ -103,8 +105,6 @@
   static const char* HTTP_HEADERS = "HttpHeaders";
   static const char* QUERY_ARGUMENTS = "Arguments";
 
-  OrthancPluginContext* context = OrthancPlugins::Configuration::GetContext();
-
   Json::Value body;
   Json::Reader reader;
   if (!reader.parse(request->body, request->body + request->bodySize, body) ||
@@ -112,10 +112,11 @@
       !body.isMember(RESOURCES) ||
       body[RESOURCES].type() != Json::arrayValue)
   {
-    OrthancPlugins::Configuration::LogError("A request to the DICOMweb STOW-RS client must provide a JSON object "
-                                            "with the field \"" + std::string(RESOURCES) + 
-                                            "\" containing an array of resources to be sent");
-    throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
+    throw Orthanc::OrthancException(
+      Orthanc::ErrorCode_BadFileFormat,
+      "A request to the DICOMweb STOW-RS client must provide a JSON object "
+      "with the field \"" + std::string(RESOURCES) + 
+      "\" containing an array of resources to be sent");
   }
 
   OrthancPlugins::ParseAssociativeArray(queryArguments, body, QUERY_ARGUMENTS);
@@ -139,17 +140,17 @@
 
     // Test whether this resource is an instance
     Json::Value tmp;
-    if (OrthancPlugins::RestApiGet(tmp, context, "/instances/" + resource, false))
+    if (OrthancPlugins::RestApiGet(tmp, "/instances/" + resource, false))
     {
       AddInstance(instances, tmp);
     }
     // This was not an instance, successively try with series/studies/patients
-    else if ((OrthancPlugins::RestApiGet(tmp, context, "/series/" + resource, false) &&
-              OrthancPlugins::RestApiGet(tmp, context, "/series/" + resource + "/instances", false)) ||
-             (OrthancPlugins::RestApiGet(tmp, context, "/studies/" + resource, false) &&
-              OrthancPlugins::RestApiGet(tmp, context, "/studies/" + resource + "/instances", false)) ||
-             (OrthancPlugins::RestApiGet(tmp, context, "/patients/" + resource, false) &&
-              OrthancPlugins::RestApiGet(tmp, context, "/patients/" + resource + "/instances", false)))
+    else if ((OrthancPlugins::RestApiGet(tmp, "/series/" + resource, false) &&
+              OrthancPlugins::RestApiGet(tmp, "/series/" + resource + "/instances", false)) ||
+             (OrthancPlugins::RestApiGet(tmp, "/studies/" + resource, false) &&
+              OrthancPlugins::RestApiGet(tmp, "/studies/" + resource + "/instances", false)) ||
+             (OrthancPlugins::RestApiGet(tmp, "/patients/" + resource, false) &&
+              OrthancPlugins::RestApiGet(tmp, "/patients/" + resource + "/instances", false)))
     {
       if (tmp.type() != Json::arrayValue)
       {
@@ -189,7 +190,7 @@
     std::string body;
     chunks.Flatten(body);
 
-    OrthancPlugins::MemoryBuffer answerBody(OrthancPlugins::Configuration::GetContext());
+    OrthancPlugins::MemoryBuffer answerBody;
     std::map<std::string, std::string> answerHeaders;
 
     std::string uri;
@@ -208,36 +209,40 @@
         response.type() != Json::objectValue ||
         !response.isMember("00081199"))
     {
-      OrthancPlugins::Configuration::LogError("Unable to parse STOW-RS JSON response from DICOMweb server " + server.GetUrl());
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol);
+      throw Orthanc::OrthancException(
+        Orthanc::ErrorCode_NetworkProtocol,
+        "Unable to parse STOW-RS JSON response from DICOMweb server " + server.GetUrl());
     }
 
     size_t size;
     if (!GetSequenceSize(size, response, "00081199", true, server.GetUrl()) ||
         size != countInstances)
     {
-      OrthancPlugins::Configuration::LogError("The STOW-RS server was only able to receive " + 
-                                              boost::lexical_cast<std::string>(size) + " instances out of " +
-                                              boost::lexical_cast<std::string>(countInstances));
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol);
+      throw Orthanc::OrthancException(
+        Orthanc::ErrorCode_NetworkProtocol,
+        "The STOW-RS server was only able to receive " + 
+        boost::lexical_cast<std::string>(size) + " instances out of " +
+        boost::lexical_cast<std::string>(countInstances));
     }
 
     if (GetSequenceSize(size, response, "00081198", false, server.GetUrl()) &&
         size != 0)
     {
-      OrthancPlugins::Configuration::LogError("The response from the STOW-RS server contains " + 
-                                              boost::lexical_cast<std::string>(size) + 
-                                              " items in its Failed SOP Sequence (0008,1198) tag");
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol);    
+      throw Orthanc::OrthancException(
+        Orthanc::ErrorCode_NetworkProtocol,
+        "The response from the STOW-RS server contains " + 
+        boost::lexical_cast<std::string>(size) + 
+        " items in its Failed SOP Sequence (0008,1198) tag");
     }
 
     if (GetSequenceSize(size, response, "0008119A", false, server.GetUrl()) &&
         size != 0)
     {
-      OrthancPlugins::Configuration::LogError("The response from the STOW-RS server contains " + 
-                                              boost::lexical_cast<std::string>(size) + 
-                                              " items in its Other Failures Sequence (0008,119A) tag");
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol);    
+      throw Orthanc::OrthancException(
+        Orthanc::ErrorCode_NetworkProtocol,
+        "The response from the STOW-RS server contains " + 
+        boost::lexical_cast<std::string>(size) + 
+        " items in its Other Failures Sequence (0008,119A) tag");
     }
 
     countInstances = 0;
@@ -249,7 +254,7 @@
                 const char* /*url*/,
                 const OrthancPluginHttpRequest* request)
 {
-  OrthancPluginContext* context = OrthancPlugins::Configuration::GetContext();
+  OrthancPluginContext* context = OrthancPlugins::GetGlobalContext();
 
   if (request->groupsCount != 1)
   {
@@ -292,15 +297,15 @@
   std::list<std::string> instances;
   ParseStowRequest(instances, httpHeaders, queryArguments, request);
 
-  OrthancPlugins::Configuration::LogInfo("Sending " + boost::lexical_cast<std::string>(instances.size()) +
-                                         " instances using STOW-RS to DICOMweb server: " + server.GetUrl());
+  OrthancPlugins::LogInfo("Sending " + boost::lexical_cast<std::string>(instances.size()) +
+                          " instances using STOW-RS to DICOMweb server: " + server.GetUrl());
 
   Orthanc::ChunkedBuffer chunks;
   size_t countInstances = 0;
 
   for (std::list<std::string>::const_iterator it = instances.begin(); it != instances.end(); ++it)
   {
-    OrthancPlugins::MemoryBuffer dicom(context);
+    OrthancPlugins::MemoryBuffer dicom;
     if (dicom.RestApiGet("/instances/" + *it + "/file", false))
     {
       chunks.AddChunk("\r\n--" + boundary + "\r\n" +
@@ -336,8 +341,9 @@
   }
   else if (json[key].type() != Json::stringValue)
   {
-    OrthancPlugins::Configuration::LogError("The field \"" + key + "\" in a JSON object should be a string");
-    throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
+    throw Orthanc::OrthancException(
+      Orthanc::ErrorCode_BadFileFormat,
+      "The field \"" + key + "\" in a JSON object should be a string");
   }
   else
   {
@@ -355,7 +361,7 @@
   static const char* HTTP_HEADERS = "HttpHeaders";
   static const char* GET_ARGUMENTS = "Arguments";
 
-  OrthancPluginContext* context = OrthancPlugins::Configuration::GetContext();
+  OrthancPluginContext* context = OrthancPlugins::GetGlobalContext();
 
   if (request->method != OrthancPluginHttpMethod_Post)
   {
@@ -372,9 +378,9 @@
       body.type() != Json::objectValue ||
       !GetStringValue(tmp, body, URI))
   {
-    OrthancPlugins::Configuration::LogError("A request to the DICOMweb client must provide a JSON object "
-                                            "with the field \"Uri\" containing the URI of interest");
-    throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
+    throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat,
+                                    "A request to the DICOMweb client must provide a JSON object "
+                                    "with the field \"Uri\" containing the URI of interest");
   }
 
   std::map<std::string, std::string> getArguments;
@@ -386,7 +392,7 @@
   std::map<std::string, std::string> httpHeaders;
   OrthancPlugins::ParseAssociativeArray(httpHeaders, body, HTTP_HEADERS);
 
-  OrthancPlugins::MemoryBuffer answerBody(context);
+  OrthancPlugins::MemoryBuffer answerBody;
   std::map<std::string, std::string> answerHeaders;
   OrthancPlugins::CallServer(answerBody, answerHeaders, server, OrthancPluginHttpMethod_Get, httpHeaders, uri, "");
 
@@ -431,22 +437,20 @@
   static const std::string MULTIPART_RELATED = "multipart/related";
   static const std::string APPLICATION_DICOM = "application/dicom";
 
-  OrthancPluginContext* context = OrthancPlugins::Configuration::GetContext();
-
   if (resource.type() != Json::objectValue)
   {
-    OrthancPlugins::Configuration::LogError("Resources of interest for the DICOMweb WADO-RS Retrieve client "
-                                            "must be provided as a JSON object");
-    throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
+    throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat,
+                                    "Resources of interest for the DICOMweb WADO-RS Retrieve client "
+                                    "must be provided as a JSON object");
   }
 
   std::string study, series, instance;
   if (!GetStringValue(study, resource, STUDY) ||
       study.empty())
   {
-    OrthancPlugins::Configuration::LogError("A non-empty \"" + STUDY + "\" field is mandatory for the "
-                                            "DICOMweb WADO-RS Retrieve client");
-    throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
+    throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat,
+                                    "A non-empty \"" + STUDY + "\" field is mandatory for the "
+                                    "DICOMweb WADO-RS Retrieve client");
   }
 
   GetStringValue(series, resource, SERIES);
@@ -455,9 +459,10 @@
   if (series.empty() && 
       !instance.empty())
   {
-    OrthancPlugins::Configuration::LogError("When specifying a \"" + INSTANCE + "\" field in a call to DICOMweb "
-                                            "WADO-RS Retrieve client, the \"" + SERIES + "\" field is mandatory");
-    throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
+    throw Orthanc::OrthancException(
+      Orthanc::ErrorCode_BadFileFormat,
+      "When specifying a \"" + INSTANCE + "\" field in a call to DICOMweb "
+      "WADO-RS Retrieve client, the \"" + SERIES + "\" field is mandatory");
   }
 
   std::string tmpUri = "studies/" + study;
@@ -473,7 +478,7 @@
   std::string uri;
   OrthancPlugins::UriEncode(uri, tmpUri, getArguments);
 
-  OrthancPlugins::MemoryBuffer answerBody(context);
+  OrthancPlugins::MemoryBuffer answerBody;
   std::map<std::string, std::string> answerHeaders;
   OrthancPlugins::CallServer(answerBody, answerHeaders, server, OrthancPluginHttpMethod_Get, httpHeaders, uri, "");
 
@@ -492,21 +497,22 @@
     }
   }
 
-  OrthancPlugins::Configuration::LogInfo("Got " + boost::lexical_cast<std::string>(answerBody.GetSize()) +
-                                         " bytes from a WADO-RS query with content type: " + contentTypeFull);
+  OrthancPlugins::LogInfo("Got " + boost::lexical_cast<std::string>(answerBody.GetSize()) +
+                          " bytes from a WADO-RS query with content type: " + contentTypeFull);
   
   if (contentType.empty())
   {
-    OrthancPlugins::Configuration::LogError("No Content-Type provided by the remote WADO-RS server");
-    throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol);
+    throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol,
+                                    "No Content-Type provided by the remote WADO-RS server");
   }
 
   Orthanc::Toolbox::ToLowerCase(contentType[0]);
   if (Orthanc::Toolbox::StripSpaces(contentType[0]) != MULTIPART_RELATED)
   {
-    OrthancPlugins::Configuration::LogError("The remote WADO-RS server answers with a \"" + contentType[0] +
-                                            "\" Content-Type, but \"" + MULTIPART_RELATED + "\" is expected");
-    throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol);
+    throw Orthanc::OrthancException(
+      Orthanc::ErrorCode_NetworkProtocol,
+      "The remote WADO-RS server answers with a \"" + contentType[0] +
+      "\" Content-Type, but \"" + MULTIPART_RELATED + "\" is expected");
   }
 
   std::string type, boundary;
@@ -552,30 +558,32 @@
     boundary = boundary.substr(1, boundary.size() - 2);
   }
 
-  OrthancPlugins::Configuration::LogInfo("  Parsing the multipart content type: " + type +
-                                         " with boundary: " + boundary);
+  OrthancPlugins::LogInfo("  Parsing the multipart content type: " + type +
+                          " with boundary: " + boundary);
 
   if (type != APPLICATION_DICOM)
   {
-    OrthancPlugins::Configuration::LogError("The remote WADO-RS server answers with a \"" + type +
-                                            "\" multipart Content-Type, but \"" + APPLICATION_DICOM + "\" is expected");
-    throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol);
+    throw Orthanc::OrthancException(
+      Orthanc::ErrorCode_NetworkProtocol,
+      "The remote WADO-RS server answers with a \"" + type +
+      "\" multipart Content-Type, but \"" + APPLICATION_DICOM + "\" is expected");
   }
 
   if (boundary.empty())
   {
-    OrthancPlugins::Configuration::LogError("The remote WADO-RS server does not provide a boundary for its multipart answer");
-    throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol);
+    throw Orthanc::OrthancException(
+      Orthanc::ErrorCode_NetworkProtocol,
+      "The remote WADO-RS server does not provide a boundary for its multipart answer");
   }
 
   std::vector<OrthancPlugins::MultipartItem> parts;
-  OrthancPlugins::ParseMultipartBody(parts, context, 
+  OrthancPlugins::ParseMultipartBody(parts, 
                                      reinterpret_cast<const char*>(answerBody.GetData()),
                                      answerBody.GetSize(), boundary);
 
-  OrthancPlugins::Configuration::LogInfo("The remote WADO-RS server has provided " +
-                                         boost::lexical_cast<std::string>(parts.size()) + 
-                                         " DICOM instances");
+  OrthancPlugins::LogInfo("The remote WADO-RS server has provided " +
+                          boost::lexical_cast<std::string>(parts.size()) + 
+                          " DICOM instances");
 
   for (size_t i = 0; i < parts.size(); i++)
   {
@@ -590,13 +598,13 @@
 
     if (partType != APPLICATION_DICOM)
     {
-      OrthancPlugins::Configuration::LogError(
+      throw Orthanc::OrthancException(
+        Orthanc::ErrorCode_NetworkProtocol,
         "The remote WADO-RS server has provided a non-DICOM file in its multipart answer"
         " (content type: " + parts[i].contentType_ + ")");
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol);      
     }
 
-    OrthancPlugins::MemoryBuffer tmp(context);
+    OrthancPlugins::MemoryBuffer tmp;
     tmp.RestApiPost("/instances", parts[i].data_, parts[i].size_, false);
 
     Json::Value result;
@@ -625,7 +633,7 @@
   static const char* HTTP_HEADERS = "HttpHeaders";
   static const std::string GET_ARGUMENTS = "Arguments";
 
-  OrthancPluginContext* context = OrthancPlugins::Configuration::GetContext();
+  OrthancPluginContext* context = OrthancPlugins::GetGlobalContext();
 
   if (request->method != OrthancPluginHttpMethod_Post)
   {
@@ -642,9 +650,10 @@
       !body.isMember(RESOURCES) ||
       body[RESOURCES].type() != Json::arrayValue)
   {
-    OrthancPlugins::Configuration::LogError("A request to the DICOMweb WADO-RS Retrieve client must provide a JSON object "
-                                            "with the field \"" + RESOURCES + "\" containing an array of resources");
-    throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
+    throw Orthanc::OrthancException(
+      Orthanc::ErrorCode_BadFileFormat,
+      "A request to the DICOMweb WADO-RS Retrieve client must provide a JSON object "
+      "with the field \"" + RESOURCES + "\" containing an array of resources");
   }
 
   std::map<std::string, std::string> httpHeaders;
--- a/Plugin/DicomWebServers.cpp	Fri Nov 09 10:25:02 2018 +0100
+++ b/Plugin/DicomWebServers.cpp	Tue Dec 04 19:08:22 2018 +0100
@@ -65,15 +65,16 @@
     }
     catch (Orthanc::OrthancException& e)
     {
-      OrthancPlugins::Configuration::LogError("Exception while parsing the \"DicomWeb.Servers\" section "
-                                              "of the configuration file: " + std::string(e.What()));
+      OrthancPlugins::LogError("Exception while parsing the \"DicomWeb.Servers\" section "
+                               "of the configuration file: " + std::string(e.What()));
       throw;
     }
 
     if (!ok)
     {
-      OrthancPlugins::Configuration::LogError("Cannot parse the \"DicomWeb.Servers\" section of the configuration file");
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
+      throw Orthanc::OrthancException(
+        Orthanc::ErrorCode_BadFileFormat,
+        "Cannot parse the \"DicomWeb.Servers\" section of the configuration file");
     }
   }
 
@@ -93,8 +94,8 @@
     if (server == servers_.end() ||
         server->second == NULL)
     {
-      OrthancPlugins::Configuration::LogError("Inexistent server: " + name);
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_InexistentItem);
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_InexistentItem,
+                                      "Inexistent server: " + name);
     }
     else
     {
@@ -193,10 +194,10 @@
       bodySize = body.size();
     }
 
-    OrthancPluginContext* context = OrthancPlugins::Configuration::GetContext();
+    OrthancPluginContext* context = OrthancPlugins::GetGlobalContext();
 
     uint16_t status = 0;
-    MemoryBuffer answerHeadersTmp(context);
+    MemoryBuffer answerHeadersTmp;
     OrthancPluginErrorCode code = OrthancPluginHttpClient(
       context, 
       /* Outputs */
@@ -219,9 +220,10 @@
     if (code != OrthancPluginErrorCode_Success ||
         (status < 200 || status >= 300))
     {
-      OrthancPlugins::Configuration::LogError("Cannot issue an HTTP query to " + url + 
-                                              " (HTTP status: " + boost::lexical_cast<std::string>(status) + ")");
-      throw Orthanc::OrthancException(static_cast<Orthanc::ErrorCode>(code));
+      throw Orthanc::OrthancException(
+        static_cast<Orthanc::ErrorCode>(code),
+        "Cannot issue an HTTP query to " + url + 
+        " (HTTP status: " + boost::lexical_cast<std::string>(status) + ")");
     }
 
     Json::Value json;
@@ -256,9 +258,9 @@
   {
     if (resource.find('?') != std::string::npos)
     {
-      OrthancPlugins::Configuration::LogError("The GET arguments must be provided in a separate field "
-                                              "(explicit \"?\" is disallowed): " + resource);
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat,
+                                      "The GET arguments must be provided in a separate field "
+                                      "(explicit \"?\" is disallowed): " + resource);
     }
 
     uri = resource;
--- a/Plugin/Plugin.cpp	Fri Nov 09 10:25:02 2018 +0100
+++ b/Plugin/Plugin.cpp	Tue Dec 04 19:08:22 2018 +0100
@@ -59,7 +59,7 @@
       break;
 
     default:
-      OrthancPluginSendMethodNotAllowed(OrthancPlugins::Configuration::GetContext(), output, "GET,POST");
+      OrthancPluginSendMethodNotAllowed(OrthancPlugins::GetGlobalContext(), output, "GET,POST");
       break;
   }
 }
@@ -82,7 +82,7 @@
       break;
 
     default:
-      OrthancPluginSendMethodNotAllowed(OrthancPlugins::Configuration::GetContext(), output, "GET,POST");
+      OrthancPluginSendMethodNotAllowed(OrthancPlugins::GetGlobalContext(), output, "GET,POST");
       break;
   }
 }
@@ -102,7 +102,7 @@
                  const char* url,
                  const OrthancPluginHttpRequest* request)
 {
-  OrthancPluginContext* context = OrthancPlugins::Configuration::GetContext();
+  OrthancPluginContext* context = OrthancPlugins::GetGlobalContext();
 
   if (request->method != OrthancPluginHttpMethod_Get)
   {
@@ -150,7 +150,7 @@
                           const char* /*url*/,
                           const OrthancPluginHttpRequest* request)
 {
-  OrthancPluginContext* context = OrthancPlugins::Configuration::GetContext();
+  OrthancPluginContext* context = OrthancPlugins::GetGlobalContext();
 
   if (request->method != OrthancPluginHttpMethod_Get)
   {
@@ -186,6 +186,8 @@
   ORTHANC_PLUGINS_API int32_t OrthancPluginInitialize(OrthancPluginContext* context)
   {
     assert(DisplayPerformanceWarning(context));
+    OrthancPlugins::SetGlobalContext(context);
+    Orthanc::Logging::Initialize(context);
 
     /* Check the version of the Orthanc core */
     if (OrthancPluginCheckVersion(context) == 0)
@@ -205,7 +207,7 @@
     try
     {
       // Read the configuration
-      OrthancPlugins::Configuration::Initialize(context);
+      OrthancPlugins::Configuration::Initialize();
 
       // Initialize GDCM
       dictionary_ = &gdcm::Global::GetInstance().GetDicts().GetPublicDict();
@@ -216,57 +218,57 @@
         std::string root = OrthancPlugins::Configuration::GetRoot();
         assert(!root.empty() && root[root.size() - 1] == '/');
 
-        OrthancPlugins::Configuration::LogWarning("URI to the DICOMweb REST API: " + root);
+        OrthancPlugins::LogWarning("URI to the DICOMweb REST API: " + root);
 
-        OrthancPlugins::RegisterRestCallback<SearchForInstances>(context, root + "instances", true);
-        OrthancPlugins::RegisterRestCallback<SearchForSeries>(context, root + "series", true);    
-        OrthancPlugins::RegisterRestCallback<SwitchStudies>(context, root + "studies", true);
-        OrthancPlugins::RegisterRestCallback<SwitchStudy>(context, root + "studies/([^/]*)", true);
-        OrthancPlugins::RegisterRestCallback<SearchForInstances>(context, root + "studies/([^/]*)/instances", true);    
-        OrthancPlugins::RegisterRestCallback<RetrieveStudyMetadata>(context, root + "studies/([^/]*)/metadata", true);
-        OrthancPlugins::RegisterRestCallback<SearchForSeries>(context, root + "studies/([^/]*)/series", true);    
-        OrthancPlugins::RegisterRestCallback<RetrieveDicomSeries>(context, root + "studies/([^/]*)/series/([^/]*)", true);
-        OrthancPlugins::RegisterRestCallback<SearchForInstances>(context, root + "studies/([^/]*)/series/([^/]*)/instances", true);    
-        OrthancPlugins::RegisterRestCallback<RetrieveDicomInstance>(context, root + "studies/([^/]*)/series/([^/]*)/instances/([^/]*)", true);
-        OrthancPlugins::RegisterRestCallback<RetrieveBulkData>(context, root + "studies/([^/]*)/series/([^/]*)/instances/([^/]*)/bulk/(.*)", true);
-        OrthancPlugins::RegisterRestCallback<RetrieveInstanceMetadata>(context, root + "studies/([^/]*)/series/([^/]*)/instances/([^/]*)/metadata", true);
-        OrthancPlugins::RegisterRestCallback<RetrieveSeriesMetadata>(context, root + "studies/([^/]*)/series/([^/]*)/metadata", true);
-        OrthancPlugins::RegisterRestCallback<RetrieveFrames>(context, root + "studies/([^/]*)/series/([^/]*)/instances/([^/]*)/frames", true);
-        OrthancPlugins::RegisterRestCallback<RetrieveFrames>(context, root + "studies/([^/]*)/series/([^/]*)/instances/([^/]*)/frames/([^/]*)", true);
+        OrthancPlugins::RegisterRestCallback<SearchForInstances>(root + "instances", true);
+        OrthancPlugins::RegisterRestCallback<SearchForSeries>(root + "series", true);    
+        OrthancPlugins::RegisterRestCallback<SwitchStudies>(root + "studies", true);
+        OrthancPlugins::RegisterRestCallback<SwitchStudy>(root + "studies/([^/]*)", true);
+        OrthancPlugins::RegisterRestCallback<SearchForInstances>(root + "studies/([^/]*)/instances", true);    
+        OrthancPlugins::RegisterRestCallback<RetrieveStudyMetadata>(root + "studies/([^/]*)/metadata", true);
+        OrthancPlugins::RegisterRestCallback<SearchForSeries>(root + "studies/([^/]*)/series", true);    
+        OrthancPlugins::RegisterRestCallback<RetrieveDicomSeries>(root + "studies/([^/]*)/series/([^/]*)", true);
+        OrthancPlugins::RegisterRestCallback<SearchForInstances>(root + "studies/([^/]*)/series/([^/]*)/instances", true);    
+        OrthancPlugins::RegisterRestCallback<RetrieveDicomInstance>(root + "studies/([^/]*)/series/([^/]*)/instances/([^/]*)", true);
+        OrthancPlugins::RegisterRestCallback<RetrieveBulkData>(root + "studies/([^/]*)/series/([^/]*)/instances/([^/]*)/bulk/(.*)", true);
+        OrthancPlugins::RegisterRestCallback<RetrieveInstanceMetadata>(root + "studies/([^/]*)/series/([^/]*)/instances/([^/]*)/metadata", true);
+        OrthancPlugins::RegisterRestCallback<RetrieveSeriesMetadata>(root + "studies/([^/]*)/series/([^/]*)/metadata", true);
+        OrthancPlugins::RegisterRestCallback<RetrieveFrames>(root + "studies/([^/]*)/series/([^/]*)/instances/([^/]*)/frames", true);
+        OrthancPlugins::RegisterRestCallback<RetrieveFrames>(root + "studies/([^/]*)/series/([^/]*)/instances/([^/]*)/frames/([^/]*)", true);
 
-        OrthancPlugins::RegisterRestCallback<ListServers>(context, root + "servers", true);
-        OrthancPlugins::RegisterRestCallback<ListServerOperations>(context, root + "servers/([^/]*)", true);
-        OrthancPlugins::RegisterRestCallback<StowClient>(context, root + "servers/([^/]*)/stow", true);
-        OrthancPlugins::RegisterRestCallback<GetFromServer>(context, root + "servers/([^/]*)/get", true);
-        OrthancPlugins::RegisterRestCallback<RetrieveFromServer>(context, root + "servers/([^/]*)/retrieve", true);
+        OrthancPlugins::RegisterRestCallback<ListServers>(root + "servers", true);
+        OrthancPlugins::RegisterRestCallback<ListServerOperations>(root + "servers/([^/]*)", true);
+        OrthancPlugins::RegisterRestCallback<StowClient>(root + "servers/([^/]*)/stow", true);
+        OrthancPlugins::RegisterRestCallback<GetFromServer>(root + "servers/([^/]*)/get", true);
+        OrthancPlugins::RegisterRestCallback<RetrieveFromServer>(root + "servers/([^/]*)/retrieve", true);
       }
       else
       {
-        OrthancPlugins::Configuration::LogWarning("DICOMweb support is disabled");
+        OrthancPlugins::LogWarning("DICOMweb support is disabled");
       }
 
       // Configure the WADO callback
       if (OrthancPlugins::Configuration::GetBooleanValue("EnableWado", true))
       {
         std::string wado = OrthancPlugins::Configuration::GetWadoRoot();
-        OrthancPlugins::Configuration::LogWarning("URI to the WADO-URI API: " + wado);
+        OrthancPlugins::LogWarning("URI to the WADO-URI API: " + wado);
 
-        OrthancPlugins::RegisterRestCallback<WadoUriCallback>(context, wado, true);
+        OrthancPlugins::RegisterRestCallback<WadoUriCallback>(wado, true);
       }
       else
       {
-        OrthancPlugins::Configuration::LogWarning("WADO-URI support is disabled");
+        OrthancPlugins::LogWarning("WADO-URI support is disabled");
       }
     }
     catch (Orthanc::OrthancException& e)
     {
-      OrthancPlugins::Configuration::LogError("Exception while initializing the DICOMweb plugin: " + 
-                                              std::string(e.What()));
+      OrthancPlugins::LogError("Exception while initializing the DICOMweb plugin: " + 
+                               std::string(e.What()));
       return -1;
     }
     catch (...)
     {
-      OrthancPlugins::Configuration::LogError("Exception while initializing the DICOMweb plugin");
+      OrthancPlugins::LogError("Exception while initializing the DICOMweb plugin");
       return -1;
     }
 
--- a/Plugin/QidoRs.cpp	Fri Nov 09 10:25:02 2018 +0100
+++ b/Plugin/QidoRs.cpp	Tue Dec 04 19:08:22 2018 +0100
@@ -192,8 +192,9 @@
           }
           else
           {
-            OrthancPlugins::Configuration::LogError("Not a proper value for fuzzy matching (true or false): " + value);
-            throw Orthanc::OrthancException(Orthanc::ErrorCode_BadRequest);
+            throw Orthanc::OrthancException(
+              Orthanc::ErrorCode_BadRequest,
+              "Not a proper value for fuzzy matching (true or false): " + value);
           }
         }
         else if (key == "includefield")
@@ -219,7 +220,7 @@
         }
       }
 
-      OrthancPlugins::Configuration::LogInfo("Arguments of QIDO-RS request:" + args);
+      OrthancPlugins::LogInfo("Arguments of QIDO-RS request:" + args);
     }
 
     unsigned int GetLimit() const
@@ -277,10 +278,9 @@
       result["Since"] = offset_;
 
       if (offset_ != 0 &&
-          !OrthancPlugins::CheckMinimalOrthancVersion(
-            OrthancPlugins::Configuration::GetContext(), 1, 3, 0))
+          !OrthancPlugins::CheckMinimalOrthancVersion(1, 3, 0))
       {
-        OrthancPlugins::Configuration::LogError(
+        OrthancPlugins::LogError(
           "QIDO-RS request with \"offset\" argument: "
           "Only available if the Orthanc core version is >= 1.3.0");
       }
@@ -297,8 +297,6 @@
                             QueryLevel level,
                             const std::string& resource) const
     {
-      OrthancPluginContext* context = OrthancPlugins::Configuration::GetContext();
-
       target.clear();
 
       switch (level)
@@ -306,8 +304,8 @@
         case QueryLevel_Study:
         {
           Json::Value series, instances;
-          if (OrthancPlugins::RestApiGet(series, context, "/studies/" + resource + "/series?expand", false) &&
-              OrthancPlugins::RestApiGet(instances, context, "/studies/" + resource + "/instances", false))
+          if (OrthancPlugins::RestApiGet(series, "/studies/" + resource + "/series?expand", false) &&
+              OrthancPlugins::RestApiGet(instances, "/studies/" + resource + "/instances", false))
           {
             // Number of Study Related Series
             target[gdcm::Tag(0x0020, 0x1206)] = boost::lexical_cast<std::string>(series.size());
@@ -353,7 +351,7 @@
         case QueryLevel_Series:
         {
           Json::Value instances;
-          if (OrthancPlugins::RestApiGet(instances, context, "/series/" + resource + "/instances", false))
+          if (OrthancPlugins::RestApiGet(instances, "/series/" + resource + "/instances", false))
           {
             // Number of Series Related Instances
             target[gdcm::Tag(0x0020, 0x1209)] = boost::lexical_cast<std::string>(instances.size());
@@ -516,8 +514,6 @@
                          const ModuleMatcher& matcher,
                          QueryLevel level)
 {
-  OrthancPluginContext* context = OrthancPlugins::Configuration::GetContext();
-
   Json::Value find;
   matcher.ConvertToOrthanc(find, level);
 
@@ -525,7 +521,7 @@
   std::string body = writer.write(find);
   
   Json::Value resources;
-  if (!OrthancPlugins::RestApiPost(resources, context, "/tools/find", body, false) ||
+  if (!OrthancPlugins::RestApiPost(resources, "/tools/find", body, false) ||
       resources.type() != Json::arrayValue)
   {
     throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
@@ -545,7 +541,7 @@
     {
       // Find one child instance of this resource
       Json::Value tmp;
-      if (OrthancPlugins::RestApiGet(tmp, context, root + resource + "/instances", false) &&
+      if (OrthancPlugins::RestApiGet(tmp, root + resource + "/instances", false) &&
           tmp.type() == Json::arrayValue &&
           tmp.size() > 0)
       {
@@ -560,7 +556,7 @@
   
   std::string wadoBase = OrthancPlugins::Configuration::GetBaseUrl(request);
 
-  OrthancPlugins::DicomResults results(context, output, wadoBase, *dictionary_, IsXmlExpected(request), true);
+  OrthancPlugins::DicomResults results(output, wadoBase, *dictionary_, IsXmlExpected(request), true);
 
 #if 0
   // Implementation up to version 0.2 of the plugin. Each instance is
@@ -603,7 +599,7 @@
          it = resourcesAndInstances.begin(); it != resourcesAndInstances.end(); ++it)
   {
     Json::Value tags;
-    if (OrthancPlugins::RestApiGet(tags, context, "/instances/" + it->second + "/tags", false))
+    if (OrthancPlugins::RestApiGet(tags, "/instances/" + it->second + "/tags", false))
     {
       std::string wadoUrl = OrthancPlugins::Configuration::GetWadoUrl(
         wadoBase, 
@@ -644,7 +640,7 @@
 {
   if (request->method != OrthancPluginHttpMethod_Get)
   {
-    OrthancPluginSendMethodNotAllowed(OrthancPlugins::Configuration::GetContext(), output, "GET");
+    OrthancPluginSendMethodNotAllowed(OrthancPlugins::GetGlobalContext(), output, "GET");
   }
   else
   {
@@ -660,7 +656,7 @@
 {
   if (request->method != OrthancPluginHttpMethod_Get)
   {
-    OrthancPluginSendMethodNotAllowed(OrthancPlugins::Configuration::GetContext(), output, "GET");
+    OrthancPluginSendMethodNotAllowed(OrthancPlugins::GetGlobalContext(), output, "GET");
   }
   else
   {
@@ -683,7 +679,7 @@
 {
   if (request->method != OrthancPluginHttpMethod_Get)
   {
-    OrthancPluginSendMethodNotAllowed(OrthancPlugins::Configuration::GetContext(), output, "GET");
+    OrthancPluginSendMethodNotAllowed(OrthancPlugins::GetGlobalContext(), output, "GET");
   }
   else
   {
--- a/Plugin/StowRs.cpp	Fri Nov 09 10:25:02 2018 +0100
+++ b/Plugin/StowRs.cpp	Tue Dec 04 19:08:22 2018 +0100
@@ -80,8 +80,8 @@
   }
   else
   {
-    OrthancPlugins::Configuration::LogError("Unsupported return MIME type: " + accept +
-                                            ", will return DICOM+JSON");
+    OrthancPlugins::LogError("Unsupported return MIME type: " + accept +
+                             ", will return DICOM+JSON");
     return false;
   }
 }
@@ -92,7 +92,7 @@
                   const char* url,
                   const OrthancPluginHttpRequest* request)
 {
-  OrthancPluginContext* context = OrthancPlugins::Configuration::GetContext();
+  OrthancPluginContext* context = OrthancPlugins::GetGlobalContext();
 
   const std::string wadoBase = OrthancPlugins::Configuration::GetBaseUrl(request);
 
@@ -110,11 +110,11 @@
 
   if (expectedStudy.empty())
   {
-    OrthancPlugins::Configuration::LogInfo("STOW-RS request without study");
+    OrthancPlugins::LogInfo("STOW-RS request without study");
   }
   else
   {
-    OrthancPlugins::Configuration::LogInfo("STOW-RS request restricted to study UID " + expectedStudy);
+    OrthancPlugins::LogInfo("STOW-RS request restricted to study UID " + expectedStudy);
   }
 
   bool isXml = IsXmlExpected(request);
@@ -122,7 +122,7 @@
   std::string header;
   if (!OrthancPlugins::LookupHttpHeader(header, request, "content-type"))
   {
-    OrthancPlugins::Configuration::LogError("No content type in the HTTP header of a STOW-RS request");
+    OrthancPlugins::LogError("No content type in the HTTP header of a STOW-RS request");
     OrthancPluginSendHttpStatusCode(context, output, 400 /* Bad request */);
     return;
   }
@@ -135,7 +135,7 @@
       attributes.find("type") == attributes.end() ||
       attributes.find("boundary") == attributes.end())
   {
-    OrthancPlugins::Configuration::LogError("Unable to parse the content type of a STOW-RS request (" + application + ")");
+    OrthancPlugins::LogError("Unable to parse the content type of a STOW-RS request (" + application + ")");
     OrthancPluginSendHttpStatusCode(context, output, 400 /* Bad request */);
     return;
   }
@@ -145,7 +145,7 @@
 
   if (attributes["type"] != "application/dicom")
   {
-    OrthancPlugins::Configuration::LogError("The STOW-RS plugin currently only supports application/dicom");
+    OrthancPlugins::LogError("The STOW-RS plugin currently only supports application/dicom");
     OrthancPluginSendHttpStatusCode(context, output, 415 /* Unsupported media type */);
     return;
   }
@@ -157,13 +157,13 @@
   gdcm::SmartPointer<gdcm::SequenceOfItems> failed = new gdcm::SequenceOfItems();
   
   std::vector<OrthancPlugins::MultipartItem> items;
-  OrthancPlugins::ParseMultipartBody(items, context, request->body, request->bodySize, boundary);
+  OrthancPlugins::ParseMultipartBody(items, request->body, request->bodySize, boundary);
 
   for (size_t i = 0; i < items.size(); i++)
   {
-    OrthancPlugins::Configuration::LogInfo("Detected multipart item with content type \"" + 
-                                           items[i].contentType_ + "\" of size " + 
-                                           boost::lexical_cast<std::string>(items[i].size_));
+    OrthancPlugins::LogInfo("Detected multipart item with content type \"" + 
+                            items[i].contentType_ + "\" of size " + 
+                            boost::lexical_cast<std::string>(items[i].size_));
   }  
 
   for (size_t i = 0; i < items.size(); i++)
@@ -171,8 +171,8 @@
     if (!items[i].contentType_.empty() &&
         items[i].contentType_ != "application/dicom")
     {
-      OrthancPlugins::Configuration::LogError("The STOW-RS request contains a part that is not "
-                                              "\"application/dicom\" (it is: \"" + items[i].contentType_ + "\")");
+      OrthancPlugins::LogError("The STOW-RS request contains a part that is not "
+                               "\"application/dicom\" (it is: \"" + items[i].contentType_ + "\")");
       OrthancPluginSendHttpStatusCode(context, output, 415 /* Unsupported media type */);
       return;
     }
@@ -193,8 +193,8 @@
     if (!expectedStudy.empty() &&
         studyInstanceUid != expectedStudy)
     {
-      OrthancPlugins::Configuration::LogInfo("STOW-RS request restricted to study [" + expectedStudy + 
-                                             "]: Ignoring instance from study [" + studyInstanceUid + "]");
+      OrthancPlugins::LogInfo("STOW-RS request restricted to study [" + expectedStudy + 
+                              "]: Ignoring instance from study [" + studyInstanceUid + "]");
 
       SetTag(status, OrthancPlugins::DICOM_TAG_WARNING_REASON, gdcm::VR::US, "B006");  // Elements discarded
       success->AddItem(item);      
@@ -208,7 +208,7 @@
         isFirst = false;
       }
 
-      OrthancPlugins::MemoryBuffer tmp(context);
+      OrthancPlugins::MemoryBuffer tmp;
       bool ok = tmp.RestApiPost("/instances", items[i].data_, items[i].size_, false);
       tmp.Clear();
 
@@ -224,7 +224,7 @@
       }
       else
       {
-        OrthancPlugins::Configuration::LogError("Orthanc was unable to store instance through STOW-RS request");
+        OrthancPlugins::LogError("Orthanc was unable to store instance through STOW-RS request");
         SetTag(status, OrthancPlugins::DICOM_TAG_FAILURE_REASON, gdcm::VR::US, "0110");  // Processing failure
         failed->AddItem(item);
       }
@@ -234,5 +234,5 @@
   SetSequenceTag(result, OrthancPlugins::DICOM_TAG_FAILED_SOP_SEQUENCE, failed);
   SetSequenceTag(result, OrthancPlugins::DICOM_TAG_REFERENCED_SOP_SEQUENCE, success);
 
-  OrthancPlugins::AnswerDicom(context, output, wadoBase, *dictionary_, result, isXml, false);
+  OrthancPlugins::AnswerDicom(output, wadoBase, *dictionary_, result, isXml, false);
 }
--- a/Plugin/WadoRs.cpp	Fri Nov 09 10:25:02 2018 +0100
+++ b/Plugin/WadoRs.cpp	Tue Dec 04 19:08:22 2018 +0100
@@ -45,7 +45,7 @@
   if (application != "multipart/related" &&
       application != "*/*")
   {
-    OrthancPlugins::Configuration::LogError("This WADO-RS plugin cannot generate the following content type: " + accept);
+    OrthancPlugins::LogError("This WADO-RS plugin cannot generate the following content type: " + accept);
     return false;
   }
 
@@ -55,16 +55,16 @@
     Orthanc::Toolbox::ToLowerCase(s);
     if (s != "application/dicom")
     {
-      OrthancPlugins::Configuration::LogError("This WADO-RS plugin only supports application/dicom "
-                                              "return type for DICOM retrieval (" + accept + ")");
+      OrthancPlugins::LogError("This WADO-RS plugin only supports application/dicom "
+                               "return type for DICOM retrieval (" + accept + ")");
       return false;
     }
   }
 
   if (attributes.find("transfer-syntax") != attributes.end())
   {
-    OrthancPlugins::Configuration::LogError("This WADO-RS plugin cannot change the transfer syntax to " + 
-                                            attributes["transfer-syntax"]);
+    OrthancPlugins::LogError("This WADO-RS plugin cannot change the transfer syntax to " + 
+                             attributes["transfer-syntax"]);
     return false;
   }
 
@@ -97,7 +97,7 @@
 
   if (application != "multipart/related")
   {
-    OrthancPlugins::Configuration::LogError("This WADO-RS plugin cannot generate the following content type: " + accept);
+    OrthancPlugins::LogError("This WADO-RS plugin cannot generate the following content type: " + accept);
     return false;
   }
 
@@ -111,21 +111,21 @@
     }
     else
     {
-      OrthancPlugins::Configuration::LogError("This WADO-RS plugin only supports application/dicom+xml "
-                                              "type for multipart/related accept (" + accept + ")");
+      OrthancPlugins::LogError("This WADO-RS plugin only supports application/dicom+xml "
+                               "type for multipart/related accept (" + accept + ")");
       return false;
     }
   }
   else
   {
-    OrthancPlugins::Configuration::LogError("Missing \"type\" in multipart/related accept type (" + accept + ")");
+    OrthancPlugins::LogError("Missing \"type\" in multipart/related accept type (" + accept + ")");
     return false;
   }
 
   if (attributes.find("transfer-syntax") != attributes.end())
   {
-    OrthancPlugins::Configuration::LogError("This WADO-RS plugin cannot change the transfer syntax to " + 
-                                            attributes["transfer-syntax"]);
+    OrthancPlugins::LogError("This WADO-RS plugin cannot change the transfer syntax to " + 
+                             attributes["transfer-syntax"]);
     return false;
   }
 
@@ -150,7 +150,7 @@
   if (application != "multipart/related" &&
       application != "*/*")
   {
-    OrthancPlugins::Configuration::LogError("This WADO-RS plugin cannot generate the following bulk data type: " + accept);
+    OrthancPlugins::LogError("This WADO-RS plugin cannot generate the following bulk data type: " + accept);
     return false;
   }
 
@@ -160,16 +160,16 @@
     Orthanc::Toolbox::ToLowerCase(s);
     if (s != "application/octet-stream")
     {
-      OrthancPlugins::Configuration::LogError("This WADO-RS plugin only supports application/octet-stream "
-                                              "return type for bulk data retrieval (" + accept + ")");
+      OrthancPlugins::LogError("This WADO-RS plugin only supports application/octet-stream "
+                               "return type for bulk data retrieval (" + accept + ")");
       return false;
     }
   }
 
   if (attributes.find("ra,ge") != attributes.end())
   {
-    OrthancPlugins::Configuration::LogError("This WADO-RS plugin does not support Range retrieval, "
-                                            "it can only return entire bulk data object");
+    OrthancPlugins::LogError("This WADO-RS plugin does not support Range retrieval, "
+                             "it can only return entire bulk data object");
     return false;
   }
 
@@ -180,10 +180,10 @@
 static void AnswerListOfDicomInstances(OrthancPluginRestOutput* output,
                                        const std::string& resource)
 {
-  OrthancPluginContext* context = OrthancPlugins::Configuration::GetContext();
+  OrthancPluginContext* context = OrthancPlugins::GetGlobalContext();
 
   Json::Value instances;
-  if (!OrthancPlugins::RestApiGet(instances, context, resource + "/instances", false))
+  if (!OrthancPlugins::RestApiGet(instances, resource + "/instances", false))
   {
     // Internal error
     OrthancPluginSendHttpStatusCode(context, output, 400);
@@ -199,7 +199,7 @@
   {
     std::string uri = "/instances/" + instances[i]["ID"].asString() + "/file";
 
-    OrthancPlugins::MemoryBuffer dicom(context);
+    OrthancPlugins::MemoryBuffer dicom;
     if (dicom.RestApiGet(uri, false) &&
         OrthancPluginSendMultipartItem(context, output, dicom.GetData(), dicom.GetSize()) != 0)
     {
@@ -216,7 +216,7 @@
                            bool isInstance,
                            bool isXml)
 {
-  OrthancPluginContext* context = OrthancPlugins::Configuration::GetContext();
+  OrthancPluginContext* context = OrthancPlugins::GetGlobalContext();
 
   std::list<std::string> files;
   if (isInstance)
@@ -226,7 +226,7 @@
   else
   {
     Json::Value instances;
-    if (!OrthancPlugins::RestApiGet(instances, context, resource + "/instances", false))
+    if (!OrthancPlugins::RestApiGet(instances, resource + "/instances", false))
     {
       // Internal error
       OrthancPluginSendHttpStatusCode(context, output, 400);
@@ -240,12 +240,12 @@
   }
 
   const std::string wadoBase = OrthancPlugins::Configuration::GetBaseUrl(request);
-  OrthancPlugins::DicomResults results(context, output, wadoBase, *dictionary_, isXml, true);
+  OrthancPlugins::DicomResults results(output, wadoBase, *dictionary_, isXml, true);
   
   for (std::list<std::string>::const_iterator
          it = files.begin(); it != files.end(); ++it)
   {
-    OrthancPlugins::MemoryBuffer content(context);
+    OrthancPlugins::MemoryBuffer content;
     if (content.RestApiGet(*it, false))
     {
       OrthancPlugins::ParsedDicomFile dicom(content);
@@ -263,7 +263,7 @@
                         std::string& uri,
                         const OrthancPluginHttpRequest* request)
 {
-  OrthancPluginContext* context = OrthancPlugins::Configuration::GetContext();
+  OrthancPluginContext* context = OrthancPlugins::GetGlobalContext();
 
   if (request->method != OrthancPluginHttpMethod_Get)
   {
@@ -277,7 +277,7 @@
     char* tmp = OrthancPluginLookupStudy(context, request->groups[0]);
     if (tmp == NULL)
     {
-      OrthancPlugins::Configuration::LogError("Accessing an inexistent study with WADO-RS: " + std::string(request->groups[0]));
+      OrthancPlugins::LogError("Accessing an inexistent study with WADO-RS: " + std::string(request->groups[0]));
       OrthancPluginSendHttpStatusCode(context, output, 404);
       return false;
     }
@@ -295,7 +295,7 @@
                          std::string& uri,
                          const OrthancPluginHttpRequest* request)
 {
-  OrthancPluginContext* context = OrthancPlugins::Configuration::GetContext();
+  OrthancPluginContext* context = OrthancPlugins::GetGlobalContext();
 
   if (request->method != OrthancPluginHttpMethod_Get)
   {
@@ -309,7 +309,7 @@
     char* tmp = OrthancPluginLookupSeries(context, request->groups[1]);
     if (tmp == NULL)
     {
-      OrthancPlugins::Configuration::LogError("Accessing an inexistent series with WADO-RS: " + std::string(request->groups[1]));
+      OrthancPlugins::LogError("Accessing an inexistent series with WADO-RS: " + std::string(request->groups[1]));
       OrthancPluginSendHttpStatusCode(context, output, 404);
       return false;
     }
@@ -319,7 +319,7 @@
   }
   
   Json::Value study;
-  if (!OrthancPlugins::RestApiGet(study, context, "/series/" + id + "/study", false))
+  if (!OrthancPlugins::RestApiGet(study, "/series/" + id + "/study", false))
   {
     OrthancPluginSendHttpStatusCode(context, output, 404);
     return false;
@@ -327,8 +327,8 @@
 
   if (study["MainDicomTags"]["StudyInstanceUID"].asString() != std::string(request->groups[0]))
   {
-    OrthancPlugins::Configuration::LogError("No series " + std::string(request->groups[1]) + 
-                                            " in study " + std::string(request->groups[0]));
+    OrthancPlugins::LogError("No series " + std::string(request->groups[1]) + 
+                             " in study " + std::string(request->groups[0]));
     OrthancPluginSendHttpStatusCode(context, output, 404);
     return false;
   }
@@ -342,7 +342,7 @@
                     std::string& uri,
                     const OrthancPluginHttpRequest* request)
 {
-  OrthancPluginContext* context = OrthancPlugins::Configuration::GetContext();
+  OrthancPluginContext* context = OrthancPlugins::GetGlobalContext();
 
   if (request->method != OrthancPluginHttpMethod_Get)
   {
@@ -356,8 +356,8 @@
     char* tmp = OrthancPluginLookupInstance(context, request->groups[2]);
     if (tmp == NULL)
     {
-      OrthancPlugins::Configuration::LogError("Accessing an inexistent instance with WADO-RS: " + 
-                                              std::string(request->groups[2]));
+      OrthancPlugins::LogError("Accessing an inexistent instance with WADO-RS: " + 
+                               std::string(request->groups[2]));
       OrthancPluginSendHttpStatusCode(context, output, 404);
       return false;
     }
@@ -367,8 +367,8 @@
   }
   
   Json::Value study, series;
-  if (!OrthancPlugins::RestApiGet(series, context, "/instances/" + id + "/series", false) ||
-      !OrthancPlugins::RestApiGet(study, context, "/instances/" + id + "/study", false))
+  if (!OrthancPlugins::RestApiGet(series, "/instances/" + id + "/series", false) ||
+      !OrthancPlugins::RestApiGet(study, "/instances/" + id + "/study", false))
   {
     OrthancPluginSendHttpStatusCode(context, output, 404);
     return false;
@@ -377,9 +377,9 @@
   if (study["MainDicomTags"]["StudyInstanceUID"].asString() != std::string(request->groups[0]) ||
       series["MainDicomTags"]["SeriesInstanceUID"].asString() != std::string(request->groups[1]))
   {
-    OrthancPlugins::Configuration::LogError("No instance " + std::string(request->groups[2]) + 
-                                            " in study " + std::string(request->groups[0]) + " or " +
-                                            " in series " + std::string(request->groups[1]));
+    OrthancPlugins::LogError("No instance " + std::string(request->groups[2]) + 
+                             " in study " + std::string(request->groups[0]) + " or " +
+                             " in series " + std::string(request->groups[1]));
     OrthancPluginSendHttpStatusCode(context, output, 404);
     return false;
   }
@@ -395,7 +395,7 @@
 {
   if (!AcceptMultipartDicom(request))
   {
-    OrthancPluginSendHttpStatusCode(OrthancPlugins::Configuration::GetContext(), output, 400 /* Bad request */);
+    OrthancPluginSendHttpStatusCode(OrthancPlugins::GetGlobalContext(), output, 400 /* Bad request */);
   }
   else
   {
@@ -414,7 +414,7 @@
 {
   if (!AcceptMultipartDicom(request))
   {
-    OrthancPluginSendHttpStatusCode(OrthancPlugins::Configuration::GetContext(), output, 400 /* Bad request */);
+    OrthancPluginSendHttpStatusCode(OrthancPlugins::GetGlobalContext(), output, 400 /* Bad request */);
   }
   else
   {
@@ -432,7 +432,7 @@
                            const char* url,
                            const OrthancPluginHttpRequest* request)
 {
-  OrthancPluginContext* context = OrthancPlugins::Configuration::GetContext();
+  OrthancPluginContext* context = OrthancPlugins::GetGlobalContext();
 
   if (!AcceptMultipartDicom(request))
   {
@@ -448,7 +448,7 @@
         throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol);
       }
 
-      OrthancPlugins::MemoryBuffer dicom(context);
+      OrthancPlugins::MemoryBuffer dicom;
       if (dicom.RestApiGet(uri + "/file", false) &&
           OrthancPluginSendMultipartItem(context, output, dicom.GetData(), dicom.GetSize()) != 0)
       {
@@ -467,7 +467,7 @@
   bool isXml;
   if (!AcceptMetadata(request, isXml))
   {
-    OrthancPluginSendHttpStatusCode(OrthancPlugins::Configuration::GetContext(), output, 400 /* Bad request */);
+    OrthancPluginSendHttpStatusCode(OrthancPlugins::GetGlobalContext(), output, 400 /* Bad request */);
   }
   else
   {
@@ -487,7 +487,7 @@
   bool isXml;
   if (!AcceptMetadata(request, isXml))
   {
-    OrthancPluginSendHttpStatusCode(OrthancPlugins::Configuration::GetContext(), output, 400 /* Bad request */);
+    OrthancPluginSendHttpStatusCode(OrthancPlugins::GetGlobalContext(), output, 400 /* Bad request */);
   }
   else
   {
@@ -507,7 +507,7 @@
   bool isXml;
   if (!AcceptMetadata(request, isXml))
   {
-    OrthancPluginSendHttpStatusCode(OrthancPlugins::Configuration::GetContext(), output, 400 /* Bad request */);
+    OrthancPluginSendHttpStatusCode(OrthancPlugins::GetGlobalContext(), output, 400 /* Bad request */);
   }
   else
   {
@@ -596,7 +596,7 @@
                       const char* url,
                       const OrthancPluginHttpRequest* request)
 {
-  OrthancPluginContext* context = OrthancPlugins::Configuration::GetContext();
+  OrthancPluginContext* context = OrthancPlugins::GetGlobalContext();
 
   if (!AcceptBulkData(request))
   {
@@ -605,7 +605,7 @@
   }
 
   std::string uri;
-  OrthancPlugins::MemoryBuffer content(context);
+  OrthancPlugins::MemoryBuffer content;
   if (LocateInstance(output, uri, request) &&
       content.RestApiGet(uri + "/file", false))
   {
--- a/Plugin/WadoRsRetrieveFrames.cpp	Fri Nov 09 10:25:02 2018 +0100
+++ b/Plugin/WadoRsRetrieveFrames.cpp	Tue Dec 04 19:08:22 2018 +0100
@@ -105,9 +105,10 @@
         }
         else
         {
-          OrthancPlugins::Configuration::LogError("DICOMweb RetrieveFrames: Cannot specify a transfer syntax (" + 
-                                                  transferSyntax + ") for default Little Endian uncompressed pixel data");
-          throw Orthanc::OrthancException(Orthanc::ErrorCode_BadRequest);
+          throw Orthanc::OrthancException(
+            Orthanc::ErrorCode_BadRequest,
+            "DICOMweb RetrieveFrames: Cannot specify a transfer syntax (" + 
+            transferSyntax + ") for default Little Endian uncompressed pixel data");
         }
       }
       else
@@ -221,10 +222,10 @@
           return gdcm::TransferSyntax::JPEG2000Part2;
         }
 
-
-        OrthancPlugins::Configuration::LogError("DICOMweb RetrieveFrames: Transfer syntax \"" + 
-                                                  transferSyntax + "\" is incompatible with media type \"" + type + "\"");
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_BadRequest);
+        throw Orthanc::OrthancException(
+          Orthanc::ErrorCode_BadRequest,
+          "DICOMweb RetrieveFrames: Transfer syntax \"" + 
+          transferSyntax + "\" is incompatible with media type \"" + type + "\"");
       }
     }
   }
@@ -257,8 +258,8 @@
     int frame = boost::lexical_cast<int>(tokens[i]);
     if (frame <= 0)
     {
-      OrthancPlugins::Configuration::LogError("Invalid frame number (must be > 0): " + tokens[i]);
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange,
+                                      "Invalid frame number (must be > 0): " + tokens[i]);
     }
 
     frames.push_back(static_cast<unsigned int>(frame - 1));
@@ -329,9 +330,9 @@
   std::string location = dicom.GetWadoUrl(request) + "frames/" + boost::lexical_cast<std::string>(frameIndex + 1);
   const char *keys[] = { "Content-Location" };
   const char *values[] = { location.c_str() };
-  error = OrthancPluginSendMultipartItem2(OrthancPlugins::Configuration::GetContext(), output, frame, size, 1, keys, values);
+  error = OrthancPluginSendMultipartItem2(OrthancPlugins::GetGlobalContext(), output, frame, size, 1, keys, values);
 #else
-  error = OrthancPluginSendMultipartItem(OrthancPlugins::Configuration::GetContext(), output, frame, size);
+  error = OrthancPluginSendMultipartItem(OrthancPlugins::GetGlobalContext(), output, frame, size);
 #endif
 
   if (error != OrthancPluginErrorCode_Success)
@@ -356,7 +357,7 @@
   const gdcm::DataElement& pixelData = dicom.GetDataSet().GetDataElement(OrthancPlugins::DICOM_TAG_PIXEL_DATA);
   const gdcm::SequenceOfFragments* fragments = pixelData.GetSequenceOfFragments();
 
-  if (OrthancPluginStartMultipartAnswer(OrthancPlugins::Configuration::GetContext(), 
+  if (OrthancPluginStartMultipartAnswer(OrthancPlugins::GetGlobalContext(), 
                                         output, "related", GetMimeType(syntax)) != OrthancPluginErrorCode_Success)
   {
     return false;
@@ -368,8 +369,8 @@
 
     if (pixelData.GetByteValue() == NULL)
     {
-      OrthancPlugins::Configuration::LogError("Image was not properly decoded");
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);      
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError,
+                                      "Image was not properly decoded");
     }
 
     int width, height, bits, samplesPerPixel;
@@ -408,9 +409,10 @@
     {
       if (*frame >= framesCount)
       {
-        OrthancPlugins::Configuration::LogError("Trying to access frame number " + boost::lexical_cast<std::string>(*frame + 1) + 
-                                                " of an image with " + boost::lexical_cast<std::string>(framesCount) + " frames");
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
+        throw Orthanc::OrthancException(
+          Orthanc::ErrorCode_ParameterOutOfRange,
+          "Trying to access frame number " + boost::lexical_cast<std::string>(*frame + 1) + 
+          " of an image with " + boost::lexical_cast<std::string>(framesCount) + " frames");
       }
       else
       {
@@ -438,12 +440,13 @@
       if (*frame >= fragments->GetNumberOfFragments())
       {
         // TODO A frame is not a fragment, looks like a bug
-        OrthancPlugins::Configuration::LogError("Trying to access frame number " + 
-                                                boost::lexical_cast<std::string>(*frame + 1) + 
-                                                " of an image with " + 
-                                                boost::lexical_cast<std::string>(fragments->GetNumberOfFragments()) + 
-                                                " frames");
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
+        throw Orthanc::OrthancException(
+          Orthanc::ErrorCode_ParameterOutOfRange,
+          "Trying to access frame number " + 
+          boost::lexical_cast<std::string>(*frame + 1) + 
+          " of an image with " + 
+          boost::lexical_cast<std::string>(fragments->GetNumberOfFragments()) + 
+          " frames");
       }
       else
       {
@@ -463,8 +466,6 @@
                     const char* url,
                     const OrthancPluginHttpRequest* request)
 {
-  OrthancPluginContext* context = OrthancPlugins::Configuration::GetContext();
-
   gdcm::TransferSyntax targetSyntax(ParseTransferSyntax(request));
 
   std::list<unsigned int> frames;
@@ -472,10 +473,10 @@
 
   Json::Value header;
   std::string uri;
-  OrthancPlugins::MemoryBuffer content(context);
+  OrthancPlugins::MemoryBuffer content;
   if (LocateInstance(output, uri, request) &&
       content.RestApiGet(uri + "/file", false) &&
-      OrthancPlugins::RestApiGet(header, context, uri + "/header?simplify", false))
+      OrthancPlugins::RestApiGet(header, uri + "/header?simplify", false))
   {
     {
       std::string s = "DICOMweb RetrieveFrames on " + uri + ", frames: ";
@@ -485,7 +486,7 @@
         s += boost::lexical_cast<std::string>(*frame + 1) + " ";
       }
 
-      OrthancPlugins::Configuration::LogInfo(s);
+      OrthancPlugins::LogInfo(s);
     }
 
     std::auto_ptr<OrthancPlugins::ParsedDicomFile> source;
@@ -521,9 +522,9 @@
       // Need to convert the transfer syntax
 
       {
-        OrthancPlugins::Configuration::LogInfo("DICOMweb RetrieveFrames: Transcoding " + uri + 
-                                               " from transfer syntax " + std::string(sourceSyntax.GetString()) + 
-                                               " to " + std::string(targetSyntax.GetString()));
+        OrthancPlugins::LogInfo("DICOMweb RetrieveFrames: Transcoding " + uri + 
+                                " from transfer syntax " + std::string(sourceSyntax.GetString()) + 
+                                " to " + std::string(targetSyntax.GetString()));
       }
 
       gdcm::ImageChangeTransferSyntax change;
@@ -537,15 +538,15 @@
       reader.SetStream(stream);
       if (!reader.Read())
       {
-        OrthancPlugins::Configuration::LogError("Cannot decode the image");
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
+        throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat,
+                                        "Cannot decode the image");
       }
 
       change.SetInput(reader.GetImage());
       if (!change.Change())
       {
-        OrthancPlugins::Configuration::LogError("Cannot change the transfer syntax of the image");
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
+        throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError,
+                                        "Cannot change the transfer syntax of the image");
       }
 
       gdcm::ImageWriter writer;
--- a/Plugin/WadoUri.cpp	Fri Nov 09 10:25:02 2018 +0100
+++ b/Plugin/WadoUri.cpp	Tue Dec 04 19:08:22 2018 +0100
@@ -31,7 +31,7 @@
                                        char* (*func) (OrthancPluginContext*, const char*),
                                        const std::string& dicom)
 {
-  OrthancPluginContext* context = OrthancPlugins::Configuration::GetContext();
+  OrthancPluginContext* context = OrthancPlugins::GetGlobalContext();
 
   char* tmp = func(context, dicom.c_str());
 
@@ -52,8 +52,6 @@
                            std::string& contentType,
                            const OrthancPluginHttpRequest* request)
 {
-  OrthancPluginContext* context = OrthancPlugins::Configuration::GetContext();
-
   std::string requestType, studyUid, seriesUid, objectUid;
 
   for (uint32_t i = 0; i < request->getCount; i++)
@@ -85,19 +83,19 @@
 
   if (requestType != "WADO")
   {
-    OrthancPlugins::Configuration::LogError("WADO-URI: Invalid requestType: \"" + requestType + "\"");
+    OrthancPlugins::LogError("WADO-URI: Invalid requestType: \"" + requestType + "\"");
     return false;
   }
 
   if (objectUid.empty())
   {
-    OrthancPlugins::Configuration::LogError("WADO-URI: No SOPInstanceUID provided");
+    OrthancPlugins::LogError("WADO-URI: No SOPInstanceUID provided");
     return false;
   }
 
   if (!MapWadoToOrthancIdentifier(instance, OrthancPluginLookupInstance, objectUid))
   {
-    OrthancPlugins::Configuration::LogError("WADO-URI: No such SOPInstanceUID in Orthanc: \"" + objectUid + "\"");
+    OrthancPlugins::LogError("WADO-URI: No such SOPInstanceUID in Orthanc: \"" + objectUid + "\"");
     return false;
   }
 
@@ -111,16 +109,16 @@
     std::string series;
     if (!MapWadoToOrthancIdentifier(series, OrthancPluginLookupSeries, seriesUid))
     {
-      OrthancPlugins::Configuration::LogError("WADO-URI: No such SeriesInstanceUID in Orthanc: \"" + seriesUid + "\"");
+      OrthancPlugins::LogError("WADO-URI: No such SeriesInstanceUID in Orthanc: \"" + seriesUid + "\"");
       return false;
     }
     else
     {
       Json::Value info;
-      if (!OrthancPlugins::RestApiGet(info, context, "/instances/" + instance + "/series", false) ||
+      if (!OrthancPlugins::RestApiGet(info, "/instances/" + instance + "/series", false) ||
           info["MainDicomTags"]["SeriesInstanceUID"] != seriesUid)
       {
-        OrthancPlugins::Configuration::LogError("WADO-URI: Instance " + objectUid + " does not belong to series " + seriesUid);
+        OrthancPlugins::LogError("WADO-URI: Instance " + objectUid + " does not belong to series " + seriesUid);
         return false;
       }
     }
@@ -131,16 +129,16 @@
     std::string study;
     if (!MapWadoToOrthancIdentifier(study, OrthancPluginLookupStudy, studyUid))
     {
-      OrthancPlugins::Configuration::LogError("WADO-URI: No such StudyInstanceUID in Orthanc: \"" + studyUid + "\"");
+      OrthancPlugins::LogError("WADO-URI: No such StudyInstanceUID in Orthanc: \"" + studyUid + "\"");
       return false;
     }
     else
     {
       Json::Value info;
-      if (!OrthancPlugins::RestApiGet(info, context, "/instances/" + instance + "/study", false) ||
+      if (!OrthancPlugins::RestApiGet(info, "/instances/" + instance + "/study", false) ||
           info["MainDicomTags"]["StudyInstanceUID"] != studyUid)
       {
-        OrthancPlugins::Configuration::LogError("WADO-URI: Instance " + objectUid + " does not belong to study " + studyUid);
+        OrthancPlugins::LogError("WADO-URI: Instance " + objectUid + " does not belong to study " + studyUid);
         return false;
       }
     }
@@ -153,11 +151,11 @@
 static void AnswerDicom(OrthancPluginRestOutput* output,
                         const std::string& instance)
 {
-  OrthancPluginContext* context = OrthancPlugins::Configuration::GetContext();
+  OrthancPluginContext* context = OrthancPlugins::GetGlobalContext();
 
   std::string uri = "/instances/" + instance + "/file";
 
-  OrthancPlugins::MemoryBuffer dicom(context);
+  OrthancPlugins::MemoryBuffer dicom;
   if (dicom.RestApiGet(uri, false))
   {
     OrthancPluginAnswerBuffer(context, output, 
@@ -165,8 +163,8 @@
   }
   else
   {
-    OrthancPlugins::Configuration::LogError("WADO-URI: Unable to retrieve DICOM file from " + uri);
-    throw Orthanc::OrthancException(Orthanc::ErrorCode_Plugin);
+    throw Orthanc::OrthancException(Orthanc::ErrorCode_Plugin,
+                                    "WADO-URI: Unable to retrieve DICOM file from " + uri);
   }
 }
 
@@ -182,7 +180,7 @@
   }
   else
   {
-    OrthancPlugins::Configuration::LogError("WADO-URI: Unable to generate a preview image for " + uri);
+    OrthancPlugins::LogError("WADO-URI: Unable to generate a preview image for " + uri);
     return false;
   }
 }
@@ -191,9 +189,9 @@
 static void AnswerPngPreview(OrthancPluginRestOutput* output,
                              const std::string& instance)
 {
-  OrthancPluginContext* context = OrthancPlugins::Configuration::GetContext();
+  OrthancPluginContext* context = OrthancPlugins::GetGlobalContext();
 
-  OrthancPlugins::MemoryBuffer png(context);
+  OrthancPlugins::MemoryBuffer png;
   if (RetrievePngPreview(png, instance))
   {
     OrthancPluginAnswerBuffer(context, output, 
@@ -209,16 +207,14 @@
 static void AnswerJpegPreview(OrthancPluginRestOutput* output,
                               const std::string& instance)
 {
-  OrthancPluginContext* context = OrthancPlugins::Configuration::GetContext();
-
   // Retrieve the preview in the PNG format
-  OrthancPlugins::MemoryBuffer png(context);
+  OrthancPlugins::MemoryBuffer png;
   if (!RetrievePngPreview(png, instance))
   {
     throw Orthanc::OrthancException(Orthanc::ErrorCode_Plugin);
   }
   
-  OrthancPlugins::OrthancImage image(context);
+  OrthancPlugins::OrthancImage image;
   image.UncompressPngImage(png.GetData(), png.GetSize());
   image.AnswerJpegImage(output, 90 /* quality */);
 }
@@ -230,7 +226,7 @@
 {
   if (request->method != OrthancPluginHttpMethod_Get)
   {
-    OrthancPluginSendMethodNotAllowed(OrthancPlugins::Configuration::GetContext(), output, "GET");
+    OrthancPluginSendMethodNotAllowed(OrthancPlugins::GetGlobalContext(), output, "GET");
     return;
   }
 
@@ -256,7 +252,8 @@
   }
   else
   {
-    OrthancPlugins::Configuration::LogError("WADO-URI: Unsupported content type: \"" + contentType + "\"");
-    throw Orthanc::OrthancException(Orthanc::ErrorCode_BadRequest);
+    throw Orthanc::OrthancException(
+      Orthanc::ErrorCode_BadRequest,
+      "WADO-URI: Unsupported content type: \"" + contentType + "\"");
   }
 }
--- a/Resources/Orthanc/DownloadOrthancFramework.cmake	Fri Nov 09 10:25:02 2018 +0100
+++ b/Resources/Orthanc/DownloadOrthancFramework.cmake	Tue Dec 04 19:08:22 2018 +0100
@@ -63,27 +63,35 @@
 
   set(ORTHANC_FRAMEWORK_MD5 "")
 
-  if (ORTHANC_FRAMEWORK_VERSION STREQUAL "mainline")
-    set(ORTHANC_FRAMEWORK_BRANCH "default")
+  if (NOT DEFINED ORTHANC_FRAMEWORK_BRANCH)
+    if (ORTHANC_FRAMEWORK_VERSION STREQUAL "mainline")
+      set(ORTHANC_FRAMEWORK_BRANCH "default")
 
-  else()
-    set(ORTHANC_FRAMEWORK_BRANCH "Orthanc-${ORTHANC_FRAMEWORK_VERSION}")
+    else()
+      set(ORTHANC_FRAMEWORK_BRANCH "Orthanc-${ORTHANC_FRAMEWORK_VERSION}")
 
-    set(RE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$")
-    string(REGEX REPLACE ${RE} "\\1" ORTHANC_FRAMEWORK_MAJOR ${ORTHANC_FRAMEWORK_VERSION})
-    string(REGEX REPLACE ${RE} "\\2" ORTHANC_FRAMEWORK_MINOR ${ORTHANC_FRAMEWORK_VERSION})
-    string(REGEX REPLACE ${RE} "\\3" ORTHANC_FRAMEWORK_REVISION ${ORTHANC_FRAMEWORK_VERSION})
+      set(RE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$")
+      string(REGEX REPLACE ${RE} "\\1" ORTHANC_FRAMEWORK_MAJOR ${ORTHANC_FRAMEWORK_VERSION})
+      string(REGEX REPLACE ${RE} "\\2" ORTHANC_FRAMEWORK_MINOR ${ORTHANC_FRAMEWORK_VERSION})
+      string(REGEX REPLACE ${RE} "\\3" ORTHANC_FRAMEWORK_REVISION ${ORTHANC_FRAMEWORK_VERSION})
 
-    if (NOT ORTHANC_FRAMEWORK_MAJOR MATCHES "^[0-9]+$" OR
-        NOT ORTHANC_FRAMEWORK_MINOR MATCHES "^[0-9]+$" OR
-        NOT ORTHANC_FRAMEWORK_REVISION MATCHES "^[0-9]+$")
-      message("Bad version of the Orthanc framework: ${ORTHANC_FRAMEWORK_VERSION}")
-    endif()
+      if (NOT ORTHANC_FRAMEWORK_MAJOR MATCHES "^[0-9]+$" OR
+          NOT ORTHANC_FRAMEWORK_MINOR MATCHES "^[0-9]+$" OR
+          NOT ORTHANC_FRAMEWORK_REVISION MATCHES "^[0-9]+$")
+        message("Bad version of the Orthanc framework: ${ORTHANC_FRAMEWORK_VERSION}")
+      endif()
 
-    if (ORTHANC_FRAMEWORK_VERSION STREQUAL "1.3.1")
-      set(ORTHANC_FRAMEWORK_MD5 "dac95bd6cf86fb19deaf4e612961f378")
-    elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "1.3.2")
-      set(ORTHANC_FRAMEWORK_MD5 "d0ccdf68e855d8224331f13774992750")
+      if (ORTHANC_FRAMEWORK_VERSION STREQUAL "1.3.1")
+        set(ORTHANC_FRAMEWORK_MD5 "dac95bd6cf86fb19deaf4e612961f378")
+      elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "1.3.2")
+        set(ORTHANC_FRAMEWORK_MD5 "d0ccdf68e855d8224331f13774992750")
+      elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "1.4.0")
+        set(ORTHANC_FRAMEWORK_MD5 "81e15f34d97ac32bbd7d26e85698835a")
+      elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "1.4.1")
+        set(ORTHANC_FRAMEWORK_MD5 "9b6f6114264b17ed421b574cd6476127")
+      elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "1.4.2")
+        set(ORTHANC_FRAMEWORK_MD5 "d1ee84927dcf668e60eb5868d24b9394")
+      endif()
     endif()
   endif()
 endif()