changeset 199:dfa2899d9960

refactoring cont
author Sebastien Jodogne <s.jodogne@gmail.com>
date Tue, 27 Nov 2012 16:20:22 +0100
parents 663cc6c46d0a
children 9c58b2b03cf0
files CMakeLists.txt OrthancServer/DatabaseWrapper.cpp OrthancServer/DatabaseWrapper.h OrthancServer/OrthancRestApi.cpp OrthancServer/ServerEnumerations.cpp OrthancServer/ServerEnumerations.h OrthancServer/ServerIndex.cpp OrthancServer/ServerIndex.h
diffstat 8 files changed, 203 insertions(+), 82 deletions(-) [+]
line wrap: on
line diff
--- a/CMakeLists.txt	Tue Nov 27 15:49:42 2012 +0100
+++ b/CMakeLists.txt	Tue Nov 27 16:20:22 2012 +0100
@@ -140,6 +140,7 @@
   OrthancServer/ServerIndex.cpp
   OrthancServer/ToDcmtkBridge.cpp
   OrthancServer/DatabaseWrapper.cpp
+  OrthancServer/ServerEnumerations.cpp
   )
 
 # Ensure autogenerated code is built before building ServerLibrary
--- a/OrthancServer/DatabaseWrapper.cpp	Tue Nov 27 15:49:42 2012 +0100
+++ b/OrthancServer/DatabaseWrapper.cpp	Tue Nov 27 16:20:22 2012 +0100
@@ -461,6 +461,22 @@
   }
 
 
+  void DatabaseWrapper::GetChildrenInternalId(std::list<int64_t>& result,
+                                              int64_t id)
+  {
+    SQLite::Statement s(db_, SQLITE_FROM_HERE, "SELECT a.internalId FROM Resources AS a, Resources AS b  "
+                        "WHERE a.parentId = b.internalId AND b.internalId = ?");     
+    s.BindInt(0, id);
+
+    result.clear();
+
+    while (s.Step())
+    {
+      result.push_back(s.ColumnInt(0));
+    }
+  }
+
+
   void DatabaseWrapper::LogChange(ChangeType changeType,
                                   int64_t internalId,
                                   ResourceType resourceType,
--- a/OrthancServer/DatabaseWrapper.h	Tue Nov 27 15:49:42 2012 +0100
+++ b/OrthancServer/DatabaseWrapper.h	Tue Nov 27 16:20:22 2012 +0100
@@ -137,6 +137,9 @@
     void GetChildrenPublicId(std::list<std::string>& result,
                              int64_t id);
 
+    void GetChildrenInternalId(std::list<int64_t>& result,
+                               int64_t id);
+
     void LogChange(ChangeType changeType,
                    int64_t internalId,
                    ResourceType resourceType,
--- a/OrthancServer/OrthancRestApi.cpp	Tue Nov 27 15:49:42 2012 +0100
+++ b/OrthancServer/OrthancRestApi.cpp	Tue Nov 27 16:20:22 2012 +0100
@@ -514,19 +514,22 @@
         if (uri[0] == "patients")
         {
           existingResource = index_.GetPatient(result, uri[1]);
-          assert(result["Type"] == "Patient");
+          assert(!existingResource || result["Type"] == "Patient");
         }
         else if (uri[0] == "studies")
         {
           existingResource = index_.GetStudy(result, uri[1]);
+          assert(!existingResource || result["Type"] == "Study");
         }
         else if (uri[0] == "series")
         {
           existingResource = index_.GetSeries(result, uri[1]);
+          assert(!existingResource || result["Type"] == "Series");
         }
         else if (uri[0] == "instances")
         {
           existingResource = index_.GetInstance(result, uri[1]);
+          assert(!existingResource || result["Type"] == "Instance");
         }
       }
       else if (method == "DELETE")
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/OrthancServer/ServerEnumerations.cpp	Tue Nov 27 16:20:22 2012 +0100
@@ -0,0 +1,79 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012 Medical Physics Department, CHU of Liege,
+ * Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * In addition, as a special exception, the copyright holders of this
+ * program give permission to link the code of its release with the
+ * OpenSSL project's "OpenSSL" library (or with modified versions of it
+ * that use the same license as the "OpenSSL" library), and distribute
+ * the linked executables. You must obey the GNU General Public License
+ * in all respects for all of the code used other than "OpenSSL". If you
+ * modify file(s) with this exception, you may extend this exception to
+ * your version of the file(s), but you are not obligated to do so. If
+ * you do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source files
+ * in the program, then also delete it here.
+ * 
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+#include "ServerEnumerations.h"
+
+#include "../Core/OrthancException.h"
+
+namespace Orthanc
+{
+  const char* ToString(ResourceType type)
+  {
+    switch (type)
+    {
+    case ResourceType_Patient:
+      return "Patient";
+
+    case ResourceType_Study:
+      return "Study";
+
+    case ResourceType_Series:
+      return "Series";
+
+    case ResourceType_Instance:
+      return "Instance";
+      
+    default:
+      throw OrthancException(ErrorCode_ParameterOutOfRange);
+    }
+  }
+
+  const char* ToString(SeriesStatus status)
+  {
+    switch (status)
+    {
+    case SeriesStatus_Complete:
+      return "Complete";
+
+    case SeriesStatus_Missing:
+      return "Missing";
+
+    case SeriesStatus_Inconsistent:
+      return "Inconsistent";
+
+    case SeriesStatus_Unknown:
+      return "Unknown";
+
+    default:
+      throw OrthancException(ErrorCode_ParameterOutOfRange);
+    }
+  }
+}
--- a/OrthancServer/ServerEnumerations.h	Tue Nov 27 15:49:42 2012 +0100
+++ b/OrthancServer/ServerEnumerations.h	Tue Nov 27 16:20:22 2012 +0100
@@ -48,7 +48,6 @@
     StoreStatus_Failure
   };
 
-
   enum ResourceType
   {
     ResourceType_Patient = 1,
@@ -86,4 +85,8 @@
     AttachedFileType_Dicom = 1,
     AttachedFileType_Json = 2
   };
+
+  const char* ToString(ResourceType type);
+
+  const char* ToString(SeriesStatus status);
 }
--- a/OrthancServer/ServerIndex.cpp	Tue Nov 27 15:49:42 2012 +0100
+++ b/OrthancServer/ServerIndex.cpp	Tue Nov 27 16:20:22 2012 +0100
@@ -787,6 +787,72 @@
   }
 
 
+  SeriesStatus ServerIndex::GetSeriesStatus(int id)
+  {
+    // Get the expected number of instances in this series (from the metadata)
+    std::string s = db2_->GetMetadata(id, MetadataType_Series_ExpectedNumberOfInstances);
+
+    size_t expected;
+    try
+    {
+      expected = boost::lexical_cast<size_t>(s);
+      if (expected < 0)
+      {
+        return SeriesStatus_Unknown;
+      }
+    }
+    catch (boost::bad_lexical_cast&)
+    {
+      return SeriesStatus_Unknown;
+    }
+
+    // Loop over the instances of this series
+    std::list<int64_t> children;
+    db2_->GetChildrenInternalId(children, id);
+
+    std::set<size_t> instances;
+    for (std::list<int64_t>::const_iterator 
+           it = children.begin(); it != children.end(); it++)
+    {
+      // Get the index of this instance in the series
+      s = db2_->GetMetadata(*it, MetadataType_Instance_IndexInSeries);
+      size_t index;
+      try
+      {
+        index = boost::lexical_cast<size_t>(s);
+      }
+      catch (boost::bad_lexical_cast&)
+      {
+        return SeriesStatus_Unknown;
+      }
+
+      if (index <= 0 || index > expected)
+      {
+        // Out-of-range instance index
+        return SeriesStatus_Inconsistent;
+      }
+
+      if (instances.find(index) != instances.end())
+      {
+        // Twice the same instance index
+        return SeriesStatus_Inconsistent;
+      }
+
+      instances.insert(index);
+    }
+
+    if (instances.size() == expected)
+    {
+      return SeriesStatus_Complete;
+    }
+    else
+    {
+      return SeriesStatus_Missing;
+    }
+  }
+
+
+
   void ServerIndex::MainDicomTagsToJson2(Json::Value& target,
                                          int64_t resourceId)
   {
@@ -797,14 +863,18 @@
   }
 
   bool ServerIndex::LookupResource(Json::Value& result,
-                                   const std::string& publicId)
+                                   const std::string& publicId,
+                                   ResourceType expectedType)
   {
     result = Json::objectValue;
 
+    boost::mutex::scoped_lock scoped_lock(mutex_);
+
     // Lookup for the requested resource
     int64_t id;
     ResourceType type;
-    if (!db2_->LookupResource(publicId, id, type))
+    if (!db2_->LookupResource(publicId, id, type) ||
+        type != expectedType)
     {
       return false;
     }
@@ -884,8 +954,21 @@
       break;
 
     case ResourceType_Series:
+    {
       result["Type"] = "Series";
+      result["Status"] = ToString(GetSeriesStatus(id));
+
+      std::string n = db2_->GetMetadata(id, MetadataType_Series_ExpectedNumberOfInstances);
+      if (n.size() > 0)
+      {
+        result["ExpectedNumberOfInstances"] = n;
+      }
+      else
+      {
+        result["ExpectedNumberOfInstances"] = Json::nullValue;
+      }
       break;
+    }
 
     case ResourceType_Instance:
       result["Type"] = "Instance";
@@ -942,6 +1025,8 @@
   bool ServerIndex::GetSeries(Json::Value& result,
                               const std::string& seriesUuid)
   {
+    return LookupResource(result, seriesUuid, ResourceType_Series);
+
     assert(result.type() == Json::objectValue);
     boost::mutex::scoped_lock scoped_lock(mutex_);
 
@@ -975,28 +1060,7 @@
       result["ExpectedNumberOfInstances"] = s1.ColumnInt(2);
     }
 
-    SeriesStatus status = GetSeriesStatus(seriesUuid);
-
-    switch (status)
-    {
-    case SeriesStatus_Complete:
-      result["Status"] = "Complete";
-      break;
-
-    case SeriesStatus_Missing:
-      result["Status"] = "Missing";
-      break;
-
-    case SeriesStatus_Inconsistent:
-      result["Status"] = "Inconsistent";
-      break;
-
-    default:
-    case SeriesStatus_Unknown:
-      result["Status"] = "Unknown";
-      break;
-    }
-
+    result["Status"] = ToString(GetSeriesStatus(seriesUuid));
     result["Type"] = "Series";
 
     return true;
@@ -1006,63 +1070,14 @@
   bool ServerIndex::GetStudy(Json::Value& result,
                              const std::string& studyUuid)
   {
-    assert(result.type() == Json::objectValue);
-    boost::mutex::scoped_lock scoped_lock(mutex_);
-
-    SQLite::Statement s1(db_, SQLITE_FROM_HERE, "SELECT parentPatient, dicomStudy FROM Studies WHERE uuid=?");
-    s1.BindString(0, studyUuid);
-    if (!s1.Step())
-    {
-      return false;
-    }
-
-    result["ID"] = studyUuid;
-    result["ParentPatient"] = s1.ColumnString(0);
-    MainDicomTagsToJson(result, studyUuid);
-
-    Json::Value series(Json::arrayValue);
-    SQLite::Statement s2(db_, SQLITE_FROM_HERE, "SELECT uuid FROM Series WHERE parentStudy=?");
-    s2.BindString(0, studyUuid);
-    while (s2.Step())
-    {
-      series.append(s2.ColumnString(0));
-    }
-      
-    result["Series"] = series;
-    result["Type"] = "Study";
-    return true;
+    return LookupResource(result, studyUuid, ResourceType_Study);
   }
 
 
   bool ServerIndex::GetPatient(Json::Value& result,
                                const std::string& patientUuid)
   {
-    assert(result.type() == Json::objectValue);
-    boost::mutex::scoped_lock scoped_lock(mutex_);
-
-    SQLite::Statement s1(db_, SQLITE_FROM_HERE, "SELECT dicomPatientId FROM Patients WHERE uuid=?");
-    s1.BindString(0, patientUuid);
-    if (!s1.Step())
-    {
-      return false;
-    }
-
-    result["ID"] = patientUuid;
-    MainDicomTagsToJson(result, patientUuid);
-
-    Json::Value studies(Json::arrayValue);
-    SQLite::Statement s2(db_, SQLITE_FROM_HERE, "SELECT uuid FROM Studies WHERE parentPatient=?");
-    s2.BindString(0, patientUuid);
-    while (s2.Step())
-    {
-      studies.append(s2.ColumnString(0));
-    }
-      
-    result["Studies"] = studies;
-    result["Type"] = "Patient";
-    return true;
-
-    //return LookupResource(result, patientUuid);
+    return LookupResource(result, patientUuid, ResourceType_Patient);
   }
 
 
--- a/OrthancServer/ServerIndex.h	Tue Nov 27 15:49:42 2012 +0100
+++ b/OrthancServer/ServerIndex.h	Tue Nov 27 16:20:22 2012 +0100
@@ -98,8 +98,6 @@
                         const std::string& jsonUuid, 
                         const std::string& remoteAet);
 
-
-
     void RecordChange(const std::string& resourceType,
                       const std::string& uuid);
 
@@ -125,7 +123,12 @@
                        const std::string& remoteAet);
 
     bool LookupResource(Json::Value& result,
-                        const std::string& publicId);
+                        const std::string& publicId,
+                        ResourceType expectedType);
+
+    SeriesStatus GetSeriesStatus(int id);
+
+    SeriesStatus GetSeriesStatus(const std::string& seriesUuid);
 
   public:
     ServerIndex(const std::string& storagePath);
@@ -147,8 +150,6 @@
 
     uint64_t GetTotalUncompressedSize();
 
-    SeriesStatus GetSeriesStatus(const std::string& seriesUuid);
-
 
     bool GetInstance(Json::Value& result,
                      const std::string& instanceUuid);