comparison OrthancServer/OrthancConfiguration.cpp @ 2944:f395460af74d

simplifying OrthancConfiguration for modalities/peers
author Sebastien Jodogne <s.jodogne@gmail.com>
date Thu, 29 Nov 2018 16:31:20 +0100
parents e292798f9980
children 2e751f615e03
comparison
equal deleted inserted replaced
2941:e292798f9980 2944:f395460af74d
40 #include "../Core/SystemToolbox.h" 40 #include "../Core/SystemToolbox.h"
41 #include "../Core/Toolbox.h" 41 #include "../Core/Toolbox.h"
42 42
43 #include "ServerIndex.h" 43 #include "ServerIndex.h"
44 44
45
46 static const char* const DICOM_MODALITIES = "DicomModalities";
47 static const char* const ORTHANC_PEERS = "OrthancPeers";
48
49
45 namespace Orthanc 50 namespace Orthanc
46 { 51 {
47 static void AddFileToConfiguration(Json::Value& target, 52 static void AddFileToConfiguration(Json::Value& target,
48 const boost::filesystem::path& path) 53 const boost::filesystem::path& path)
49 { 54 {
82 Json::Value::Members members = config.getMemberNames(); 87 Json::Value::Members members = config.getMemberNames();
83 for (Json::Value::ArrayIndex i = 0; i < members.size(); i++) 88 for (Json::Value::ArrayIndex i = 0; i < members.size(); i++)
84 { 89 {
85 if (target.isMember(members[i])) 90 if (target.isMember(members[i]))
86 { 91 {
87 LOG(ERROR) << "The configuration section \"" << members[i] << "\" is defined in 2 different configuration files"; 92 LOG(ERROR) << "The configuration section \"" << members[i]
93 << "\" is defined in 2 different configuration files";
88 throw OrthancException(ErrorCode_BadFileFormat); 94 throw OrthancException(ErrorCode_BadFileFormat);
89 } 95 }
90 else 96 else
91 { 97 {
92 target[members[i]] = config[members[i]]; 98 target[members[i]] = config[members[i]];
162 AddFileToConfiguration(target, p); 168 AddFileToConfiguration(target, p);
163 #endif 169 #endif
164 } 170 }
165 } 171 }
166 172
167 173
168 void OrthancConfiguration::ValidateConfiguration() const 174 static void CheckAlphanumeric(const std::string& s)
169 { 175 {
170 std::set<std::string> ids; 176 for (size_t j = 0; j < s.size(); j++)
171 177 {
172 GetListOfOrthancPeers(ids); 178 if (!isalnum(s[j]) &&
173 for (std::set<std::string>::const_iterator it = ids.begin(); it != ids.end(); ++it) 179 s[j] != '-')
174 { 180 {
181 LOG(ERROR) << "Only alphanumeric and dash characters are allowed "
182 << "in the names of modalities/peers, but found: " << s;
183 throw OrthancException(ErrorCode_BadFileFormat);
184 }
185 }
186 }
187
188
189 void OrthancConfiguration::LoadModalitiesFromJson(const Json::Value& source)
190 {
191 modalities_.clear();
192
193 if (source.type() != Json::objectValue)
194 {
195 LOG(ERROR) << "Bad format of the \"" << DICOM_MODALITIES << "\" configuration section";
196 throw OrthancException(ErrorCode_BadFileFormat);
197 }
198
199 Json::Value::Members members = source.getMemberNames();
200
201 for (size_t i = 0; i < members.size(); i++)
202 {
203 const std::string& name = members[i];
204 CheckAlphanumeric(name);
205
206 RemoteModalityParameters modality;
207 modality.Unserialize(source[name]);
208 modalities_[name] = modality;
209 }
210 }
211
212
213 void OrthancConfiguration::SaveModalitiesToJson(Json::Value& target)
214 {
215 target = Json::objectValue;
216
217 for (Modalities::const_iterator it = modalities_.begin(); it != modalities_.end(); ++it)
218 {
219 Json::Value modality;
220 it->second.Serialize(modality, true /* force advanced format */);
221
222 target[it->first] = modality;
223 }
224 }
225
226
227 void OrthancConfiguration::LoadPeersFromJson(const Json::Value& source)
228 {
229 peers_.clear();
230
231 if (source.type() != Json::objectValue)
232 {
233 LOG(ERROR) << "Bad format of the \"" << ORTHANC_PEERS << "\" configuration section";
234 throw OrthancException(ErrorCode_BadFileFormat);
235 }
236
237 Json::Value::Members members = source.getMemberNames();
238
239 for (size_t i = 0; i < members.size(); i++)
240 {
241 const std::string& name = members[i];
242 CheckAlphanumeric(name);
243
175 WebServiceParameters peer; 244 WebServiceParameters peer;
176 GetOrthancPeer(peer, *it); 245 peer.Unserialize(source[name]);
177 peer.CheckClientCertificate(); 246 peers_[name] = peer;
178 } 247 }
179 248 }
180 GetListOfDicomModalities(ids); 249
181 for (std::set<std::string>::const_iterator it = ids.begin(); it != ids.end(); ++it) 250
182 { 251 void OrthancConfiguration::SavePeersToJson(Json::Value& target)
183 RemoteModalityParameters modality; 252 {
184 GetDicomModalityUsingSymbolicName(modality, *it); 253 target = Json::objectValue;
185 } 254
255 for (Peers::const_iterator it = peers_.begin(); it != peers_.end(); ++it)
256 {
257 Json::Value peer;
258 it->second.Serialize(peer,
259 false /* use simple format if possible */,
260 true /* include passwords */);
261
262 target[it->first] = peer;
263 }
264 }
265
266
267 void OrthancConfiguration::LoadModalitiesAndPeers()
268 {
269 if (json_.isMember(DICOM_MODALITIES))
270 {
271 LoadModalitiesFromJson(json_[DICOM_MODALITIES]);
272 }
273 else
274 {
275 // TODO - Read from DB
276 modalities_.clear();
277 }
278
279 if (json_.isMember(ORTHANC_PEERS))
280 {
281 LoadPeersFromJson(json_[ORTHANC_PEERS]);
282 }
283 else
284 {
285 // TODO - Read from DB
286 peers_.clear();
287 }
288 }
289
290
291 void OrthancConfiguration::SaveModalities()
292 {
293 if (!modalities_.empty() ||
294 json_.isMember(DICOM_MODALITIES))
295 {
296 SaveModalitiesToJson(json_[DICOM_MODALITIES]);
297 }
298
299 // TODO - Write to DB
300 }
301
302
303 void OrthancConfiguration::SavePeers()
304 {
305 if (!peers_.empty() ||
306 json_.isMember(ORTHANC_PEERS))
307 {
308 SavePeersToJson(json_[ORTHANC_PEERS]);
309 }
310
311 // TODO - Write to DB
186 } 312 }
187 313
188 314
189 OrthancConfiguration& OrthancConfiguration::GetInstance() 315 OrthancConfiguration& OrthancConfiguration::GetInstance()
190 { 316 {
312 p /= "Configuration.json"; 438 p /= "Configuration.json";
313 configurationAbsolutePath_ = boost::filesystem::absolute(p).string(); 439 configurationAbsolutePath_ = boost::filesystem::absolute(p).string();
314 #endif 440 #endif
315 } 441 }
316 442
317 ValidateConfiguration(); 443 LoadModalitiesAndPeers();
318 } 444 }
319 445
320 446
321 void OrthancConfiguration::GetDicomModalityUsingSymbolicName( 447 void OrthancConfiguration::GetDicomModalityUsingSymbolicName(
322 RemoteModalityParameters& modality, 448 RemoteModalityParameters& modality,
323 const std::string& name) const 449 const std::string& name) const
324 { 450 {
325 if (!json_.isMember("DicomModalities")) 451 Modalities::const_iterator found = modalities_.find(name);
452
453 if (found == modalities_.end())
326 { 454 {
327 LOG(ERROR) << "No modality with symbolic name: " << name; 455 LOG(ERROR) << "No modality with symbolic name: " << name;
328 throw OrthancException(ErrorCode_InexistentItem); 456 throw OrthancException(ErrorCode_InexistentItem);
329 } 457 }
330 458 else
331 const Json::Value& modalities = json_["DicomModalities"]; 459 {
332 if (modalities.type() != Json::objectValue || 460 modality = found->second;
333 !modalities.isMember(name)) 461 }
334 { 462 }
335 LOG(ERROR) << "No modality with symbolic name: " << name; 463
336 throw OrthancException(ErrorCode_InexistentItem); 464
337 } 465 bool OrthancConfiguration::LookupOrthancPeer(WebServiceParameters& peer,
338 466 const std::string& name) const
339 try 467 {
340 { 468 Peers::const_iterator found = peers_.find(name);
341 modality.Unserialize(modalities[name]); 469
342 } 470 if (found == peers_.end())
343 catch (OrthancException&) 471 {
344 { 472 LOG(ERROR) << "No peer with symbolic name: " << name;
345 LOG(ERROR) << "Syntax error in the definition of DICOM modality \"" << name
346 << "\". Please check your configuration file.";
347 throw;
348 }
349 }
350
351
352 bool OrthancConfiguration::GetOrthancPeer(WebServiceParameters& peer,
353 const std::string& name) const
354 {
355 if (!json_.isMember("OrthancPeers"))
356 {
357 return false; 473 return false;
358 } 474 }
359 475 else
360 try 476 {
361 { 477 peer = found->second;
362 const Json::Value& modalities = json_["OrthancPeers"]; 478 return true;
363 if (modalities.type() != Json::objectValue || 479 }
364 !modalities.isMember(name)) 480 }
365 { 481
366 return false; 482
367 } 483 void OrthancConfiguration::GetListOfDicomModalities(std::set<std::string>& target) const
368 else
369 {
370 peer.Unserialize(modalities[name]);
371 return true;
372 }
373 }
374 catch (OrthancException&)
375 {
376 LOG(ERROR) << "Syntax error in the definition of peer \"" << name
377 << "\". Please check your configuration file.";
378 throw;
379 }
380 }
381
382
383 bool OrthancConfiguration::ReadKeys(std::set<std::string>& target,
384 const char* parameter,
385 bool onlyAlphanumeric) const
386 { 484 {
387 target.clear(); 485 target.clear();
388 486
389 if (!json_.isMember(parameter)) 487 for (Modalities::const_iterator
390 { 488 it = modalities_.begin(); it != modalities_.end(); ++it)
391 return true; 489 {
392 } 490 target.insert(it->first);
393 491 }
394 const Json::Value& modalities = json_[parameter]; 492 }
395 if (modalities.type() != Json::objectValue) 493
396 { 494
397 LOG(ERROR) << "Bad format of the \"DicomModalities\" configuration section"; 495 void OrthancConfiguration::GetListOfOrthancPeers(std::set<std::string>& target) const
398 throw OrthancException(ErrorCode_BadFileFormat);
399 }
400
401 Json::Value::Members members = modalities.getMemberNames();
402 for (size_t i = 0; i < members.size(); i++)
403 {
404 if (onlyAlphanumeric)
405 {
406 for (size_t j = 0; j < members[i].size(); j++)
407 {
408 if (!isalnum(members[i][j]) && members[i][j] != '-')
409 {
410 return false;
411 }
412 }
413 }
414
415 target.insert(members[i]);
416 }
417
418 return true;
419 }
420
421
422 void OrthancConfiguration::GetListOfDicomModalities(std::set<std::string>& target) const
423 { 496 {
424 target.clear(); 497 target.clear();
425 498
426 if (!ReadKeys(target, "DicomModalities", true)) 499 for (Peers::const_iterator it = peers_.begin(); it != peers_.end(); ++it)
427 { 500 {
428 LOG(ERROR) << "Only alphanumeric and dash characters are allowed in the names of the modalities"; 501 target.insert(it->first);
429 throw OrthancException(ErrorCode_BadFileFormat);
430 }
431 }
432
433
434 void OrthancConfiguration::GetListOfOrthancPeers(std::set<std::string>& target) const
435 {
436 target.clear();
437
438 if (!ReadKeys(target, "OrthancPeers", true))
439 {
440 LOG(ERROR) << "Only alphanumeric and dash characters are allowed in the names of Orthanc peers";
441 throw OrthancException(ErrorCode_BadFileFormat);
442 } 502 }
443 } 503 }
444 504
445 505
446 void OrthancConfiguration::SetupRegisteredUsers(MongooseServer& httpServer) const 506 void OrthancConfiguration::SetupRegisteredUsers(MongooseServer& httpServer) const
518 return tmp1 == tmp2; 578 return tmp1 == tmp2;
519 } 579 }
520 } 580 }
521 581
522 582
523 bool OrthancConfiguration::LookupDicomModalityUsingAETitle( 583 bool OrthancConfiguration::LookupDicomModalityUsingAETitle(RemoteModalityParameters& modality,
524 RemoteModalityParameters& modality, 584 const std::string& aet) const
525 const std::string& aet) const 585 {
526 { 586 for (Modalities::const_iterator it = modalities_.begin(); it != modalities_.end(); ++it)
527 std::set<std::string> modalities; 587 {
528 GetListOfDicomModalities(modalities); 588 if (IsSameAETitle(aet, it->second.GetApplicationEntityTitle()))
529 589 {
530 for (std::set<std::string>::const_iterator 590 modality = it->second;
531 it = modalities.begin(); it != modalities.end(); ++it) 591 return true;
532 {
533 try
534 {
535 GetDicomModalityUsingSymbolicName(modality, *it);
536
537 if (IsSameAETitle(aet, modality.GetApplicationEntityTitle()))
538 {
539 return true;
540 }
541 }
542 catch (OrthancException&)
543 {
544 } 592 }
545 } 593 }
546 594
547 return false; 595 return false;
548 } 596 }
573 return false; 621 return false;
574 } 622 }
575 } 623 }
576 624
577 625
578 RemoteModalityParameters OrthancConfiguration::GetModalityUsingSymbolicName( 626 RemoteModalityParameters
579 const std::string& name) const 627 OrthancConfiguration::GetModalityUsingSymbolicName(const std::string& name) const
580 { 628 {
581 RemoteModalityParameters modality; 629 RemoteModalityParameters modality;
582 GetDicomModalityUsingSymbolicName(modality, name); 630 GetDicomModalityUsingSymbolicName(modality, name);
583 631
584 return modality; 632 return modality;
585 } 633 }
586 634
587 635
588 RemoteModalityParameters OrthancConfiguration::GetModalityUsingAet( 636 RemoteModalityParameters
589 const std::string& aet) const 637 OrthancConfiguration::GetModalityUsingAet(const std::string& aet) const
590 { 638 {
591 RemoteModalityParameters modality; 639 RemoteModalityParameters modality;
592 640
593 if (LookupDicomModalityUsingAETitle(modality, aet)) 641 if (LookupDicomModalityUsingAETitle(modality, aet))
594 { 642 {
603 651
604 652
605 void OrthancConfiguration::UpdateModality(const std::string& symbolicName, 653 void OrthancConfiguration::UpdateModality(const std::string& symbolicName,
606 const RemoteModalityParameters& modality) 654 const RemoteModalityParameters& modality)
607 { 655 {
608 if (!json_.isMember("DicomModalities")) 656 modalities_[symbolicName] = modality;
609 { 657 SaveModalities();
610 json_["DicomModalities"] = Json::objectValue;
611 }
612
613 Json::Value& modalities = json_["DicomModalities"];
614 if (modalities.type() != Json::objectValue)
615 {
616 LOG(ERROR) << "Bad file format for modality: " << symbolicName;
617 throw OrthancException(ErrorCode_BadFileFormat);
618 }
619
620 modalities.removeMember(symbolicName);
621
622 Json::Value v;
623 modality.Serialize(v, true /* force advanced format */);
624 modalities[symbolicName] = v;
625 } 658 }
626 659
627 660
628 void OrthancConfiguration::RemoveModality(const std::string& symbolicName) 661 void OrthancConfiguration::RemoveModality(const std::string& symbolicName)
629 { 662 {
630 if (!json_.isMember("DicomModalities")) 663 modalities_.erase(symbolicName);
631 { 664 SaveModalities();
632 LOG(ERROR) << "No modality with symbolic name: " << symbolicName;
633 throw OrthancException(ErrorCode_BadFileFormat);
634 }
635
636 Json::Value& modalities = json_["DicomModalities"];
637 if (modalities.type() != Json::objectValue)
638 {
639 LOG(ERROR) << "Bad file format for the \"DicomModalities\" configuration section";
640 throw OrthancException(ErrorCode_BadFileFormat);
641 }
642
643 modalities.removeMember(symbolicName.c_str());
644 } 665 }
645 666
646 667
647 void OrthancConfiguration::UpdatePeer(const std::string& symbolicName, 668 void OrthancConfiguration::UpdatePeer(const std::string& symbolicName,
648 const WebServiceParameters& peer) 669 const WebServiceParameters& peer)
649 { 670 {
650 peer.CheckClientCertificate(); 671 peer.CheckClientCertificate();
651 672
652 if (!json_.isMember("OrthancPeers")) 673 peers_[symbolicName] = peer;
653 { 674 SavePeers();
654 LOG(ERROR) << "No peer with symbolic name: " << symbolicName;
655 json_["OrthancPeers"] = Json::objectValue;
656 }
657
658 Json::Value& peers = json_["OrthancPeers"];
659 if (peers.type() != Json::objectValue)
660 {
661 LOG(ERROR) << "Bad file format for the \"OrthancPeers\" configuration section";
662 throw OrthancException(ErrorCode_BadFileFormat);
663 }
664
665 peers.removeMember(symbolicName);
666
667 Json::Value v;
668 peer.Serialize(v,
669 false /* use simple format if possible */,
670 true /* include passwords */);
671 peers[symbolicName] = v;
672 } 675 }
673 676
674 677
675 void OrthancConfiguration::RemovePeer(const std::string& symbolicName) 678 void OrthancConfiguration::RemovePeer(const std::string& symbolicName)
676 { 679 {
677 if (!json_.isMember("OrthancPeers")) 680 peers_.erase(symbolicName);
678 { 681 SavePeers();
679 LOG(ERROR) << "No peer with symbolic name: " << symbolicName;
680 throw OrthancException(ErrorCode_BadFileFormat);
681 }
682
683 Json::Value& peers = json_["OrthancPeers"];
684 if (peers.type() != Json::objectValue)
685 {
686 LOG(ERROR) << "Bad file format for the \"OrthancPeers\" configuration section";
687 throw OrthancException(ErrorCode_BadFileFormat);
688 }
689
690 peers.removeMember(symbolicName.c_str());
691 } 682 }
692 683
693 684
694 void OrthancConfiguration::Format(std::string& result) const 685 void OrthancConfiguration::Format(std::string& result) const
695 { 686 {