Mercurial > hg > orthanc
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 { |