Mercurial > hg > orthanc
comparison OrthancServer/Sources/Database/StatelessDatabaseOperations.cpp @ 5641:3f13db27b399 find-refactoring
integration mainline->find-refactoring
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Thu, 30 May 2024 21:27:48 +0200 |
parents | 824a5fb0774e f7adfb22e20e |
children |
comparison
equal
deleted
inserted
replaced
5629:2c95a34af64f | 5641:3f13db27b399 |
---|---|
1 /** | 1 /** |
2 * Orthanc - A Lightweight, RESTful DICOM Store | 2 * Orthanc - A Lightweight, RESTful DICOM Store |
3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics | 3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics |
4 * Department, University Hospital of Liege, Belgium | 4 * Department, University Hospital of Liege, Belgium |
5 * Copyright (C) 2017-2024 Osimis S.A., Belgium | 5 * Copyright (C) 2017-2023 Osimis S.A., Belgium |
6 * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium | |
6 * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium | 7 * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium |
7 * | 8 * |
8 * This program is free software: you can redistribute it and/or | 9 * This program is free software: you can redistribute it and/or |
9 * modify it under the terms of the GNU General Public License as | 10 * modify it under the terms of the GNU General Public License as |
10 * published by the Free Software Foundation, either version 3 of the | 11 * published by the Free Software Foundation, either version 3 of the |
3233 } | 3234 } |
3234 | 3235 |
3235 transaction.AddAttachment(instanceId, *it, 0 /* this is the first revision */); | 3236 transaction.AddAttachment(instanceId, *it, 0 /* this is the first revision */); |
3236 } | 3237 } |
3237 | 3238 |
3239 ResourcesContent content(true /* new resource, metadata can be set */); | |
3240 | |
3241 // Attach the user-specified metadata (in case of reconstruction, metadata_ contains all past metadata, including the system ones we want to keep) | |
3242 for (MetadataMap::const_iterator | |
3243 it = metadata_.begin(); it != metadata_.end(); ++it) | |
3244 { | |
3245 switch (it->first.first) | |
3246 { | |
3247 case ResourceType_Patient: | |
3248 content.AddMetadata(status.patientId_, it->first.second, it->second); | |
3249 break; | |
3250 | |
3251 case ResourceType_Study: | |
3252 content.AddMetadata(status.studyId_, it->first.second, it->second); | |
3253 break; | |
3254 | |
3255 case ResourceType_Series: | |
3256 content.AddMetadata(status.seriesId_, it->first.second, it->second); | |
3257 break; | |
3258 | |
3259 case ResourceType_Instance: | |
3260 SetInstanceMetadata(content, instanceMetadata_, instanceId, | |
3261 it->first.second, it->second); | |
3262 break; | |
3263 | |
3264 default: | |
3265 throw OrthancException(ErrorCode_ParameterOutOfRange); | |
3266 } | |
3267 } | |
3268 | |
3238 if (!isReconstruct_) | 3269 if (!isReconstruct_) |
3239 { | 3270 { |
3240 ResourcesContent content(true /* new resource, metadata can be set */); | 3271 // Populate the tags of the newly-created resources |
3241 | 3272 content.AddResource(instanceId, ResourceType_Instance, dicomSummary_); |
3242 // Attach the user-specified metadata (in case of reconstruction, metadata_ contains all past metadata, including the system ones we want to keep) | 3273 SetInstanceMetadata(content, instanceMetadata_, instanceId, MetadataType_MainDicomTagsSignature, DicomMap::GetMainDicomTagsSignature(ResourceType_Instance)); // New in Orthanc 1.11.0 |
3243 for (MetadataMap::const_iterator | 3274 SetMainDicomSequenceMetadata(content, instanceId, dicomSummary_, ResourceType_Instance); // new in Orthanc 1.11.1 |
3244 it = metadata_.begin(); it != metadata_.end(); ++it) | 3275 |
3245 { | 3276 if (status.isNewSeries_) |
3246 switch (it->first.first) | 3277 { |
3278 content.AddResource(status.seriesId_, ResourceType_Series, dicomSummary_); | |
3279 content.AddMetadata(status.seriesId_, MetadataType_MainDicomTagsSignature, DicomMap::GetMainDicomTagsSignature(ResourceType_Series)); // New in Orthanc 1.11.0 | |
3280 SetMainDicomSequenceMetadata(content, status.seriesId_, dicomSummary_, ResourceType_Series); // new in Orthanc 1.11.1 | |
3281 } | |
3282 | |
3283 if (status.isNewStudy_) | |
3284 { | |
3285 content.AddResource(status.studyId_, ResourceType_Study, dicomSummary_); | |
3286 content.AddMetadata(status.studyId_, MetadataType_MainDicomTagsSignature, DicomMap::GetMainDicomTagsSignature(ResourceType_Study)); // New in Orthanc 1.11.0 | |
3287 SetMainDicomSequenceMetadata(content, status.studyId_, dicomSummary_, ResourceType_Study); // new in Orthanc 1.11.1 | |
3288 } | |
3289 | |
3290 if (status.isNewPatient_) | |
3291 { | |
3292 content.AddResource(status.patientId_, ResourceType_Patient, dicomSummary_); | |
3293 content.AddMetadata(status.patientId_, MetadataType_MainDicomTagsSignature, DicomMap::GetMainDicomTagsSignature(ResourceType_Patient)); // New in Orthanc 1.11.0 | |
3294 SetMainDicomSequenceMetadata(content, status.patientId_, dicomSummary_, ResourceType_Patient); // new in Orthanc 1.11.1 | |
3295 } | |
3296 | |
3297 // Attach the auto-computed metadata for the patient/study/series levels | |
3298 std::string now = SystemToolbox::GetNowIsoString(true /* use UTC time (not local time) */); | |
3299 content.AddMetadata(status.seriesId_, MetadataType_LastUpdate, now); | |
3300 content.AddMetadata(status.studyId_, MetadataType_LastUpdate, now); | |
3301 content.AddMetadata(status.patientId_, MetadataType_LastUpdate, now); | |
3302 | |
3303 if (status.isNewSeries_) | |
3304 { | |
3305 if (hasExpectedInstances_) | |
3247 { | 3306 { |
3248 case ResourceType_Patient: | 3307 content.AddMetadata(status.seriesId_, MetadataType_Series_ExpectedNumberOfInstances, |
3249 content.AddMetadata(status.patientId_, it->first.second, it->second); | 3308 boost::lexical_cast<std::string>(expectedInstances_)); |
3250 break; | |
3251 | |
3252 case ResourceType_Study: | |
3253 content.AddMetadata(status.studyId_, it->first.second, it->second); | |
3254 break; | |
3255 | |
3256 case ResourceType_Series: | |
3257 content.AddMetadata(status.seriesId_, it->first.second, it->second); | |
3258 break; | |
3259 | |
3260 case ResourceType_Instance: | |
3261 SetInstanceMetadata(content, instanceMetadata_, instanceId, | |
3262 it->first.second, it->second); | |
3263 break; | |
3264 | |
3265 default: | |
3266 throw OrthancException(ErrorCode_ParameterOutOfRange); | |
3267 } | 3309 } |
3268 } | 3310 |
3269 | 3311 // New in Orthanc 1.9.0 |
3270 if (!isReconstruct_) | 3312 content.AddMetadata(status.seriesId_, MetadataType_RemoteAet, |
3271 { | 3313 origin_.GetRemoteAetC()); |
3272 // Populate the tags of the newly-created resources | 3314 } |
3273 content.AddResource(instanceId, ResourceType_Instance, dicomSummary_); | 3315 // Attach the auto-computed metadata for the instance level, |
3274 SetInstanceMetadata(content, instanceMetadata_, instanceId, MetadataType_MainDicomTagsSignature, DicomMap::GetMainDicomTagsSignature(ResourceType_Instance)); // New in Orthanc 1.11.0 | 3316 // reflecting these additions into the input metadata map |
3275 SetMainDicomSequenceMetadata(content, instanceId, dicomSummary_, ResourceType_Instance); // new in Orthanc 1.11.1 | 3317 SetInstanceMetadata(content, instanceMetadata_, instanceId, |
3276 | 3318 MetadataType_Instance_ReceptionDate, now); |
3277 if (status.isNewSeries_) | 3319 SetInstanceMetadata(content, instanceMetadata_, instanceId, MetadataType_RemoteAet, |
3320 origin_.GetRemoteAetC()); | |
3321 SetInstanceMetadata(content, instanceMetadata_, instanceId, MetadataType_Instance_Origin, | |
3322 EnumerationToString(origin_.GetRequestOrigin())); | |
3323 | |
3324 std::string s; | |
3325 | |
3326 if (origin_.LookupRemoteIp(s)) | |
3327 { | |
3328 // New in Orthanc 1.4.0 | |
3329 SetInstanceMetadata(content, instanceMetadata_, instanceId, | |
3330 MetadataType_Instance_RemoteIp, s); | |
3331 } | |
3332 | |
3333 if (origin_.LookupCalledAet(s)) | |
3334 { | |
3335 // New in Orthanc 1.4.0 | |
3336 SetInstanceMetadata(content, instanceMetadata_, instanceId, | |
3337 MetadataType_Instance_CalledAet, s); | |
3338 } | |
3339 | |
3340 if (origin_.LookupHttpUsername(s)) | |
3341 { | |
3342 // New in Orthanc 1.4.0 | |
3343 SetInstanceMetadata(content, instanceMetadata_, instanceId, | |
3344 MetadataType_Instance_HttpUsername, s); | |
3345 } | |
3346 } | |
3347 | |
3348 // Following metadatas are also updated if reconstructing the instance. | |
3349 // They might be missing since they have been introduced along Orthanc versions. | |
3350 | |
3351 if (hasTransferSyntax_) | |
3352 { | |
3353 // New in Orthanc 1.2.0 | |
3354 SetInstanceMetadata(content, instanceMetadata_, instanceId, | |
3355 MetadataType_Instance_TransferSyntax, | |
3356 GetTransferSyntaxUid(transferSyntax_)); | |
3357 } | |
3358 | |
3359 if (hasPixelDataOffset_) | |
3360 { | |
3361 // New in Orthanc 1.9.1 | |
3362 SetInstanceMetadata(content, instanceMetadata_, instanceId, | |
3363 MetadataType_Instance_PixelDataOffset, | |
3364 boost::lexical_cast<std::string>(pixelDataOffset_)); | |
3365 | |
3366 // New in Orthanc 1.12.1 | |
3367 if (dicomSummary_.GuessPixelDataValueRepresentation(transferSyntax_) != pixelDataVR_) | |
3368 { | |
3369 // Store the VR of pixel data if it doesn't comply with the standard | |
3370 SetInstanceMetadata(content, instanceMetadata_, instanceId, | |
3371 MetadataType_Instance_PixelDataVR, | |
3372 EnumerationToString(pixelDataVR_)); | |
3373 } | |
3374 } | |
3375 | |
3376 const DicomValue* value; | |
3377 if ((value = dicomSummary_.TestAndGetValue(DICOM_TAG_SOP_CLASS_UID)) != NULL && | |
3378 !value->IsNull() && | |
3379 !value->IsBinary()) | |
3380 { | |
3381 SetInstanceMetadata(content, instanceMetadata_, instanceId, | |
3382 MetadataType_Instance_SopClassUid, value->GetContent()); | |
3383 } | |
3384 | |
3385 | |
3386 if ((value = dicomSummary_.TestAndGetValue(DICOM_TAG_INSTANCE_NUMBER)) != NULL || | |
3387 (value = dicomSummary_.TestAndGetValue(DICOM_TAG_IMAGE_INDEX)) != NULL) | |
3388 { | |
3389 if (!value->IsNull() && | |
3390 !value->IsBinary()) | |
3391 { | |
3392 SetInstanceMetadata(content, instanceMetadata_, instanceId, | |
3393 MetadataType_Instance_IndexInSeries, Toolbox::StripSpaces(value->GetContent())); | |
3394 } | |
3395 } | |
3396 | |
3397 | |
3398 transaction.SetResourcesContent(content); | |
3399 | |
3400 | |
3401 if (!isReconstruct_) // a reconstruct shall not trigger any events | |
3402 { | |
3403 // Check whether the series of this new instance is now completed | |
3404 int64_t expectedNumberOfInstances; | |
3405 if (ComputeExpectedNumberOfInstances(expectedNumberOfInstances, dicomSummary_)) | |
3406 { | |
3407 SeriesStatus seriesStatus = transaction.GetSeriesStatus(status.seriesId_, expectedNumberOfInstances); | |
3408 if (seriesStatus == SeriesStatus_Complete) | |
3278 { | 3409 { |
3279 content.AddResource(status.seriesId_, ResourceType_Series, dicomSummary_); | 3410 transaction.LogChange(status.seriesId_, ChangeType_CompletedSeries, ResourceType_Series, hashSeries_); |
3280 content.AddMetadata(status.seriesId_, MetadataType_MainDicomTagsSignature, DicomMap::GetMainDicomTagsSignature(ResourceType_Series)); // New in Orthanc 1.11.0 | |
3281 SetMainDicomSequenceMetadata(content, status.seriesId_, dicomSummary_, ResourceType_Series); // new in Orthanc 1.11.1 | |
3282 } | 3411 } |
3283 | 3412 } |
3284 if (status.isNewStudy_) | 3413 |
3285 { | 3414 transaction.LogChange(status.seriesId_, ChangeType_NewChildInstance, ResourceType_Series, hashSeries_); |
3286 content.AddResource(status.studyId_, ResourceType_Study, dicomSummary_); | 3415 transaction.LogChange(status.studyId_, ChangeType_NewChildInstance, ResourceType_Study, hashStudy_); |
3287 content.AddMetadata(status.studyId_, MetadataType_MainDicomTagsSignature, DicomMap::GetMainDicomTagsSignature(ResourceType_Study)); // New in Orthanc 1.11.0 | 3416 transaction.LogChange(status.patientId_, ChangeType_NewChildInstance, ResourceType_Patient, hashPatient_); |
3288 SetMainDicomSequenceMetadata(content, status.studyId_, dicomSummary_, ResourceType_Study); // new in Orthanc 1.11.1 | 3417 |
3289 } | 3418 // Mark the parent resources of this instance as unstable |
3290 | 3419 transaction.GetTransactionContext().MarkAsUnstable(ResourceType_Series, status.seriesId_, hashSeries_); |
3291 if (status.isNewPatient_) | 3420 transaction.GetTransactionContext().MarkAsUnstable(ResourceType_Study, status.studyId_, hashStudy_); |
3292 { | 3421 transaction.GetTransactionContext().MarkAsUnstable(ResourceType_Patient, status.patientId_, hashPatient_); |
3293 content.AddResource(status.patientId_, ResourceType_Patient, dicomSummary_); | 3422 } |
3294 content.AddMetadata(status.patientId_, MetadataType_MainDicomTagsSignature, DicomMap::GetMainDicomTagsSignature(ResourceType_Patient)); // New in Orthanc 1.11.0 | 3423 |
3295 SetMainDicomSequenceMetadata(content, status.patientId_, dicomSummary_, ResourceType_Patient); // new in Orthanc 1.11.1 | |
3296 } | |
3297 | |
3298 // Attach the auto-computed metadata for the patient/study/series levels | |
3299 std::string now = SystemToolbox::GetNowIsoString(true /* use UTC time (not local time) */); | |
3300 content.AddMetadata(status.seriesId_, MetadataType_LastUpdate, now); | |
3301 content.AddMetadata(status.studyId_, MetadataType_LastUpdate, now); | |
3302 content.AddMetadata(status.patientId_, MetadataType_LastUpdate, now); | |
3303 | |
3304 if (status.isNewSeries_) | |
3305 { | |
3306 if (hasExpectedInstances_) | |
3307 { | |
3308 content.AddMetadata(status.seriesId_, MetadataType_Series_ExpectedNumberOfInstances, | |
3309 boost::lexical_cast<std::string>(expectedInstances_)); | |
3310 } | |
3311 | |
3312 // New in Orthanc 1.9.0 | |
3313 content.AddMetadata(status.seriesId_, MetadataType_RemoteAet, | |
3314 origin_.GetRemoteAetC()); | |
3315 } | |
3316 // Attach the auto-computed metadata for the instance level, | |
3317 // reflecting these additions into the input metadata map | |
3318 SetInstanceMetadata(content, instanceMetadata_, instanceId, | |
3319 MetadataType_Instance_ReceptionDate, now); | |
3320 SetInstanceMetadata(content, instanceMetadata_, instanceId, MetadataType_RemoteAet, | |
3321 origin_.GetRemoteAetC()); | |
3322 SetInstanceMetadata(content, instanceMetadata_, instanceId, MetadataType_Instance_Origin, | |
3323 EnumerationToString(origin_.GetRequestOrigin())); | |
3324 | |
3325 std::string s; | |
3326 | |
3327 if (origin_.LookupRemoteIp(s)) | |
3328 { | |
3329 // New in Orthanc 1.4.0 | |
3330 SetInstanceMetadata(content, instanceMetadata_, instanceId, | |
3331 MetadataType_Instance_RemoteIp, s); | |
3332 } | |
3333 | |
3334 if (origin_.LookupCalledAet(s)) | |
3335 { | |
3336 // New in Orthanc 1.4.0 | |
3337 SetInstanceMetadata(content, instanceMetadata_, instanceId, | |
3338 MetadataType_Instance_CalledAet, s); | |
3339 } | |
3340 | |
3341 if (origin_.LookupHttpUsername(s)) | |
3342 { | |
3343 // New in Orthanc 1.4.0 | |
3344 SetInstanceMetadata(content, instanceMetadata_, instanceId, | |
3345 MetadataType_Instance_HttpUsername, s); | |
3346 } | |
3347 } | |
3348 | |
3349 // Following metadatas are also updated if reconstructing the instance. | |
3350 // They might be missing since they have been introduced along Orthanc versions. | |
3351 | |
3352 if (hasTransferSyntax_) | |
3353 { | |
3354 // New in Orthanc 1.2.0 | |
3355 SetInstanceMetadata(content, instanceMetadata_, instanceId, | |
3356 MetadataType_Instance_TransferSyntax, | |
3357 GetTransferSyntaxUid(transferSyntax_)); | |
3358 } | |
3359 | |
3360 if (hasPixelDataOffset_) | |
3361 { | |
3362 // New in Orthanc 1.9.1 | |
3363 SetInstanceMetadata(content, instanceMetadata_, instanceId, | |
3364 MetadataType_Instance_PixelDataOffset, | |
3365 boost::lexical_cast<std::string>(pixelDataOffset_)); | |
3366 | |
3367 // New in Orthanc 1.12.1 | |
3368 if (dicomSummary_.GuessPixelDataValueRepresentation(transferSyntax_) != pixelDataVR_) | |
3369 { | |
3370 // Store the VR of pixel data if it doesn't comply with the standard | |
3371 SetInstanceMetadata(content, instanceMetadata_, instanceId, | |
3372 MetadataType_Instance_PixelDataVR, | |
3373 EnumerationToString(pixelDataVR_)); | |
3374 } | |
3375 } | |
3376 | |
3377 const DicomValue* value; | |
3378 if ((value = dicomSummary_.TestAndGetValue(DICOM_TAG_SOP_CLASS_UID)) != NULL && | |
3379 !value->IsNull() && | |
3380 !value->IsBinary()) | |
3381 { | |
3382 SetInstanceMetadata(content, instanceMetadata_, instanceId, | |
3383 MetadataType_Instance_SopClassUid, value->GetContent()); | |
3384 } | |
3385 | |
3386 | |
3387 if ((value = dicomSummary_.TestAndGetValue(DICOM_TAG_INSTANCE_NUMBER)) != NULL || | |
3388 (value = dicomSummary_.TestAndGetValue(DICOM_TAG_IMAGE_INDEX)) != NULL) | |
3389 { | |
3390 if (!value->IsNull() && | |
3391 !value->IsBinary()) | |
3392 { | |
3393 SetInstanceMetadata(content, instanceMetadata_, instanceId, | |
3394 MetadataType_Instance_IndexInSeries, Toolbox::StripSpaces(value->GetContent())); | |
3395 } | |
3396 } | |
3397 | |
3398 | |
3399 transaction.SetResourcesContent(content); | |
3400 } | |
3401 | |
3402 | |
3403 // Check whether the series of this new instance is now completed | |
3404 int64_t expectedNumberOfInstances; | |
3405 if (ComputeExpectedNumberOfInstances(expectedNumberOfInstances, dicomSummary_)) | |
3406 { | |
3407 SeriesStatus seriesStatus = transaction.GetSeriesStatus(status.seriesId_, expectedNumberOfInstances); | |
3408 if (seriesStatus == SeriesStatus_Complete) | |
3409 { | |
3410 transaction.LogChange(status.seriesId_, ChangeType_CompletedSeries, ResourceType_Series, hashSeries_); | |
3411 } | |
3412 } | |
3413 | |
3414 transaction.LogChange(status.seriesId_, ChangeType_NewChildInstance, ResourceType_Series, hashSeries_); | |
3415 transaction.LogChange(status.studyId_, ChangeType_NewChildInstance, ResourceType_Study, hashStudy_); | |
3416 transaction.LogChange(status.patientId_, ChangeType_NewChildInstance, ResourceType_Patient, hashPatient_); | |
3417 | |
3418 // Mark the parent resources of this instance as unstable | |
3419 transaction.GetTransactionContext().MarkAsUnstable(ResourceType_Series, status.seriesId_, hashSeries_); | |
3420 transaction.GetTransactionContext().MarkAsUnstable(ResourceType_Study, status.studyId_, hashStudy_); | |
3421 transaction.GetTransactionContext().MarkAsUnstable(ResourceType_Patient, status.patientId_, hashPatient_); | |
3422 transaction.GetTransactionContext().SignalAttachmentsAdded(instanceSize); | 3424 transaction.GetTransactionContext().SignalAttachmentsAdded(instanceSize); |
3423 | 3425 storeStatus_ = StoreStatus_Success; |
3424 storeStatus_ = StoreStatus_Success; | |
3425 } | 3426 } |
3426 }; | 3427 }; |
3427 | 3428 |
3428 | 3429 |
3429 Operations operations(instanceMetadata, dicomSummary, attachments, metadata, origin, overwrite, | 3430 Operations operations(instanceMetadata, dicomSummary, attachments, metadata, origin, overwrite, |