changeset 1002:b067017a8a5b lua-scripting

anonymization refactoring
author Sebastien Jodogne <s.jodogne@gmail.com>
date Fri, 04 Jul 2014 16:31:14 +0200
parents f3929718ea7e
children 1d35281d967c
files Core/Lua/LuaContext.cpp OrthancServer/OrthancRestApi/OrthancRestAnonymizeModify.cpp OrthancServer/ServerContext.cpp OrthancServer/ServerContext.h OrthancServer/ServerIndex.cpp OrthancServer/ServerIndex.h Resources/Samples/Lua/Autorouting.lua
diffstat 7 files changed, 172 insertions(+), 61 deletions(-) [+]
line wrap: on
line diff
--- a/Core/Lua/LuaContext.cpp	Fri Jul 04 15:31:42 2014 +0200
+++ b/Core/Lua/LuaContext.cpp	Fri Jul 04 16:31:14 2014 +0200
@@ -79,7 +79,7 @@
       lua_pop(state, 1);
     }
 
-    LOG(INFO) << "Lua says: " << result;         
+    LOG(WARNING) << "Lua says: " << result;         
     that->log_.append(result);
     that->log_.append("\n");
 
--- a/OrthancServer/OrthancRestApi/OrthancRestAnonymizeModify.cpp	Fri Jul 04 15:31:42 2014 +0200
+++ b/OrthancServer/OrthancRestApi/OrthancRestAnonymizeModify.cpp	Fri Jul 04 16:31:14 2014 +0200
@@ -252,47 +252,53 @@
 
 
       /**
-       * Compute the resulting DICOM instance and store it into the Orthanc store.
+       * Compute the resulting DICOM instance.
        **/
 
       std::auto_ptr<ParsedDicomFile> modified(original.Clone());
       modification.Apply(*modified);
 
+
+      /**
+       * Prepare the metadata information to associate with the
+       * resulting DICOM instance (AnonymizedFrom/ModifiedFrom).
+       **/
+
+      DicomInstanceHasher modifiedHasher = modified->GetHasher();
+      ServerIndex::MetadataMap metadata;
+
+      if (originalHasher.HashSeries() != modifiedHasher.HashSeries())
+      {
+        metadata[std::make_pair(ResourceType_Series, metadataType)] = originalHasher.HashSeries();
+      }
+
+      if (originalHasher.HashStudy() != modifiedHasher.HashStudy())
+      {
+        metadata[std::make_pair(ResourceType_Study, metadataType)] = originalHasher.HashStudy();
+      }
+
+      if (originalHasher.HashPatient() != modifiedHasher.HashPatient())
+      {
+        metadata[std::make_pair(ResourceType_Patient, metadataType)] = originalHasher.HashPatient();
+      }
+
+      assert(*it == originalHasher.HashInstance());
+      metadata[std::make_pair(ResourceType_Instance, metadataType)] = *it;
+
+
+      /**
+       * Store the resulting DICOM instance into the Orthanc store.
+       **/
+
       std::string modifiedInstance;
-      if (context.Store(modifiedInstance, *modified) != StoreStatus_Success)
+      if (context.Store(modifiedInstance, *modified, metadata) != StoreStatus_Success)
       {
         LOG(ERROR) << "Error while storing a modified instance " << *it;
         return;
       }
 
-
-      /**
-       * Record metadata information (AnonymizedFrom/ModifiedFrom).
-       **/
-
-      DicomInstanceHasher modifiedHasher = modified->GetHasher();
-
-      if (originalHasher.HashSeries() != modifiedHasher.HashSeries())
-      {
-        context.GetIndex().SetMetadata(modifiedHasher.HashSeries(), 
-                                       metadataType, originalHasher.HashSeries());
-      }
-
-      if (originalHasher.HashStudy() != modifiedHasher.HashStudy())
-      {
-        context.GetIndex().SetMetadata(modifiedHasher.HashStudy(), 
-                                       metadataType, originalHasher.HashStudy());
-      }
-
-      if (originalHasher.HashPatient() != modifiedHasher.HashPatient())
-      {
-        context.GetIndex().SetMetadata(modifiedHasher.HashPatient(), 
-                                       metadataType, originalHasher.HashPatient());
-      }
-
-      assert(*it == originalHasher.HashInstance());
+      // Sanity checks in debug mode
       assert(modifiedInstance == modifiedHasher.HashInstance());
-      context.GetIndex().SetMetadata(modifiedInstance, metadataType, *it);
 
 
       /**
--- a/OrthancServer/ServerContext.cpp	Fri Jul 04 15:31:42 2014 +0200
+++ b/OrthancServer/ServerContext.cpp	Fri Jul 04 16:31:14 2014 +0200
@@ -120,16 +120,18 @@
   }
 
 
-  void ServerContext::ApplyOnStoredInstance(const Json::Value& simplified,
-                                            const std::string& instanceId)
+  void ServerContext::ApplyOnStoredInstance(const std::string& instanceId,
+                                            const Json::Value& simplifiedDicom,
+                                            const Json::Value& metadata)
   {
     LuaContextLocker locker(*this);
 
     if (locker.GetLua().IsExistingFunction(ON_STORED_INSTANCE))
     {
       LuaFunctionCall call(locker.GetLua(), ON_STORED_INSTANCE);
-      call.PushJson(simplified);
       call.PushString(instanceId);
+      call.PushJson(simplifiedDicom);
+      call.PushJson(metadata);
 
       Json::Value result;
       call.ExecuteToJson(result);
@@ -138,19 +140,22 @@
       std::cout << result;
     }
 
+#if 1
     {
       // Autorouting test
       RemoteModalityParameters p = Configuration::GetModalityUsingSymbolicName("sample");
 
       ServerJob job;
       ServerCommandInstance& a = job.AddCommand(new StoreScuCommand(*this, p));
-      ServerCommandInstance& b = job.AddCommand(new DeleteInstanceCommand(*this));
       a.AddInput(instanceId);
-      a.ConnectNext(b);
+
+      /*ServerCommandInstance& b = job.AddCommand(new DeleteInstanceCommand(*this));
+        a.ConnectNext(b);*/
 
       job.SetDescription("Autorouting test");
       scheduler_.Submit(job);
     }
+#endif
   }
 
 
@@ -158,7 +163,8 @@
                                    size_t dicomSize,
                                    const DicomMap& dicomSummary,
                                    const Json::Value& dicomJson,
-                                   const std::string& remoteAet)
+                                   const std::string& remoteAet,
+                                   const ServerIndex::MetadataMap& metadata)
   {
     Json::Value simplified;
     SimplifyTags(simplified, dicomJson);
@@ -186,7 +192,7 @@
     attachments.push_back(dicomInfo);
     attachments.push_back(jsonInfo);
 
-    StoreStatus status = index_.Store(dicomSummary, attachments, remoteAet);
+    StoreStatus status = index_.Store(dicomSummary, attachments, remoteAet, metadata);
 
     if (status != StoreStatus_Success)
     {
@@ -219,7 +225,12 @@
       try
       {
         DicomInstanceHasher hasher(dicomSummary);
-        ApplyOnStoredInstance(simplified, hasher.HashInstance());
+        std::string instanceId = hasher.HashInstance();
+
+        Json::Value metadata;
+        index_.GetMetadata(metadata, instanceId);
+
+        ApplyOnStoredInstance(instanceId, simplified, metadata);
       }
       catch (OrthancException&)
       {
@@ -329,7 +340,8 @@
   StoreStatus ServerContext::Store(std::string& resultPublicId,
                                    ParsedDicomFile& dicomInstance,
                                    const char* dicomBuffer,
-                                   size_t dicomSize)
+                                   size_t dicomSize,
+                                   const ServerIndex::MetadataMap& metadata)
   {
     DicomMap dicomSummary;
     FromDcmtkBridge::Convert(dicomSummary, *GetDicom(dicomInstance).getDataset());
@@ -345,7 +357,7 @@
       StoreStatus status = StoreStatus_Failure;
       if (dicomSize > 0)
       {
-        status = Store(dicomBuffer, dicomSize, dicomSummary, dicomJson, "");
+        status = Store(dicomBuffer, dicomSize, dicomSummary, dicomJson, "", metadata);
       }   
 
       return status;
@@ -363,7 +375,8 @@
 
 
   StoreStatus ServerContext::Store(std::string& resultPublicId,
-                                   ParsedDicomFile& dicomInstance)
+                                   ParsedDicomFile& dicomInstance,
+                                   const ServerIndex::MetadataMap& metadata)
   {
     std::string buffer;
     if (!FromDcmtkBridge::SaveToMemoryBuffer(buffer, GetDicom(dicomInstance).getDataset()))
@@ -372,23 +385,25 @@
     }
 
     if (buffer.size() == 0)
-      return Store(resultPublicId, dicomInstance, NULL, 0);
+      return Store(resultPublicId, dicomInstance, NULL, 0, metadata);
     else
-      return Store(resultPublicId, dicomInstance, &buffer[0], buffer.size());
+      return Store(resultPublicId, dicomInstance, &buffer[0], buffer.size(), metadata);
   }
 
 
   StoreStatus ServerContext::Store(std::string& resultPublicId,
                                    const char* dicomBuffer,
-                                   size_t dicomSize)
+                                   size_t dicomSize,
+                                   const ServerIndex::MetadataMap& metadata)
   {
     ParsedDicomFile dicom(dicomBuffer, dicomSize);
-    return Store(resultPublicId, dicom, dicomBuffer, dicomSize);
+    return Store(resultPublicId, dicom, dicomBuffer, dicomSize, metadata);
   }
 
 
   StoreStatus ServerContext::Store(std::string& resultPublicId,
-                                   const std::string& dicomContent)
+                                   const std::string& dicomContent,
+                                   const ServerIndex::MetadataMap& metadata)
   {
     if (dicomContent.size() == 0)
     {
@@ -396,7 +411,7 @@
     }
     else
     {
-      return Store(resultPublicId, &dicomContent[0], dicomContent.size());
+      return Store(resultPublicId, &dicomContent[0], dicomContent.size(), metadata);
     }
   }
 
--- a/OrthancServer/ServerContext.h	Fri Jul 04 15:31:42 2014 +0200
+++ b/OrthancServer/ServerContext.h	Fri Jul 04 16:31:14 2014 +0200
@@ -68,8 +68,9 @@
     bool ApplyReceivedInstanceFilter(const Json::Value& simplified,
                                      const std::string& remoteAet);
 
-    void ApplyOnStoredInstance(const Json::Value& simplified,
-                               const std::string& instanceId);
+    void ApplyOnStoredInstance(const std::string& instanceId,
+                               const Json::Value& simplifiedDicom,
+                               const Json::Value& metadata);
 
     FileStorage storage_;
     ServerIndex index_;
@@ -148,26 +149,33 @@
                        const void* data,
                        size_t size);
 
+
+    // TODO SIMPLIFY THESE MANY "Store" methods!
     StoreStatus Store(const char* dicomInstance,
                       size_t dicomSize,
                       const DicomMap& dicomSummary,
                       const Json::Value& dicomJson,
-                      const std::string& remoteAet);
+                      const std::string& remoteAet,
+                      const ServerIndex::MetadataMap& metadata = ServerIndex::MetadataMap());
 
     StoreStatus Store(std::string& resultPublicId,
                       ParsedDicomFile& dicomInstance,
                       const char* dicomBuffer,
-                      size_t dicomSize);
+                      size_t dicomSize,
+                      const ServerIndex::MetadataMap& metadata = ServerIndex::MetadataMap());
 
     StoreStatus Store(std::string& resultPublicId,
-                      ParsedDicomFile& dicomInstance);
+                      ParsedDicomFile& dicomInstance,
+                      const ServerIndex::MetadataMap& metadata = ServerIndex::MetadataMap());
 
     StoreStatus Store(std::string& resultPublicId,
                       const char* dicomBuffer,
-                      size_t dicomSize);
+                      size_t dicomSize,
+                      const ServerIndex::MetadataMap& metadata = ServerIndex::MetadataMap());
 
     StoreStatus Store(std::string& resultPublicId,
-                      const std::string& dicomContent);
+                      const std::string& dicomContent,
+                      const ServerIndex::MetadataMap& metadata = ServerIndex::MetadataMap());
 
     void AnswerDicomFile(RestApiOutput& output,
                          const std::string& instancePublicId,
--- a/OrthancServer/ServerIndex.cpp	Fri Jul 04 15:31:42 2014 +0200
+++ b/OrthancServer/ServerIndex.cpp	Fri Jul 04 16:31:14 2014 +0200
@@ -384,7 +384,8 @@
 
   StoreStatus ServerIndex::Store(const DicomMap& dicomSummary,
                                  const Attachments& attachments,
-                                 const std::string& remoteAet)
+                                 const std::string& remoteAet,
+                                 const MetadataMap* metadata)
   {
     boost::mutex::scoped_lock lock(mutex_);
     listener_->Reset();
@@ -519,7 +520,37 @@
         db_->AddAttachment(instance, *it);
       }
 
-      // Attach the metadata
+      // Attach the user-specified metadata
+      if (metadata)
+      {
+        for (MetadataMap::const_iterator 
+               it = metadata->begin(); it != metadata->end(); ++it)
+        {
+          switch (it->first.first)
+          {
+            case ResourceType_Patient:
+              db_->SetMetadata(patient, it->first.second, it->second);
+              break;
+
+            case ResourceType_Study:
+              db_->SetMetadata(study, it->first.second, it->second);
+              break;
+
+            case ResourceType_Series:
+              db_->SetMetadata(series, it->first.second, it->second);
+              break;
+
+            case ResourceType_Instance:
+              db_->SetMetadata(instance, it->first.second, it->second);
+              break;
+
+            default:
+              throw OrthancException(ErrorCode_ParameterOutOfRange);
+          }
+        }
+      }
+
+      // Attach the auto-computer metadata
       std::string now = Toolbox::GetNowIsoString();
       db_->SetMetadata(instance, MetadataType_Instance_ReceptionDate, now);
       db_->SetMetadata(series, MetadataType_LastUpdate, now);
@@ -1694,4 +1725,33 @@
   }
 
 
+  bool ServerIndex::GetMetadata(Json::Value& target,
+                                const std::string& publicId)
+  {
+    boost::mutex::scoped_lock lock(mutex_);
+
+    target = Json::objectValue;
+
+    ResourceType type;
+    int64_t id;
+    if (!db_->LookupResource(publicId, id, type))
+    {
+      return false;
+    }
+
+    std::list<MetadataType> metadata;
+    db_->ListAvailableMetadata(metadata, id);
+
+    for (std::list<MetadataType>::const_iterator
+           it = metadata.begin(); it != metadata.end(); it++)
+    {
+      std::string key = EnumerationToString(*it);
+      std::string value = db_->GetMetadata(id, *it);
+      target[key] = value;
+    }
+
+    return true;
+  }
+
+
 }
--- a/OrthancServer/ServerIndex.h	Fri Jul 04 15:31:42 2014 +0200
+++ b/OrthancServer/ServerIndex.h	Fri Jul 04 16:31:14 2014 +0200
@@ -54,6 +54,10 @@
 
   class ServerIndex : public boost::noncopyable
   {
+  public:
+    typedef std::list<FileInfo> Attachments;
+    typedef std::map< std::pair<ResourceType, MetadataType>, std::string>  MetadataMap;
+
   private:
     class Transaction;
     struct UnstableResourcePayload;
@@ -98,9 +102,12 @@
                                /* in  */ int64_t id,
                                /* in  */ ResourceType type);
 
+    StoreStatus Store(const DicomMap& dicomSummary,
+                      const Attachments& attachments,
+                      const std::string& remoteAet,
+                      const MetadataMap* metadata);
+
   public:
-    typedef std::list<FileInfo> Attachments;
-
     ServerIndex(ServerContext& context,
                 const std::string& dbPath);
 
@@ -124,7 +131,18 @@
 
     StoreStatus Store(const DicomMap& dicomSummary,
                       const Attachments& attachments,
-                      const std::string& remoteAet);
+                      const std::string& remoteAet)
+    {
+      return Store(dicomSummary, attachments, remoteAet, NULL);
+    }
+
+    StoreStatus Store(const DicomMap& dicomSummary,
+                      const Attachments& attachments,
+                      const std::string& remoteAet,
+                      const MetadataMap& metadata)
+    {
+      return Store(dicomSummary, attachments, remoteAet, &metadata);
+    }
 
     void ComputeStatistics(Json::Value& target);                        
 
@@ -183,6 +201,9 @@
     void ListAvailableMetadata(std::list<MetadataType>& target,
                                const std::string& publicId);
 
+    bool GetMetadata(Json::Value& target,
+                     const std::string& publicId);
+
     void ListAvailableAttachments(std::list<FileContentType>& target,
                                   const std::string& publicId,
                                   ResourceType expectedType);
--- a/Resources/Samples/Lua/Autorouting.lua	Fri Jul 04 15:31:42 2014 +0200
+++ b/Resources/Samples/Lua/Autorouting.lua	Fri Jul 04 16:31:14 2014 +0200
@@ -1,5 +1,6 @@
-function OnStoredInstance(tags, instance)
-  PrintRecursive(tags)
+function OnStoredInstance(instance, tags, metadata)
+   --PrintRecursive(tags)
+  PrintRecursive(metadata)
   return { 
     { "store", instance, "pacs" }, 
     { "delete", instance }