From c9990b16272d9c9a55f1f7be1fdef5b625ad27aa Mon Sep 17 00:00:00 2001 From: randomdan Date: Thu, 8 Dec 2011 16:46:11 +0000 Subject: Drop Boost::program_options in favour of our own, pluggable system which integrates application platforms properly --- project2/cgi/Jamfile.jam | 3 - project2/cgi/cgiAppEngine.cpp | 26 -------- project2/cgi/cgiAppEngine.h | 5 -- project2/cgi/cgiCommon.cpp | 2 +- project2/cgi/cgiEnvironment.cpp | 94 +++++++++++++++++++-------- project2/cgi/cgiEnvironment.h | 18 +++++- project2/cgi/cgiOutputOptions.cpp | 18 +++--- project2/cgi/cgiOutputOptions.h | 7 +- project2/cgi/cgiStageFail.cpp | 1 + project2/cgi/pch.hpp | 2 +- project2/cgi/testCgi.cpp | 105 +++++++++++++++--------------- project2/common/Jamfile.jam | 3 - project2/common/appEngine.cpp | 3 +- project2/common/appEngine.h | 5 +- project2/common/config.cpp | 73 --------------------- project2/common/config.h | 43 ------------- project2/common/environment.cpp | 92 +++++++++++++------------- project2/common/environment.h | 20 +++--- project2/common/memoryCache.cpp | 11 ++-- project2/common/options.cpp | 110 ++++++++++++++++++++++++++++++++ project2/common/options.h | 110 ++++++++++++++++++++++++++++++++ project2/common/optionsSource.h | 35 ++++++++++ project2/common/pch.hpp | 2 +- project2/common/variables-modconfig.cpp | 56 +++++++++++++++- project2/common/xmlObjectLoader.cpp | 4 +- project2/common/xmlObjectLoader.h | 5 +- project2/console/claOptions.cpp | 61 ++++++++++++++++++ project2/console/consoleAppEngine.cpp | 7 -- project2/console/consoleAppEngine.h | 1 - project2/console/consoleEnvironment.cpp | 74 +++++++++------------ project2/console/consoleEnvironment.h | 15 +++-- project2/console/pch.hpp | 2 +- project2/files/Jamfile.jam | 4 +- project2/files/optionsSource.cpp | 62 ++++++++++++++++++ project2/files/optionsSource.h | 17 +++++ project2/json/couchSession.cpp | 13 ++-- project2/mail/sendmailTask.cpp | 11 ++-- project2/sql/pch.hpp | 2 +- project2/sql/sqlCache.cpp | 15 ++--- project2/xml/pch.hpp | 2 +- project2/xml/sessionXml.cpp | 13 ++-- project2/xml/xmlCache.cpp | 15 ++--- 42 files changed, 740 insertions(+), 427 deletions(-) delete mode 100644 project2/common/config.cpp delete mode 100644 project2/common/config.h create mode 100644 project2/common/options.cpp create mode 100644 project2/common/options.h create mode 100644 project2/common/optionsSource.h create mode 100644 project2/console/claOptions.cpp create mode 100644 project2/files/optionsSource.cpp create mode 100644 project2/files/optionsSource.h diff --git a/project2/cgi/Jamfile.jam b/project2/cgi/Jamfile.jam index 261e992..48225cb 100644 --- a/project2/cgi/Jamfile.jam +++ b/project2/cgi/Jamfile.jam @@ -2,7 +2,6 @@ alias libxmlpp : : : : "`pkg-config --cflags libxml++-2.6`" "`pkg-config --libs libxml++-2.6`" ; lib boost_filesystem : : boost_filesystem ; -lib boost_program_options : : boost_program_options ; lib cgicc : : cgicc ; lib fcgi : : fcgi ; lib fcgi++ : : fcgi++ ; @@ -12,7 +11,6 @@ cpp-pch pch : pch.hpp : cgicc libxmlpp ../common//p2common - boost_program_options boost_filesystem ../xml//p2xml ; @@ -24,7 +22,6 @@ lib p2web : cgicc libxmlpp ../common//p2common - boost_program_options boost_filesystem ../xml//p2xml : : diff --git a/project2/cgi/cgiAppEngine.cpp b/project2/cgi/cgiAppEngine.cpp index 779b25a..7fd7c33 100644 --- a/project2/cgi/cgiAppEngine.cpp +++ b/project2/cgi/cgiAppEngine.cpp @@ -9,7 +9,6 @@ #include #include "ostreamWrapper.h" #include -#include const std::string SESSIONID = "sessionID"; typedef UUID SIDKey; @@ -27,7 +26,6 @@ getSessionID(const std::vector & cookies) { return UUID(); } CgiApplicationEngine::CgiApplicationEngine(const CgiEnvironment * e, std::ostream & io) : - ApplicationEngine("web/host"), _env(e), sessionsContainer(LoaderBase::getLoader(e->sessionModule)->open()), IO(io) @@ -200,27 +198,3 @@ CgiApplicationEngine::session() const return cursession; } -bool -CgiApplicationEngine::checkDomain(const DomainPlatforms::value_type & i) const -{ - Glib::RefPtr reg = Glib::Regex::create(i.first, Glib::REGEX_CASELESS | Glib::REGEX_DOTALL); - return reg->match(_env->getServerName()); -} - -Glib::ustring -CgiApplicationEngine::resolveCurrentConfig() const -{ - DomainPlatforms::const_iterator i = std::find_if(domplat.begin(), domplat.end(), boost::bind(&CgiApplicationEngine::checkDomain, this, _1)); - if (i != domplat.end()) { - return i->second; - } - throw UnknownDomain(_env->getServerName()); -} - -void -CgiApplicationEngine::loadEngineSection(const xmlpp::Element * e) const -{ - domplat.push_back(DomainPlatforms::value_type(e->get_attribute_value("name"), e->get_attribute_value("platform"))); -} - - diff --git a/project2/cgi/cgiAppEngine.h b/project2/cgi/cgiAppEngine.h index e837b9d..25d3b93 100644 --- a/project2/cgi/cgiAppEngine.h +++ b/project2/cgi/cgiAppEngine.h @@ -36,7 +36,6 @@ class CgiApplicationEngine : public ApplicationEngine, public TransformChainLink void process() const; const Environment * env() const; SessionPtr session() const; - virtual Glib::ustring resolveCurrentConfig() const; void addAppData(const MultiRowSetPresenter * p, OutputOptionsPtr) const; void addEnvData(const MultiRowSetPresenter * p, OutputOptionsPtr) const; const CgiEnvironment * _env; @@ -44,10 +43,6 @@ class CgiApplicationEngine : public ApplicationEngine, public TransformChainLink private: mutable boost::posix_time::ptime startTime; mutable boost::posix_time::ptime endTime; - typedef std::pair DomainPlatform; - typedef std::list DomainPlatforms; - mutable DomainPlatforms domplat; - bool checkDomain(const DomainPlatforms::value_type & i) const; void loadEngineSection(const xmlpp::Element *) const; SessionContainerPtr sessionsContainer; // Helpers diff --git a/project2/cgi/cgiCommon.cpp b/project2/cgi/cgiCommon.cpp index 579e3f4..3664e9f 100644 --- a/project2/cgi/cgiCommon.cpp +++ b/project2/cgi/cgiCommon.cpp @@ -34,7 +34,7 @@ doExceptionReporting(const E & e, std::ostream & IO) IO << "Kaboom!" << std::endl << std::endl << buf << std::endl - << e.what() << std::endl; + << "what '" << e.what() << "'" << std::endl; free(buf); } diff --git a/project2/cgi/cgiEnvironment.cpp b/project2/cgi/cgiEnvironment.cpp index 541e7ae..ae7ad52 100644 --- a/project2/cgi/cgiEnvironment.cpp +++ b/project2/cgi/cgiEnvironment.cpp @@ -1,9 +1,11 @@ #include +#include #include "cgiEnvironment.h" #include "appEngine.h" #include "exceptions.h" #include #include +#include std::vector makeVector(const boost::filesystem::path & y) @@ -22,53 +24,56 @@ makeVector(const boost::filesystem::path & y) } CgiEnvironment::CgiEnvironment(cgicc::Cgicc * c) : - Environment(0, NULL), cgicc::CgiEnvironment(c->getEnvironment()), elems(makeVector(boost::filesystem::path(getRedirectURL()))), - cgi(c) + cgi(c), + cgiOptions("Project2 CGI options"), + hpi(new HostnamePlatformIdentifier()) { -} - -CgiEnvironment::~CgiEnvironment() -{ -} - -boost::program_options::options_description -CgiEnvironment::addOptions(boost::program_options::positional_options_description &) -{ - boost::program_options::options_description cgi("Project2 CGI options"); - cgi.add_options() - ("defaultpresenter", boost::program_options::value(&defaultPresenter)->default_value("xml"), + cgiOptions + ("cgi.defaultPresenter", Options::value(&defaultPresenter, "xml"), "The default engine for formatting presentations") - ("defaultpresent", boost::program_options::value(&defaultPresent)->default_value("index"), + ("cgi.defaultPresent", Options::value(&defaultPresent, "index"), "The present script to use when no other is specified") - ("presentroot", boost::program_options::value(&presentRoot)->default_value("present"), + ("cgi.presentRoot", Options::value(&presentRoot, "present"), "The folder in which to find presentation scripts") - ("requestroot", boost::program_options::value(&requestRoot)->default_value("request"), + ("cgi.requestRoot", Options::value(&requestRoot, "request"), "The folder in which to find request scripts") - ("errorpresentroot", boost::program_options::value(&errorPresentRoot)->default_value("error"), + ("cgi.errorPresentRoot", Options::value(&errorPresentRoot, "error"), "The folder in which to find presentation scripts for error handling") - ("errorcontenttype", boost::program_options::value(&errorContentType)->default_value("text/xml"), + ("cgi.errorContentType", Options::value(&errorContentType, "text/xml"), "The Content-Type to use in HTTP headers in event of an error") - ("errortransformstyle", boost::program_options::value(&errorTransformStyle), + ("cgi.errorTransformStyle", Options::value(&errorTransformStyle), "The xml-stylesheet to specify in the data document in event of an error") - ("notfoundpresent", boost::program_options::value(¬FoundPresent), + ("cgi.notFoundPresent", Options::value(¬FoundPresent), "The present script to use when the requested script does not exist") - ("onerrorpresent", boost::program_options::value(&onErrorPresent), + ("cgi.onErrorPresent", Options::value(&onErrorPresent), "The present script to use when the requested script (or child) fails") - ("dumpdatadoc", boost::program_options::value(&dumpdatadoc), + ("cgi.dumpDataDoc", Options::value(&dumpdatadoc), "Write a copy of the data document before sending it to the web server") - ("sessionModule", boost::program_options::value(&sessionModule)->default_value("xml"), + ("cgi.sessionModule", Options::value(&sessionModule, "xml"), "The module with which to implement session management") + ("cgi.hostRegex", hpi, + "Regular expression used to define a hostname -> platform association") ; - return cgi; } -void -CgiEnvironment::postinit(const boost::program_options::options_description &, const boost::program_options::variables_map &) +const Options & +CgiEnvironment::engineOptions() const { + return cgiOptions; +} + +CgiEnvironment::~CgiEnvironment() +{ +} + +const Glib::ustring & +CgiEnvironment::platform() const { + return hpi->derivedPlatform(); } + Glib::ustring CgiEnvironment::getParamUri(unsigned int p) const { @@ -88,3 +93,38 @@ CgiEnvironment::getParamQuery(const std::string & p) const return (*cgi)(p); } +HostnamePlatformIdentifier::HostnamePlatformIdentifier() : + platform(NULL) +{ +} + +HostnamePlatformIdentifier::~HostnamePlatformIdentifier() +{ + reset(); +} + +const Glib::ustring & +HostnamePlatformIdentifier::derivedPlatform() const +{ + if (platform) { + return *platform; + } + throw NoSuchPlatform(Environment::getCurrent()->getServerName()); +} + +void +HostnamePlatformIdentifier::reset() const +{ + if (platform) { + delete platform; + } +} + +void +HostnamePlatformIdentifier::consume(const Glib::ustring & p, const Glib::ustring & r) const +{ + if (!platform && Glib::Regex::create(r, Glib::REGEX_CASELESS | Glib::REGEX_DOTALL)->match(Environment::getCurrent()->getServerName())) { + platform = new Glib::ustring(p); + } +} + diff --git a/project2/cgi/cgiEnvironment.h b/project2/cgi/cgiEnvironment.h index fe99f5e..654f772 100644 --- a/project2/cgi/cgiEnvironment.h +++ b/project2/cgi/cgiEnvironment.h @@ -10,6 +10,17 @@ namespace cgicc { class Cgicc; } +class HostnamePlatformIdentifier : public Options::Target { + public: + HostnamePlatformIdentifier(); + virtual ~HostnamePlatformIdentifier(); + void reset() const; + void consume(const Glib::ustring &, const Glib::ustring &) const; + const Glib::ustring & derivedPlatform() const; + private: + mutable Glib::ustring * platform; +}; + class CgiEnvironment : public Environment, public cgicc::CgiEnvironment { public: CgiEnvironment(cgicc::Cgicc *); @@ -24,8 +35,11 @@ class CgiEnvironment : public Environment, public cgicc::CgiEnvironment { const cgicc::Cgicc * const cgi; private: - boost::program_options::options_description addOptions(boost::program_options::positional_options_description &); - void postinit(const boost::program_options::options_description &, const boost::program_options::variables_map &); + const Options & engineOptions() const; + const Glib::ustring & platform() const; + Options cgiOptions; + boost::intrusive_ptr hpi; + public: std::string dumpdatadoc; Glib::ustring errorContentType; diff --git a/project2/cgi/cgiOutputOptions.cpp b/project2/cgi/cgiOutputOptions.cpp index eb07b25..add1671 100644 --- a/project2/cgi/cgiOutputOptions.cpp +++ b/project2/cgi/cgiOutputOptions.cpp @@ -20,13 +20,13 @@ OutputOptions::OutputOptions(const xmlpp::Element * p) : OutputOptionsLoader::OutputOptionsLoader() : opts("CGI default output options") { - opts.add_options() - ("cgi.output.core", po::value(&OutputOptions::core)->default_value(true), "Core messages") - ("cgi.output.session", po::value(&OutputOptions::core)->default_value(true), "Session values") - ("cgi.output.timing", po::value(&OutputOptions::core)->default_value(true), "Timing") - ("cgi.output.environment", po::value(&OutputOptions::core)->default_value(true), "Environment") - ("cgi.output.url", po::value(&OutputOptions::core)->default_value(true), "URL breakdown") - ("cgi.output.parameters", po::value(&OutputOptions::core)->default_value(true), "Parameters") + opts + ("cgi.output.core", Options::value(&OutputOptions::core, true), "Core messages") + ("cgi.output.session", Options::value(&OutputOptions::core, true), "Session values") + ("cgi.output.timing", Options::value(&OutputOptions::core, true), "Timing") + ("cgi.output.environment", Options::value(&OutputOptions::core, true), "Environment") + ("cgi.output.url", Options::value(&OutputOptions::core, true), "URL breakdown") + ("cgi.output.parameters", Options::value(&OutputOptions::core, true), "Parameters") ; } @@ -35,8 +35,8 @@ OutputOptionsLoader::createFrom(const xmlpp::Element * e) const { return new OutputOptions(e); } -po::options_description * -OutputOptionsLoader::options() +const Options * +OutputOptionsLoader::options() const { return &opts; } diff --git a/project2/cgi/cgiOutputOptions.h b/project2/cgi/cgiOutputOptions.h index 540764e..a1ff62d 100644 --- a/project2/cgi/cgiOutputOptions.h +++ b/project2/cgi/cgiOutputOptions.h @@ -2,7 +2,7 @@ #define OUTPUTOPTIONS_H #include "intrusivePtrBase.h" -#include +#include "options.h" #include "variables.h" namespace xmlpp { @@ -32,15 +32,14 @@ class OutputOptions : public IntrusivePtrBase { }; typedef boost::intrusive_ptr OutputOptionsPtr; -namespace po = boost::program_options; class OutputOptionsLoader : public ComponentLoader { public: OutputOptionsLoader(); OutputOptionsPtr createFrom(const xmlpp::Element * e) const; - po::options_description * options(); + const Options * options() const; private: - po::options_description opts; + Options opts; }; #endif diff --git a/project2/cgi/cgiStageFail.cpp b/project2/cgi/cgiStageFail.cpp index 97ac22a..87aba66 100644 --- a/project2/cgi/cgiStageFail.cpp +++ b/project2/cgi/cgiStageFail.cpp @@ -1,4 +1,5 @@ #include +#include #include "cgiAppEngine.h" #include "cgiEnvironment.h" #include "cgiHttpHeader.h" diff --git a/project2/cgi/pch.hpp b/project2/cgi/pch.hpp index b3c7108..ff0b175 100644 --- a/project2/cgi/pch.hpp +++ b/project2/cgi/pch.hpp @@ -13,7 +13,7 @@ #include "xmlObjectLoader.h" #include #include -#include +#include "options.h" #include #include #include diff --git a/project2/cgi/testCgi.cpp b/project2/cgi/testCgi.cpp index 438e1b0..c2e8d4e 100644 --- a/project2/cgi/testCgi.cpp +++ b/project2/cgi/testCgi.cpp @@ -1,70 +1,71 @@ #include -#include -#include +#include +#include +#include "options.h" +#include "safeMapFind.h" #include "cgiCommon.h" +#include "../files/optionsSource.h" -namespace po = boost::program_options; - +#define TESTOPT(name, def, desc) \ + (name, Options::value(optStore.insert(OptStore::value_type(name, new std::string())).first->second, def), desc) class TestInput : public cgicc::CgiInput { public: - TestInput(int argc, char ** argv) + typedef std::string * StrPtr; + typedef std::map OptStore; + OptStore optStore; + TestInput() : + opts("Project2 CGI test options") { - po::options_description test("Project2 CGI test options"); - test.add_options() - ("help,h", "Print usage and exit") - ("SERVER_NAME", "FQDN of web service") - ("SERVER_SOFTWARE", po::value()->default_value("Apache"), "") - ("GATEWAY_INTERFACE", po::value()->default_value("CGI/1.1"), "") - ("SERVER_PROTOCOL", po::value()->default_value("HTTP/1.1"), "") - ("SERVER_PORT", po::value()->default_value("80"), "") - ("REQUEST_METHOD", po::value()->default_value("GET"), "") - ("PATH_INFO", "") - ("PATH_TRANSLATED", "") - ("SCRIPT_NAME", po::value()->default_value("p2fcgi"), "") - ("QUERY_STRING", "") - ("REMOTE_HOST", "") - ("REMOTE_ADDR", "") - ("AUTH_TYPE", "") - ("REMOTE_USER", "") - ("REMOTE_IDENT", "") - ("CONTENT_TYPE", "") - ("CONTENT_LENGTH", "") - ("HTTP_ACCEPT", po::value()->default_value("text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"), "") - ("HTTP_USER_AGENT", po::value()->default_value("Mozilla/5.0"), "") - ("REDIRECT_REQUEST", "") - ("REDIRECT_URL", "") - ("REDIRECT_STATUS", "") - ("HTTP_REFERER", "") - ("HTTP_COOKIE", "") - ("HTTPS", po::value()->default_value("No"), "") + opts + TESTOPT("SERVER_NAME", "localhost", "FQDN of web service") + TESTOPT("SERVER_SOFTWARE", "Apache", "Web server version string") + TESTOPT("GATEWAY_INTERFACE", "CGI/1.1", "Web server/script interface version") + TESTOPT("SERVER_PROTOCOL", "HTTP/1.1", "Web server/client interface version") + TESTOPT("SERVER_PORT", "80", "Server Port") + TESTOPT("REQUEST_METHOD", "GET", "Request method") + TESTOPT("PATH_INFO", "", "Path info") + TESTOPT("PATH_TRANSLATED", "", "Path translated") + TESTOPT("SCRIPT_NAME", "p2fcgi", "Script name") + TESTOPT("QUERY_STRING", "", "Query string") + TESTOPT("REMOTE_HOST", "", "Remote host") + TESTOPT("REMOTE_ADDR", "", "Remote address") + TESTOPT("AUTH_TYPE", "", "Authentication type") + TESTOPT("REMOTE_USER", "", "Remote user") + TESTOPT("REMOTE_IDENT", "", "Remote ident") + TESTOPT("CONTENT_TYPE", "", "Content type") + TESTOPT("CONTENT_LENGTH", "", "Content length") + TESTOPT("HTTP_ACCEPT", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", "Accepted MIME types") + TESTOPT("HTTP_USER_AGENT", "Mozilla/5.0", "User agent") + TESTOPT("REDIRECT_REQUEST", "", "Redirect request") + TESTOPT("REDIRECT_URL", "", "Redirect URL") + TESTOPT("REDIRECT_STATUS", "", "Redirect status") + TESTOPT("HTTP_REFERER", "", "Referrer") + TESTOPT("HTTP_COOKIE", "", "Cookie") + TESTOPT("HTTPS", "No", "HTTPS?") ; - po::parsed_options parsed = po::command_line_parser(argc, argv).options(test).allow_unregistered().run(); - po::store(parsed, settings); - if (boost::filesystem::exists("testCgi.settings")) { - std::ifstream f("testCgi.settings"); - po::store(po::parse_config_file(f, test, true), settings); - } - po::notify(settings); - if (settings.count("help")) { - std::cout << test; - exit(1); - } + FileOptions fo(".testCgi.settings"); + opts.reset(); + fo.loadInto(boost::bind(&Options::consume, &opts, _1, _2, _3)); + } + + const Options * options() const { + return &opts; } - virtual std::string getenv(const char *varName) + + virtual std::string getenv(const char * varName) { - if (settings.count(varName)) { - return settings[varName].as(); - } - return ""; + StrPtr def(new std::string()); + return *defaultMapFind(optStore, varName, def); } + private: - po::variables_map settings; + Options opts; }; int -main(int argc, char ** argv) +main(int, char **) { - TestInput ti(argc, argv); + TestInput ti; cgiServe(&ti, std::cout); } diff --git a/project2/common/Jamfile.jam b/project2/common/Jamfile.jam index f08a2ff..4964ea1 100644 --- a/project2/common/Jamfile.jam +++ b/project2/common/Jamfile.jam @@ -5,7 +5,6 @@ lib dl : : dl ; lib boost_system : : boost_system ; lib boost_filesystem : : boost_filesystem ; lib boost_date_time : : boost_date_time ; -lib boost_program_options : : boost_program_options ; cpp-pch pch : pch.hpp : ../../libmisc @@ -24,12 +23,10 @@ lib p2common : boost_system boost_filesystem boost_date_time - boost_program_options ../uuid//p2uuid : : . ../../libmisc boost_system - boost_program_options ; diff --git a/project2/common/appEngine.cpp b/project2/common/appEngine.cpp index 245f4e5..db44a94 100644 --- a/project2/common/appEngine.cpp +++ b/project2/common/appEngine.cpp @@ -7,8 +7,7 @@ ApplicationEngine * ApplicationEngine::currentEngine = NULL; -ApplicationEngine::ApplicationEngine(const Glib::ustring & engineKeys) : - Configuration(engineKeys) +ApplicationEngine::ApplicationEngine() { if (currentEngine) { throw std::runtime_error("One application at a time, please"); diff --git a/project2/common/appEngine.h b/project2/common/appEngine.h index 85e7229..6de21e1 100644 --- a/project2/common/appEngine.h +++ b/project2/common/appEngine.h @@ -3,11 +3,10 @@ #include "environment.h" #include "session.h" -#include "config.h" class MultiRowSetPresenter; -class ApplicationEngine : public Configuration { +class ApplicationEngine { public: class Message : public IntrusivePtrBase { public: @@ -19,7 +18,7 @@ class ApplicationEngine : public Configuration { typedef boost::intrusive_ptr MessagePtr; typedef std::list Messages; - ApplicationEngine(const Glib::ustring & engineKeys); + ApplicationEngine(); virtual ~ApplicationEngine() = 0; void logMessage(bool writeLog, const Glib::ustring & g, const Glib::ustring & m); diff --git a/project2/common/config.cpp b/project2/common/config.cpp deleted file mode 100644 index cb316e5..0000000 --- a/project2/common/config.cpp +++ /dev/null @@ -1,73 +0,0 @@ -#include -#include "config.h" -#include "safeMapFind.h" -#include "exceptions.h" -#include -#include -#include "xmlScriptParser.h" - -SimpleMessageException(NoSuchPlatform); -SimpleMessageException(NoSuchConfigurationValue); - -Configuration::Configuration(const Glib::ustring & ek) : - loaded(false), - engineKeys(ek) -{ -} - -void -Configuration::load() const -{ - if (loaded) { - return; - } - loaded = true; - if (!boost::filesystem::exists("config.xml")) { - return; - } - XmlScriptParser configxml("config.xml", true); - xmlpp::NodeSet ps(configxml.get_document()->get_root_node()->find("platform")); - BOOST_FOREACH(const xmlpp::Node * p, ps) { - const xmlpp::Element * pe = dynamic_cast(p); - if (pe) { - platforms[pe->get_attribute_value("name")] = new Platform(pe); - } - } - xmlpp::NodeSet eks(configxml.get_document()->get_root_node()->find(engineKeys)); - BOOST_FOREACH(const xmlpp::Node * ek, eks) { - const xmlpp::Element * eke = dynamic_cast(ek); - if (eke) { - loadEngineSection(eke); - } - } -} - -Configuration::~Configuration() -{ -} - -Configuration::PlatformPtr -Configuration::getCurrentConfig() const -{ - load(); - Glib::ustring platformName(resolveCurrentConfig()); - return safeMapLookup(platforms, platformName); -} - -const Glib::ustring & -Configuration::Platform::getValue(const Glib::ustring & key) const -{ - return safeMapLookup(values, key); -} - -Configuration::Platform::Platform(const xmlpp::Element * e) -{ - xmlpp::NodeSet vs(e->find("variable")); - BOOST_FOREACH(const xmlpp::Node * v, vs) { - const xmlpp::Element * ve = dynamic_cast(v); - if (ve) { - values.insert(Values::value_type(ve->get_attribute_value("name"), ve->get_attribute_value("value"))); - } - } -} - diff --git a/project2/common/config.h b/project2/common/config.h deleted file mode 100644 index 9f6cd5d..0000000 --- a/project2/common/config.h +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef CONFIG_H -#define CONFIG_H - -#include -#include -#include "intrusivePtrBase.h" -#include - -class Configuration { - public: - class Platform : public virtual IntrusivePtrBase { - public: - typedef std::map Values; - - Platform(const xmlpp::Element * instanceRoot); - const Glib::ustring & getValue(const Glib::ustring & key) const; - - private: - Values values; - }; - typedef boost::intrusive_ptr PlatformPtr; - - typedef std::map Platforms; - - Configuration(const Glib::ustring & engineKeys); - virtual ~Configuration() = 0; - - PlatformPtr getCurrentConfig() const; - - protected: - virtual Glib::ustring resolveCurrentConfig() const = 0; - void load() const; - - private: - virtual void loadEngineSection(const xmlpp::Element *) const = 0; - - mutable bool loaded; - mutable Platforms platforms; - const Glib::ustring engineKeys; -}; - -#endif - diff --git a/project2/common/environment.cpp b/project2/common/environment.cpp index 3106e9a..18d60a0 100644 --- a/project2/common/environment.cpp +++ b/project2/common/environment.cpp @@ -1,5 +1,6 @@ #include #include "environment.h" +#include "optionsSource.h" #include "loggers.h" #include "xmlObjectLoader.h" #include @@ -8,73 +9,66 @@ #include #include -namespace po = boost::program_options; - const Environment * Environment::currentEnv(NULL); int Environment::clLevel(-1); int Environment::slLevel(-1); -bool Environment::optionsBuilt(false); -po::options_description Environment::allOptions("Project2 options"); -po::positional_options_description Environment::posOptions; -Environment::Environment(int c, char ** v) : - argc(c), - argv(v) +Environment::Environment() : + commonOptions("Project2 Common options") { currentEnv = this; + commonOptions + ("common.syslogLevel", Options::value(&slLevel, -1), + "Log to syslog with level (default OFF)")("s") + ("common.consolelogLevel", Options::value(&clLevel, LOG_WARNING), + "Log to console with level (default WARNING)")("c") + ("common.datasourceRoot", Options::value(&datasourceRoot, "datasources"), + "The folder in which to find datasource definitions") + ("common.namespace", Options::value(&xmlNamespace, "http://project2.randomdan.homeip.net"), + "The namespace to use for Project2 components and responses") + ("common.namespacePrefix", Options::value(&xmlPrefix, "project2"), + "The namespace prefix to use for the Project2 namespace") + ("common.sessionTimeOut", Options::value(&sessionTimeOut, 3600), + "The time after which idle sessions are forgetten") + ; } +typedef std::vector AllOptions; + static -po::variables_map -injectSettingsHelper(int argc, char ** argv, const po::options_description * opts, po::positional_options_description * posOpts) +void +optionsHelper(AllOptions * ao, const Options * options) { - po::variables_map settings; - if (!opts) { - return settings; - } - if (argc > 0 && argv != NULL) { - if (posOpts) { - po::store(po::command_line_parser(argc, argv).options(*opts).positional(*posOpts).allow_unregistered().run(), settings); - } - else { - po::store(po::command_line_parser(argc, argv).options(*opts).allow_unregistered().run(), settings); - } + if (options) { + ao->push_back(options); } - po::store(po::parse_environment(*opts, "P2_"), settings); - if (boost::filesystem::exists(".p2config")) { - std::ifstream f(".p2config"); - po::store(po::parse_config_file(f, *opts, true), settings); +} + +static +void +consumeIntoAll(const AllOptions * ao, const Glib::ustring & n, const Glib::ustring & p, const Glib::ustring & v) +{ + BOOST_FOREACH(const Options * o, *ao) { + o->consume(n, p, v); } - po::notify(settings); - return settings; } void Environment::init() { - if (!optionsBuilt) { - po::options_description common("Project2 Common options"); - common.add_options() - ("sysloglevel,s", po::value(&slLevel)->default_value(-1), - "Log to syslog with level (default OFF)") - ("consoleloglevel,c", po::value(&clLevel)->default_value(LOG_WARNING), - "Log to console with level (default WARNING)") - ("datasourceroot", boost::program_options::value(&datasourceRoot)->default_value("datasources"), - "The folder in which to find datasource definitions") - ("xmlnamespace", boost::program_options::value(&xmlNamespace)->default_value("http://project2.randomdan.homeip.net"), - "The XML namespace to use for Project2 components and responses") - ("xmlprefix", boost::program_options::value(&xmlPrefix)->default_value("project2"), - "The XML namespace prefix to use for the Project2 XML namespace") - ("sessionTimeOut", boost::program_options::value(&sessionTimeOut)->default_value(3600), - "The time after which idle sessions are forgetten") - ; - allOptions.add(common).add(addOptions(posOptions)); - optionsBuilt = true; + AllOptions allOptions; + allOptions.push_back(&commonOptions); + allOptions.push_back(&engineOptions()); + LoaderBase::onAllComponents(boost::bind(optionsHelper, &allOptions, boost::bind(&ComponentLoader::options, _1))); + + BOOST_FOREACH(const AllOptions::value_type & v, allOptions) { + v->reset(); + } + + typedef std::map > ConfigParsersMap; + BOOST_FOREACH(const ConfigParsersMap::value_type & cp, *LoaderBase::objLoaders()) { + cp.second->create()->loadInto(boost::bind(&consumeIntoAll, &allOptions, _1, _2, _3)); } - po::variables_map settings(injectSettingsHelper(argc, argv, &allOptions, &posOptions)); - postinit(allOptions, settings); - LoaderBase::onAllComponents(boost::bind( - injectSettingsHelper, argc, argv, boost::bind(&ComponentLoader::options, _1), (po::positional_options_description*)NULL)); Logger()->clear(); if (clLevel >= 0) { diff --git a/project2/common/environment.h b/project2/common/environment.h index 367d800..6185178 100644 --- a/project2/common/environment.h +++ b/project2/common/environment.h @@ -3,13 +3,16 @@ #include #include -#include #include #include +#include "options.h" +#include "exceptions.h" + +SimpleMessageException(NoSuchPlatform); class Environment { public: - Environment(int argc, char ** argv); + Environment(); virtual ~Environment() = 0; void init(); @@ -21,20 +24,15 @@ class Environment { virtual std::string getServerName() const = 0; virtual std::string getScriptName() const = 0; + virtual const Glib::ustring & platform() const = 0; boost::filesystem::path resolveScript(const std::string & group, const std::string & name) const; private: - static const Environment * currentEnv; + Options commonOptions; + virtual const Options & engineOptions() const = 0; - virtual boost::program_options::options_description addOptions(boost::program_options::positional_options_description &) = 0; - virtual void postinit(const boost::program_options::options_description &, const boost::program_options::variables_map &) = 0; - int argc; - char ** argv; - - static bool optionsBuilt; - static boost::program_options::options_description allOptions; - static boost::program_options::positional_options_description posOptions; + static const Environment * currentEnv; static int clLevel; static int slLevel; diff --git a/project2/common/memoryCache.cpp b/project2/common/memoryCache.cpp index 34d2cf9..5942cb8 100644 --- a/project2/common/memoryCache.cpp +++ b/project2/common/memoryCache.cpp @@ -2,7 +2,7 @@ #include "logger.h" #include "cache.h" #include -#include +#include "options.h" #include "rowSet.h" #include "presenter.h" #include "safeMapFind.h" @@ -145,19 +145,18 @@ class MemoryCache : public Cache { time_t MemoryCache::CacheLife; MemoryCache::CacheStore MemoryCache::Store; -namespace po = boost::program_options; class CustomMemoryCacheLoader : public ElementLoaderImpl { public: CustomMemoryCacheLoader() : opts("Memory Cache options") { - opts.add_options() - ("cache.memory.life", po::value(&MemoryCache::CacheLife)->default_value(3600), + opts + ("cache.memory.life", Options::value(&MemoryCache::CacheLife, 3600), "The age of cache entries after which they are removed (seconds)") ; } - po::options_description * options() { + const Options * options() const { return &opts; } @@ -169,7 +168,7 @@ class CustomMemoryCacheLoader : public ElementLoaderImpl { } private: - po::options_description opts; + Options opts; }; DECLARE_CUSTOM_LOADER("memorycache", CustomMemoryCacheLoader); diff --git a/project2/common/options.cpp b/project2/common/options.cpp new file mode 100644 index 0000000..a99c78e --- /dev/null +++ b/project2/common/options.cpp @@ -0,0 +1,110 @@ +#include +#include "options.h" +#include "environment.h" +#include + +class NamedOption : public Options::Option { + public: + NamedOption(Glib::ustring const & n, Options::TargetPtr t, Glib::ustring const & d) : + name(n), + target(t), + desc(d) + { + } + void consume(const Glib::ustring & n, const Glib::ustring & p, const Glib::ustring & v) const { + if (n == name) { + target->consume(p, v); + } + } + void reset() const { + target->reset(); + } + + const Glib::ustring name; + const Options::TargetPtr target; + const Glib::ustring desc; +}; + +class OptionAlias : public Options::Option { + public: + OptionAlias(const Glib::ustring & a, Options::TargetPtr t) : + alias(a), + target(t) + { + } + void consume(const Glib::ustring & a, const Glib::ustring & p, const Glib::ustring & v) const { + if (a == alias) { + target->consume(p, v); + } + } + void reset() const { + target->reset(); + } + const Glib::ustring alias; + const Options::TargetPtr target; +}; + +Options::Options(Glib::ustring const&) +{ +} + +Options & +Options::operator()(const Glib::ustring & n, TargetPtr t, const Glib::ustring & d) +{ + options.push_back(new NamedOption(n, t, d)); + return *this; +} + +Options & +Options::operator()(const Glib::ustring & a) +{ + for (OptionList::const_reverse_iterator i = options.rbegin(); i != options.rend(); i++) { + if (const NamedOption * no = dynamic_cast(i->get())) { + options.push_back(new OptionAlias(a, no->target)); + break; + } + } + return *this; +} + +Options & +Options::operator()(OptionPtr o) +{ + options.push_back(o); + return *this; +} + +void +Options::reset() const +{ + BOOST_FOREACH(const OptionPtr & o, options) { + o->reset(); + } +} + +void +Options::consume(const Glib::ustring & n, const Glib::ustring & p, const Glib::ustring & v) const +{ + BOOST_FOREACH(const OptionPtr & o, options) { + o->consume(n, p, v); + } +} + +Options::InstanceTarget::InstanceTarget() : + ts(Default) +{ +} + +void +Options::InstanceTarget::consume(const Glib::ustring & p, const Glib::ustring & v) const +{ + if (ts != Platform && p.empty()) { + assign(v); + ts = Global; + } + else if (!p.empty() && p == Environment::getCurrent()->platform()) { + assign(v); + ts = Platform; + } +} + diff --git a/project2/common/options.h b/project2/common/options.h new file mode 100644 index 0000000..77c71b5 --- /dev/null +++ b/project2/common/options.h @@ -0,0 +1,110 @@ +#ifndef OPTIONS_H +#define OPTIONS_H + +#include +#include +#include +#include +#include + +class Options { + public: + class Target; + template class TypedTarget; + + enum TargetState { Default = 1, Global = 2, Platform = 3 }; + class Target : public IntrusivePtrBase { + public: + virtual void reset() const = 0; + virtual void consume(const Glib::ustring & platform, const Glib::ustring & value) const = 0; + }; + typedef boost::intrusive_ptr TargetPtr; + + class InstanceTarget : public Target { + public: + InstanceTarget(); + void consume(const Glib::ustring & platform, const Glib::ustring & value) const; + protected: + virtual void assign(const Glib::ustring & value) const = 0; + mutable TargetState ts; + }; + + template class TypedTarget : public InstanceTarget { + public: + TypedTarget(T * t) : + target(t) { + } + void reset() const { + ts = Default; + *target = T(); + } + void assign(const Glib::ustring & value) const { + *target = boost::lexical_cast(value); + } + protected: + T * target; + }; + + template class TypedTarget > : public InstanceTarget { + public: + typedef std::vector VofT; + TypedTarget(VofT * t) : + target(t) { + } + void reset() const { + ts = Default; + target->clear(); + } + void assign(const Glib::ustring & value) const { + target->push_back(boost::lexical_cast(value)); + } + protected: + VofT * target; + }; + + template class DefaultTypedTarget : public TypedTarget { + public: + DefaultTypedTarget(T * t, const T & d) : + TypedTarget(t), + defValue(d) { + } + void reset() const { + InstanceTarget::ts = Default; + *TypedTarget::target = defValue; + } + private: + T defValue; + }; + + class Option : public IntrusivePtrBase { + public: + virtual void reset() const = 0; + virtual void consume(const Glib::ustring & name, const Glib::ustring & platform, const Glib::ustring & value) const = 0; + }; + typedef boost::intrusive_ptr