update Configuration

move string parsing into the base class.
Add several sub-classes for different configuration
sources (environment, std::map), and ConfigurationStack
to allow  chaining of different sources.

Mark Properties as deprecated, just use std::map by way
of ConfigurationMap.
This commit is contained in:
Michael Davidsaver
2015-12-11 08:09:10 -05:00
parent 7a2e25f79c
commit b3f78718b0
2 changed files with 113 additions and 105 deletions

View File

@@ -9,6 +9,7 @@
#include <pv/epicsException.h>
#include <osiSock.h>
#include <epicsStdlib.h>
#define epicsExportSharedSymbols
#include <pv/configuration.h>
@@ -139,105 +140,63 @@ void Properties::list()
}
}
SystemConfigurationImpl::SystemConfigurationImpl() :
_properties(new Properties())
bool Configuration::getPropertyAsBoolean(const std::string &name, const bool defaultValue) const
{
// no exception, default value is taken
//_ibuffer.exceptions ( ifstream::failbit | ifstream::badbit );
//_obuffer.exceptions ( ifstream::failbit | ifstream::badbit );
}
string value = getPropertyAsString(name, defaultValue ? "1" : "0");
std::transform(value.begin(), value.end(), value.begin(), ::tolower);
SystemConfigurationImpl::~SystemConfigurationImpl()
{
}
bool SystemConfigurationImpl::getPropertyAsBoolean(const string &name, const bool defaultValue)
{
/*
bool retval;
_ibuffer.clear();
_obuffer.clear();
_obuffer.str("");
_obuffer << defaultValue;
_ibuffer.str(getPropertyAsString(name,_obuffer.str()));
_ibuffer >> retval;
if (_ibuffer.fail() || _ibuffer.bad())
return defaultValue;
else
return retval;
*/
string value = getPropertyAsString(name, defaultValue ? "1" : "0");
std::transform(value.begin(), value.end(), value.begin(), ::tolower);
bool isTrue = (value == "1") || (value == "true") || (value == "yes");
bool isTrue = (value == "1") || (value == "true") || (value == "yes");
if (isTrue)
return true;
bool isFalse = (value == "0") || (value == "false") || (value == "no");
bool isFalse = (value == "0") || (value == "false") || (value == "no");
if (isFalse)
return false;
// invalid value
// invalid value
return defaultValue;
}
int32 SystemConfigurationImpl::getPropertyAsInteger(const string &name, const int32 defaultValue)
epics::pvData::int32 Configuration::getPropertyAsInteger(const std::string &name, const epics::pvData::int32 defaultValue) const
{
int32 retval = defaultValue;
_ibuffer.clear();
_obuffer.clear();
_obuffer.str("");
_obuffer << defaultValue;
_ibuffer.str(getPropertyAsString(name, _obuffer.str()));
_ibuffer >> retval;
if (_ibuffer.fail() || _ibuffer.bad())
epicsInt32 ret;
std::string val(getPropertyAsString(name, ""));
if(epicsParseInt32(val.c_str(), &ret, 0, NULL))
return defaultValue;
else
return retval;
return ret;
}
float SystemConfigurationImpl::getPropertyAsFloat(const string &name, const float defaultValue)
float Configuration::getPropertyAsFloat(const std::string &name, const float defaultValue) const
{
float retval;
_ibuffer.clear();
_obuffer.clear();
_obuffer.str("");
_obuffer << defaultValue;
_ibuffer.str(getPropertyAsString(name, _obuffer.str()));
_ibuffer >> retval;
if (_ibuffer.fail() || _ibuffer.bad())
float ret;
std::string val(getPropertyAsString(name, ""));
if(epicsParseFloat(val.c_str(), &ret, NULL))
return defaultValue;
else
return retval;
return ret;
}
float SystemConfigurationImpl::getPropertyAsDouble(const string &name, const double defaultValue)
double Configuration::getPropertyAsDouble(const std::string &name, const double defaultValue) const
{
float retval;
_ibuffer.clear();
_obuffer.clear();
_obuffer.str("");
_obuffer << defaultValue;
_ibuffer.str(getPropertyAsString(name, _obuffer.str()));
_ibuffer >> retval;
if (_ibuffer.fail() || _ibuffer.bad())
double ret;
std::string val(getPropertyAsString(name, ""));
if(epicsParseDouble(val.c_str(), &ret, NULL))
return defaultValue;
else
return retval;
return ret;
}
string SystemConfigurationImpl::getPropertyAsString(const string &name, const string &defaultValue)
std::string Configuration::getPropertyAsString(const std::string &name, const std::string &defaultValue) const
{
const char* val = getenv(name.c_str());
if(val != NULL)
{
return _properties->getProperty(name, string(val));
}
return _properties->getProperty(name, defaultValue);
std::string val;
if(tryGetPropertyAsString(name, &val))
return val;
else
return defaultValue;
}
bool SystemConfigurationImpl::getPropertyAsAddress(const std::string& name, osiSockAddr* addr)
bool Configuration::getPropertyAsAddress(const std::string& name, osiSockAddr* addr) const
{
unsigned short dftport=0;
if(addr->sa.sa_family==AF_INET)
@@ -253,19 +212,41 @@ bool SystemConfigurationImpl::getPropertyAsAddress(const std::string& name, osiS
return true;
}
bool SystemConfigurationImpl::hasProperty(const string &key)
bool Configuration::hasProperty(const std::string &name) const
{
const char* val = getenv(key.c_str());
return (val != NULL) || _properties->hasProperty(key);
return tryGetPropertyAsString(name, NULL);
}
ConfigurationProviderImpl::ConfigurationProviderImpl()
bool ConfigurationMap::tryGetPropertyAsString(const std::string& name, std::string* val) const
{
properties_t::const_iterator it = properties.find(name);
if(it==properties.end())
return false;
if(val)
*val = it->second;
return true;
}
ConfigurationProviderImpl::~ConfigurationProviderImpl()
bool ConfigurationEnviron::tryGetPropertyAsString(const std::string& name, std::string* val) const
{
const char *env = getenv(name.c_str());
if(!env || !*env)
return false;
if(val)
*val = env;
return true;
}
bool ConfigurationStack::tryGetPropertyAsString(const std::string& name, std::string* val) const
{
for(confs_t::const_reverse_iterator it = confs.rbegin(), end = confs.rend();
it!=end; ++it)
{
Configuration& conf = **it;
if(conf.tryGetPropertyAsString(name, val))
return true;
}
return false;
}
void ConfigurationProviderImpl::registerConfiguration(const string &name, Configuration::shared_pointer const & configuration)

View File

@@ -39,8 +39,8 @@ namespace pvAccess {
class epicsShareClass Properties
{
public:
Properties();
Properties(const std::string &fileName);
Properties() EPICS_DEPRECATED;
Properties(const std::string &fileName) EPICS_DEPRECATED;
inline void setProperty(const std::string &key,const std::string &value)
{ _properties[key] = value; }
@@ -57,14 +57,16 @@ public:
void load(std::istream& strm);
void list();
size_t size() const {return _properties.size();}
inline size_t size() const {return _properties.size();}
private:
typedef std::map<std::string,std::string> _properties_t;
_properties_t _properties;
std::string _fileName;
public:
inline const _properties_t& map() const {return _properties;}
};
class ConfigurationStack;
/**
* Configuration
@@ -87,7 +89,7 @@ public:
*
* @return environment variable value as bool or default value if it does not exist.
*/
virtual bool getPropertyAsBoolean(const std::string &name, const bool defaultValue) = 0;
bool getPropertyAsBoolean(const std::string &name, const bool defaultValue) const;
/**
* Get the environment variable specified by name or return default value
* if it does not exist.
@@ -97,7 +99,7 @@ public:
*
* @return environment variable value as int32 or default value if it does not exist.
*/
virtual epics::pvData::int32 getPropertyAsInteger(const std::string &name, const epics::pvData::int32 defaultValue) = 0;
epics::pvData::int32 getPropertyAsInteger(const std::string &name, const epics::pvData::int32 defaultValue) const;
/**
* Get the environment variable specified by name or return default value
* if it does not exist.
@@ -107,7 +109,7 @@ public:
*
* @return environment variable value as float or default value if it does not exist.
*/
virtual float getPropertyAsFloat(const std::string &name, const float defaultValue) = 0;
float getPropertyAsFloat(const std::string &name, const float defaultValue) const;
/**
* Get the environment variable specified by name or return default value
* if it does not exist.
@@ -117,7 +119,7 @@ public:
*
* @return environment variable value as double or default value if it does not exist.
*/
virtual float getPropertyAsDouble(const std::string &name, const double defaultValue) = 0;
double getPropertyAsDouble(const std::string &name, const double defaultValue) const;
/**
* Get the environment variable specified by name or return default value
* if it does not exist.
@@ -127,7 +129,7 @@ public:
*
* @return environment variable value as std::string or default value if it does not exist.
*/
virtual std::string getPropertyAsString(const std::string &name, const std::string &defaultValue) = 0;
std::string getPropertyAsString(const std::string &name, const std::string &defaultValue) const;
/**
* Fetch and parse as a socket address and port number (address family set accordingly).
* At present only numeric addresses are parsed (eg. "127.0.0.1:4242").
@@ -138,28 +140,53 @@ public:
* @pram addr pointer to the address struct to be filled in
* @return true if addr now contains an address, false otherwise
*/
virtual bool getPropertyAsAddress(const std::string& name, osiSockAddr* addr) = 0;
bool getPropertyAsAddress(const std::string& name, osiSockAddr* addr) const;
virtual bool hasProperty(const std::string &name) = 0;
bool hasProperty(const std::string &name) const;
protected:
friend class ConfigurationStack;
virtual bool tryGetPropertyAsString(const std::string& name, std::string* val) const = 0;
};
class epicsShareClass SystemConfigurationImpl: public Configuration
//! Lookup configuration strings from an in memory store
class epicsShareClass ConfigurationMap: public Configuration
{
public:
SystemConfigurationImpl();
~SystemConfigurationImpl();
bool getPropertyAsBoolean(const std::string &name, const bool defaultValue);
epics::pvData::int32 getPropertyAsInteger(const std::string &name, const epics::pvData::int32 defaultValue);
float getPropertyAsFloat(const std::string &name, const float defaultValue);
float getPropertyAsDouble(const std::string &name, const double defaultValue);
std::string getPropertyAsString(const std::string &name, const std::string &defaultValue);
bool getPropertyAsAddress(const std::string& name, osiSockAddr* addr);
bool hasProperty(const std::string &name);
std::auto_ptr<Properties> _properties;
typedef std::map<std::string, std::string> properties_t;
properties_t properties;
private:
std::istringstream _ibuffer;
std::ostringstream _obuffer;
virtual bool tryGetPropertyAsString(const std::string& name, std::string* val) const;
};
//! Lookup configuration strings from the process environment
class epicsShareClass ConfigurationEnviron: public Configuration
{
private:
virtual bool tryGetPropertyAsString(const std::string& name, std::string* val) const;
};
typedef ConfigurationEnviron SystemConfigurationImpl;
//! Lookup configuration strings from a heap of sub-Configurations.
//! Most recently push'd is checked first.
class epicsShareClass ConfigurationStack : public Configuration
{
typedef std::vector<std::tr1::shared_ptr<Configuration> > confs_t;
confs_t confs;
virtual bool tryGetPropertyAsString(const std::string& name, std::string* val) const;
public:
inline void push_back(const confs_t::value_type& conf) {
confs.push_back(conf);
}
inline confs_t::value_type pop_back() {
if(confs.empty())
throw std::runtime_error("Stack empty");
confs_t::value_type ret(confs.back());
confs.pop_back();
return ret;
}
inline size_t size() const {return confs.size();}
};
/**
@@ -193,11 +220,11 @@ public:
class ConfigurationProviderImpl: public ConfigurationProvider
{
public:
ConfigurationProviderImpl();
ConfigurationProviderImpl() {}
/**
* Destructor. Note: Registered configurations will be deleted!!
*/
~ConfigurationProviderImpl();
~ConfigurationProviderImpl() {}
Configuration::shared_pointer getConfiguration(const std::string &name);
void registerConfiguration(const std::string &name, Configuration::shared_pointer const & configuration);
private: