Mercurial > hg > orthanc
comparison OrthancServer/Plugins/Engine/OrthancPluginDatabaseV4.cpp @ 5807:8279eaab0d1d attach-custom-data
merged default -> attach-custom-data
author | Alain Mazy <am@orthanc.team> |
---|---|
date | Tue, 24 Sep 2024 11:39:52 +0200 |
parents | 75e949689c08 68fc5af30c03 |
children | 023a99146dd0 |
comparison
equal
deleted
inserted
replaced
5085:79f98ee4f04b | 5807:8279eaab0d1d |
---|---|
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-2022 Osimis S.A., Belgium | 5 * Copyright (C) 2017-2023 Osimis S.A., Belgium |
6 * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium | 6 * Copyright (C) 2024-2024 Orthanc Team SRL, 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 |
11 * License, or (at your option) any later version. | 12 * License, or (at your option) any later version. |
25 | 26 |
26 #if ORTHANC_ENABLE_PLUGINS != 1 | 27 #if ORTHANC_ENABLE_PLUGINS != 1 |
27 # error The plugin support is disabled | 28 # error The plugin support is disabled |
28 #endif | 29 #endif |
29 | 30 |
31 #include "../../../OrthancFramework/Sources/DicomParsing/FromDcmtkBridge.h" | |
30 #include "../../../OrthancFramework/Sources/Logging.h" | 32 #include "../../../OrthancFramework/Sources/Logging.h" |
31 #include "../../../OrthancFramework/Sources/OrthancException.h" | 33 #include "../../../OrthancFramework/Sources/OrthancException.h" |
32 #include "../../Sources/Database/ResourcesContent.h" | 34 #include "../../Sources/Database/ResourcesContent.h" |
33 #include "../../Sources/Database/VoidDatabaseListener.h" | 35 #include "../../Sources/Database/VoidDatabaseListener.h" |
36 #include "../../Sources/ServerToolbox.h" | |
34 #include "PluginsEnumerations.h" | 37 #include "PluginsEnumerations.h" |
35 | 38 |
39 #include "OrthancDatabasePlugin.pb.h" // Auto-generated file | |
40 | |
36 #include <cassert> | 41 #include <cassert> |
37 | 42 |
38 | |
39 #define CHECK_FUNCTION_EXISTS(backend, func) \ | |
40 if (backend.func == NULL) \ | |
41 { \ | |
42 throw OrthancException( \ | |
43 ErrorCode_DatabasePlugin, "Missing primitive: " #func "()"); \ | |
44 } | |
45 | 43 |
46 namespace Orthanc | 44 namespace Orthanc |
47 { | 45 { |
46 static void CheckSuccess(PluginsErrorDictionary& errorDictionary, | |
47 OrthancPluginErrorCode code) | |
48 { | |
49 if (code != OrthancPluginErrorCode_Success) | |
50 { | |
51 errorDictionary.LogError(code, true); | |
52 throw OrthancException(static_cast<ErrorCode>(code)); | |
53 } | |
54 } | |
55 | |
56 | |
57 static ResourceType Convert(DatabasePluginMessages::ResourceType type) | |
58 { | |
59 switch (type) | |
60 { | |
61 case DatabasePluginMessages::RESOURCE_PATIENT: | |
62 return ResourceType_Patient; | |
63 | |
64 case DatabasePluginMessages::RESOURCE_STUDY: | |
65 return ResourceType_Study; | |
66 | |
67 case DatabasePluginMessages::RESOURCE_SERIES: | |
68 return ResourceType_Series; | |
69 | |
70 case DatabasePluginMessages::RESOURCE_INSTANCE: | |
71 return ResourceType_Instance; | |
72 | |
73 default: | |
74 throw OrthancException(ErrorCode_ParameterOutOfRange); | |
75 } | |
76 } | |
77 | |
78 | |
79 static DatabasePluginMessages::ResourceType Convert(ResourceType type) | |
80 { | |
81 switch (type) | |
82 { | |
83 case ResourceType_Patient: | |
84 return DatabasePluginMessages::RESOURCE_PATIENT; | |
85 | |
86 case ResourceType_Study: | |
87 return DatabasePluginMessages::RESOURCE_STUDY; | |
88 | |
89 case ResourceType_Series: | |
90 return DatabasePluginMessages::RESOURCE_SERIES; | |
91 | |
92 case ResourceType_Instance: | |
93 return DatabasePluginMessages::RESOURCE_INSTANCE; | |
94 | |
95 default: | |
96 throw OrthancException(ErrorCode_ParameterOutOfRange); | |
97 } | |
98 } | |
99 | |
100 | |
101 static FileInfo Convert(const DatabasePluginMessages::FileInfo& source) | |
102 { | |
103 return FileInfo(source.uuid(), | |
104 static_cast<FileContentType>(source.content_type()), | |
105 source.uncompressed_size(), | |
106 source.uncompressed_hash(), | |
107 static_cast<CompressionType>(source.compression_type()), | |
108 source.compressed_size(), | |
109 source.compressed_hash(), | |
110 source.custom_data()); | |
111 } | |
112 | |
113 | |
114 static ServerIndexChange Convert(const DatabasePluginMessages::ServerIndexChange& source) | |
115 { | |
116 return ServerIndexChange(source.seq(), | |
117 static_cast<ChangeType>(source.change_type()), | |
118 Convert(source.resource_type()), | |
119 source.public_id(), | |
120 source.date()); | |
121 } | |
122 | |
123 | |
124 static ExportedResource Convert(const DatabasePluginMessages::ExportedResource& source) | |
125 { | |
126 return ExportedResource(source.seq(), | |
127 Convert(source.resource_type()), | |
128 source.public_id(), | |
129 source.modality(), | |
130 source.date(), | |
131 source.patient_id(), | |
132 source.study_instance_uid(), | |
133 source.series_instance_uid(), | |
134 source.sop_instance_uid()); | |
135 } | |
136 | |
137 | |
138 static void Execute(DatabasePluginMessages::Response& response, | |
139 const OrthancPluginDatabaseV4& database, | |
140 const DatabasePluginMessages::Request& request) | |
141 { | |
142 std::string requestSerialized; | |
143 request.SerializeToString(&requestSerialized); | |
144 | |
145 OrthancPluginMemoryBuffer64 responseSerialized; | |
146 CheckSuccess(database.GetErrorDictionary(), database.GetDefinition().operations( | |
147 &responseSerialized, database.GetDefinition().backend, | |
148 requestSerialized.empty() ? NULL : requestSerialized.c_str(), | |
149 requestSerialized.size())); | |
150 | |
151 bool success = response.ParseFromArray(responseSerialized.data, responseSerialized.size); | |
152 | |
153 if (responseSerialized.size > 0) | |
154 { | |
155 free(responseSerialized.data); | |
156 } | |
157 | |
158 if (!success) | |
159 { | |
160 throw OrthancException(ErrorCode_DatabasePlugin, "Cannot unserialize protobuf originating from the database plugin"); | |
161 } | |
162 } | |
163 | |
164 | |
165 static void ExecuteDatabase(DatabasePluginMessages::DatabaseResponse& response, | |
166 const OrthancPluginDatabaseV4& database, | |
167 DatabasePluginMessages::DatabaseOperation operation, | |
168 const DatabasePluginMessages::DatabaseRequest& request) | |
169 { | |
170 DatabasePluginMessages::Request fullRequest; | |
171 fullRequest.set_type(DatabasePluginMessages::REQUEST_DATABASE); | |
172 fullRequest.mutable_database_request()->CopyFrom(request); | |
173 fullRequest.mutable_database_request()->set_operation(operation); | |
174 | |
175 DatabasePluginMessages::Response fullResponse; | |
176 Execute(fullResponse, database, fullRequest); | |
177 | |
178 response.CopyFrom(fullResponse.database_response()); | |
179 } | |
180 | |
181 | |
48 class OrthancPluginDatabaseV4::Transaction : public IDatabaseWrapper::ITransaction | 182 class OrthancPluginDatabaseV4::Transaction : public IDatabaseWrapper::ITransaction |
49 { | 183 { |
50 private: | 184 private: |
51 OrthancPluginDatabaseV4& that_; | 185 OrthancPluginDatabaseV4& database_; |
52 IDatabaseListener& listener_; | 186 IDatabaseListener& listener_; |
53 OrthancPluginDatabaseTransaction* transaction_; | 187 void* transaction_; |
54 | 188 |
55 | 189 void ExecuteTransaction(DatabasePluginMessages::TransactionResponse& response, |
56 void CheckSuccess(OrthancPluginErrorCode code) const | 190 DatabasePluginMessages::TransactionOperation operation, |
57 { | 191 const DatabasePluginMessages::TransactionRequest& request) |
58 that_.CheckSuccess(code); | 192 { |
59 } | 193 DatabasePluginMessages::Request fullRequest; |
60 | 194 fullRequest.set_type(DatabasePluginMessages::REQUEST_TRANSACTION); |
61 | 195 fullRequest.mutable_transaction_request()->CopyFrom(request); |
62 static FileInfo Convert(const OrthancPluginAttachment& attachment) | 196 fullRequest.mutable_transaction_request()->set_transaction(reinterpret_cast<intptr_t>(transaction_)); |
63 { | 197 fullRequest.mutable_transaction_request()->set_operation(operation); |
64 std::string customData; | 198 |
65 return FileInfo(attachment.uuid, | 199 DatabasePluginMessages::Response fullResponse; |
66 static_cast<FileContentType>(attachment.contentType), | 200 Execute(fullResponse, database_, fullRequest); |
67 attachment.uncompressedSize, | 201 |
68 attachment.uncompressedHash, | 202 response.CopyFrom(fullResponse.transaction_response()); |
69 static_cast<CompressionType>(attachment.compressionType), | 203 } |
70 attachment.compressedSize, | 204 |
71 attachment.compressedHash, | 205 |
72 customData); | 206 void ExecuteTransaction(DatabasePluginMessages::TransactionResponse& response, |
73 } | 207 DatabasePluginMessages::TransactionOperation operation) |
74 | 208 { |
75 static FileInfo Convert(const OrthancPluginAttachment2& attachment) | 209 DatabasePluginMessages::TransactionRequest request; // Ignored |
76 { | 210 ExecuteTransaction(response, operation, request); |
77 return FileInfo(attachment.uuid, | 211 } |
78 static_cast<FileContentType>(attachment.contentType), | 212 |
79 attachment.uncompressedSize, | 213 |
80 attachment.uncompressedHash, | 214 void ExecuteTransaction(DatabasePluginMessages::TransactionOperation operation, |
81 static_cast<CompressionType>(attachment.compressionType), | 215 const DatabasePluginMessages::TransactionRequest& request) |
82 attachment.compressedSize, | 216 { |
83 attachment.compressedHash, | 217 DatabasePluginMessages::TransactionResponse response; // Ignored |
84 attachment.customData); | 218 ExecuteTransaction(response, operation, request); |
85 } | 219 } |
86 | 220 |
87 void ReadStringAnswers(std::list<std::string>& target) | 221 |
88 { | 222 void ExecuteTransaction(DatabasePluginMessages::TransactionOperation operation) |
89 uint32_t count; | 223 { |
90 CheckSuccess(that_.backend_.readAnswersCount(transaction_, &count)); | 224 DatabasePluginMessages::TransactionResponse response; // Ignored |
225 DatabasePluginMessages::TransactionRequest request; // Ignored | |
226 ExecuteTransaction(response, operation, request); | |
227 } | |
228 | |
229 | |
230 void ListLabelsInternal(std::set<std::string>& target, | |
231 bool isSingleResource, | |
232 int64_t resource) | |
233 { | |
234 if (database_.GetDatabaseCapabilities().HasLabelsSupport()) | |
235 { | |
236 DatabasePluginMessages::TransactionRequest request; | |
237 request.mutable_list_labels()->set_single_resource(isSingleResource); | |
238 request.mutable_list_labels()->set_id(resource); | |
239 | |
240 DatabasePluginMessages::TransactionResponse response; | |
241 ExecuteTransaction(response, DatabasePluginMessages::OPERATION_LIST_LABELS, request); | |
242 | |
243 target.clear(); | |
244 for (int i = 0; i < response.list_labels().labels().size(); i++) | |
245 { | |
246 target.insert(response.list_labels().labels(i)); | |
247 } | |
248 } | |
249 else | |
250 { | |
251 // This method shouldn't have been called | |
252 throw OrthancException(ErrorCode_InternalError); | |
253 } | |
254 } | |
255 | |
256 | |
257 public: | |
258 Transaction(OrthancPluginDatabaseV4& database, | |
259 IDatabaseListener& listener, | |
260 TransactionType type) : | |
261 database_(database), | |
262 listener_(listener), | |
263 transaction_(NULL) | |
264 { | |
265 DatabasePluginMessages::DatabaseRequest request; | |
266 | |
267 switch (type) | |
268 { | |
269 case TransactionType_ReadOnly: | |
270 request.mutable_start_transaction()->set_type(DatabasePluginMessages::TRANSACTION_READ_ONLY); | |
271 break; | |
272 | |
273 case TransactionType_ReadWrite: | |
274 request.mutable_start_transaction()->set_type(DatabasePluginMessages::TRANSACTION_READ_WRITE); | |
275 break; | |
276 | |
277 default: | |
278 throw OrthancException(ErrorCode_ParameterOutOfRange); | |
279 } | |
280 | |
281 DatabasePluginMessages::DatabaseResponse response; | |
282 ExecuteDatabase(response, database, DatabasePluginMessages::OPERATION_START_TRANSACTION, request); | |
283 | |
284 transaction_ = reinterpret_cast<void*>(response.start_transaction().transaction()); | |
285 | |
286 if (transaction_ == NULL) | |
287 { | |
288 throw OrthancException(ErrorCode_NullPointer); | |
289 } | |
290 } | |
291 | |
292 | |
293 virtual ~Transaction() | |
294 { | |
295 try | |
296 { | |
297 DatabasePluginMessages::DatabaseRequest request; | |
298 request.mutable_finalize_transaction()->set_transaction(reinterpret_cast<intptr_t>(transaction_)); | |
299 | |
300 DatabasePluginMessages::DatabaseResponse response; | |
301 ExecuteDatabase(response, database_, DatabasePluginMessages::OPERATION_FINALIZE_TRANSACTION, request); | |
302 } | |
303 catch (OrthancException& e) | |
304 { | |
305 // Destructors must not throw exceptions | |
306 LOG(ERROR) << "Cannot finalize the database engine: " << e.What(); | |
307 } | |
308 } | |
309 | |
310 void* GetTransactionObject() | |
311 { | |
312 return transaction_; | |
313 } | |
314 | |
315 | |
316 virtual void Rollback() ORTHANC_OVERRIDE | |
317 { | |
318 ExecuteTransaction(DatabasePluginMessages::OPERATION_ROLLBACK); | |
319 } | |
320 | |
321 | |
322 virtual void Commit(int64_t fileSizeDelta) ORTHANC_OVERRIDE | |
323 { | |
324 DatabasePluginMessages::TransactionRequest request; | |
325 request.mutable_commit()->set_file_size_delta(fileSizeDelta); | |
326 | |
327 ExecuteTransaction(DatabasePluginMessages::OPERATION_COMMIT, request); | |
328 } | |
329 | |
330 | |
331 virtual void AddAttachment(int64_t id, | |
332 const FileInfo& attachment, | |
333 int64_t revision) ORTHANC_OVERRIDE | |
334 { | |
335 DatabasePluginMessages::TransactionRequest request; | |
336 request.mutable_add_attachment()->set_id(id); | |
337 request.mutable_add_attachment()->mutable_attachment()->set_uuid(attachment.GetUuid()); | |
338 request.mutable_add_attachment()->mutable_attachment()->set_content_type(attachment.GetContentType()); | |
339 request.mutable_add_attachment()->mutable_attachment()->set_uncompressed_size(attachment.GetUncompressedSize()); | |
340 request.mutable_add_attachment()->mutable_attachment()->set_uncompressed_hash(attachment.GetUncompressedMD5()); | |
341 request.mutable_add_attachment()->mutable_attachment()->set_compression_type(attachment.GetCompressionType()); | |
342 request.mutable_add_attachment()->mutable_attachment()->set_compressed_size(attachment.GetCompressedSize()); | |
343 request.mutable_add_attachment()->mutable_attachment()->set_compressed_hash(attachment.GetCompressedMD5()); | |
344 request.mutable_add_attachment()->set_revision(revision); | |
345 | |
346 ExecuteTransaction(DatabasePluginMessages::OPERATION_ADD_ATTACHMENT, request); | |
347 } | |
348 | |
349 | |
350 virtual void ClearChanges() ORTHANC_OVERRIDE | |
351 { | |
352 ExecuteTransaction(DatabasePluginMessages::OPERATION_CLEAR_CHANGES); | |
353 } | |
354 | |
355 | |
356 virtual void ClearExportedResources() ORTHANC_OVERRIDE | |
357 { | |
358 ExecuteTransaction(DatabasePluginMessages::OPERATION_CLEAR_EXPORTED_RESOURCES); | |
359 } | |
360 | |
361 | |
362 virtual void DeleteAttachment(int64_t id, | |
363 FileContentType attachment) ORTHANC_OVERRIDE | |
364 { | |
365 DatabasePluginMessages::TransactionRequest request; | |
366 request.mutable_delete_attachment()->set_id(id); | |
367 request.mutable_delete_attachment()->set_type(attachment); | |
368 | |
369 DatabasePluginMessages::TransactionResponse response; | |
370 ExecuteTransaction(response, DatabasePluginMessages::OPERATION_DELETE_ATTACHMENT, request); | |
371 | |
372 listener_.SignalAttachmentDeleted(Convert(response.delete_attachment().deleted_attachment())); | |
373 } | |
374 | |
375 | |
376 virtual void DeleteMetadata(int64_t id, | |
377 MetadataType type) ORTHANC_OVERRIDE | |
378 { | |
379 DatabasePluginMessages::TransactionRequest request; | |
380 request.mutable_delete_metadata()->set_id(id); | |
381 request.mutable_delete_metadata()->set_type(type); | |
382 | |
383 ExecuteTransaction(DatabasePluginMessages::OPERATION_DELETE_METADATA, request); | |
384 } | |
385 | |
386 | |
387 virtual void DeleteResource(int64_t id) ORTHANC_OVERRIDE | |
388 { | |
389 DatabasePluginMessages::TransactionRequest request; | |
390 request.mutable_delete_resource()->set_id(id); | |
391 | |
392 DatabasePluginMessages::TransactionResponse response; | |
393 ExecuteTransaction(response, DatabasePluginMessages::OPERATION_DELETE_RESOURCE, request); | |
394 | |
395 for (int i = 0; i < response.delete_resource().deleted_attachments().size(); i++) | |
396 { | |
397 listener_.SignalAttachmentDeleted(Convert(response.delete_resource().deleted_attachments(i))); | |
398 } | |
399 | |
400 for (int i = 0; i < response.delete_resource().deleted_resources().size(); i++) | |
401 { | |
402 listener_.SignalResourceDeleted(Convert(response.delete_resource().deleted_resources(i).level()), | |
403 response.delete_resource().deleted_resources(i).public_id()); | |
404 } | |
405 | |
406 if (response.delete_resource().is_remaining_ancestor()) | |
407 { | |
408 listener_.SignalRemainingAncestor(Convert(response.delete_resource().remaining_ancestor().level()), | |
409 response.delete_resource().remaining_ancestor().public_id()); | |
410 } | |
411 } | |
412 | |
413 | |
414 virtual void GetAllMetadata(std::map<MetadataType, std::string>& target, | |
415 int64_t id) ORTHANC_OVERRIDE | |
416 { | |
417 DatabasePluginMessages::TransactionRequest request; | |
418 request.mutable_get_all_metadata()->set_id(id); | |
419 | |
420 DatabasePluginMessages::TransactionResponse response; | |
421 ExecuteTransaction(response, DatabasePluginMessages::OPERATION_GET_ALL_METADATA, request); | |
91 | 422 |
92 target.clear(); | 423 target.clear(); |
93 for (uint32_t i = 0; i < count; i++) | 424 for (int i = 0; i < response.get_all_metadata().metadata().size(); i++) |
94 { | 425 { |
95 const char* value = NULL; | 426 MetadataType key = static_cast<MetadataType>(response.get_all_metadata().metadata(i).type()); |
96 CheckSuccess(that_.backend_.readAnswerString(transaction_, &value, i)); | 427 |
97 if (value == NULL) | 428 if (target.find(key) == target.end()) |
429 { | |
430 target[key] = response.get_all_metadata().metadata(i).value(); | |
431 } | |
432 else | |
433 { | |
434 throw OrthancException(ErrorCode_DatabasePlugin); | |
435 } | |
436 } | |
437 } | |
438 | |
439 | |
440 virtual void GetAllPublicIds(std::list<std::string>& target, | |
441 ResourceType resourceType) ORTHANC_OVERRIDE | |
442 { | |
443 DatabasePluginMessages::TransactionRequest request; | |
444 request.mutable_get_all_public_ids()->set_resource_type(Convert(resourceType)); | |
445 | |
446 DatabasePluginMessages::TransactionResponse response; | |
447 ExecuteTransaction(response, DatabasePluginMessages::OPERATION_GET_ALL_PUBLIC_IDS, request); | |
448 | |
449 target.clear(); | |
450 for (int i = 0; i < response.get_all_public_ids().ids().size(); i++) | |
451 { | |
452 target.push_back(response.get_all_public_ids().ids(i)); | |
453 } | |
454 } | |
455 | |
456 | |
457 virtual void GetAllPublicIds(std::list<std::string>& target, | |
458 ResourceType resourceType, | |
459 int64_t since, | |
460 uint32_t limit) ORTHANC_OVERRIDE | |
461 { | |
462 DatabasePluginMessages::TransactionRequest request; | |
463 request.mutable_get_all_public_ids_with_limits()->set_resource_type(Convert(resourceType)); | |
464 request.mutable_get_all_public_ids_with_limits()->set_since(since); | |
465 request.mutable_get_all_public_ids_with_limits()->set_limit(limit); | |
466 | |
467 DatabasePluginMessages::TransactionResponse response; | |
468 ExecuteTransaction(response, DatabasePluginMessages::OPERATION_GET_ALL_PUBLIC_IDS_WITH_LIMITS, request); | |
469 | |
470 target.clear(); | |
471 for (int i = 0; i < response.get_all_public_ids_with_limits().ids().size(); i++) | |
472 { | |
473 target.push_back(response.get_all_public_ids_with_limits().ids(i)); | |
474 } | |
475 } | |
476 | |
477 | |
478 virtual void GetChanges(std::list<ServerIndexChange>& target /*out*/, | |
479 bool& done /*out*/, | |
480 int64_t since, | |
481 uint32_t limit) ORTHANC_OVERRIDE | |
482 { | |
483 DatabasePluginMessages::TransactionRequest request; | |
484 request.mutable_get_changes()->set_since(since); | |
485 request.mutable_get_changes()->set_limit(limit); | |
486 | |
487 DatabasePluginMessages::TransactionResponse response; | |
488 ExecuteTransaction(response, DatabasePluginMessages::OPERATION_GET_CHANGES, request); | |
489 | |
490 done = response.get_changes().done(); | |
491 | |
492 target.clear(); | |
493 for (int i = 0; i < response.get_changes().changes().size(); i++) | |
494 { | |
495 target.push_back(Convert(response.get_changes().changes(i))); | |
496 } | |
497 } | |
498 | |
499 | |
500 virtual void GetChildrenInternalId(std::list<int64_t>& target, | |
501 int64_t id) ORTHANC_OVERRIDE | |
502 { | |
503 DatabasePluginMessages::TransactionRequest request; | |
504 request.mutable_get_children_internal_id()->set_id(id); | |
505 | |
506 DatabasePluginMessages::TransactionResponse response; | |
507 ExecuteTransaction(response, DatabasePluginMessages::OPERATION_GET_CHILDREN_INTERNAL_ID, request); | |
508 | |
509 target.clear(); | |
510 for (int i = 0; i < response.get_children_internal_id().ids().size(); i++) | |
511 { | |
512 target.push_back(response.get_children_internal_id().ids(i)); | |
513 } | |
514 } | |
515 | |
516 | |
517 virtual void GetChildrenPublicId(std::list<std::string>& target, | |
518 int64_t id) ORTHANC_OVERRIDE | |
519 { | |
520 DatabasePluginMessages::TransactionRequest request; | |
521 request.mutable_get_children_public_id()->set_id(id); | |
522 | |
523 DatabasePluginMessages::TransactionResponse response; | |
524 ExecuteTransaction(response, DatabasePluginMessages::OPERATION_GET_CHILDREN_PUBLIC_ID, request); | |
525 | |
526 target.clear(); | |
527 for (int i = 0; i < response.get_children_public_id().ids().size(); i++) | |
528 { | |
529 target.push_back(response.get_children_public_id().ids(i)); | |
530 } | |
531 } | |
532 | |
533 | |
534 virtual void GetExportedResources(std::list<ExportedResource>& target /*out*/, | |
535 bool& done /*out*/, | |
536 int64_t since, | |
537 uint32_t limit) ORTHANC_OVERRIDE | |
538 { | |
539 DatabasePluginMessages::TransactionRequest request; | |
540 request.mutable_get_exported_resources()->set_since(since); | |
541 request.mutable_get_exported_resources()->set_limit(limit); | |
542 | |
543 DatabasePluginMessages::TransactionResponse response; | |
544 ExecuteTransaction(response, DatabasePluginMessages::OPERATION_GET_EXPORTED_RESOURCES, request); | |
545 | |
546 done = response.get_exported_resources().done(); | |
547 | |
548 target.clear(); | |
549 for (int i = 0; i < response.get_exported_resources().resources().size(); i++) | |
550 { | |
551 target.push_back(Convert(response.get_exported_resources().resources(i))); | |
552 } | |
553 } | |
554 | |
555 | |
556 virtual void GetLastChange(std::list<ServerIndexChange>& target /*out*/) ORTHANC_OVERRIDE | |
557 { | |
558 DatabasePluginMessages::TransactionResponse response; | |
559 ExecuteTransaction(response, DatabasePluginMessages::OPERATION_GET_LAST_CHANGE); | |
560 | |
561 target.clear(); | |
562 if (response.get_last_change().found()) | |
563 { | |
564 target.push_back(Convert(response.get_last_change().change())); | |
565 } | |
566 } | |
567 | |
568 | |
569 virtual void GetLastExportedResource(std::list<ExportedResource>& target /*out*/) ORTHANC_OVERRIDE | |
570 { | |
571 DatabasePluginMessages::TransactionResponse response; | |
572 ExecuteTransaction(response, DatabasePluginMessages::OPERATION_GET_LAST_EXPORTED_RESOURCE); | |
573 | |
574 target.clear(); | |
575 if (response.get_last_exported_resource().found()) | |
576 { | |
577 target.push_back(Convert(response.get_last_exported_resource().resource())); | |
578 } | |
579 } | |
580 | |
581 | |
582 virtual void GetMainDicomTags(DicomMap& target, | |
583 int64_t id) ORTHANC_OVERRIDE | |
584 { | |
585 DatabasePluginMessages::TransactionRequest request; | |
586 request.mutable_get_main_dicom_tags()->set_id(id); | |
587 | |
588 DatabasePluginMessages::TransactionResponse response; | |
589 ExecuteTransaction(response, DatabasePluginMessages::OPERATION_GET_MAIN_DICOM_TAGS, request); | |
590 | |
591 target.Clear(); | |
592 | |
593 for (int i = 0; i < response.get_main_dicom_tags().tags().size(); i++) | |
594 { | |
595 const DatabasePluginMessages::GetMainDicomTags_Response_Tag& tag = response.get_main_dicom_tags().tags(i); | |
596 if (tag.group() > 0xffffu || | |
597 tag.element() > 0xffffu) | |
598 { | |
599 throw OrthancException(ErrorCode_ParameterOutOfRange); | |
600 } | |
601 else | |
602 { | |
603 target.SetValue(tag.group(), tag.element(), tag.value(), false); | |
604 } | |
605 } | |
606 } | |
607 | |
608 | |
609 virtual std::string GetPublicId(int64_t resourceId) ORTHANC_OVERRIDE | |
610 { | |
611 DatabasePluginMessages::TransactionRequest request; | |
612 request.mutable_get_public_id()->set_id(resourceId); | |
613 | |
614 DatabasePluginMessages::TransactionResponse response; | |
615 ExecuteTransaction(response, DatabasePluginMessages::OPERATION_GET_PUBLIC_ID, request); | |
616 return response.get_public_id().id(); | |
617 } | |
618 | |
619 | |
620 virtual uint64_t GetResourcesCount(ResourceType resourceType) ORTHANC_OVERRIDE | |
621 { | |
622 DatabasePluginMessages::TransactionRequest request; | |
623 request.mutable_get_resources_count()->set_type(Convert(resourceType)); | |
624 | |
625 DatabasePluginMessages::TransactionResponse response; | |
626 ExecuteTransaction(response, DatabasePluginMessages::OPERATION_GET_RESOURCES_COUNT, request); | |
627 return response.get_resources_count().count(); | |
628 } | |
629 | |
630 | |
631 virtual ResourceType GetResourceType(int64_t resourceId) ORTHANC_OVERRIDE | |
632 { | |
633 DatabasePluginMessages::TransactionRequest request; | |
634 request.mutable_get_resource_type()->set_id(resourceId); | |
635 | |
636 DatabasePluginMessages::TransactionResponse response; | |
637 ExecuteTransaction(response, DatabasePluginMessages::OPERATION_GET_RESOURCE_TYPE, request); | |
638 return Convert(response.get_resource_type().type()); | |
639 } | |
640 | |
641 | |
642 virtual uint64_t GetTotalCompressedSize() ORTHANC_OVERRIDE | |
643 { | |
644 DatabasePluginMessages::TransactionResponse response; | |
645 ExecuteTransaction(response, DatabasePluginMessages::OPERATION_GET_TOTAL_COMPRESSED_SIZE); | |
646 return response.get_total_compressed_size().size(); | |
647 } | |
648 | |
649 | |
650 virtual uint64_t GetTotalUncompressedSize() ORTHANC_OVERRIDE | |
651 { | |
652 DatabasePluginMessages::TransactionResponse response; | |
653 ExecuteTransaction(response, DatabasePluginMessages::OPERATION_GET_TOTAL_UNCOMPRESSED_SIZE); | |
654 return response.get_total_uncompressed_size().size(); | |
655 } | |
656 | |
657 | |
658 virtual bool IsProtectedPatient(int64_t internalId) ORTHANC_OVERRIDE | |
659 { | |
660 DatabasePluginMessages::TransactionRequest request; | |
661 request.mutable_is_protected_patient()->set_patient_id(internalId); | |
662 | |
663 DatabasePluginMessages::TransactionResponse response; | |
664 ExecuteTransaction(response, DatabasePluginMessages::OPERATION_IS_PROTECTED_PATIENT, request); | |
665 return response.is_protected_patient().protected_patient(); | |
666 } | |
667 | |
668 | |
669 virtual void ListAvailableAttachments(std::set<FileContentType>& target, | |
670 int64_t id) ORTHANC_OVERRIDE | |
671 { | |
672 DatabasePluginMessages::TransactionRequest request; | |
673 request.mutable_list_available_attachments()->set_id(id); | |
674 | |
675 DatabasePluginMessages::TransactionResponse response; | |
676 ExecuteTransaction(response, DatabasePluginMessages::OPERATION_LIST_AVAILABLE_ATTACHMENTS, request); | |
677 | |
678 target.clear(); | |
679 for (int i = 0; i < response.list_available_attachments().attachments().size(); i++) | |
680 { | |
681 FileContentType attachment = static_cast<FileContentType>(response.list_available_attachments().attachments(i)); | |
682 | |
683 if (target.find(attachment) == target.end()) | |
684 { | |
685 target.insert(attachment); | |
686 } | |
687 else | |
688 { | |
689 throw OrthancException(ErrorCode_DatabasePlugin); | |
690 } | |
691 } | |
692 } | |
693 | |
694 | |
695 virtual void LogChange(ChangeType changeType, | |
696 ResourceType resourceType, | |
697 int64_t internalId, | |
698 const std::string& /* publicId - unused */, | |
699 const std::string& date) ORTHANC_OVERRIDE | |
700 { | |
701 DatabasePluginMessages::TransactionRequest request; | |
702 request.mutable_log_change()->set_change_type(changeType); | |
703 request.mutable_log_change()->set_resource_type(Convert(resourceType)); | |
704 request.mutable_log_change()->set_resource_id(internalId); | |
705 request.mutable_log_change()->set_date(date); | |
706 | |
707 ExecuteTransaction(DatabasePluginMessages::OPERATION_LOG_CHANGE, request); | |
708 } | |
709 | |
710 | |
711 virtual void LogExportedResource(const ExportedResource& resource) ORTHANC_OVERRIDE | |
712 { | |
713 // TODO: "seq" is ignored, could be simplified in "ExportedResource" | |
714 | |
715 DatabasePluginMessages::TransactionRequest request; | |
716 request.mutable_log_exported_resource()->set_resource_type(Convert(resource.GetResourceType())); | |
717 request.mutable_log_exported_resource()->set_public_id(resource.GetPublicId()); | |
718 request.mutable_log_exported_resource()->set_modality(resource.GetModality()); | |
719 request.mutable_log_exported_resource()->set_date(resource.GetDate()); | |
720 request.mutable_log_exported_resource()->set_patient_id(resource.GetPatientId()); | |
721 request.mutable_log_exported_resource()->set_study_instance_uid(resource.GetStudyInstanceUid()); | |
722 request.mutable_log_exported_resource()->set_series_instance_uid(resource.GetSeriesInstanceUid()); | |
723 request.mutable_log_exported_resource()->set_sop_instance_uid(resource.GetSopInstanceUid()); | |
724 | |
725 ExecuteTransaction(DatabasePluginMessages::OPERATION_LOG_EXPORTED_RESOURCE, request); | |
726 } | |
727 | |
728 | |
729 virtual bool LookupAttachment(FileInfo& attachment, | |
730 int64_t& revision, | |
731 int64_t id, | |
732 FileContentType contentType) ORTHANC_OVERRIDE | |
733 { | |
734 DatabasePluginMessages::TransactionRequest request; | |
735 request.mutable_lookup_attachment()->set_id(id); | |
736 request.mutable_lookup_attachment()->set_content_type(contentType); | |
737 | |
738 DatabasePluginMessages::TransactionResponse response; | |
739 ExecuteTransaction(response, DatabasePluginMessages::OPERATION_LOOKUP_ATTACHMENT, request); | |
740 | |
741 if (response.lookup_attachment().found()) | |
742 { | |
743 attachment = Convert(response.lookup_attachment().attachment()); | |
744 revision = response.lookup_attachment().revision(); | |
745 return true; | |
746 } | |
747 else | |
748 { | |
749 return false; | |
750 } | |
751 } | |
752 | |
753 | |
754 virtual bool LookupGlobalProperty(std::string& target, | |
755 GlobalProperty property, | |
756 bool shared) ORTHANC_OVERRIDE | |
757 { | |
758 DatabasePluginMessages::TransactionRequest request; | |
759 request.mutable_lookup_global_property()->set_server_id(shared ? "" : database_.GetServerIdentifier()); | |
760 request.mutable_lookup_global_property()->set_property(property); | |
761 | |
762 DatabasePluginMessages::TransactionResponse response; | |
763 ExecuteTransaction(response, DatabasePluginMessages::OPERATION_LOOKUP_GLOBAL_PROPERTY, request); | |
764 | |
765 if (response.lookup_global_property().found()) | |
766 { | |
767 target = response.lookup_global_property().value(); | |
768 return true; | |
769 } | |
770 else | |
771 { | |
772 return false; | |
773 } | |
774 } | |
775 | |
776 | |
777 virtual int64_t IncrementGlobalProperty(GlobalProperty property, | |
778 int64_t increment, | |
779 bool shared) ORTHANC_OVERRIDE | |
780 { | |
781 DatabasePluginMessages::TransactionRequest request; | |
782 request.mutable_increment_global_property()->set_server_id(shared ? "" : database_.GetServerIdentifier()); | |
783 request.mutable_increment_global_property()->set_property(property); | |
784 request.mutable_increment_global_property()->set_increment(increment); | |
785 | |
786 DatabasePluginMessages::TransactionResponse response; | |
787 ExecuteTransaction(response, DatabasePluginMessages::OPERATION_INCREMENT_GLOBAL_PROPERTY, request); | |
788 | |
789 return response.increment_global_property().new_value(); | |
790 } | |
791 | |
792 virtual void UpdateAndGetStatistics(int64_t& patientsCount, | |
793 int64_t& studiesCount, | |
794 int64_t& seriesCount, | |
795 int64_t& instancesCount, | |
796 int64_t& compressedSize, | |
797 int64_t& uncompressedSize) ORTHANC_OVERRIDE | |
798 { | |
799 DatabasePluginMessages::TransactionResponse response; | |
800 ExecuteTransaction(response, DatabasePluginMessages::OPERATION_UPDATE_AND_GET_STATISTICS); | |
801 | |
802 patientsCount = response.update_and_get_statistics().patients_count(); | |
803 studiesCount = response.update_and_get_statistics().studies_count(); | |
804 seriesCount = response.update_and_get_statistics().series_count(); | |
805 instancesCount = response.update_and_get_statistics().instances_count(); | |
806 compressedSize = response.update_and_get_statistics().total_compressed_size(); | |
807 uncompressedSize = response.update_and_get_statistics().total_uncompressed_size(); | |
808 } | |
809 | |
810 virtual bool LookupMetadata(std::string& target, | |
811 int64_t& revision, | |
812 int64_t id, | |
813 MetadataType type) ORTHANC_OVERRIDE | |
814 { | |
815 DatabasePluginMessages::TransactionRequest request; | |
816 request.mutable_lookup_metadata()->set_id(id); | |
817 request.mutable_lookup_metadata()->set_metadata_type(type); | |
818 | |
819 DatabasePluginMessages::TransactionResponse response; | |
820 ExecuteTransaction(response, DatabasePluginMessages::OPERATION_LOOKUP_METADATA, request); | |
821 | |
822 if (response.lookup_metadata().found()) | |
823 { | |
824 target = response.lookup_metadata().value(); | |
825 revision = response.lookup_metadata().revision(); | |
826 return true; | |
827 } | |
828 else | |
829 { | |
830 return false; | |
831 } | |
832 } | |
833 | |
834 | |
835 virtual bool LookupParent(int64_t& parentId, | |
836 int64_t resourceId) ORTHANC_OVERRIDE | |
837 { | |
838 DatabasePluginMessages::TransactionRequest request; | |
839 request.mutable_lookup_parent()->set_id(resourceId); | |
840 | |
841 DatabasePluginMessages::TransactionResponse response; | |
842 ExecuteTransaction(response, DatabasePluginMessages::OPERATION_LOOKUP_PARENT, request); | |
843 | |
844 if (response.lookup_parent().found()) | |
845 { | |
846 parentId = response.lookup_parent().parent(); | |
847 return true; | |
848 } | |
849 else | |
850 { | |
851 return false; | |
852 } | |
853 } | |
854 | |
855 | |
856 virtual bool LookupResource(int64_t& id, | |
857 ResourceType& type, | |
858 const std::string& publicId) ORTHANC_OVERRIDE | |
859 { | |
860 DatabasePluginMessages::TransactionRequest request; | |
861 request.mutable_lookup_resource()->set_public_id(publicId); | |
862 | |
863 DatabasePluginMessages::TransactionResponse response; | |
864 ExecuteTransaction(response, DatabasePluginMessages::OPERATION_LOOKUP_RESOURCE, request); | |
865 | |
866 if (response.lookup_resource().found()) | |
867 { | |
868 id = response.lookup_resource().internal_id(); | |
869 type = Convert(response.lookup_resource().type()); | |
870 return true; | |
871 } | |
872 else | |
873 { | |
874 return false; | |
875 } | |
876 } | |
877 | |
878 | |
879 virtual bool SelectPatientToRecycle(int64_t& internalId) ORTHANC_OVERRIDE | |
880 { | |
881 DatabasePluginMessages::TransactionResponse response; | |
882 ExecuteTransaction(response, DatabasePluginMessages::OPERATION_SELECT_PATIENT_TO_RECYCLE); | |
883 | |
884 if (response.select_patient_to_recycle().found()) | |
885 { | |
886 internalId = response.select_patient_to_recycle().patient_id(); | |
887 return true; | |
888 } | |
889 else | |
890 { | |
891 return false; | |
892 } | |
893 } | |
894 | |
895 | |
896 virtual bool SelectPatientToRecycle(int64_t& internalId, | |
897 int64_t patientIdToAvoid) ORTHANC_OVERRIDE | |
898 { | |
899 DatabasePluginMessages::TransactionRequest request; | |
900 request.mutable_select_patient_to_recycle_with_avoid()->set_patient_id_to_avoid(patientIdToAvoid); | |
901 | |
902 DatabasePluginMessages::TransactionResponse response; | |
903 ExecuteTransaction(response, DatabasePluginMessages::OPERATION_SELECT_PATIENT_TO_RECYCLE_WITH_AVOID, request); | |
904 | |
905 if (response.select_patient_to_recycle_with_avoid().found()) | |
906 { | |
907 internalId = response.select_patient_to_recycle_with_avoid().patient_id(); | |
908 return true; | |
909 } | |
910 else | |
911 { | |
912 return false; | |
913 } | |
914 } | |
915 | |
916 | |
917 virtual void SetGlobalProperty(GlobalProperty property, | |
918 bool shared, | |
919 const std::string& value) ORTHANC_OVERRIDE | |
920 { | |
921 DatabasePluginMessages::TransactionRequest request; | |
922 request.mutable_set_global_property()->set_server_id(shared ? "" : database_.GetServerIdentifier()); | |
923 request.mutable_set_global_property()->set_property(property); | |
924 request.mutable_set_global_property()->set_value(value); | |
925 | |
926 ExecuteTransaction(DatabasePluginMessages::OPERATION_SET_GLOBAL_PROPERTY, request); | |
927 } | |
928 | |
929 | |
930 virtual void ClearMainDicomTags(int64_t id) ORTHANC_OVERRIDE | |
931 { | |
932 DatabasePluginMessages::TransactionRequest request; | |
933 request.mutable_clear_main_dicom_tags()->set_id(id); | |
934 | |
935 ExecuteTransaction(DatabasePluginMessages::OPERATION_CLEAR_MAIN_DICOM_TAGS, request); | |
936 } | |
937 | |
938 | |
939 virtual void SetMetadata(int64_t id, | |
940 MetadataType type, | |
941 const std::string& value, | |
942 int64_t revision) ORTHANC_OVERRIDE | |
943 { | |
944 DatabasePluginMessages::TransactionRequest request; | |
945 request.mutable_set_metadata()->set_id(id); | |
946 request.mutable_set_metadata()->set_metadata_type(type); | |
947 request.mutable_set_metadata()->set_value(value); | |
948 request.mutable_set_metadata()->set_revision(revision); | |
949 | |
950 ExecuteTransaction(DatabasePluginMessages::OPERATION_SET_METADATA, request); | |
951 } | |
952 | |
953 | |
954 virtual void SetProtectedPatient(int64_t internalId, | |
955 bool isProtected) ORTHANC_OVERRIDE | |
956 { | |
957 DatabasePluginMessages::TransactionRequest request; | |
958 request.mutable_set_protected_patient()->set_patient_id(internalId); | |
959 request.mutable_set_protected_patient()->set_protected_patient(isProtected); | |
960 | |
961 ExecuteTransaction(DatabasePluginMessages::OPERATION_SET_PROTECTED_PATIENT, request); | |
962 } | |
963 | |
964 | |
965 virtual bool IsDiskSizeAbove(uint64_t threshold) ORTHANC_OVERRIDE | |
966 { | |
967 DatabasePluginMessages::TransactionRequest request; | |
968 request.mutable_is_disk_size_above()->set_threshold(threshold); | |
969 | |
970 DatabasePluginMessages::TransactionResponse response; | |
971 ExecuteTransaction(response, DatabasePluginMessages::OPERATION_IS_DISK_SIZE_ABOVE, request); | |
972 | |
973 return response.is_disk_size_above().result(); | |
974 } | |
975 | |
976 | |
977 virtual void ApplyLookupResources(std::list<std::string>& resourcesId, | |
978 std::list<std::string>* instancesId, // Can be NULL if not needed | |
979 const DatabaseConstraints& lookup, | |
980 ResourceType queryLevel, | |
981 const std::set<std::string>& labels, | |
982 LabelsConstraint labelsConstraint, | |
983 uint32_t limit) ORTHANC_OVERRIDE | |
984 { | |
985 if (!database_.GetDatabaseCapabilities().HasLabelsSupport() && | |
986 !labels.empty()) | |
987 { | |
988 throw OrthancException(ErrorCode_InternalError); | |
989 } | |
990 | |
991 DatabasePluginMessages::TransactionRequest request; | |
992 request.mutable_lookup_resources()->set_query_level(Convert(queryLevel)); | |
993 request.mutable_lookup_resources()->set_limit(limit); | |
994 request.mutable_lookup_resources()->set_retrieve_instances_ids(instancesId != NULL); | |
995 | |
996 request.mutable_lookup_resources()->mutable_lookup()->Reserve(lookup.GetSize()); | |
997 | |
998 for (size_t i = 0; i < lookup.GetSize(); i++) | |
999 { | |
1000 const DatabaseConstraint& source = lookup.GetConstraint(i); | |
1001 | |
1002 DatabasePluginMessages::DatabaseConstraint* target = request.mutable_lookup_resources()->add_lookup(); | |
1003 target->set_level(Convert(source.GetLevel())); | |
1004 target->set_tag_group(source.GetTag().GetGroup()); | |
1005 target->set_tag_element(source.GetTag().GetElement()); | |
1006 target->set_is_identifier_tag(source.IsIdentifier()); | |
1007 target->set_is_case_sensitive(source.IsCaseSensitive()); | |
1008 target->set_is_mandatory(source.IsMandatory()); | |
1009 | |
1010 target->mutable_values()->Reserve(source.GetValuesCount()); | |
1011 for (size_t j = 0; j < source.GetValuesCount(); j++) | |
1012 { | |
1013 target->add_values(source.GetValue(j)); | |
1014 } | |
1015 | |
1016 switch (source.GetConstraintType()) | |
1017 { | |
1018 case ConstraintType_Equal: | |
1019 target->set_type(DatabasePluginMessages::CONSTRAINT_EQUAL); | |
1020 break; | |
1021 | |
1022 case ConstraintType_SmallerOrEqual: | |
1023 target->set_type(DatabasePluginMessages::CONSTRAINT_SMALLER_OR_EQUAL); | |
1024 break; | |
1025 | |
1026 case ConstraintType_GreaterOrEqual: | |
1027 target->set_type(DatabasePluginMessages::CONSTRAINT_GREATER_OR_EQUAL); | |
1028 break; | |
1029 | |
1030 case ConstraintType_Wildcard: | |
1031 target->set_type(DatabasePluginMessages::CONSTRAINT_WILDCARD); | |
1032 break; | |
1033 | |
1034 case ConstraintType_List: | |
1035 target->set_type(DatabasePluginMessages::CONSTRAINT_LIST); | |
1036 break; | |
1037 | |
1038 default: | |
1039 throw OrthancException(ErrorCode_ParameterOutOfRange); | |
1040 } | |
1041 } | |
1042 | |
1043 for (std::set<std::string>::const_iterator it = labels.begin(); it != labels.end(); ++it) | |
1044 { | |
1045 request.mutable_lookup_resources()->add_labels(*it); | |
1046 } | |
1047 | |
1048 switch (labelsConstraint) | |
1049 { | |
1050 case LabelsConstraint_All: | |
1051 request.mutable_lookup_resources()->set_labels_constraint(DatabasePluginMessages::LABELS_CONSTRAINT_ALL); | |
1052 break; | |
1053 | |
1054 case LabelsConstraint_Any: | |
1055 request.mutable_lookup_resources()->set_labels_constraint(DatabasePluginMessages::LABELS_CONSTRAINT_ANY); | |
1056 break; | |
1057 | |
1058 case LabelsConstraint_None: | |
1059 request.mutable_lookup_resources()->set_labels_constraint(DatabasePluginMessages::LABELS_CONSTRAINT_NONE); | |
1060 break; | |
1061 | |
1062 default: | |
1063 throw OrthancException(ErrorCode_ParameterOutOfRange); | |
1064 } | |
1065 | |
1066 DatabasePluginMessages::TransactionResponse response; | |
1067 ExecuteTransaction(response, DatabasePluginMessages::OPERATION_LOOKUP_RESOURCES, request); | |
1068 | |
1069 for (int i = 0; i < response.lookup_resources().resources_ids().size(); i++) | |
1070 { | |
1071 resourcesId.push_back(response.lookup_resources().resources_ids(i)); | |
1072 } | |
1073 | |
1074 if (instancesId != NULL) | |
1075 { | |
1076 if (response.lookup_resources().resources_ids().size() != response.lookup_resources().instances_ids().size()) | |
98 { | 1077 { |
99 throw OrthancException(ErrorCode_DatabasePlugin); | 1078 throw OrthancException(ErrorCode_DatabasePlugin); |
100 } | 1079 } |
101 else | 1080 else |
102 { | 1081 { |
103 target.push_back(value); | 1082 for (int i = 0; i < response.lookup_resources().instances_ids().size(); i++) |
104 } | |
105 } | |
106 } | |
107 | |
108 | |
109 bool ReadSingleStringAnswer(std::string& target) | |
110 { | |
111 uint32_t count; | |
112 CheckSuccess(that_.backend_.readAnswersCount(transaction_, &count)); | |
113 | |
114 if (count == 0) | |
115 { | |
116 return false; | |
117 } | |
118 else if (count == 1) | |
119 { | |
120 const char* value = NULL; | |
121 CheckSuccess(that_.backend_.readAnswerString(transaction_, &value, 0)); | |
122 if (value == NULL) | |
123 { | |
124 throw OrthancException(ErrorCode_DatabasePlugin); | |
125 } | |
126 else | |
127 { | |
128 target.assign(value); | |
129 return true; | |
130 } | |
131 } | |
132 else | |
133 { | |
134 throw OrthancException(ErrorCode_DatabasePlugin); | |
135 } | |
136 } | |
137 | |
138 | |
139 bool ReadSingleInt64Answer(int64_t& target) | |
140 { | |
141 uint32_t count; | |
142 CheckSuccess(that_.backend_.readAnswersCount(transaction_, &count)); | |
143 | |
144 if (count == 0) | |
145 { | |
146 return false; | |
147 } | |
148 else if (count == 1) | |
149 { | |
150 CheckSuccess(that_.backend_.readAnswerInt64(transaction_, &target, 0)); | |
151 return true; | |
152 } | |
153 else | |
154 { | |
155 throw OrthancException(ErrorCode_DatabasePlugin); | |
156 } | |
157 } | |
158 | |
159 | |
160 ExportedResource ReadAnswerExportedResource(uint32_t answerIndex) | |
161 { | |
162 OrthancPluginExportedResource exported; | |
163 CheckSuccess(that_.backend_.readAnswerExportedResource(transaction_, &exported, answerIndex)); | |
164 | |
165 if (exported.publicId == NULL || | |
166 exported.modality == NULL || | |
167 exported.date == NULL || | |
168 exported.patientId == NULL || | |
169 exported.studyInstanceUid == NULL || | |
170 exported.seriesInstanceUid == NULL || | |
171 exported.sopInstanceUid == NULL) | |
172 { | |
173 throw OrthancException(ErrorCode_DatabasePlugin); | |
174 } | |
175 else | |
176 { | |
177 return ExportedResource(exported.seq, | |
178 Plugins::Convert(exported.resourceType), | |
179 exported.publicId, | |
180 exported.modality, | |
181 exported.date, | |
182 exported.patientId, | |
183 exported.studyInstanceUid, | |
184 exported.seriesInstanceUid, | |
185 exported.sopInstanceUid); | |
186 } | |
187 } | |
188 | |
189 | |
190 ServerIndexChange ReadAnswerChange(uint32_t answerIndex) | |
191 { | |
192 OrthancPluginChange change; | |
193 CheckSuccess(that_.backend_.readAnswerChange(transaction_, &change, answerIndex)); | |
194 | |
195 if (change.publicId == NULL || | |
196 change.date == NULL) | |
197 { | |
198 throw OrthancException(ErrorCode_DatabasePlugin); | |
199 } | |
200 else | |
201 { | |
202 return ServerIndexChange(change.seq, | |
203 static_cast<ChangeType>(change.changeType), | |
204 Plugins::Convert(change.resourceType), | |
205 change.publicId, | |
206 change.date); | |
207 } | |
208 } | |
209 | |
210 | |
211 void CheckNoEvent() | |
212 { | |
213 uint32_t count; | |
214 CheckSuccess(that_.backend_.readEventsCount(transaction_, &count)); | |
215 if (count != 0) | |
216 { | |
217 throw OrthancException(ErrorCode_DatabasePlugin); | |
218 } | |
219 } | |
220 | |
221 | |
222 void ProcessEvents(bool isDeletingAttachment) | |
223 { | |
224 uint32_t count; | |
225 CheckSuccess(that_.backend_.readEventsCount(transaction_, &count)); | |
226 | |
227 for (uint32_t i = 0; i < count; i++) | |
228 { | |
229 OrthancPluginDatabaseEvent2 event; | |
230 CheckSuccess(that_.backend_.readEvent2(transaction_, &event, i)); | |
231 | |
232 switch (event.type) | |
233 { | |
234 case OrthancPluginDatabaseEventType_DeletedAttachment: | |
235 listener_.SignalAttachmentDeleted(Convert(event.content.attachment)); | |
236 break; | |
237 | |
238 case OrthancPluginDatabaseEventType_DeletedResource: | |
239 if (isDeletingAttachment) | |
240 { | |
241 // This event should only be triggered by "DeleteResource()" | |
242 throw OrthancException(ErrorCode_DatabasePlugin); | |
243 } | |
244 else | |
245 { | |
246 listener_.SignalResourceDeleted(Plugins::Convert(event.content.resource.level), event.content.resource.publicId); | |
247 } | |
248 break; | |
249 | |
250 case OrthancPluginDatabaseEventType_RemainingAncestor: | |
251 if (isDeletingAttachment) | |
252 { | |
253 // This event should only triggered by "DeleteResource()" | |
254 throw OrthancException(ErrorCode_DatabasePlugin); | |
255 } | |
256 else | |
257 { | |
258 listener_.SignalRemainingAncestor(Plugins::Convert(event.content.resource.level), event.content.resource.publicId); | |
259 } | |
260 break; | |
261 | |
262 default: | |
263 break; // Unhandled event | |
264 } | |
265 } | |
266 } | |
267 | |
268 | |
269 public: | |
270 Transaction(OrthancPluginDatabaseV4& that, | |
271 IDatabaseListener& listener, | |
272 OrthancPluginDatabaseTransactionType type) : | |
273 that_(that), | |
274 listener_(listener) | |
275 { | |
276 CheckSuccess(that.backend_.startTransaction(that.database_, &transaction_, type)); | |
277 if (transaction_ == NULL) | |
278 { | |
279 throw OrthancException(ErrorCode_DatabasePlugin); | |
280 } | |
281 } | |
282 | |
283 | |
284 virtual ~Transaction() | |
285 { | |
286 OrthancPluginErrorCode code = that_.backend_.destructTransaction(transaction_); | |
287 if (code != OrthancPluginErrorCode_Success) | |
288 { | |
289 // Don't throw exception in destructors | |
290 that_.errorDictionary_.LogError(code, true); | |
291 } | |
292 } | |
293 | |
294 | |
295 virtual void Rollback() ORTHANC_OVERRIDE | |
296 { | |
297 CheckSuccess(that_.backend_.rollback(transaction_)); | |
298 CheckNoEvent(); | |
299 } | |
300 | |
301 | |
302 virtual void Commit(int64_t fileSizeDelta) ORTHANC_OVERRIDE | |
303 { | |
304 CheckSuccess(that_.backend_.commit(transaction_, fileSizeDelta)); | |
305 CheckNoEvent(); | |
306 } | |
307 | |
308 | |
309 virtual void AddAttachment(int64_t id, | |
310 const FileInfo& attachment, | |
311 int64_t revision) ORTHANC_OVERRIDE | |
312 { | |
313 OrthancPluginAttachment2 tmp; | |
314 tmp.uuid = attachment.GetUuid().c_str(); | |
315 tmp.contentType = static_cast<int32_t>(attachment.GetContentType()); | |
316 tmp.uncompressedSize = attachment.GetUncompressedSize(); | |
317 tmp.uncompressedHash = attachment.GetUncompressedMD5().c_str(); | |
318 tmp.compressionType = static_cast<int32_t>(attachment.GetCompressionType()); | |
319 tmp.compressedSize = attachment.GetCompressedSize(); | |
320 tmp.compressedHash = attachment.GetCompressedMD5().c_str(); | |
321 tmp.customData = attachment.GetCustomData().c_str(); | |
322 | |
323 CheckSuccess(that_.backend_.addAttachment2(transaction_, id, &tmp, revision)); | |
324 CheckNoEvent(); | |
325 } | |
326 | |
327 | |
328 virtual void ClearChanges() ORTHANC_OVERRIDE | |
329 { | |
330 CheckSuccess(that_.backend_.clearChanges(transaction_)); | |
331 CheckNoEvent(); | |
332 } | |
333 | |
334 | |
335 virtual void ClearExportedResources() ORTHANC_OVERRIDE | |
336 { | |
337 CheckSuccess(that_.backend_.clearExportedResources(transaction_)); | |
338 CheckNoEvent(); | |
339 } | |
340 | |
341 | |
342 virtual void DeleteAttachment(int64_t id, | |
343 FileContentType attachment) ORTHANC_OVERRIDE | |
344 { | |
345 CheckSuccess(that_.backend_.deleteAttachment(transaction_, id, static_cast<int32_t>(attachment))); | |
346 ProcessEvents(true); | |
347 } | |
348 | |
349 | |
350 virtual void DeleteMetadata(int64_t id, | |
351 MetadataType type) ORTHANC_OVERRIDE | |
352 { | |
353 CheckSuccess(that_.backend_.deleteMetadata(transaction_, id, static_cast<int32_t>(type))); | |
354 CheckNoEvent(); | |
355 } | |
356 | |
357 | |
358 virtual void DeleteResource(int64_t id) ORTHANC_OVERRIDE | |
359 { | |
360 CheckSuccess(that_.backend_.deleteResource(transaction_, id)); | |
361 ProcessEvents(false); | |
362 } | |
363 | |
364 | |
365 virtual void GetAllMetadata(std::map<MetadataType, std::string>& target, | |
366 int64_t id) ORTHANC_OVERRIDE | |
367 { | |
368 CheckSuccess(that_.backend_.getAllMetadata(transaction_, id)); | |
369 CheckNoEvent(); | |
370 | |
371 uint32_t count; | |
372 CheckSuccess(that_.backend_.readAnswersCount(transaction_, &count)); | |
373 | |
374 target.clear(); | |
375 for (uint32_t i = 0; i < count; i++) | |
376 { | |
377 int32_t metadata; | |
378 const char* value = NULL; | |
379 CheckSuccess(that_.backend_.readAnswerMetadata(transaction_, &metadata, &value, i)); | |
380 | |
381 if (value == NULL) | |
382 { | |
383 throw OrthancException(ErrorCode_DatabasePlugin); | |
384 } | |
385 else | |
386 { | |
387 target[static_cast<MetadataType>(metadata)] = value; | |
388 } | |
389 } | |
390 } | |
391 | |
392 | |
393 virtual void GetAllPublicIds(std::list<std::string>& target, | |
394 ResourceType resourceType) ORTHANC_OVERRIDE | |
395 { | |
396 CheckSuccess(that_.backend_.getAllPublicIds(transaction_, Plugins::Convert(resourceType))); | |
397 CheckNoEvent(); | |
398 | |
399 ReadStringAnswers(target); | |
400 } | |
401 | |
402 | |
403 virtual void GetAllPublicIds(std::list<std::string>& target, | |
404 ResourceType resourceType, | |
405 size_t since, | |
406 size_t limit) ORTHANC_OVERRIDE | |
407 { | |
408 CheckSuccess(that_.backend_.getAllPublicIdsWithLimit( | |
409 transaction_, Plugins::Convert(resourceType), | |
410 static_cast<uint64_t>(since), static_cast<uint64_t>(limit))); | |
411 CheckNoEvent(); | |
412 | |
413 ReadStringAnswers(target); | |
414 } | |
415 | |
416 | |
417 virtual void GetChanges(std::list<ServerIndexChange>& target /*out*/, | |
418 bool& done /*out*/, | |
419 int64_t since, | |
420 uint32_t maxResults) ORTHANC_OVERRIDE | |
421 { | |
422 uint8_t tmpDone = true; | |
423 CheckSuccess(that_.backend_.getChanges(transaction_, &tmpDone, since, maxResults)); | |
424 CheckNoEvent(); | |
425 | |
426 done = (tmpDone != 0); | |
427 | |
428 uint32_t count; | |
429 CheckSuccess(that_.backend_.readAnswersCount(transaction_, &count)); | |
430 | |
431 target.clear(); | |
432 for (uint32_t i = 0; i < count; i++) | |
433 { | |
434 target.push_back(ReadAnswerChange(i)); | |
435 } | |
436 } | |
437 | |
438 | |
439 virtual void GetChildrenInternalId(std::list<int64_t>& target, | |
440 int64_t id) ORTHANC_OVERRIDE | |
441 { | |
442 CheckSuccess(that_.backend_.getChildrenInternalId(transaction_, id)); | |
443 CheckNoEvent(); | |
444 | |
445 uint32_t count; | |
446 CheckSuccess(that_.backend_.readAnswersCount(transaction_, &count)); | |
447 | |
448 target.clear(); | |
449 for (uint32_t i = 0; i < count; i++) | |
450 { | |
451 int64_t value; | |
452 CheckSuccess(that_.backend_.readAnswerInt64(transaction_, &value, i)); | |
453 target.push_back(value); | |
454 } | |
455 } | |
456 | |
457 | |
458 virtual void GetChildrenPublicId(std::list<std::string>& target, | |
459 int64_t id) ORTHANC_OVERRIDE | |
460 { | |
461 CheckSuccess(that_.backend_.getChildrenPublicId(transaction_, id)); | |
462 CheckNoEvent(); | |
463 | |
464 ReadStringAnswers(target); | |
465 } | |
466 | |
467 | |
468 virtual void GetExportedResources(std::list<ExportedResource>& target /*out*/, | |
469 bool& done /*out*/, | |
470 int64_t since, | |
471 uint32_t maxResults) ORTHANC_OVERRIDE | |
472 { | |
473 uint8_t tmpDone = true; | |
474 CheckSuccess(that_.backend_.getExportedResources(transaction_, &tmpDone, since, maxResults)); | |
475 CheckNoEvent(); | |
476 | |
477 done = (tmpDone != 0); | |
478 | |
479 uint32_t count; | |
480 CheckSuccess(that_.backend_.readAnswersCount(transaction_, &count)); | |
481 | |
482 target.clear(); | |
483 for (uint32_t i = 0; i < count; i++) | |
484 { | |
485 target.push_back(ReadAnswerExportedResource(i)); | |
486 } | |
487 } | |
488 | |
489 | |
490 virtual void GetLastChange(std::list<ServerIndexChange>& target /*out*/) ORTHANC_OVERRIDE | |
491 { | |
492 CheckSuccess(that_.backend_.getLastChange(transaction_)); | |
493 CheckNoEvent(); | |
494 | |
495 uint32_t count; | |
496 CheckSuccess(that_.backend_.readAnswersCount(transaction_, &count)); | |
497 | |
498 target.clear(); | |
499 if (count == 1) | |
500 { | |
501 target.push_back(ReadAnswerChange(0)); | |
502 } | |
503 else if (count > 1) | |
504 { | |
505 throw OrthancException(ErrorCode_DatabasePlugin); | |
506 } | |
507 } | |
508 | |
509 | |
510 virtual void GetLastExportedResource(std::list<ExportedResource>& target /*out*/) ORTHANC_OVERRIDE | |
511 { | |
512 CheckSuccess(that_.backend_.getLastExportedResource(transaction_)); | |
513 CheckNoEvent(); | |
514 | |
515 uint32_t count; | |
516 CheckSuccess(that_.backend_.readAnswersCount(transaction_, &count)); | |
517 | |
518 target.clear(); | |
519 if (count == 1) | |
520 { | |
521 target.push_back(ReadAnswerExportedResource(0)); | |
522 } | |
523 else if (count > 1) | |
524 { | |
525 throw OrthancException(ErrorCode_DatabasePlugin); | |
526 } | |
527 } | |
528 | |
529 | |
530 virtual void GetMainDicomTags(DicomMap& target, | |
531 int64_t id) ORTHANC_OVERRIDE | |
532 { | |
533 CheckSuccess(that_.backend_.getMainDicomTags(transaction_, id)); | |
534 CheckNoEvent(); | |
535 | |
536 uint32_t count; | |
537 CheckSuccess(that_.backend_.readAnswersCount(transaction_, &count)); | |
538 | |
539 target.Clear(); | |
540 for (uint32_t i = 0; i < count; i++) | |
541 { | |
542 uint16_t group, element; | |
543 const char* value = NULL; | |
544 CheckSuccess(that_.backend_.readAnswerDicomTag(transaction_, &group, &element, &value, i)); | |
545 | |
546 if (value == NULL) | |
547 { | |
548 throw OrthancException(ErrorCode_DatabasePlugin); | |
549 } | |
550 else | |
551 { | |
552 target.SetValue(group, element, std::string(value), false); | |
553 } | |
554 } | |
555 } | |
556 | |
557 | |
558 virtual std::string GetPublicId(int64_t resourceId) ORTHANC_OVERRIDE | |
559 { | |
560 CheckSuccess(that_.backend_.getPublicId(transaction_, resourceId)); | |
561 CheckNoEvent(); | |
562 | |
563 std::string s; | |
564 if (ReadSingleStringAnswer(s)) | |
565 { | |
566 return s; | |
567 } | |
568 else | |
569 { | |
570 throw OrthancException(ErrorCode_InexistentItem); | |
571 } | |
572 } | |
573 | |
574 | |
575 virtual uint64_t GetResourcesCount(ResourceType resourceType) ORTHANC_OVERRIDE | |
576 { | |
577 uint64_t value; | |
578 CheckSuccess(that_.backend_.getResourcesCount(transaction_, &value, Plugins::Convert(resourceType))); | |
579 CheckNoEvent(); | |
580 return value; | |
581 } | |
582 | |
583 | |
584 virtual ResourceType GetResourceType(int64_t resourceId) ORTHANC_OVERRIDE | |
585 { | |
586 OrthancPluginResourceType type; | |
587 CheckSuccess(that_.backend_.getResourceType(transaction_, &type, resourceId)); | |
588 CheckNoEvent(); | |
589 return Plugins::Convert(type); | |
590 } | |
591 | |
592 | |
593 virtual uint64_t GetTotalCompressedSize() ORTHANC_OVERRIDE | |
594 { | |
595 uint64_t s; | |
596 CheckSuccess(that_.backend_.getTotalCompressedSize(transaction_, &s)); | |
597 CheckNoEvent(); | |
598 return s; | |
599 } | |
600 | |
601 | |
602 virtual uint64_t GetTotalUncompressedSize() ORTHANC_OVERRIDE | |
603 { | |
604 uint64_t s; | |
605 CheckSuccess(that_.backend_.getTotalUncompressedSize(transaction_, &s)); | |
606 CheckNoEvent(); | |
607 return s; | |
608 } | |
609 | |
610 | |
611 virtual bool IsExistingResource(int64_t internalId) ORTHANC_OVERRIDE | |
612 { | |
613 uint8_t b; | |
614 CheckSuccess(that_.backend_.isExistingResource(transaction_, &b, internalId)); | |
615 CheckNoEvent(); | |
616 return (b != 0); | |
617 } | |
618 | |
619 | |
620 virtual bool IsProtectedPatient(int64_t internalId) ORTHANC_OVERRIDE | |
621 { | |
622 uint8_t b; | |
623 CheckSuccess(that_.backend_.isProtectedPatient(transaction_, &b, internalId)); | |
624 CheckNoEvent(); | |
625 return (b != 0); | |
626 } | |
627 | |
628 | |
629 virtual void ListAvailableAttachments(std::set<FileContentType>& target, | |
630 int64_t id) ORTHANC_OVERRIDE | |
631 { | |
632 CheckSuccess(that_.backend_.listAvailableAttachments(transaction_, id)); | |
633 CheckNoEvent(); | |
634 | |
635 uint32_t count; | |
636 CheckSuccess(that_.backend_.readAnswersCount(transaction_, &count)); | |
637 | |
638 target.clear(); | |
639 for (uint32_t i = 0; i < count; i++) | |
640 { | |
641 int32_t value; | |
642 CheckSuccess(that_.backend_.readAnswerInt32(transaction_, &value, i)); | |
643 target.insert(static_cast<FileContentType>(value)); | |
644 } | |
645 } | |
646 | |
647 | |
648 virtual void LogChange(int64_t internalId, | |
649 const ServerIndexChange& change) ORTHANC_OVERRIDE | |
650 { | |
651 CheckSuccess(that_.backend_.logChange(transaction_, static_cast<int32_t>(change.GetChangeType()), | |
652 internalId, Plugins::Convert(change.GetResourceType()), | |
653 change.GetDate().c_str())); | |
654 CheckNoEvent(); | |
655 } | |
656 | |
657 | |
658 virtual void LogExportedResource(const ExportedResource& resource) ORTHANC_OVERRIDE | |
659 { | |
660 CheckSuccess(that_.backend_.logExportedResource(transaction_, Plugins::Convert(resource.GetResourceType()), | |
661 resource.GetPublicId().c_str(), | |
662 resource.GetModality().c_str(), | |
663 resource.GetDate().c_str(), | |
664 resource.GetPatientId().c_str(), | |
665 resource.GetStudyInstanceUid().c_str(), | |
666 resource.GetSeriesInstanceUid().c_str(), | |
667 resource.GetSopInstanceUid().c_str())); | |
668 CheckNoEvent(); | |
669 } | |
670 | |
671 | |
672 virtual bool LookupAttachment(FileInfo& attachment, | |
673 int64_t& revision, | |
674 int64_t id, | |
675 FileContentType contentType) ORTHANC_OVERRIDE | |
676 { | |
677 CheckSuccess(that_.backend_.lookupAttachment(transaction_, &revision, id, static_cast<int32_t>(contentType))); | |
678 CheckNoEvent(); | |
679 | |
680 uint32_t count; | |
681 CheckSuccess(that_.backend_.readAnswersCount(transaction_, &count)); | |
682 | |
683 if (count == 0) | |
684 { | |
685 return false; | |
686 } | |
687 else if (count == 1) | |
688 { | |
689 OrthancPluginAttachment2 tmp; | |
690 CheckSuccess(that_.backend_.readAnswerAttachment2(transaction_, &tmp, 0)); | |
691 attachment = Convert(tmp); | |
692 return true; | |
693 } | |
694 else | |
695 { | |
696 throw OrthancException(ErrorCode_DatabasePlugin); | |
697 } | |
698 } | |
699 | |
700 | |
701 virtual bool LookupGlobalProperty(std::string& target, | |
702 GlobalProperty property, | |
703 bool shared) ORTHANC_OVERRIDE | |
704 { | |
705 const char* id = (shared ? "" : that_.serverIdentifier_.c_str()); | |
706 | |
707 CheckSuccess(that_.backend_.lookupGlobalProperty(transaction_, id, static_cast<int32_t>(property))); | |
708 CheckNoEvent(); | |
709 return ReadSingleStringAnswer(target); | |
710 } | |
711 | |
712 | |
713 virtual bool LookupMetadata(std::string& target, | |
714 int64_t& revision, | |
715 int64_t id, | |
716 MetadataType type) ORTHANC_OVERRIDE | |
717 { | |
718 CheckSuccess(that_.backend_.lookupMetadata(transaction_, &revision, id, static_cast<int32_t>(type))); | |
719 CheckNoEvent(); | |
720 return ReadSingleStringAnswer(target); | |
721 } | |
722 | |
723 | |
724 virtual bool LookupParent(int64_t& parentId, | |
725 int64_t resourceId) ORTHANC_OVERRIDE | |
726 { | |
727 uint8_t existing; | |
728 CheckSuccess(that_.backend_.lookupParent(transaction_, &existing, &parentId, resourceId)); | |
729 CheckNoEvent(); | |
730 return (existing != 0); | |
731 } | |
732 | |
733 | |
734 virtual bool LookupResource(int64_t& id, | |
735 ResourceType& type, | |
736 const std::string& publicId) ORTHANC_OVERRIDE | |
737 { | |
738 uint8_t existing; | |
739 OrthancPluginResourceType t; | |
740 CheckSuccess(that_.backend_.lookupResource(transaction_, &existing, &id, &t, publicId.c_str())); | |
741 CheckNoEvent(); | |
742 | |
743 if (existing == 0) | |
744 { | |
745 return false; | |
746 } | |
747 else | |
748 { | |
749 type = Plugins::Convert(t); | |
750 return true; | |
751 } | |
752 } | |
753 | |
754 | |
755 virtual bool SelectPatientToRecycle(int64_t& internalId) ORTHANC_OVERRIDE | |
756 { | |
757 uint8_t available; | |
758 CheckSuccess(that_.backend_.selectPatientToRecycle(transaction_, &available, &internalId)); | |
759 CheckNoEvent(); | |
760 return (available != 0); | |
761 } | |
762 | |
763 | |
764 virtual bool SelectPatientToRecycle(int64_t& internalId, | |
765 int64_t patientIdToAvoid) ORTHANC_OVERRIDE | |
766 { | |
767 uint8_t available; | |
768 CheckSuccess(that_.backend_.selectPatientToRecycle2(transaction_, &available, &internalId, patientIdToAvoid)); | |
769 CheckNoEvent(); | |
770 return (available != 0); | |
771 } | |
772 | |
773 | |
774 virtual void SetGlobalProperty(GlobalProperty property, | |
775 bool shared, | |
776 const std::string& value) ORTHANC_OVERRIDE | |
777 { | |
778 const char* id = (shared ? "" : that_.serverIdentifier_.c_str()); | |
779 | |
780 CheckSuccess(that_.backend_.setGlobalProperty(transaction_, id, static_cast<int32_t>(property), value.c_str())); | |
781 CheckNoEvent(); | |
782 } | |
783 | |
784 | |
785 virtual void ClearMainDicomTags(int64_t id) ORTHANC_OVERRIDE | |
786 { | |
787 CheckSuccess(that_.backend_.clearMainDicomTags(transaction_, id)); | |
788 CheckNoEvent(); | |
789 } | |
790 | |
791 | |
792 virtual void SetMetadata(int64_t id, | |
793 MetadataType type, | |
794 const std::string& value, | |
795 int64_t revision) ORTHANC_OVERRIDE | |
796 { | |
797 CheckSuccess(that_.backend_.setMetadata(transaction_, id, static_cast<int32_t>(type), value.c_str(), revision)); | |
798 CheckNoEvent(); | |
799 } | |
800 | |
801 | |
802 virtual void SetProtectedPatient(int64_t internalId, | |
803 bool isProtected) ORTHANC_OVERRIDE | |
804 { | |
805 CheckSuccess(that_.backend_.setProtectedPatient(transaction_, internalId, (isProtected ? 1 : 0))); | |
806 CheckNoEvent(); | |
807 } | |
808 | |
809 | |
810 virtual bool IsDiskSizeAbove(uint64_t threshold) ORTHANC_OVERRIDE | |
811 { | |
812 uint8_t tmp; | |
813 CheckSuccess(that_.backend_.isDiskSizeAbove(transaction_, &tmp, threshold)); | |
814 CheckNoEvent(); | |
815 return (tmp != 0); | |
816 } | |
817 | |
818 | |
819 virtual void ApplyLookupResources(std::list<std::string>& resourcesId, | |
820 std::list<std::string>* instancesId, // Can be NULL if not needed | |
821 const std::vector<DatabaseConstraint>& lookup, | |
822 ResourceType queryLevel, | |
823 size_t limit) ORTHANC_OVERRIDE | |
824 { | |
825 std::vector<OrthancPluginDatabaseConstraint> constraints; | |
826 std::vector< std::vector<const char*> > constraintsValues; | |
827 | |
828 constraints.resize(lookup.size()); | |
829 constraintsValues.resize(lookup.size()); | |
830 | |
831 for (size_t i = 0; i < lookup.size(); i++) | |
832 { | |
833 lookup[i].EncodeForPlugins(constraints[i], constraintsValues[i]); | |
834 } | |
835 | |
836 CheckSuccess(that_.backend_.lookupResources(transaction_, lookup.size(), | |
837 (lookup.empty() ? NULL : &constraints[0]), | |
838 Plugins::Convert(queryLevel), | |
839 limit, (instancesId == NULL ? 0 : 1))); | |
840 CheckNoEvent(); | |
841 | |
842 uint32_t count; | |
843 CheckSuccess(that_.backend_.readAnswersCount(transaction_, &count)); | |
844 | |
845 resourcesId.clear(); | |
846 | |
847 if (instancesId != NULL) | |
848 { | |
849 instancesId->clear(); | |
850 } | |
851 | |
852 for (uint32_t i = 0; i < count; i++) | |
853 { | |
854 OrthancPluginMatchingResource resource; | |
855 CheckSuccess(that_.backend_.readAnswerMatchingResource(transaction_, &resource, i)); | |
856 | |
857 if (resource.resourceId == NULL) | |
858 { | |
859 throw OrthancException(ErrorCode_DatabasePlugin); | |
860 } | |
861 | |
862 resourcesId.push_back(resource.resourceId); | |
863 | |
864 if (instancesId != NULL) | |
865 { | |
866 if (resource.someInstanceId == NULL) | |
867 { | 1083 { |
868 throw OrthancException(ErrorCode_DatabasePlugin); | 1084 instancesId->push_back(response.lookup_resources().instances_ids(i)); |
869 } | |
870 else | |
871 { | |
872 instancesId->push_back(resource.someInstanceId); | |
873 } | 1085 } |
874 } | 1086 } |
875 } | 1087 } |
876 } | 1088 } |
877 | 1089 |
881 const std::string& patient, | 1093 const std::string& patient, |
882 const std::string& study, | 1094 const std::string& study, |
883 const std::string& series, | 1095 const std::string& series, |
884 const std::string& instance) ORTHANC_OVERRIDE | 1096 const std::string& instance) ORTHANC_OVERRIDE |
885 { | 1097 { |
886 OrthancPluginCreateInstanceResult output; | 1098 // TODO: "CreateInstanceResult" => constructor and getters |
887 memset(&output, 0, sizeof(output)); | |
888 | |
889 CheckSuccess(that_.backend_.createInstance(transaction_, &output, patient.c_str(), | |
890 study.c_str(), series.c_str(), instance.c_str())); | |
891 CheckNoEvent(); | |
892 | |
893 instanceId = output.instanceId; | |
894 | 1099 |
895 if (output.isNewInstance) | 1100 DatabasePluginMessages::TransactionRequest request; |
896 { | 1101 request.mutable_create_instance()->set_patient(patient); |
897 result.isNewPatient_ = output.isNewPatient; | 1102 request.mutable_create_instance()->set_study(study); |
898 result.isNewStudy_ = output.isNewStudy; | 1103 request.mutable_create_instance()->set_series(series); |
899 result.isNewSeries_ = output.isNewSeries; | 1104 request.mutable_create_instance()->set_instance(instance); |
900 result.patientId_ = output.patientId; | 1105 |
901 result.studyId_ = output.studyId; | 1106 DatabasePluginMessages::TransactionResponse response; |
902 result.seriesId_ = output.seriesId; | 1107 ExecuteTransaction(response, DatabasePluginMessages::OPERATION_CREATE_INSTANCE, request); |
1108 | |
1109 instanceId = response.create_instance().instance_id(); | |
1110 | |
1111 if (response.create_instance().is_new_instance()) | |
1112 { | |
1113 result.isNewPatient_ = response.create_instance().is_new_patient(); | |
1114 result.isNewStudy_ = response.create_instance().is_new_study(); | |
1115 result.isNewSeries_ = response.create_instance().is_new_series(); | |
1116 result.patientId_ = response.create_instance().patient_id(); | |
1117 result.studyId_ = response.create_instance().study_id(); | |
1118 result.seriesId_ = response.create_instance().series_id(); | |
903 return true; | 1119 return true; |
904 } | 1120 } |
905 else | 1121 else |
906 { | 1122 { |
907 return false; | 1123 return false; |
908 } | 1124 } |
909 | |
910 } | 1125 } |
911 | 1126 |
912 | 1127 |
913 virtual void SetResourcesContent(const ResourcesContent& content) ORTHANC_OVERRIDE | 1128 virtual void SetResourcesContent(const ResourcesContent& content) ORTHANC_OVERRIDE |
914 { | 1129 { |
915 std::vector<OrthancPluginResourcesContentTags> identifierTags; | 1130 DatabasePluginMessages::TransactionRequest request; |
916 std::vector<OrthancPluginResourcesContentTags> mainDicomTags; | 1131 |
917 std::vector<OrthancPluginResourcesContentMetadata> metadata; | 1132 request.mutable_set_resources_content()->mutable_tags()->Reserve(content.GetListTags().size()); |
918 | 1133 for (ResourcesContent::ListTags::const_iterator it = content.GetListTags().begin(); it != content.GetListTags().end(); ++it) |
919 identifierTags.reserve(content.GetListTags().size()); | 1134 { |
920 mainDicomTags.reserve(content.GetListTags().size()); | 1135 DatabasePluginMessages::SetResourcesContent_Request_Tag* tag = request.mutable_set_resources_content()->add_tags(); |
921 metadata.reserve(content.GetListMetadata().size()); | 1136 tag->set_resource_id(it->GetResourceId()); |
922 | 1137 tag->set_is_identifier(it->IsIdentifier()); |
923 for (ResourcesContent::ListTags::const_iterator | 1138 tag->set_group(it->GetTag().GetGroup()); |
924 it = content.GetListTags().begin(); it != content.GetListTags().end(); ++it) | 1139 tag->set_element(it->GetTag().GetElement()); |
925 { | 1140 tag->set_value(it->GetValue()); |
926 OrthancPluginResourcesContentTags tmp; | 1141 } |
927 tmp.resource = it->resourceId_; | 1142 |
928 tmp.group = it->tag_.GetGroup(); | 1143 request.mutable_set_resources_content()->mutable_metadata()->Reserve(content.GetListMetadata().size()); |
929 tmp.element = it->tag_.GetElement(); | 1144 for (ResourcesContent::ListMetadata::const_iterator it = content.GetListMetadata().begin(); it != content.GetListMetadata().end(); ++it) |
930 tmp.value = it->value_.c_str(); | 1145 { |
931 | 1146 DatabasePluginMessages::SetResourcesContent_Request_Metadata* metadata = request.mutable_set_resources_content()->add_metadata(); |
932 if (it->isIdentifier_) | 1147 metadata->set_resource_id(it->GetResourceId()); |
933 { | 1148 metadata->set_metadata(it->GetType()); |
934 identifierTags.push_back(tmp); | 1149 metadata->set_value(it->GetValue()); |
935 } | 1150 } |
936 else | 1151 |
937 { | 1152 ExecuteTransaction(DatabasePluginMessages::OPERATION_SET_RESOURCES_CONTENT, request); |
938 mainDicomTags.push_back(tmp); | |
939 } | |
940 } | |
941 | |
942 for (ResourcesContent::ListMetadata::const_iterator | |
943 it = content.GetListMetadata().begin(); it != content.GetListMetadata().end(); ++it) | |
944 { | |
945 OrthancPluginResourcesContentMetadata tmp; | |
946 tmp.resource = it->resourceId_; | |
947 tmp.metadata = it->metadata_; | |
948 tmp.value = it->value_.c_str(); | |
949 metadata.push_back(tmp); | |
950 } | |
951 | |
952 assert(identifierTags.size() + mainDicomTags.size() == content.GetListTags().size() && | |
953 metadata.size() == content.GetListMetadata().size()); | |
954 | |
955 CheckSuccess(that_.backend_.setResourcesContent(transaction_, | |
956 identifierTags.size(), | |
957 (identifierTags.empty() ? NULL : &identifierTags[0]), | |
958 mainDicomTags.size(), | |
959 (mainDicomTags.empty() ? NULL : &mainDicomTags[0]), | |
960 metadata.size(), | |
961 (metadata.empty() ? NULL : &metadata[0]))); | |
962 CheckNoEvent(); | |
963 } | 1153 } |
964 | 1154 |
965 | 1155 |
966 virtual void GetChildrenMetadata(std::list<std::string>& target, | 1156 virtual void GetChildrenMetadata(std::list<std::string>& target, |
967 int64_t resourceId, | 1157 int64_t resourceId, |
968 MetadataType metadata) ORTHANC_OVERRIDE | 1158 MetadataType metadata) ORTHANC_OVERRIDE |
969 { | 1159 { |
970 CheckSuccess(that_.backend_.getChildrenMetadata(transaction_, resourceId, static_cast<int32_t>(metadata))); | 1160 DatabasePluginMessages::TransactionRequest request; |
971 CheckNoEvent(); | 1161 request.mutable_get_children_metadata()->set_id(resourceId); |
972 ReadStringAnswers(target); | 1162 request.mutable_get_children_metadata()->set_metadata(metadata); |
1163 | |
1164 DatabasePluginMessages::TransactionResponse response; | |
1165 ExecuteTransaction(response, DatabasePluginMessages::OPERATION_GET_CHILDREN_METADATA, request); | |
1166 | |
1167 for (int i = 0; i < response.get_children_metadata().values().size(); i++) | |
1168 { | |
1169 target.push_back(response.get_children_metadata().values(i)); | |
1170 } | |
973 } | 1171 } |
974 | 1172 |
975 | 1173 |
976 virtual int64_t GetLastChangeIndex() ORTHANC_OVERRIDE | 1174 virtual int64_t GetLastChangeIndex() ORTHANC_OVERRIDE |
977 { | 1175 { |
978 int64_t tmp; | 1176 DatabasePluginMessages::TransactionResponse response; |
979 CheckSuccess(that_.backend_.getLastChangeIndex(transaction_, &tmp)); | 1177 ExecuteTransaction(response, DatabasePluginMessages::OPERATION_GET_LAST_CHANGE_INDEX); |
980 CheckNoEvent(); | 1178 return response.get_last_change_index().result(); |
981 return tmp; | |
982 } | 1179 } |
983 | 1180 |
984 | 1181 |
985 virtual bool LookupResourceAndParent(int64_t& id, | 1182 virtual bool LookupResourceAndParent(int64_t& id, |
986 ResourceType& type, | 1183 ResourceType& type, |
987 std::string& parentPublicId, | 1184 std::string& parentPublicId, |
988 const std::string& publicId) ORTHANC_OVERRIDE | 1185 const std::string& publicId) ORTHANC_OVERRIDE |
989 { | 1186 { |
990 uint8_t isExisting; | 1187 DatabasePluginMessages::TransactionRequest request; |
991 OrthancPluginResourceType tmpType; | 1188 request.mutable_lookup_resource_and_parent()->set_public_id(publicId); |
992 CheckSuccess(that_.backend_.lookupResourceAndParent(transaction_, &isExisting, &id, &tmpType, publicId.c_str())); | 1189 |
993 CheckNoEvent(); | 1190 DatabasePluginMessages::TransactionResponse response; |
994 | 1191 ExecuteTransaction(response, DatabasePluginMessages::OPERATION_LOOKUP_RESOURCE_AND_PARENT, request); |
995 if (isExisting) | 1192 |
996 { | 1193 if (response.lookup_resource_and_parent().found()) |
997 type = Plugins::Convert(tmpType); | 1194 { |
998 | 1195 id = response.lookup_resource_and_parent().id(); |
999 uint32_t count; | 1196 type = Convert(response.lookup_resource_and_parent().type()); |
1000 CheckSuccess(that_.backend_.readAnswersCount(transaction_, &count)); | |
1001 | |
1002 if (count > 1) | |
1003 { | |
1004 throw OrthancException(ErrorCode_DatabasePlugin); | |
1005 } | |
1006 | 1197 |
1007 switch (type) | 1198 switch (type) |
1008 { | 1199 { |
1009 case ResourceType_Patient: | 1200 case ResourceType_Patient: |
1010 // A patient has no parent | 1201 if (!response.lookup_resource_and_parent().parent_public_id().empty()) |
1011 if (count == 1) | |
1012 { | 1202 { |
1013 throw OrthancException(ErrorCode_DatabasePlugin); | 1203 throw OrthancException(ErrorCode_DatabasePlugin); |
1014 } | 1204 } |
1015 break; | 1205 break; |
1016 | 1206 |
1017 case ResourceType_Study: | 1207 case ResourceType_Study: |
1018 case ResourceType_Series: | 1208 case ResourceType_Series: |
1019 case ResourceType_Instance: | 1209 case ResourceType_Instance: |
1020 if (count == 0) | 1210 if (response.lookup_resource_and_parent().parent_public_id().empty()) |
1021 { | 1211 { |
1022 throw OrthancException(ErrorCode_DatabasePlugin); | 1212 throw OrthancException(ErrorCode_DatabasePlugin); |
1023 } | 1213 } |
1024 else | 1214 else |
1025 { | 1215 { |
1026 const char* value = NULL; | 1216 parentPublicId = response.lookup_resource_and_parent().parent_public_id(); |
1027 CheckSuccess(that_.backend_.readAnswerString(transaction_, &value, 0)); | |
1028 if (value == NULL) | |
1029 { | |
1030 throw OrthancException(ErrorCode_DatabasePlugin); | |
1031 } | |
1032 else | |
1033 { | |
1034 parentPublicId.assign(value); | |
1035 } | |
1036 } | 1217 } |
1037 break; | 1218 break; |
1038 | 1219 |
1039 default: | 1220 default: |
1040 throw OrthancException(ErrorCode_DatabasePlugin); | 1221 throw OrthancException(ErrorCode_ParameterOutOfRange); |
1041 } | 1222 } |
1042 | 1223 |
1043 return true; | 1224 return true; |
1044 } | 1225 } |
1045 else | 1226 else |
1046 { | 1227 { |
1047 return false; | 1228 return false; |
1048 } | 1229 } |
1049 } | 1230 } |
1231 | |
1232 | |
1233 virtual void AddLabel(int64_t resource, | |
1234 const std::string& label) ORTHANC_OVERRIDE | |
1235 { | |
1236 if (database_.GetDatabaseCapabilities().HasLabelsSupport()) | |
1237 { | |
1238 DatabasePluginMessages::TransactionRequest request; | |
1239 request.mutable_add_label()->set_id(resource); | |
1240 request.mutable_add_label()->set_label(label); | |
1241 | |
1242 ExecuteTransaction(DatabasePluginMessages::OPERATION_ADD_LABEL, request); | |
1243 } | |
1244 else | |
1245 { | |
1246 // This method shouldn't have been called | |
1247 throw OrthancException(ErrorCode_InternalError); | |
1248 } | |
1249 } | |
1250 | |
1251 | |
1252 virtual void RemoveLabel(int64_t resource, | |
1253 const std::string& label) ORTHANC_OVERRIDE | |
1254 { | |
1255 if (database_.GetDatabaseCapabilities().HasLabelsSupport()) | |
1256 { | |
1257 DatabasePluginMessages::TransactionRequest request; | |
1258 request.mutable_remove_label()->set_id(resource); | |
1259 request.mutable_remove_label()->set_label(label); | |
1260 | |
1261 ExecuteTransaction(DatabasePluginMessages::OPERATION_REMOVE_LABEL, request); | |
1262 } | |
1263 else | |
1264 { | |
1265 // This method shouldn't have been called | |
1266 throw OrthancException(ErrorCode_InternalError); | |
1267 } | |
1268 } | |
1269 | |
1270 | |
1271 virtual void ListLabels(std::set<std::string>& target, | |
1272 int64_t resource) ORTHANC_OVERRIDE | |
1273 { | |
1274 ListLabelsInternal(target, true, resource); | |
1275 } | |
1276 | |
1277 | |
1278 virtual void ListAllLabels(std::set<std::string>& target) ORTHANC_OVERRIDE | |
1279 { | |
1280 ListLabelsInternal(target, false, -1); | |
1281 } | |
1050 }; | 1282 }; |
1051 | |
1052 | |
1053 void OrthancPluginDatabaseV4::CheckSuccess(OrthancPluginErrorCode code) const | |
1054 { | |
1055 if (code != OrthancPluginErrorCode_Success) | |
1056 { | |
1057 errorDictionary_.LogError(code, true); | |
1058 throw OrthancException(static_cast<ErrorCode>(code)); | |
1059 } | |
1060 } | |
1061 | 1283 |
1062 | 1284 |
1063 OrthancPluginDatabaseV4::OrthancPluginDatabaseV4(SharedLibrary& library, | 1285 OrthancPluginDatabaseV4::OrthancPluginDatabaseV4(SharedLibrary& library, |
1064 PluginsErrorDictionary& errorDictionary, | 1286 PluginsErrorDictionary& errorDictionary, |
1065 const OrthancPluginDatabaseBackendV4* backend, | 1287 const _OrthancPluginRegisterDatabaseBackendV4& database, |
1066 size_t backendSize, | |
1067 void* database, | |
1068 const std::string& serverIdentifier) : | 1288 const std::string& serverIdentifier) : |
1069 library_(library), | 1289 library_(library), |
1070 errorDictionary_(errorDictionary), | 1290 errorDictionary_(errorDictionary), |
1071 database_(database), | 1291 definition_(database), |
1072 serverIdentifier_(serverIdentifier) | 1292 serverIdentifier_(serverIdentifier), |
1293 open_(false), | |
1294 databaseVersion_(0) | |
1073 { | 1295 { |
1074 CLOG(INFO, PLUGINS) << "Identifier of this Orthanc server for the global properties " | 1296 CLOG(INFO, PLUGINS) << "Identifier of this Orthanc server for the global properties " |
1075 << "of the custom database: \"" << serverIdentifier << "\""; | 1297 << "of the custom database: \"" << serverIdentifier << "\""; |
1076 | 1298 |
1077 if (backendSize >= sizeof(backend_)) | 1299 if (definition_.backend == NULL || |
1078 { | 1300 definition_.operations == NULL || |
1079 memcpy(&backend_, backend, sizeof(backend_)); | 1301 definition_.finalize == NULL) |
1080 } | 1302 { |
1081 else | 1303 throw OrthancException(ErrorCode_NullPointer); |
1082 { | 1304 } |
1083 // Not all the primitives are implemented by the plugin | |
1084 memset(&backend_, 0, sizeof(backend_)); | |
1085 memcpy(&backend_, backend, backendSize); | |
1086 } | |
1087 | |
1088 // Sanity checks | |
1089 CHECK_FUNCTION_EXISTS(backend_, readAnswersCount); | |
1090 CHECK_FUNCTION_EXISTS(backend_, readAnswerAttachment2); | |
1091 CHECK_FUNCTION_EXISTS(backend_, readAnswerChange); | |
1092 CHECK_FUNCTION_EXISTS(backend_, readAnswerDicomTag); | |
1093 CHECK_FUNCTION_EXISTS(backend_, readAnswerExportedResource); | |
1094 CHECK_FUNCTION_EXISTS(backend_, readAnswerInt32); | |
1095 CHECK_FUNCTION_EXISTS(backend_, readAnswerInt64); | |
1096 CHECK_FUNCTION_EXISTS(backend_, readAnswerMatchingResource); | |
1097 CHECK_FUNCTION_EXISTS(backend_, readAnswerMetadata); | |
1098 CHECK_FUNCTION_EXISTS(backend_, readAnswerString); | |
1099 | |
1100 CHECK_FUNCTION_EXISTS(backend_, readEventsCount); | |
1101 CHECK_FUNCTION_EXISTS(backend_, readEvent2); | |
1102 | |
1103 CHECK_FUNCTION_EXISTS(backend_, open); | |
1104 CHECK_FUNCTION_EXISTS(backend_, close); | |
1105 CHECK_FUNCTION_EXISTS(backend_, destructDatabase); | |
1106 CHECK_FUNCTION_EXISTS(backend_, getDatabaseVersion); | |
1107 CHECK_FUNCTION_EXISTS(backend_, upgradeDatabase); | |
1108 CHECK_FUNCTION_EXISTS(backend_, startTransaction); | |
1109 CHECK_FUNCTION_EXISTS(backend_, destructTransaction); | |
1110 CHECK_FUNCTION_EXISTS(backend_, hasRevisionsSupport); | |
1111 CHECK_FUNCTION_EXISTS(backend_, hasAttachmentCustomDataSupport); // new in v4 | |
1112 | |
1113 CHECK_FUNCTION_EXISTS(backend_, rollback); | |
1114 CHECK_FUNCTION_EXISTS(backend_, commit); | |
1115 | |
1116 CHECK_FUNCTION_EXISTS(backend_, addAttachment2); | |
1117 CHECK_FUNCTION_EXISTS(backend_, clearChanges); | |
1118 CHECK_FUNCTION_EXISTS(backend_, clearExportedResources); | |
1119 CHECK_FUNCTION_EXISTS(backend_, clearMainDicomTags); | |
1120 CHECK_FUNCTION_EXISTS(backend_, createInstance); | |
1121 CHECK_FUNCTION_EXISTS(backend_, deleteAttachment); | |
1122 CHECK_FUNCTION_EXISTS(backend_, deleteMetadata); | |
1123 CHECK_FUNCTION_EXISTS(backend_, deleteResource); | |
1124 CHECK_FUNCTION_EXISTS(backend_, getAllMetadata); | |
1125 CHECK_FUNCTION_EXISTS(backend_, getAllPublicIds); | |
1126 CHECK_FUNCTION_EXISTS(backend_, getAllPublicIdsWithLimit); | |
1127 CHECK_FUNCTION_EXISTS(backend_, getChanges); | |
1128 CHECK_FUNCTION_EXISTS(backend_, getChildrenInternalId); | |
1129 CHECK_FUNCTION_EXISTS(backend_, getChildrenMetadata); | |
1130 CHECK_FUNCTION_EXISTS(backend_, getChildrenPublicId); | |
1131 CHECK_FUNCTION_EXISTS(backend_, getExportedResources); | |
1132 CHECK_FUNCTION_EXISTS(backend_, getLastChange); | |
1133 CHECK_FUNCTION_EXISTS(backend_, getLastChangeIndex); | |
1134 CHECK_FUNCTION_EXISTS(backend_, getLastExportedResource); | |
1135 CHECK_FUNCTION_EXISTS(backend_, getMainDicomTags); | |
1136 CHECK_FUNCTION_EXISTS(backend_, getPublicId); | |
1137 CHECK_FUNCTION_EXISTS(backend_, getResourceType); | |
1138 CHECK_FUNCTION_EXISTS(backend_, getResourcesCount); | |
1139 CHECK_FUNCTION_EXISTS(backend_, getTotalCompressedSize); | |
1140 CHECK_FUNCTION_EXISTS(backend_, getTotalUncompressedSize); | |
1141 CHECK_FUNCTION_EXISTS(backend_, isDiskSizeAbove); | |
1142 CHECK_FUNCTION_EXISTS(backend_, isExistingResource); | |
1143 CHECK_FUNCTION_EXISTS(backend_, isProtectedPatient); | |
1144 CHECK_FUNCTION_EXISTS(backend_, listAvailableAttachments); | |
1145 CHECK_FUNCTION_EXISTS(backend_, logChange); | |
1146 CHECK_FUNCTION_EXISTS(backend_, logExportedResource); | |
1147 CHECK_FUNCTION_EXISTS(backend_, lookupAttachment); | |
1148 CHECK_FUNCTION_EXISTS(backend_, lookupGlobalProperty); | |
1149 CHECK_FUNCTION_EXISTS(backend_, lookupMetadata); | |
1150 CHECK_FUNCTION_EXISTS(backend_, lookupParent); | |
1151 CHECK_FUNCTION_EXISTS(backend_, lookupResource); | |
1152 CHECK_FUNCTION_EXISTS(backend_, lookupResourceAndParent); | |
1153 CHECK_FUNCTION_EXISTS(backend_, lookupResources); | |
1154 CHECK_FUNCTION_EXISTS(backend_, selectPatientToRecycle); | |
1155 CHECK_FUNCTION_EXISTS(backend_, selectPatientToRecycle2); | |
1156 CHECK_FUNCTION_EXISTS(backend_, setGlobalProperty); | |
1157 CHECK_FUNCTION_EXISTS(backend_, setMetadata); | |
1158 CHECK_FUNCTION_EXISTS(backend_, setProtectedPatient); | |
1159 CHECK_FUNCTION_EXISTS(backend_, setResourcesContent); | |
1160 } | 1305 } |
1161 | 1306 |
1162 | 1307 |
1163 OrthancPluginDatabaseV4::~OrthancPluginDatabaseV4() | 1308 OrthancPluginDatabaseV4::~OrthancPluginDatabaseV4() |
1164 { | 1309 { |
1165 if (database_ != NULL) | 1310 definition_.finalize(definition_.backend); |
1166 { | 1311 } |
1167 OrthancPluginErrorCode code = backend_.destructDatabase(database_); | 1312 |
1168 if (code != OrthancPluginErrorCode_Success) | 1313 |
1169 { | 1314 static void AddIdentifierTags(DatabasePluginMessages::Open::Request& request, |
1170 // Don't throw exception in destructors | 1315 ResourceType level) |
1171 errorDictionary_.LogError(code, true); | 1316 { |
1172 } | 1317 const DicomTag* tags = NULL; |
1318 size_t size; | |
1319 | |
1320 ServerToolbox::LoadIdentifiers(tags, size, level); | |
1321 | |
1322 if (tags == NULL || | |
1323 size == 0) | |
1324 { | |
1325 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); | |
1326 } | |
1327 | |
1328 for (size_t i = 0; i < size; i++) | |
1329 { | |
1330 DatabasePluginMessages::Open_Request_IdentifierTag* tag = request.add_identifier_tags(); | |
1331 tag->set_level(Convert(level)); | |
1332 tag->set_group(tags[i].GetGroup()); | |
1333 tag->set_element(tags[i].GetElement()); | |
1334 tag->set_name(FromDcmtkBridge::GetTagName(tags[i], "")); | |
1173 } | 1335 } |
1174 } | 1336 } |
1175 | 1337 |
1176 | 1338 |
1177 void OrthancPluginDatabaseV4::Open() | 1339 void OrthancPluginDatabaseV4::Open() |
1178 { | 1340 { |
1179 CheckSuccess(backend_.open(database_)); | 1341 if (open_) |
1342 { | |
1343 throw OrthancException(ErrorCode_BadSequenceOfCalls); | |
1344 } | |
1345 | |
1346 { | |
1347 DatabasePluginMessages::DatabaseRequest request; | |
1348 AddIdentifierTags(*request.mutable_open(), ResourceType_Patient); | |
1349 AddIdentifierTags(*request.mutable_open(), ResourceType_Study); | |
1350 AddIdentifierTags(*request.mutable_open(), ResourceType_Series); | |
1351 AddIdentifierTags(*request.mutable_open(), ResourceType_Instance); | |
1352 | |
1353 DatabasePluginMessages::DatabaseResponse response; | |
1354 ExecuteDatabase(response, *this, DatabasePluginMessages::OPERATION_OPEN, request); | |
1355 } | |
1356 | |
1357 { | |
1358 DatabasePluginMessages::DatabaseRequest request; | |
1359 DatabasePluginMessages::DatabaseResponse response; | |
1360 ExecuteDatabase(response, *this, DatabasePluginMessages::OPERATION_GET_SYSTEM_INFORMATION, request); | |
1361 | |
1362 const ::Orthanc::DatabasePluginMessages::GetSystemInformation_Response& systemInfo = response.get_system_information(); | |
1363 databaseVersion_ = systemInfo.database_version(); | |
1364 dbCapabilities_.SetFlushToDisk(systemInfo.supports_flush_to_disk()); | |
1365 dbCapabilities_.SetRevisionsSupport(systemInfo.supports_revisions()); | |
1366 dbCapabilities_.SetLabelsSupport(systemInfo.supports_labels()); | |
1367 dbCapabilities_.SetAtomicIncrementGlobalProperty(systemInfo.supports_increment_global_property()); | |
1368 dbCapabilities_.SetUpdateAndGetStatistics(systemInfo.has_update_and_get_statistics()); | |
1369 dbCapabilities_.SetMeasureLatency(systemInfo.has_measure_latency()); | |
1370 } | |
1371 | |
1372 open_ = true; | |
1180 } | 1373 } |
1181 | 1374 |
1182 | 1375 |
1183 void OrthancPluginDatabaseV4::Close() | 1376 void OrthancPluginDatabaseV4::Close() |
1184 { | 1377 { |
1185 CheckSuccess(backend_.close(database_)); | 1378 if (!open_) |
1379 { | |
1380 throw OrthancException(ErrorCode_BadSequenceOfCalls); | |
1381 } | |
1382 else | |
1383 { | |
1384 DatabasePluginMessages::DatabaseRequest request; | |
1385 DatabasePluginMessages::DatabaseResponse response; | |
1386 ExecuteDatabase(response, *this, DatabasePluginMessages::OPERATION_CLOSE, request); | |
1387 } | |
1388 } | |
1389 | |
1390 | |
1391 | |
1392 void OrthancPluginDatabaseV4::FlushToDisk() | |
1393 { | |
1394 if (!open_ || | |
1395 !GetDatabaseCapabilities().HasFlushToDisk()) | |
1396 { | |
1397 throw OrthancException(ErrorCode_BadSequenceOfCalls); | |
1398 } | |
1399 else | |
1400 { | |
1401 DatabasePluginMessages::DatabaseRequest request; | |
1402 DatabasePluginMessages::DatabaseResponse response; | |
1403 ExecuteDatabase(response, *this, DatabasePluginMessages::OPERATION_FLUSH_TO_DISK, request); | |
1404 } | |
1186 } | 1405 } |
1187 | 1406 |
1188 | 1407 |
1189 IDatabaseWrapper::ITransaction* OrthancPluginDatabaseV4::StartTransaction(TransactionType type, | 1408 IDatabaseWrapper::ITransaction* OrthancPluginDatabaseV4::StartTransaction(TransactionType type, |
1190 IDatabaseListener& listener) | 1409 IDatabaseListener& listener) |
1191 { | 1410 { |
1192 switch (type) | 1411 if (!open_) |
1193 { | 1412 { |
1194 case TransactionType_ReadOnly: | 1413 throw OrthancException(ErrorCode_BadSequenceOfCalls); |
1195 return new Transaction(*this, listener, OrthancPluginDatabaseTransactionType_ReadOnly); | 1414 } |
1196 | 1415 else |
1197 case TransactionType_ReadWrite: | 1416 { |
1198 return new Transaction(*this, listener, OrthancPluginDatabaseTransactionType_ReadWrite); | 1417 return new Transaction(*this, listener, type); |
1199 | |
1200 default: | |
1201 throw OrthancException(ErrorCode_InternalError); | |
1202 } | 1418 } |
1203 } | 1419 } |
1204 | 1420 |
1205 | 1421 |
1206 unsigned int OrthancPluginDatabaseV4::GetDatabaseVersion() | 1422 unsigned int OrthancPluginDatabaseV4::GetDatabaseVersion() |
1207 { | 1423 { |
1208 uint32_t version = 0; | 1424 if (!open_) |
1209 CheckSuccess(backend_.getDatabaseVersion(database_, &version)); | 1425 { |
1210 return version; | 1426 throw OrthancException(ErrorCode_BadSequenceOfCalls); |
1427 } | |
1428 else | |
1429 { | |
1430 return databaseVersion_; | |
1431 } | |
1211 } | 1432 } |
1212 | 1433 |
1213 | 1434 |
1214 void OrthancPluginDatabaseV4::Upgrade(unsigned int targetVersion, | 1435 void OrthancPluginDatabaseV4::Upgrade(unsigned int targetVersion, |
1215 IStorageArea& storageArea) | 1436 IStorageArea& storageArea) |
1216 { | 1437 { |
1217 VoidDatabaseListener listener; | 1438 if (!open_) |
1218 | 1439 { |
1219 if (backend_.upgradeDatabase != NULL) | 1440 throw OrthancException(ErrorCode_BadSequenceOfCalls); |
1220 { | 1441 } |
1221 Transaction transaction(*this, listener, OrthancPluginDatabaseTransactionType_ReadWrite); | 1442 else |
1222 | 1443 { |
1223 OrthancPluginErrorCode code = backend_.upgradeDatabase( | 1444 VoidDatabaseListener listener; |
1224 database_, reinterpret_cast<OrthancPluginStorageArea*>(&storageArea), | 1445 Transaction transaction(*this, listener, TransactionType_ReadWrite); |
1225 static_cast<uint32_t>(targetVersion)); | 1446 |
1226 | 1447 try |
1227 if (code == OrthancPluginErrorCode_Success) | 1448 { |
1228 { | 1449 DatabasePluginMessages::DatabaseRequest request; |
1450 request.mutable_upgrade()->set_target_version(targetVersion); | |
1451 request.mutable_upgrade()->set_storage_area(reinterpret_cast<intptr_t>(&storageArea)); | |
1452 request.mutable_upgrade()->set_transaction(reinterpret_cast<intptr_t>(transaction.GetTransactionObject())); | |
1453 | |
1454 DatabasePluginMessages::DatabaseResponse response; | |
1455 | |
1456 ExecuteDatabase(response, *this, DatabasePluginMessages::OPERATION_UPGRADE, request); | |
1229 transaction.Commit(0); | 1457 transaction.Commit(0); |
1230 } | 1458 } |
1231 else | 1459 catch (OrthancException& e) |
1232 { | 1460 { |
1233 transaction.Rollback(); | 1461 transaction.Rollback(); |
1234 errorDictionary_.LogError(code, true); | 1462 throw; |
1235 throw OrthancException(static_cast<ErrorCode>(code)); | 1463 } |
1236 } | 1464 } |
1237 } | 1465 } |
1238 } | 1466 |
1239 | 1467 |
1240 | 1468 uint64_t OrthancPluginDatabaseV4::MeasureLatency() |
1241 bool OrthancPluginDatabaseV4::HasRevisionsSupport() const | 1469 { |
1242 { | 1470 if (!open_) |
1243 // WARNING: This method requires "Open()" to have been called | 1471 { |
1244 uint8_t hasRevisions; | 1472 throw OrthancException(ErrorCode_BadSequenceOfCalls); |
1245 CheckSuccess(backend_.hasRevisionsSupport(database_, &hasRevisions)); | 1473 } |
1246 return (hasRevisions != 0); | 1474 else |
1247 } | 1475 { |
1248 | 1476 DatabasePluginMessages::DatabaseRequest request; |
1249 bool OrthancPluginDatabaseV4::HasAttachmentCustomDataSupport() const | 1477 DatabasePluginMessages::DatabaseResponse response; |
1250 { | 1478 |
1251 // WARNING: This method requires "Open()" to have been called | 1479 ExecuteDatabase(response, *this, DatabasePluginMessages::OPERATION_MEASURE_LATENCY, request); |
1252 uint8_t hasAttachmentCustomDataSupport; | 1480 return response.measure_latency().latency_us(); |
1253 CheckSuccess(backend_.hasAttachmentCustomDataSupport(database_, &hasAttachmentCustomDataSupport)); | 1481 } |
1254 return (hasAttachmentCustomDataSupport != 0); | 1482 } |
1483 | |
1484 | |
1485 const IDatabaseWrapper::Capabilities OrthancPluginDatabaseV4::GetDatabaseCapabilities() const | |
1486 { | |
1487 if (!open_) | |
1488 { | |
1489 throw OrthancException(ErrorCode_BadSequenceOfCalls); | |
1490 } | |
1491 else | |
1492 { | |
1493 return dbCapabilities_; | |
1494 } | |
1255 } | 1495 } |
1256 } | 1496 } |