From 589f65d5748e0055a534d797c9b98206bafedc57 Mon Sep 17 00:00:00 2001 From: randomdan Date: Wed, 9 Mar 2011 16:43:04 +0000 Subject: Allow specifying all sorts of previously hardcoded things, most importantly paths Rework the CGI stage structure to support custom presentations in the event of errors Changes to the Jamfile to ensure each component is complete in itself --- project2/Jamfile.jam | 29 +++- project2/cgi/cgiAppEngine.cpp | 273 +++++-------------------------- project2/cgi/cgiAppEngine.h | 78 ++++++--- project2/cgi/cgiEnvironment.cpp | 12 ++ project2/cgi/cgiEnvironment.h | 6 + project2/cgi/cgiHttpHeader.cpp | 29 ++++ project2/cgi/cgiHttpHeader.h | 20 +++ project2/cgi/cgiStageCustomError.cpp | 44 +++++ project2/cgi/cgiStageCustomNotFound.cpp | 43 +++++ project2/cgi/cgiStageDefaultError.cpp | 52 ++++++ project2/cgi/cgiStageDefaultNotFound.cpp | 44 +++++ project2/cgi/cgiStageInitial.cpp | 19 +++ project2/cgi/cgiStagePresent.cpp | 44 +++++ project2/cgi/cgiStageRequest.cpp | 60 +++++++ project2/cgi/p2webFCgi.cpp | 1 - project2/commonObjects.cpp | 5 +- project2/console/consoleAppEngine.cpp | 2 +- project2/environment.cpp | 24 +++ project2/environment.h | 8 + project2/if.cpp | 5 +- project2/iterate.cpp | 3 +- project2/rowView.cpp | 3 +- project2/sqlMergeTask.cpp | 3 +- project2/xmlPresenter.cpp | 31 ++-- project2/xmlPresenter.h | 6 +- 25 files changed, 563 insertions(+), 281 deletions(-) create mode 100644 project2/cgi/cgiHttpHeader.cpp create mode 100644 project2/cgi/cgiHttpHeader.h create mode 100644 project2/cgi/cgiStageCustomError.cpp create mode 100644 project2/cgi/cgiStageCustomNotFound.cpp create mode 100644 project2/cgi/cgiStageDefaultError.cpp create mode 100644 project2/cgi/cgiStageDefaultNotFound.cpp create mode 100644 project2/cgi/cgiStageInitial.cpp create mode 100644 project2/cgi/cgiStagePresent.cpp create mode 100644 project2/cgi/cgiStageRequest.cpp diff --git a/project2/Jamfile.jam b/project2/Jamfile.jam index 1d9ba9b..0b8425e 100644 --- a/project2/Jamfile.jam +++ b/project2/Jamfile.jam @@ -16,6 +16,7 @@ alias libxslt : : : : lib fcgi : : fcgi ; lib fcgi++ : : fcgi++ ; lib boost_regex : : boost_regex ; +lib boost_system : : boost_system ; lib boost_filesystem : : boost_filesystem ; lib boost_date_time : : boost_date_time ; lib boost_program_options : : boost_program_options ; @@ -39,6 +40,11 @@ feature uuid : boost ossp : propagated ; feature odbc : yes no ; feature pq : yes no ; +project + : requirements + debug:-Wl,-z,defs "-W -Wall -Werror -Wwrite-strings" + ; + lib p2uuid : uuid.cpp : @@ -58,6 +64,7 @@ lib p2common : : ../libmisc libxmlpp + boost_system boost_filesystem boost_date_time boost_program_options @@ -65,10 +72,11 @@ lib p2common : lib p2xml : xmlRows.cpp xslRows.cpp - p2url : ../libmisc libxmlpp + p2common + p2url libxslt ; @@ -77,6 +85,8 @@ lib p2processes : : ../libmisc libxmlpp + p2common + p2files ; lib p2files : @@ -87,6 +97,8 @@ lib p2files : ../libmisc libxmlpp boost_filesystem + boost_system + p2common ; lib p2regex : @@ -95,6 +107,7 @@ lib p2regex : ../libmisc boost_regex libxmlpp + p2common ; lib p2xmlSession : @@ -102,8 +115,8 @@ lib p2xmlSession : : ../libmisc libxmlpp - : : p2uuid + p2common ; obj rdbmsDataSource : @@ -123,6 +136,7 @@ lib p2sql : yes:../libodbcpp//odbcpp yes:../libpqpp//pqpp libxmlpp + p2common ../libmisc : : yes:../libodbcpp//odbcpp @@ -134,9 +148,13 @@ lib p2url : curlHelper.cpp ../libmisc/curlsup.cpp : + p2common + p2files ../libmisc libxmlpp curl + : : + curl ; lib p2mail : @@ -146,6 +164,7 @@ lib p2mail : libxmlpp libxslt esmtp + p2common ; lib p2web : @@ -155,9 +174,13 @@ lib p2web : cgicc glibmm libxmlpp + p2common + p2uuid + boost_program_options + boost_regex + p2xmlSession : : p2parts - p2xmlSession ; exe p2cgi : diff --git a/project2/cgi/cgiAppEngine.cpp b/project2/cgi/cgiAppEngine.cpp index 7df0279..547506d 100644 --- a/project2/cgi/cgiAppEngine.cpp +++ b/project2/cgi/cgiAppEngine.cpp @@ -2,14 +2,12 @@ #include #include #include "cgiEnvironment.h" -#include "../xmlObjectLoader.h" #include "../iterate.h" #include "../logger.h" #include #include #include #include "../sessionXml.h" -#include #include const std::string SESSIONID = "sessionID"; @@ -20,32 +18,6 @@ SessionContainer * sessionsContainer = new SessionContainerXml(); SimpleMessageException(UnknownDomain); -class Project2HttpHeader : public cgicc::HTTPHeader { - public: - typedef std::map Headers; - Project2HttpHeader(const std::string & s, const std::string & t) : - cgicc::HTTPHeader("") - { - addHeader("Status", s); - addHeader("Content-Type", t); - } - void addHeader(const std::string & name, const Glib::ustring & value) { - headers.erase(name); - headers.insert(Headers::value_type(name, value)); - } - void render(std::ostream & out) const { - BOOST_FOREACH(const Headers::value_type & h, headers) { - out << h.first << ": " << h.second << std::endl; - } - BOOST_FOREACH(const cgicc::HTTPCookie & cookie, getCookies()) { - out << cookie << std::endl; - } - out << std::endl; - } - private: - Headers headers; -}; - static int xmlWrite(void * _out, const char * buf, int len) @@ -64,20 +36,7 @@ CgiApplicationEngine::CgiApplicationEngine(const CgiEnvironment * e) : sessionID = c.getValue(); } } - try { - if (_env->getRequestMethod() == "POST") { - currentStage = new RequestStage(e->elems[0]); - } - else { - currentStage = new PresentStage(e->elems.size() > 0 ? e->elems[0] : "index"); - } - } - catch (const XmlScriptParser::NotFound & nf) { - currentStage = new NotFoundStage(_env, nf); - } - catch (const std::exception & ex) { - currentStage = new ErrorStage(_env, ex); - } + currentStage = new InitialStage(e); } CgiApplicationEngine::~CgiApplicationEngine() @@ -114,25 +73,41 @@ void CgiApplicationEngine::process() const { startTime = boost::date_time::microsec_clock::universal_time(); - try { - for (StagePtr nextStage; (nextStage = currentStage->run()); ) { - currentStage = nextStage; + bool triedNotFound = false; + bool triedOnError = false; + StagePtr nextStage; + do { + try { + nextStage = currentStage->run(); } - } - catch (const XmlScriptParser::NotFound & nf) { - currentStage = new NotFoundStage(_env, nf); - } - catch (const std::exception & ex) { - currentStage = new ErrorStage(_env, ex); - } + catch (const XmlScriptParser::NotFound & nf) { + if (_env->notFoundPresent.empty() || triedNotFound) { + nextStage = new DefaultNotFoundStage(_env, nf); + } + else { + triedNotFound = true; + nextStage = new CustomNotFoundStage(_env, nf); + } + } + catch (const std::exception & ex) { + if (_env->onErrorPresent.empty() || triedOnError) { + nextStage = new DefaultErrorStage(_env, ex); + } + else { + triedNotFound = true; + nextStage = new CustomErrorStage(_env, ex); + } + } + } while (nextStage && (currentStage = nextStage)); endTime = boost::date_time::microsec_clock::universal_time(); - const Presenter * p = boost::dynamic_pointer_cast(currentStage).get(); + PresenterPtr p = boost::dynamic_pointer_cast(currentStage); if (p) { - addAppData(p); + addAppData(p.get()); } } -CgiApplicationEngine::Stage::Stage() +CgiApplicationEngine::Stage::Stage(const CgiEnvironment * env) : + e(env) { } @@ -140,59 +115,36 @@ CgiApplicationEngine::Stage::~Stage() { } -CgiApplicationEngine::PresentStage::PresentStage(const std::string & id) : - XmlProcessPresenter("present", id, false) -{ -} - -CgiApplicationEngine::PresentStage::~PresentStage() -{ -} - -CgiApplicationEngine::StagePtr -CgiApplicationEngine::PresentStage::run() -{ - BOOST_FOREACH(ParamCheckers::value_type pc, parameterChecks.get()) { - if (!pc->performCheck()) { - return new PresentStage(pc->present); - } - } - execute(); - return NULL; -} - CgiApplicationEngine::HttpHeaderPtr -CgiApplicationEngine::PresentStage::getHeader() const +CgiApplicationEngine::Stage::getHeader() const { - Project2HttpHeader * header = new Project2HttpHeader("200 OK", contentType); - header->addHeader("Cache-control", "no-cache"); - return HttpHeaderPtr(header); + return CgiApplicationEngine::HttpHeaderPtr(); } CgiApplicationEngine::XmlDocPtr -CgiApplicationEngine::PresentStage::getDataDocument() const +CgiApplicationEngine::Stage::getDataDocument() const { - return XmlProcessPresenter::getDataDocument(); + return XmlDocPtr(); } void CgiApplicationEngine::addEnvData(const Presenter * p) const { // These were for debug... but why not pass them on? - p->addField("servername", "project2", env()->getServerName()); - p->addField("scriptname", "project2", env()->getScriptName()); + p->addField("servername", env()->getXmlPrefix(), env()->getServerName()); + p->addField("scriptname", env()->getXmlPrefix(), env()->getScriptName()); // URL elements - p->pushSub("uriElems", "project2"); + p->pushSub("uriElems", env()->getXmlPrefix()); BOOST_FOREACH(std::string s, _env->elems) { - p->addField("uriElem", "project2", s); + p->addField("uriElem", env()->getXmlPrefix(), s); } p->popSub(); // Parameters - p->pushSub("params", "project2"); + p->pushSub("params", env()->getXmlPrefix()); BOOST_FOREACH(cgicc::FormEntry fe, _env->cgi->getElements()) { - p->pushSub("param", "project2"); + p->pushSub("param", env()->getXmlPrefix()); p->addAttr("name", fe.getName()); p->addAttr("value", fe.getValue()); p->popSub(); @@ -205,11 +157,11 @@ CgiApplicationEngine::addAppData(const Presenter * p) const { // Sessions variables if (!sessionID.is_nil()) { - p->pushSub("session", "project2"); + p->pushSub("session", env()->getXmlPrefix()); p->addField("id", sessionID.str()); Session::Values session(sessionsContainer->GetSession(sessionID)->GetValuesCopy()); BOOST_FOREACH(Session::Values::value_type sv, session) { - p->pushSub("var", "project2"); + p->pushSub("var", env()->getXmlPrefix()); p->addAttr("value", sv.second); p->addAttr("name", sv.first); p->popSub(); @@ -218,7 +170,7 @@ CgiApplicationEngine::addAppData(const Presenter * p) const } // Timing info - p->pushSub("timing", "project2"); + p->pushSub("timing", env()->getXmlPrefix()); p->addAttr("start", startTime); if (!endTime.is_not_a_date_time()) { p->addAttr("end", endTime); @@ -227,60 +179,6 @@ CgiApplicationEngine::addAppData(const Presenter * p) const p->popSub(); } -CgiApplicationEngine::RequestStage::RequestStage(const std::string & id) -{ - XmlScriptParser request("request", id, false); - xmlpp::Element * requestRoot = request.get_document()->get_root_node(); - present = requestRoot->get_attribute_value("present"); - rollbackBeforeHandle = requestRoot->get_attribute_value("rollbackBeforeHandle") == "true"; - localErrorHandling = requestRoot->get_attribute_value("errorHandling") == "local"; - - LoaderBase loader("http://project2.randomdan.homeip.net", true); - loader.supportedStorers.insert(Storer::into(¶meterChecks)); - loader.supportedStorers.insert(Storer::into(&rowSets)); - loader.supportedStorers.insert(Storer::into(&tasks)); - loader.collectAll(this, requestRoot, true); -} -CgiApplicationEngine::RequestStage::~RequestStage() -{ -} -CgiApplicationEngine::StagePtr -CgiApplicationEngine::RequestStage::run() -{ - BOOST_FOREACH(const ParamCheckers::value_type & pc, parameterChecks.get()) { - if (!pc->performCheck()) { - return new PresentStage(pc->present); - } - } - RequestHost::run(); - return present.empty() ? NULL : new PresentStage(present); -} - -CgiApplicationEngine::HttpHeaderPtr -CgiApplicationEngine::RequestStage::getHeader() const -{ - return HttpHeaderPtr(new Project2HttpHeader("200 OK", "text/xml")); -} - -CgiApplicationEngine::XmlDocPtr -CgiApplicationEngine::RequestStage::getDataDocument() const -{ - return XmlPresenter::getDataDocument(); -} - -const Glib::ustring CgiApplicationEngine::RequestStage::resp("request"); -const Glib::ustring CgiApplicationEngine::RequestStage::style; -const Glib::ustring & -CgiApplicationEngine::RequestStage::getResponseRootNodeName() const -{ - return resp; -} -const Glib::ustring & -CgiApplicationEngine::RequestStage::getResponseStyle() const -{ - return style; -} - SessionPtr CgiApplicationEngine::session() const { @@ -310,89 +208,4 @@ CgiApplicationEngine::loadEngineSection(const xmlpp::Element * e) const domplat.push_back(DomainPlatforms::value_type(e->get_attribute_value("name"), e->get_attribute_value("platform"))); } -CgiApplicationEngine::FailStage::FailStage(const CgiEnvironment * e) : - env(e) -{ -} - -CgiApplicationEngine::FailStage::~FailStage() -{ -} - -const Glib::ustring & -CgiApplicationEngine::FailStage::getResponseStyle() const -{ - return env->errorTransformStyle; -} - -CgiApplicationEngine::StagePtr -CgiApplicationEngine::FailStage::run() -{ - return NULL; -} - -CgiApplicationEngine::NotFoundStage::NotFoundStage(const CgiEnvironment * e, const XmlScriptParser::NotFound & nf) : - CgiApplicationEngine::FailStage(e) -{ - initDoc(); - responseDoc->get_root_node()->add_child("resource")->set_child_text(nf.what()); -} - -CgiApplicationEngine::NotFoundStage::~NotFoundStage() -{ -} - -CgiApplicationEngine::HttpHeaderPtr -CgiApplicationEngine::NotFoundStage::getHeader() const -{ - return HttpHeaderPtr(new Project2HttpHeader("404 Not found", env->errorContentType)); -} - -const Glib::ustring CgiApplicationEngine::NotFoundStage::resp("notfound"); -const Glib::ustring & -CgiApplicationEngine::NotFoundStage::getResponseRootNodeName() const -{ - return resp; -} - -CgiApplicationEngine::XmlDocPtr -CgiApplicationEngine::NotFoundStage::getDataDocument() const -{ - return XmlPresenter::getDataDocument(); -} - -CgiApplicationEngine::ErrorStage::ErrorStage(const CgiEnvironment * e, const std::exception & ex) : - CgiApplicationEngine::FailStage(e) -{ - initDoc(); - char * buf = __cxxabiv1::__cxa_demangle(typeid(ex).name(), NULL, NULL, NULL); - Logger()->messagef(LOG_ERR, "%s: Request errored: %s: %s", __FUNCTION__, buf, ex.what()); - responseDoc->get_root_node()->add_child("type")->set_child_text(buf); - responseDoc->get_root_node()->add_child("what")->set_child_text(ex.what()); - free(buf); -} - -CgiApplicationEngine::ErrorStage::~ErrorStage() -{ -} - -CgiApplicationEngine::HttpHeaderPtr -CgiApplicationEngine::ErrorStage::getHeader() const -{ - return HttpHeaderPtr(new Project2HttpHeader("500 Internal Server Error", env->errorContentType)); -} - -const Glib::ustring CgiApplicationEngine::ErrorStage::resp("error"); -const Glib::ustring & -CgiApplicationEngine::ErrorStage::getResponseRootNodeName() const -{ - return resp; -} - -CgiApplicationEngine::XmlDocPtr -CgiApplicationEngine::ErrorStage::getDataDocument() const -{ - return XmlPresenter::getDataDocument(); -} - diff --git a/project2/cgi/cgiAppEngine.h b/project2/cgi/cgiAppEngine.h index cfab7c4..de9b95a 100644 --- a/project2/cgi/cgiAppEngine.h +++ b/project2/cgi/cgiAppEngine.h @@ -47,19 +47,29 @@ class CgiApplicationEngine : public ApplicationEngine { class Stage; typedef boost::intrusive_ptr StagePtr; + /// Base class for a stage iteration that should eventually produce a response for the client class Stage : public virtual CommonObjects { public: - Stage(); + Stage(const CgiEnvironment * e); virtual ~Stage() = 0; virtual StagePtr run() = 0; - virtual XmlDocPtr getDataDocument() const = 0; - virtual HttpHeaderPtr getHeader() const = 0; + virtual XmlDocPtr getDataDocument() const; + virtual HttpHeaderPtr getHeader() const; + protected: + const CgiEnvironment * e; + }; + + /// Stage implementation used to bootstrap the iteration process based on the CGI environment + class InitialStage : public Stage { + public: + InitialStage(const CgiEnvironment * e); + virtual StagePtr run(); }; + /// Stage to process POST requests class RequestStage : public Stage, public XmlPresenter, RequestHost { public: - RequestStage(const std::string & id); - virtual ~RequestStage(); + RequestStage(const CgiEnvironment *, const std::string & id); virtual StagePtr run(); virtual XmlDocPtr getDataDocument() const; @@ -77,51 +87,73 @@ class CgiApplicationEngine : public ApplicationEngine { static const Glib::ustring style; }; - class PresentStage : public Stage, public XmlProcessPresenter { + /// Stage to process GET requests and follow up RequestStages + class PresentStage : public virtual Stage, public XmlProcessPresenter { public: - PresentStage(const std::string & id); - virtual ~PresentStage(); + PresentStage(const CgiEnvironment * e, const std::string & id); + PresentStage(const CgiEnvironment * e, const std::string & group, const std::string & id); virtual StagePtr run(); virtual XmlDocPtr getDataDocument() const; virtual HttpHeaderPtr getHeader() const; }; - class FailStage : public Stage, public XmlPresenter { + /// The built-in fail-safe not found stage + class DefaultNotFoundStage : public virtual Stage, public XmlPresenter { public: - FailStage(const CgiEnvironment *); - virtual ~FailStage(); + DefaultNotFoundStage(const CgiEnvironment *, const XmlScriptParser::NotFound &); - virtual const Glib::ustring & getResponseStyle() const; + virtual XmlDocPtr getDataDocument() const; + virtual HttpHeaderPtr getHeader() const; virtual StagePtr run(); + virtual const Glib::ustring & getResponseRootNodeName() const; + virtual const Glib::ustring & getResponseStyle() const; + private: + static const Glib::ustring resp; + const CgiEnvironment * e; + const XmlScriptParser::NotFound nf; + }; - protected: - const CgiEnvironment * env; + /// Custom not found handling stage + class CustomNotFoundStage : public DefaultNotFoundStage, public PresentStage { + public: + CustomNotFoundStage(const CgiEnvironment *, const XmlScriptParser::NotFound &); + virtual StagePtr run(); + virtual XmlDocPtr getDataDocument() const; + virtual HttpHeaderPtr getHeader() const; + virtual const Glib::ustring & getResponseRootNodeName() const; + virtual const Glib::ustring & getResponseStyle() const; }; - class NotFoundStage : public FailStage { + /// The built-in fail-safe unhandled error stage + class DefaultErrorStage : public virtual Stage, public XmlPresenter { public: - NotFoundStage(const CgiEnvironment *, const XmlScriptParser::NotFound &); - virtual ~NotFoundStage(); + DefaultErrorStage(const CgiEnvironment *, const std::exception &); + ~DefaultErrorStage(); virtual XmlDocPtr getDataDocument() const; virtual HttpHeaderPtr getHeader() const; + virtual StagePtr run(); virtual const Glib::ustring & getResponseRootNodeName() const; + virtual const Glib::ustring & getResponseStyle() const; private: static const Glib::ustring resp; + const CgiEnvironment * e; + char * buf; + std::string what; }; - class ErrorStage : public FailStage { + /// Custom unhandled error handling stage + class CustomErrorStage : public DefaultErrorStage, public PresentStage { public: - ErrorStage(const CgiEnvironment *, const std::exception &); - virtual ~ErrorStage(); - + CustomErrorStage(const CgiEnvironment *, const std::exception &); + virtual StagePtr run(); virtual XmlDocPtr getDataDocument() const; virtual HttpHeaderPtr getHeader() const; virtual const Glib::ustring & getResponseRootNodeName() const; - private: - static const Glib::ustring resp; + virtual const Glib::ustring & getResponseStyle() const; }; + mutable StagePtr currentStage; mutable UUID sessionID; }; diff --git a/project2/cgi/cgiEnvironment.cpp b/project2/cgi/cgiEnvironment.cpp index 43f45f2..e8d5ba3 100644 --- a/project2/cgi/cgiEnvironment.cpp +++ b/project2/cgi/cgiEnvironment.cpp @@ -28,10 +28,22 @@ CgiEnvironment::addOptions(boost::program_options::positional_options_descriptio { boost::program_options::options_description cgi("Project2 CGI options"); cgi.add_options() + ("defaultpresent", boost::program_options::value(&defaultPresent)->default_value("index"), + "The present script to use when no other is specified") + ("presentroot", boost::program_options::value(&presentRoot)->default_value("present"), + "The folder in which to find presentation scripts") + ("requestroot", boost::program_options::value(&requestRoot)->default_value("request"), + "The folder in which to find request scripts") + ("errorpresentroot", boost::program_options::value(&errorPresentRoot)->default_value("error"), + "The folder in which to find presentation scripts for error handling") ("errorcontenttype", boost::program_options::value(&errorContentType)->default_value("text/xml"), "The Content-Type to use in HTTP headers in event of an error") ("errortransformstyle", boost::program_options::value(&errorTransformStyle), "The xml-stylesheet to specify in the data document in event of an error") + ("notfoundpresent", boost::program_options::value(¬FoundPresent), + "The present script to use when the requested script does not exist") + ("onerrorpresent", boost::program_options::value(&onErrorPresent), + "The present script to use when the requested script (or child) fails") #ifndef NDEBUG ("dumpdatadoc", boost::program_options::value(&dumpdatadoc), "Write a copy of the data document before sending it to the web server") diff --git a/project2/cgi/cgiEnvironment.h b/project2/cgi/cgiEnvironment.h index c9b33fa..ce765bf 100644 --- a/project2/cgi/cgiEnvironment.h +++ b/project2/cgi/cgiEnvironment.h @@ -32,6 +32,12 @@ class CgiEnvironment : public Environment, public cgicc::CgiEnvironment { #endif Glib::ustring errorContentType; Glib::ustring errorTransformStyle; + std::string defaultPresent; + std::string presentRoot; + std::string requestRoot; + std::string errorPresentRoot; + std::string notFoundPresent; + std::string onErrorPresent; }; #endif diff --git a/project2/cgi/cgiHttpHeader.cpp b/project2/cgi/cgiHttpHeader.cpp new file mode 100644 index 0000000..37a48c9 --- /dev/null +++ b/project2/cgi/cgiHttpHeader.cpp @@ -0,0 +1,29 @@ +#include "cgiHttpHeader.h" +#include + +Project2HttpHeader::Project2HttpHeader(const std::string & s, const std::string & t) : + cgicc::HTTPHeader("") +{ + addHeader("Status", s); + addHeader("Content-Type", t); +} + +void +Project2HttpHeader::addHeader(const std::string & name, const Glib::ustring & value) +{ + headers.erase(name); + headers.insert(Headers::value_type(name, value)); +} + +void +Project2HttpHeader::render(std::ostream & out) const +{ + BOOST_FOREACH(const Headers::value_type & h, headers) { + out << h.first << ": " << h.second << std::endl; + } + BOOST_FOREACH(const cgicc::HTTPCookie & cookie, getCookies()) { + out << cookie << std::endl; + } + out << std::endl; +} + diff --git a/project2/cgi/cgiHttpHeader.h b/project2/cgi/cgiHttpHeader.h new file mode 100644 index 0000000..f84c707 --- /dev/null +++ b/project2/cgi/cgiHttpHeader.h @@ -0,0 +1,20 @@ +#ifndef HTTP_HEADER_H +#define HTTP_HEADER_H + +#include +#include +#include +#include + +class Project2HttpHeader : public cgicc::HTTPHeader { + public: + typedef std::map Headers; + Project2HttpHeader(const std::string & s, const std::string & t); + void addHeader(const std::string & name, const Glib::ustring & value); + void render(std::ostream & out) const; + private: + Headers headers; +}; + +#endif + diff --git a/project2/cgi/cgiStageCustomError.cpp b/project2/cgi/cgiStageCustomError.cpp new file mode 100644 index 0000000..a3fbc1f --- /dev/null +++ b/project2/cgi/cgiStageCustomError.cpp @@ -0,0 +1,44 @@ +#include "cgiAppEngine.h" +#include "cgiEnvironment.h" +#include "cgiHttpHeader.h" +#include "../logger.h" + +CgiApplicationEngine::CustomErrorStage::CustomErrorStage(const CgiEnvironment * env, const std::exception & ex) : + CgiApplicationEngine::Stage(env), + CgiApplicationEngine::DefaultErrorStage(env, ex), + CgiApplicationEngine::PresentStage(env, env->errorPresentRoot, env->onErrorPresent) +{ +} + +CgiApplicationEngine::HttpHeaderPtr +CgiApplicationEngine::CustomErrorStage::getHeader() const +{ + return CgiApplicationEngine::DefaultErrorStage::getHeader(); +} + +CgiApplicationEngine::StagePtr +CgiApplicationEngine::CustomErrorStage::run() +{ + CgiApplicationEngine::DefaultErrorStage::run(); + return CgiApplicationEngine::PresentStage::run(); +} + +const Glib::ustring & +CgiApplicationEngine::CustomErrorStage::getResponseRootNodeName() const +{ + return CgiApplicationEngine::PresentStage::getResponseRootNodeName(); +} + +CgiApplicationEngine::XmlDocPtr +CgiApplicationEngine::CustomErrorStage::getDataDocument() const +{ + return CgiApplicationEngine::PresentStage::getDataDocument(); +} + +const Glib::ustring & +CgiApplicationEngine::CustomErrorStage::getResponseStyle() const +{ + return CgiApplicationEngine::PresentStage::getResponseStyle(); +} + + diff --git a/project2/cgi/cgiStageCustomNotFound.cpp b/project2/cgi/cgiStageCustomNotFound.cpp new file mode 100644 index 0000000..a2d33dc --- /dev/null +++ b/project2/cgi/cgiStageCustomNotFound.cpp @@ -0,0 +1,43 @@ +#include "cgiAppEngine.h" +#include "cgiEnvironment.h" +#include "cgiHttpHeader.h" +#include "../logger.h" + +CgiApplicationEngine::CustomNotFoundStage::CustomNotFoundStage(const CgiEnvironment * env, const XmlScriptParser::NotFound & notfound) : + CgiApplicationEngine::Stage(env), + CgiApplicationEngine::DefaultNotFoundStage(env, notfound), + CgiApplicationEngine::PresentStage(env, env->errorPresentRoot, env->notFoundPresent) +{ +} + +CgiApplicationEngine::HttpHeaderPtr +CgiApplicationEngine::CustomNotFoundStage::getHeader() const +{ + return CgiApplicationEngine::DefaultNotFoundStage::getHeader(); +} + +CgiApplicationEngine::StagePtr +CgiApplicationEngine::CustomNotFoundStage::run() +{ + CgiApplicationEngine::DefaultNotFoundStage::run(); + return CgiApplicationEngine::PresentStage::run(); +} + +const Glib::ustring & +CgiApplicationEngine::CustomNotFoundStage::getResponseRootNodeName() const +{ + return CgiApplicationEngine::PresentStage::getResponseRootNodeName(); +} + +CgiApplicationEngine::XmlDocPtr +CgiApplicationEngine::CustomNotFoundStage::getDataDocument() const +{ + return CgiApplicationEngine::PresentStage::getDataDocument(); +} + +const Glib::ustring & +CgiApplicationEngine::CustomNotFoundStage::getResponseStyle() const +{ + return CgiApplicationEngine::PresentStage::getResponseStyle(); +} + diff --git a/project2/cgi/cgiStageDefaultError.cpp b/project2/cgi/cgiStageDefaultError.cpp new file mode 100644 index 0000000..c881da1 --- /dev/null +++ b/project2/cgi/cgiStageDefaultError.cpp @@ -0,0 +1,52 @@ +#include "cgiAppEngine.h" +#include "cgiHttpHeader.h" +#include "../logger.h" +#include "cgiEnvironment.h" +#include + +const Glib::ustring CgiApplicationEngine::DefaultErrorStage::resp("error"); + +CgiApplicationEngine::DefaultErrorStage::DefaultErrorStage(const CgiEnvironment * env, const std::exception & ex) : + CgiApplicationEngine::Stage(env), + buf(__cxxabiv1::__cxa_demangle(typeid(ex).name(), NULL, NULL, NULL)), + what(ex.what()) +{ +} + +CgiApplicationEngine::DefaultErrorStage::~DefaultErrorStage() +{ + free(buf); +} + +CgiApplicationEngine::HttpHeaderPtr +CgiApplicationEngine::DefaultErrorStage::getHeader() const +{ + return HttpHeaderPtr(new Project2HttpHeader("500 Internal Server Error", e->errorContentType)); +} + +CgiApplicationEngine::StagePtr +CgiApplicationEngine::DefaultErrorStage::run() +{ + addField("error-type", e->getXmlPrefix(), buf); + addField("error-what", e->getXmlPrefix(), what.c_str()); + return NULL; +} + +const Glib::ustring & +CgiApplicationEngine::DefaultErrorStage::getResponseRootNodeName() const +{ + return resp; +} + +CgiApplicationEngine::XmlDocPtr +CgiApplicationEngine::DefaultErrorStage::getDataDocument() const +{ + return XmlPresenter::getDataDocument(); +} + +const Glib::ustring & +CgiApplicationEngine::DefaultErrorStage::getResponseStyle() const +{ + return e->errorTransformStyle; +} + diff --git a/project2/cgi/cgiStageDefaultNotFound.cpp b/project2/cgi/cgiStageDefaultNotFound.cpp new file mode 100644 index 0000000..f32ad1f --- /dev/null +++ b/project2/cgi/cgiStageDefaultNotFound.cpp @@ -0,0 +1,44 @@ +#include "cgiAppEngine.h" +#include "cgiEnvironment.h" +#include "cgiHttpHeader.h" +#include "../logger.h" + +CgiApplicationEngine::DefaultNotFoundStage::DefaultNotFoundStage(const CgiEnvironment * env, const XmlScriptParser::NotFound & notfound) : + CgiApplicationEngine::Stage(env), + nf(notfound) +{ + Logger()->messagef(LOG_ERR, "%s: Resource not found: %s", __FUNCTION__, nf.what()); +} + +CgiApplicationEngine::HttpHeaderPtr +CgiApplicationEngine::DefaultNotFoundStage::getHeader() const +{ + return HttpHeaderPtr(new Project2HttpHeader("404 Not found", e->errorContentType)); +} + +CgiApplicationEngine::StagePtr +CgiApplicationEngine::DefaultNotFoundStage::run() +{ + addField("missing-resource", e->getXmlPrefix(), nf.what()); + return NULL; +} + +const Glib::ustring CgiApplicationEngine::DefaultNotFoundStage::resp("notfound"); +const Glib::ustring & +CgiApplicationEngine::DefaultNotFoundStage::getResponseRootNodeName() const +{ + return resp; +} + +CgiApplicationEngine::XmlDocPtr +CgiApplicationEngine::DefaultNotFoundStage::getDataDocument() const +{ + return XmlPresenter::getDataDocument(); +} + +const Glib::ustring & +CgiApplicationEngine::DefaultNotFoundStage::getResponseStyle() const +{ + return e->errorTransformStyle; +} + diff --git a/project2/cgi/cgiStageInitial.cpp b/project2/cgi/cgiStageInitial.cpp new file mode 100644 index 0000000..a9315bc --- /dev/null +++ b/project2/cgi/cgiStageInitial.cpp @@ -0,0 +1,19 @@ +#include "cgiAppEngine.h" +#include "cgiEnvironment.h" + +CgiApplicationEngine::InitialStage::InitialStage(const CgiEnvironment * env) : + CgiApplicationEngine::Stage(env) +{ +} + +CgiApplicationEngine::StagePtr +CgiApplicationEngine::InitialStage::run() +{ + if (e->getRequestMethod() == "POST") { + return new RequestStage(e, e->elems[0]); + } + else { + return new PresentStage(e, e->elems.empty() ? e->defaultPresent : e->elems[0]); + } +} + diff --git a/project2/cgi/cgiStagePresent.cpp b/project2/cgi/cgiStagePresent.cpp new file mode 100644 index 0000000..9dcf124 --- /dev/null +++ b/project2/cgi/cgiStagePresent.cpp @@ -0,0 +1,44 @@ +#include "cgiAppEngine.h" +#include "cgiEnvironment.h" +#include "cgiHttpHeader.h" +#include + +CgiApplicationEngine::PresentStage::PresentStage(const CgiEnvironment * e, const std::string & id) : + CgiApplicationEngine::Stage(e), + XmlProcessPresenter(e->presentRoot, id, false) +{ +} + +CgiApplicationEngine::PresentStage::PresentStage(const CgiEnvironment * e, const std::string & group, const std::string & id) : + CgiApplicationEngine::Stage(e), + XmlProcessPresenter(group, id, false) +{ +} + +CgiApplicationEngine::StagePtr +CgiApplicationEngine::PresentStage::run() +{ + BOOST_FOREACH(ParamCheckers::value_type pc, parameterChecks.get()) { + if (!pc->performCheck()) { + return new PresentStage(e, pc->present); + } + } + execute(); + return NULL; +} + +CgiApplicationEngine::HttpHeaderPtr +CgiApplicationEngine::PresentStage::getHeader() const +{ + Project2HttpHeader * header = new Project2HttpHeader("200 OK", contentType); + header->addHeader("Cache-control", "no-cache"); + return HttpHeaderPtr(header); +} + +CgiApplicationEngine::XmlDocPtr +CgiApplicationEngine::PresentStage::getDataDocument() const +{ + return XmlProcessPresenter::getDataDocument(); +} + + diff --git a/project2/cgi/cgiStageRequest.cpp b/project2/cgi/cgiStageRequest.cpp new file mode 100644 index 0000000..6602527 --- /dev/null +++ b/project2/cgi/cgiStageRequest.cpp @@ -0,0 +1,60 @@ +#include "cgiAppEngine.h" +#include "cgiEnvironment.h" +#include "cgiHttpHeader.h" +#include "../xmlObjectLoader.h" +#include + +CgiApplicationEngine::RequestStage::RequestStage(const CgiEnvironment * e, const std::string & id) : + CgiApplicationEngine::Stage(e) +{ + XmlScriptParser request(e->requestRoot, id, false); + xmlpp::Element * requestRoot = request.get_document()->get_root_node(); + present = requestRoot->get_attribute_value("present"); + rollbackBeforeHandle = requestRoot->get_attribute_value("rollbackBeforeHandle") == "true"; + localErrorHandling = requestRoot->get_attribute_value("errorHandling") == "local"; + + LoaderBase loader(ApplicationEngine::getCurrent()->env()->getXmlNamespace(), true); + loader.supportedStorers.insert(Storer::into(¶meterChecks)); + loader.supportedStorers.insert(Storer::into(&rowSets)); + loader.supportedStorers.insert(Storer::into(&tasks)); + loader.collectAll(this, requestRoot, true); +} + +CgiApplicationEngine::StagePtr +CgiApplicationEngine::RequestStage::run() +{ + BOOST_FOREACH(const ParamCheckers::value_type & pc, parameterChecks.get()) { + if (!pc->performCheck()) { + return new PresentStage(e, pc->present); + } + } + RequestHost::run(); + return present.empty() ? NULL : new PresentStage(e, present); +} + +CgiApplicationEngine::HttpHeaderPtr +CgiApplicationEngine::RequestStage::getHeader() const +{ + return HttpHeaderPtr(new Project2HttpHeader("200 OK", "text/xml")); +} + +CgiApplicationEngine::XmlDocPtr +CgiApplicationEngine::RequestStage::getDataDocument() const +{ + return XmlPresenter::getDataDocument(); +} + +const Glib::ustring CgiApplicationEngine::RequestStage::resp("request"); +const Glib::ustring CgiApplicationEngine::RequestStage::style; +const Glib::ustring & +CgiApplicationEngine::RequestStage::getResponseRootNodeName() const +{ + return resp; +} +const Glib::ustring & +CgiApplicationEngine::RequestStage::getResponseStyle() const +{ + return style; +} + + diff --git a/project2/cgi/p2webFCgi.cpp b/project2/cgi/p2webFCgi.cpp index d501787..d1aa29e 100644 --- a/project2/cgi/p2webFCgi.cpp +++ b/project2/cgi/p2webFCgi.cpp @@ -1,7 +1,6 @@ #include "cgiCommon.h" #include "FCgiIO.h" #include "../xmlObjectLoader.h" -#include "../logger.h" time_t lastPeriodic = 0; time_t periodicDelay = 600; diff --git a/project2/commonObjects.cpp b/project2/commonObjects.cpp index b6a3b7d..d661588 100644 --- a/project2/commonObjects.cpp +++ b/project2/commonObjects.cpp @@ -1,4 +1,5 @@ #include "commonObjects.h" +#include "appEngine.h" #include "xmlObjectLoader.h" #include "xmlScriptParser.h" @@ -21,9 +22,9 @@ CommonObjects::getSource(const std::string & name) const CommonObjects::DataSources::index::type::const_iterator CommonObjects::loadDataSource(const std::string & name) const { - XmlScriptParser xml("datasources", name, true); + XmlScriptParser xml(ApplicationEngine::getCurrent()->env()->getDatasourceRoot(), name, true); - LoaderBase loader("http://project2.randomdan.homeip.net", true); + LoaderBase loader(ApplicationEngine::getCurrent()->env()->getXmlNamespace(), true); loader.supportedStorers.insert(Storer::into(&datasources)); loader.collectAll(xml.get_document()->get_root_node(), false); diff --git a/project2/console/consoleAppEngine.cpp b/project2/console/consoleAppEngine.cpp index a45f704..7a08f69 100644 --- a/project2/console/consoleAppEngine.cpp +++ b/project2/console/consoleAppEngine.cpp @@ -64,7 +64,7 @@ ConsoleApplicationEngine::ConsoleApplicationEngine(const ConsoleEnvironment * en rollbackBeforeHandle = requestRoot->get_attribute_value("rollbackBeforeHandle") == "true"; localErrorHandling = requestRoot->get_attribute_value("errorHandling") == "local"; - LoaderBase loader("http://project2.randomdan.homeip.net", true); + LoaderBase loader(ApplicationEngine::getCurrent()->env()->getXmlNamespace(), true); loader.supportedStorers.insert(Storer::into(¶meterChecks)); loader.supportedStorers.insert(Storer::into(&tasks)); loader.supportedStorers.insert(Storer::into(&rowSets)); diff --git a/project2/environment.cpp b/project2/environment.cpp index a3985ca..a3a3d5e 100644 --- a/project2/environment.cpp +++ b/project2/environment.cpp @@ -28,6 +28,12 @@ Environment::init() "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") ; allOptions.add(common).add(addOptions(posOptions)); optionsBuilt = true; @@ -58,3 +64,21 @@ Environment::~Environment() Logger()->clear(); } +const std::string & +Environment::getDatasourceRoot() const +{ + return datasourceRoot; +} + +const Glib::ustring & +Environment::getXmlNamespace() const +{ + return xmlNamespace; +} + +const Glib::ustring & +Environment::getXmlPrefix() const +{ + return xmlPrefix; +} + diff --git a/project2/environment.h b/project2/environment.h index 99f9253..5c66518 100644 --- a/project2/environment.h +++ b/project2/environment.h @@ -13,6 +13,10 @@ class Environment { void init(); + const std::string & getDatasourceRoot() const; + const Glib::ustring & getXmlNamespace() const; + const Glib::ustring & getXmlPrefix() const; + virtual Glib::ustring getParamUri(unsigned int idx) const = 0; virtual Glib::ustring getParamQuery(const std::string & idx) const = 0; @@ -30,6 +34,10 @@ class Environment { static int clLevel; static int slLevel; + + std::string datasourceRoot; + Glib::ustring xmlNamespace; + Glib::ustring xmlPrefix; }; #endif diff --git a/project2/if.cpp b/project2/if.cpp index b1b98a6..01368cc 100644 --- a/project2/if.cpp +++ b/project2/if.cpp @@ -1,4 +1,5 @@ #include "if.h" +#include "appEngine.h" #include "logger.h" #include "xmlObjectLoader.h" #include @@ -10,7 +11,7 @@ SimpleMessageException(IfModeIsNonsense); IfSet::IfSet(const xmlpp::Element * e) : mode(e->get_attribute_value("mode") == "or" ? Or : And) { - LoaderBase loader("http://project2.randomdan.homeip.net", true); + LoaderBase loader(ApplicationEngine::getCurrent()->env()->getXmlNamespace(), true); loader.supportedStorers.insert(Storer::into(&checks)); loader.collectAll(e, true, IgnoreUnsupported); } @@ -44,7 +45,7 @@ If::If(const xmlpp::Element * e) : IfSet(e), localErrorHandling(e->get_attribute_value("errorHandling") == "local") { - LoaderBase loader("http://project2.randomdan.homeip.net", true); + LoaderBase loader(ApplicationEngine::getCurrent()->env()->getXmlNamespace(), true); loader.supportedStorers.insert(Storer::into(&subNOEs)); loader.supportedStorers.insert(Storer::into(&subViews)); loader.collectAll(e, true, IgnoreUnsupported); diff --git a/project2/iterate.cpp b/project2/iterate.cpp index ccf289e..b06d7e1 100644 --- a/project2/iterate.cpp +++ b/project2/iterate.cpp @@ -1,4 +1,5 @@ #include "iterate.h" +#include "appEngine.h" #include #include "xmlObjectLoader.h" @@ -10,7 +11,7 @@ Iterate::Iterate(const xmlpp::Element * p) : RowProcessor(p), localErrorHandling(p->get_attribute_value("errorHandling") == "local") { - LoaderBase loader("http://project2.randomdan.homeip.net", true); + LoaderBase loader(ApplicationEngine::getCurrent()->env()->getXmlNamespace(), true); loader.supportedStorers.insert(Storer::into(&subNOEs)); loader.collectAll(p, true, IgnoreUnsupported); } diff --git a/project2/rowView.cpp b/project2/rowView.cpp index e036dd7..541bf5e 100644 --- a/project2/rowView.cpp +++ b/project2/rowView.cpp @@ -1,4 +1,5 @@ #include "rowView.h" +#include "appEngine.h" #include "presenter.h" #include "xmlObjectLoader.h" #include @@ -20,7 +21,7 @@ RowView::RowView(const xmlpp::Element * p) : Variable::makeParent(elem->get_child_text()->get_content(), elem->get_attribute_value("source") == "attribute", 0))); } } - LoaderBase loader("http://project2.randomdan.homeip.net", true); + LoaderBase loader(ApplicationEngine::getCurrent()->env()->getXmlNamespace(), true); loader.supportedStorers.insert(Storer::into(&subViews)); loader.collectAll(p, true, IgnoreUnsupported); } diff --git a/project2/sqlMergeTask.cpp b/project2/sqlMergeTask.cpp index 0160a7f..ab8546b 100644 --- a/project2/sqlMergeTask.cpp +++ b/project2/sqlMergeTask.cpp @@ -1,4 +1,5 @@ #include "sqlMergeTask.h" +#include "appEngine.h" #include "commonObjects.h" #include "rdbmsDataSource.h" #include "exceptions.h" @@ -56,7 +57,7 @@ SqlMergeTask::SqlMergeTask(const xmlpp::Element * p) : dtable(p->get_attribute_value("targettable")), dtablet(stringf("tmp_%s_%d", dtable.c_str(), getpid())) { - LoaderBase loader("http://project2.randomdan.homeip.net", true); + LoaderBase loader(ApplicationEngine::getCurrent()->env()->getXmlNamespace(), true); loader.supportedStorers.insert(Storer::into(&sources)); loader.collectAll(p, true); diff --git a/project2/xmlPresenter.cpp b/project2/xmlPresenter.cpp index 244c96c..494a88e 100644 --- a/project2/xmlPresenter.cpp +++ b/project2/xmlPresenter.cpp @@ -1,6 +1,7 @@ #include "xmlPresenter.h" #include "xmlObjectLoader.h" #include "variables.h" +#include "appEngine.h" XmlPresenter::XmlPresenter() : responseDoc(XmlDocumentPtr(new xmlpp::Document("1.0"))) @@ -12,17 +13,21 @@ XmlPresenter::~XmlPresenter() } void -XmlPresenter::initDoc() +XmlPresenter::createDoc() const { - nodeStack.push_back(responseDoc->create_root_node(getResponseRootNodeName())); - xmlNewNs(nodeStack.back()->cobj(), BAD_CAST "http://project2.randomdan.homeip.net", BAD_CAST "project2"); - // XSLT Style - char * buf; - if (!getResponseStyle().empty() && asprintf(&buf, "type=\"text/xsl\" href=\"%s\"", - getResponseStyle().c_str()) > 0) { - xmlAddPrevSibling(nodeStack.back()->cobj(), - xmlNewDocPI(responseDoc->cobj(), BAD_CAST "xml-stylesheet", BAD_CAST buf)); - free(buf); + if (nodeStack.empty()) { + nodeStack.push_back(responseDoc->create_root_node(getResponseRootNodeName())); + xmlNewNs(nodeStack.back()->cobj(), + BAD_CAST ApplicationEngine::getCurrent()->env()->getXmlNamespace().c_str(), + BAD_CAST ApplicationEngine::getCurrent()->env()->getXmlPrefix().c_str()); + // XSLT Style + char * buf; + if (!getResponseStyle().empty() && asprintf(&buf, "type=\"text/xsl\" href=\"%s\"", + getResponseStyle().c_str()) > 0) { + xmlAddPrevSibling(nodeStack.back()->cobj(), + xmlNewDocPI(responseDoc->cobj(), BAD_CAST "xml-stylesheet", BAD_CAST buf)); + free(buf); + } } } @@ -32,12 +37,11 @@ XmlProcessPresenter::XmlProcessPresenter(const std::string & group, const std::s responseStyle(present.get_document()->get_root_node()->get_attribute_value("style")), contentType(present.get_document()->get_root_node()->get_attribute_value("contenttype")) { - LoaderBase loader("http://project2.randomdan.homeip.net", true); + LoaderBase loader(ApplicationEngine::getCurrent()->env()->getXmlNamespace(), true); loader.supportedStorers.insert(Storer::into(&rowSets)); loader.supportedStorers.insert(Storer::into(&views)); loader.supportedStorers.insert(Storer::into(¶meterChecks)); loader.collectAll(this, present.get_document()->get_root_node(), true); - initDoc(); } XmlProcessPresenter::~XmlProcessPresenter() @@ -65,6 +69,7 @@ XmlPresenter::getDataDocument() const void XmlPresenter::pushSub(const Glib::ustring & name, const Glib::ustring & ns) const { + createDoc(); nodeStack.push_back(nodeStack.back()->add_child(name, ns)); } @@ -72,6 +77,7 @@ void XmlPresenter::addAttr(const Glib::ustring & name, const Glib::ustring & ns, const VariableType & value) const { if (!boost::get(&value)) { + createDoc(); nodeStack.back()->set_attribute(name, value, ns); } } @@ -80,6 +86,7 @@ void XmlPresenter::setText(const VariableType & value) const { if (!boost::get(&value)) { + createDoc(); nodeStack.back()->set_child_text(value); } } diff --git a/project2/xmlPresenter.h b/project2/xmlPresenter.h index 8ced38f..cc1312a 100644 --- a/project2/xmlPresenter.h +++ b/project2/xmlPresenter.h @@ -23,11 +23,9 @@ class XmlPresenter : public Presenter { virtual const Glib::ustring & getResponseRootNodeName() const = 0; virtual const Glib::ustring & getResponseStyle() const = 0; - protected: - void initDoc(); - XmlDocumentPtr responseDoc; - private: + void createDoc() const; + XmlDocumentPtr responseDoc; mutable std::vector nodeStack; }; -- cgit v1.2.3