comparison OrthancServer/OrthancInitialization.cpp @ 1423:7b7d597a190c

The configuration can be splitted into several files stored inside the same folder
author Sebastien Jodogne <s.jodogne@gmail.com>
date Fri, 26 Jun 2015 14:44:10 +0200
parents 52b2070fc8f1
children fe384a9d3b51
comparison
equal deleted inserted replaced
1422:52b2070fc8f1 1423:7b7d597a190c
60 60
61 61
62 namespace Orthanc 62 namespace Orthanc
63 { 63 {
64 static boost::mutex globalMutex_; 64 static boost::mutex globalMutex_;
65 static std::auto_ptr<Json::Value> configuration_; 65 static Json::Value configuration_;
66 static boost::filesystem::path defaultDirectory_; 66 static boost::filesystem::path defaultDirectory_;
67 static std::string configurationAbsolutePath_; 67 static std::string configurationAbsolutePath_;
68 68
69 69
70 static void AddFileToConfiguration(const boost::filesystem::path& path)
71 {
72 LOG(WARNING) << "Reading the configuration from: " << path;
73
74 std::string content;
75 Toolbox::ReadFile(content, path.string());
76
77 Json::Value tmp;
78 Json::Reader reader;
79 if (!reader.parse(content, tmp) ||
80 tmp.type() != Json::objectValue)
81 {
82 LOG(ERROR) << "Bad file format for this configuration file: " << path;
83 throw OrthancException(ErrorCode_BadFileFormat);
84 }
85
86 if (configuration_.size() == 0)
87 {
88 configuration_ = tmp;
89 }
90 else
91 {
92 Json::Value::Members members = tmp.getMemberNames();
93 for (Json::Value::ArrayIndex i = 0; i < members.size(); i++)
94 {
95 if (configuration_.isMember(members[i]))
96 {
97 LOG(ERROR) << "The configuration section \"" << members[i] << "\" is defined in 2 different configuration files";
98 throw OrthancException(ErrorCode_BadFileFormat);
99 }
100 else
101 {
102 configuration_[members[i]] = tmp[members[i]];
103 }
104 }
105 }
106 }
107
108
109 static void ScanFolderForConfiguration(const char* folder)
110 {
111 using namespace boost::filesystem;
112
113 LOG(WARNING) << "Scanning folder \"" << folder << "\" for configuration files";
114
115 directory_iterator end_it; // default construction yields past-the-end
116 for (directory_iterator it(folder);
117 it != end_it;
118 ++it)
119 {
120 if (!is_directory(it->status()))
121 {
122 std::string extension = boost::filesystem::extension(it->path());
123 Toolbox::ToLowerCase(extension);
124
125 if (extension == ".json")
126 {
127 AddFileToConfiguration(it->path().string());
128 }
129 }
130 }
131 }
132
133
70 static void ReadGlobalConfiguration(const char* configurationFile) 134 static void ReadGlobalConfiguration(const char* configurationFile)
71 { 135 {
72 configuration_.reset(new Json::Value); 136 // Prepare the default configuration
73 137 defaultDirectory_ = boost::filesystem::current_path();
74 std::string content; 138 configuration_ = Json::objectValue;
139 configurationAbsolutePath_ = "";
75 140
76 if (configurationFile) 141 if (configurationFile)
77 { 142 {
78 Toolbox::ReadFile(content, configurationFile); 143 if (!boost::filesystem::exists(configurationFile))
79 defaultDirectory_ = boost::filesystem::path(configurationFile).parent_path(); 144 {
80 LOG(WARNING) << "Using the configuration from: " << configurationFile; 145 LOG(ERROR) << "Inexistent path to configuration: " << configurationFile;
81 configurationAbsolutePath_ = boost::filesystem::absolute(configurationFile).string(); 146 return;
147 }
148
149 if (boost::filesystem::is_directory(configurationFile))
150 {
151 defaultDirectory_ = boost::filesystem::path(configurationFile);
152 configurationAbsolutePath_ = boost::filesystem::absolute(configurationFile).parent_path().string();
153 ScanFolderForConfiguration(configurationFile);
154 }
155 else
156 {
157 defaultDirectory_ = boost::filesystem::path(configurationFile).parent_path();
158 configurationAbsolutePath_ = boost::filesystem::absolute(configurationFile).string();
159 AddFileToConfiguration(configurationFile);
160 }
82 } 161 }
83 else 162 else
84 { 163 {
85 #if ORTHANC_STANDALONE == 1 164 #if ORTHANC_STANDALONE == 1
86 // No default path for the standalone configuration 165 // No default path for the standalone configuration
89 168
90 #else 169 #else
91 // In a non-standalone build, we use the 170 // In a non-standalone build, we use the
92 // "Resources/Configuration.json" from the Orthanc source code 171 // "Resources/Configuration.json" from the Orthanc source code
93 172
94 try 173 boost::filesystem::path p = ORTHANC_PATH;
95 { 174 p /= "Resources";
96 boost::filesystem::path p = ORTHANC_PATH; 175 p /= "Configuration.json";
97 p /= "Resources"; 176 configurationAbsolutePath_ = boost::filesystem::absolute(p).string();
98 p /= "Configuration.json"; 177
99 Toolbox::ReadFile(content, p.string()); 178 AddFileToConfiguration(p);
100 LOG(WARNING) << "Using the configuration from: " << p.string();
101 configurationAbsolutePath_ = boost::filesystem::absolute(p).string();
102 }
103 catch (OrthancException&)
104 {
105 // No configuration file found, give up with empty configuration
106 LOG(WARNING) << "Using the default Orthanc configuration";
107 return;
108 }
109 #endif 179 #endif
110 } 180 }
111
112
113 Json::Reader reader;
114 if (!reader.parse(content, *configuration_))
115 {
116 LOG(ERROR) << "Unable to read the configuration file";
117 throw OrthancException(ErrorCode_BadFileFormat);
118 }
119 } 181 }
120 182
121 183
122 static void RegisterUserMetadata() 184 static void RegisterUserMetadata()
123 { 185 {
124 if (configuration_->isMember("UserMetadata")) 186 if (configuration_.isMember("UserMetadata"))
125 { 187 {
126 const Json::Value& parameter = (*configuration_) ["UserMetadata"]; 188 const Json::Value& parameter = configuration_["UserMetadata"];
127 189
128 Json::Value::Members members = parameter.getMemberNames(); 190 Json::Value::Members members = parameter.getMemberNames();
129 for (size_t i = 0; i < members.size(); i++) 191 for (size_t i = 0; i < members.size(); i++)
130 { 192 {
131 std::string info = "\"" + members[i] + "\" = " + parameter[members[i]].toStyledString(); 193 std::string info = "\"" + members[i] + "\" = " + parameter[members[i]].toStyledString();
153 } 215 }
154 216
155 217
156 static void RegisterUserContentType() 218 static void RegisterUserContentType()
157 { 219 {
158 if (configuration_->isMember("UserContentType")) 220 if (configuration_.isMember("UserContentType"))
159 { 221 {
160 const Json::Value& parameter = (*configuration_) ["UserContentType"]; 222 const Json::Value& parameter = configuration_["UserContentType"];
161 223
162 Json::Value::Members members = parameter.getMemberNames(); 224 Json::Value::Members members = parameter.getMemberNames();
163 for (size_t i = 0; i < members.size(); i++) 225 for (size_t i = 0; i < members.size(); i++)
164 { 226 {
165 std::string info = "\"" + members[i] + "\" = " + parameter[members[i]].toStyledString(); 227 std::string info = "\"" + members[i] + "\" = " + parameter[members[i]].toStyledString();
190 void OrthancInitialize(const char* configurationFile) 252 void OrthancInitialize(const char* configurationFile)
191 { 253 {
192 boost::mutex::scoped_lock lock(globalMutex_); 254 boost::mutex::scoped_lock lock(globalMutex_);
193 255
194 InitializeServerEnumerations(); 256 InitializeServerEnumerations();
195 defaultDirectory_ = boost::filesystem::current_path(); 257
258 // Read the user-provided configuration
196 ReadGlobalConfiguration(configurationFile); 259 ReadGlobalConfiguration(configurationFile);
197 260
198 HttpClient::GlobalInitialize(); 261 HttpClient::GlobalInitialize();
199 262
200 RegisterUserMetadata(); 263 RegisterUserMetadata();
217 280
218 void OrthancFinalize() 281 void OrthancFinalize()
219 { 282 {
220 boost::mutex::scoped_lock lock(globalMutex_); 283 boost::mutex::scoped_lock lock(globalMutex_);
221 HttpClient::GlobalFinalize(); 284 HttpClient::GlobalFinalize();
222 configuration_.reset(NULL);
223 285
224 #if ORTHANC_JPEG_LOSSLESS_ENABLED == 1 286 #if ORTHANC_JPEG_LOSSLESS_ENABLED == 1
225 // Unregister JPEG-LS codecs 287 // Unregister JPEG-LS codecs
226 DJLSDecoderRegistration::cleanup(); 288 DJLSDecoderRegistration::cleanup();
227 #endif 289 #endif
237 std::string Configuration::GetGlobalStringParameter(const std::string& parameter, 299 std::string Configuration::GetGlobalStringParameter(const std::string& parameter,
238 const std::string& defaultValue) 300 const std::string& defaultValue)
239 { 301 {
240 boost::mutex::scoped_lock lock(globalMutex_); 302 boost::mutex::scoped_lock lock(globalMutex_);
241 303
242 if (configuration_.get() != NULL && 304 if (configuration_.isMember(parameter))
243 configuration_->isMember(parameter)) 305 {
244 { 306 return configuration_[parameter].asString();
245 return (*configuration_) [parameter].asString();
246 } 307 }
247 else 308 else
248 { 309 {
249 return defaultValue; 310 return defaultValue;
250 } 311 }
254 int Configuration::GetGlobalIntegerParameter(const std::string& parameter, 315 int Configuration::GetGlobalIntegerParameter(const std::string& parameter,
255 int defaultValue) 316 int defaultValue)
256 { 317 {
257 boost::mutex::scoped_lock lock(globalMutex_); 318 boost::mutex::scoped_lock lock(globalMutex_);
258 319
259 if (configuration_.get() != NULL && 320 if (configuration_.isMember(parameter))
260 configuration_->isMember(parameter)) 321 {
261 { 322 return configuration_[parameter].asInt();
262 return (*configuration_) [parameter].asInt();
263 } 323 }
264 else 324 else
265 { 325 {
266 return defaultValue; 326 return defaultValue;
267 } 327 }
271 bool Configuration::GetGlobalBoolParameter(const std::string& parameter, 331 bool Configuration::GetGlobalBoolParameter(const std::string& parameter,
272 bool defaultValue) 332 bool defaultValue)
273 { 333 {
274 boost::mutex::scoped_lock lock(globalMutex_); 334 boost::mutex::scoped_lock lock(globalMutex_);
275 335
276 if (configuration_.get() != NULL && 336 if (configuration_.isMember(parameter))
277 configuration_->isMember(parameter)) 337 {
278 { 338 return configuration_[parameter].asBool();
279 return (*configuration_) [parameter].asBool();
280 } 339 }
281 else 340 else
282 { 341 {
283 return defaultValue; 342 return defaultValue;
284 } 343 }
288 void Configuration::GetDicomModalityUsingSymbolicName(RemoteModalityParameters& modality, 347 void Configuration::GetDicomModalityUsingSymbolicName(RemoteModalityParameters& modality,
289 const std::string& name) 348 const std::string& name)
290 { 349 {
291 boost::mutex::scoped_lock lock(globalMutex_); 350 boost::mutex::scoped_lock lock(globalMutex_);
292 351
293 if (configuration_.get() == NULL) 352 if (!configuration_.isMember("DicomModalities"))
294 {
295 LOG(ERROR) << "The configuration file was not properly loaded";
296 throw OrthancException(ErrorCode_InexistentItem);
297 }
298
299 if (!configuration_->isMember("DicomModalities"))
300 { 353 {
301 LOG(ERROR) << "No modality with symbolic name: " << name; 354 LOG(ERROR) << "No modality with symbolic name: " << name;
302 throw OrthancException(ErrorCode_InexistentItem); 355 throw OrthancException(ErrorCode_InexistentItem);
303 } 356 }
304 357
305 const Json::Value& modalities = (*configuration_) ["DicomModalities"]; 358 const Json::Value& modalities = configuration_["DicomModalities"];
306 if (modalities.type() != Json::objectValue || 359 if (modalities.type() != Json::objectValue ||
307 !modalities.isMember(name)) 360 !modalities.isMember(name))
308 { 361 {
309 LOG(ERROR) << "No modality with symbolic name: " << name; 362 LOG(ERROR) << "No modality with symbolic name: " << name;
310 throw OrthancException(ErrorCode_InexistentItem); 363 throw OrthancException(ErrorCode_InexistentItem);
327 void Configuration::GetOrthancPeer(OrthancPeerParameters& peer, 380 void Configuration::GetOrthancPeer(OrthancPeerParameters& peer,
328 const std::string& name) 381 const std::string& name)
329 { 382 {
330 boost::mutex::scoped_lock lock(globalMutex_); 383 boost::mutex::scoped_lock lock(globalMutex_);
331 384
332 if (configuration_.get() == NULL) 385 if (!configuration_.isMember("OrthancPeers"))
333 {
334 LOG(ERROR) << "The configuration file was not properly loaded";
335 throw OrthancException(ErrorCode_InexistentItem);
336 }
337
338 if (!configuration_->isMember("OrthancPeers"))
339 { 386 {
340 LOG(ERROR) << "No peer with symbolic name: " << name; 387 LOG(ERROR) << "No peer with symbolic name: " << name;
341 throw OrthancException(ErrorCode_InexistentItem); 388 throw OrthancException(ErrorCode_InexistentItem);
342 } 389 }
343 390
344 try 391 try
345 { 392 {
346 const Json::Value& modalities = (*configuration_) ["OrthancPeers"]; 393 const Json::Value& modalities = configuration_["OrthancPeers"];
347 if (modalities.type() != Json::objectValue || 394 if (modalities.type() != Json::objectValue ||
348 !modalities.isMember(name)) 395 !modalities.isMember(name))
349 { 396 {
350 LOG(ERROR) << "No peer with symbolic name: " << name; 397 LOG(ERROR) << "No peer with symbolic name: " << name;
351 throw OrthancException(ErrorCode_InexistentItem); 398 throw OrthancException(ErrorCode_InexistentItem);
368 { 415 {
369 boost::mutex::scoped_lock lock(globalMutex_); 416 boost::mutex::scoped_lock lock(globalMutex_);
370 417
371 target.clear(); 418 target.clear();
372 419
373 if (configuration_.get() == NULL || 420 if (!configuration_.isMember(parameter))
374 !configuration_->isMember(parameter))
375 { 421 {
376 return true; 422 return true;
377 } 423 }
378 424
379 const Json::Value& modalities = (*configuration_) [parameter]; 425 const Json::Value& modalities = configuration_[parameter];
380 if (modalities.type() != Json::objectValue) 426 if (modalities.type() != Json::objectValue)
381 { 427 {
382 LOG(ERROR) << "Bad format of the \"DicomModalities\" configuration section"; 428 LOG(ERROR) << "Bad format of the \"DicomModalities\" configuration section";
383 throw OrthancException(ErrorCode_BadFileFormat); 429 throw OrthancException(ErrorCode_BadFileFormat);
384 } 430 }
429 { 475 {
430 boost::mutex::scoped_lock lock(globalMutex_); 476 boost::mutex::scoped_lock lock(globalMutex_);
431 477
432 httpServer.ClearUsers(); 478 httpServer.ClearUsers();
433 479
434 if (configuration_.get() == NULL || 480 if (!configuration_.isMember("RegisteredUsers"))
435 !configuration_->isMember("RegisteredUsers"))
436 { 481 {
437 return; 482 return;
438 } 483 }
439 484
440 const Json::Value& users = (*configuration_) ["RegisteredUsers"]; 485 const Json::Value& users = configuration_["RegisteredUsers"];
441 if (users.type() != Json::objectValue) 486 if (users.type() != Json::objectValue)
442 { 487 {
443 LOG(ERROR) << "Badly formatted list of users"; 488 LOG(ERROR) << "Badly formatted list of users";
444 throw OrthancException(ErrorCode_BadFileFormat); 489 throw OrthancException(ErrorCode_BadFileFormat);
445 } 490 }
492 { 537 {
493 boost::mutex::scoped_lock lock(globalMutex_); 538 boost::mutex::scoped_lock lock(globalMutex_);
494 539
495 target.clear(); 540 target.clear();
496 541
497 if (configuration_.get() == NULL || 542 if (!configuration_.isMember(key))
498 !configuration_->isMember(key))
499 { 543 {
500 return; 544 return;
501 } 545 }
502 546
503 const Json::Value& lst = (*configuration_) [key]; 547 const Json::Value& lst = configuration_[key];
504 548
505 if (lst.type() != Json::arrayValue) 549 if (lst.type() != Json::arrayValue)
506 { 550 {
507 LOG(ERROR) << "Badly formatted list of strings"; 551 LOG(ERROR) << "Badly formatted list of strings";
508 throw OrthancException(ErrorCode_BadFileFormat); 552 throw OrthancException(ErrorCode_BadFileFormat);
596 void Configuration::UpdateModality(const std::string& symbolicName, 640 void Configuration::UpdateModality(const std::string& symbolicName,
597 const RemoteModalityParameters& modality) 641 const RemoteModalityParameters& modality)
598 { 642 {
599 boost::mutex::scoped_lock lock(globalMutex_); 643 boost::mutex::scoped_lock lock(globalMutex_);
600 644
601 if (configuration_.get() == NULL) 645 if (!configuration_.isMember("DicomModalities"))
602 { 646 {
603 LOG(ERROR) << "The configuration file was not properly loaded"; 647 configuration_["DicomModalities"] = Json::objectValue;
604 throw OrthancException(ErrorCode_InternalError); 648 }
605 } 649
606 650 Json::Value& modalities = configuration_["DicomModalities"];
607 if (!configuration_->isMember("DicomModalities"))
608 {
609 (*configuration_) ["DicomModalities"] = Json::objectValue;
610 }
611
612 Json::Value& modalities = (*configuration_) ["DicomModalities"];
613 if (modalities.type() != Json::objectValue) 651 if (modalities.type() != Json::objectValue)
614 { 652 {
615 LOG(ERROR) << "Bad file format for modality: " << symbolicName; 653 LOG(ERROR) << "Bad file format for modality: " << symbolicName;
616 throw OrthancException(ErrorCode_BadFileFormat); 654 throw OrthancException(ErrorCode_BadFileFormat);
617 } 655 }
626 664
627 void Configuration::RemoveModality(const std::string& symbolicName) 665 void Configuration::RemoveModality(const std::string& symbolicName)
628 { 666 {
629 boost::mutex::scoped_lock lock(globalMutex_); 667 boost::mutex::scoped_lock lock(globalMutex_);
630 668
631 if (configuration_.get() == NULL) 669 if (!configuration_.isMember("DicomModalities"))
632 {
633 LOG(ERROR) << "The configuration file was not properly loaded";
634 throw OrthancException(ErrorCode_InternalError);
635 }
636
637 if (!configuration_->isMember("DicomModalities"))
638 { 670 {
639 LOG(ERROR) << "No modality with symbolic name: " << symbolicName; 671 LOG(ERROR) << "No modality with symbolic name: " << symbolicName;
640 throw OrthancException(ErrorCode_BadFileFormat); 672 throw OrthancException(ErrorCode_BadFileFormat);
641 } 673 }
642 674
643 Json::Value& modalities = (*configuration_) ["DicomModalities"]; 675 Json::Value& modalities = configuration_["DicomModalities"];
644 if (modalities.type() != Json::objectValue) 676 if (modalities.type() != Json::objectValue)
645 { 677 {
646 LOG(ERROR) << "Bad file format for the \"DicomModalities\" configuration section"; 678 LOG(ERROR) << "Bad file format for the \"DicomModalities\" configuration section";
647 throw OrthancException(ErrorCode_BadFileFormat); 679 throw OrthancException(ErrorCode_BadFileFormat);
648 } 680 }
654 void Configuration::UpdatePeer(const std::string& symbolicName, 686 void Configuration::UpdatePeer(const std::string& symbolicName,
655 const OrthancPeerParameters& peer) 687 const OrthancPeerParameters& peer)
656 { 688 {
657 boost::mutex::scoped_lock lock(globalMutex_); 689 boost::mutex::scoped_lock lock(globalMutex_);
658 690
659 if (configuration_.get() == NULL) 691 if (!configuration_.isMember("OrthancPeers"))
660 {
661 LOG(ERROR) << "The configuration file was not properly loaded";
662 throw OrthancException(ErrorCode_InternalError);
663 }
664
665 if (!configuration_->isMember("OrthancPeers"))
666 { 692 {
667 LOG(ERROR) << "No peer with symbolic name: " << symbolicName; 693 LOG(ERROR) << "No peer with symbolic name: " << symbolicName;
668 (*configuration_) ["OrthancPeers"] = Json::objectValue; 694 configuration_["OrthancPeers"] = Json::objectValue;
669 } 695 }
670 696
671 Json::Value& peers = (*configuration_) ["OrthancPeers"]; 697 Json::Value& peers = configuration_["OrthancPeers"];
672 if (peers.type() != Json::objectValue) 698 if (peers.type() != Json::objectValue)
673 { 699 {
674 LOG(ERROR) << "Bad file format for the \"OrthancPeers\" configuration section"; 700 LOG(ERROR) << "Bad file format for the \"OrthancPeers\" configuration section";
675 throw OrthancException(ErrorCode_BadFileFormat); 701 throw OrthancException(ErrorCode_BadFileFormat);
676 } 702 }
685 711
686 void Configuration::RemovePeer(const std::string& symbolicName) 712 void Configuration::RemovePeer(const std::string& symbolicName)
687 { 713 {
688 boost::mutex::scoped_lock lock(globalMutex_); 714 boost::mutex::scoped_lock lock(globalMutex_);
689 715
690 if (configuration_.get() == NULL) 716 if (!configuration_.isMember("OrthancPeers"))
691 {
692 LOG(ERROR) << "The configuration file was not properly loaded";
693 throw OrthancException(ErrorCode_InternalError);
694 }
695
696 if (!configuration_->isMember("OrthancPeers"))
697 { 717 {
698 LOG(ERROR) << "No peer with symbolic name: " << symbolicName; 718 LOG(ERROR) << "No peer with symbolic name: " << symbolicName;
699 throw OrthancException(ErrorCode_BadFileFormat); 719 throw OrthancException(ErrorCode_BadFileFormat);
700 } 720 }
701 721
702 Json::Value& peers = (*configuration_) ["OrthancPeers"]; 722 Json::Value& peers = configuration_["OrthancPeers"];
703 if (peers.type() != Json::objectValue) 723 if (peers.type() != Json::objectValue)
704 { 724 {
705 LOG(ERROR) << "Bad file format for the \"OrthancPeers\" configuration section"; 725 LOG(ERROR) << "Bad file format for the \"OrthancPeers\" configuration section";
706 throw OrthancException(ErrorCode_BadFileFormat); 726 throw OrthancException(ErrorCode_BadFileFormat);
707 } 727 }