Mercurial > hg > orthanc
comparison Plugins/Engine/OrthancPlugins.cpp @ 1995:f0acfa753973
New callback to handle non-worklists C-Find requests: OrthancPluginRegisterCFindCallback()
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Tue, 24 May 2016 17:45:56 +0200 |
parents | ce90d109bb64 |
children | 364cc624eb65 |
comparison
equal
deleted
inserted
replaced
1994:4d099fee5eca | 1995:f0acfa753973 |
---|---|
37 #error The plugin support is disabled | 37 #error The plugin support is disabled |
38 #endif | 38 #endif |
39 | 39 |
40 | 40 |
41 #include "../../Core/ChunkedBuffer.h" | 41 #include "../../Core/ChunkedBuffer.h" |
42 #include "../../Core/DicomFormat/DicomArray.h" | |
42 #include "../../Core/HttpServer/HttpToolbox.h" | 43 #include "../../Core/HttpServer/HttpToolbox.h" |
43 #include "../../Core/Logging.h" | 44 #include "../../Core/Logging.h" |
44 #include "../../Core/OrthancException.h" | 45 #include "../../Core/OrthancException.h" |
45 #include "../../Core/Toolbox.h" | 46 #include "../../Core/Toolbox.h" |
46 #include "../../OrthancServer/FromDcmtkBridge.h" | 47 #include "../../OrthancServer/FromDcmtkBridge.h" |
105 CopyToMemoryBuffer(target, str.c_str(), str.size()); | 106 CopyToMemoryBuffer(target, str.c_str(), str.size()); |
106 } | 107 } |
107 } | 108 } |
108 | 109 |
109 | 110 |
111 static char* CopyString(const std::string& str) | |
112 { | |
113 char *result = reinterpret_cast<char*>(malloc(str.size() + 1)); | |
114 if (result == NULL) | |
115 { | |
116 throw OrthancException(ErrorCode_NotEnoughMemory); | |
117 } | |
118 | |
119 if (str.size() == 0) | |
120 { | |
121 result[0] = '\0'; | |
122 } | |
123 else | |
124 { | |
125 memcpy(result, &str[0], str.size() + 1); | |
126 } | |
127 | |
128 return result; | |
129 } | |
130 | |
131 | |
110 namespace | 132 namespace |
111 { | 133 { |
112 class PluginStorageArea : public IStorageArea | 134 class PluginStorageArea : public IStorageArea |
113 { | 135 { |
114 private: | 136 private: |
289 PluginsManager manager_; | 311 PluginsManager manager_; |
290 ServerContext* context_; | 312 ServerContext* context_; |
291 RestCallbacks restCallbacks_; | 313 RestCallbacks restCallbacks_; |
292 OnStoredCallbacks onStoredCallbacks_; | 314 OnStoredCallbacks onStoredCallbacks_; |
293 OnChangeCallbacks onChangeCallbacks_; | 315 OnChangeCallbacks onChangeCallbacks_; |
316 OrthancPluginFindCallback findCallback_; | |
294 OrthancPluginWorklistCallback worklistCallback_; | 317 OrthancPluginWorklistCallback worklistCallback_; |
295 OrthancPluginDecodeImageCallback decodeImageCallback_; | 318 OrthancPluginDecodeImageCallback decodeImageCallback_; |
296 IncomingHttpRequestFilters incomingHttpRequestFilters_; | 319 IncomingHttpRequestFilters incomingHttpRequestFilters_; |
297 std::auto_ptr<StorageAreaFactory> storageArea_; | 320 std::auto_ptr<StorageAreaFactory> storageArea_; |
298 boost::recursive_mutex restCallbackMutex_; | 321 boost::recursive_mutex restCallbackMutex_; |
299 boost::recursive_mutex storedCallbackMutex_; | 322 boost::recursive_mutex storedCallbackMutex_; |
300 boost::recursive_mutex changeCallbackMutex_; | 323 boost::recursive_mutex changeCallbackMutex_; |
324 boost::mutex findCallbackMutex_; | |
301 boost::mutex worklistCallbackMutex_; | 325 boost::mutex worklistCallbackMutex_; |
302 boost::mutex decodeImageCallbackMutex_; | 326 boost::mutex decodeImageCallbackMutex_; |
303 boost::recursive_mutex invokeServiceMutex_; | 327 boost::recursive_mutex invokeServiceMutex_; |
304 Properties properties_; | 328 Properties properties_; |
305 int argc_; | 329 int argc_; |
307 std::auto_ptr<OrthancPluginDatabase> database_; | 331 std::auto_ptr<OrthancPluginDatabase> database_; |
308 PluginsErrorDictionary dictionary_; | 332 PluginsErrorDictionary dictionary_; |
309 | 333 |
310 PImpl() : | 334 PImpl() : |
311 context_(NULL), | 335 context_(NULL), |
336 findCallback_(NULL), | |
312 worklistCallback_(NULL), | 337 worklistCallback_(NULL), |
313 decodeImageCallback_(NULL), | 338 decodeImageCallback_(NULL), |
314 argc_(1), | 339 argc_(1), |
315 argv_(NULL) | 340 argv_(NULL) |
316 { | 341 { |
343 const std::string& remoteIp, | 368 const std::string& remoteIp, |
344 const std::string& remoteAet, | 369 const std::string& remoteAet, |
345 const std::string& calledAet) | 370 const std::string& calledAet) |
346 { | 371 { |
347 bool caseSensitivePN = Configuration::GetGlobalBoolParameter("CaseSensitivePN", false); | 372 bool caseSensitivePN = Configuration::GetGlobalBoolParameter("CaseSensitivePN", false); |
348 matcher_.reset(new HierarchicalMatcher(query, caseSensitivePN)); | |
349 currentQuery_ = &query; | |
350 | 373 |
351 { | 374 { |
352 boost::mutex::scoped_lock lock(that_.pimpl_->worklistCallbackMutex_); | 375 boost::mutex::scoped_lock lock(that_.pimpl_->worklistCallbackMutex_); |
376 | |
377 matcher_.reset(new HierarchicalMatcher(query, caseSensitivePN)); | |
378 currentQuery_ = &query; | |
353 | 379 |
354 if (that_.pimpl_->worklistCallback_) | 380 if (that_.pimpl_->worklistCallback_) |
355 { | 381 { |
356 OrthancPluginErrorCode error = that_.pimpl_->worklistCallback_ | 382 OrthancPluginErrorCode error = that_.pimpl_->worklistCallback_ |
357 (reinterpret_cast<OrthancPluginWorklistAnswers*>(&answers), | 383 (reinterpret_cast<OrthancPluginWorklistAnswers*>(&answers), |
364 Reset(); | 390 Reset(); |
365 that_.GetErrorDictionary().LogError(error, true); | 391 that_.GetErrorDictionary().LogError(error, true); |
366 throw OrthancException(static_cast<ErrorCode>(error)); | 392 throw OrthancException(static_cast<ErrorCode>(error)); |
367 } | 393 } |
368 } | 394 } |
369 } | 395 |
370 | 396 Reset(); |
371 Reset(); | 397 } |
372 } | 398 } |
373 | 399 |
374 void GetDicomQuery(OrthancPluginMemoryBuffer& target) const | 400 void GetDicomQuery(OrthancPluginMemoryBuffer& target) const |
375 { | 401 { |
376 assert(currentQuery_ != NULL); | 402 if (currentQuery_ == NULL) |
403 { | |
404 throw OrthancException(ErrorCode_Plugin); | |
405 } | |
406 | |
377 std::string dicom; | 407 std::string dicom; |
378 currentQuery_->SaveToMemoryBuffer(dicom); | 408 currentQuery_->SaveToMemoryBuffer(dicom); |
379 CopyToMemoryBuffer(target, dicom.c_str(), dicom.size()); | 409 CopyToMemoryBuffer(target, dicom.c_str(), dicom.size()); |
380 } | 410 } |
381 | 411 |
382 bool IsMatch(const void* dicom, | 412 bool IsMatch(const void* dicom, |
383 size_t size) const | 413 size_t size) const |
384 { | 414 { |
385 assert(matcher_.get() != NULL); | 415 if (matcher_.get() == NULL) |
416 { | |
417 throw OrthancException(ErrorCode_Plugin); | |
418 } | |
419 | |
386 ParsedDicomFile f(dicom, size); | 420 ParsedDicomFile f(dicom, size); |
387 return matcher_->Match(f); | 421 return matcher_->Match(f); |
388 } | 422 } |
389 | 423 |
390 void AddAnswer(OrthancPluginWorklistAnswers* answers, | 424 void AddAnswer(OrthancPluginWorklistAnswers* answers, |
391 const void* dicom, | 425 const void* dicom, |
392 size_t size) const | 426 size_t size) const |
393 { | 427 { |
394 assert(matcher_.get() != NULL); | 428 if (matcher_.get() == NULL) |
429 { | |
430 throw OrthancException(ErrorCode_Plugin); | |
431 } | |
432 | |
395 ParsedDicomFile f(dicom, size); | 433 ParsedDicomFile f(dicom, size); |
396 std::auto_ptr<ParsedDicomFile> summary(matcher_->Extract(f)); | 434 std::auto_ptr<ParsedDicomFile> summary(matcher_->Extract(f)); |
397 reinterpret_cast<DicomFindAnswers*>(answers)->Add(*summary); | 435 reinterpret_cast<DicomFindAnswers*>(answers)->Add(*summary); |
398 } | 436 } |
399 }; | 437 }; |
400 | 438 |
401 | 439 |
402 static char* CopyString(const std::string& str) | 440 class OrthancPlugins::FindHandler : public IFindRequestHandler |
403 { | 441 { |
404 char *result = reinterpret_cast<char*>(malloc(str.size() + 1)); | 442 private: |
405 if (result == NULL) | 443 OrthancPlugins& that_; |
406 { | 444 std::auto_ptr<DicomArray> currentQuery_; |
407 throw OrthancException(ErrorCode_NotEnoughMemory); | 445 |
408 } | 446 void Reset() |
409 | 447 { |
410 if (str.size() == 0) | 448 currentQuery_.reset(NULL); |
411 { | 449 } |
412 result[0] = '\0'; | 450 |
413 } | 451 public: |
414 else | 452 FindHandler(OrthancPlugins& that) : that_(that) |
415 { | 453 { |
416 memcpy(result, &str[0], str.size() + 1); | 454 Reset(); |
417 } | 455 } |
418 | 456 |
419 return result; | 457 virtual void Handle(DicomFindAnswers& answers, |
420 } | 458 const DicomMap& input, |
459 const std::list<DicomTag>& sequencesToReturn, | |
460 const std::string& remoteIp, | |
461 const std::string& remoteAet, | |
462 const std::string& calledAet) | |
463 { | |
464 DicomMap tmp; | |
465 tmp.Assign(input); | |
466 | |
467 for (std::list<DicomTag>::const_iterator it = sequencesToReturn.begin(); | |
468 it != sequencesToReturn.end(); ++it) | |
469 { | |
470 if (!input.HasTag(*it)) | |
471 { | |
472 tmp.SetValue(*it, ""); | |
473 } | |
474 } | |
475 | |
476 { | |
477 boost::mutex::scoped_lock lock(that_.pimpl_->findCallbackMutex_); | |
478 currentQuery_.reset(new DicomArray(tmp)); | |
479 | |
480 if (that_.pimpl_->findCallback_) | |
481 { | |
482 OrthancPluginErrorCode error = that_.pimpl_->findCallback_ | |
483 (reinterpret_cast<OrthancPluginFindAnswers*>(&answers), | |
484 reinterpret_cast<const OrthancPluginFindQuery*>(this), | |
485 remoteAet.c_str(), | |
486 calledAet.c_str()); | |
487 | |
488 if (error != OrthancPluginErrorCode_Success) | |
489 { | |
490 Reset(); | |
491 that_.GetErrorDictionary().LogError(error, true); | |
492 throw OrthancException(static_cast<ErrorCode>(error)); | |
493 } | |
494 } | |
495 | |
496 Reset(); | |
497 } | |
498 } | |
499 | |
500 void Invoke(_OrthancPluginService service, | |
501 const _OrthancPluginFindOperation& operation) const | |
502 { | |
503 if (currentQuery_.get() == NULL) | |
504 { | |
505 throw OrthancException(ErrorCode_Plugin); | |
506 } | |
507 | |
508 switch (service) | |
509 { | |
510 case _OrthancPluginService_GetFindQuerySize: | |
511 *operation.resultUint32 = currentQuery_->GetSize(); | |
512 break; | |
513 | |
514 case _OrthancPluginService_GetFindQueryTag: | |
515 { | |
516 const DicomTag& tag = currentQuery_->GetElement(operation.index).GetTag(); | |
517 *operation.resultGroup = tag.GetGroup(); | |
518 *operation.resultElement = tag.GetElement(); | |
519 break; | |
520 } | |
521 | |
522 case _OrthancPluginService_GetFindQueryTagName: | |
523 { | |
524 const DicomTag& tag = currentQuery_->GetElement(operation.index).GetTag(); | |
525 *operation.resultString = CopyString(FromDcmtkBridge::GetName(tag)); | |
526 break; | |
527 } | |
528 | |
529 case _OrthancPluginService_GetFindQueryValue: | |
530 { | |
531 *operation.resultString = CopyString(currentQuery_->GetElement(operation.index).GetValue().GetContent()); | |
532 break; | |
533 } | |
534 | |
535 default: | |
536 throw OrthancException(ErrorCode_InternalError); | |
537 } | |
538 } | |
539 }; | |
540 | |
421 | 541 |
422 | 542 |
423 OrthancPlugins::OrthancPlugins() | 543 OrthancPlugins::OrthancPlugins() |
424 { | 544 { |
425 /* Sanity check of the compiler */ | 545 /* Sanity check of the compiler */ |
739 pimpl_->worklistCallback_ = p.callback; | 859 pimpl_->worklistCallback_ = p.callback; |
740 } | 860 } |
741 } | 861 } |
742 | 862 |
743 | 863 |
864 void OrthancPlugins::RegisterFindCallback(const void* parameters) | |
865 { | |
866 const _OrthancPluginFindCallback& p = | |
867 *reinterpret_cast<const _OrthancPluginFindCallback*>(parameters); | |
868 | |
869 boost::mutex::scoped_lock lock(pimpl_->findCallbackMutex_); | |
870 | |
871 if (pimpl_->findCallback_ != NULL) | |
872 { | |
873 LOG(ERROR) << "Can only register one plugin to handle C-FIND requests"; | |
874 throw OrthancException(ErrorCode_Plugin); | |
875 } | |
876 else | |
877 { | |
878 LOG(INFO) << "Plugin has registered a callback to handle C-FIND requests"; | |
879 pimpl_->findCallback_ = p.callback; | |
880 } | |
881 } | |
882 | |
883 | |
744 void OrthancPlugins::RegisterDecodeImageCallback(const void* parameters) | 884 void OrthancPlugins::RegisterDecodeImageCallback(const void* parameters) |
745 { | 885 { |
746 const _OrthancPluginDecodeImageCallback& p = | 886 const _OrthancPluginDecodeImageCallback& p = |
747 *reinterpret_cast<const _OrthancPluginDecodeImageCallback*>(parameters); | 887 *reinterpret_cast<const _OrthancPluginDecodeImageCallback*>(parameters); |
748 | 888 |
1836 | 1976 |
1837 case _OrthancPluginService_RegisterWorklistCallback: | 1977 case _OrthancPluginService_RegisterWorklistCallback: |
1838 RegisterWorklistCallback(parameters); | 1978 RegisterWorklistCallback(parameters); |
1839 return true; | 1979 return true; |
1840 | 1980 |
1981 case _OrthancPluginService_RegisterFindCallback: | |
1982 RegisterFindCallback(parameters); | |
1983 return true; | |
1984 | |
1841 case _OrthancPluginService_RegisterDecodeImageCallback: | 1985 case _OrthancPluginService_RegisterDecodeImageCallback: |
1842 RegisterDecodeImageCallback(parameters); | 1986 RegisterDecodeImageCallback(parameters); |
1843 return true; | 1987 return true; |
1844 | 1988 |
1845 case _OrthancPluginService_RegisterIncomingHttpRequestFilter: | 1989 case _OrthancPluginService_RegisterIncomingHttpRequestFilter: |
2312 *reinterpret_cast<const _OrthancPluginWorklistQueryOperation*>(parameters); | 2456 *reinterpret_cast<const _OrthancPluginWorklistQueryOperation*>(parameters); |
2313 reinterpret_cast<const WorklistHandler*>(p.query)->GetDicomQuery(*p.target); | 2457 reinterpret_cast<const WorklistHandler*>(p.query)->GetDicomQuery(*p.target); |
2314 return true; | 2458 return true; |
2315 } | 2459 } |
2316 | 2460 |
2461 case _OrthancPluginService_FindAddAnswer: | |
2462 { | |
2463 const _OrthancPluginFindOperation& p = | |
2464 *reinterpret_cast<const _OrthancPluginFindOperation*>(parameters); | |
2465 reinterpret_cast<DicomFindAnswers*>(p.answers)->Add(p.dicom, p.size); | |
2466 return true; | |
2467 } | |
2468 | |
2469 case _OrthancPluginService_FindMarkIncomplete: | |
2470 { | |
2471 const _OrthancPluginFindOperation& p = | |
2472 *reinterpret_cast<const _OrthancPluginFindOperation*>(parameters); | |
2473 reinterpret_cast<DicomFindAnswers*>(p.answers)->SetComplete(false); | |
2474 return true; | |
2475 } | |
2476 | |
2477 case _OrthancPluginService_GetFindQuerySize: | |
2478 case _OrthancPluginService_GetFindQueryTag: | |
2479 case _OrthancPluginService_GetFindQueryTagName: | |
2480 case _OrthancPluginService_GetFindQueryValue: | |
2481 { | |
2482 const _OrthancPluginFindOperation& p = | |
2483 *reinterpret_cast<const _OrthancPluginFindOperation*>(parameters); | |
2484 reinterpret_cast<const FindHandler*>(p.query)->Invoke(service, p); | |
2485 return true; | |
2486 } | |
2487 | |
2317 case _OrthancPluginService_CreateImage: | 2488 case _OrthancPluginService_CreateImage: |
2318 case _OrthancPluginService_CreateImageAccessor: | 2489 case _OrthancPluginService_CreateImageAccessor: |
2319 case _OrthancPluginService_DecodeDicomImage: | 2490 case _OrthancPluginService_DecodeDicomImage: |
2320 ApplyCreateImage(service, parameters); | 2491 ApplyCreateImage(service, parameters); |
2321 return true; | 2492 return true; |
2470 | 2641 |
2471 bool OrthancPlugins::HasWorklistHandler() | 2642 bool OrthancPlugins::HasWorklistHandler() |
2472 { | 2643 { |
2473 boost::mutex::scoped_lock lock(pimpl_->worklistCallbackMutex_); | 2644 boost::mutex::scoped_lock lock(pimpl_->worklistCallbackMutex_); |
2474 return pimpl_->worklistCallback_ != NULL; | 2645 return pimpl_->worklistCallback_ != NULL; |
2646 } | |
2647 | |
2648 | |
2649 IFindRequestHandler* OrthancPlugins::ConstructFindRequestHandler() | |
2650 { | |
2651 if (HasFindHandler()) | |
2652 { | |
2653 return new FindHandler(*this); | |
2654 } | |
2655 else | |
2656 { | |
2657 return NULL; | |
2658 } | |
2659 } | |
2660 | |
2661 | |
2662 bool OrthancPlugins::HasFindHandler() | |
2663 { | |
2664 boost::mutex::scoped_lock lock(pimpl_->findCallbackMutex_); | |
2665 return pimpl_->findCallback_ != NULL; | |
2475 } | 2666 } |
2476 | 2667 |
2477 | 2668 |
2478 bool OrthancPlugins::HasCustomImageDecoder() | 2669 bool OrthancPlugins::HasCustomImageDecoder() |
2479 { | 2670 { |