From f96bb4c7b63c2034b3659f4e81c774a03197d027 Mon Sep 17 00:00:00 2001 From: "Justin R. Wilson" Date: Fri, 2 Feb 2024 10:48:06 -0600 Subject: [PATCH] Multiple config files are not supported Problem ------- OpenDDS currently supports a single configuration file. Supporting multiple configuration files would allow complex configurations to be broken down into more modular configuration files and it allows "base" configuration to be customized. Solution -------- Add a command-line argument named `-DCPSSingleConfigFile 0` to turn on support for multiple config files. For backwards compatibility, the default is `-DCPSSingleConfigFile 0`. When multiple config files are enabled, process command-line arguments in order and process each configuration file as it is encountered. Multiple configuration files are supported via multiple `-DCPSConfigFile` arguments. Configuration now processes environment variables first and then command-line arguments in order. Each config file is processed as it is encounter in the command-line. --- dds/DCPS/ConfigStoreImpl.cpp | 6 +- dds/DCPS/ConfigStoreImpl.h | 1 - dds/DCPS/Service_Participant.cpp | 432 +++++++++++------- dds/DCPS/Service_Participant.h | 12 +- .../transport/framework/TransportRegistry.cpp | 27 +- .../transport/framework/TransportRegistry.h | 7 +- .../transport/framework/TransportRegistry.inl | 10 +- dds/FACE/config/Parser.cpp | 4 + tests/DCPS/ConfigFile/README.rst | 10 + tests/DCPS/ConfigFile/run_test.pl | 2 + tests/DCPS/ConfigFile/test0.ini | 7 + tests/unit-tests/dds/DCPS/ConfigStoreImpl.cpp | 12 +- 12 files changed, 341 insertions(+), 189 deletions(-) create mode 100644 tests/DCPS/ConfigFile/README.rst create mode 100644 tests/DCPS/ConfigFile/test0.ini diff --git a/dds/DCPS/ConfigStoreImpl.cpp b/dds/DCPS/ConfigStoreImpl.cpp index af6e29ca059..421d68e5665 100644 --- a/dds/DCPS/ConfigStoreImpl.cpp +++ b/dds/DCPS/ConfigStoreImpl.cpp @@ -1060,7 +1060,6 @@ process_section(ConfigStoreImpl& config_store, const String& key_prefix, ACE_Configuration_Heap& config, const ACE_Configuration_Section_Key& base, - const String& filename, bool allow_overwrite) { // Process the values. @@ -1077,9 +1076,6 @@ process_section(ConfigStoreImpl& config_store, if (config.get_string_value(base, key.c_str(), value) == 0) { const String key_name = key_prefix + "_" + ACE_TEXT_ALWAYS_CHAR(key.c_str()); String value_str = ACE_TEXT_ALWAYS_CHAR(value.c_str()); - if (value_str == "$file") { - value_str = filename; - } if (allow_overwrite || !config_store.has(key_name.c_str())) { config_store.set(key_name.c_str(), value_str); if (listener && reader) { @@ -1125,7 +1121,7 @@ process_section(ConfigStoreImpl& config_store, if (status == 0) { ACE_Configuration_Section_Key key; if (config.open_section(base, section_name.c_str(), 0, key) == 0) { - process_section(config_store, reader, listener, next_key_prefix, config, key, filename, allow_overwrite); + process_section(config_store, reader, listener, next_key_prefix, config, key, allow_overwrite); } else { if (log_level >= LogLevel::Error) { ACE_ERROR((LM_ERROR, diff --git a/dds/DCPS/ConfigStoreImpl.h b/dds/DCPS/ConfigStoreImpl.h index 36d324f6c45..4055e7002b6 100644 --- a/dds/DCPS/ConfigStoreImpl.h +++ b/dds/DCPS/ConfigStoreImpl.h @@ -261,7 +261,6 @@ process_section(ConfigStoreImpl& config_store, const String& key_prefix, ACE_Configuration_Heap& config, const ACE_Configuration_Section_Key& base, - const String& filename, bool allow_overwrite); } // namespace DCPS diff --git a/dds/DCPS/Service_Participant.cpp b/dds/DCPS/Service_Participant.cpp index 97c4b7792b2..ecf8baea3c3 100644 --- a/dds/DCPS/Service_Participant.cpp +++ b/dds/DCPS/Service_Participant.cpp @@ -398,66 +398,6 @@ Service_Participant::get_domain_participant_factory(int &argc, return DDS::DomainParticipantFactory::_nil(); } - String config_fname = config_store_->get(COMMON_DCPS_CONFIG_FILE, - COMMON_DCPS_CONFIG_FILE_default); - const String default_configuration_file = config_store_->get(DEFAULT_CONFIGURATION_FILE, - DEFAULT_CONFIGURATION_FILE_default); - - if (config_fname.empty() && !default_configuration_file.empty()) { - config_fname = default_configuration_file; - } - - if (config_fname.empty()) { - if (log_level >= LogLevel::Info) { - ACE_DEBUG((LM_INFO, - "(%P|%t) INFO: Service_Participant::get_domain_participant_factory: " - "no configuration file specified.\n")); - } - - } else { - // Convenient way to run tests in a different place from ini files. - const char* const config_dir = ACE_OS::getenv("OPENDDS_CONFIG_DIR"); - if (config_dir && config_dir[0]) { - String new_path = config_dir; - new_path += ACE_DIRECTORY_SEPARATOR_CHAR_A; - new_path += config_fname; - config_fname = new_path; - } - - // Load configuration only if the configuration file exists. - FILE* const in = ACE_OS::fopen(config_fname.c_str(), ACE_TEXT("r")); - if (!in) { - if (log_level >= LogLevel::Error) { - ACE_ERROR((LM_ERROR, - "(%P|%t) ERROR: Service_Participant::get_domain_participant_factory: " - "could not find config file \"%s\": %p\n", - config_fname.c_str(), ACE_TEXT("fopen"))); - } - return DDS::DomainParticipantFactory::_nil(); - - } else { - ACE_OS::fclose(in); - - if (log_level >= LogLevel::Info) { - ACE_DEBUG((LM_INFO, - "(%P|%t) INFO: Service_Participant::get_domain_participant_factory: " - "Going to load configuration from <%s>\n", - config_fname.c_str())); - } - - if (this->load_configuration(config_fname) != 0) { - if (log_level >= LogLevel::Error) { - ACE_ERROR((LM_ERROR, - "(%P|%t) ERROR: Service_Participant::get_domain_participant_factory: " - "load_configuration() failed.\n")); - } - return DDS::DomainParticipantFactory::_nil(); - } - } - } - - config_reader_listener_->on_data_available(config_reader_); - #if OPENDDS_POOL_ALLOCATOR // For non-FACE tests, configure pool configure_pool(); @@ -636,6 +576,9 @@ void Service_Participant::parse_env(const String& p) int Service_Participant::parse_args(int& argc, ACE_TCHAR* argv[]) { + int retval = 0; + bool config_file_loaded = false; + // Process logging options first, so they are in effect if we need to log // while processing other options. ACE_Arg_Shifter log_arg_shifter(argc, argv); @@ -652,18 +595,68 @@ int Service_Participant::parse_args(int& argc, ACE_TCHAR* argv[]) config_reader_listener_->on_data_available(config_reader_); log_arg_shifter.consume_arg(); + } else if ((currentArg = log_arg_shifter.get_the_parameter(ACE_TEXT("-DCPSSingleConfigFile"))) != 0) { + config_store_->set_string("CommonDCPSSingleConfigFile", ACE_TEXT_ALWAYS_CHAR(currentArg)); + config_reader_listener_->on_data_available(config_reader_); + log_arg_shifter.consume_arg(); + } else { log_arg_shifter.ignore_arg(); } } + // Change the default to false in OpenDDS 4. + const bool single_config_file = config_store_->get_boolean("CommonDCPSSingleConfigFile", true); + String single_config_file_name; + ACE_Arg_Shifter arg_shifter(argc, argv); while (arg_shifter.is_anything_left()) { const String current = ACE_TEXT_ALWAYS_CHAR(arg_shifter.get_current()); - if (toupper(current.substr(0, 5)) == "-DCPS" || toupper(current.substr(0, 11)) == "-FEDERATION") { + if (current == "-DCPSConfigFile") { + arg_shifter.consume_arg(); + if (!arg_shifter.is_anything_left()) { + if (log_level >= LogLevel::Error) { + ACE_ERROR((LM_ERROR, + "(%P|%t) ERROR: Service_Participant::parse_args: %C requires a parameter\n", + current.c_str())); + } + retval = -1; + break; + } + if (arg_shifter.is_parameter_next()) { + const String filename = ACE_TEXT_ALWAYS_CHAR(arg_shifter.get_current()); + config_store_->set("CommonDCPSConfigFile", filename); + config_reader_listener_->on_data_available(config_reader_); + arg_shifter.consume_arg(); + + if (single_config_file) { + single_config_file_name = filename; + } else { + if (process_config_file(filename, true)) { + config_file_loaded = true; + } else { + retval = -1; + } + } + } else { + if (log_level >= LogLevel::Error) { + ACE_ERROR((LM_ERROR, + "(%P|%t) ERROR: Service_Participant::parse_args: %C requires a parameter\n", + current.c_str())); + } + retval = -1; + arg_shifter.ignore_arg(); + } + } else if (toupper(current.substr(0, 5)) == "-DCPS" || toupper(current.substr(0, 11)) == "-FEDERATION") { arg_shifter.consume_arg(); if (!arg_shifter.is_anything_left()) { + if (log_level >= LogLevel::Error) { + ACE_ERROR((LM_ERROR, + "(%P|%t) ERROR: Service_Participant::parse_args: %C requires a parameter\n", + current.c_str())); + } + retval = -1; break; } const String key = "COMMON" + current; @@ -672,11 +665,23 @@ int Service_Participant::parse_args(int& argc, ACE_TCHAR* argv[]) config_reader_listener_->on_data_available(config_reader_); arg_shifter.consume_arg(); } else { + if (log_level >= LogLevel::Error) { + ACE_ERROR((LM_ERROR, + "(%P|%t) ERROR: Service_Participant::parse_args: %C requires a parameter\n", + current.c_str())); + } + retval = -1; arg_shifter.ignore_arg(); } } else if (current.substr(0, 8) == "-OpenDDS") { arg_shifter.consume_arg(); if (!arg_shifter.is_anything_left()) { + if (log_level >= LogLevel::Error) { + ACE_ERROR((LM_ERROR, + "(%P|%t) ERROR: Service_Participant::parse_args: %C requires a parameter\n", + current.c_str())); + } + retval = -1; break; } const String key = current.substr(8); @@ -685,6 +690,12 @@ int Service_Participant::parse_args(int& argc, ACE_TCHAR* argv[]) config_reader_listener_->on_data_available(config_reader_); arg_shifter.consume_arg(); } else { + if (log_level >= LogLevel::Error) { + ACE_ERROR((LM_ERROR, + "(%P|%t) ERROR: Service_Participant::parse_args: %C requires a parameter\n", + current.c_str())); + } + retval = -1; arg_shifter.ignore_arg(); } } else { @@ -692,8 +703,195 @@ int Service_Participant::parse_args(int& argc, ACE_TCHAR* argv[]) } } + if (single_config_file && !single_config_file_name.empty()) { + if (process_config_file(single_config_file_name, false)) { + config_file_loaded = true; + } else { + retval = -1; + } + } + + if (!config_file_loaded) { + const String default_configuration_file = config_store_->get(DEFAULT_CONFIGURATION_FILE, + DEFAULT_CONFIGURATION_FILE_default); + if (!default_configuration_file.empty()) { + if (!process_config_file(default_configuration_file, !single_config_file)) { + retval = -1; + } + } + } + + // Register static discovery. + add_discovery(static_rchandle_cast(StaticDiscovery::instance())); + + // load any discovery configuration templates before rtps discovery + // this will populate the domain_range_templates_ + int status = load_domain_ranges(); + + if (status != 0) { + if (log_level >= LogLevel::Error) { + ACE_ERROR((LM_ERROR, + "(%P|%t) ERROR: Service_Participant::parse_args: " + "load_domain_ranges() returned %d\n", + status)); + } + return -1; + } + + + // Domain config is loaded after Discovery (see below). Since the domain + // could be a domain_range that specifies the DiscoveryTemplate, check + // for config templates before loading any config information. + + status = this->load_discovery_configuration(RTPS_DISCOVERY_TYPE, false); + + if (status != 0) { + if (log_level >= LogLevel::Error) { + ACE_ERROR((LM_ERROR, + "(%P|%t) ERROR: Service_Participant::parse_args: " + "load_discovery_configuration() returned %d\n", + status)); + } + return -1; + } + + status = this->load_discovery_configuration(REPO_DISCOVERY_TYPE, false); + + if (status != 0) { + if (log_level >= LogLevel::Error) { + ACE_ERROR((LM_ERROR, + "(%P|%t) ERROR: Service_Participant::parse_args: " + "load_discovery_configuration() returned %d\n", + status)); + } + return -1; + } + + status = TransportRegistry::instance()->load_transport_configuration(); + + if (status != 0) { + if (log_level >= LogLevel::Error) { + ACE_ERROR((LM_ERROR, + "(%P|%t) ERROR: Service_Participant::parse_args: " + "load_transport_configuration () returned %d\n", + status)); + } + return -1; + } + + const String global_transport_config = config_store_->get(COMMON_DCPS_GLOBAL_TRANSPORT_CONFIG, + COMMON_DCPS_GLOBAL_TRANSPORT_CONFIG_default); + if (!global_transport_config.empty()) { + TransportConfig_rch config = TransportRegistry::instance()->get_config(global_transport_config); + if (config) { + TransportRegistry::instance()->global_config(config); + } else { + if (log_level >= LogLevel::Error) { + ACE_ERROR((LM_ERROR, + "(%P|%t) ERROR: Service_Participant::parse_args: " + "Unable to locate specified global transport config: %C\n", + global_transport_config.c_str())); + } + return -1; + } + } + + // Needs to be loaded after the [rtps_discovery/*] and [repository/*] + // sections to allow error reporting on bad discovery config names. + // Also loaded after the transport configuration so that + // DefaultTransportConfig within [domain/*] can use TransportConfig objects. + status = load_domain_configuration(); + + if (status != 0) { + if (log_level >= LogLevel::Error) { + ACE_ERROR((LM_ERROR, + "(%P|%t) ERROR: Service_Participant::parse_args: " + "load_domain_configuration () returned %d\n", + status)); + } + return -1; + } + + // Needs to be loaded after transport configs and instances and domains. + try { + status = StaticDiscovery::instance()->load_configuration(); + + if (status != 0) { + if (log_level >= LogLevel::Error) { + ACE_ERROR((LM_ERROR, + "(%P|%t) ERROR: Service_Participant::parse_args: " + "load_discovery_configuration() returned %d\n", + status)); + } + return -1; + } + } catch (const CORBA::BAD_PARAM& ex) { + ex._tao_print_exception("Exception caught in Service_Participant::parse_args: " + "trying to load_discovery_configuration()"); + return -1; + } + // Indicates successful parsing of the command line - return 0; + return retval; +} + +bool +Service_Participant::process_config_file(const String& config_name, + bool allow_overwrite) +{ + if (config_name.empty()) { + if (log_level >= LogLevel::Error) { + ACE_DEBUG((LM_INFO, + "(%P|%t) ERROR: Service_Participant::process_config_file: " + "configuration file name is empty.\n")); + } + return false; + } + + String config_fname = config_name; + + // Convenient way to run tests in a different place from ini files. + const char* const config_dir = ACE_OS::getenv("OPENDDS_CONFIG_DIR"); + if (config_dir && config_dir[0]) { + String new_path = config_dir; + new_path += ACE_DIRECTORY_SEPARATOR_CHAR_A; + new_path += config_fname; + config_fname = new_path; + } + + // Load configuration only if the configuration file exists. + FILE* const in = ACE_OS::fopen(config_fname.c_str(), ACE_TEXT("r")); + if (!in) { + if (log_level >= LogLevel::Error) { + ACE_ERROR((LM_ERROR, + "(%P|%t) ERROR: Service_Participant::process_config_file: " + "could not find config file \"%C\": %p\n", + config_fname.c_str(), ACE_TEXT("fopen"))); + } + return false; + } + + ACE_OS::fclose(in); + + if (log_level >= LogLevel::Info) { + ACE_DEBUG((LM_INFO, + "(%P|%t) INFO: Service_Participant::process_config_file: " + "Going to load configuration from \"%C\"\n", + config_fname.c_str())); + } + + if (load_configuration(config_fname, allow_overwrite) != 0) { + if (log_level >= LogLevel::Error) { + ACE_ERROR((LM_ERROR, + "(%P|%t) ERROR: Service_Participant::process_config_file: " + "load_configuration() failed.\n")); + } + return false; + } + + config_reader_listener_->on_data_available(config_reader_); + + return true; } void @@ -1522,7 +1720,8 @@ Service_Participant::register_discovery_type(const char* section_name, } int -Service_Participant::load_configuration(const String& config_fname) +Service_Participant::load_configuration(const String& config_fname, + bool allow_overwrite) { ACE_Configuration_Heap cf; int status = 0; @@ -1544,114 +1743,19 @@ Service_Participant::load_configuration(const String& config_fname) status), -1); } else { - status = this->load_configuration(cf, ACE_TEXT_CHAR_TO_TCHAR(config_fname.c_str())); + status = this->load_configuration(cf, ACE_TEXT_CHAR_TO_TCHAR(config_fname.c_str()), allow_overwrite); } return status; } int -Service_Participant::load_configuration( - ACE_Configuration_Heap& config, - const ACE_TCHAR* filename) +Service_Participant::load_configuration(ACE_Configuration_Heap& config, + const ACE_TCHAR* filename, + bool allow_overwrite) { - process_section(*config_store_, config_reader_, config_reader_listener_, "", config, config.root_section(), ACE_TEXT_ALWAYS_CHAR(filename), false); - - // Register static discovery. - add_discovery(static_rchandle_cast(StaticDiscovery::instance())); - - // load any discovery configuration templates before rtps discovery - // this will populate the domain_range_templates_ - int status = load_domain_ranges(); - - if (status != 0) { - if (log_level >= LogLevel::Error) { - ACE_ERROR((LM_ERROR, - "(%P|%t) ERROR: Service_Participant::load_configuration: " - "load_domain_ranges() returned %d\n", - status)); - } - return -1; - } - - // Domain config is loaded after Discovery (see below). Since the domain - // could be a domain_range that specifies the DiscoveryTemplate, check - // for config templates before loading any config information. - - status = this->load_discovery_configuration(RTPS_DISCOVERY_TYPE, false); - - if (status != 0) { - ACE_ERROR_RETURN((LM_ERROR, - ACE_TEXT("(%P|%t) ERROR: Service_Participant::load_configuration ") - ACE_TEXT("load_discovery_configuration() returned %d\n"), - status), - -1); - } - - status = this->load_discovery_configuration(REPO_DISCOVERY_TYPE, false); - - if (status != 0) { - ACE_ERROR_RETURN((LM_ERROR, - ACE_TEXT("(%P|%t) ERROR: Service_Participant::load_configuration ") - ACE_TEXT("load_discovery_configuration() returned %d\n"), - status), - -1); - } - - status = TransportRegistry::instance()->load_transport_configuration(ACE_TEXT_ALWAYS_CHAR(filename)); - const String global_transport_config = config_store_->get(COMMON_DCPS_GLOBAL_TRANSPORT_CONFIG, - COMMON_DCPS_GLOBAL_TRANSPORT_CONFIG_default); - if (!global_transport_config.empty()) { - TransportConfig_rch config = TransportRegistry::instance()->get_config(global_transport_config); - if (config) { - TransportRegistry::instance()->global_config(config); - } else { - ACE_ERROR_RETURN((LM_ERROR, - ACE_TEXT("(%P|%t) ERROR: Service_Participant::load_configuration ") - ACE_TEXT("Unable to locate specified global transport config: %C\n"), - global_transport_config.c_str()), - -1); - } - } - - if (status != 0) { - ACE_ERROR_RETURN((LM_ERROR, - ACE_TEXT("(%P|%t) ERROR: Service_Participant::load_configuration ") - ACE_TEXT("load_transport_configuration () returned %d\n"), - status), - -1); - } - - // Needs to be loaded after the [rtps_discovery/*] and [repository/*] - // sections to allow error reporting on bad discovery config names. - // Also loaded after the transport configuration so that - // DefaultTransportConfig within [domain/*] can use TransportConfig objects. - status = load_domain_configuration(); - - if (status != 0) { - ACE_ERROR_RETURN((LM_ERROR, - ACE_TEXT("(%P|%t) ERROR: Service_Participant::load_configuration ") - ACE_TEXT("load_domain_configuration () returned %d\n"), - status), - -1); - } - - // Needs to be loaded after transport configs and instances and domains. - try { - status = StaticDiscovery::instance()->load_configuration(); - - if (status != 0) { - ACE_ERROR_RETURN((LM_ERROR, - ACE_TEXT("(%P|%t) ERROR: Service_Participant::load_configuration ") - ACE_TEXT("load_discovery_configuration() returned %d\n"), - status), - -1); - } - } catch (const CORBA::BAD_PARAM& ex) { - ex._tao_print_exception("Exception caught in Service_Participant::load_configuration: " - "trying to load_discovery_configuration()"); - return -1; - } + process_section(*config_store_, config_reader_, config_reader_listener_, "", config, config.root_section(), allow_overwrite); + TransportRegistry::instance()->add_config_alias(ACE_TEXT_ALWAYS_CHAR(filename), "$file"); return 0; } diff --git a/dds/DCPS/Service_Participant.h b/dds/DCPS/Service_Participant.h index 1663a6e4772..42bee23a91d 100644 --- a/dds/DCPS/Service_Participant.h +++ b/dds/DCPS/Service_Participant.h @@ -80,9 +80,6 @@ const char COMMON_DCPS_CHUNK_ASSOCIATION_MULTIPLIER[] = "COMMON_DCPS_CHUNK_ASSOC const char COMMON_DCPS_CHUNK_ASSOCIATION_MUTLTIPLIER[] = "COMMON_DCPS_CHUNK_ASSOCIATION_MUTLTIPLIER"; const size_t COMMON_DCPS_CHUNK_ASSOCIATION_MULTIPLIER_default = 10; -const char COMMON_DCPS_CONFIG_FILE[] = "COMMON_DCPS_CONFIG_FILE"; -const String COMMON_DCPS_CONFIG_FILE_default = ""; - const char COMMON_DCPS_DEBUG_LEVEL[] = "COMMON_DCPS_DEBUG_LEVEL"; const char COMMON_DCPS_DEFAULT_ADDRESS[] = "COMMON_DCPS_DEFAULT_ADDRESS"; @@ -534,7 +531,8 @@ class OpenDDS_Dcps_Export Service_Participant { * singleton. */ int load_configuration(ACE_Configuration_Heap& cf, - const ACE_TCHAR* filename); + const ACE_TCHAR* filename, + bool allow_overwrite = false); #ifdef OPENDDS_SAFETY_PROFILE /** @@ -618,6 +616,9 @@ class OpenDDS_Dcps_Export Service_Participant { */ int parse_args(int &argc, ACE_TCHAR *argv[]); + bool process_config_file(const String& config_fname, + bool allow_overwrite); + /** * Import the configuration file to the ACE_Configuration_Heap * object and load common section configuration to the @@ -625,7 +626,8 @@ class OpenDDS_Dcps_Export Service_Participant { * transport section configuration to the TransportRegistry * singleton. */ - int load_configuration(const String& config_fname); + int load_configuration(const String& config_fname, + bool allow_overwrite = false); /** * Load the domain configuration to the Service_Participant diff --git a/dds/DCPS/transport/framework/TransportRegistry.cpp b/dds/DCPS/transport/framework/TransportRegistry.cpp index 9eca0e7029b..396bd1538db 100644 --- a/dds/DCPS/transport/framework/TransportRegistry.cpp +++ b/dds/DCPS/transport/framework/TransportRegistry.cpp @@ -166,7 +166,7 @@ bool TransportRegistry::process_config(const String& config_id) } int -TransportRegistry::load_transport_configuration(const String& file_name) +TransportRegistry::load_transport_configuration() { // Record the transport instances created, so we can place them // in the implicit transport configuration for this file. @@ -208,13 +208,12 @@ TransportRegistry::load_transport_configuration(const String& file_name) // Create and populate the default configuration for this // file with all the instances from this file. if (!instances.empty()) { - TransportConfig_rch config = create_config(file_name); + TransportConfig_rch config = create_config("$file"); if (!config) { if (log_level >= LogLevel::Error) { ACE_ERROR((LM_ERROR, - "(%P|%t) TransportRegistry::load_transport_configuration: " - "Unable to create default transport config.\n", - file_name.c_str())); + "(%P|%t) ERROR: TransportRegistry::load_transport_configuration: " + "Unable to create default transport config.\n")); } return -1; } @@ -343,7 +342,15 @@ TransportConfig_rch TransportRegistry::get_config(const OPENDDS_STRING& name) const { GuardType guard(lock_); - ConfigMap::const_iterator found = config_map_.find(name); + + String real_name = name; + + AliasMap::const_iterator pos = alias_map_.find(real_name); + if (pos != alias_map_.end()) { + real_name = pos->second; + } + + ConfigMap::const_iterator found = config_map_.find(real_name); if (found != config_map_.end()) { return found->second; } @@ -366,6 +373,14 @@ TransportRegistry::bind_config(const TransportConfig_rch& cfg, ei->transport_config(cfg); } +void +TransportRegistry::add_config_alias(const String& key, + const String& value) +{ + GuardType guard(lock_); + alias_map_[key] = value; +} + TransportConfig_rch TransportRegistry::fix_empty_default() { diff --git a/dds/DCPS/transport/framework/TransportRegistry.h b/dds/DCPS/transport/framework/TransportRegistry.h index bee86aa1299..c86bffd9d02 100644 --- a/dds/DCPS/transport/framework/TransportRegistry.h +++ b/dds/DCPS/transport/framework/TransportRegistry.h @@ -81,6 +81,9 @@ class OpenDDS_Dcps_Export TransportRegistry { void bind_config(const OPENDDS_STRING& name, DDS::Entity_ptr entity); void bind_config(const TransportConfig_rch& cfg, DDS::Entity_ptr entity); + void add_config_alias(const String& key, + const String& value); + /// SPI (Service Provider Interface) for specific transport types: /// This function is called as the concrete transport library is /// loaded. The concrete transport library creates a concrete @@ -94,7 +97,7 @@ class OpenDDS_Dcps_Export TransportRegistry { /// time. This function iterates each section in the configuration /// file, and creates TransportInst and TransportConfig objects and /// adds them to the registry. - int load_transport_configuration(const String& file_name); + int load_transport_configuration(); /// For internal use by OpenDDS DCPS layer: /// If the default config is empty when it's about to be used, allow the @@ -117,6 +120,7 @@ class OpenDDS_Dcps_Export TransportRegistry { ~TransportRegistry(); typedef OPENDDS_MAP(OPENDDS_STRING, TransportType_rch) TypeMap; + typedef OPENDDS_MAP(OPENDDS_STRING, OPENDDS_STRING) AliasMap; typedef OPENDDS_MAP(OPENDDS_STRING, TransportConfig_rch) ConfigMap; typedef OPENDDS_MAP(OPENDDS_STRING, TransportInst_rch) InstMap; typedef OPENDDS_MAP(OPENDDS_STRING, OPENDDS_STRING) LibDirectiveMap; @@ -126,6 +130,7 @@ class OpenDDS_Dcps_Export TransportRegistry { typedef ACE_Guard GuardType; TypeMap type_map_; + AliasMap alias_map_; ConfigMap config_map_; InstMap inst_map_; LibDirectiveMap lib_directive_map_; diff --git a/dds/DCPS/transport/framework/TransportRegistry.inl b/dds/DCPS/transport/framework/TransportRegistry.inl index 9ef73582d35..be5ac8c5310 100644 --- a/dds/DCPS/transport/framework/TransportRegistry.inl +++ b/dds/DCPS/transport/framework/TransportRegistry.inl @@ -97,7 +97,15 @@ void TransportRegistry::remove_config(const OPENDDS_STRING& config_name) { GuardType guard(this->lock_); - config_map_.erase(config_name); + + String real_name = config_name; + + AliasMap::const_iterator pos = alias_map_.find(real_name); + if (pos != alias_map_.end()) { + real_name = pos->second; + } + + config_map_.erase(real_name); } ACE_INLINE diff --git a/dds/FACE/config/Parser.cpp b/dds/FACE/config/Parser.cpp index 0a46a9f44b4..cd665d92bb1 100644 --- a/dds/FACE/config/Parser.cpp +++ b/dds/FACE/config/Parser.cpp @@ -99,6 +99,10 @@ Parser::parse(const char* filename) if (status) return status; + const DDS::DomainParticipantFactory_var dpf = TheParticipantFactory; + // For the configuration to be loaded. + ACE_UNUSED_ARG(dpf); + for (ConnectionMap::const_iterator pos = connection_map_.begin(), limit = connection_map_.end(); pos != limit; ++pos) { diff --git a/tests/DCPS/ConfigFile/README.rst b/tests/DCPS/ConfigFile/README.rst new file mode 100644 index 00000000000..f20294f4252 --- /dev/null +++ b/tests/DCPS/ConfigFile/README.rst @@ -0,0 +1,10 @@ +############### +ConfigFile Test +############### + +This test has two processes. + +The first process parses an environment variable, config file, and command line argument and checks that the configuration was parsed correctly. +The second process parses two config files with `-DCPSSingleConfigFile 0` and checks that both were parsed and that settings from the last overwrite the settings from the first. + +Run th test with `./run_test.pl`. diff --git a/tests/DCPS/ConfigFile/run_test.pl b/tests/DCPS/ConfigFile/run_test.pl index 0c1880a3296..4af01f98bd5 100755 --- a/tests/DCPS/ConfigFile/run_test.pl +++ b/tests/DCPS/ConfigFile/run_test.pl @@ -29,10 +29,12 @@ ? 'test1_nobits.ini' : 'test1.ini'; $test->process('ConfigFile', 'ConfigFile', "-DCPSConfigFile $cfg -OpenDDSMyConfigKey1 value1"); +$test->process('ConfigFile2', 'ConfigFile', "-DCPSSingleConfigFile 0 -DCPSConfigFile test0.ini -DCPSConfigFile $cfg"); $ENV{'OPENDDS_MY_CONFIG_KEY2'} = "value2"; $test->start_process('ConfigFile'); +$test->start_process('ConfigFile2'); my $status = $test->finish(5); diff --git a/tests/DCPS/ConfigFile/test0.ini b/tests/DCPS/ConfigFile/test0.ini new file mode 100644 index 00000000000..c9536fea46a --- /dev/null +++ b/tests/DCPS/ConfigFile/test0.ini @@ -0,0 +1,7 @@ +[common] +# This will be overwritten by the second config file. +DCPSChunks=100 + +[MyConfig] +# This will not be overwritten +Key1=value1 diff --git a/tests/unit-tests/dds/DCPS/ConfigStoreImpl.cpp b/tests/unit-tests/dds/DCPS/ConfigStoreImpl.cpp index 1134b73ba86..b299959d1de 100644 --- a/tests/unit-tests/dds/DCPS/ConfigStoreImpl.cpp +++ b/tests/unit-tests/dds/DCPS/ConfigStoreImpl.cpp @@ -522,11 +522,11 @@ TEST(dds_DCPS_ConfigStoreImpl, process_section) EXPECT_CALL(*listener.get(), on_data_available(reader)).Times(3); - process_section(config_store, reader, listener, "MYPREFIX", config, config.root_section(), "my file name", false); + process_section(config_store, reader, listener, "MYPREFIX", config, config.root_section(), false); EXPECT_EQ(config_store.get("MYPREFIX_MY_SECTION", "default"), "@my_section"); EXPECT_EQ(config_store.get("MYPREFIX_MY_SECTION_MYKEY", "default"), "myvalue"); - EXPECT_EQ(config_store.get("MYPREFIX_MY_SECTION_ANOTHERKEY", "default"), "my file name"); + EXPECT_EQ(config_store.get("MYPREFIX_MY_SECTION_ANOTHERKEY", "default"), "$file"); EXPECT_EQ(config_store.get("MYPREFIX_MY_SECTION_THIRDKEY", "default"), "firstvalue"); } @@ -543,10 +543,10 @@ TEST(dds_DCPS_ConfigStoreImpl, process_section_allow_overwrite) config.set_string_value(section_key, ACE_TEXT("anotherkey"), ACE_TEXT("$file")); config.set_string_value(section_key, ACE_TEXT("thirdkey"), ACE_TEXT("secondvalue")); - process_section(config_store, ConfigReader_rch(), ConfigReaderListener_rch(), "MYPREFIX", config, config.root_section(), "my file name", true); + process_section(config_store, ConfigReader_rch(), ConfigReaderListener_rch(), "MYPREFIX", config, config.root_section(), true); EXPECT_EQ(config_store.get("MYPREFIX_MY_SECTION_MYKEY", "default"), "myvalue"); - EXPECT_EQ(config_store.get("MYPREFIX_MY_SECTION_ANOTHERKEY", "default"), "my file name"); + EXPECT_EQ(config_store.get("MYPREFIX_MY_SECTION_ANOTHERKEY", "default"), "$file"); EXPECT_EQ(config_store.get("MYPREFIX_MY_SECTION_THIRDKEY", "default"), "secondvalue"); } @@ -584,11 +584,11 @@ TEST(dds_DCPS_ConfigStoreImpl, get_section_values) EXPECT_CALL(*listener.get(), on_data_available(reader)).Times(4); - process_section(config_store, reader, listener, "MYPREFIX", config, config.root_section(), "my file name", false); + process_section(config_store, reader, listener, "MYPREFIX", config, config.root_section(), false); ConfigStoreImpl::StringMap expected_sm; expected_sm["MYKEY"] = "myvalue"; - expected_sm["ANOTHERKEY"] = "my file name"; + expected_sm["ANOTHERKEY"] = "$file"; expected_sm["THIRDKEY"] = "secondvalue"; const ConfigStoreImpl::StringMap sm = config_store.get_section_values("MYPREFIX_MY_SECTION");