# HG changeset patch # User Sebastien Jodogne # Date 1382110046 -7200 # Node ID 60d90e48e809c9e2aac119ad8444fbbc74eb2398 # Parent fdd5f7f9c4d79d57dc0fcb360f698d86e5a73487 query/retrieve diff -r fdd5f7f9c4d7 -r 60d90e48e809 OrthancServer/Internals/MoveScp.cpp --- a/OrthancServer/Internals/MoveScp.cpp Fri Oct 18 14:17:51 2013 +0200 +++ b/OrthancServer/Internals/MoveScp.cpp Fri Oct 18 17:27:26 2013 +0200 @@ -82,6 +82,13 @@ try { data.iterator_.reset(data.handler_->Handle(data.target_, data.input_)); + if (data.iterator_.get() == NULL) + { + // Internal error! + response->DimseStatus = STATUS_MOVE_Failed_UnableToProcess; + return; + } + data.subOperationCount_ = data.iterator_->GetSubOperationCount(); data.failureCount_ = 0; data.warningCount_ = 0; diff -r fdd5f7f9c4d7 -r 60d90e48e809 OrthancServer/OrthancInitialization.cpp --- a/OrthancServer/OrthancInitialization.cpp Fri Oct 18 14:17:51 2013 +0200 +++ b/OrthancServer/OrthancInitialization.cpp Fri Oct 18 17:27:26 2013 +0200 @@ -464,4 +464,69 @@ target.push_back(lst[i].asString()); } } + + + void ConnectToModalityUsingSymbolicName(DicomUserConnection& connection, + const std::string& name) + { + std::string aet, address; + int port; + ModalityManufacturer manufacturer; + GetDicomModality(name, aet, address, port, manufacturer); + + LOG(WARNING) << "Connecting to remote DICOM modality: AET=" << aet << ", address=" << address << ", port=" << port; + + connection.SetLocalApplicationEntityTitle(GetGlobalStringParameter("DicomAet", "ORTHANC")); + connection.SetDistantApplicationEntityTitle(aet); + connection.SetDistantHost(address); + connection.SetDistantPort(port); + connection.SetDistantManufacturer(manufacturer); + connection.Open(); + } + + + void ConnectToModalityUsingAETitle(DicomUserConnection& connection, + const std::string& aet) + { + std::set modalities; + GetListOfDicomModalities(modalities); + + std::string address; + int port; + ModalityManufacturer manufacturer; + bool found = false; + + for (std::set::const_iterator + it = modalities.begin(); it != modalities.end(); it++) + { + try + { + std::string thisAet; + GetDicomModality(*it, thisAet, address, port, manufacturer); + + if (aet == thisAet) + { + found = true; + break; + } + } + catch (OrthancException&) + { + } + } + + if (!found) + { + throw OrthancException("Unknown modality: " + aet); + } + + LOG(WARNING) << "Connecting to remote DICOM modality: AET=" << aet << ", address=" << address << ", port=" << port; + + connection.SetLocalApplicationEntityTitle(GetGlobalStringParameter("DicomAet", "ORTHANC")); + connection.SetDistantApplicationEntityTitle(aet); + connection.SetDistantHost(address); + connection.SetDistantPort(port); + connection.SetDistantManufacturer(manufacturer); + connection.Open(); + } } diff -r fdd5f7f9c4d7 -r 60d90e48e809 OrthancServer/OrthancInitialization.h --- a/OrthancServer/OrthancInitialization.h Fri Oct 18 14:17:51 2013 +0200 +++ b/OrthancServer/OrthancInitialization.h Fri Oct 18 17:27:26 2013 +0200 @@ -37,6 +37,7 @@ #include #include #include "../Core/HttpServer/MongooseServer.h" +#include "DicomProtocol/DicomUserConnection.h" #include "ServerEnumerations.h" namespace Orthanc @@ -78,4 +79,10 @@ void GetGlobalListOfStringsParameter(std::list& target, const std::string& key); + + void ConnectToModalityUsingSymbolicName(DicomUserConnection& connection, + const std::string& name); + + void ConnectToModalityUsingAETitle(DicomUserConnection& connection, + const std::string& aet); } diff -r fdd5f7f9c4d7 -r 60d90e48e809 OrthancServer/OrthancRestApi.cpp --- a/OrthancServer/OrthancRestApi.cpp Fri Oct 18 14:17:51 2013 +0200 +++ b/OrthancServer/OrthancRestApi.cpp Fri Oct 18 17:27:26 2013 +0200 @@ -71,21 +71,6 @@ // DICOM SCU ---------------------------------------------------------------- - static void ConnectToModality(DicomUserConnection& connection, - const std::string& name) - { - std::string aet, address; - int port; - ModalityManufacturer manufacturer; - GetDicomModality(name, aet, address, port, manufacturer); - connection.SetLocalApplicationEntityTitle(GetGlobalStringParameter("DicomAet", "ORTHANC")); - connection.SetDistantApplicationEntityTitle(aet); - connection.SetDistantHost(address); - connection.SetDistantPort(port); - connection.SetDistantManufacturer(manufacturer); - connection.Open(); - } - static bool MergeQueryAndTemplate(DicomMap& result, const std::string& postData) { @@ -118,7 +103,7 @@ } DicomUserConnection connection; - ConnectToModality(connection, call.GetUriComponent("id", "")); + ConnectToModalityUsingSymbolicName(connection, call.GetUriComponent("id", "")); DicomFindAnswers answers; connection.FindPatient(answers, m); @@ -144,7 +129,7 @@ } DicomUserConnection connection; - ConnectToModality(connection, call.GetUriComponent("id", "")); + ConnectToModalityUsingSymbolicName(connection, call.GetUriComponent("id", "")); DicomFindAnswers answers; connection.FindStudy(answers, m); @@ -171,7 +156,7 @@ } DicomUserConnection connection; - ConnectToModality(connection, call.GetUriComponent("id", "")); + ConnectToModalityUsingSymbolicName(connection, call.GetUriComponent("id", "")); DicomFindAnswers answers; connection.FindSeries(answers, m); @@ -199,7 +184,7 @@ } DicomUserConnection connection; - ConnectToModality(connection, call.GetUriComponent("id", "")); + ConnectToModalityUsingSymbolicName(connection, call.GetUriComponent("id", "")); DicomFindAnswers answers; connection.FindInstance(answers, m); @@ -219,7 +204,7 @@ } DicomUserConnection connection; - ConnectToModality(connection, call.GetUriComponent("id", "")); + ConnectToModalityUsingSymbolicName(connection, call.GetUriComponent("id", "")); DicomFindAnswers patients; connection.FindPatient(patients, m); @@ -350,7 +335,7 @@ } DicomUserConnection connection; - ConnectToModality(connection, remote); + ConnectToModalityUsingSymbolicName(connection, remote); for (std::list::const_iterator it = instances.begin(); it != instances.end(); it++) diff -r fdd5f7f9c4d7 -r 60d90e48e809 OrthancServer/main.cpp --- a/OrthancServer/main.cpp Fri Oct 18 14:17:51 2013 +0200 +++ b/OrthancServer/main.cpp Fri Oct 18 17:27:26 2013 +0200 @@ -41,6 +41,7 @@ #include "../Core/Lua/LuaFunctionCall.h" #include "../Core/DicomFormat/DicomArray.h" #include "DicomProtocol/DicomServer.h" +#include "DicomProtocol/DicomUserConnection.h" #include "OrthancInitialization.h" #include "ServerContext.h" #include "OrthancFindRequestHandler.h" @@ -49,13 +50,13 @@ -class MyStoreRequestHandler : public IStoreRequestHandler +class OrthancStoreRequestHandler : public IStoreRequestHandler { private: ServerContext& server_; public: - MyStoreRequestHandler(ServerContext& context) : + OrthancStoreRequestHandler(ServerContext& context) : server_(context) { } @@ -73,13 +74,92 @@ }; -class MyMoveRequestHandler : public IMoveRequestHandler + +class OrthancMoveRequestIterator : public IMoveRequestIterator +{ +private: + ServerContext& context_; + std::vector instances_; + DicomUserConnection connection_; + size_t position_; + +public: + OrthancMoveRequestIterator(ServerContext& context, + const std::string& target, + const std::string& publicId) : + context_(context), + position_(0) + { + LOG(INFO) << "Sending resource " << publicId << " to modality \"" << target << "\""; + + std::list tmp; + context_.GetIndex().GetChildInstances(tmp, publicId); + + instances_.reserve(tmp.size()); + for (std::list::iterator it = tmp.begin(); it != tmp.end(); it++) + { + instances_.push_back(*it); + } + + ConnectToModalityUsingAETitle(connection_, target); + } + + virtual unsigned int GetSubOperationCount() const + { + return instances_.size(); + } + + virtual Status DoNext() + { + if (position_ >= instances_.size()) + { + return Status_Failure; + } + + const std::string& id = instances_[position_++]; + + std::string dicom; + context_.ReadFile(dicom, id, FileContentType_Dicom); + connection_.Store(dicom); + + return Status_Success; + } +}; + + + +class OrthancMoveRequestHandler : public IMoveRequestHandler { private: ServerContext& context_; + bool LookupResource(std::string& publicId, + DicomTag tag, + const DicomMap& input) + { + if (!input.HasTag(tag)) + { + return false; + } + + std::string value = input.GetValue(tag).AsString(); + + std::list ids; + context_.GetIndex().LookupTagValue(ids, tag, value); + + if (ids.size() != 1) + { + return false; + } + else + { + publicId = ids.front(); + return true; + } + } + public: - MyMoveRequestHandler(ServerContext& context) : + OrthancMoveRequestHandler(ServerContext& context) : context_(context) { } @@ -88,8 +168,57 @@ virtual IMoveRequestIterator* Handle(const std::string& target, const DicomMap& input) { - LOG(WARNING) << "Move-SCU request received"; - return NULL; + LOG(WARNING) << "Move-SCU request received for AET \"" << target << "\""; + + + /** + * Retrieve the query level. + **/ + + const DicomValue* levelTmp = input.TestAndGetValue(DICOM_TAG_QUERY_RETRIEVE_LEVEL); + if (levelTmp == NULL) + { + throw OrthancException(ErrorCode_BadRequest); + } + + ResourceType level = StringToResourceType(levelTmp->AsString().c_str()); + + + /** + * Lookup for the resource to be sent. + **/ + + bool ok; + std::string publicId; + + switch (level) + { + case ResourceType_Patient: + ok = LookupResource(publicId, DICOM_TAG_PATIENT_ID, input); + break; + + case ResourceType_Study: + ok = LookupResource(publicId, DICOM_TAG_STUDY_INSTANCE_UID, input); + break; + + case ResourceType_Series: + ok = LookupResource(publicId, DICOM_TAG_SERIES_INSTANCE_UID, input); + break; + + case ResourceType_Instance: + ok = LookupResource(publicId, DICOM_TAG_SOP_INSTANCE_UID, input); + break; + + default: + ok = false; + } + + if (!ok) + { + throw OrthancException(ErrorCode_BadRequest); + } + + return new OrthancMoveRequestIterator(context_, target, publicId); } }; @@ -109,7 +238,7 @@ virtual IStoreRequestHandler* ConstructStoreRequestHandler() { - return new MyStoreRequestHandler(context_); + return new OrthancStoreRequestHandler(context_); } virtual IFindRequestHandler* ConstructFindRequestHandler() @@ -119,7 +248,7 @@ virtual IMoveRequestHandler* ConstructMoveRequestHandler() { - return new MyMoveRequestHandler(context_); + return new OrthancMoveRequestHandler(context_); } void Done()