comparison OrthancServer/OrthancRestApi/OrthancRestModalities.cpp @ 2982:94c8222c52b7

New URIs to launch new C-FIND to explore the hierarchy of a C-FIND answer
author Sebastien Jodogne <s.jodogne@gmail.com>
date Fri, 07 Dec 2018 18:03:56 +0100
parents bbfd95a0c429
children b1ba0a8311b5
comparison
equal deleted inserted replaced
2980:63b724c7b046 2982:94c8222c52b7
45 #include "../ServerToolbox.h" 45 #include "../ServerToolbox.h"
46 46
47 47
48 namespace Orthanc 48 namespace Orthanc
49 { 49 {
50 static const char* const KEY_LEVEL = "Level";
51 static const char* const KEY_QUERY = "Query";
52 static const char* const KEY_RESOURCES = "Resources";
53
54
50 static RemoteModalityParameters MyGetModalityUsingSymbolicName(const std::string& name) 55 static RemoteModalityParameters MyGetModalityUsingSymbolicName(const std::string& name)
51 { 56 {
52 OrthancConfiguration::ReaderLock lock; 57 OrthancConfiguration::ReaderLock lock;
53 return lock.GetConfiguration().GetModalityUsingSymbolicName(name); 58 return lock.GetConfiguration().GetModalityUsingSymbolicName(name);
54 } 59 }
406 411
407 /*************************************************************************** 412 /***************************************************************************
408 * DICOM C-Find and C-Move SCU => Recommended since Orthanc 0.9.0 413 * DICOM C-Find and C-Move SCU => Recommended since Orthanc 0.9.0
409 ***************************************************************************/ 414 ***************************************************************************/
410 415
416 static void AnswerQueryHandler(RestApiPostCall& call,
417 std::auto_ptr<QueryRetrieveHandler>& handler)
418 {
419 ServerContext& context = OrthancRestApi::GetContext(call);
420
421 if (handler.get() == NULL)
422 {
423 throw OrthancException(ErrorCode_NullPointer);
424 }
425
426 handler->Run();
427
428 std::string s = context.GetQueryRetrieveArchive().Add(handler.release());
429 Json::Value result = Json::objectValue;
430 result["ID"] = s;
431 result["Path"] = "/queries/" + s;
432
433 call.GetOutput().AnswerJson(result);
434 }
435
436
411 static void DicomQuery(RestApiPostCall& call) 437 static void DicomQuery(RestApiPostCall& call)
412 { 438 {
413 ServerContext& context = OrthancRestApi::GetContext(call); 439 ServerContext& context = OrthancRestApi::GetContext(call);
414 Json::Value request; 440 Json::Value request;
415 441
416 if (call.ParseJsonRequest(request) && 442 if (call.ParseJsonRequest(request) &&
417 request.type() == Json::objectValue && 443 request.type() == Json::objectValue &&
418 request.isMember("Level") && request["Level"].type() == Json::stringValue && 444 request.isMember(KEY_LEVEL) && request[KEY_LEVEL].type() == Json::stringValue &&
419 (!request.isMember("Query") || request["Query"].type() == Json::objectValue)) 445 (!request.isMember(KEY_QUERY) || request[KEY_QUERY].type() == Json::objectValue))
420 { 446 {
421 std::auto_ptr<QueryRetrieveHandler> handler(new QueryRetrieveHandler(context)); 447 std::auto_ptr<QueryRetrieveHandler> handler(new QueryRetrieveHandler(context));
422 448
423 handler->SetModality(call.GetUriComponent("id", "")); 449 handler->SetModality(call.GetUriComponent("id", ""));
424 handler->SetLevel(StringToResourceType(request["Level"].asCString())); 450 handler->SetLevel(StringToResourceType(request[KEY_LEVEL].asCString()));
425 451
426 if (request.isMember("Query")) 452 if (request.isMember(KEY_QUERY))
427 { 453 {
428 Json::Value::Members tags = request["Query"].getMemberNames(); 454 std::map<DicomTag, std::string> query;
429 for (size_t i = 0; i < tags.size(); i++) 455 SerializationToolbox::ReadMapOfTags(query, request, KEY_QUERY);
456
457 for (std::map<DicomTag, std::string>::const_iterator
458 it = query.begin(); it != query.end(); ++it)
430 { 459 {
431 handler->SetQuery(FromDcmtkBridge::ParseTag(tags[i].c_str()), 460 handler->SetQuery(it->first, it->second);
432 request["Query"][tags[i]].asString());
433 } 461 }
434 } 462 }
435 463
436 handler->Run(); 464 AnswerQueryHandler(call, handler);
437
438 std::string s = context.GetQueryRetrieveArchive().Add(handler.release());
439 Json::Value result = Json::objectValue;
440 result["ID"] = s;
441 result["Path"] = "/queries/" + s;
442 call.GetOutput().AnswerJson(result);
443 } 465 }
444 } 466 }
445 467
446 468
447 static void ListQueries(RestApiGetCall& call) 469 static void ListQueries(RestApiGetCall& call)
467 class QueryAccessor 489 class QueryAccessor
468 { 490 {
469 private: 491 private:
470 ServerContext& context_; 492 ServerContext& context_;
471 SharedArchive::Accessor accessor_; 493 SharedArchive::Accessor accessor_;
472 QueryRetrieveHandler& handler_; 494 QueryRetrieveHandler* handler_;
473 495
474 public: 496 public:
475 QueryAccessor(RestApiCall& call) : 497 QueryAccessor(RestApiCall& call) :
476 context_(OrthancRestApi::GetContext(call)), 498 context_(OrthancRestApi::GetContext(call)),
477 accessor_(context_.GetQueryRetrieveArchive(), call.GetUriComponent("id", "")), 499 accessor_(context_.GetQueryRetrieveArchive(), call.GetUriComponent("id", "")),
478 handler_(dynamic_cast<QueryRetrieveHandler&>(accessor_.GetItem())) 500 handler_(NULL)
479 { 501 {
502 if (accessor_.IsValid())
503 {
504 handler_ = &dynamic_cast<QueryRetrieveHandler&>(accessor_.GetItem());
505 }
506 else
507 {
508 throw OrthancException(ErrorCode_UnknownResource);
509 }
480 } 510 }
481 511
482 QueryRetrieveHandler& GetHandler() const 512 QueryRetrieveHandler& GetHandler() const
483 { 513 {
484 return handler_; 514 assert(handler_ != NULL);
515 return *handler_;
485 } 516 }
486 }; 517 };
487 518
488 static void AnswerDicomMap(RestApiCall& call, 519 static void AnswerDicomMap(RestApiCall& call,
489 const DicomMap& value, 520 const DicomMap& value,
650 size_t index = boost::lexical_cast<size_t>(call.GetUriComponent("index", "")); 681 size_t index = boost::lexical_cast<size_t>(call.GetUriComponent("index", ""));
651 682
652 DicomMap map; 683 DicomMap map;
653 query.GetHandler().GetAnswer(map, index); 684 query.GetHandler().GetAnswer(map, index);
654 685
655 RestApi::AutoListChildren(call); 686 Json::Value answer = Json::arrayValue;
656 } 687 answer.append("content");
657 688 answer.append("retrieve");
658 689
690 switch (query.GetHandler().GetLevel())
691 {
692 case ResourceType_Patient:
693 answer.append("query-study");
694
695 case ResourceType_Study:
696 answer.append("query-series");
697
698 case ResourceType_Series:
699 answer.append("query-instances");
700 break;
701
702 default:
703 break;
704 }
705
706 call.GetOutput().AnswerJson(answer);
707 }
708
709
710 template <ResourceType CHILDREN_LEVEL>
711 static void AnswerQueryChildren(RestApiPostCall& call)
712 {
713 // New in Orthanc 1.4.3
714 assert(CHILDREN_LEVEL == ResourceType_Study ||
715 CHILDREN_LEVEL == ResourceType_Series ||
716 CHILDREN_LEVEL == ResourceType_Instance);
717
718 ServerContext& context = OrthancRestApi::GetContext(call);
719
720 std::auto_ptr<QueryRetrieveHandler> handler(new QueryRetrieveHandler(context));
721
722 {
723 const QueryAccessor parent(call);
724 const ResourceType level = parent.GetHandler().GetLevel();
725
726 const size_t index = boost::lexical_cast<size_t>(call.GetUriComponent("index", ""));
727
728 Json::Value request;
729
730 if (index >= parent.GetHandler().GetAnswersCount())
731 {
732 throw OrthancException(ErrorCode_ParameterOutOfRange);
733 }
734 else if (CHILDREN_LEVEL == ResourceType_Study &&
735 level != ResourceType_Patient)
736 {
737 throw OrthancException(ErrorCode_UnknownResource);
738 }
739 else if (CHILDREN_LEVEL == ResourceType_Series &&
740 level != ResourceType_Patient &&
741 level != ResourceType_Study)
742 {
743 throw OrthancException(ErrorCode_UnknownResource);
744 }
745 else if (CHILDREN_LEVEL == ResourceType_Instance &&
746 level != ResourceType_Patient &&
747 level != ResourceType_Study &&
748 level != ResourceType_Series)
749 {
750 throw OrthancException(ErrorCode_UnknownResource);
751 }
752 else if (!call.ParseJsonRequest(request))
753 {
754 throw OrthancException(ErrorCode_BadFileFormat, "Must provide a JSON object");
755 }
756 else
757 {
758 handler->SetModality(parent.GetHandler().GetModalitySymbolicName());
759 handler->SetLevel(CHILDREN_LEVEL);
760
761 if (request.isMember(KEY_QUERY))
762 {
763 std::map<DicomTag, std::string> query;
764 SerializationToolbox::ReadMapOfTags(query, request, KEY_QUERY);
765
766 for (std::map<DicomTag, std::string>::const_iterator
767 it = query.begin(); it != query.end(); ++it)
768 {
769 handler->SetQuery(it->first, it->second);
770 }
771 }
772 }
773 }
774
775 AnswerQueryHandler(call, handler);
776 }
777
659 778
660 779
661 /*************************************************************************** 780 /***************************************************************************
662 * DICOM C-Store SCU 781 * DICOM C-Store SCU
663 ***************************************************************************/ 782 ***************************************************************************/
699 resources = &request; 818 resources = &request;
700 } 819 }
701 else 820 else
702 { 821 {
703 if (request.type() != Json::objectValue || 822 if (request.type() != Json::objectValue ||
704 !request.isMember("Resources")) 823 !request.isMember(KEY_RESOURCES))
705 { 824 {
706 return false; 825 return false;
707 } 826 }
708 827
709 resources = &request["Resources"]; 828 resources = &request[KEY_RESOURCES];
710 if (!resources->isArray()) 829 if (!resources->isArray())
711 { 830 {
712 return false; 831 return false;
713 } 832 }
714 833
792 { 911 {
793 ServerContext& context = OrthancRestApi::GetContext(call); 912 ServerContext& context = OrthancRestApi::GetContext(call);
794 913
795 Json::Value request; 914 Json::Value request;
796 915
797 static const char* RESOURCES = "Resources";
798 static const char* LEVEL = "Level";
799
800 if (!call.ParseJsonRequest(request) || 916 if (!call.ParseJsonRequest(request) ||
801 request.type() != Json::objectValue || 917 request.type() != Json::objectValue ||
802 !request.isMember(RESOURCES) || 918 !request.isMember(KEY_RESOURCES) ||
803 !request.isMember(LEVEL) || 919 !request.isMember(KEY_LEVEL) ||
804 request[RESOURCES].type() != Json::arrayValue || 920 request[KEY_RESOURCES].type() != Json::arrayValue ||
805 request[LEVEL].type() != Json::stringValue) 921 request[KEY_LEVEL].type() != Json::stringValue)
806 { 922 {
807 throw OrthancException(ErrorCode_BadFileFormat); 923 throw OrthancException(ErrorCode_BadFileFormat);
808 } 924 }
809 925
810 ResourceType level = StringToResourceType(request["Level"].asCString()); 926 ResourceType level = StringToResourceType(request[KEY_LEVEL].asCString());
811 927
812 std::string localAet = Toolbox::GetJsonStringField 928 std::string localAet = Toolbox::GetJsonStringField
813 (request, "LocalAet", context.GetDefaultLocalApplicationEntityTitle()); 929 (request, "LocalAet", context.GetDefaultLocalApplicationEntityTitle());
814 std::string targetAet = Toolbox::GetJsonStringField 930 std::string targetAet = Toolbox::GetJsonStringField
815 (request, "TargetAet", context.GetDefaultLocalApplicationEntityTitle()); 931 (request, "TargetAet", context.GetDefaultLocalApplicationEntityTitle());
818 MyGetModalityUsingSymbolicName(call.GetUriComponent("id", "")); 934 MyGetModalityUsingSymbolicName(call.GetUriComponent("id", ""));
819 935
820 DicomUserConnection connection(localAet, source); 936 DicomUserConnection connection(localAet, source);
821 connection.Open(); 937 connection.Open();
822 938
823 for (Json::Value::ArrayIndex i = 0; i < request[RESOURCES].size(); i++) 939 for (Json::Value::ArrayIndex i = 0; i < request[KEY_RESOURCES].size(); i++)
824 { 940 {
825 DicomMap resource; 941 DicomMap resource;
826 FromDcmtkBridge::FromJson(resource, request[RESOURCES][i]); 942 FromDcmtkBridge::FromJson(resource, request[KEY_RESOURCES][i]);
827 943
828 connection.Move(targetAet, level, resource); 944 connection.Move(targetAet, level, resource);
829 } 945 }
830 946
831 // Move has succeeded 947 // Move has succeeded
1073 { 1189 {
1074 const std::string& localAet = context.GetDefaultLocalApplicationEntityTitle(); 1190 const std::string& localAet = context.GetDefaultLocalApplicationEntityTitle();
1075 RemoteModalityParameters remote = 1191 RemoteModalityParameters remote =
1076 MyGetModalityUsingSymbolicName(call.GetUriComponent("id", "")); 1192 MyGetModalityUsingSymbolicName(call.GetUriComponent("id", ""));
1077 1193
1078 std::auto_ptr<ParsedDicomFile> query(ParsedDicomFile::CreateFromJson(json, static_cast<DicomFromJsonFlags>(0))); 1194 std::auto_ptr<ParsedDicomFile> query
1195 (ParsedDicomFile::CreateFromJson(json, static_cast<DicomFromJsonFlags>(0)));
1079 1196
1080 DicomFindAnswers answers(true); 1197 DicomFindAnswers answers(true);
1081 1198
1082 { 1199 {
1083 DicomUserConnection connection(localAet, remote); 1200 DicomUserConnection connection(localAet, remote);
1114 Register("/queries/{id}", ListQueryOperations); 1231 Register("/queries/{id}", ListQueryOperations);
1115 Register("/queries/{id}/answers", ListQueryAnswers); 1232 Register("/queries/{id}/answers", ListQueryAnswers);
1116 Register("/queries/{id}/answers/{index}", ListQueryAnswerOperations); 1233 Register("/queries/{id}/answers/{index}", ListQueryAnswerOperations);
1117 Register("/queries/{id}/answers/{index}/content", GetQueryOneAnswer); 1234 Register("/queries/{id}/answers/{index}/content", GetQueryOneAnswer);
1118 Register("/queries/{id}/answers/{index}/retrieve", RetrieveOneAnswer); 1235 Register("/queries/{id}/answers/{index}/retrieve", RetrieveOneAnswer);
1236 Register("/queries/{id}/answers/{index}/query-instances",
1237 AnswerQueryChildren<ResourceType_Instance>);
1238 Register("/queries/{id}/answers/{index}/query-series",
1239 AnswerQueryChildren<ResourceType_Series>);
1240 Register("/queries/{id}/answers/{index}/query-studies",
1241 AnswerQueryChildren<ResourceType_Study>);
1119 Register("/queries/{id}/level", GetQueryLevel); 1242 Register("/queries/{id}/level", GetQueryLevel);
1120 Register("/queries/{id}/modality", GetQueryModality); 1243 Register("/queries/{id}/modality", GetQueryModality);
1121 Register("/queries/{id}/query", GetQueryArguments); 1244 Register("/queries/{id}/query", GetQueryArguments);
1122 Register("/queries/{id}/retrieve", RetrieveAllAnswers); 1245 Register("/queries/{id}/retrieve", RetrieveAllAnswers);
1123 1246