comparison OrthancServer/Sources/ServerIndex.cpp @ 4562:e19f11e08226 db-changes

cont
author Sebastien Jodogne <s.jodogne@gmail.com>
date Fri, 05 Mar 2021 15:37:53 +0100
parents 02510325d869
children bb1c365f9e44
comparison
equal deleted inserted replaced
4561:02510325d869 4562:e19f11e08226
1488 db_.ClearExportedResources(); 1488 db_.ClearExportedResources();
1489 transaction.Commit(0); 1489 transaction.Commit(0);
1490 } 1490 }
1491 1491
1492 1492
1493 void ServerIndex::GetResourceStatistics(/* out */ ResourceType& type,
1494 /* out */ uint64_t& diskSize,
1495 /* out */ uint64_t& uncompressedSize,
1496 /* out */ unsigned int& countStudies,
1497 /* out */ unsigned int& countSeries,
1498 /* out */ unsigned int& countInstances,
1499 /* out */ uint64_t& dicomDiskSize,
1500 /* out */ uint64_t& dicomUncompressedSize,
1501 const std::string& publicId)
1502 {
1503 boost::mutex::scoped_lock lock(mutex_);
1504
1505 int64_t top;
1506 if (!db_.LookupResource(top, type, publicId))
1507 {
1508 throw OrthancException(ErrorCode_UnknownResource);
1509 }
1510
1511 std::stack<int64_t> toExplore;
1512 toExplore.push(top);
1513
1514 countInstances = 0;
1515 countSeries = 0;
1516 countStudies = 0;
1517 diskSize = 0;
1518 uncompressedSize = 0;
1519 dicomDiskSize = 0;
1520 dicomUncompressedSize = 0;
1521
1522 while (!toExplore.empty())
1523 {
1524 // Get the internal ID of the current resource
1525 int64_t resource = toExplore.top();
1526 toExplore.pop();
1527
1528 ResourceType thisType = db_.GetResourceType(resource);
1529
1530 std::set<FileContentType> f;
1531 db_.ListAvailableAttachments(f, resource);
1532
1533 for (std::set<FileContentType>::const_iterator
1534 it = f.begin(); it != f.end(); ++it)
1535 {
1536 FileInfo attachment;
1537 if (db_.LookupAttachment(attachment, resource, *it))
1538 {
1539 if (attachment.GetContentType() == FileContentType_Dicom)
1540 {
1541 dicomDiskSize += attachment.GetCompressedSize();
1542 dicomUncompressedSize += attachment.GetUncompressedSize();
1543 }
1544
1545 diskSize += attachment.GetCompressedSize();
1546 uncompressedSize += attachment.GetUncompressedSize();
1547 }
1548 }
1549
1550 if (thisType == ResourceType_Instance)
1551 {
1552 countInstances++;
1553 }
1554 else
1555 {
1556 switch (thisType)
1557 {
1558 case ResourceType_Study:
1559 countStudies++;
1560 break;
1561
1562 case ResourceType_Series:
1563 countSeries++;
1564 break;
1565
1566 default:
1567 break;
1568 }
1569
1570 // Tag all the children of this resource as to be explored
1571 std::list<int64_t> tmp;
1572 db_.GetChildrenInternalId(tmp, resource);
1573 for (std::list<int64_t>::const_iterator
1574 it = tmp.begin(); it != tmp.end(); ++it)
1575 {
1576 toExplore.push(*it);
1577 }
1578 }
1579 }
1580
1581 if (countStudies == 0)
1582 {
1583 countStudies = 1;
1584 }
1585
1586 if (countSeries == 0)
1587 {
1588 countSeries = 1;
1589 }
1590 }
1591
1592
1593 void ServerIndex::UnstableResourcesMonitorThread(ServerIndex* that, 1493 void ServerIndex::UnstableResourcesMonitorThread(ServerIndex* that,
1594 unsigned int threadSleep) 1494 unsigned int threadSleep)
1595 { 1495 {
1596 int stableAge; 1496 int stableAge;
1597 1497
1670 LogChange(id, ChangeType_NewChildInstance, type, publicId); 1570 LogChange(id, ChangeType_NewChildInstance, type, publicId);
1671 } 1571 }
1672 1572
1673 1573
1674 1574
1675 void ServerIndex::LookupIdentifierExact(std::vector<std::string>& result,
1676 ResourceType level,
1677 const DicomTag& tag,
1678 const std::string& value)
1679 {
1680 assert((level == ResourceType_Patient && tag == DICOM_TAG_PATIENT_ID) ||
1681 (level == ResourceType_Study && tag == DICOM_TAG_STUDY_INSTANCE_UID) ||
1682 (level == ResourceType_Study && tag == DICOM_TAG_ACCESSION_NUMBER) ||
1683 (level == ResourceType_Series && tag == DICOM_TAG_SERIES_INSTANCE_UID) ||
1684 (level == ResourceType_Instance && tag == DICOM_TAG_SOP_INSTANCE_UID));
1685
1686 result.clear();
1687
1688 DicomTagConstraint c(tag, ConstraintType_Equal, value, true, true);
1689
1690 std::vector<DatabaseConstraint> query;
1691 query.push_back(c.ConvertToDatabaseConstraint(level, DicomTagType_Identifier));
1692
1693 std::list<std::string> tmp;
1694
1695 {
1696 boost::mutex::scoped_lock lock(mutex_);
1697 db_.ApplyLookupResources(tmp, NULL, query, level, 0);
1698 }
1699
1700 CopyListToVector(result, tmp);
1701 }
1702
1703
1704 StoreStatus ServerIndex::AddAttachment(const FileInfo& attachment, 1575 StoreStatus ServerIndex::AddAttachment(const FileInfo& attachment,
1705 const std::string& publicId) 1576 const std::string& publicId)
1706 { 1577 {
1707 boost::mutex::scoped_lock lock(mutex_); 1578 boost::mutex::scoped_lock lock(mutex_);
1708 1579
1785 db_.SetGlobalProperty(property, value); 1656 db_.SetGlobalProperty(property, value);
1786 transaction.Commit(0); 1657 transaction.Commit(0);
1787 } 1658 }
1788 1659
1789 1660
1790 bool ServerIndex::LookupGlobalProperty(std::string& value,
1791 GlobalProperty property)
1792 {
1793 boost::mutex::scoped_lock lock(mutex_);
1794 return db_.LookupGlobalProperty(value, property);
1795 }
1796
1797
1798 std::string ServerIndex::GetGlobalProperty(GlobalProperty property,
1799 const std::string& defaultValue)
1800 {
1801 std::string value;
1802
1803 if (LookupGlobalProperty(value, property))
1804 {
1805 return value;
1806 }
1807 else
1808 {
1809 return defaultValue;
1810 }
1811 }
1812
1813
1814 bool ServerIndex::GetMainDicomTags(DicomMap& result,
1815 const std::string& publicId,
1816 ResourceType expectedType,
1817 ResourceType levelOfInterest)
1818 {
1819 // Yes, the following test could be shortened, but we wish to make it as clear as possible
1820 if (!(expectedType == ResourceType_Patient && levelOfInterest == ResourceType_Patient) &&
1821 !(expectedType == ResourceType_Study && levelOfInterest == ResourceType_Patient) &&
1822 !(expectedType == ResourceType_Study && levelOfInterest == ResourceType_Study) &&
1823 !(expectedType == ResourceType_Series && levelOfInterest == ResourceType_Series) &&
1824 !(expectedType == ResourceType_Instance && levelOfInterest == ResourceType_Instance))
1825 {
1826 throw OrthancException(ErrorCode_ParameterOutOfRange);
1827 }
1828
1829 result.Clear();
1830
1831 boost::mutex::scoped_lock lock(mutex_);
1832
1833 // Lookup for the requested resource
1834 int64_t id;
1835 ResourceType type;
1836 if (!db_.LookupResource(id, type, publicId) ||
1837 type != expectedType)
1838 {
1839 return false;
1840 }
1841
1842 if (type == ResourceType_Study)
1843 {
1844 DicomMap tmp;
1845 db_.GetMainDicomTags(tmp, id);
1846
1847 switch (levelOfInterest)
1848 {
1849 case ResourceType_Patient:
1850 tmp.ExtractPatientInformation(result);
1851 return true;
1852
1853 case ResourceType_Study:
1854 tmp.ExtractStudyInformation(result);
1855 return true;
1856
1857 default:
1858 throw OrthancException(ErrorCode_InternalError);
1859 }
1860 }
1861 else
1862 {
1863 db_.GetMainDicomTags(result, id);
1864 return true;
1865 }
1866 }
1867 1661
1868 1662
1869 bool ServerIndex::GetAllMainDicomTags(DicomMap& result, 1663 bool ServerIndex::GetAllMainDicomTags(DicomMap& result,
1870 const std::string& instancePublicId) 1664 const std::string& instancePublicId)
1871 { 1665 {
2344 2138
2345 Transaction transaction(*this); // TODO - Only if "TransactionType_SingleStatement" 2139 Transaction transaction(*this); // TODO - Only if "TransactionType_SingleStatement"
2346 2140
2347 if (readOperations != NULL) 2141 if (readOperations != NULL)
2348 { 2142 {
2349 ReadOnlyTransaction transaction(db_); 2143 ReadOnlyTransaction t(db_);
2350 readOperations->Apply(transaction); 2144 readOperations->Apply(t);
2351 } 2145 }
2352 else 2146 else
2353 { 2147 {
2354 assert(writeOperations != NULL); 2148 assert(writeOperations != NULL);
2355 ReadWriteTransaction transaction(db_); 2149 ReadWriteTransaction t(db_);
2356 writeOperations->Apply(transaction); 2150 writeOperations->Apply(t);
2357 } 2151 }
2358 2152
2359 transaction.Commit(0); 2153 transaction.Commit(0);
2360 2154
2361 return; // Success 2155 return; // Success
2409 2203
2410 bool ServerIndex::ExpandResource(Json::Value& target, 2204 bool ServerIndex::ExpandResource(Json::Value& target,
2411 const std::string& publicId, 2205 const std::string& publicId,
2412 ResourceType level) 2206 ResourceType level)
2413 { 2207 {
2414 class Operations : public ReadOnlyOperationsT3<Json::Value*, std::string, ResourceType> 2208 class Operations : public ReadOnlyOperationsT4<bool*, Json::Value*, std::string, ResourceType>
2415 { 2209 {
2416 private: 2210 private:
2417 ServerIndex& index_; 2211 ServerIndex& index_;
2418 bool found_;
2419 2212
2420 public: 2213 public:
2421 Operations(ServerIndex& index) : 2214 explicit Operations(ServerIndex& index) :
2422 index_(index), 2215 index_(index)
2423 found_(false)
2424 { 2216 {
2425 } 2217 }
2426 2218
2427 bool HasFound() const
2428 {
2429 return found_;
2430 }
2431
2432 virtual void ApplyTuple(ReadOnlyTransaction& transaction, 2219 virtual void ApplyTuple(ReadOnlyTransaction& transaction,
2433 const Tuple& tuple) ORTHANC_OVERRIDE 2220 const Tuple& tuple) ORTHANC_OVERRIDE
2434 { 2221 {
2435 Json::Value& target = *tuple.get<0>();
2436
2437 // Lookup for the requested resource 2222 // Lookup for the requested resource
2438 int64_t internalId; // unused 2223 int64_t internalId; // unused
2439 ResourceType type; 2224 ResourceType type;
2440 std::string parent; 2225 std::string parent;
2441 if (!transaction.LookupResourceAndParent(internalId, type, parent, tuple.get<1>()) || 2226 if (!transaction.LookupResourceAndParent(internalId, type, parent, tuple.get<2>()) ||
2442 type != tuple.get<2>()) 2227 type != tuple.get<3>())
2443 { 2228 {
2444 found_ = false; 2229 *tuple.get<0>() = false;
2445 } 2230 }
2446 else 2231 else
2447 { 2232 {
2233 Json::Value& target = *tuple.get<1>();
2448 target = Json::objectValue; 2234 target = Json::objectValue;
2449 2235
2450 // Set information about the parent resource (if it exists) 2236 // Set information about the parent resource (if it exists)
2451 if (type == ResourceType_Patient) 2237 if (type == ResourceType_Patient)
2452 { 2238 {
2577 default: 2363 default:
2578 throw OrthancException(ErrorCode_InternalError); 2364 throw OrthancException(ErrorCode_InternalError);
2579 } 2365 }
2580 2366
2581 // Record the remaining information 2367 // Record the remaining information
2582 target["ID"] = tuple.get<1>(); 2368 target["ID"] = tuple.get<2>();
2583 transaction.MainDicomTagsToJson(target, internalId, type); 2369 transaction.MainDicomTagsToJson(target, internalId, type);
2584 2370
2585 std::string tmp; 2371 std::string tmp;
2586 2372
2587 if (LookupStringMetadata(tmp, metadata, MetadataType_AnonymizedFrom)) 2373 if (LookupStringMetadata(tmp, metadata, MetadataType_AnonymizedFrom))
2604 { 2390 {
2605 target["LastUpdate"] = tmp; 2391 target["LastUpdate"] = tmp;
2606 } 2392 }
2607 } 2393 }
2608 2394
2609 found_ = true; 2395 *tuple.get<0>() = true;
2610 } 2396 }
2611 } 2397 }
2612 }; 2398 };
2613 2399
2400 bool found;
2614 Operations operations(*this); 2401 Operations operations(*this);
2615 operations.Apply(*this, &target, publicId, level); 2402 operations.Apply(*this, &found, &target, publicId, level);
2616 return operations.HasFound(); 2403 return found;
2617 } 2404 }
2618 2405
2619 2406
2620 void ServerIndex::GetAllMetadata(std::map<MetadataType, std::string>& target, 2407 void ServerIndex::GetAllMetadata(std::map<MetadataType, std::string>& target,
2621 const std::string& publicId, 2408 const std::string& publicId,
2648 2435
2649 bool ServerIndex::LookupAttachment(FileInfo& attachment, 2436 bool ServerIndex::LookupAttachment(FileInfo& attachment,
2650 const std::string& instancePublicId, 2437 const std::string& instancePublicId,
2651 FileContentType contentType) 2438 FileContentType contentType)
2652 { 2439 {
2653 class Operations : public ReadOnlyOperationsT3<FileInfo*, std::string, FileContentType> 2440 class Operations : public ReadOnlyOperationsT4<bool*, FileInfo*, std::string, FileContentType>
2654 { 2441 {
2655 private:
2656 bool found_;
2657
2658 public: 2442 public:
2659 Operations() :
2660 found_(false)
2661 {
2662 }
2663
2664 bool HasFound() const
2665 {
2666 return found_;
2667 }
2668
2669 virtual void ApplyTuple(ReadOnlyTransaction& transaction, 2443 virtual void ApplyTuple(ReadOnlyTransaction& transaction,
2670 const Tuple& tuple) ORTHANC_OVERRIDE 2444 const Tuple& tuple) ORTHANC_OVERRIDE
2671 { 2445 {
2672 int64_t internalId; 2446 int64_t internalId;
2673 ResourceType type; 2447 ResourceType type;
2674 if (!transaction.LookupResource(internalId, type, tuple.get<1>())) 2448 if (!transaction.LookupResource(internalId, type, tuple.get<2>()))
2675 { 2449 {
2676 throw OrthancException(ErrorCode_UnknownResource); 2450 throw OrthancException(ErrorCode_UnknownResource);
2677 } 2451 }
2678 else if (transaction.LookupAttachment(*tuple.get<0>(), internalId, tuple.get<2>())) 2452 else if (transaction.LookupAttachment(*tuple.get<1>(), internalId, tuple.get<3>()))
2679 { 2453 {
2680 assert(tuple.get<0>()->GetContentType() == tuple.get<2>()); 2454 assert(tuple.get<1>()->GetContentType() == tuple.get<3>());
2681 found_ = true; 2455 *tuple.get<0>() = true;
2682 } 2456 }
2683 else 2457 else
2684 { 2458 {
2685 found_ = false; 2459 *tuple.get<0>() = false;
2686 } 2460 }
2687 } 2461 }
2688 }; 2462 };
2689 2463
2464 bool found;
2690 Operations operations; 2465 Operations operations;
2691 operations.Apply(*this, &attachment, instancePublicId, contentType); 2466 operations.Apply(*this, &found, &attachment, instancePublicId, contentType);
2692 return operations.HasFound(); 2467 return found;
2693 } 2468 }
2694 2469
2695 2470
2696 void ServerIndex::GetAllUuids(std::list<std::string>& target, 2471 void ServerIndex::GetAllUuids(std::list<std::string>& target,
2697 ResourceType resourceType) 2472 ResourceType resourceType)
2878 } 2653 }
2879 2654
2880 2655
2881 bool ServerIndex::IsProtectedPatient(const std::string& publicId) 2656 bool ServerIndex::IsProtectedPatient(const std::string& publicId)
2882 { 2657 {
2883 class Operations : public ReadOnlyOperationsT1<std::string> 2658 class Operations : public ReadOnlyOperationsT2<bool*, std::string>
2884 { 2659 {
2885 private:
2886 bool protected_;
2887
2888 public: 2660 public:
2889 Operations() :
2890 protected_(false)
2891 {
2892 }
2893
2894 bool IsProtected() const
2895 {
2896 return protected_;
2897 }
2898
2899 virtual void ApplyTuple(ReadOnlyTransaction& transaction, 2661 virtual void ApplyTuple(ReadOnlyTransaction& transaction,
2900 const Tuple& tuple) ORTHANC_OVERRIDE 2662 const Tuple& tuple) ORTHANC_OVERRIDE
2901 { 2663 {
2902 // Lookup for the requested resource 2664 // Lookup for the requested resource
2903 int64_t id; 2665 int64_t id;
2904 ResourceType type; 2666 ResourceType type;
2905 if (!transaction.LookupResource(id, type, tuple.get<0>()) || 2667 if (!transaction.LookupResource(id, type, tuple.get<1>()) ||
2906 type != ResourceType_Patient) 2668 type != ResourceType_Patient)
2907 { 2669 {
2908 throw OrthancException(ErrorCode_ParameterOutOfRange); 2670 throw OrthancException(ErrorCode_ParameterOutOfRange);
2909 } 2671 }
2910 else 2672 else
2911 { 2673 {
2912 protected_ = transaction.IsProtectedPatient(id); 2674 *tuple.get<0>() = transaction.IsProtectedPatient(id);
2913 } 2675 }
2914 } 2676 }
2915 }; 2677 };
2916 2678
2679 bool isProtected;
2917 Operations operations; 2680 Operations operations;
2918 operations.Apply(*this, publicId); 2681 operations.Apply(*this, &isProtected, publicId);
2919 return operations.IsProtected(); 2682 return isProtected;
2920 } 2683 }
2921 2684
2922 2685
2923 void ServerIndex::GetChildren(std::list<std::string>& result, 2686 void ServerIndex::GetChildren(std::list<std::string>& result,
2924 const std::string& publicId) 2687 const std::string& publicId)
3025 bool ServerIndex::LookupMetadata(std::string& target, 2788 bool ServerIndex::LookupMetadata(std::string& target,
3026 const std::string& publicId, 2789 const std::string& publicId,
3027 ResourceType expectedType, 2790 ResourceType expectedType,
3028 MetadataType type) 2791 MetadataType type)
3029 { 2792 {
3030 class Operations : public ReadOnlyOperationsT4<std::string*, std::string, ResourceType, MetadataType> 2793 class Operations : public ReadOnlyOperationsT5<bool*, std::string*, std::string, ResourceType, MetadataType>
3031 { 2794 {
3032 private:
3033 bool found_;
3034
3035 public: 2795 public:
3036 Operations() :
3037 found_(false)
3038 {
3039 }
3040
3041 bool HasFound()
3042 {
3043 return found_;
3044 }
3045
3046 virtual void ApplyTuple(ReadOnlyTransaction& transaction, 2796 virtual void ApplyTuple(ReadOnlyTransaction& transaction,
3047 const Tuple& tuple) ORTHANC_OVERRIDE 2797 const Tuple& tuple) ORTHANC_OVERRIDE
3048 { 2798 {
3049 ResourceType rtype; 2799 ResourceType rtype;
3050 int64_t id; 2800 int64_t id;
3051 if (!transaction.LookupResource(id, rtype, tuple.get<1>()) || 2801 if (!transaction.LookupResource(id, rtype, tuple.get<2>()) ||
3052 rtype != tuple.get<2>()) 2802 rtype != tuple.get<3>())
3053 { 2803 {
3054 throw OrthancException(ErrorCode_UnknownResource); 2804 throw OrthancException(ErrorCode_UnknownResource);
3055 } 2805 }
3056 else 2806 else
3057 { 2807 {
3058 found_ = transaction.LookupMetadata(*tuple.get<0>(), id, tuple.get<3>()); 2808 *tuple.get<0>() = transaction.LookupMetadata(*tuple.get<1>(), id, tuple.get<4>());
3059 } 2809 }
3060 } 2810 }
3061 }; 2811 };
3062 2812
2813 bool found;
3063 Operations operations; 2814 Operations operations;
3064 operations.Apply(*this, &target, publicId, expectedType, type); 2815 operations.Apply(*this, &found, &target, publicId, expectedType, type);
3065 return operations.HasFound(); 2816 return found;
3066 } 2817 }
3067 2818
3068 2819
3069 void ServerIndex::ListAvailableAttachments(std::set<FileContentType>& target, 2820 void ServerIndex::ListAvailableAttachments(std::set<FileContentType>& target,
3070 const std::string& publicId, 2821 const std::string& publicId,
3096 2847
3097 2848
3098 bool ServerIndex::LookupParent(std::string& target, 2849 bool ServerIndex::LookupParent(std::string& target,
3099 const std::string& publicId) 2850 const std::string& publicId)
3100 { 2851 {
3101 class Operations : public ReadOnlyOperationsT2<std::string*, std::string> 2852 class Operations : public ReadOnlyOperationsT3<bool*, std::string*, std::string>
2853 {
2854 public:
2855 virtual void ApplyTuple(ReadOnlyTransaction& transaction,
2856 const Tuple& tuple) ORTHANC_OVERRIDE
2857 {
2858 ResourceType type;
2859 int64_t id;
2860 if (!transaction.LookupResource(id, type, tuple.get<2>()))
2861 {
2862 throw OrthancException(ErrorCode_UnknownResource);
2863 }
2864 else
2865 {
2866 int64_t parentId;
2867 if (transaction.LookupParent(parentId, id))
2868 {
2869 *tuple.get<1>() = transaction.GetPublicId(parentId);
2870 *tuple.get<0>() = true;
2871 }
2872 else
2873 {
2874 *tuple.get<0>() = false;
2875 }
2876 }
2877 }
2878 };
2879
2880 bool found;
2881 Operations operations;
2882 operations.Apply(*this, &found, &target, publicId);
2883 return found;
2884 }
2885
2886
2887 void ServerIndex::GetResourceStatistics(/* out */ ResourceType& type,
2888 /* out */ uint64_t& diskSize,
2889 /* out */ uint64_t& uncompressedSize,
2890 /* out */ unsigned int& countStudies,
2891 /* out */ unsigned int& countSeries,
2892 /* out */ unsigned int& countInstances,
2893 /* out */ uint64_t& dicomDiskSize,
2894 /* out */ uint64_t& dicomUncompressedSize,
2895 const std::string& publicId)
2896 {
2897 class Operations : public ServerIndex::IReadOnlyOperations
3102 { 2898 {
3103 private: 2899 private:
3104 bool found_; 2900 ResourceType& type_;
2901 uint64_t& diskSize_;
2902 uint64_t& uncompressedSize_;
2903 unsigned int& countStudies_;
2904 unsigned int& countSeries_;
2905 unsigned int& countInstances_;
2906 uint64_t& dicomDiskSize_;
2907 uint64_t& dicomUncompressedSize_;
2908 const std::string& publicId_;
2909
2910 public:
2911 explicit Operations(ResourceType& type,
2912 uint64_t& diskSize,
2913 uint64_t& uncompressedSize,
2914 unsigned int& countStudies,
2915 unsigned int& countSeries,
2916 unsigned int& countInstances,
2917 uint64_t& dicomDiskSize,
2918 uint64_t& dicomUncompressedSize,
2919 const std::string& publicId) :
2920 type_(type),
2921 diskSize_(diskSize),
2922 uncompressedSize_(uncompressedSize),
2923 countStudies_(countStudies),
2924 countSeries_(countSeries),
2925 countInstances_(countInstances),
2926 dicomDiskSize_(dicomDiskSize),
2927 dicomUncompressedSize_(dicomUncompressedSize),
2928 publicId_(publicId)
2929 {
2930 }
2931
2932 virtual void Apply(ServerIndex::ReadOnlyTransaction& transaction) ORTHANC_OVERRIDE
2933 {
2934 int64_t top;
2935 if (!transaction.LookupResource(top, type_, publicId_))
2936 {
2937 throw OrthancException(ErrorCode_UnknownResource);
2938 }
2939 else
2940 {
2941 countInstances_ = 0;
2942 countSeries_ = 0;
2943 countStudies_ = 0;
2944 diskSize_ = 0;
2945 uncompressedSize_ = 0;
2946 dicomDiskSize_ = 0;
2947 dicomUncompressedSize_ = 0;
2948
2949 std::stack<int64_t> toExplore;
2950 toExplore.push(top);
2951
2952 while (!toExplore.empty())
2953 {
2954 // Get the internal ID of the current resource
2955 int64_t resource = toExplore.top();
2956 toExplore.pop();
2957
2958 ResourceType thisType = transaction.GetResourceType(resource);
2959
2960 std::set<FileContentType> f;
2961 transaction.ListAvailableAttachments(f, resource);
2962
2963 for (std::set<FileContentType>::const_iterator
2964 it = f.begin(); it != f.end(); ++it)
2965 {
2966 FileInfo attachment;
2967 if (transaction.LookupAttachment(attachment, resource, *it))
2968 {
2969 if (attachment.GetContentType() == FileContentType_Dicom)
2970 {
2971 dicomDiskSize_ += attachment.GetCompressedSize();
2972 dicomUncompressedSize_ += attachment.GetUncompressedSize();
2973 }
2974
2975 diskSize_ += attachment.GetCompressedSize();
2976 uncompressedSize_ += attachment.GetUncompressedSize();
2977 }
2978 }
2979
2980 if (thisType == ResourceType_Instance)
2981 {
2982 countInstances_++;
2983 }
2984 else
2985 {
2986 switch (thisType)
2987 {
2988 case ResourceType_Study:
2989 countStudies_++;
2990 break;
2991
2992 case ResourceType_Series:
2993 countSeries_++;
2994 break;
2995
2996 default:
2997 break;
2998 }
2999
3000 // Tag all the children of this resource as to be explored
3001 std::list<int64_t> tmp;
3002 transaction.GetChildrenInternalId(tmp, resource);
3003 for (std::list<int64_t>::const_iterator
3004 it = tmp.begin(); it != tmp.end(); ++it)
3005 {
3006 toExplore.push(*it);
3007 }
3008 }
3009 }
3010
3011 if (countStudies_ == 0)
3012 {
3013 countStudies_ = 1;
3014 }
3015
3016 if (countSeries_ == 0)
3017 {
3018 countSeries_ = 1;
3019 }
3020 }
3021 }
3022 };
3023
3024 Operations operations(type, diskSize, uncompressedSize, countStudies, countSeries,
3025 countInstances, dicomDiskSize, dicomUncompressedSize, publicId);
3026 Apply(operations);
3027 }
3028
3029
3030 void ServerIndex::LookupIdentifierExact(std::vector<std::string>& result,
3031 ResourceType level,
3032 const DicomTag& tag,
3033 const std::string& value)
3034 {
3035 assert((level == ResourceType_Patient && tag == DICOM_TAG_PATIENT_ID) ||
3036 (level == ResourceType_Study && tag == DICOM_TAG_STUDY_INSTANCE_UID) ||
3037 (level == ResourceType_Study && tag == DICOM_TAG_ACCESSION_NUMBER) ||
3038 (level == ResourceType_Series && tag == DICOM_TAG_SERIES_INSTANCE_UID) ||
3039 (level == ResourceType_Instance && tag == DICOM_TAG_SOP_INSTANCE_UID));
3040
3041 result.clear();
3042
3043 DicomTagConstraint c(tag, ConstraintType_Equal, value, true, true);
3044
3045 std::vector<DatabaseConstraint> query;
3046 query.push_back(c.ConvertToDatabaseConstraint(level, DicomTagType_Identifier));
3047
3048
3049 class Operations : public ServerIndex::IReadOnlyOperations
3050 {
3051 private:
3052 std::vector<std::string>& result_;
3053 const std::vector<DatabaseConstraint>& query_;
3054 ResourceType level_;
3105 3055
3106 public: 3056 public:
3107 Operations() : 3057 Operations(std::vector<std::string>& result,
3108 found_(false) 3058 const std::vector<DatabaseConstraint>& query,
3109 { 3059 ResourceType level) :
3110 } 3060 result_(result),
3111 3061 query_(query),
3112 bool HasFound() 3062 level_(level)
3113 { 3063 {
3114 return found_; 3064 }
3115 } 3065
3116 3066 virtual void Apply(ReadOnlyTransaction& transaction) ORTHANC_OVERRIDE
3067 {
3068 std::list<std::string> tmp;
3069 transaction.ApplyLookupResources(tmp, NULL, query_, level_, 0);
3070 CopyListToVector(result_, tmp);
3071 }
3072 };
3073
3074 Operations operations(result, query, level);
3075 Apply(operations);
3076 }
3077
3078
3079 bool ServerIndex::LookupGlobalProperty(std::string& value,
3080 GlobalProperty property)
3081 {
3082 class Operations : public ReadOnlyOperationsT3<bool*, std::string*, GlobalProperty>
3083 {
3084 public:
3117 virtual void ApplyTuple(ReadOnlyTransaction& transaction, 3085 virtual void ApplyTuple(ReadOnlyTransaction& transaction,
3118 const Tuple& tuple) ORTHANC_OVERRIDE 3086 const Tuple& tuple) ORTHANC_OVERRIDE
3119 { 3087 {
3088 *tuple.get<0>() = transaction.LookupGlobalProperty(*tuple.get<1>(), tuple.get<2>());
3089 }
3090 };
3091
3092 bool found;
3093 Operations operations;
3094 operations.Apply(*this, &found, &value, property);
3095 return found;
3096 }
3097
3098
3099 std::string ServerIndex::GetGlobalProperty(GlobalProperty property,
3100 const std::string& defaultValue)
3101 {
3102 class Operations : public ReadOnlyOperationsT3<std::string*, GlobalProperty, std::string>
3103 {
3104 public:
3105 virtual void ApplyTuple(ReadOnlyTransaction& transaction,
3106 const Tuple& tuple) ORTHANC_OVERRIDE
3107 {
3108 if (!transaction.LookupGlobalProperty(*tuple.get<0>(), tuple.get<1>()))
3109 {
3110 *tuple.get<0>() = tuple.get<2>(); // Default value
3111 }
3112 }
3113 };
3114
3115 std::string s;
3116 Operations operations;
3117 operations.Apply(*this, &s, property, defaultValue);
3118 return s;
3119 }
3120
3121
3122 bool ServerIndex::GetMainDicomTags(DicomMap& result,
3123 const std::string& publicId,
3124 ResourceType expectedType,
3125 ResourceType levelOfInterest)
3126 {
3127 // Yes, the following test could be shortened, but we wish to make it as clear as possible
3128 if (!(expectedType == ResourceType_Patient && levelOfInterest == ResourceType_Patient) &&
3129 !(expectedType == ResourceType_Study && levelOfInterest == ResourceType_Patient) &&
3130 !(expectedType == ResourceType_Study && levelOfInterest == ResourceType_Study) &&
3131 !(expectedType == ResourceType_Series && levelOfInterest == ResourceType_Series) &&
3132 !(expectedType == ResourceType_Instance && levelOfInterest == ResourceType_Instance))
3133 {
3134 throw OrthancException(ErrorCode_ParameterOutOfRange);
3135 }
3136
3137
3138 class Operations : public ReadOnlyOperationsT5<bool*, DicomMap*, std::string, ResourceType, ResourceType>
3139 {
3140 public:
3141 virtual void ApplyTuple(ReadOnlyTransaction& transaction,
3142 const Tuple& tuple) ORTHANC_OVERRIDE
3143 {
3144 // Lookup for the requested resource
3145 int64_t id;
3120 ResourceType type; 3146 ResourceType type;
3121 int64_t id; 3147 if (!transaction.LookupResource(id, type, tuple.get<2>()) ||
3122 if (!transaction.LookupResource(id, type, tuple.get<1>())) 3148 type != tuple.get<3>())
3123 { 3149 {
3124 throw OrthancException(ErrorCode_UnknownResource); 3150 *tuple.get<0>() = false;
3151 }
3152 else if (type == ResourceType_Study)
3153 {
3154 DicomMap tmp;
3155 transaction.GetMainDicomTags(tmp, id);
3156
3157 switch (tuple.get<4>())
3158 {
3159 case ResourceType_Patient:
3160 tmp.ExtractPatientInformation(*tuple.get<1>());
3161 *tuple.get<0>() = true;
3162 break;
3163
3164 case ResourceType_Study:
3165 tmp.ExtractStudyInformation(*tuple.get<1>());
3166 *tuple.get<0>() = true;
3167 break;
3168
3169 default:
3170 throw OrthancException(ErrorCode_InternalError);
3171 }
3125 } 3172 }
3126 else 3173 else
3127 { 3174 {
3128 int64_t parentId; 3175 transaction.GetMainDicomTags(*tuple.get<1>(), id);
3129 if (transaction.LookupParent(parentId, id)) 3176 *tuple.get<0>() = true;
3130 { 3177 }
3131 *tuple.get<0>() = transaction.GetPublicId(parentId);
3132 found_ = true;
3133 }
3134 }
3135 } 3178 }
3136 }; 3179 };
3137 3180
3181 result.Clear();
3182
3183 bool found;
3138 Operations operations; 3184 Operations operations;
3139 operations.Apply(*this, &target, publicId); 3185 operations.Apply(*this, &found, &result, publicId, expectedType, levelOfInterest);
3140 return operations.HasFound(); 3186 return found;
3141 } 3187 }
3142 } 3188 }