comparison OrthancServer/Sources/ServerIndex.cpp @ 4557:b6d4b735eb4d db-changes

templates to reduce verbosity in ServerIndex implementation
author Sebastien Jodogne <s.jodogne@gmail.com>
date Thu, 04 Mar 2021 15:22:55 +0100
parents 2a0f8031fb93
children 2f4d7ec9b993
comparison
equal deleted inserted replaced
4556:2a0f8031fb93 4557:b6d4b735eb4d
51 #include "ServerContext.h" 51 #include "ServerContext.h"
52 #include "ServerIndexChange.h" 52 #include "ServerIndexChange.h"
53 #include "ServerToolbox.h" 53 #include "ServerToolbox.h"
54 54
55 #include <boost/lexical_cast.hpp> 55 #include <boost/lexical_cast.hpp>
56 #include <boost/tuple/tuple.hpp>
56 #include <stdio.h> 57 #include <stdio.h>
57 #include <stack> 58 #include <stack>
58 59
59 static const uint64_t MEGA_BYTES = 1024 * 1024; 60 static const uint64_t MEGA_BYTES = 1024 * 1024;
60 61
2386 2387
2387 /*** 2388 /***
2388 ** PROTOTYPING FOR DB REFACTORING BELOW 2389 ** PROTOTYPING FOR DB REFACTORING BELOW
2389 ***/ 2390 ***/
2390 2391
2392 namespace
2393 {
2394 /**
2395 * Some handy templates to reduce the verbosity in the definitions
2396 * of the internal classes.
2397 **/
2398
2399 template <typename Operations,
2400 typename Tuple>
2401 class TupleOperationsWrapper : public ServerIndex::IReadOnlyOperations
2402 {
2403 protected:
2404 Operations& operations_;
2405 const Tuple& tuple_;
2406
2407 public:
2408 TupleOperationsWrapper(Operations& operations,
2409 const Tuple& tuple) :
2410 operations_(operations),
2411 tuple_(tuple)
2412 {
2413 }
2414
2415 virtual void Apply(ServerIndex::ReadOnlyTransaction& transaction) ORTHANC_OVERRIDE
2416 {
2417 operations_.ApplyTuple(transaction, tuple_);
2418 }
2419 };
2420
2421
2422 template <typename T1>
2423 class ReadOnlyOperationsT1 : public boost::noncopyable
2424 {
2425 public:
2426 typedef typename boost::tuple<T1> Tuple;
2427
2428 virtual ~ReadOnlyOperationsT1()
2429 {
2430 }
2431
2432 virtual void ApplyTuple(ServerIndex::ReadOnlyTransaction& transaction,
2433 const Tuple& tuple) = 0;
2434
2435 void Apply(ServerIndex& index,
2436 T1 t1)
2437 {
2438 const Tuple tuple(t1);
2439 TupleOperationsWrapper<ReadOnlyOperationsT1, Tuple> wrapper(*this, tuple);
2440 index.Apply(wrapper);
2441 }
2442 };
2443
2444
2445 template <typename T1,
2446 typename T2>
2447 class ReadOnlyOperationsT2 : public boost::noncopyable
2448 {
2449 public:
2450 typedef typename boost::tuple<T1, T2> Tuple;
2451
2452 virtual ~ReadOnlyOperationsT2()
2453 {
2454 }
2455
2456 virtual void ApplyTuple(ServerIndex::ReadOnlyTransaction& transaction,
2457 const Tuple& tuple) = 0;
2458
2459 void Apply(ServerIndex& index,
2460 T1 t1,
2461 T2 t2)
2462 {
2463 const Tuple tuple(t1, t2);
2464 TupleOperationsWrapper<ReadOnlyOperationsT2, Tuple> wrapper(*this, tuple);
2465 index.Apply(wrapper);
2466 }
2467 };
2468
2469
2470 template <typename T1,
2471 typename T2,
2472 typename T3>
2473 class ReadOnlyOperationsT3 : public boost::noncopyable
2474 {
2475 public:
2476 typedef typename boost::tuple<T1, T2, T3> Tuple;
2477
2478 virtual ~ReadOnlyOperationsT3()
2479 {
2480 }
2481
2482 virtual void ApplyTuple(ServerIndex::ReadOnlyTransaction& transaction,
2483 const Tuple& tuple) = 0;
2484
2485 void Apply(ServerIndex& index,
2486 T1 t1,
2487 T2 t2,
2488 T3 t3)
2489 {
2490 const Tuple tuple(t1, t2, t3);
2491 TupleOperationsWrapper<ReadOnlyOperationsT3, Tuple> wrapper(*this, tuple);
2492 index.Apply(wrapper);
2493 }
2494 };
2495
2496
2497 template <typename T1,
2498 typename T2,
2499 typename T3,
2500 typename T4>
2501 class ReadOnlyOperationsT4 : public boost::noncopyable
2502 {
2503 public:
2504 typedef typename boost::tuple<T1, T2, T3, T4> Tuple;
2505
2506 virtual ~ReadOnlyOperationsT4()
2507 {
2508 }
2509
2510 virtual void ApplyTuple(ServerIndex::ReadOnlyTransaction& transaction,
2511 const Tuple& tuple) = 0;
2512
2513 void Apply(ServerIndex& index,
2514 T1 t1,
2515 T2 t2,
2516 T3 t3,
2517 T4 t4)
2518 {
2519 const Tuple tuple(t1, t2, t3, t4);
2520 TupleOperationsWrapper<ReadOnlyOperationsT4, Tuple> wrapper(*this, tuple);
2521 index.Apply(wrapper);
2522 }
2523 };
2524 }
2525
2526
2391 class ServerIndex::ReadOnlyWrapper : public IReadOnlyOperations 2527 class ServerIndex::ReadOnlyWrapper : public IReadOnlyOperations
2392 { 2528 {
2393 private: 2529 private:
2394 ReadOnlyFunction func_; 2530 ReadOnlyFunction func_;
2395 2531
2516 2652
2517 bool ServerIndex::ExpandResource(Json::Value& target, 2653 bool ServerIndex::ExpandResource(Json::Value& target,
2518 const std::string& publicId, 2654 const std::string& publicId,
2519 ResourceType level) 2655 ResourceType level)
2520 { 2656 {
2521 class Operations : public ServerIndex::IReadOnlyOperations 2657 class Operations : public ReadOnlyOperationsT3<Json::Value*, std::string, ResourceType>
2522 { 2658 {
2523 private: 2659 private:
2524 Json::Value& target_; 2660 ServerIndex& index_;
2525 bool found_; 2661 bool found_;
2526 ServerIndex& index_;
2527 const std::string& publicId_;
2528 ResourceType level_;
2529 2662
2530 public: 2663 public:
2531 Operations(Json::Value& target, 2664 Operations(ServerIndex& index) :
2532 ServerIndex& index,
2533 const std::string& publicId,
2534 ResourceType level) :
2535 target_(target),
2536 found_(false),
2537 index_(index), 2665 index_(index),
2538 publicId_(publicId), 2666 found_(false)
2539 level_(level)
2540 { 2667 {
2541 } 2668 }
2542 2669
2543 virtual void Apply(ServerIndex::ReadOnlyTransaction& transaction) ORTHANC_OVERRIDE 2670 bool HasFound() const
2544 { 2671 {
2672 return found_;
2673 }
2674
2675 virtual void ApplyTuple(ReadOnlyTransaction& transaction,
2676 const Tuple& tuple) ORTHANC_OVERRIDE
2677 {
2678 Json::Value& target = *tuple.get<0>();
2679
2545 // Lookup for the requested resource 2680 // Lookup for the requested resource
2546 int64_t internalId; // unused 2681 int64_t internalId; // unused
2547 ResourceType type; 2682 ResourceType type;
2548 std::string parent; 2683 std::string parent;
2549 if (!transaction.LookupResourceAndParent(internalId, type, parent, publicId_) || 2684 if (!transaction.LookupResourceAndParent(internalId, type, parent, tuple.get<1>()) ||
2550 type != level_) 2685 type != tuple.get<2>())
2551 { 2686 {
2552 found_ = false; 2687 found_ = false;
2553 } 2688 }
2554 else 2689 else
2555 { 2690 {
2556 target_ = Json::objectValue; 2691 target = Json::objectValue;
2557 2692
2558 // Set information about the parent resource (if it exists) 2693 // Set information about the parent resource (if it exists)
2559 if (type == ResourceType_Patient) 2694 if (type == ResourceType_Patient)
2560 { 2695 {
2561 if (!parent.empty()) 2696 if (!parent.empty())
2571 } 2706 }
2572 2707
2573 switch (type) 2708 switch (type)
2574 { 2709 {
2575 case ResourceType_Study: 2710 case ResourceType_Study:
2576 target_["ParentPatient"] = parent; 2711 target["ParentPatient"] = parent;
2577 break; 2712 break;
2578 2713
2579 case ResourceType_Series: 2714 case ResourceType_Series:
2580 target_["ParentStudy"] = parent; 2715 target["ParentStudy"] = parent;
2581 break; 2716 break;
2582 2717
2583 case ResourceType_Instance: 2718 case ResourceType_Instance:
2584 target_["ParentSeries"] = parent; 2719 target["ParentSeries"] = parent;
2585 break; 2720 break;
2586 2721
2587 default: 2722 default:
2588 throw OrthancException(ErrorCode_InternalError); 2723 throw OrthancException(ErrorCode_InternalError);
2589 } 2724 }
2604 } 2739 }
2605 2740
2606 switch (type) 2741 switch (type)
2607 { 2742 {
2608 case ResourceType_Patient: 2743 case ResourceType_Patient:
2609 target_["Studies"] = c; 2744 target["Studies"] = c;
2610 break; 2745 break;
2611 2746
2612 case ResourceType_Study: 2747 case ResourceType_Study:
2613 target_["Series"] = c; 2748 target["Series"] = c;
2614 break; 2749 break;
2615 2750
2616 case ResourceType_Series: 2751 case ResourceType_Series:
2617 target_["Instances"] = c; 2752 target["Instances"] = c;
2618 break; 2753 break;
2619 2754
2620 default: 2755 default:
2621 throw OrthancException(ErrorCode_InternalError); 2756 throw OrthancException(ErrorCode_InternalError);
2622 } 2757 }
2628 2763
2629 // Set the resource type 2764 // Set the resource type
2630 switch (type) 2765 switch (type)
2631 { 2766 {
2632 case ResourceType_Patient: 2767 case ResourceType_Patient:
2633 target_["Type"] = "Patient"; 2768 target["Type"] = "Patient";
2634 break; 2769 break;
2635 2770
2636 case ResourceType_Study: 2771 case ResourceType_Study:
2637 target_["Type"] = "Study"; 2772 target["Type"] = "Study";
2638 break; 2773 break;
2639 2774
2640 case ResourceType_Series: 2775 case ResourceType_Series:
2641 { 2776 {
2642 target_["Type"] = "Series"; 2777 target["Type"] = "Series";
2643 2778
2644 int64_t i; 2779 int64_t i;
2645 if (LookupIntegerMetadata(i, metadata, MetadataType_Series_ExpectedNumberOfInstances)) 2780 if (LookupIntegerMetadata(i, metadata, MetadataType_Series_ExpectedNumberOfInstances))
2646 { 2781 {
2647 target_["ExpectedNumberOfInstances"] = static_cast<int>(i); 2782 target["ExpectedNumberOfInstances"] = static_cast<int>(i);
2648 target_["Status"] = EnumerationToString(transaction.GetSeriesStatus(internalId, i)); 2783 target["Status"] = EnumerationToString(transaction.GetSeriesStatus(internalId, i));
2649 } 2784 }
2650 else 2785 else
2651 { 2786 {
2652 target_["ExpectedNumberOfInstances"] = Json::nullValue; 2787 target["ExpectedNumberOfInstances"] = Json::nullValue;
2653 target_["Status"] = EnumerationToString(SeriesStatus_Unknown); 2788 target["Status"] = EnumerationToString(SeriesStatus_Unknown);
2654 } 2789 }
2655 2790
2656 break; 2791 break;
2657 } 2792 }
2658 2793
2659 case ResourceType_Instance: 2794 case ResourceType_Instance:
2660 { 2795 {
2661 target_["Type"] = "Instance"; 2796 target["Type"] = "Instance";
2662 2797
2663 FileInfo attachment; 2798 FileInfo attachment;
2664 if (!transaction.LookupAttachment(attachment, internalId, FileContentType_Dicom)) 2799 if (!transaction.LookupAttachment(attachment, internalId, FileContentType_Dicom))
2665 { 2800 {
2666 throw OrthancException(ErrorCode_InternalError); 2801 throw OrthancException(ErrorCode_InternalError);
2667 } 2802 }
2668 2803
2669 target_["FileSize"] = static_cast<unsigned int>(attachment.GetUncompressedSize()); 2804 target["FileSize"] = static_cast<unsigned int>(attachment.GetUncompressedSize());
2670 target_["FileUuid"] = attachment.GetUuid(); 2805 target["FileUuid"] = attachment.GetUuid();
2671 2806
2672 int64_t i; 2807 int64_t i;
2673 if (LookupIntegerMetadata(i, metadata, MetadataType_Instance_IndexInSeries)) 2808 if (LookupIntegerMetadata(i, metadata, MetadataType_Instance_IndexInSeries))
2674 { 2809 {
2675 target_["IndexInSeries"] = static_cast<int>(i); 2810 target["IndexInSeries"] = static_cast<int>(i);
2676 } 2811 }
2677 else 2812 else
2678 { 2813 {
2679 target_["IndexInSeries"] = Json::nullValue; 2814 target["IndexInSeries"] = Json::nullValue;
2680 } 2815 }
2681 2816
2682 break; 2817 break;
2683 } 2818 }
2684 2819
2685 default: 2820 default:
2686 throw OrthancException(ErrorCode_InternalError); 2821 throw OrthancException(ErrorCode_InternalError);
2687 } 2822 }
2688 2823
2689 // Record the remaining information 2824 // Record the remaining information
2690 target_["ID"] = publicId_; 2825 target["ID"] = tuple.get<1>();
2691 transaction.MainDicomTagsToJson(target_, internalId, type); 2826 transaction.MainDicomTagsToJson(target, internalId, type);
2692 2827
2693 std::string tmp; 2828 std::string tmp;
2694 2829
2695 if (LookupStringMetadata(tmp, metadata, MetadataType_AnonymizedFrom)) 2830 if (LookupStringMetadata(tmp, metadata, MetadataType_AnonymizedFrom))
2696 { 2831 {
2697 target_["AnonymizedFrom"] = tmp; 2832 target["AnonymizedFrom"] = tmp;
2698 } 2833 }
2699 2834
2700 if (LookupStringMetadata(tmp, metadata, MetadataType_ModifiedFrom)) 2835 if (LookupStringMetadata(tmp, metadata, MetadataType_ModifiedFrom))
2701 { 2836 {
2702 target_["ModifiedFrom"] = tmp; 2837 target["ModifiedFrom"] = tmp;
2703 } 2838 }
2704 2839
2705 if (type == ResourceType_Patient || 2840 if (type == ResourceType_Patient ||
2706 type == ResourceType_Study || 2841 type == ResourceType_Study ||
2707 type == ResourceType_Series) 2842 type == ResourceType_Series)
2708 { 2843 {
2709 target_["IsStable"] = !index_.IsUnstableResource(internalId); 2844 target["IsStable"] = !index_.IsUnstableResource(internalId);
2710 2845
2711 if (LookupStringMetadata(tmp, metadata, MetadataType_LastUpdate)) 2846 if (LookupStringMetadata(tmp, metadata, MetadataType_LastUpdate))
2712 { 2847 {
2713 target_["LastUpdate"] = tmp; 2848 target["LastUpdate"] = tmp;
2714 } 2849 }
2715 } 2850 }
2716 2851
2717 found_ = true; 2852 found_ = true;
2718 } 2853 }
2719 } 2854 }
2720
2721 bool HasFound() const
2722 {
2723 return found_;
2724 }
2725 }; 2855 };
2726 2856
2727 Operations operations(target, *this, publicId, level); 2857 Operations operations(*this);
2728 Apply(operations); 2858 operations.Apply(*this, &target, publicId, level);
2729 return operations.HasFound(); 2859 return operations.HasFound();
2730 } 2860 }
2731 2861
2732 2862
2733 void ServerIndex::GetAllMetadata(std::map<MetadataType, std::string>& target, 2863 void ServerIndex::GetAllMetadata(std::map<MetadataType, std::string>& target,
2734 const std::string& publicId, 2864 const std::string& publicId,
2735 ResourceType level) 2865 ResourceType level)
2736 { 2866 {
2737 class Operations : public ServerIndex::IReadOnlyOperations 2867 class Operations : public ReadOnlyOperationsT3<std::map<MetadataType, std::string>*, std::string, ResourceType>
2738 { 2868 {
2739 private:
2740 std::map<MetadataType, std::string>& metadata_;
2741 std::string publicId_;
2742 ResourceType level_;
2743
2744 public: 2869 public:
2745 Operations(std::map<MetadataType, std::string>& metadata, 2870 virtual void ApplyTuple(ReadOnlyTransaction& transaction,
2746 const std::string& publicId, 2871 const Tuple& tuple) ORTHANC_OVERRIDE
2747 ResourceType level) :
2748 metadata_(metadata),
2749 publicId_(publicId),
2750 level_(level)
2751 {
2752 }
2753
2754 virtual void Apply(ServerIndex::ReadOnlyTransaction& transaction) ORTHANC_OVERRIDE
2755 { 2872 {
2756 ResourceType type; 2873 ResourceType type;
2757 int64_t id; 2874 int64_t id;
2758 if (!transaction.LookupResource(id, type, publicId_) || 2875 if (!transaction.LookupResource(id, type, tuple.get<1>()) ||
2759 level_ != type) 2876 tuple.get<2>() != type)
2760 { 2877 {
2761 throw OrthancException(ErrorCode_UnknownResource); 2878 throw OrthancException(ErrorCode_UnknownResource);
2762 } 2879 }
2763 else 2880 else
2764 { 2881 {
2765 transaction.GetAllMetadata(metadata_, id); 2882 transaction.GetAllMetadata(*tuple.get<0>(), id);
2766 } 2883 }
2767 } 2884 }
2768 }; 2885 };
2769 2886
2770 Operations operations(target, publicId, level); 2887 Operations operations;
2771 Apply(operations); 2888 operations.Apply(*this, &target, publicId, level);
2772 } 2889 }
2773 2890
2774 2891
2775 bool ServerIndex::LookupAttachment(FileInfo& attachment, 2892 bool ServerIndex::LookupAttachment(FileInfo& attachment,
2776 const std::string& instancePublicId, 2893 const std::string& instancePublicId,
2777 FileContentType contentType) 2894 FileContentType contentType)
2778 { 2895 {
2779 class Operations : public ServerIndex::IReadOnlyOperations 2896 class Operations : public ReadOnlyOperationsT3<FileInfo*, std::string, FileContentType>
2780 { 2897 {
2781 private: 2898 private:
2782 FileInfo& attachment_; 2899 bool found_;
2783 bool found_; 2900
2784 std::string instancePublicId_;
2785 FileContentType contentType_;
2786
2787 public: 2901 public:
2788 Operations(FileInfo& attachment, 2902 Operations() :
2789 const std::string& instancePublicId, 2903 found_(false)
2790 FileContentType contentType) : 2904 {
2791 attachment_(attachment), 2905 }
2792 found_(false), 2906
2793 instancePublicId_(instancePublicId), 2907 bool HasFound() const
2794 contentType_(contentType) 2908 {
2795 { 2909 return found_;
2796 } 2910 }
2797 2911
2798 virtual void Apply(ServerIndex::ReadOnlyTransaction& transaction) ORTHANC_OVERRIDE 2912 virtual void ApplyTuple(ReadOnlyTransaction& transaction,
2913 const Tuple& tuple) ORTHANC_OVERRIDE
2799 { 2914 {
2800 int64_t internalId; 2915 int64_t internalId;
2801 ResourceType type; 2916 ResourceType type;
2802 if (!transaction.LookupResource(internalId, type, instancePublicId_)) 2917 if (!transaction.LookupResource(internalId, type, tuple.get<1>()))
2803 { 2918 {
2804 throw OrthancException(ErrorCode_UnknownResource); 2919 throw OrthancException(ErrorCode_UnknownResource);
2805 } 2920 }
2806 else if (transaction.LookupAttachment(attachment_, internalId, contentType_)) 2921 else if (transaction.LookupAttachment(*tuple.get<0>(), internalId, tuple.get<2>()))
2807 { 2922 {
2808 assert(attachment_.GetContentType() == contentType_); 2923 assert(tuple.get<0>()->GetContentType() == tuple.get<2>());
2809 found_ = true; 2924 found_ = true;
2810 } 2925 }
2811 else 2926 else
2812 { 2927 {
2813 found_ = false; 2928 found_ = false;
2814 } 2929 }
2815 } 2930 }
2816
2817 bool HasFound() const
2818 {
2819 return found_;
2820 }
2821 }; 2931 };
2822 2932
2823 Operations operations(attachment, instancePublicId, contentType); 2933 Operations operations;
2824 Apply(operations); 2934 operations.Apply(*this, &attachment, instancePublicId, contentType);
2825 return operations.HasFound(); 2935 return operations.HasFound();
2826 } 2936 }
2827 2937
2828 2938
2829 2939
2830 void ServerIndex::GetAllUuids(std::list<std::string>& target, 2940 void ServerIndex::GetAllUuids(std::list<std::string>& target,
2831 ResourceType resourceType) 2941 ResourceType resourceType)
2832 { 2942 {
2833 class Operations : public ServerIndex::IReadOnlyOperations 2943 class Operations : public ReadOnlyOperationsT2<std::list<std::string>*, ResourceType>
2834 { 2944 {
2835 private:
2836 std::list<std::string>& target_;
2837 ResourceType resourceType_;
2838
2839 public: 2945 public:
2840 Operations(std::list<std::string>& target, 2946 virtual void ApplyTuple(ReadOnlyTransaction& transaction,
2841 ResourceType resourceType) : 2947 const Tuple& tuple) ORTHANC_OVERRIDE
2842 target_(target), 2948 {
2843 resourceType_(resourceType) 2949 transaction.GetAllPublicIds(*tuple.get<0>(), tuple.get<1>());
2844 {
2845 }
2846
2847 virtual void Apply(ServerIndex::ReadOnlyTransaction& transaction) ORTHANC_OVERRIDE
2848 {
2849 transaction.GetAllPublicIds(target_, resourceType_);
2850 } 2950 }
2851 }; 2951 };
2852 2952
2853 Operations operations(target, resourceType); 2953 Operations operations;
2854 Apply(operations); 2954 operations.Apply(*this, &target, resourceType);
2855 } 2955 }
2956
2856 2957
2857 2958
2858 void ServerIndex::GetAllUuids(std::list<std::string>& target, 2959 void ServerIndex::GetAllUuids(std::list<std::string>& target,
2859 ResourceType resourceType, 2960 ResourceType resourceType,
2860 size_t since, 2961 size_t since,
2864 { 2965 {
2865 target.clear(); 2966 target.clear();
2866 } 2967 }
2867 else 2968 else
2868 { 2969 {
2869 class Operations : public ServerIndex::IReadOnlyOperations 2970 class Operations : public ReadOnlyOperationsT4<std::list<std::string>*, ResourceType, size_t, size_t>
2870 { 2971 {
2871 private:
2872 std::list<std::string>& target_;
2873 ResourceType resourceType_;
2874 size_t since_;
2875 size_t limit_;
2876
2877 public: 2972 public:
2878 Operations(std::list<std::string>& target, 2973 virtual void ApplyTuple(ReadOnlyTransaction& transaction,
2879 ResourceType resourceType, 2974 const Tuple& tuple) ORTHANC_OVERRIDE
2880 size_t since, 2975 {
2881 size_t limit) : 2976 transaction.GetAllPublicIds(*tuple.get<0>(), tuple.get<1>(), tuple.get<2>(), tuple.get<3>());
2882 target_(target),
2883 resourceType_(resourceType),
2884 since_(since),
2885 limit_(limit)
2886 {
2887 }
2888
2889 virtual void Apply(ServerIndex::ReadOnlyTransaction& transaction) ORTHANC_OVERRIDE
2890 {
2891 transaction.GetAllPublicIds(target_, resourceType_, since_, limit_);
2892 } 2977 }
2893 }; 2978 };
2894 2979
2895 Operations operations(target, resourceType, since, limit); 2980 Operations operations;
2896 Apply(operations); 2981 operations.Apply(*this, &target, resourceType, since, limit);
2897 } 2982 }
2898 } 2983 }
2899 } 2984 }