# HG changeset patch # User Sebastien Jodogne # Date 1354029622 -3600 # Node ID dfa2899d99607b15e271321a3a3ef0a6d381a01e # Parent 663cc6c46d0a47e19a59f76f7a783dcfdf883fab refactoring cont diff -r 663cc6c46d0a -r dfa2899d9960 CMakeLists.txt --- 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 diff -r 663cc6c46d0a -r dfa2899d9960 OrthancServer/DatabaseWrapper.cpp --- 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& 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, diff -r 663cc6c46d0a -r dfa2899d9960 OrthancServer/DatabaseWrapper.h --- 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& result, int64_t id); + void GetChildrenInternalId(std::list& result, + int64_t id); + void LogChange(ChangeType changeType, int64_t internalId, ResourceType resourceType, diff -r 663cc6c46d0a -r dfa2899d9960 OrthancServer/OrthancRestApi.cpp --- 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") diff -r 663cc6c46d0a -r dfa2899d9960 OrthancServer/ServerEnumerations.cpp --- /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 . + **/ + +#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); + } + } +} diff -r 663cc6c46d0a -r dfa2899d9960 OrthancServer/ServerEnumerations.h --- 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); } diff -r 663cc6c46d0a -r dfa2899d9960 OrthancServer/ServerIndex.cpp --- 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(s); + if (expected < 0) + { + return SeriesStatus_Unknown; + } + } + catch (boost::bad_lexical_cast&) + { + return SeriesStatus_Unknown; + } + + // Loop over the instances of this series + std::list children; + db2_->GetChildrenInternalId(children, id); + + std::set instances; + for (std::list::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(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); } diff -r 663cc6c46d0a -r dfa2899d9960 OrthancServer/ServerIndex.h --- 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);