changeset 2010:4dafe2a0d3ab

Support of SIGHUP signal (restart Orthanc only if the configuration files have changed)
author Sebastien Jodogne <s.jodogne@gmail.com>
date Thu, 09 Jun 2016 17:57:47 +0200
parents e2dd40abce72
children 5b3b2de4e018
files Core/Toolbox.cpp NEWS OrthancServer/OrthancInitialization.cpp OrthancServer/OrthancInitialization.h OrthancServer/main.cpp
diffstat 5 files changed, 106 insertions(+), 28 deletions(-) [+]
line wrap: on
line diff
--- a/Core/Toolbox.cpp	Thu Jun 09 17:25:34 2016 +0200
+++ b/Core/Toolbox.cpp	Thu Jun 09 17:57:47 2016 +0200
@@ -119,7 +119,6 @@
   {
     // http://msdn.microsoft.com/en-us/library/ms683242(v=vs.85).aspx
     finish_ = true;
-    barrierEvent_ = ServerBarrierEvent_Stop;
     return true;
   }
 #else
--- a/NEWS	Thu Jun 09 17:25:34 2016 +0200
+++ b/NEWS	Thu Jun 09 17:57:47 2016 +0200
@@ -2,6 +2,11 @@
 ===============================
 
 
+General
+-------
+
+* Support of SIGHUP signal (restart Orthanc only if the configuration files have changed)
+
 REST API
 --------
 
--- a/OrthancServer/OrthancInitialization.cpp	Thu Jun 09 17:25:34 2016 +0200
+++ b/OrthancServer/OrthancInitialization.cpp	Thu Jun 09 17:57:47 2016 +0200
@@ -81,6 +81,7 @@
   static boost::filesystem::path defaultDirectory_;
   static std::string configurationAbsolutePath_;
   static FontRegistry fontRegistry_;
+  static const char* configurationFileArg_ = NULL;
 
 
   static std::string GetGlobalStringParameterInternal(const std::string& parameter,
@@ -128,7 +129,8 @@
 
 
 
-  static void AddFileToConfiguration(const boost::filesystem::path& path)
+  static void AddFileToConfiguration(Json::Value& target,
+                                     const boost::filesystem::path& path)
   {
     LOG(WARNING) << "Reading the configuration from: " << path;
 
@@ -150,30 +152,31 @@
       Toolbox::CopyJsonWithoutComments(config, tmp);
     }
 
-    if (configuration_.size() == 0)
+    if (target.size() == 0)
     {
-      configuration_ = config;
+      target = config;
     }
     else
     {
       Json::Value::Members members = config.getMemberNames();
       for (Json::Value::ArrayIndex i = 0; i < members.size(); i++)
       {
-        if (configuration_.isMember(members[i]))
+        if (target.isMember(members[i]))
         {
           LOG(ERROR) << "The configuration section \"" << members[i] << "\" is defined in 2 different configuration files";
           throw OrthancException(ErrorCode_BadFileFormat);          
         }
         else
         {
-          configuration_[members[i]] = config[members[i]];
+          target[members[i]] = config[members[i]];
         }
       }
     }
   }
 
 
-  static void ScanFolderForConfiguration(const char* folder)
+  static void ScanFolderForConfiguration(Json::Value& target,
+                                         const char* folder)
   {
     using namespace boost::filesystem;
 
@@ -191,19 +194,17 @@
 
         if (extension == ".json")
         {
-          AddFileToConfiguration(it->path().string());
+          AddFileToConfiguration(target, it->path().string());
         }
       }
     }
   }
 
 
-  static void ReadGlobalConfiguration(const char* configurationFile)
+  static void ReadConfiguration(Json::Value& target,
+                                const char* configurationFile)
   {
-    // Prepare the default configuration
-    defaultDirectory_ = boost::filesystem::current_path();
-    configuration_ = Json::objectValue;
-    configurationAbsolutePath_ = "";
+    target = Json::objectValue;
 
     if (configurationFile)
     {
@@ -215,15 +216,11 @@
       
       if (boost::filesystem::is_directory(configurationFile))
       {
-        defaultDirectory_ = boost::filesystem::path(configurationFile);
-        configurationAbsolutePath_ = boost::filesystem::absolute(configurationFile).parent_path().string();
-        ScanFolderForConfiguration(configurationFile);
+        ScanFolderForConfiguration(target, configurationFile);
       }
       else
       {
-        defaultDirectory_ = boost::filesystem::path(configurationFile).parent_path();
-        configurationAbsolutePath_ = boost::filesystem::absolute(configurationFile).string();
-        AddFileToConfiguration(configurationFile);
+        AddFileToConfiguration(target, configurationFile);
       }
     }
     else
@@ -240,9 +237,47 @@
       boost::filesystem::path p = ORTHANC_PATH;
       p /= "Resources";
       p /= "Configuration.json";
-      configurationAbsolutePath_ = boost::filesystem::absolute(p).string();
+
+      AddFileToConfiguration(target, p);
+#endif
+    }
+  }
+
+
+
+  static void ReadGlobalConfiguration(const char* configurationFile)
+  {
+    // Read the content of the configuration
+    configurationFileArg_ = configurationFile;
+    ReadConfiguration(configuration_, configurationFile);
+
+    // Adapt the paths to the configurations
+    defaultDirectory_ = boost::filesystem::current_path();
+    configurationAbsolutePath_ = "";
 
-      AddFileToConfiguration(p);      
+    if (configurationFile)
+    {
+      if (boost::filesystem::is_directory(configurationFile))
+      {
+        defaultDirectory_ = boost::filesystem::path(configurationFile);
+        configurationAbsolutePath_ = boost::filesystem::absolute(configurationFile).parent_path().string();
+      }
+      else
+      {
+        defaultDirectory_ = boost::filesystem::path(configurationFile).parent_path();
+        configurationAbsolutePath_ = boost::filesystem::absolute(configurationFile).string();
+      }
+    }
+    else
+    {
+#if ORTHANC_STANDALONE != 1
+      // In a non-standalone build, we use the
+      // "Resources/Configuration.json" from the Orthanc source code
+
+      boost::filesystem::path p = ORTHANC_PATH;
+      p /= "Resources";
+      p /= "Configuration.json";
+      configurationAbsolutePath_ = boost::filesystem::absolute(p).string();
 #endif
     }
   }
@@ -1040,4 +1075,20 @@
     // By default, Latin1 encoding is assumed
     return s.empty() ? Encoding_Latin1 : StringToEncoding(s.c_str());
   }
+
+
+  bool Configuration::HasConfigurationChanged()
+  {
+    Json::Value starting;
+    GetConfiguration(starting);
+
+    Json::Value current;
+    ReadConfiguration(current, configurationFileArg_);
+
+    Json::FastWriter writer;
+    std::string a = writer.write(starting);
+    std::string b = writer.write(current);
+
+    return a != b;
+  }
 }
--- a/OrthancServer/OrthancInitialization.h	Thu Jun 09 17:25:34 2016 +0200
+++ b/OrthancServer/OrthancInitialization.h	Thu Jun 09 17:57:47 2016 +0200
@@ -52,6 +52,9 @@
 
   class Configuration
   {
+  private:
+    Configuration();  // Forbidden, this is a static class
+
   public:
     static std::string GetGlobalStringParameter(const std::string& parameter,
                                                 const std::string& defaultValue);
@@ -117,5 +120,7 @@
     static const FontRegistry& GetFontRegistry();
 
     static Encoding GetDefaultEncoding();
+
+    static bool HasConfigurationChanged();
   };
 }
--- a/OrthancServer/main.cpp	Thu Jun 09 17:25:34 2016 +0200
+++ b/OrthancServer/main.cpp	Thu Jun 09 17:57:47 2016 +0200
@@ -651,16 +651,34 @@
 
   context.GetLua().Execute("Initialize");
 
-  ServerBarrierEvent event = Toolbox::ServerBarrier(restApi.LeaveBarrierFlag());
-  bool restart = restApi.IsResetRequestReceived();
+  bool restart;
+
+  for (;;)
+  {
+    ServerBarrierEvent event = Toolbox::ServerBarrier(restApi.LeaveBarrierFlag());
+    restart = restApi.IsResetRequestReceived();
 
-  if (!restart && 
-      event == ServerBarrierEvent_Reload)
-  {
-    printf("RECEIVED SIGHUP\n");
+    if (!restart && 
+        event == ServerBarrierEvent_Reload)
+    {
+      if (Configuration::HasConfigurationChanged())
+      {
+        LOG(WARNING) << "A SIGHUP signal has been received, resetting Orthanc";
+        restart = true;
+        break;
+      }
+      else
+      {
+        LOG(WARNING) << "A SIGHUP signal has been received, but is ignored as the configuration has not changed";
+        continue;
+      }
+    }
+    else
+    {
+      break;
+    }
   }
 
-
   context.GetLua().Execute("Finalize");
 
 #if ORTHANC_PLUGINS_ENABLED == 1