48#include "TheBESKeys.h"
54#include "BESInternalFatalError.h"
55#include "BESInternalError.h"
56#include "BESSyntaxUserError.h"
59#define BES_INCLUDE_KEY "BES.Include"
64#define prolog std::string("TheBESKeys::").append(__func__).append("() - ")
66set<string> TheBESKeys::d_ingested_key_files;
73 if (d_instance)
return d_instance;
83 string try_ini =
"/usr/local/etc/bes/bes.conf";
84 if (access(try_ini.c_str(), R_OK) == 0) {
90 try_ini =
"/etc/bes/bes.conf";
91 if (access(try_ini.c_str(), R_OK) == 0) {
97 try_ini =
"/usr/etc/bes/bes.conf";
98 if (access(try_ini.c_str(), R_OK) == 0) {
123TheBESKeys::TheBESKeys(
const string &keys_file_name) :
124 d_keys_file_name(keys_file_name), d_the_keys(0), d_the_original_keys(0), d_dynamic_config_in_use(false), d_own_keys(true)
126 d_the_keys =
new map<string, vector<string> >;
127 d_the_original_keys =
new map<string, vector<string> >;
132TheBESKeys::TheBESKeys(
const string &keys_file_name, map<
string, vector<string> > *keys) :
133 d_keys_file_name(keys_file_name), d_the_keys(keys), d_the_original_keys(0), d_dynamic_config_in_use(false), d_own_keys(false)
146void TheBESKeys::initialize_keys()
148 kvp::load_keys(d_keys_file_name, d_ingested_key_files, *d_the_keys);
149 *d_the_original_keys = *d_the_keys;
150 BESDEBUG(MODULE, prolog <<
" d_keys_file_name: " << d_keys_file_name << endl);
151 BESDEBUG(MODULE, prolog <<
" d_the_keys.size(): " << d_the_keys->size() << endl);
152 BESDEBUG(MODULE, prolog <<
"d_the_original_keys.size(): " << d_the_original_keys->size() << endl);
155void TheBESKeys::clean()
157 if (d_the_keys && d_own_keys) {
161 if(d_the_original_keys){
162 delete d_the_original_keys;
163 d_the_original_keys = 0;
174bool TheBESKeys::LoadedKeys(
const string &key_file)
177 vector<string>::const_iterator i = TheBESKeys::d_ingested_key_files.begin();
178 vector<string>::const_iterator e = TheBESKeys::d_ingested_key_files.end();
179 for (; i != e; i++) {
180 if ((*i) == key_file) {
185 set<string>::iterator it = d_ingested_key_files.find(key_file);
187 return it != d_ingested_key_files.end();
208 map<string, vector<string> >::iterator i;
209 i = d_the_keys->find(key);
210 if (i == d_the_keys->end()) {
212 (*d_the_keys)[key] = vals;
214 if (!addto) (*d_the_keys)[key].clear();
216 (*d_the_keys)[key].push_back(val);
238 map<string, vector<string> >::iterator i;
239 i = d_the_keys->find(key);
240 if (i == d_the_keys->end()) {
242 (*d_the_keys)[key] = vals;
244 if (!addto) (*d_the_keys)[key].clear();
247 for(j = 0; j!=values.size(); j++){
248 if (!values[j].empty()) {
249 (*d_the_keys)[key].push_back(values[j]);
274 const map<string, string> &values,
275 const bool case_insensitive_map_keys,
278 map<string, vector<string> >::iterator i;
279 i = d_the_keys->find(key);
280 if (i == d_the_keys->end()) {
282 (*d_the_keys)[key] = vals;
285 (*d_the_keys)[key].clear();
288 map<string, string>::const_iterator mit;
289 for(mit = values.begin(); mit!=values.end(); mit++){
290 string map_key = mit->first;
291 if(map_key.empty() ){
292 BESDEBUG(MODULE, prolog <<
"The map_key is empty. SKIPPING." << endl);
295 if(case_insensitive_map_keys){
298 string map_record=map_key+
":"+mit->second;
299 (*d_the_keys)[key].push_back(map_record);
322 kvp::break_pair(pair.c_str(), key, val, addto);
343 map<string, vector<string> >::iterator i;
344 i = d_the_keys->find(s);
345 if (i != d_the_keys->end()) {
347 if ((*i).second.size() > 1) {
348 string err = string(
"Multiple values for the key ") + s +
" found, should only be one.";
351 if ((*i).second.size() == 1) {
352 val = (*i).second[0];
374 map<string, vector<string> >::iterator i;
375 i = d_the_keys->find(s);
376 if (i != d_the_keys->end()) {
378 vector<string>::iterator j;
379 for(j=(*i).second.begin(); j!=(*i).second.end(); j++){
406 return (value ==
"true" || value ==
"yes"|| value ==
"on");
409 return default_value;
436 return default_value;
457 std::istringstream iss(value);
460 if (!iss.eof() || iss.bad() || iss.fail())
461 return default_value;
466 return default_value;
489 ss << BESIndent::LMarg <<
"BESKeys::dump - (" << (
void *)
this <<
")" << endl;
491 ss << BESIndent::LMarg <<
"key file:" << d_keys_file_name << endl;
494 if (_keys_file && *_keys_file) {
495 strm << BESIndent::LMarg <<
"key file is valid" << endl;
498 strm << BESIndent::LMarg <<
"key file is NOT valid" << endl;
502 if (d_the_keys && d_the_keys->size()) {
503 ss << BESIndent::LMarg <<
" keys:" << endl;
505 Keys_citer i = d_the_keys->begin();
506 Keys_citer ie = d_the_keys->end();
507 for (; i != ie; i++) {
508 ss << BESIndent::LMarg << (*i).first <<
": " ;
510 vector<string>::const_iterator v = (*i).second.begin();
511 vector<string>::const_iterator ve = (*i).second.end();
512 for (; v != ve; v++) {
518 BESIndent::UnIndent();
521 ss << BESIndent::LMarg <<
"keys: none" << endl;
523 BESIndent::UnIndent();
528string TheBESKeys::get_as_config()
const
532 ss <<
"# TheBESKeys::get_as_config()" << endl;
533 if (d_the_keys && d_the_keys->size()) {
534 Keys_citer i = d_the_keys->begin();
535 Keys_citer ie = d_the_keys->end();
536 for (; i != ie; i++) {
537 string name = (*i).first;
538 vector<string> values = (*i).second;
540 for(
string value: values){
541 ss << name << (first?
"=":
"+=") << value << endl;
547 ss <<
"# TheBESKeys are empty()" << endl;
553#define MAP_SEPARATOR ":"
555bool parse_map_record(
const string &map_record,
const bool &case_insensitive_map_keys,
string &key,
string &value) {
556 int primary_index = map_record.find(MAP_SEPARATOR);
557 if (primary_index > 0) {
558 key = map_record.substr(0, primary_index);
559 if (case_insensitive_map_keys)
561 value = map_record.substr(primary_index + 1);
562 BESDEBUG(MODULE, prolog <<
"key: '" << key <<
"' value: " << value << endl);
577 const std::string &key,
578 std::map<std::string,std::string> &map_values,
579 const bool &case_insensitive_map_keys,
582 vector<string> values;
588 vector<string>::iterator it;
589 for(it=values.begin(); it!=values.end(); it++){
592 if(parse_map_record(*it,case_insensitive_map_keys,map_key,map_value)){
593 map_values.insert( std::pair<string,string>(map_key,map_value));
596 BESDEBUG(MODULE, prolog <<
string(
"The configuration entry for the ") << key <<
" was not " <<
597 "formatted as a map record. The offending entry: " << *it <<
" HAS BEEN SKIPPED." << endl);
612 const std::string &key,
613 std::map< std::string, std::map<std::string,std::vector<std::string> > > &primary_map,
614 const bool &case_insensitive_map_keys,
617 BESDEBUG(MODULE, prolog <<
"BEGIN" << endl);
618 vector<string> values;
624 vector<string>::iterator it;
625 for(it=values.begin(); it!=values.end(); it++){
626 string map_record = *it;
627 string primary_map_key;
628 string primary_map_value;
629 if(parse_map_record(map_record,case_insensitive_map_keys,primary_map_key,primary_map_value)){
630 string secondary_key;
631 string secondary_value;
632 if(parse_map_record(primary_map_value,case_insensitive_map_keys,secondary_key,secondary_value)){
633 map<string, map<string,vector<string>>>::iterator pit;
634 pit = primary_map.find(primary_map_key);
635 if(pit!=primary_map.end()){
636 map<string,vector<string>>::iterator sit;
637 sit = pit->second.find(secondary_key);
638 if(sit!=pit->second.end()){
639 sit->second.push_back(secondary_value);
643 vector<string> secondary_map_entry_values;
644 secondary_map_entry_values.push_back(secondary_value);
645 pit->second.insert(pair<
string,vector<string>>(secondary_key,secondary_map_entry_values));
650 map<string,vector<string>> secondary_map_entry;
651 vector<string> secondary_map_entry_values;
652 secondary_map_entry_values.push_back(secondary_value);
653 secondary_map_entry.insert(pair<
string,vector<string>>(secondary_key,secondary_map_entry_values));
654 primary_map.insert(pair<
string, map<
string,vector<string>>>(primary_map_key,secondary_map_entry));
659 BESDEBUG(MODULE, prolog <<
string(
"The configuration entry for the ") << key <<
" was not " <<
660 "formatted as a map record. The offending entry: " << map_record <<
661 " HAS BEEN SKIPPED." << endl);
665 BESDEBUG(MODULE, prolog <<
string(
"The configuration entry for the ") << key <<
" was not " <<
666 "formatted as a map record. The offending entry: " << map_record <<
667 " HAS BEEN SKIPPED." << endl);
670 BESDEBUG(MODULE, prolog <<
"END" << endl);
674bool TheBESKeys::using_dynamic_config(){
675 return d_dynamic_config_in_use;
684#if DYNAMIC_CONFIG_ENABLED
685 BESDEBUG(MODULE, prolog <<
"BEGIN" << endl);
689 if( d_dynamic_config_in_use ){
690 BESDEBUG(MODULE, prolog <<
"Unloading DynamicConfig." << endl);
692 *d_the_keys = *d_the_original_keys;
693 d_dynamic_config_in_use =
false;
696 map<string, map<string, vector<string>>> dynamic_confg;
698 get_values(DYNAMIC_CONFIG_KEY, dynamic_confg,
true, found);
700 BESDEBUG(MODULE, prolog <<
"Unable to locate " << DYNAMIC_CONFIG_KEY
701 <<
" in the configuration keys." << endl);
704 BESDEBUG(MODULE, prolog <<
"Found a " << DYNAMIC_CONFIG_KEY <<
" in TheBESKeys." << endl);
706 string best_matching_config_name;
707 long longest_match=0;
708 map<string, map<string, vector<string>>>::iterator best_matching_config=dynamic_confg.end();
710 map<string, map<string, vector<string>>>::iterator dcit;
711 for(dcit = dynamic_confg.begin(); dcit != dynamic_confg.end(); dcit++){
712 BESDEBUG(MODULE, prolog <<
"Processing " << DYNAMIC_CONFIG_KEY <<
"["<<dcit->first<<
"]" << endl);
714 map<string, vector<string>>::iterator rit;
715 rit = dcit->second.find(DC_REGEX_KEY);
716 if(rit==dcit->second.end()){
717 BESDEBUG(MODULE, prolog <<
"Could not find a " << DC_REGEX_KEY <<
" (regular expression) for the "
718 << DYNAMIC_CONFIG_KEY <<
" named: " << dcit->first <<
" SKIPPING!" << endl);
721 BESDEBUG(MODULE, prolog <<
"Found " << DC_REGEX_KEY <<
" vector for "
722 << DYNAMIC_CONFIG_KEY <<
"["<< dcit->first <<
"]" << endl);
723 vector<string>::iterator vit;
724 for(vit = rit->second.begin(); vit != rit->second.end(); vit ++){
725 BESDEBUG(MODULE, prolog <<
"Processing " << DC_REGEX_KEY <<
" value '" << *vit <<
"'" << endl);
727 long match_length = regex.
match(name.c_str(),name.size(),0);
729 BESDEBUG(MODULE, prolog <<
"The name '"<< name << (match_length<0?
"' does not match ":
"' matches ")
730 <<
"the regular expression: '"<< *vit <<
"' (match_length: " << match_length <<
")" << endl);
731 if(match_length>longest_match){
732 BESDEBUG(MODULE, prolog <<
"match_length of " << match_length
733 <<
" is larger than the current longest_match of "<< longest_match << endl);
735 map<string, vector<string>>::iterator cit;
736 cit = dcit->second.find(DC_CONFIG_KEY);
737 if(cit==dcit->second.end() || cit->second.empty()){
738 BESDEBUG(MODULE, prolog <<
"There were no " << DC_CONFIG_KEY
739 <<
" (configuration) values for the " << DYNAMIC_CONFIG_KEY <<
" named: "
740 << dcit->first <<
" SKIPPING!" << endl);
744 best_matching_config = dcit;
745 longest_match = match_length;
746 best_matching_config_name = dcit->first;
747 BESDEBUG(MODULE, prolog <<
"Found new best " << DYNAMIC_CONFIG_KEY <<
" match for '" << name
748 <<
"' " << DYNAMIC_CONFIG_KEY <<
": " << best_matching_config_name << endl);
755 if( longest_match==0 || best_matching_config==dynamic_confg.end() ){
756 BESDEBUG(MODULE, prolog <<
"None of the " << DYNAMIC_CONFIG_KEY
757 <<
" regex patterns matched the name: " << name << endl);
763 msg << prolog <<
"Using " << DYNAMIC_CONFIG_KEY <<
":" << best_matching_config_name <<
" for: " << name << endl;
764 BESDEBUG(MODULE, msg.str());
765 INFO_LOG( msg.str());
769 map<string, vector<string>>::iterator cit;
770 cit = best_matching_config->second.find(DC_CONFIG_KEY);
771 vector<string>::iterator vit;
772 for(vit=cit->second.begin(); vit != cit->second.end(); vit++){
775 BESDEBUG(MODULE, prolog <<
"Adding dynamic configuration BES Key: " << *vit << endl);
778 d_dynamic_config_in_use =
true;
780 BESDEBUG(MODULE, prolog <<
"END" << endl);
783 BESDEBUG(
"bes:keys",
dump());
exception thrown if internal error encountered
exception thrown if an internal error is found and is fatal to the BES
Regular expression matching.
int match(const char *s, int len, int pos=0) const
Does the pattern match.
static std::string lowercase(const std::string &s)
static void trim_if_trailing_slash(std::string &value)
If the string ends in a slash, remove it This function works for empty strings (doing nothing)....
mapping of key/value pairs defining different behaviors of an application.
void get_value(const std::string &s, std::string &val, bool &found)
Retrieve the value of a given key, if set.
static TheBESKeys * TheKeys()
void set_key(const std::string &key, const std::string &val, bool addto=false)
allows the user to set key/value pairs from within the application.
int read_int_key(const std::string &key, int default_value)
Read an integer-valued key from the bes.conf file.
void get_values(const std::string &s, std::vector< std::string > &vals, bool &found)
Retrieve the values of a given key, if set.
void load_dynamic_config(std::string name)
Loads the the applicable dynamic configuration or nothing if no configuration is applicable.
virtual std::string dump() const
dumps information about this object
static std::string ConfigFile
bool read_bool_key(const std::string &key, bool default_value)
Read a boolean-valued key from the bes.conf file.
std::string read_string_key(const std::string &key, const std::string &default_value)
Read a string-valued key from the bes.conf file.
void set_keys(const std::string &key, const std::vector< std::string > &values, bool addto)
allows the user to set key/value pairs from within the application.
virtual ~TheBESKeys()
cleans up the key/value pair mapping