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 {