Mercurial > hg > orthanc
comparison OrthancServer/Sources/ServerIndex.cpp @ 4554:efd90f778cd2 db-changes
simplification
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Wed, 03 Mar 2021 16:31:57 +0100 |
parents | 350a22c094f2 |
children | 456ed3fcff81 |
comparison
equal
deleted
inserted
replaced
4552:beb8ba8a0b12 | 4554:efd90f778cd2 |
---|---|
669 return 1; | 669 return 1; |
670 } | 670 } |
671 } | 671 } |
672 | 672 |
673 | 673 |
674 bool ServerIndex::IsUnstableResource(int64_t id) | |
675 { | |
676 return unstableResources_.Contains(id); | |
677 } | |
678 | |
674 | 679 |
675 ServerIndex::ServerIndex(ServerContext& context, | 680 ServerIndex::ServerIndex(ServerContext& context, |
676 IDatabaseWrapper& db, | 681 IDatabaseWrapper& db, |
677 unsigned int threadSleep) : | 682 unsigned int threadSleep) : |
678 done_(false), | 683 done_(false), |
679 db_(db), | 684 db_(db), |
680 maximumStorageSize_(0), | 685 maximumStorageSize_(0), |
681 maximumPatients_(0), | 686 maximumPatients_(0), |
682 mainDicomTagsRegistry_(new MainDicomTagsRegistry), | 687 mainDicomTagsRegistry_(new MainDicomTagsRegistry), |
683 maxRetries_(0) | 688 maxRetries_(10) |
684 { | 689 { |
685 listener_.reset(new Listener(context)); | 690 listener_.reset(new Listener(context)); |
686 db_.SetListener(*listener_); | 691 db_.SetListener(*listener_); |
687 | 692 |
688 // Initial recycling if the parameters have changed since the last | 693 // Initial recycling if the parameters have changed since the last |
1012 | 1017 |
1013 // Check whether the series of this new instance is now completed | 1018 // Check whether the series of this new instance is now completed |
1014 int64_t expectedNumberOfInstances; | 1019 int64_t expectedNumberOfInstances; |
1015 if (ComputeExpectedNumberOfInstances(expectedNumberOfInstances, dicomSummary)) | 1020 if (ComputeExpectedNumberOfInstances(expectedNumberOfInstances, dicomSummary)) |
1016 { | 1021 { |
1017 SeriesStatus seriesStatus = GetSeriesStatus(status.seriesId_, expectedNumberOfInstances); | 1022 SeriesStatus seriesStatus = GetSeriesStatus(db_, status.seriesId_, expectedNumberOfInstances); |
1018 if (seriesStatus == SeriesStatus_Complete) | 1023 if (seriesStatus == SeriesStatus_Complete) |
1019 { | 1024 { |
1020 LogChange(status.seriesId_, ChangeType_CompletedSeries, ResourceType_Series, hashSeries); | 1025 LogChange(status.seriesId_, ChangeType_CompletedSeries, ResourceType_Series, hashSeries); |
1021 } | 1026 } |
1022 } | 1027 } |
1055 countSeries = db_.GetResourceCount(ResourceType_Series); | 1060 countSeries = db_.GetResourceCount(ResourceType_Series); |
1056 countInstances = db_.GetResourceCount(ResourceType_Instance); | 1061 countInstances = db_.GetResourceCount(ResourceType_Instance); |
1057 } | 1062 } |
1058 | 1063 |
1059 | 1064 |
1060 SeriesStatus ServerIndex::GetSeriesStatus(int64_t id, | 1065 SeriesStatus ServerIndex::GetSeriesStatus(IDatabaseWrapper& db, |
1066 int64_t id, | |
1061 int64_t expectedNumberOfInstances) | 1067 int64_t expectedNumberOfInstances) |
1062 { | 1068 { |
1063 std::list<std::string> values; | 1069 std::list<std::string> values; |
1064 db_.GetChildrenMetadata(values, id, MetadataType_Instance_IndexInSeries); | 1070 db.GetChildrenMetadata(values, id, MetadataType_Instance_IndexInSeries); |
1065 | 1071 |
1066 std::set<int64_t> instances; | 1072 std::set<int64_t> instances; |
1067 | 1073 |
1068 for (std::list<std::string>::const_iterator | 1074 for (std::list<std::string>::const_iterator |
1069 it = values.begin(); it != values.end(); ++it) | 1075 it = values.begin(); it != values.end(); ++it) |
1104 } | 1110 } |
1105 } | 1111 } |
1106 | 1112 |
1107 | 1113 |
1108 void ServerIndex::MainDicomTagsToJson(Json::Value& target, | 1114 void ServerIndex::MainDicomTagsToJson(Json::Value& target, |
1115 IDatabaseWrapper& db, | |
1109 int64_t resourceId, | 1116 int64_t resourceId, |
1110 ResourceType resourceType) | 1117 ResourceType resourceType) |
1111 { | 1118 { |
1112 DicomMap tags; | 1119 DicomMap tags; |
1113 db_.GetMainDicomTags(tags, resourceId); | 1120 db.GetMainDicomTags(tags, resourceId); |
1114 | 1121 |
1115 if (resourceType == ResourceType_Study) | 1122 if (resourceType == ResourceType_Study) |
1116 { | 1123 { |
1117 DicomMap t1, t2; | 1124 DicomMap t1, t2; |
1118 tags.ExtractStudyInformation(t1); | 1125 tags.ExtractStudyInformation(t1); |
1130 FromDcmtkBridge::ToJson(target["MainDicomTags"], tags, true); | 1137 FromDcmtkBridge::ToJson(target["MainDicomTags"], tags, true); |
1131 } | 1138 } |
1132 } | 1139 } |
1133 | 1140 |
1134 | 1141 |
1135 bool ServerIndex::LookupResource(Json::Value& result, | |
1136 const std::string& publicId, | |
1137 ResourceType expectedType) | |
1138 { | |
1139 result = Json::objectValue; | |
1140 | |
1141 boost::mutex::scoped_lock lock(mutex_); | |
1142 | |
1143 // Lookup for the requested resource | |
1144 int64_t id; | |
1145 ResourceType type; | |
1146 std::string parent; | |
1147 if (!db_.LookupResourceAndParent(id, type, parent, publicId) || | |
1148 type != expectedType) | |
1149 { | |
1150 return false; | |
1151 } | |
1152 | |
1153 // Set information about the parent resource (if it exists) | |
1154 if (type == ResourceType_Patient) | |
1155 { | |
1156 if (!parent.empty()) | |
1157 { | |
1158 throw OrthancException(ErrorCode_DatabasePlugin); | |
1159 } | |
1160 } | |
1161 else | |
1162 { | |
1163 if (parent.empty()) | |
1164 { | |
1165 throw OrthancException(ErrorCode_DatabasePlugin); | |
1166 } | |
1167 | |
1168 switch (type) | |
1169 { | |
1170 case ResourceType_Study: | |
1171 result["ParentPatient"] = parent; | |
1172 break; | |
1173 | |
1174 case ResourceType_Series: | |
1175 result["ParentStudy"] = parent; | |
1176 break; | |
1177 | |
1178 case ResourceType_Instance: | |
1179 result["ParentSeries"] = parent; | |
1180 break; | |
1181 | |
1182 default: | |
1183 throw OrthancException(ErrorCode_InternalError); | |
1184 } | |
1185 } | |
1186 | |
1187 // List the children resources | |
1188 std::list<std::string> children; | |
1189 db_.GetChildrenPublicId(children, id); | |
1190 | |
1191 if (type != ResourceType_Instance) | |
1192 { | |
1193 Json::Value c = Json::arrayValue; | |
1194 | |
1195 for (std::list<std::string>::const_iterator | |
1196 it = children.begin(); it != children.end(); ++it) | |
1197 { | |
1198 c.append(*it); | |
1199 } | |
1200 | |
1201 switch (type) | |
1202 { | |
1203 case ResourceType_Patient: | |
1204 result["Studies"] = c; | |
1205 break; | |
1206 | |
1207 case ResourceType_Study: | |
1208 result["Series"] = c; | |
1209 break; | |
1210 | |
1211 case ResourceType_Series: | |
1212 result["Instances"] = c; | |
1213 break; | |
1214 | |
1215 default: | |
1216 throw OrthancException(ErrorCode_InternalError); | |
1217 } | |
1218 } | |
1219 | |
1220 // Extract the metadata | |
1221 std::map<MetadataType, std::string> metadata; | |
1222 db_.GetAllMetadata(metadata, id); | |
1223 | |
1224 // Set the resource type | |
1225 switch (type) | |
1226 { | |
1227 case ResourceType_Patient: | |
1228 result["Type"] = "Patient"; | |
1229 break; | |
1230 | |
1231 case ResourceType_Study: | |
1232 result["Type"] = "Study"; | |
1233 break; | |
1234 | |
1235 case ResourceType_Series: | |
1236 { | |
1237 result["Type"] = "Series"; | |
1238 | |
1239 int64_t i; | |
1240 if (LookupIntegerMetadata(i, metadata, MetadataType_Series_ExpectedNumberOfInstances)) | |
1241 { | |
1242 result["ExpectedNumberOfInstances"] = static_cast<int>(i); | |
1243 result["Status"] = EnumerationToString(GetSeriesStatus(id, i)); | |
1244 } | |
1245 else | |
1246 { | |
1247 result["ExpectedNumberOfInstances"] = Json::nullValue; | |
1248 result["Status"] = EnumerationToString(SeriesStatus_Unknown); | |
1249 } | |
1250 | |
1251 break; | |
1252 } | |
1253 | |
1254 case ResourceType_Instance: | |
1255 { | |
1256 result["Type"] = "Instance"; | |
1257 | |
1258 FileInfo attachment; | |
1259 if (!db_.LookupAttachment(attachment, id, FileContentType_Dicom)) | |
1260 { | |
1261 throw OrthancException(ErrorCode_InternalError); | |
1262 } | |
1263 | |
1264 result["FileSize"] = static_cast<unsigned int>(attachment.GetUncompressedSize()); | |
1265 result["FileUuid"] = attachment.GetUuid(); | |
1266 | |
1267 int64_t i; | |
1268 if (LookupIntegerMetadata(i, metadata, MetadataType_Instance_IndexInSeries)) | |
1269 { | |
1270 result["IndexInSeries"] = static_cast<int>(i); | |
1271 } | |
1272 else | |
1273 { | |
1274 result["IndexInSeries"] = Json::nullValue; | |
1275 } | |
1276 | |
1277 break; | |
1278 } | |
1279 | |
1280 default: | |
1281 throw OrthancException(ErrorCode_InternalError); | |
1282 } | |
1283 | |
1284 // Record the remaining information | |
1285 result["ID"] = publicId; | |
1286 MainDicomTagsToJson(result, id, type); | |
1287 | |
1288 std::string tmp; | |
1289 | |
1290 if (LookupStringMetadata(tmp, metadata, MetadataType_AnonymizedFrom)) | |
1291 { | |
1292 result["AnonymizedFrom"] = tmp; | |
1293 } | |
1294 | |
1295 if (LookupStringMetadata(tmp, metadata, MetadataType_ModifiedFrom)) | |
1296 { | |
1297 result["ModifiedFrom"] = tmp; | |
1298 } | |
1299 | |
1300 if (type == ResourceType_Patient || | |
1301 type == ResourceType_Study || | |
1302 type == ResourceType_Series) | |
1303 { | |
1304 result["IsStable"] = !unstableResources_.Contains(id); | |
1305 | |
1306 if (LookupStringMetadata(tmp, metadata, MetadataType_LastUpdate)) | |
1307 { | |
1308 result["LastUpdate"] = tmp; | |
1309 } | |
1310 } | |
1311 | |
1312 return true; | |
1313 } | |
1314 | |
1315 | |
1316 bool ServerIndex::LookupAttachment(FileInfo& attachment, | 1142 bool ServerIndex::LookupAttachment(FileInfo& attachment, |
1317 const std::string& instanceUuid, | 1143 const std::string& instanceUuid, |
1318 FileContentType contentType) | 1144 FileContentType contentType) |
1319 { | 1145 { |
1320 boost::mutex::scoped_lock lock(mutex_); | 1146 boost::mutex::scoped_lock lock(mutex_); |
1883 | 1709 |
1884 return db_.LookupMetadata(target, id, type); | 1710 return db_.LookupMetadata(target, id, type); |
1885 } | 1711 } |
1886 | 1712 |
1887 | 1713 |
1888 void ServerIndex::GetAllMetadata(std::map<MetadataType, std::string>& target, | |
1889 const std::string& publicId, | |
1890 ResourceType expectedType) | |
1891 { | |
1892 boost::mutex::scoped_lock lock(mutex_); | |
1893 | |
1894 ResourceType type; | |
1895 int64_t id; | |
1896 if (!db_.LookupResource(id, type, publicId) || | |
1897 expectedType != type) | |
1898 { | |
1899 throw OrthancException(ErrorCode_UnknownResource); | |
1900 } | |
1901 | |
1902 return db_.GetAllMetadata(target, id); | |
1903 } | |
1904 | |
1905 | |
1906 void ServerIndex::ListAvailableAttachments(std::set<FileContentType>& target, | 1714 void ServerIndex::ListAvailableAttachments(std::set<FileContentType>& target, |
1907 const std::string& publicId, | 1715 const std::string& publicId, |
1908 ResourceType expectedType) | 1716 ResourceType expectedType) |
1909 { | 1717 { |
1910 boost::mutex::scoped_lock lock(mutex_); | 1718 boost::mutex::scoped_lock lock(mutex_); |
2630 | 2438 |
2631 /*** | 2439 /*** |
2632 ** PROTOTYPING FOR DB REFACTORING BELOW | 2440 ** PROTOTYPING FOR DB REFACTORING BELOW |
2633 ***/ | 2441 ***/ |
2634 | 2442 |
2635 ServerIndex::ExpandResourceOperation::ExpandResourceOperation(const std::string& resource, | |
2636 ResourceType level) : | |
2637 found_(false), | |
2638 resource_(resource), | |
2639 level_(level) | |
2640 { | |
2641 } | |
2642 | |
2643 | |
2644 void ServerIndex::ExpandResourceOperation::Apply(ServerIndex::ReadOnlyTransaction& transaction) | |
2645 { | |
2646 found_ = transaction.LookupResource(item_, resource_, level_); | |
2647 } | |
2648 | |
2649 | |
2650 const Json::Value& ServerIndex::ExpandResourceOperation::GetResource() const | |
2651 { | |
2652 if (found_) | |
2653 { | |
2654 return item_; | |
2655 } | |
2656 else | |
2657 { | |
2658 throw OrthancException(ErrorCode_BadSequenceOfCalls); | |
2659 } | |
2660 } | |
2661 | |
2662 | |
2663 class ServerIndex::ReadOnlyWrapper : public IReadOnlyOperations | 2443 class ServerIndex::ReadOnlyWrapper : public IReadOnlyOperations |
2664 { | 2444 { |
2665 private: | 2445 private: |
2666 ReadOnlyFunction func_; | 2446 ReadOnlyFunction func_; |
2667 | 2447 |
2711 | 2491 |
2712 for (;;) | 2492 for (;;) |
2713 { | 2493 { |
2714 try | 2494 try |
2715 { | 2495 { |
2496 boost::mutex::scoped_lock lock(mutex_); // TODO - REMOVE | |
2497 | |
2716 if (readOperations != NULL) | 2498 if (readOperations != NULL) |
2717 { | 2499 { |
2718 ReadOnlyTransaction transaction(*this); | 2500 ReadOnlyTransaction transaction(db_); |
2719 readOperations->Apply(transaction); | 2501 readOperations->Apply(transaction); |
2720 } | 2502 } |
2721 else | 2503 else |
2722 { | 2504 { |
2723 assert(writeOperations != NULL); | 2505 assert(writeOperations != NULL); |
2724 ReadWriteTransaction transaction(*this); | 2506 ReadWriteTransaction transaction(db_); |
2725 writeOperations->Apply(transaction); | 2507 writeOperations->Apply(transaction); |
2726 } | 2508 } |
2727 | 2509 |
2728 return; // Success | 2510 return; // Success |
2729 } | 2511 } |
2780 void ServerIndex::Apply(ReadWriteFunction func) | 2562 void ServerIndex::Apply(ReadWriteFunction func) |
2781 { | 2563 { |
2782 ReadWriteWrapper wrapper(func); | 2564 ReadWriteWrapper wrapper(func); |
2783 Apply(wrapper); | 2565 Apply(wrapper); |
2784 } | 2566 } |
2567 | |
2568 | |
2569 bool ServerIndex::ExpandResource(Json::Value& target, | |
2570 const std::string& publicId, | |
2571 ResourceType level) | |
2572 { | |
2573 class Operations : public ServerIndex::IReadOnlyOperations | |
2574 { | |
2575 private: | |
2576 Json::Value& target_; | |
2577 bool found_; | |
2578 ServerIndex& index_; | |
2579 const std::string& publicId_; | |
2580 ResourceType level_; | |
2581 | |
2582 public: | |
2583 Operations(Json::Value& target, | |
2584 ServerIndex& index, | |
2585 const std::string& publicId, | |
2586 ResourceType level) : | |
2587 target_(target), | |
2588 found_(false), | |
2589 index_(index), | |
2590 publicId_(publicId), | |
2591 level_(level) | |
2592 { | |
2593 } | |
2594 | |
2595 virtual void Apply(ServerIndex::ReadOnlyTransaction& transaction) ORTHANC_OVERRIDE | |
2596 { | |
2597 // Lookup for the requested resource | |
2598 int64_t internalId; // unused | |
2599 ResourceType type; | |
2600 std::string parent; | |
2601 if (!transaction.LookupResourceAndParent(internalId, type, parent, publicId_) || | |
2602 type != level_) | |
2603 { | |
2604 found_ = false; | |
2605 } | |
2606 else | |
2607 { | |
2608 target_ = Json::objectValue; | |
2609 | |
2610 // Set information about the parent resource (if it exists) | |
2611 if (type == ResourceType_Patient) | |
2612 { | |
2613 if (!parent.empty()) | |
2614 { | |
2615 throw OrthancException(ErrorCode_DatabasePlugin); | |
2616 } | |
2617 } | |
2618 else | |
2619 { | |
2620 if (parent.empty()) | |
2621 { | |
2622 throw OrthancException(ErrorCode_DatabasePlugin); | |
2623 } | |
2624 | |
2625 switch (type) | |
2626 { | |
2627 case ResourceType_Study: | |
2628 target_["ParentPatient"] = parent; | |
2629 break; | |
2630 | |
2631 case ResourceType_Series: | |
2632 target_["ParentStudy"] = parent; | |
2633 break; | |
2634 | |
2635 case ResourceType_Instance: | |
2636 target_["ParentSeries"] = parent; | |
2637 break; | |
2638 | |
2639 default: | |
2640 throw OrthancException(ErrorCode_InternalError); | |
2641 } | |
2642 } | |
2643 | |
2644 // List the children resources | |
2645 std::list<std::string> children; | |
2646 transaction.GetChildrenPublicId(children, internalId); | |
2647 | |
2648 if (type != ResourceType_Instance) | |
2649 { | |
2650 Json::Value c = Json::arrayValue; | |
2651 | |
2652 for (std::list<std::string>::const_iterator | |
2653 it = children.begin(); it != children.end(); ++it) | |
2654 { | |
2655 c.append(*it); | |
2656 } | |
2657 | |
2658 switch (type) | |
2659 { | |
2660 case ResourceType_Patient: | |
2661 target_["Studies"] = c; | |
2662 break; | |
2663 | |
2664 case ResourceType_Study: | |
2665 target_["Series"] = c; | |
2666 break; | |
2667 | |
2668 case ResourceType_Series: | |
2669 target_["Instances"] = c; | |
2670 break; | |
2671 | |
2672 default: | |
2673 throw OrthancException(ErrorCode_InternalError); | |
2674 } | |
2675 } | |
2676 | |
2677 // Extract the metadata | |
2678 std::map<MetadataType, std::string> metadata; | |
2679 transaction.GetAllMetadata(metadata, internalId); | |
2680 | |
2681 // Set the resource type | |
2682 switch (type) | |
2683 { | |
2684 case ResourceType_Patient: | |
2685 target_["Type"] = "Patient"; | |
2686 break; | |
2687 | |
2688 case ResourceType_Study: | |
2689 target_["Type"] = "Study"; | |
2690 break; | |
2691 | |
2692 case ResourceType_Series: | |
2693 { | |
2694 target_["Type"] = "Series"; | |
2695 | |
2696 int64_t i; | |
2697 if (LookupIntegerMetadata(i, metadata, MetadataType_Series_ExpectedNumberOfInstances)) | |
2698 { | |
2699 target_["ExpectedNumberOfInstances"] = static_cast<int>(i); | |
2700 target_["Status"] = EnumerationToString(transaction.GetSeriesStatus(internalId, i)); | |
2701 } | |
2702 else | |
2703 { | |
2704 target_["ExpectedNumberOfInstances"] = Json::nullValue; | |
2705 target_["Status"] = EnumerationToString(SeriesStatus_Unknown); | |
2706 } | |
2707 | |
2708 break; | |
2709 } | |
2710 | |
2711 case ResourceType_Instance: | |
2712 { | |
2713 target_["Type"] = "Instance"; | |
2714 | |
2715 FileInfo attachment; | |
2716 if (!transaction.LookupAttachment(attachment, internalId, FileContentType_Dicom)) | |
2717 { | |
2718 throw OrthancException(ErrorCode_InternalError); | |
2719 } | |
2720 | |
2721 target_["FileSize"] = static_cast<unsigned int>(attachment.GetUncompressedSize()); | |
2722 target_["FileUuid"] = attachment.GetUuid(); | |
2723 | |
2724 int64_t i; | |
2725 if (LookupIntegerMetadata(i, metadata, MetadataType_Instance_IndexInSeries)) | |
2726 { | |
2727 target_["IndexInSeries"] = static_cast<int>(i); | |
2728 } | |
2729 else | |
2730 { | |
2731 target_["IndexInSeries"] = Json::nullValue; | |
2732 } | |
2733 | |
2734 break; | |
2735 } | |
2736 | |
2737 default: | |
2738 throw OrthancException(ErrorCode_InternalError); | |
2739 } | |
2740 | |
2741 // Record the remaining information | |
2742 target_["ID"] = publicId_; | |
2743 transaction.MainDicomTagsToJson(target_, internalId, type); | |
2744 | |
2745 std::string tmp; | |
2746 | |
2747 if (LookupStringMetadata(tmp, metadata, MetadataType_AnonymizedFrom)) | |
2748 { | |
2749 target_["AnonymizedFrom"] = tmp; | |
2750 } | |
2751 | |
2752 if (LookupStringMetadata(tmp, metadata, MetadataType_ModifiedFrom)) | |
2753 { | |
2754 target_["ModifiedFrom"] = tmp; | |
2755 } | |
2756 | |
2757 if (type == ResourceType_Patient || | |
2758 type == ResourceType_Study || | |
2759 type == ResourceType_Series) | |
2760 { | |
2761 target_["IsStable"] = !index_.IsUnstableResource(internalId); | |
2762 | |
2763 if (LookupStringMetadata(tmp, metadata, MetadataType_LastUpdate)) | |
2764 { | |
2765 target_["LastUpdate"] = tmp; | |
2766 } | |
2767 } | |
2768 | |
2769 found_ = true; | |
2770 } | |
2771 } | |
2772 | |
2773 bool HasFound() const | |
2774 { | |
2775 return found_; | |
2776 } | |
2777 }; | |
2778 | |
2779 Operations operations(target, *this, publicId, level); | |
2780 Apply(operations); | |
2781 return operations.HasFound(); | |
2782 } | |
2783 | |
2784 | |
2785 void ServerIndex::GetAllMetadata(std::map<MetadataType, std::string>& target, | |
2786 const std::string& publicId, | |
2787 ResourceType level) | |
2788 { | |
2789 class Operations : public ServerIndex::IReadOnlyOperations | |
2790 { | |
2791 private: | |
2792 std::map<MetadataType, std::string>& metadata_; | |
2793 std::string publicId_; | |
2794 ResourceType level_; | |
2795 | |
2796 public: | |
2797 Operations(std::map<MetadataType, std::string>& metadata, | |
2798 const std::string& publicId, | |
2799 ResourceType level) : | |
2800 metadata_(metadata), | |
2801 publicId_(publicId), | |
2802 level_(level) | |
2803 { | |
2804 } | |
2805 | |
2806 virtual void Apply(ServerIndex::ReadOnlyTransaction& transaction) ORTHANC_OVERRIDE | |
2807 { | |
2808 ResourceType type; | |
2809 int64_t id; | |
2810 if (!transaction.LookupResource(id, type, publicId_) || | |
2811 level_ != type) | |
2812 { | |
2813 throw OrthancException(ErrorCode_UnknownResource); | |
2814 } | |
2815 else | |
2816 { | |
2817 transaction.GetAllMetadata(metadata_, id); | |
2818 } | |
2819 } | |
2820 }; | |
2821 | |
2822 Operations operations(target, publicId, level); | |
2823 Apply(operations); | |
2824 } | |
2785 } | 2825 } |