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,