From bebea4009ed5a273fbf9ed3644a2140a8f477f99 Mon Sep 17 00:00:00 2001 From: Eduardo Ramos Testillano Date: Tue, 25 Jun 2013 03:12:45 +0200 Subject: [PATCH] New Environment core class --- SConstruct | 4 + include/anna/app/Application.hpp | 2 - .../anna/core/{ => util}/Configuration.hpp | 8 +- include/anna/core/util/Environment.hpp | 87 ++++++++++++ include/anna/core/util/defines.hpp | 132 +++++++++--------- source/core/util/Configuration.cpp | 2 +- source/core/util/Environment.cpp | 129 +++++++++++++++++ test/core/SConscript | 7 + test/core/example.cnf | 7 + test/core/main.cpp | 45 ++++++ test/time/main.cpp | 2 +- 11 files changed, 352 insertions(+), 73 deletions(-) rename include/anna/core/{ => util}/Configuration.hpp (95%) create mode 100644 include/anna/core/util/Environment.hpp create mode 100644 source/core/util/Environment.cpp create mode 100644 test/core/example.cnf diff --git a/SConstruct b/SConstruct index 1cff096..d811f34 100644 --- a/SConstruct +++ b/SConstruct @@ -22,6 +22,7 @@ source_include = os.path.join (current_directory, "include") usr_include = [ "/usr/include/oracle/11.2/client", "/usr/include/libxml2", + #"/usr/include/boost", #"/usr/include/mysql", #"/usr/include/openssl", ] @@ -34,6 +35,9 @@ env = Environment () # CPPPATH will be relative to src/ env.Append (CPPPATH = [source_include, usr_local_include, usr_include ]) env.Append (CCFLAGS = '-std=c++0x') +# C++11 support: +env.Append (CXXFLAGS = '-std=c++11') + env.Append (LIBS = ['']) # scons -Q release=1 if int(release): diff --git a/include/anna/app/Application.hpp b/include/anna/app/Application.hpp index fe40542..c34c46a 100644 --- a/include/anna/app/Application.hpp +++ b/include/anna/app/Application.hpp @@ -43,8 +43,6 @@ namespace anna { -class Configuration; - namespace xml { class Node; } diff --git a/include/anna/core/Configuration.hpp b/include/anna/core/util/Configuration.hpp similarity index 95% rename from include/anna/core/Configuration.hpp rename to include/anna/core/util/Configuration.hpp index 584ba5f..7385301 100644 --- a/include/anna/core/Configuration.hpp +++ b/include/anna/core/util/Configuration.hpp @@ -100,8 +100,8 @@ public: @param sectionName Nombre de la seccion a la que pertenece la variable. @param variableName Nombre de la variable de configuracion. @param strict Si es true indica que debe devolver el valor estricto de la variable, de forma, - que si esta variable no esta contenida en el archivo de configuracion devolvera NULL, en otro - caso, devolvera el posible valor por defecto que tenga asociado esta variable (ver #setDefaultValue). + que si esta variable no esta contenida en el archivo de configuracion aun habiendo asociado + un valor por defecto (ver #setDefaultValue) devolvera NULL. @return El valor asociado a la variable. Puede ser NULL. */ @@ -113,8 +113,8 @@ public: @param sectionName Nombre de la seccion a la que pertenece la variable. @param variableName Nombre de la variable de configuracion. @param strict Si es true indica que debe devolver el valor estricto de la variable, de forma, - que si esta variable no esta contenida en el archivo de configuracion devolvera NULL, en otro - caso, devolvera el posible valor por defecto que tenga asociado esta variable (ver #setDefaultValue). + que si esta variable no esta contenida en el archivo de configuracion aun habiendo asociado + un valor por defecto (ver #setDefaultValue) devolvera NULL. @return El valor asociado a la variable. */ diff --git a/include/anna/core/util/Environment.hpp b/include/anna/core/util/Environment.hpp new file mode 100644 index 0000000..fa7fb09 --- /dev/null +++ b/include/anna/core/util/Environment.hpp @@ -0,0 +1,87 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#ifndef anna_core_Environment_hpp +#define anna_core_Environment_hpp + +#include +#include + +#include +#include + + +namespace anna { + +/** + Environment variables reader +*/ +class Environment : public Singleton { +public: + + /** + * Destructor. + */ + ~Environment() {;} + + /** + Parses the current environment data (all variables available) + */ + void initialize() throw(); + + /** + Return associated value (could be empty). + + @param variableName Environment variable name. + @param exceptionIfMissing When enabled, an exception is launched for missing variables. Empty string in other case (default behaviour). + + @return Environment value. + */ + std::string getValue(const char* variableName, bool exceptionIfMissing = false) const throw(RuntimeException); + +private: + + std::map a_managedVars; + + Environment() { initialize();} + + friend class Singleton ; +}; + +} + +#endif + diff --git a/include/anna/core/util/defines.hpp b/include/anna/core/util/defines.hpp index 3acb459..fbe7bc9 100644 --- a/include/anna/core/util/defines.hpp +++ b/include/anna/core/util/defines.hpp @@ -403,69 +403,71 @@ typedef struct { /** - Struct for IANA Addresses +* IANA Address Family Numbers +* @see http://www.iana.org/assignments/address-family-numbers/address-family-numbers.xml */ typedef struct { + enum _v { + //Number Description Reference + //------ ---------------------------------------------------- --------- + // 0 Reserved + IPv4 = 1, //IP (IP version 4) + IPv6 = 2, //IP6 (IP version 6) + // 3 NSAP + // 4 HDLC (8-bit multidrop) + // 5 BBN 1822 + // 6 802 (includes all 802 media plus Ethernet "canonical format") + // 7 E.163 + E164 = 8 //E.164 (SMDS, Frame Relay, ATM) + // 9 F.69 (Telex) + // 10 X.121 (X.25, Frame Relay) + // 11 IPX + // 12 Appletalk + // 13 Decnet IV + // 14 Banyan Vines + // 15 E.164 with NSAP format subaddress [UNI-3.1] [Andy_Malis] + // 16 DNS (Domain Name System) + // 17 Distinguished Name [Charles_Lynn] + // 18 AS Number [Charles_Lynn] + // 19 XTP over IP version 4 [Mike_Saul] + // 20 XTP over IP version 6 [Mike_Saul] + // 21 XTP native mode XTP [Mike_Saul] + // 22 Fibre Channel World-Wide Port Name [Mark_Bakke] + // 23 Fibre Channel World-Wide Node Name [Mark_Bakke] + // 24 GWID [Subra_Hegde] + // 25 AFI for L2VPN information [RFC4761][RFC6074] + // 26-16383 Unassigned + // 16384 EIGRP Common Service Family [Donnie_Savage] 2008-05-13 + // 16385 EIGRP IPv4 Service Family [Donnie_Savage] 2008-05-13 + // 16386 EIGRP IPv6 Service Family [Donnie_Savage] 2008-05-13 + // 16387 LISP Canonical Address Format (LCAF) [David_Meyer] 2009-11-12 + // 16388-32767 Unassigned + // 32768-65534 Unassigned + // 65535 Reserved + }; /** - * IANA Address Family Numbers - * @see http://www.iana.org/assignments/address-family-numbers/address-family-numbers.xml + * Version description + * @param v Version type + * @return Version description */ - struct version { - enum _v { - //Number Description Reference - //------ ---------------------------------------------------- --------- - // 0 Reserved - IPv4 = 1, //IP (IP version 4) - IPv6 = 2, //IP6 (IP version 6) - // 3 NSAP - // 4 HDLC (8-bit multidrop) - // 5 BBN 1822 - // 6 802 (includes all 802 media plus Ethernet "canonical format") - // 7 E.163 - E164 = 8 //E.164 (SMDS, Frame Relay, ATM) - // 9 F.69 (Telex) - // 10 X.121 (X.25, Frame Relay) - // 11 IPX - // 12 Appletalk - // 13 Decnet IV - // 14 Banyan Vines - // 15 E.164 with NSAP format subaddress [UNI-3.1] [Andy_Malis] - // 16 DNS (Domain Name System) - // 17 Distinguished Name [Charles_Lynn] - // 18 AS Number [Charles_Lynn] - // 19 XTP over IP version 4 [Mike_Saul] - // 20 XTP over IP version 6 [Mike_Saul] - // 21 XTP native mode XTP [Mike_Saul] - // 22 Fibre Channel World-Wide Port Name [Mark_Bakke] - // 23 Fibre Channel World-Wide Node Name [Mark_Bakke] - // 24 GWID [Subra_Hegde] - // 25 AFI for L2VPN information [RFC4761][RFC6074] - // 26-16383 Unassigned - // 16384 EIGRP Common Service Family [Donnie_Savage] 2008-05-13 - // 16385 EIGRP IPv4 Service Family [Donnie_Savage] 2008-05-13 - // 16386 EIGRP IPv6 Service Family [Donnie_Savage] 2008-05-13 - // 16387 LISP Canonical Address Format (LCAF) [David_Meyer] 2009-11-12 - // 16388-32767 Unassigned - // 32768-65534 Unassigned - // 65535 Reserved - }; - - /** - * Version description - * @param v Version type - * @return Version description - */ - static const char* asText(const version::_v v) throw() { // anna_declare_enum is not safe, because labels don't have to match a sequence - if(v == version::IPv4) return "IPv4"; - - if(v == version::IPv6) return "IPv6"; - - if(v == version::E164) return "E164"; - - return NULL; - } - }; + static const char* asText(const _v v) throw() { // anna_declare_enum is not safe, because labels don't have to match a sequence + if(v == IPv4) return "IPv4"; + + if(v == IPv6) return "IPv6"; + + if(v == E164) return "E164"; + + return NULL; + } + +} iana_address_version_t; + + +/** + Struct for IANA Addresses +*/ +typedef struct { /** address version */ U16 Version; @@ -484,20 +486,20 @@ typedef struct { // Helpers /** Return true when is an IPv4 address */ - bool isIPv4() const throw() { return ((version::_v)Version == version::IPv4); } + bool isIPv4() const throw() { return ((iana_address_version_t::_v)Version == iana_address_version_t::IPv4); } /** Return true when is an IPv6 address */ - bool isIPv6() const throw() { return ((version::_v)Version == version::IPv6); } + bool isIPv6() const throw() { return ((iana_address_version_t::_v)Version == iana_address_version_t::IPv6); } /** Return true when is an E164 (SMDS, Frame Relay, ATM) address */ - bool isE164() const throw() { return ((version::_v)Version == version::E164); } + bool isE164() const throw() { return ((iana_address_version_t::_v)Version == iana_address_version_t::E164); } /** Sets version for IPv4 address and address itself. Checking is not performed (could assign IPv6 instead ...) */ - void setIPv4(const char *value) throw() { Version = version::IPv4; Value = value ? value : ""; } + void setIPv4(const char *value) throw() { Version = iana_address_version_t::IPv4; Value = value ? value : ""; } /** Sets version for IPv6 address and address itself. Checking is not performed (could assign IPv4 instead ...) */ - void setIPv6(const char *value) throw() { Version = version::IPv6; Value = value ? value : ""; } + void setIPv6(const char *value) throw() { Version = iana_address_version_t::IPv6; Value = value ? value : ""; } /** Sets version for E164 address and address itself. Checking is not performed ... */ - void setE164(const char *value) throw() { Version = version::E164; Value = value ? value : ""; } + void setE164(const char *value) throw() { Version = iana_address_version_t::E164; Value = value ? value : ""; } /** @@ -509,7 +511,7 @@ typedef struct { std::string result; result += Value.c_str(); // assume that all IANA addresses have a printable representation result += " ("; - const char *versionAsText = version::asText((version::_v)Version); + const char *versionAsText = iana_address_version_t::asText((iana_address_version_t::_v)Version); if(versionAsText) { result += versionAsText; diff --git a/source/core/util/Configuration.cpp b/source/core/util/Configuration.cpp index 60bf5d0..10d5087 100644 --- a/source/core/util/Configuration.cpp +++ b/source/core/util/Configuration.cpp @@ -40,7 +40,7 @@ #include #include -#include +#include #include #include #include diff --git a/source/core/util/Environment.cpp b/source/core/util/Environment.cpp new file mode 100644 index 0000000..7b51fa1 --- /dev/null +++ b/source/core/util/Environment.cpp @@ -0,0 +1,129 @@ +// ANNA - Anna is Not 'N' Anymore +// +// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo +// +// https://bitbucket.org/testillano/anna +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: eduardo.ramos.testillano@gmail.com +// cisco.tierra@gmail.com + + +#include + +#include +#include +#include + +#include +#include + + +#include + + + +using namespace std; +using namespace anna; + + + +void Environment::initialize() throw() { + LOGMETHOD(TraceMethod tm("Environment", "initialize", ANNA_FILE_LOCATION)); + + // clear data + a_managedVars.clear(); + + // Register: + namespace po = boost::program_options; + po::options_description desc("Options"); + + FILE *fp; + char c_var[256]; + std::string var; + + /* Open the command for reading. */ + fp = popen("env | cut -d'=' -f1", "r"); + if (fp == NULL) { + Logger::error("Failed to get environment variables list", ANNA_FILE_LOCATION); + return; + } + + /* Read the output a line at a time - output it. */ + while (fgets(c_var, sizeof(c_var)-1, fp) != NULL) { + var = c_var; + boost::trim(var); + desc.add_options()(var.c_str(), var.c_str()); + a_managedVars[var] = ""; // temporary + } + + /* close */ + pclose(fp); + + // Parsing: + po::variables_map vm; + try { + po::store(po::parse_environment(desc, [](const std::string& variable) { return variable; }), vm); // can throw + + std::map::const_iterator it; + std::string var, val; + for (it = a_managedVars.begin(); it != a_managedVars.end(); it++) { + var = (*it).first; + if (vm.count(var.c_str())) { // protection + val = vm[var.c_str()].as(); + a_managedVars[var] = val; + } + } + + po::notify(vm); + + } catch (po::error& e) { + Logger::error(e.what(), ANNA_FILE_LOCATION); + } +} + +std::string Environment::getValue (const char* variableName, bool exceptionIfMissing) const throw(RuntimeException) { + std::string result = ""; + + if (!variableName) + throw RuntimeException("Invalid NULL variable name!", ANNA_FILE_LOCATION); + + std::map::const_iterator it = a_managedVars.find(variableName); + if (it == a_managedVars.end()) { + std::string msg = "The variable '"; + msg += variableName; + msg += "' is not defined in the environment."; + LOGDEBUG(Logger::debug(msg, ANNA_FILE_LOCATION)); + if (exceptionIfMissing) + throw RuntimeException(msg, ANNA_FILE_LOCATION); + return ""; + } + + return it->second; +} + diff --git a/test/core/SConscript b/test/core/SConscript index 3b28786..4216c09 100644 --- a/test/core/SConscript +++ b/test/core/SConscript @@ -8,6 +8,9 @@ env.MergeFlags (boost_library) anna_library = { 'LIBS' : 'anna_core' } env.MergeFlags (anna_library) +system_library = { 'LIBS' : 'boost_program_options' } +env.MergeFlags (system_library) + pwd = Dir ('.').abspath; current_directory = str (pwd); @@ -17,3 +20,7 @@ env.Append (LIBPATH = [libpath]) result = env.Program ('anna_test_core', Glob ('*.cpp')) Return ('result') + + + + diff --git a/test/core/example.cnf b/test/core/example.cnf new file mode 100644 index 0000000..ed3fa84 --- /dev/null +++ b/test/core/example.cnf @@ -0,0 +1,7 @@ +[ property ] +thing = tshirt +size = 1 +color = blue +[ owner ] +name = edu +address = madrid diff --git a/test/core/main.cpp b/test/core/main.cpp index 9208755..d804ab0 100644 --- a/test/core/main.cpp +++ b/test/core/main.cpp @@ -44,6 +44,8 @@ #include #include +#include +#include #include using namespace std; @@ -111,3 +113,46 @@ BOOST_AUTO_TEST_CASE(functions_asString) { BOOST_REQUIRE_EQUAL(anna::functions::asString(d, "%4.2f"), cad_aux); } +BOOST_AUTO_TEST_CASE(configuration) { + + anna::Configuration conf; + + BOOST_CHECK_THROW(conf.load("missing_file.cnf"), anna::RuntimeException); + BOOST_CHECK_NO_THROW(conf.load("test/core/example.cnf")); + + //[ property ] + //thing = tshirt + //size = 1 + //color = blue + //[ owner ] + //name = edu + //address = madrid + + BOOST_CHECK_THROW(conf.getValue("property", "WRONG_VAR"), anna::RuntimeException); + BOOST_CHECK_THROW(conf.getValue("WRONG_SECTION", "thing"), anna::RuntimeException); + + std::string value; + + BOOST_REQUIRE_EQUAL(value = conf.getValue("property", "thing"), "tshirt"); + BOOST_REQUIRE_EQUAL(conf.getIntegerValue("property", "size"), 1); + BOOST_REQUIRE_EQUAL(std::string(conf.getValue("property", "color")), "blue"); + BOOST_REQUIRE_EQUAL(std::string(conf.getValue("owner", "name")), "edu"); + BOOST_REQUIRE_EQUAL(std::string(conf.getValue("owner", "address")), "madrid"); + + conf.setDefaultValue("owner", "phone", "555 55 55"); + BOOST_REQUIRE_EQUAL(std::string(conf.getValue("owner", "phone")), "555 55 55"); + BOOST_REQUIRE(!conf.getValue("owner", "phone", true) /* query value is NULL: 'true = strict' even with default value assigned */); + BOOST_REQUIRE(!conf.exists("owner", "phone")); + BOOST_REQUIRE(conf.exists("owner", "name")); +} + +BOOST_AUTO_TEST_CASE(environment) { + + anna::Environment &env = anna::Environment::instantiate(); + + BOOST_CHECK_THROW(env.getValue("WRONG_ENV_VAR", true /* exception if missing */), anna::RuntimeException); + BOOST_CHECK_THROW(env.getValue(NULL), anna::RuntimeException); + BOOST_REQUIRE_EQUAL(env.getValue("HOME"), std::string("/home/eramos")); + BOOST_REQUIRE_EQUAL(env.getValue("MISSING_ENV_VAR"), std::string("")); +} + diff --git a/test/time/main.cpp b/test/time/main.cpp index ab78bc6..77d0af3 100644 --- a/test/time/main.cpp +++ b/test/time/main.cpp @@ -50,7 +50,7 @@ using namespace anna; // see http://www.boost.org/doc/libs/1_44_0/libs/test/doc/html/utf/testing-tools.html // http://www.boost.org/doc/libs/1_44_0/libs/test/doc/html/utf/testing-tools/reference.html -BOOST_AUTO_TEST_CASE(Date) { +BOOST_AUTO_TEST_CASE(date) { const char * tzarg = NULL; anna::time::functions::initialize(); anna::time::Date current, current2; -- 2.20.1