diff OrthancServer/Sources/OrthancInitialization.cpp @ 4044:d25f4c0fa160 framework

splitting code into OrthancFramework and OrthancServer
author Sebastien Jodogne <s.jodogne@gmail.com>
date Wed, 10 Jun 2020 20:30:34 +0200
parents OrthancServer/OrthancInitialization.cpp@058b5ade8acd
children 05b8fd21089c
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/OrthancServer/Sources/OrthancInitialization.cpp	Wed Jun 10 20:30:34 2020 +0200
@@ -0,0 +1,391 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2020 Osimis S.A., Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * In addition, as a special exception, the copyright holders of this
+ * program give permission to link the code of its release with the
+ * OpenSSL project's "OpenSSL" library (or with modified versions of it
+ * that use the same license as the "OpenSSL" library), and distribute
+ * the linked executables. You must obey the GNU General Public License
+ * in all respects for all of the code used other than "OpenSSL". If you
+ * modify file(s) with this exception, you may extend this exception to
+ * your version of the file(s), but you are not obligated to do so. If
+ * you do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source files
+ * in the program, then also delete it here.
+ * 
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+#include "PrecompiledHeadersServer.h"
+
+#if defined(_WIN32)
+// "Please include winsock2.h before windows.h"
+#  include <winsock2.h>
+#endif
+
+#include "OrthancInitialization.h"
+
+#include "../Core/DicomParsing/FromDcmtkBridge.h"
+#include "../Core/FileStorage/FilesystemStorage.h"
+#include "../Core/Logging.h"
+#include "../Core/OrthancException.h"
+
+#include "Database/SQLiteDatabaseWrapper.h"
+#include "OrthancConfiguration.h"
+
+#include <OrthancServerResources.h>
+
+#include <dcmtk/dcmnet/dul.h>   // For dcmDisableGethostbyaddr()
+
+
+
+namespace Orthanc
+{
+  static void RegisterUserMetadata(const Json::Value& config)
+  {
+    if (config.isMember("UserMetadata"))
+    {
+      const Json::Value& parameter = config["UserMetadata"];
+
+      Json::Value::Members members = parameter.getMemberNames();
+      for (size_t i = 0; i < members.size(); i++)
+      {
+        const std::string& name = members[i];
+
+        if (!parameter[name].isInt())
+        {
+          throw OrthancException(ErrorCode_BadParameterType,
+                                 "Not a number in this user-defined metadata: " + name);
+        }
+
+        int metadata = parameter[name].asInt();        
+
+        LOG(INFO) << "Registering user-defined metadata: " << name << " (index " 
+                  << metadata << ")";
+
+        try
+        {
+          RegisterUserMetadata(metadata, name);
+        }
+        catch (OrthancException&)
+        {
+          LOG(ERROR) << "Cannot register this user-defined metadata: " << name;
+          throw;
+        }
+      }
+    }
+  }
+
+
+  static void RegisterUserContentType(const Json::Value& config)
+  {
+    if (config.isMember("UserContentType"))
+    {
+      const Json::Value& parameter = config["UserContentType"];
+
+      Json::Value::Members members = parameter.getMemberNames();
+      for (size_t i = 0; i < members.size(); i++)
+      {
+        const std::string& name = members[i];
+        std::string mime = MIME_BINARY;
+
+        const Json::Value& value = parameter[name];
+        int contentType;
+
+        if (value.isArray() &&
+            value.size() == 2 &&
+            value[0].isInt() &&
+            value[1].isString())
+        {
+          contentType = value[0].asInt();
+          mime = value[1].asString();
+        }
+        else if (value.isInt())
+        {
+          contentType = value.asInt();
+        }
+        else
+        {
+          throw OrthancException(ErrorCode_BadParameterType,
+                                 "Not a number in this user-defined attachment type: " + name);
+        }
+
+        LOG(INFO) << "Registering user-defined attachment type: " << name << " (index " 
+                  << contentType << ") with MIME type \"" << mime << "\"";
+
+        try
+        {
+          RegisterUserContentType(contentType, name, mime);
+        }
+        catch (OrthancException&)
+        {
+          throw;
+        }
+      }
+    }
+  }
+
+
+  static void LoadCustomDictionary(const Json::Value& configuration)
+  {
+    if (configuration.type() != Json::objectValue ||
+        !configuration.isMember("Dictionary") ||
+        configuration["Dictionary"].type() != Json::objectValue)
+    {
+      return;
+    }
+
+    Json::Value::Members tags(configuration["Dictionary"].getMemberNames());
+
+    for (Json::Value::ArrayIndex i = 0; i < tags.size(); i++)
+    {
+      const Json::Value& content = configuration["Dictionary"][tags[i]];
+      if (content.type() != Json::arrayValue ||
+          content.size() < 2 ||
+          content.size() > 5 ||
+          content[0].type() != Json::stringValue ||
+          content[1].type() != Json::stringValue ||
+          (content.size() >= 3 && content[2].type() != Json::intValue) ||
+          (content.size() >= 4 && content[3].type() != Json::intValue) ||
+          (content.size() >= 5 && content[4].type() != Json::stringValue))
+      {
+        throw OrthancException(ErrorCode_BadFileFormat, "The definition of the '" + tags[i] + "' dictionary entry is invalid.");
+      }
+
+      DicomTag tag(FromDcmtkBridge::ParseTag(tags[i]));
+      ValueRepresentation vr = StringToValueRepresentation(content[0].asString(), true);
+      std::string name = content[1].asString();
+      unsigned int minMultiplicity = (content.size() >= 2) ? content[2].asUInt() : 1;
+      unsigned int maxMultiplicity = (content.size() >= 3) ? content[3].asUInt() : 1;
+      std::string privateCreator = (content.size() >= 4) ? content[4].asString() : "";
+
+      FromDcmtkBridge::RegisterDictionaryTag(tag, vr, name, minMultiplicity, maxMultiplicity, privateCreator);
+    }
+  }
+
+
+  static void ConfigurePkcs11(const Json::Value& config)
+  {
+    if (config.type() != Json::objectValue ||
+        !config.isMember("Module") ||
+        config["Module"].type() != Json::stringValue)
+    {
+      throw OrthancException(ErrorCode_BadFileFormat,
+                             "No path to the PKCS#11 module (DLL or .so) is provided "
+                             "for HTTPS client authentication");
+    }
+
+    std::string pin;
+    if (config.isMember("Pin"))
+    {
+      if (config["Pin"].type() == Json::stringValue)
+      {
+        pin = config["Pin"].asString();
+      }
+      else
+      {
+        throw OrthancException(ErrorCode_BadFileFormat,
+                               "The PIN number in the PKCS#11 configuration must be a string");
+      }
+    }
+
+    bool verbose = false;
+    if (config.isMember("Verbose"))
+    {
+      if (config["Verbose"].type() == Json::booleanValue)
+      {
+        verbose = config["Verbose"].asBool();
+      }
+      else
+      {
+        throw OrthancException(ErrorCode_BadFileFormat,
+                               "The Verbose option in the PKCS#11 configuration must be a Boolean");
+      }
+    }
+
+    HttpClient::InitializePkcs11(config["Module"].asString(), pin, verbose);
+  }
+
+
+
+  void OrthancInitialize(const char* configurationFile)
+  {
+    OrthancConfiguration::WriterLock lock;
+
+    InitializeServerEnumerations();
+
+    // Read the user-provided configuration
+    lock.GetConfiguration().Read(configurationFile);
+
+    {
+      std::string locale;
+      
+      if (lock.GetJson().isMember("Locale"))
+      {
+        locale = lock.GetConfiguration().GetStringParameter("Locale", "");
+      }
+      
+      bool loadPrivate = lock.GetConfiguration().GetBooleanParameter("LoadPrivateDictionary", true);
+      Orthanc::InitializeFramework(locale, loadPrivate);
+    }
+
+    // The Orthanc framework is now initialized
+
+    if (lock.GetJson().isMember("DefaultEncoding"))
+    {
+      std::string encoding = lock.GetConfiguration().GetStringParameter("DefaultEncoding", "");
+      SetDefaultDicomEncoding(StringToEncoding(encoding.c_str()));
+    }
+    else
+    {
+      SetDefaultDicomEncoding(ORTHANC_DEFAULT_DICOM_ENCODING);
+    }
+
+    if (lock.GetJson().isMember("Pkcs11"))
+    {
+      ConfigurePkcs11(lock.GetJson()["Pkcs11"]);
+    }
+
+    RegisterUserMetadata(lock.GetJson());
+    RegisterUserContentType(lock.GetJson());
+
+    LoadCustomDictionary(lock.GetJson());
+
+    lock.GetConfiguration().RegisterFont(ServerResources::FONT_UBUNTU_MONO_BOLD_16);
+  }
+
+
+
+  void OrthancFinalize()
+  {
+    OrthancConfiguration::WriterLock lock;
+    Orthanc::FinalizeFramework();
+  }
+
+
+  static IDatabaseWrapper* CreateSQLiteWrapper()
+  {
+    OrthancConfiguration::ReaderLock lock;
+
+    std::string storageDirectoryStr = 
+      lock.GetConfiguration().GetStringParameter("StorageDirectory", "OrthancStorage");
+
+    // Open the database
+    boost::filesystem::path indexDirectory = lock.GetConfiguration().InterpretStringParameterAsPath(
+      lock.GetConfiguration().GetStringParameter("IndexDirectory", storageDirectoryStr));
+
+    LOG(WARNING) << "SQLite index directory: " << indexDirectory;
+
+    try
+    {
+      boost::filesystem::create_directories(indexDirectory);
+    }
+    catch (boost::filesystem::filesystem_error&)
+    {
+    }
+
+    return new SQLiteDatabaseWrapper(indexDirectory.string() + "/index");
+  }
+
+
+  namespace
+  {
+    // Anonymous namespace to avoid clashes between compilation modules
+
+    class FilesystemStorageWithoutDicom : public IStorageArea
+    {
+    private:
+      FilesystemStorage storage_;
+
+    public:
+      FilesystemStorageWithoutDicom(const std::string& path) : storage_(path)
+      {
+      }
+
+      virtual void Create(const std::string& uuid,
+                          const void* content, 
+                          size_t size,
+                          FileContentType type)
+      {
+        if (type != FileContentType_Dicom)
+        {
+          storage_.Create(uuid, content, size, type);
+        }
+      }
+
+      virtual void Read(std::string& content,
+                        const std::string& uuid,
+                        FileContentType type)
+      {
+        if (type != FileContentType_Dicom)
+        {
+          storage_.Read(content, uuid, type);
+        }
+        else
+        {
+          throw OrthancException(ErrorCode_UnknownResource);
+        }
+      }
+
+      virtual void Remove(const std::string& uuid,
+                          FileContentType type) 
+      {
+        if (type != FileContentType_Dicom)
+        {
+          storage_.Remove(uuid, type);
+        }
+      }
+    };
+  }
+
+
+  static IStorageArea* CreateFilesystemStorage()
+  {
+    OrthancConfiguration::ReaderLock lock;
+
+    std::string storageDirectoryStr = 
+      lock.GetConfiguration().GetStringParameter("StorageDirectory", "OrthancStorage");
+
+    boost::filesystem::path storageDirectory = 
+      lock.GetConfiguration().InterpretStringParameterAsPath(storageDirectoryStr);
+
+    LOG(WARNING) << "Storage directory: " << storageDirectory;
+
+    if (lock.GetConfiguration().GetBooleanParameter("StoreDicom", true))
+    {
+      return new FilesystemStorage(storageDirectory.string());
+    }
+    else
+    {
+      LOG(WARNING) << "The DICOM files will not be stored, Orthanc running in index-only mode";
+      return new FilesystemStorageWithoutDicom(storageDirectory.string());
+    }
+  }
+
+
+  IDatabaseWrapper* CreateDatabaseWrapper()
+  {
+    return CreateSQLiteWrapper();
+  }
+
+
+  IStorageArea* CreateStorageArea()
+  {
+    return CreateFilesystemStorage();
+  }  
+}