48 #include "TheBESKeys.h"
49 #include "kvp_utils.h"
53 #include "BESFSFile.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("() - ")
66 set<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) {
122 TheBESKeys::TheBESKeys(
const string &keys_file_name) :
123 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)
125 d_the_keys =
new map<string, vector<string> >;
126 d_the_original_keys =
new map<string, vector<string> >;
131 TheBESKeys::TheBESKeys(
const string &keys_file_name, map<
string, vector<string> > *keys) :
132 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)
145 void TheBESKeys::initialize_keys()
147 kvp::load_keys(d_keys_file_name, d_ingested_key_files, *d_the_keys);
148 *d_the_original_keys = *d_the_keys;
149 BESDEBUG(MODULE, prolog <<
" d_the_keys.size(): " << d_the_keys->size() << endl);
150 BESDEBUG(MODULE, prolog <<
"d_the_original_keys.size(): " << d_the_original_keys->size() << endl);
153 void TheBESKeys::clean()
156 if (d_the_keys && d_own_keys) {
160 if(d_the_original_keys){
161 delete d_the_original_keys;
162 d_the_original_keys = 0;
173 bool TheBESKeys::LoadedKeys(
const string &key_file)
176 vector<string>::const_iterator i = TheBESKeys::d_ingested_key_files.begin();
177 vector<string>::const_iterator e = TheBESKeys::d_ingested_key_files.end();
178 for (; i != e; i++) {
179 if ((*i) == key_file) {
184 set<string>::iterator it = d_ingested_key_files.find(key_file);
186 return it != d_ingested_key_files.end();
207 map<string, vector<string> >::iterator i;
208 i = d_the_keys->find(key);
209 if (i == d_the_keys->end()) {
211 (*d_the_keys)[key] = vals;
213 if (!addto) (*d_the_keys)[key].clear();
215 (*d_the_keys)[key].push_back(val);
237 map<string, vector<string> >::iterator i;
238 i = d_the_keys->find(key);
239 if (i == d_the_keys->end()) {
241 (*d_the_keys)[key] = vals;
243 if (!addto) (*d_the_keys)[key].clear();
246 for(j = 0; j!=values.size(); j++){
247 if (!values[j].empty()) {
248 (*d_the_keys)[key].push_back(values[j]);
273 const map<string, string> &values,
274 const bool case_insensitive_map_keys,
277 map<string, vector<string> >::iterator i;
278 i = d_the_keys->find(key);
279 if (i == d_the_keys->end()) {
281 (*d_the_keys)[key] = vals;
284 (*d_the_keys)[key].clear();
287 map<string, string>::const_iterator mit;
288 for(mit = values.begin(); mit!=values.end(); mit++){
289 string map_key = mit->first;
290 if(map_key.empty() ){
291 BESDEBUG(MODULE, prolog <<
"The map_key is empty. SKIPPING." << endl);
294 if(case_insensitive_map_keys){
297 string map_record=map_key+
":"+mit->second;
298 (*d_the_keys)[key].push_back(map_record);
321 kvp::break_pair(pair.c_str(), key, val, addto);
342 map<string, vector<string> >::iterator i;
343 i = d_the_keys->find(s);
344 if (i != d_the_keys->end()) {
346 if ((*i).second.size() > 1) {
347 string err = string(
"Multiple values for the key ") + s +
" found, should only be one.";
350 if ((*i).second.size() == 1) {
351 val = (*i).second[0];
373 map<string, vector<string> >::iterator i;
374 i = d_the_keys->find(s);
375 if (i != d_the_keys->end()) {
377 vector<string>::iterator j;
378 for(j=(*i).second.begin(); j!=(*i).second.end(); j++){
405 return (value ==
"true" || value ==
"yes"|| value ==
"on");
408 return default_value;
429 if (value[value.length() - 1] ==
'/') value.erase(value.length() - 1);
433 return default_value;
454 std::istringstream iss(value);
457 if (iss.eof() || iss.bad() || iss.fail())
458 return default_value;
463 return default_value;
486 ss << BESIndent::LMarg <<
"BESKeys::dump - (" << (
void *)
this <<
")" << endl;
488 ss << BESIndent::LMarg <<
"key file:" << d_keys_file_name << endl;
491 if (_keys_file && *_keys_file) {
492 strm << BESIndent::LMarg <<
"key file is valid" << endl;
495 strm << BESIndent::LMarg <<
"key file is NOT valid" << endl;
499 if (d_the_keys && d_the_keys->size()) {
500 ss << BESIndent::LMarg <<
" keys:" << endl;
502 Keys_citer i = d_the_keys->begin();
503 Keys_citer ie = d_the_keys->end();
504 for (; i != ie; i++) {
505 ss << BESIndent::LMarg << (*i).first <<
": " ;
507 vector<string>::const_iterator v = (*i).second.begin();
508 vector<string>::const_iterator ve = (*i).second.end();
509 for (; v != ve; v++) {
515 BESIndent::UnIndent();
518 ss << BESIndent::LMarg <<
"keys: none" << endl;
520 BESIndent::UnIndent();
526 #define MAP_SEPARATOR ":"
528 bool parse_map_record(
const string &map_record,
const bool &case_insensitive_map_keys,
string &key,
string &value) {
529 int primary_index = map_record.find(MAP_SEPARATOR);
530 if (primary_index > 0) {
531 key = map_record.substr(0, primary_index);
532 if (case_insensitive_map_keys)
534 value = map_record.substr(primary_index + 1);
535 BESDEBUG(MODULE, prolog <<
"key: '" << key <<
"' value: " << value << endl);
550 const std::string &key,
551 std::map<std::string,std::string> &map_values,
552 const bool &case_insensitive_map_keys,
555 vector<string> values;
561 vector<string>::iterator it;
562 for(it=values.begin(); it!=values.end(); it++){
565 if(parse_map_record(*it,case_insensitive_map_keys,map_key,map_value)){
566 map_values.insert( std::pair<string,string>(map_key,map_value));
569 BESDEBUG(MODULE, prolog <<
string(
"The configuration entry for the ") << key <<
" was not " <<
570 "formatted as a map record. The offending entry: " << *it <<
" HAS BEEN SKIPPED." << endl);
585 const std::string &key,
586 std::map< std::string, std::map<std::string,std::vector<std::string> > > &primary_map,
587 const bool &case_insensitive_map_keys,
590 BESDEBUG(MODULE, prolog <<
"BEGIN" << endl);
591 vector<string> values;
597 vector<string>::iterator it;
598 for(it=values.begin(); it!=values.end(); it++){
599 string map_record = *it;
600 string primary_map_key;
601 string primary_map_value;
602 if(parse_map_record(map_record,case_insensitive_map_keys,primary_map_key,primary_map_value)){
603 string secondary_key;
604 string secondary_value;
605 if(parse_map_record(primary_map_value,case_insensitive_map_keys,secondary_key,secondary_value)){
606 map<string, map<string,vector<string>>>::iterator pit;
607 pit = primary_map.find(primary_map_key);
608 if(pit!=primary_map.end()){
609 map<string,vector<string>>::iterator sit;
610 sit = pit->second.find(secondary_key);
611 if(sit!=pit->second.end()){
612 sit->second.push_back(secondary_value);
616 vector<string> secondary_map_entry_values;
617 secondary_map_entry_values.push_back(secondary_value);
618 pit->second.insert(pair<
string,vector<string>>(secondary_key,secondary_map_entry_values));
623 map<string,vector<string>> secondary_map_entry;
624 vector<string> secondary_map_entry_values;
625 secondary_map_entry_values.push_back(secondary_value);
626 secondary_map_entry.insert(pair<
string,vector<string>>(secondary_key,secondary_map_entry_values));
627 primary_map.insert(pair<
string, map<
string,vector<string>>>(primary_map_key,secondary_map_entry));
632 BESDEBUG(MODULE, prolog <<
string(
"The configuration entry for the ") << key <<
" was not " <<
633 "formatted as a map record. The offending entry: " << map_record <<
634 " HAS BEEN SKIPPED." << endl);
638 BESDEBUG(MODULE, prolog <<
string(
"The configuration entry for the ") << key <<
" was not " <<
639 "formatted as a map record. The offending entry: " << map_record <<
640 " HAS BEEN SKIPPED." << endl);
643 BESDEBUG(MODULE, prolog <<
"END" << endl);
647 bool TheBESKeys::using_dynamic_config(){
648 return d_dynamic_config_in_use;
658 #if DYNAMIC_CONFIG_ENABLED
660 BESDEBUG(MODULE, prolog <<
"BEGIN" << endl);
664 if( d_dynamic_config_in_use ){
665 BESDEBUG(MODULE, prolog <<
"Unloading DynamicConfig." << endl);
667 *d_the_keys = *d_the_original_keys;
668 d_dynamic_config_in_use =
false;
671 map<string, map<string, vector<string>>> dynamic_confg;
673 get_values(DYNAMIC_CONFIG_KEY, dynamic_confg,
true, found);
675 BESDEBUG(MODULE, prolog <<
"Unable to locate " << DYNAMIC_CONFIG_KEY
676 <<
" in the configuration keys." << endl);
679 BESDEBUG(MODULE, prolog <<
"Found a " << DYNAMIC_CONFIG_KEY <<
" in TheBESKeys." << endl);
681 string best_matching_config_name;
682 long longest_match=0;
683 map<string, map<string, vector<string>>>::iterator best_matching_config=dynamic_confg.end();
685 map<string, map<string, vector<string>>>::iterator dcit;
686 for(dcit = dynamic_confg.begin(); dcit != dynamic_confg.end(); dcit++){
687 BESDEBUG(MODULE, prolog <<
"Processing " << DYNAMIC_CONFIG_KEY <<
"["<<dcit->first<<
"]" << endl);
689 map<string, vector<string>>::iterator rit;
690 rit = dcit->second.find(DC_REGEX_KEY);
691 if(rit==dcit->second.end()){
692 BESDEBUG(MODULE, prolog <<
"Could not find a " << DC_REGEX_KEY <<
" (regular expression) for the "
693 << DYNAMIC_CONFIG_KEY <<
" named: " << dcit->first <<
" SKIPPING!" << endl);
696 BESDEBUG(MODULE, prolog <<
"Found " << DC_REGEX_KEY <<
" vector for "
697 << DYNAMIC_CONFIG_KEY <<
"["<< dcit->first <<
"]" << endl);
698 vector<string>::iterator vit;
699 for(vit = rit->second.begin(); vit != rit->second.end(); vit ++){
700 BESDEBUG(MODULE, prolog <<
"Processing " << DC_REGEX_KEY <<
" value '" << *vit <<
"'" << endl);
702 long match_length = regex.
match(name.c_str(),name.size(),0);
704 BESDEBUG(MODULE, prolog <<
"The name '"<< name << (match_length<0?
"' does not match ":
"' matches ")
705 <<
"the regular expression: '"<< *vit <<
"' (match_length: " << match_length <<
")" << endl);
706 if(match_length>longest_match){
707 BESDEBUG(MODULE, prolog <<
"match_length of " << match_length
708 <<
" is larger than the current longest_match of "<< longest_match << endl);
710 map<string, vector<string>>::iterator cit;
711 cit = dcit->second.find(DC_CONFIG_KEY);
712 if(cit==dcit->second.end() || cit->second.empty()){
713 BESDEBUG(MODULE, prolog <<
"There were no " << DC_CONFIG_KEY
714 <<
" (configuration) values for the " << DYNAMIC_CONFIG_KEY <<
" named: "
715 << dcit->first <<
" SKIPPING!" << endl);
719 best_matching_config = dcit;
720 longest_match = match_length;
721 best_matching_config_name = dcit->first;
722 BESDEBUG(MODULE, prolog <<
"Found new best " << DYNAMIC_CONFIG_KEY <<
" match for '" << name
723 <<
"' " << DYNAMIC_CONFIG_KEY <<
": " << best_matching_config_name << endl);
730 if( longest_match==0 || best_matching_config==dynamic_confg.end() ){
731 BESDEBUG(MODULE, prolog <<
"None of the " << DYNAMIC_CONFIG_KEY
732 <<
" regex patterns matched the name: " << name << endl);
738 msg << prolog <<
"Using " << DYNAMIC_CONFIG_KEY <<
":" << best_matching_config_name <<
" for: " << name << endl;
739 BESDEBUG(MODULE, msg.str());
744 map<string, vector<string>>::iterator cit;
745 cit = best_matching_config->second.find(DC_CONFIG_KEY);
746 vector<string>::iterator vit;
747 for(vit=cit->second.begin(); vit != cit->second.end(); vit++){
750 BESDEBUG(MODULE, prolog <<
"Adding dynamic configuration BES Key: " << *vit << endl);
753 d_dynamic_config_in_use =
true;
755 BESDEBUG(MODULE, prolog <<
"END" << endl);
758 BESDEBUG(
"bes:keys",
dump());
exception thrown if internal error encountered
exception thrown if an internal error is found and is fatal to the BES
int match(const char *s, int len, int pos=0)
Does the pattern match.
static std::string lowercase(const std::string &s)
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)
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