From 99e694337f0b7dd3749b142e8abe77b70754cff8 Mon Sep 17 00:00:00 2001 From: randomdan Date: Fri, 4 Feb 2011 14:39:54 +0000 Subject: Add concept of runtime configuration, set by HTTP hostname or environment variable depending on engine Use it in ArtfulSeller, although there is currently only one platform --- project2/Jamfile.jam | 2 +- project2/appEngine.cpp | 3 +- project2/appEngine.h | 5 ++- project2/cgi/cgiAppEngine.cpp | 28 +++++++++++- project2/cgi/cgiAppEngine.h | 13 ++++++ project2/config.cpp | 81 +++++++++++++++++++++++++++++++++++ project2/config.h | 43 +++++++++++++++++++ project2/console/consoleAppEngine.cpp | 25 ++++++++++- project2/console/consoleAppEngine.h | 9 +++- project2/sqlCheck.cpp | 6 ++- project2/sqlCheck.h | 2 +- project2/sqlMergeTask.cpp | 4 +- project2/sqlMergeTask.h | 66 ++++++++++++++-------------- project2/sqlRows.cpp | 5 ++- project2/sqlRows.h | 2 +- project2/sqlTask.cpp | 6 ++- project2/sqlTask.h | 2 +- project2/variables.cpp | 21 +++++++++ 18 files changed, 272 insertions(+), 51 deletions(-) create mode 100644 project2/config.cpp create mode 100644 project2/config.h diff --git a/project2/Jamfile.jam b/project2/Jamfile.jam index e2eaf42..d42e278 100644 --- a/project2/Jamfile.jam +++ b/project2/Jamfile.jam @@ -33,7 +33,7 @@ lib p2common : iterate.cpp paramChecker.cpp presenter.cpp rawView.cpp dumpTask.cpp sourceObject.cpp task.cpp variables.cpp view.cpp xmlObjectLoader.cpp exceptions.cpp sessionClearTask.cpp session.cpp sessionSetTask.cpp commonObjects.cpp xmlPresenter.cpp - rowView.cpp rowSet.cpp rowUser.cpp rowProcessor.cpp + rowView.cpp rowSet.cpp rowUser.cpp rowProcessor.cpp config.cpp : ../libmisc//misc libxmlpp diff --git a/project2/appEngine.cpp b/project2/appEngine.cpp index 3961ffe..1489cd1 100644 --- a/project2/appEngine.cpp +++ b/project2/appEngine.cpp @@ -3,7 +3,8 @@ ApplicationEngine * ApplicationEngine::currentEngine = NULL; -ApplicationEngine::ApplicationEngine() +ApplicationEngine::ApplicationEngine(const Glib::ustring & engineKeys) : + Configuration(engineKeys) { if (currentEngine) { throw std::runtime_error("One application at a time, please"); diff --git a/project2/appEngine.h b/project2/appEngine.h index 04fe486..2921b2d 100644 --- a/project2/appEngine.h +++ b/project2/appEngine.h @@ -4,10 +4,11 @@ #include "environment.h" #include "session.h" #include "presenter.h" +#include "config.h" -class ApplicationEngine { +class ApplicationEngine : public Configuration { public: - ApplicationEngine(); + ApplicationEngine(const Glib::ustring & engineKeys); virtual ~ApplicationEngine() = 0; virtual void process() const = 0; diff --git a/project2/cgi/cgiAppEngine.cpp b/project2/cgi/cgiAppEngine.cpp index d1c1579..3a9e362 100644 --- a/project2/cgi/cgiAppEngine.cpp +++ b/project2/cgi/cgiAppEngine.cpp @@ -7,6 +7,7 @@ #include "../xmlObjectLoader.h" #include "../iterate.h" #include +#include #include "../sessionXml.h" const std::string SESSIONID = "sessionID"; @@ -15,8 +16,10 @@ typedef std::string SValue; SessionContainer * sessionsContainer = new SessionContainerXml(); +class UnknownDomain : public std::exception { }; + CgiApplicationEngine::CgiApplicationEngine(const CgiEnvironment * e) : - ApplicationEngine(), + ApplicationEngine("web/host"), _env(e), header(NULL) { @@ -181,3 +184,26 @@ CgiApplicationEngine::session() const return sessionsContainer->GetSession(sessionID); } +bool +CgiApplicationEngine::checkDomain(const CgiApplicationEngine::DomainPlatforms::value_type & i) const +{ + const std::string & h = _env->getServerName(); + return boost::regex_match(h.begin(), h.end(), boost::regex(i.first.raw())); +} + +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(); +} + +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 532b74d..5a21e98 100644 --- a/project2/cgi/cgiAppEngine.h +++ b/project2/cgi/cgiAppEngine.h @@ -31,12 +31,22 @@ class CgiApplicationEngine : public ApplicationEngine { } const Environment * env() const; SessionPtr session() const; + virtual Glib::ustring resolveCurrentConfig() const; void addAppData(const Presenter * p) const; const CgiEnvironment * _env; + protected: mutable cgicc::HTTPContentHeader * header; + private: + 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; + mutable boost::shared_ptr doc; + class Stage; typedef boost::intrusive_ptr StagePtr; class Stage : public virtual CommonObjects { @@ -47,6 +57,7 @@ class CgiApplicationEngine : public ApplicationEngine { protected: const CgiApplicationEngine * appEngine; }; + class RequestStage : public Stage { public: RequestStage(const CgiApplicationEngine *, const std::string & id); @@ -57,12 +68,14 @@ class CgiApplicationEngine : public ApplicationEngine { OrderedParamCheckers parameterChecks; NoOutputExecutes tasks; }; + class PresentStage : public Stage, public XmlPresenter { public: PresentStage(const CgiApplicationEngine *, const std::string & id); PresentStage(const CgiApplicationEngine *, const std::string & group, const std::string & id); virtual ~PresentStage(); virtual StagePtr run(); + }; mutable StagePtr currentStage; mutable UUID sessionID; diff --git a/project2/config.cpp b/project2/config.cpp new file mode 100644 index 0000000..f973c05 --- /dev/null +++ b/project2/config.cpp @@ -0,0 +1,81 @@ +#include "config.h" +#include "exceptions.h" +#include +#include +#include +#include + +class NoSuchPlatform : public std::exception { }; +class NoSuchConfigurationValue : public std::exception { }; + +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; + } + xmlpp::DomParser configxml("config.xml"); + while (xmlXIncludeProcessFlags(configxml.get_document()->cobj(), XML_PARSE_NOXINCNODE) > 0); + 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()); + Platforms::const_iterator i = platforms.find(platformName); + if (i == platforms.end()) { + throw NoSuchPlatform(); + } + return i->second; +} + +const Glib::ustring & +Configuration::Platform::getValue(const Glib::ustring & key) const +{ + Values::const_iterator i = values.find(key); + if (i == values.end()) { + throw NoSuchConfigurationValue(); + } + return i->second; +} + +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/config.h b/project2/config.h new file mode 100644 index 0000000..9f6cd5d --- /dev/null +++ b/project2/config.h @@ -0,0 +1,43 @@ +#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/console/consoleAppEngine.cpp b/project2/console/consoleAppEngine.cpp index bd17458..43b58c9 100644 --- a/project2/console/consoleAppEngine.cpp +++ b/project2/console/consoleAppEngine.cpp @@ -3,6 +3,9 @@ #include "../iterate.h" #include #include +#include + +class UnknownPlatformAlias : public std::exception { }; class ConsoleSession : public Session { public: @@ -49,7 +52,7 @@ class ConsoleSession : public Session { }; ConsoleApplicationEngine::ConsoleApplicationEngine(const ConsoleEnvironment * env, const boost::filesystem::path & f) : - ApplicationEngine(), + ApplicationEngine("console/environment"), _env(env), runtime(new ConsoleSession()) { @@ -138,3 +141,23 @@ ConsoleApplicationEngine::ConsolePresenter::popSub() const indent -= 2; } +Glib::ustring +ConsoleApplicationEngine::resolveCurrentConfig() const +{ + const char * e = getenv("P2_PLATFORM"); + if (!e) { + e = ""; + } + ConsolePlatforms::const_iterator i = conplat.find(e); + if (i != conplat.end()) { + return i->second; + } + throw UnknownPlatformAlias(); +} + +void +ConsoleApplicationEngine::loadEngineSection(const xmlpp::Element * e) const +{ + conplat.insert(ConsolePlatforms::value_type(e->get_attribute_value("setting"), e->get_attribute_value("platform"))); +} + diff --git a/project2/console/consoleAppEngine.h b/project2/console/consoleAppEngine.h index 9d4ee96..abc471f 100644 --- a/project2/console/consoleAppEngine.h +++ b/project2/console/consoleAppEngine.h @@ -9,7 +9,6 @@ #include #include #include -#include class ConsoleEnvironment; @@ -21,10 +20,17 @@ class ConsoleApplicationEngine : public ApplicationEngine, public CommonObjects void process() const; const Environment * env() const; SessionPtr session() const; + virtual Glib::ustring resolveCurrentConfig() const; virtual void addAppData(const Presenter * p) const; + protected: const ConsoleEnvironment * _env; + private: + typedef std::map ConsolePlatforms; + mutable ConsolePlatforms conplat; + void loadEngineSection(const xmlpp::Element *) const; + class ConsolePresenter : public Presenter { public: ConsolePresenter(const ConsoleApplicationEngine *, const std::string & id); @@ -37,6 +43,7 @@ class ConsoleApplicationEngine : public ApplicationEngine, public CommonObjects private: mutable unsigned int indent; }; + OrderedParamCheckers parameterChecks; NoOutputExecutes tasks; SessionPtr runtime; diff --git a/project2/sqlCheck.cpp b/project2/sqlCheck.cpp index 3537134..9a5bb94 100644 --- a/project2/sqlCheck.cpp +++ b/project2/sqlCheck.cpp @@ -6,6 +6,7 @@ #include #include "commonObjects.h" #include "sqlVariableBinder.h" +#include "genericVisitor.h" ElementLoaderImpl sqlCheckLoader("sqlcheck"); @@ -13,7 +14,7 @@ SqlCheck::SqlCheck(const xmlpp::Element * p) : SourceObject(p), IHaveParameters(p), ParamChecker(p), - dataSource(p->get_attribute_value("datasource")), + dataSource(p, "datasource"), sql(xmlChildText(p, "sql")), testOp(p->get_attribute_value("testOp")), testValue(atof(p->get_attribute_value("testValue").c_str())), @@ -29,7 +30,8 @@ SqlCheck::~SqlCheck() void SqlCheck::loadComplete(const CommonObjects * co) { - query = new ODBC::SelectCommand(co->dataSource(dataSource)->getReadonly(), sql); + query = new ODBC::SelectCommand(LexicalCall(boost::bind( + &CommonObjects::dataSource, co, _1), dataSource)->getReadonly(), sql); } bool diff --git a/project2/sqlCheck.h b/project2/sqlCheck.h index e4f79ee..bfc7b37 100644 --- a/project2/sqlCheck.h +++ b/project2/sqlCheck.h @@ -14,7 +14,7 @@ class SqlCheck : public IHaveParameters, public ParamChecker { virtual void loadComplete(const CommonObjects *); bool performCheck() const; - const std::string dataSource; + const Variable dataSource; const Glib::ustring sql; const std::string testOp; const double testValue; diff --git a/project2/sqlMergeTask.cpp b/project2/sqlMergeTask.cpp index 2436f1f..6a5ebf7 100644 --- a/project2/sqlMergeTask.cpp +++ b/project2/sqlMergeTask.cpp @@ -49,7 +49,7 @@ SqlMergeTask::SqlMergeTask(const xmlpp::Element * p) : tempTableCreated(false), insCmd(NULL), destdb(NULL), - dataSource(p->get_attribute_value("datasource")), + dataSource(p, "datasource"), dtable(p->get_attribute_value("targettable")), dtablet(stringf("tmp_%s_%d", dtable.c_str(), getpid())) { @@ -89,7 +89,7 @@ SqlMergeTask::~SqlMergeTask() void SqlMergeTask::loadComplete(const CommonObjects * co) { - destdb = &co->dataSource(dataSource)->getWritable(); + destdb = &LexicalCall(boost::bind(&CommonObjects::dataSource, co, _1), dataSource)->getWritable(); insCmd = insertCommand(); BOOST_FOREACH(const Iterates::value_type & i, sources) { attach(i.second, insCmd); diff --git a/project2/sqlMergeTask.h b/project2/sqlMergeTask.h index 08246d0..c7a7e4e 100644 --- a/project2/sqlMergeTask.h +++ b/project2/sqlMergeTask.h @@ -15,9 +15,9 @@ #include class SqlMergeTask : public Task { - public: - typedef std::string Table; - typedef std::string Column; + public: + typedef std::string Table; + typedef std::string Column; class TargetColumn; typedef boost::intrusive_ptr TargetColumnPtr; class TargetColumn : public virtual IntrusivePtrBase { @@ -33,44 +33,44 @@ class SqlMergeTask : public Task { Table maptable; }; - typedef std::set Columns; + typedef std::set Columns; - typedef std::set Keys; + typedef std::set Keys; - SqlMergeTask(const xmlpp::Element * p); - virtual ~SqlMergeTask(); + SqlMergeTask(const xmlpp::Element * p); + virtual ~SqlMergeTask(); - virtual void loadComplete(const CommonObjects *); - void execute() const; - Columns cols; - Keys keys; - Keys indexes; - const Variable updateWhere; - const std::string patchOrder; - const bool earlyKeys; - const bool useView; + virtual void loadComplete(const CommonObjects *); + void execute() const; + Columns cols; + Keys keys; + Keys indexes; + const Variable updateWhere; + const std::string patchOrder; + const bool earlyKeys; + const bool useView; - private: - virtual void copyToTempTable() const; - void createTempTable() const; - void dropTempTable() const; - void createTempKey() const; + private: + virtual void copyToTempTable() const; + void createTempTable() const; + void dropTempTable() const; + void createTempKey() const; - mutable bool tempTableCreated; - Iterates sources; + mutable bool tempTableCreated; + Iterates sources; std::list sqls; - protected: - ModifyCommand * insertCommand() const; - ModifyCommand * insCmd; + protected: + ModifyCommand * insertCommand() const; + ModifyCommand * insCmd; - public: - ODBC::Connection * destdb; - const std::string dataSource; - const Table dtable; - const Table dtablet; + public: + ODBC::Connection * destdb; + const Variable dataSource; + const Table dtable; + const Table dtablet; - static unsigned int defaultVerbosity; - static bool defaultUseTempTable; + static unsigned int defaultVerbosity; + static bool defaultUseTempTable; }; #endif diff --git a/project2/sqlRows.cpp b/project2/sqlRows.cpp index 31948df..f592337 100644 --- a/project2/sqlRows.cpp +++ b/project2/sqlRows.cpp @@ -9,6 +9,7 @@ #include "xmlObjectLoader.h" #include "commonObjects.h" #include "sqlVariableBinder.h" +#include "genericVisitor.h" #include ElementLoaderImpl sqlviewLoader("sqlrows"); @@ -16,7 +17,7 @@ ElementLoaderImpl sqlviewLoader("sqlrows"); SqlRows::SqlRows(const xmlpp::Element * p) : SourceObject(p), RowSet(p), - dataSource(p->get_attribute_value("datasource")), + dataSource(p, "datasource"), sqlCommand(dynamic_cast(p->get_children("sql").front())), query(NULL), db(NULL) @@ -30,7 +31,7 @@ SqlRows::~SqlRows() void SqlRows::loadComplete(const CommonObjects * co) { - db = co->dataSource(dataSource); + db = LexicalCall(boost::bind(&CommonObjects::dataSource, co, _1), dataSource); } void diff --git a/project2/sqlRows.h b/project2/sqlRows.h index 9c6dadb..942da5d 100644 --- a/project2/sqlRows.h +++ b/project2/sqlRows.h @@ -25,7 +25,7 @@ class SqlRows : public RowSet { bool isNull(unsigned int col) const; bool isNull(const Glib::ustring & id) const; - const std::string dataSource; + const Variable dataSource; private: class SqlWriter; diff --git a/project2/sqlTask.cpp b/project2/sqlTask.cpp index d5810be..3c54660 100644 --- a/project2/sqlTask.cpp +++ b/project2/sqlTask.cpp @@ -5,6 +5,7 @@ #include "rdbmsDataSource.h" #include "commonObjects.h" #include "sqlVariableBinder.h" +#include "genericVisitor.h" ElementLoaderImpl sqltaskLoader("sqltask"); @@ -12,7 +13,7 @@ SqlTask::SqlTask(const xmlpp::Element * p) : SourceObject(p), Task(p), IHaveParameters(p), - dataSource(p->get_attribute_value("datasource")), + dataSource(p, "datasource"), sql(xmlChildText(p, "sql")), modify(NULL) { @@ -26,7 +27,8 @@ SqlTask::~SqlTask() void SqlTask::loadComplete(const CommonObjects * co) { - modify = new ODBC::ModifyCommand(co->dataSource(dataSource)->getWritable(), sql); + modify = new ODBC::ModifyCommand(LexicalCall(boost::bind( + &CommonObjects::dataSource, co, _1), dataSource)->getWritable(), sql); } void diff --git a/project2/sqlTask.h b/project2/sqlTask.h index 3cd93c6..6432022 100644 --- a/project2/sqlTask.h +++ b/project2/sqlTask.h @@ -16,7 +16,7 @@ class SqlTask : public Task, public IHaveParameters { virtual void loadComplete(const CommonObjects *); virtual void execute() const; - const std::string dataSource; + const Variable dataSource; const std::string sql; protected: mutable ODBC::ModifyCommand * modify; diff --git a/project2/variables.cpp b/project2/variables.cpp index 130d210..20b4fa2 100644 --- a/project2/variables.cpp +++ b/project2/variables.cpp @@ -252,6 +252,25 @@ class VariableFixed : public VariableImpl { VariableType var; }; +class VariableConfig : public VariableImplDyn { + public: + VariableConfig(const xmlpp::Element * e) : + VariableImplDyn(e), + name(e->get_attribute_value("name")) + { + } + const VariableType & value() const + { + if (!cacheValid) { + cache = ApplicationEngine::getCurrent()->getCurrentConfig()->getValue(name); + cacheValid = true; + } + return cache; + } + private: + const Glib::ustring name; +}; + Variable::Variable(const xmlpp::Element * e, const Glib::ustring & n, bool required, VariableType def) { xmlpp::Attribute * a = e->get_attribute(n); @@ -272,6 +291,8 @@ Variable::Variable(const xmlpp::Element * e, const Glib::ustring & n, bool requi var = new VariableUri(c); else if (source == "param") var = new VariableParam(c); + else if (source == "config") + var = new VariableConfig(c); else if (source == "literal" || source.empty()) var = new VariableLiteral(c->get_attribute_value("value"), c->get_attribute_value("type")); else -- cgit v1.2.3