Mercurial > hg > orthanc-databases
comparison Framework/Plugins/DatabaseBackendAdapterV4.cpp @ 387:f35b17a38301
integration db-protobuf->mainline
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Mon, 03 Apr 2023 17:12:08 +0200 |
parents | e236be67e5f9 |
children | 3d6886f3e5b3 |
comparison
equal
deleted
inserted
replaced
371:c1fe28de1bf6 | 387:f35b17a38301 |
---|---|
1 /** | |
2 * Orthanc - A Lightweight, RESTful DICOM Store | |
3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics | |
4 * Department, University Hospital of Liege, Belgium | |
5 * Copyright (C) 2017-2022 Osimis S.A., Belgium | |
6 * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium | |
7 * | |
8 * This program is free software: you can redistribute it and/or | |
9 * modify it under the terms of the GNU Affero General Public License | |
10 * as published by the Free Software Foundation, either version 3 of | |
11 * the License, or (at your option) any later version. | |
12 * | |
13 * This program is distributed in the hope that it will be useful, but | |
14 * WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
16 * Affero General Public License for more details. | |
17 * | |
18 * You should have received a copy of the GNU Affero General Public License | |
19 * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
20 **/ | |
21 | |
22 | |
23 #include "DatabaseBackendAdapterV4.h" | |
24 | |
25 #if defined(ORTHANC_PLUGINS_VERSION_IS_ABOVE) // Macro introduced in Orthanc 1.3.1 | |
26 # if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 12, 0) | |
27 | |
28 #include "IndexConnectionsPool.h" | |
29 | |
30 #include <OrthancDatabasePlugin.pb.h> // Include protobuf messages | |
31 | |
32 #include <Logging.h> | |
33 #include <OrthancException.h> | |
34 | |
35 #include <stdexcept> | |
36 #include <list> | |
37 #include <string> | |
38 #include <cassert> | |
39 | |
40 | |
41 #define ORTHANC_PLUGINS_DATABASE_CATCH(context) \ | |
42 | |
43 | |
44 namespace OrthancDatabases | |
45 { | |
46 static bool isBackendInUse_ = false; // Only for sanity checks | |
47 | |
48 | |
49 static Orthanc::DatabasePluginMessages::ResourceType Convert(OrthancPluginResourceType resourceType) | |
50 { | |
51 switch (resourceType) | |
52 { | |
53 case OrthancPluginResourceType_Patient: | |
54 return Orthanc::DatabasePluginMessages::RESOURCE_PATIENT; | |
55 | |
56 case OrthancPluginResourceType_Study: | |
57 return Orthanc::DatabasePluginMessages::RESOURCE_STUDY; | |
58 | |
59 case OrthancPluginResourceType_Series: | |
60 return Orthanc::DatabasePluginMessages::RESOURCE_SERIES; | |
61 | |
62 case OrthancPluginResourceType_Instance: | |
63 return Orthanc::DatabasePluginMessages::RESOURCE_INSTANCE; | |
64 | |
65 default: | |
66 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); | |
67 } | |
68 } | |
69 | |
70 | |
71 static OrthancPluginResourceType Convert(Orthanc::DatabasePluginMessages::ResourceType resourceType) | |
72 { | |
73 switch (resourceType) | |
74 { | |
75 case Orthanc::DatabasePluginMessages::RESOURCE_PATIENT: | |
76 return OrthancPluginResourceType_Patient; | |
77 | |
78 case Orthanc::DatabasePluginMessages::RESOURCE_STUDY: | |
79 return OrthancPluginResourceType_Study; | |
80 | |
81 case Orthanc::DatabasePluginMessages::RESOURCE_SERIES: | |
82 return OrthancPluginResourceType_Series; | |
83 | |
84 case Orthanc::DatabasePluginMessages::RESOURCE_INSTANCE: | |
85 return OrthancPluginResourceType_Instance; | |
86 | |
87 default: | |
88 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); | |
89 } | |
90 } | |
91 | |
92 | |
93 class Output : public IDatabaseBackendOutput | |
94 { | |
95 private: | |
96 Orthanc::DatabasePluginMessages::DeleteAttachment::Response* deleteAttachment_; | |
97 Orthanc::DatabasePluginMessages::DeleteResource::Response* deleteResource_; | |
98 Orthanc::DatabasePluginMessages::GetChanges::Response* getChanges_; | |
99 Orthanc::DatabasePluginMessages::GetExportedResources::Response* getExportedResources_; | |
100 Orthanc::DatabasePluginMessages::GetLastChange::Response* getLastChange_; | |
101 Orthanc::DatabasePluginMessages::GetLastExportedResource::Response* getLastExportedResource_; | |
102 Orthanc::DatabasePluginMessages::GetMainDicomTags::Response* getMainDicomTags_; | |
103 Orthanc::DatabasePluginMessages::LookupAttachment::Response* lookupAttachment_; | |
104 Orthanc::DatabasePluginMessages::LookupResources::Response* lookupResources_; | |
105 | |
106 void Clear() | |
107 { | |
108 deleteAttachment_ = NULL; | |
109 deleteResource_ = NULL; | |
110 getChanges_ = NULL; | |
111 getExportedResources_ = NULL; | |
112 getLastChange_ = NULL; | |
113 getLastExportedResource_ = NULL; | |
114 getMainDicomTags_ = NULL; | |
115 lookupAttachment_ = NULL; | |
116 lookupResources_ = NULL; | |
117 } | |
118 | |
119 public: | |
120 Output(Orthanc::DatabasePluginMessages::DeleteAttachment::Response& deleteAttachment) | |
121 { | |
122 Clear(); | |
123 deleteAttachment_ = &deleteAttachment; | |
124 } | |
125 | |
126 Output(Orthanc::DatabasePluginMessages::DeleteResource::Response& deleteResource) | |
127 { | |
128 Clear(); | |
129 deleteResource_ = &deleteResource; | |
130 } | |
131 | |
132 Output(Orthanc::DatabasePluginMessages::GetChanges::Response& getChanges) | |
133 { | |
134 Clear(); | |
135 getChanges_ = &getChanges; | |
136 } | |
137 | |
138 Output(Orthanc::DatabasePluginMessages::GetExportedResources::Response& getExportedResources) | |
139 { | |
140 Clear(); | |
141 getExportedResources_ = &getExportedResources; | |
142 } | |
143 | |
144 Output(Orthanc::DatabasePluginMessages::GetLastChange::Response& getLastChange) | |
145 { | |
146 Clear(); | |
147 getLastChange_ = &getLastChange; | |
148 } | |
149 | |
150 Output(Orthanc::DatabasePluginMessages::GetLastExportedResource::Response& getLastExportedResource) | |
151 { | |
152 Clear(); | |
153 getLastExportedResource_ = &getLastExportedResource; | |
154 } | |
155 | |
156 Output(Orthanc::DatabasePluginMessages::GetMainDicomTags::Response& getMainDicomTags) | |
157 { | |
158 Clear(); | |
159 getMainDicomTags_ = &getMainDicomTags; | |
160 } | |
161 | |
162 Output(Orthanc::DatabasePluginMessages::LookupAttachment::Response& lookupAttachment) | |
163 { | |
164 Clear(); | |
165 lookupAttachment_ = &lookupAttachment; | |
166 } | |
167 | |
168 Output(Orthanc::DatabasePluginMessages::LookupResources::Response& lookupResources) | |
169 { | |
170 Clear(); | |
171 lookupResources_ = &lookupResources; | |
172 } | |
173 | |
174 virtual void SignalDeletedAttachment(const std::string& uuid, | |
175 int32_t contentType, | |
176 uint64_t uncompressedSize, | |
177 const std::string& uncompressedHash, | |
178 int32_t compressionType, | |
179 uint64_t compressedSize, | |
180 const std::string& compressedHash) ORTHANC_OVERRIDE | |
181 { | |
182 Orthanc::DatabasePluginMessages::FileInfo* attachment; | |
183 | |
184 if (deleteAttachment_ != NULL) | |
185 { | |
186 if (deleteAttachment_->has_deleted_attachment()) | |
187 { | |
188 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | |
189 } | |
190 | |
191 attachment = deleteAttachment_->mutable_deleted_attachment(); | |
192 } | |
193 else if (deleteResource_ != NULL) | |
194 { | |
195 attachment = deleteResource_->add_deleted_attachments(); | |
196 } | |
197 else | |
198 { | |
199 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | |
200 } | |
201 | |
202 attachment->set_uuid(uuid); | |
203 attachment->set_content_type(contentType); | |
204 attachment->set_uncompressed_size(uncompressedSize); | |
205 attachment->set_uncompressed_hash(uncompressedHash); | |
206 attachment->set_compression_type(compressionType); | |
207 attachment->set_compressed_size(compressedSize); | |
208 attachment->set_compressed_hash(compressedHash); | |
209 } | |
210 | |
211 virtual void SignalDeletedResource(const std::string& publicId, | |
212 OrthancPluginResourceType resourceType) ORTHANC_OVERRIDE | |
213 { | |
214 if (deleteResource_ != NULL) | |
215 { | |
216 Orthanc::DatabasePluginMessages::DeleteResource_Response_Resource* resource = deleteResource_->add_deleted_resources(); | |
217 resource->set_level(Convert(resourceType)); | |
218 resource->set_public_id(publicId); | |
219 } | |
220 else | |
221 { | |
222 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | |
223 } | |
224 } | |
225 | |
226 virtual void SignalRemainingAncestor(const std::string& ancestorId, | |
227 OrthancPluginResourceType ancestorType) ORTHANC_OVERRIDE | |
228 { | |
229 if (deleteResource_ != NULL) | |
230 { | |
231 if (deleteResource_->is_remaining_ancestor()) | |
232 { | |
233 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | |
234 } | |
235 else | |
236 { | |
237 deleteResource_->set_is_remaining_ancestor(true); | |
238 deleteResource_->mutable_remaining_ancestor()->set_level(Convert(ancestorType)); | |
239 deleteResource_->mutable_remaining_ancestor()->set_public_id(ancestorId); | |
240 } | |
241 } | |
242 else | |
243 { | |
244 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | |
245 } | |
246 } | |
247 | |
248 virtual void AnswerAttachment(const std::string& uuid, | |
249 int32_t contentType, | |
250 uint64_t uncompressedSize, | |
251 const std::string& uncompressedHash, | |
252 int32_t compressionType, | |
253 uint64_t compressedSize, | |
254 const std::string& compressedHash) ORTHANC_OVERRIDE | |
255 { | |
256 if (lookupAttachment_ != NULL) | |
257 { | |
258 if (lookupAttachment_->found()) | |
259 { | |
260 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | |
261 } | |
262 | |
263 lookupAttachment_->set_found(true); | |
264 lookupAttachment_->mutable_attachment()->set_uuid(uuid); | |
265 lookupAttachment_->mutable_attachment()->set_content_type(contentType); | |
266 lookupAttachment_->mutable_attachment()->set_uncompressed_size(uncompressedSize); | |
267 lookupAttachment_->mutable_attachment()->set_uncompressed_hash(uncompressedHash); | |
268 lookupAttachment_->mutable_attachment()->set_compression_type(compressionType); | |
269 lookupAttachment_->mutable_attachment()->set_compressed_size(compressedSize); | |
270 lookupAttachment_->mutable_attachment()->set_compressed_hash(compressedHash); | |
271 } | |
272 else | |
273 { | |
274 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | |
275 } | |
276 } | |
277 | |
278 virtual void AnswerChange(int64_t seq, | |
279 int32_t changeType, | |
280 OrthancPluginResourceType resourceType, | |
281 const std::string& publicId, | |
282 const std::string& date) ORTHANC_OVERRIDE | |
283 { | |
284 Orthanc::DatabasePluginMessages::ServerIndexChange* change; | |
285 | |
286 if (getChanges_ != NULL) | |
287 { | |
288 change = getChanges_->add_changes(); | |
289 } | |
290 else if (getLastChange_ != NULL) | |
291 { | |
292 if (getLastChange_->found()) | |
293 { | |
294 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | |
295 } | |
296 | |
297 getLastChange_->set_found(true); | |
298 change = getLastChange_->mutable_change(); | |
299 } | |
300 else | |
301 { | |
302 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | |
303 } | |
304 | |
305 change->set_seq(seq); | |
306 change->set_change_type(changeType); | |
307 change->set_resource_type(Convert(resourceType)); | |
308 change->set_public_id(publicId); | |
309 change->set_date(date); | |
310 } | |
311 | |
312 virtual void AnswerDicomTag(uint16_t group, | |
313 uint16_t element, | |
314 const std::string& value) ORTHANC_OVERRIDE | |
315 { | |
316 if (getMainDicomTags_ != NULL) | |
317 { | |
318 Orthanc::DatabasePluginMessages::GetMainDicomTags_Response_Tag* tag = getMainDicomTags_->add_tags(); | |
319 tag->set_group(group); | |
320 tag->set_element(element); | |
321 tag->set_value(value); | |
322 } | |
323 else | |
324 { | |
325 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | |
326 } | |
327 } | |
328 | |
329 virtual void AnswerExportedResource(int64_t seq, | |
330 OrthancPluginResourceType resourceType, | |
331 const std::string& publicId, | |
332 const std::string& modality, | |
333 const std::string& date, | |
334 const std::string& patientId, | |
335 const std::string& studyInstanceUid, | |
336 const std::string& seriesInstanceUid, | |
337 const std::string& sopInstanceUid) ORTHANC_OVERRIDE | |
338 { | |
339 Orthanc::DatabasePluginMessages::ExportedResource* resource; | |
340 | |
341 if (getExportedResources_ != NULL) | |
342 { | |
343 resource = getExportedResources_->add_resources(); | |
344 } | |
345 else if (getLastExportedResource_ != NULL) | |
346 { | |
347 if (getLastExportedResource_->found()) | |
348 { | |
349 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | |
350 } | |
351 | |
352 getLastExportedResource_->set_found(true); | |
353 resource = getLastExportedResource_->mutable_resource(); | |
354 } | |
355 else | |
356 { | |
357 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | |
358 } | |
359 | |
360 resource->set_seq(seq); | |
361 resource->set_resource_type(Convert(resourceType)); | |
362 resource->set_public_id(publicId); | |
363 resource->set_modality(modality); | |
364 resource->set_date(date); | |
365 resource->set_patient_id(patientId); | |
366 resource->set_study_instance_uid(studyInstanceUid); | |
367 resource->set_series_instance_uid(seriesInstanceUid); | |
368 resource->set_sop_instance_uid(sopInstanceUid); | |
369 } | |
370 | |
371 virtual void AnswerMatchingResource(const std::string& resourceId) ORTHANC_OVERRIDE | |
372 { | |
373 if (lookupResources_ != NULL) | |
374 { | |
375 lookupResources_->add_resources_ids(resourceId); | |
376 } | |
377 else | |
378 { | |
379 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | |
380 } | |
381 } | |
382 | |
383 virtual void AnswerMatchingResource(const std::string& resourceId, | |
384 const std::string& someInstanceId) ORTHANC_OVERRIDE | |
385 { | |
386 if (lookupResources_ != NULL) | |
387 { | |
388 lookupResources_->add_resources_ids(resourceId); | |
389 lookupResources_->add_instances_ids(someInstanceId); | |
390 } | |
391 else | |
392 { | |
393 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | |
394 } | |
395 } | |
396 }; | |
397 | |
398 | |
399 static void ProcessDatabaseOperation(Orthanc::DatabasePluginMessages::DatabaseResponse& response, | |
400 const Orthanc::DatabasePluginMessages::DatabaseRequest& request, | |
401 IndexConnectionsPool& pool) | |
402 { | |
403 switch (request.operation()) | |
404 { | |
405 case Orthanc::DatabasePluginMessages::OPERATION_GET_SYSTEM_INFORMATION: | |
406 { | |
407 IndexConnectionsPool::Accessor accessor(pool); | |
408 response.mutable_get_system_information()->set_database_version(accessor.GetBackend().GetDatabaseVersion(accessor.GetManager())); | |
409 response.mutable_get_system_information()->set_supports_flush_to_disk(false); | |
410 response.mutable_get_system_information()->set_supports_revisions(accessor.GetBackend().HasRevisionsSupport()); | |
411 break; | |
412 } | |
413 | |
414 case Orthanc::DatabasePluginMessages::OPERATION_OPEN: | |
415 { | |
416 pool.OpenConnections(); | |
417 break; | |
418 } | |
419 | |
420 case Orthanc::DatabasePluginMessages::OPERATION_CLOSE: | |
421 { | |
422 pool.CloseConnections(); | |
423 break; | |
424 } | |
425 | |
426 case Orthanc::DatabasePluginMessages::OPERATION_FLUSH_TO_DISK: | |
427 { | |
428 // Raise an exception since "set_supports_flush_to_disk(false)" | |
429 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); | |
430 } | |
431 | |
432 case Orthanc::DatabasePluginMessages::OPERATION_START_TRANSACTION: | |
433 { | |
434 std::unique_ptr<IndexConnectionsPool::Accessor> transaction(new IndexConnectionsPool::Accessor(pool)); | |
435 | |
436 switch (request.start_transaction().type()) | |
437 { | |
438 case Orthanc::DatabasePluginMessages::TRANSACTION_READ_ONLY: | |
439 transaction->GetManager().StartTransaction(TransactionType_ReadOnly); | |
440 break; | |
441 | |
442 case Orthanc::DatabasePluginMessages::TRANSACTION_READ_WRITE: | |
443 transaction->GetManager().StartTransaction(TransactionType_ReadWrite); | |
444 break; | |
445 | |
446 default: | |
447 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); | |
448 } | |
449 | |
450 response.mutable_start_transaction()->set_transaction(reinterpret_cast<intptr_t>(transaction.release())); | |
451 break; | |
452 } | |
453 | |
454 case Orthanc::DatabasePluginMessages::OPERATION_UPGRADE: | |
455 { | |
456 IndexConnectionsPool::Accessor accessor(pool); | |
457 OrthancPluginStorageArea* storageArea = reinterpret_cast<OrthancPluginStorageArea*>(request.upgrade().storage_area()); | |
458 accessor.GetBackend().UpgradeDatabase(accessor.GetManager(), request.upgrade().target_version(), storageArea); | |
459 break; | |
460 } | |
461 | |
462 case Orthanc::DatabasePluginMessages::OPERATION_FINALIZE_TRANSACTION: | |
463 { | |
464 IndexConnectionsPool::Accessor* transaction = reinterpret_cast<IndexConnectionsPool::Accessor*>(request.finalize_transaction().transaction()); | |
465 | |
466 if (transaction == NULL) | |
467 { | |
468 throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); | |
469 } | |
470 else | |
471 { | |
472 delete transaction; | |
473 } | |
474 | |
475 break; | |
476 } | |
477 | |
478 default: | |
479 LOG(ERROR) << "Not implemented database operation from protobuf: " << request.operation(); | |
480 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); | |
481 } | |
482 } | |
483 | |
484 | |
485 static void ApplyLookupResources(Orthanc::DatabasePluginMessages::LookupResources_Response& response, | |
486 const Orthanc::DatabasePluginMessages::LookupResources_Request& request, | |
487 IndexBackend& backend, | |
488 DatabaseManager& manager) | |
489 { | |
490 std::vector<Orthanc::DatabaseConstraint> lookup; | |
491 lookup.reserve(request.lookup().size()); | |
492 | |
493 size_t countValues = 0; | |
494 | |
495 for (int i = 0; i < request.lookup().size(); i++) | |
496 { | |
497 const Orthanc::DatabasePluginMessages::DatabaseConstraint& constraint = request.lookup(i); | |
498 countValues += constraint.values().size(); | |
499 } | |
500 | |
501 std::vector<const char*> values; | |
502 values.reserve(countValues); | |
503 | |
504 for (int i = 0; i < request.lookup().size(); i++) | |
505 { | |
506 const Orthanc::DatabasePluginMessages::DatabaseConstraint& constraint = request.lookup(i); | |
507 | |
508 if (constraint.tag_group() > 0xffffu || | |
509 constraint.tag_element() > 0xffffu) | |
510 { | |
511 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); | |
512 } | |
513 | |
514 OrthancPluginDatabaseConstraint c; | |
515 c.level = Convert(constraint.level()); | |
516 c.tagGroup = constraint.tag_group(); | |
517 c.tagElement = constraint.tag_element(); | |
518 c.isIdentifierTag = (constraint.is_identifier_tag() ? 1 : 0); | |
519 c.isCaseSensitive = (constraint.is_case_sensitive() ? 1 : 0); | |
520 c.isMandatory = (constraint.is_mandatory() ? 1 : 0); | |
521 | |
522 switch (constraint.type()) | |
523 { | |
524 case Orthanc::DatabasePluginMessages::CONSTRAINT_EQUAL: | |
525 c.type = OrthancPluginConstraintType_Equal; | |
526 break; | |
527 | |
528 case Orthanc::DatabasePluginMessages::CONSTRAINT_SMALLER_OR_EQUAL: | |
529 c.type = OrthancPluginConstraintType_SmallerOrEqual; | |
530 break; | |
531 | |
532 case Orthanc::DatabasePluginMessages::CONSTRAINT_GREATER_OR_EQUAL: | |
533 c.type = OrthancPluginConstraintType_GreaterOrEqual; | |
534 break; | |
535 | |
536 case Orthanc::DatabasePluginMessages::CONSTRAINT_WILDCARD: | |
537 c.type = OrthancPluginConstraintType_Wildcard; | |
538 break; | |
539 | |
540 case Orthanc::DatabasePluginMessages::CONSTRAINT_LIST: | |
541 c.type = OrthancPluginConstraintType_List; | |
542 break; | |
543 | |
544 default: | |
545 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); | |
546 } | |
547 | |
548 c.valuesCount = constraint.values().size(); | |
549 | |
550 if (c.valuesCount == 0) | |
551 { | |
552 c.values = NULL; | |
553 } | |
554 else | |
555 { | |
556 c.values = &values[values.size()]; | |
557 | |
558 for (int j = 0; j < constraint.values().size(); j++) | |
559 { | |
560 assert(values.size() < countValues); | |
561 values.push_back(constraint.values(j).c_str()); | |
562 } | |
563 } | |
564 | |
565 lookup.push_back(Orthanc::DatabaseConstraint(c)); | |
566 } | |
567 | |
568 assert(values.size() == countValues); | |
569 | |
570 Output output(response); | |
571 backend.LookupResources(output, manager, lookup, Convert(request.query_level()), | |
572 request.limit(), request.retrieve_instances_ids()); | |
573 } | |
574 | |
575 | |
576 static void ProcessTransactionOperation(Orthanc::DatabasePluginMessages::TransactionResponse& response, | |
577 const Orthanc::DatabasePluginMessages::TransactionRequest& request, | |
578 IndexBackend& backend, | |
579 DatabaseManager& manager) | |
580 { | |
581 switch (request.operation()) | |
582 { | |
583 case Orthanc::DatabasePluginMessages::OPERATION_ROLLBACK: | |
584 { | |
585 manager.RollbackTransaction(); | |
586 break; | |
587 } | |
588 | |
589 case Orthanc::DatabasePluginMessages::OPERATION_COMMIT: | |
590 { | |
591 manager.CommitTransaction(); | |
592 break; | |
593 } | |
594 | |
595 case Orthanc::DatabasePluginMessages::OPERATION_ADD_ATTACHMENT: | |
596 { | |
597 OrthancPluginAttachment attachment; | |
598 attachment.uuid = request.add_attachment().attachment().uuid().c_str(); | |
599 attachment.contentType = request.add_attachment().attachment().content_type(); | |
600 attachment.uncompressedSize = request.add_attachment().attachment().uncompressed_size(); | |
601 attachment.uncompressedHash = request.add_attachment().attachment().uncompressed_hash().c_str(); | |
602 attachment.compressionType = request.add_attachment().attachment().compression_type(); | |
603 attachment.compressedSize = request.add_attachment().attachment().compressed_size(); | |
604 attachment.compressedHash = request.add_attachment().attachment().compressed_hash().c_str(); | |
605 | |
606 backend.AddAttachment(manager, request.add_attachment().id(), attachment, request.add_attachment().revision()); | |
607 break; | |
608 } | |
609 | |
610 case Orthanc::DatabasePluginMessages::OPERATION_CLEAR_CHANGES: | |
611 { | |
612 backend.ClearChanges(manager); | |
613 break; | |
614 } | |
615 | |
616 case Orthanc::DatabasePluginMessages::OPERATION_CLEAR_EXPORTED_RESOURCES: | |
617 { | |
618 backend.ClearExportedResources(manager); | |
619 break; | |
620 } | |
621 | |
622 case Orthanc::DatabasePluginMessages::OPERATION_DELETE_ATTACHMENT: | |
623 { | |
624 Output output(*response.mutable_delete_attachment()); | |
625 backend.DeleteAttachment(output, manager, request.delete_attachment().id(), request.delete_attachment().type()); | |
626 break; | |
627 } | |
628 | |
629 case Orthanc::DatabasePluginMessages::OPERATION_DELETE_METADATA: | |
630 { | |
631 backend.DeleteMetadata(manager, request.delete_metadata().id(), request.delete_metadata().type()); | |
632 break; | |
633 } | |
634 | |
635 case Orthanc::DatabasePluginMessages::OPERATION_DELETE_RESOURCE: | |
636 { | |
637 response.mutable_delete_resource()->set_is_remaining_ancestor(false); | |
638 | |
639 Output output(*response.mutable_delete_resource()); | |
640 backend.DeleteResource(output, manager, request.delete_resource().id()); | |
641 break; | |
642 } | |
643 | |
644 case Orthanc::DatabasePluginMessages::OPERATION_GET_ALL_METADATA: | |
645 { | |
646 typedef std::map<int32_t, std::string> Values; | |
647 | |
648 Values values; | |
649 backend.GetAllMetadata(values, manager, request.get_all_metadata().id()); | |
650 | |
651 response.mutable_get_all_metadata()->mutable_metadata()->Reserve(values.size()); | |
652 for (Values::const_iterator it = values.begin(); it != values.end(); ++it) | |
653 { | |
654 Orthanc::DatabasePluginMessages::GetAllMetadata_Response_Metadata* metadata = | |
655 response.mutable_get_all_metadata()->add_metadata(); | |
656 metadata->set_type(it->first); | |
657 metadata->set_value(it->second); | |
658 } | |
659 | |
660 break; | |
661 } | |
662 | |
663 case Orthanc::DatabasePluginMessages::OPERATION_GET_ALL_PUBLIC_IDS: | |
664 { | |
665 std::list<std::string> values; | |
666 backend.GetAllPublicIds(values, manager, Convert(request.get_all_public_ids().resource_type())); | |
667 | |
668 response.mutable_get_all_public_ids()->mutable_ids()->Reserve(values.size()); | |
669 for (std::list<std::string>::const_iterator it = values.begin(); it != values.end(); ++it) | |
670 { | |
671 response.mutable_get_all_public_ids()->add_ids(*it); | |
672 } | |
673 | |
674 break; | |
675 } | |
676 | |
677 case Orthanc::DatabasePluginMessages::OPERATION_GET_ALL_PUBLIC_IDS_WITH_LIMITS: | |
678 { | |
679 std::list<std::string> values; | |
680 backend.GetAllPublicIds(values, manager, Convert(request.get_all_public_ids_with_limits().resource_type()), | |
681 request.get_all_public_ids_with_limits().since(), | |
682 request.get_all_public_ids_with_limits().limit()); | |
683 | |
684 response.mutable_get_all_public_ids_with_limits()->mutable_ids()->Reserve(values.size()); | |
685 for (std::list<std::string>::const_iterator it = values.begin(); it != values.end(); ++it) | |
686 { | |
687 response.mutable_get_all_public_ids_with_limits()->add_ids(*it); | |
688 } | |
689 | |
690 break; | |
691 } | |
692 | |
693 case Orthanc::DatabasePluginMessages::OPERATION_GET_CHANGES: | |
694 { | |
695 Output output(*response.mutable_get_changes()); | |
696 | |
697 bool done; | |
698 backend.GetChanges(output, done, manager, request.get_changes().since(), request.get_changes().limit()); | |
699 | |
700 response.mutable_get_changes()->set_done(done); | |
701 break; | |
702 } | |
703 | |
704 case Orthanc::DatabasePluginMessages::OPERATION_GET_CHILDREN_INTERNAL_ID: | |
705 { | |
706 std::list<int64_t> values; | |
707 backend.GetChildrenInternalId(values, manager, request.get_children_internal_id().id()); | |
708 | |
709 response.mutable_get_children_internal_id()->mutable_ids()->Reserve(values.size()); | |
710 for (std::list<int64_t>::const_iterator it = values.begin(); it != values.end(); ++it) | |
711 { | |
712 response.mutable_get_children_internal_id()->add_ids(*it); | |
713 } | |
714 | |
715 break; | |
716 } | |
717 | |
718 case Orthanc::DatabasePluginMessages::OPERATION_GET_CHILDREN_PUBLIC_ID: | |
719 { | |
720 std::list<std::string> values; | |
721 backend.GetChildrenPublicId(values, manager, request.get_children_public_id().id()); | |
722 | |
723 response.mutable_get_children_public_id()->mutable_ids()->Reserve(values.size()); | |
724 for (std::list<std::string>::const_iterator it = values.begin(); it != values.end(); ++it) | |
725 { | |
726 response.mutable_get_children_public_id()->add_ids(*it); | |
727 } | |
728 | |
729 break; | |
730 } | |
731 | |
732 case Orthanc::DatabasePluginMessages::OPERATION_GET_EXPORTED_RESOURCES: | |
733 { | |
734 Output output(*response.mutable_get_exported_resources()); | |
735 | |
736 bool done; | |
737 backend.GetExportedResources(output, done, manager, request.get_exported_resources().since(), | |
738 request.get_exported_resources().limit()); | |
739 | |
740 response.mutable_get_exported_resources()->set_done(done); | |
741 break; | |
742 } | |
743 | |
744 case Orthanc::DatabasePluginMessages::OPERATION_GET_LAST_CHANGE: | |
745 { | |
746 response.mutable_get_last_change()->set_found(false); | |
747 | |
748 Output output(*response.mutable_get_last_change()); | |
749 backend.GetLastChange(output, manager); | |
750 break; | |
751 } | |
752 | |
753 case Orthanc::DatabasePluginMessages::OPERATION_GET_LAST_EXPORTED_RESOURCE: | |
754 { | |
755 response.mutable_get_last_exported_resource()->set_found(false); | |
756 | |
757 Output output(*response.mutable_get_last_exported_resource()); | |
758 backend.GetLastExportedResource(output, manager); | |
759 break; | |
760 } | |
761 | |
762 case Orthanc::DatabasePluginMessages::OPERATION_GET_MAIN_DICOM_TAGS: | |
763 { | |
764 Output output(*response.mutable_get_main_dicom_tags()); | |
765 backend.GetMainDicomTags(output, manager, request.get_main_dicom_tags().id()); | |
766 break; | |
767 } | |
768 | |
769 case Orthanc::DatabasePluginMessages::OPERATION_GET_PUBLIC_ID: | |
770 { | |
771 const std::string id = backend.GetPublicId(manager, request.get_public_id().id()); | |
772 response.mutable_get_public_id()->set_id(id); | |
773 break; | |
774 } | |
775 | |
776 case Orthanc::DatabasePluginMessages::OPERATION_GET_RESOURCES_COUNT: | |
777 { | |
778 OrthancPluginResourceType type = Convert(request.get_resources_count().type()); | |
779 uint64_t count = backend.GetResourcesCount(manager, type); | |
780 response.mutable_get_resources_count()->set_count(count); | |
781 break; | |
782 } | |
783 | |
784 case Orthanc::DatabasePluginMessages::OPERATION_GET_RESOURCE_TYPE: | |
785 { | |
786 OrthancPluginResourceType type = backend.GetResourceType(manager, request.get_resource_type().id()); | |
787 response.mutable_get_resource_type()->set_type(Convert(type)); | |
788 break; | |
789 } | |
790 | |
791 case Orthanc::DatabasePluginMessages::OPERATION_GET_TOTAL_COMPRESSED_SIZE: | |
792 { | |
793 response.mutable_get_total_compressed_size()->set_size(backend.GetTotalCompressedSize(manager)); | |
794 break; | |
795 } | |
796 | |
797 case Orthanc::DatabasePluginMessages::OPERATION_GET_TOTAL_UNCOMPRESSED_SIZE: | |
798 { | |
799 response.mutable_get_total_uncompressed_size()->set_size(backend.GetTotalUncompressedSize(manager)); | |
800 break; | |
801 } | |
802 | |
803 case Orthanc::DatabasePluginMessages::OPERATION_IS_PROTECTED_PATIENT: | |
804 { | |
805 bool isProtected = backend.IsProtectedPatient(manager, request.is_protected_patient().patient_id()); | |
806 response.mutable_is_protected_patient()->set_protected_patient(isProtected); | |
807 break; | |
808 } | |
809 | |
810 case Orthanc::DatabasePluginMessages::OPERATION_LIST_AVAILABLE_ATTACHMENTS: | |
811 { | |
812 std::list<int32_t> values; | |
813 backend.ListAvailableAttachments(values, manager, request.list_available_attachments().id()); | |
814 | |
815 response.mutable_list_available_attachments()->mutable_attachments()->Reserve(values.size()); | |
816 for (std::list<int32_t>::const_iterator it = values.begin(); it != values.end(); ++it) | |
817 { | |
818 response.mutable_list_available_attachments()->add_attachments(*it); | |
819 } | |
820 | |
821 break; | |
822 } | |
823 | |
824 case Orthanc::DatabasePluginMessages::OPERATION_LOG_CHANGE: | |
825 { | |
826 backend.LogChange(manager, request.log_change().change_type(), | |
827 request.log_change().resource_id(), | |
828 Convert(request.log_change().resource_type()), | |
829 request.log_change().date().c_str()); | |
830 break; | |
831 } | |
832 | |
833 case Orthanc::DatabasePluginMessages::OPERATION_LOG_EXPORTED_RESOURCE: | |
834 { | |
835 backend.LogExportedResource(manager, | |
836 Convert(request.log_exported_resource().resource_type()), | |
837 request.log_exported_resource().public_id().c_str(), | |
838 request.log_exported_resource().modality().c_str(), | |
839 request.log_exported_resource().date().c_str(), | |
840 request.log_exported_resource().patient_id().c_str(), | |
841 request.log_exported_resource().study_instance_uid().c_str(), | |
842 request.log_exported_resource().series_instance_uid().c_str(), | |
843 request.log_exported_resource().sop_instance_uid().c_str()); | |
844 break; | |
845 } | |
846 | |
847 case Orthanc::DatabasePluginMessages::OPERATION_LOOKUP_ATTACHMENT: | |
848 { | |
849 Output output(*response.mutable_lookup_attachment()); | |
850 | |
851 int64_t revision = -1; | |
852 backend.LookupAttachment(output, revision, manager, request.lookup_attachment().id(), request.lookup_attachment().content_type()); | |
853 | |
854 if (response.lookup_attachment().found()) | |
855 { | |
856 response.mutable_lookup_attachment()->set_revision(revision); | |
857 } | |
858 | |
859 break; | |
860 } | |
861 | |
862 case Orthanc::DatabasePluginMessages::OPERATION_LOOKUP_GLOBAL_PROPERTY: | |
863 { | |
864 std::string value; | |
865 if (backend.LookupGlobalProperty(value, manager, request.lookup_global_property().server_id().c_str(), | |
866 request.lookup_global_property().property())) | |
867 { | |
868 response.mutable_lookup_global_property()->set_found(true); | |
869 response.mutable_lookup_global_property()->set_value(value); | |
870 } | |
871 else | |
872 { | |
873 response.mutable_lookup_global_property()->set_found(false); | |
874 } | |
875 | |
876 break; | |
877 } | |
878 | |
879 case Orthanc::DatabasePluginMessages::OPERATION_LOOKUP_METADATA: | |
880 { | |
881 std::string value; | |
882 int64_t revision = -1; | |
883 if (backend.LookupMetadata(value, revision, manager, request.lookup_metadata().id(), request.lookup_metadata().metadata_type())) | |
884 { | |
885 response.mutable_lookup_metadata()->set_found(true); | |
886 response.mutable_lookup_metadata()->set_value(value); | |
887 response.mutable_lookup_metadata()->set_revision(revision); | |
888 } | |
889 else | |
890 { | |
891 response.mutable_lookup_metadata()->set_found(false); | |
892 } | |
893 | |
894 break; | |
895 } | |
896 | |
897 case Orthanc::DatabasePluginMessages::OPERATION_LOOKUP_PARENT: | |
898 { | |
899 int64_t parent = -1; | |
900 if (backend.LookupParent(parent, manager, request.lookup_parent().id())) | |
901 { | |
902 response.mutable_lookup_parent()->set_found(true); | |
903 response.mutable_lookup_parent()->set_parent(parent); | |
904 } | |
905 else | |
906 { | |
907 response.mutable_lookup_parent()->set_found(false); | |
908 } | |
909 | |
910 break; | |
911 } | |
912 | |
913 case Orthanc::DatabasePluginMessages::OPERATION_LOOKUP_RESOURCE: | |
914 { | |
915 int64_t internalId = -1; | |
916 OrthancPluginResourceType type; | |
917 if (backend.LookupResource(internalId, type, manager, request.lookup_resource().public_id().c_str())) | |
918 { | |
919 response.mutable_lookup_resource()->set_found(true); | |
920 response.mutable_lookup_resource()->set_internal_id(internalId); | |
921 response.mutable_lookup_resource()->set_type(Convert(type)); | |
922 } | |
923 else | |
924 { | |
925 response.mutable_lookup_resource()->set_found(false); | |
926 } | |
927 | |
928 break; | |
929 } | |
930 | |
931 case Orthanc::DatabasePluginMessages::OPERATION_SELECT_PATIENT_TO_RECYCLE: | |
932 { | |
933 int64_t patientId = -1; | |
934 if (backend.SelectPatientToRecycle(patientId, manager)) | |
935 { | |
936 response.mutable_select_patient_to_recycle()->set_found(true); | |
937 response.mutable_select_patient_to_recycle()->set_patient_id(patientId); | |
938 } | |
939 else | |
940 { | |
941 response.mutable_select_patient_to_recycle()->set_found(false); | |
942 } | |
943 | |
944 break; | |
945 } | |
946 | |
947 case Orthanc::DatabasePluginMessages::OPERATION_SELECT_PATIENT_TO_RECYCLE_WITH_AVOID: | |
948 { | |
949 int64_t patientId = -1; | |
950 if (backend.SelectPatientToRecycle(patientId, manager, request.select_patient_to_recycle_with_avoid().patient_id_to_avoid())) | |
951 { | |
952 response.mutable_select_patient_to_recycle_with_avoid()->set_found(true); | |
953 response.mutable_select_patient_to_recycle_with_avoid()->set_patient_id(patientId); | |
954 } | |
955 else | |
956 { | |
957 response.mutable_select_patient_to_recycle_with_avoid()->set_found(false); | |
958 } | |
959 | |
960 break; | |
961 } | |
962 | |
963 case Orthanc::DatabasePluginMessages::OPERATION_SET_GLOBAL_PROPERTY: | |
964 { | |
965 backend.SetGlobalProperty(manager, request.set_global_property().server_id().c_str(), | |
966 request.set_global_property().property(), | |
967 request.set_global_property().value().c_str()); | |
968 break; | |
969 } | |
970 | |
971 case Orthanc::DatabasePluginMessages::OPERATION_CLEAR_MAIN_DICOM_TAGS: | |
972 { | |
973 backend.ClearMainDicomTags(manager, request.clear_main_dicom_tags().id()); | |
974 break; | |
975 } | |
976 | |
977 case Orthanc::DatabasePluginMessages::OPERATION_SET_METADATA: | |
978 { | |
979 backend.SetMetadata(manager, request.set_metadata().id(), | |
980 request.set_metadata().metadata_type(), | |
981 request.set_metadata().value().c_str(), | |
982 request.set_metadata().revision()); | |
983 break; | |
984 } | |
985 | |
986 case Orthanc::DatabasePluginMessages::OPERATION_SET_PROTECTED_PATIENT: | |
987 { | |
988 backend.SetProtectedPatient(manager, request.set_protected_patient().patient_id(), | |
989 request.set_protected_patient().protected_patient()); | |
990 break; | |
991 } | |
992 | |
993 case Orthanc::DatabasePluginMessages::OPERATION_IS_DISK_SIZE_ABOVE: | |
994 { | |
995 bool above = (backend.GetTotalCompressedSize(manager) >= request.is_disk_size_above().threshold()); | |
996 response.mutable_is_disk_size_above()->set_result(above); | |
997 break; | |
998 } | |
999 | |
1000 case Orthanc::DatabasePluginMessages::OPERATION_LOOKUP_RESOURCES: | |
1001 { | |
1002 ApplyLookupResources(*response.mutable_lookup_resources(), request.lookup_resources(), backend, manager); | |
1003 break; | |
1004 } | |
1005 | |
1006 case Orthanc::DatabasePluginMessages::OPERATION_CREATE_INSTANCE: | |
1007 { | |
1008 const char* hashPatient = request.create_instance().patient().c_str(); | |
1009 const char* hashStudy = request.create_instance().study().c_str(); | |
1010 const char* hashSeries = request.create_instance().series().c_str(); | |
1011 const char* hashInstance = request.create_instance().instance().c_str(); | |
1012 | |
1013 OrthancPluginCreateInstanceResult result; | |
1014 | |
1015 if (backend.HasCreateInstance()) | |
1016 { | |
1017 backend.CreateInstance(result, manager, hashPatient, hashStudy, hashSeries, hashInstance); | |
1018 } | |
1019 else | |
1020 { | |
1021 backend.CreateInstanceGeneric(result, manager, hashPatient, hashStudy, hashSeries, hashInstance); | |
1022 } | |
1023 | |
1024 response.mutable_create_instance()->set_is_new_instance(result.isNewInstance); | |
1025 response.mutable_create_instance()->set_instance_id(result.instanceId); | |
1026 | |
1027 if (result.isNewInstance) | |
1028 { | |
1029 response.mutable_create_instance()->set_is_new_patient(result.isNewPatient); | |
1030 response.mutable_create_instance()->set_is_new_study(result.isNewStudy); | |
1031 response.mutable_create_instance()->set_is_new_series(result.isNewSeries); | |
1032 response.mutable_create_instance()->set_patient_id(result.patientId); | |
1033 response.mutable_create_instance()->set_study_id(result.studyId); | |
1034 response.mutable_create_instance()->set_series_id(result.seriesId); | |
1035 } | |
1036 | |
1037 break; | |
1038 } | |
1039 | |
1040 case Orthanc::DatabasePluginMessages::OPERATION_SET_RESOURCES_CONTENT: | |
1041 { | |
1042 std::vector<OrthancPluginResourcesContentTags> identifierTags; | |
1043 std::vector<OrthancPluginResourcesContentTags> mainDicomTags; | |
1044 | |
1045 identifierTags.reserve(request.set_resources_content().tags().size()); | |
1046 mainDicomTags.reserve(request.set_resources_content().tags().size()); | |
1047 | |
1048 for (int i = 0; i < request.set_resources_content().tags().size(); i++) | |
1049 { | |
1050 if (request.set_resources_content().tags(i).group() > 0xffffu || | |
1051 request.set_resources_content().tags(i).element() > 0xffffu) | |
1052 { | |
1053 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); | |
1054 } | |
1055 | |
1056 OrthancPluginResourcesContentTags tag; | |
1057 tag.resource = request.set_resources_content().tags(i).resource_id(); | |
1058 tag.group = request.set_resources_content().tags(i).group(); | |
1059 tag.element = request.set_resources_content().tags(i).element(); | |
1060 tag.value = request.set_resources_content().tags(i).value().c_str(); | |
1061 | |
1062 if (request.set_resources_content().tags(i).is_identifier()) | |
1063 { | |
1064 identifierTags.push_back(tag); | |
1065 } | |
1066 else | |
1067 { | |
1068 mainDicomTags.push_back(tag); | |
1069 } | |
1070 } | |
1071 | |
1072 std::vector<OrthancPluginResourcesContentMetadata> metadata; | |
1073 metadata.reserve(request.set_resources_content().metadata().size()); | |
1074 | |
1075 for (int i = 0; i < request.set_resources_content().metadata().size(); i++) | |
1076 { | |
1077 OrthancPluginResourcesContentMetadata item; | |
1078 item.resource = request.set_resources_content().metadata(i).resource_id(); | |
1079 item.metadata = request.set_resources_content().metadata(i).metadata(); | |
1080 item.value = request.set_resources_content().metadata(i).value().c_str(); | |
1081 metadata.push_back(item); | |
1082 } | |
1083 | |
1084 backend.SetResourcesContent(manager, | |
1085 identifierTags.size(), (identifierTags.empty() ? NULL : &identifierTags[0]), | |
1086 mainDicomTags.size(), (mainDicomTags.empty() ? NULL : &mainDicomTags[0]), | |
1087 metadata.size(), (metadata.empty() ? NULL : &metadata[0])); | |
1088 break; | |
1089 } | |
1090 | |
1091 case Orthanc::DatabasePluginMessages::OPERATION_GET_CHILDREN_METADATA: | |
1092 { | |
1093 std::list<std::string> values; | |
1094 backend.GetChildrenMetadata(values, manager, request.get_children_metadata().id(), request.get_children_metadata().metadata()); | |
1095 | |
1096 response.mutable_get_children_metadata()->mutable_values()->Reserve(values.size()); | |
1097 for (std::list<std::string>::const_iterator it = values.begin(); it != values.end(); ++it) | |
1098 { | |
1099 response.mutable_get_children_metadata()->add_values(*it); | |
1100 } | |
1101 | |
1102 break; | |
1103 } | |
1104 | |
1105 case Orthanc::DatabasePluginMessages::OPERATION_GET_LAST_CHANGE_INDEX: | |
1106 { | |
1107 response.mutable_get_last_change_index()->set_result(backend.GetLastChangeIndex(manager)); | |
1108 break; | |
1109 } | |
1110 | |
1111 case Orthanc::DatabasePluginMessages::OPERATION_LOOKUP_RESOURCE_AND_PARENT: | |
1112 { | |
1113 int64_t id; | |
1114 OrthancPluginResourceType type; | |
1115 std::string parent; | |
1116 | |
1117 if (backend.LookupResourceAndParent(id, type, parent, manager, request.lookup_resource_and_parent().public_id().c_str())) | |
1118 { | |
1119 response.mutable_lookup_resource_and_parent()->set_found(true); | |
1120 response.mutable_lookup_resource_and_parent()->set_id(id); | |
1121 response.mutable_lookup_resource_and_parent()->set_type(Convert(type)); | |
1122 | |
1123 switch (type) | |
1124 { | |
1125 case OrthancPluginResourceType_Study: | |
1126 case OrthancPluginResourceType_Series: | |
1127 case OrthancPluginResourceType_Instance: | |
1128 if (parent.empty()) | |
1129 { | |
1130 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); | |
1131 } | |
1132 else | |
1133 { | |
1134 response.mutable_lookup_resource_and_parent()->set_parent_public_id(parent); | |
1135 } | |
1136 break; | |
1137 | |
1138 case OrthancPluginResourceType_Patient: | |
1139 if (!parent.empty()) | |
1140 { | |
1141 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); | |
1142 } | |
1143 break; | |
1144 | |
1145 default: | |
1146 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); | |
1147 } | |
1148 } | |
1149 else | |
1150 { | |
1151 response.mutable_lookup_resource_and_parent()->set_found(false); | |
1152 } | |
1153 | |
1154 break; | |
1155 } | |
1156 | |
1157 default: | |
1158 LOG(ERROR) << "Not implemented transaction operation from protobuf: " << request.operation(); | |
1159 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); | |
1160 } | |
1161 } | |
1162 | |
1163 | |
1164 static OrthancPluginErrorCode CallBackend(OrthancPluginMemoryBuffer64* serializedResponse, | |
1165 void* rawPool, | |
1166 const void* requestData, | |
1167 uint64_t requestSize) | |
1168 { | |
1169 Orthanc::DatabasePluginMessages::Request request; | |
1170 if (!request.ParseFromArray(requestData, requestSize)) | |
1171 { | |
1172 LOG(ERROR) << "Cannot parse message from the Orthanc core using protobuf"; | |
1173 return OrthancPluginErrorCode_InternalError; | |
1174 } | |
1175 | |
1176 if (rawPool == NULL) | |
1177 { | |
1178 LOG(ERROR) << "Received a NULL pointer from the database"; | |
1179 return OrthancPluginErrorCode_InternalError; | |
1180 } | |
1181 | |
1182 IndexConnectionsPool& pool = *reinterpret_cast<IndexConnectionsPool*>(rawPool); | |
1183 | |
1184 try | |
1185 { | |
1186 Orthanc::DatabasePluginMessages::Response response; | |
1187 | |
1188 switch (request.type()) | |
1189 { | |
1190 case Orthanc::DatabasePluginMessages::REQUEST_DATABASE: | |
1191 ProcessDatabaseOperation(*response.mutable_database_response(), request.database_request(), pool); | |
1192 break; | |
1193 | |
1194 case Orthanc::DatabasePluginMessages::REQUEST_TRANSACTION: | |
1195 { | |
1196 IndexConnectionsPool::Accessor& transaction = *reinterpret_cast<IndexConnectionsPool::Accessor*>(request.transaction_request().transaction()); | |
1197 ProcessTransactionOperation(*response.mutable_transaction_response(), request.transaction_request(), | |
1198 transaction.GetBackend(), transaction.GetManager()); | |
1199 break; | |
1200 } | |
1201 | |
1202 default: | |
1203 LOG(ERROR) << "Not implemented request type from protobuf: " << request.type(); | |
1204 break; | |
1205 } | |
1206 | |
1207 std::string s; | |
1208 if (!response.SerializeToString(&s)) | |
1209 { | |
1210 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError, "Cannot serialize to protobuf"); | |
1211 } | |
1212 | |
1213 if (OrthancPluginCreateMemoryBuffer64(pool.GetContext(), serializedResponse, s.size()) != OrthancPluginErrorCode_Success) | |
1214 { | |
1215 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotEnoughMemory, "Cannot allocate a memory buffer"); | |
1216 } | |
1217 | |
1218 if (!s.empty()) | |
1219 { | |
1220 assert(serializedResponse->size == s.size()); | |
1221 memcpy(serializedResponse->data, s.c_str(), s.size()); | |
1222 } | |
1223 | |
1224 return OrthancPluginErrorCode_Success; | |
1225 } | |
1226 catch (::Orthanc::OrthancException& e) | |
1227 { | |
1228 LOG(ERROR) << "Exception in database back-end: " << e.What(); | |
1229 return static_cast<OrthancPluginErrorCode>(e.GetErrorCode()); | |
1230 } | |
1231 catch (::std::runtime_error& e) | |
1232 { | |
1233 LOG(ERROR) << "Exception in database back-end: " << e.what(); | |
1234 return OrthancPluginErrorCode_DatabasePlugin; | |
1235 } | |
1236 catch (...) | |
1237 { | |
1238 LOG(ERROR) << "Native exception"; | |
1239 return OrthancPluginErrorCode_DatabasePlugin; | |
1240 } | |
1241 } | |
1242 | |
1243 static void FinalizeBackend(void* rawPool) | |
1244 { | |
1245 if (rawPool != NULL) | |
1246 { | |
1247 IndexConnectionsPool* pool = reinterpret_cast<IndexConnectionsPool*>(rawPool); | |
1248 | |
1249 if (isBackendInUse_) | |
1250 { | |
1251 isBackendInUse_ = false; | |
1252 } | |
1253 else | |
1254 { | |
1255 LOG(ERROR) << "More than one index backend was registered, internal error"; | |
1256 } | |
1257 | |
1258 delete pool; | |
1259 } | |
1260 else | |
1261 { | |
1262 LOG(ERROR) << "Received a null pointer from the Orthanc core, internal error"; | |
1263 } | |
1264 } | |
1265 | |
1266 | |
1267 void DatabaseBackendAdapterV4::Register(IndexBackend* backend, | |
1268 size_t countConnections, | |
1269 unsigned int maxDatabaseRetries) | |
1270 { | |
1271 std::unique_ptr<IndexConnectionsPool> pool(new IndexConnectionsPool(backend, countConnections)); | |
1272 | |
1273 if (isBackendInUse_) | |
1274 { | |
1275 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | |
1276 } | |
1277 | |
1278 OrthancPluginContext* context = backend->GetContext(); | |
1279 | |
1280 if (OrthancPluginRegisterDatabaseBackendV4(context, pool.release(), maxDatabaseRetries, | |
1281 CallBackend, FinalizeBackend) != OrthancPluginErrorCode_Success) | |
1282 { | |
1283 delete backend; | |
1284 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError, "Unable to register the database backend"); | |
1285 } | |
1286 | |
1287 isBackendInUse_ = true; | |
1288 } | |
1289 | |
1290 | |
1291 void DatabaseBackendAdapterV4::Finalize() | |
1292 { | |
1293 if (isBackendInUse_) | |
1294 { | |
1295 LOG(ERROR) << "The Orthanc core has not destructed the index backend, internal error"; | |
1296 } | |
1297 } | |
1298 } | |
1299 | |
1300 # endif | |
1301 #endif |