From 8faab38b589a99b316ba41960ad8ce43b4339387 Mon Sep 17 00:00:00 2001 From: randomdan Date: Fri, 25 Feb 2011 14:53:40 +0000 Subject: Build a common base for loading p2 xml scripts with proper error checking Extend cgiAppEngine to be able to return data documents specifying an error (requires Apache 2.2.16 and to have filter-errordocs set) Allow cgi requests to return a default document, suitable for 'yes, I did that' type responses Updates to GentooBrowse to use these features --- project2/Jamfile.jam | 2 +- project2/cgi/cgiAppEngine.cpp | 238 ++++++++++++++++++++++++++++------ project2/cgi/cgiAppEngine.h | 83 +++++++++--- project2/cgi/cgiCommon.cpp | 17 +-- project2/cgi/cgiEnvironment.cpp | 8 +- project2/cgi/cgiEnvironment.h | 4 +- project2/commonObjects.cpp | 6 +- project2/config.cpp | 6 +- project2/console/consoleAppEngine.cpp | 6 +- project2/exceptions.h | 5 + project2/presenter.h | 1 - project2/sendmailTask.cpp | 4 +- project2/xmlPresenter.cpp | 56 +++++--- project2/xmlPresenter.h | 32 +++-- project2/xmlScriptParser.cpp | 40 ++++++ project2/xmlScriptParser.h | 25 ++++ 16 files changed, 415 insertions(+), 118 deletions(-) create mode 100644 project2/xmlScriptParser.cpp create mode 100644 project2/xmlScriptParser.h diff --git a/project2/Jamfile.jam b/project2/Jamfile.jam index d4e72e8..f591344 100644 --- a/project2/Jamfile.jam +++ b/project2/Jamfile.jam @@ -49,7 +49,7 @@ lib p2uuid : lib p2common : appEngine.cpp dataSource.cpp environment.cpp fileStarGlibIoChannel.cpp iHaveParameters.cpp - iterate.cpp paramChecker.cpp presenter.cpp rawView.cpp logger.cpp if.cpp + iterate.cpp paramChecker.cpp presenter.cpp rawView.cpp logger.cpp if.cpp xmlScriptParser.cpp sourceObject.cpp task.cpp variables.cpp variableConvert.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 config.cpp fileStrmVarWriter.cpp diff --git a/project2/cgi/cgiAppEngine.cpp b/project2/cgi/cgiAppEngine.cpp index 40d1431..043da76 100644 --- a/project2/cgi/cgiAppEngine.cpp +++ b/project2/cgi/cgiAppEngine.cpp @@ -1,14 +1,15 @@ #include "cgiAppEngine.h" #include -#include +#include #include "cgiEnvironment.h" -#include #include "../xmlObjectLoader.h" #include "../iterate.h" +#include "../logger.h" #include #include #include #include "../sessionXml.h" +#include const std::string SESSIONID = "sessionID"; typedef UUID SIDKey; @@ -18,27 +19,64 @@ SessionContainer * sessionsContainer = new SessionContainerXml(); SimpleMessageException(UnknownDomain); +class Project2HttpHeader : public cgicc::HTTPStatusHeader { + public: + typedef std::map Headers; + Project2HttpHeader(int c, const std::string & m, const std::string & t) : + cgicc::HTTPStatusHeader(c, m) + { + 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; + } + cgicc::HTTPStatusHeader::render(out); + } + private: + Headers headers; +}; + +static +int +xmlWrite(void * _out, const char * buf, int len) +{ + std::ostream * IO = static_cast(_out); + IO->write(buf, len); + return len; +} + CgiApplicationEngine::CgiApplicationEngine(const CgiEnvironment * e) : ApplicationEngine("web/host"), - _env(e), - header(NULL) + _env(e) { BOOST_FOREACH(const cgicc::HTTPCookie c, e->getCookieList()) { if (c.getName() == SESSIONID) { sessionID = c.getValue(); } } - if (_env->getRequestMethod() == "POST") { - currentStage = new RequestStage(this, e->elems[0]); + 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); } - else { - currentStage = new PresentStage(this, e->elems.size() > 0 ? e->elems[0] : "index"); + catch (const std::exception & ex) { + currentStage = new ErrorStage(_env, ex); } } CgiApplicationEngine::~CgiApplicationEngine() { - delete header; } const Environment * @@ -48,45 +86,50 @@ CgiApplicationEngine::env() const } void -CgiApplicationEngine::write(const XmlWriter & w) const +CgiApplicationEngine::write(std::ostream & IO) const { - w(doc->cobj()); -} - -void -CgiApplicationEngine::process() const -{ - while (!doc && currentStage) { - currentStage = currentStage->run(); - } + HttpHeaderPtr header = currentStage->getHeader(); if (!sessionID.is_nil()) { header->setCookie(cgicc::HTTPCookie(SESSIONID, sessionID.str(), "Session ID", _env->getServerName().substr(_env->getServerName().find(".")), 3600, "/", false)); } + header->render(IO); + xmlOutputBufferPtr out = xmlOutputBufferCreateIO( + xmlWrite, NULL, &IO, xmlGetCharEncodingHandler(XML_CHAR_ENCODING_UTF8)); + xmlSaveFileTo(out, currentStage->getDataDocument()->cobj(), "utf-8"); #ifndef NDEBUG if (!_env->dumpdatadoc.empty()) { - doc->write_to_file_formatted(_env->dumpdatadoc); + currentStage->getDataDocument()->write_to_file_formatted(_env->dumpdatadoc); } #endif } -CgiApplicationEngine::Stage::Stage(const CgiApplicationEngine * e) : appEngine(e) +void +CgiApplicationEngine::process() const { + try { + for (StagePtr nextStage; (nextStage = currentStage->run()); ) { + currentStage = nextStage; + } + } + catch (const XmlScriptParser::NotFound & nf) { + currentStage = new NotFoundStage(_env, nf); + } + catch (const std::exception & ex) { + currentStage = new ErrorStage(_env, ex); + } } -CgiApplicationEngine::Stage::~Stage() +CgiApplicationEngine::Stage::Stage() { } -CgiApplicationEngine::PresentStage::PresentStage(const CgiApplicationEngine * e, const std::string & id) : - CgiApplicationEngine::Stage(e), - XmlPresenter("present", id) +CgiApplicationEngine::Stage::~Stage() { } -CgiApplicationEngine::PresentStage::PresentStage(const CgiApplicationEngine * e, const std::string & group, const std::string & id) : - CgiApplicationEngine::Stage(e), - XmlPresenter(group, id) +CgiApplicationEngine::PresentStage::PresentStage(const std::string & id) : + XmlProcessPresenter("present", id, false) { } @@ -99,16 +142,28 @@ CgiApplicationEngine::PresentStage::run() { BOOST_FOREACH(ParamCheckers::value_type pc, parameterChecks.get()) { if (!pc->performCheck()) { - return new PresentStage(appEngine, pc->present); + return new PresentStage(pc->present); } } execute(); - appEngine->doc = getDataDocument(); - appEngine->header = new cgicc::HTTPContentHeader(contentType); sessionsContainer->CleanUp(); 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(); +} + void CgiApplicationEngine::addAppData(const Presenter * p) const { @@ -144,11 +199,9 @@ CgiApplicationEngine::addAppData(const Presenter * p) const } } -CgiApplicationEngine::RequestStage::RequestStage(const CgiApplicationEngine * e, const std::string & id) : - CgiApplicationEngine::Stage(e) +CgiApplicationEngine::RequestStage::RequestStage(const std::string & id) { - xmlpp::DomParser request("request/" + id + ".xml"); - while (xmlXIncludeProcessFlags(request.get_document()->cobj(), XML_PARSE_NOXINCNODE) > 0); + XmlScriptParser request("request", id, false); xmlpp::Element * requestRoot = request.get_document()->get_root_node(); present = requestRoot->get_attribute_value("present"); @@ -166,7 +219,7 @@ CgiApplicationEngine::RequestStage::run() { BOOST_FOREACH(const ParamCheckers::value_type & pc, parameterChecks.get()) { if (!pc->performCheck()) { - return new PresentStage(appEngine, pc->present); + return new PresentStage(pc->present); } } try { @@ -177,7 +230,7 @@ CgiApplicationEngine::RequestStage::run() BOOST_FOREACH(const DataSources::value_type & ds, datasources) { ds->commit(); } - return new PresentStage(appEngine, present); + return present.empty() ? NULL : new PresentStage(present); } catch (...) { // Do something about the error @@ -188,6 +241,31 @@ CgiApplicationEngine::RequestStage::run() } } +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 { @@ -217,3 +295,89 @@ 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 1425207..79638f4 100644 --- a/project2/cgi/cgiAppEngine.h +++ b/project2/cgi/cgiAppEngine.h @@ -8,36 +8,32 @@ #include "../commonObjects.h" #include "../uuid.h" #include -#include -#include -#include class CgiEnvironment; class Session; namespace cgicc { - class HTTPContentHeader; + class HTTPHeader; +} +namespace xmlpp { + class Document; } class CgiApplicationEngine : public ApplicationEngine { public: typedef boost::shared_ptr XmlDocPtr; - typedef boost::function1 XmlWriter; + typedef boost::shared_ptr HttpHeaderPtr; CgiApplicationEngine(const CgiEnvironment *); virtual ~CgiApplicationEngine(); void process() const; - const cgicc::HTTPContentHeader * getHeader() const { return header; } - void write(const XmlWriter & w) const; + void write(std::ostream &) const; 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; @@ -45,39 +41,84 @@ class CgiApplicationEngine : public ApplicationEngine { bool checkDomain(const DomainPlatforms::value_type & i) const; void loadEngineSection(const xmlpp::Element *) const; - mutable XmlDocPtr doc; - class Stage; typedef boost::intrusive_ptr StagePtr; class Stage : public virtual CommonObjects { public: - Stage(const CgiApplicationEngine *); + Stage(); virtual ~Stage() = 0; virtual StagePtr run() = 0; - protected: - const CgiApplicationEngine * appEngine; + virtual XmlDocPtr getDataDocument() const = 0; + virtual HttpHeaderPtr getHeader() const = 0; }; - class RequestStage : public Stage { + class RequestStage : public Stage, public XmlPresenter { public: - RequestStage(const CgiApplicationEngine *, const std::string & id); + RequestStage(const std::string & id); virtual ~RequestStage(); + virtual StagePtr run(); - std::string present; + virtual XmlDocPtr getDataDocument() const; + virtual HttpHeaderPtr getHeader() const; + virtual const Glib::ustring & getResponseRootNodeName() const; + virtual const Glib::ustring & getResponseStyle() const; + protected: + std::string present; typedef Storage::Objects ParamCheckers; ParamCheckers parameterChecks; typedef Storage::Objects Tasks; Tasks tasks; + + private: + static const Glib::ustring resp; + static const Glib::ustring style; }; - class PresentStage : public Stage, public XmlPresenter { + class PresentStage : public Stage, public XmlProcessPresenter { public: - PresentStage(const CgiApplicationEngine *, const std::string & id); - PresentStage(const CgiApplicationEngine *, const std::string & group, const std::string & id); + PresentStage(const std::string & id); virtual ~PresentStage(); + + virtual StagePtr run(); + virtual XmlDocPtr getDataDocument() const; + virtual HttpHeaderPtr getHeader() const; + }; + + class FailStage : public Stage, public XmlPresenter { + public: + FailStage(const CgiEnvironment *); + virtual ~FailStage(); + + virtual const Glib::ustring & getResponseStyle() const; virtual StagePtr run(); + + protected: + const CgiEnvironment * env; + }; + + class NotFoundStage : public FailStage { + public: + NotFoundStage(const CgiEnvironment *, const XmlScriptParser::NotFound &); + virtual ~NotFoundStage(); + + virtual XmlDocPtr getDataDocument() const; + virtual HttpHeaderPtr getHeader() const; + virtual const Glib::ustring & getResponseRootNodeName() const; + private: + static const Glib::ustring resp; + }; + + class ErrorStage : public FailStage { + public: + ErrorStage(const CgiEnvironment *, const std::exception &); + virtual ~ErrorStage(); + virtual XmlDocPtr getDataDocument() const; + virtual HttpHeaderPtr getHeader() const; + virtual const Glib::ustring & getResponseRootNodeName() const; + private: + static const Glib::ustring resp; }; mutable StagePtr currentStage; mutable UUID sessionID; diff --git a/project2/cgi/cgiCommon.cpp b/project2/cgi/cgiCommon.cpp index 322bdf7..fa40d2b 100644 --- a/project2/cgi/cgiCommon.cpp +++ b/project2/cgi/cgiCommon.cpp @@ -10,15 +10,6 @@ #include #include -static -int -xmlWrite(void * _out, const char * buf, int len) -{ - std::ostream * IO = static_cast(_out); - IO->write(buf, len); - return len; -} - // These are templates because some people don't inherit their // exceptions from std::exception like normal people (Glib) const char * @@ -57,14 +48,8 @@ cgiServe(cgicc::CgiInput * i, std::ostream & IO) Logger()->messagef(LOG_DEBUG, "%s: Processing request", __FUNCTION__); app.process(); - Logger()->messagef(LOG_DEBUG, "%s: Sending request result", __FUNCTION__); - IO << "Cache-control: no-cache" << std::endl; - app.getHeader()->render(IO); - xmlOutputBufferPtr out = xmlOutputBufferCreateIO( - xmlWrite, NULL, &IO, xmlGetCharEncodingHandler(XML_CHAR_ENCODING_UTF8)); - app.write(boost::bind(xmlSaveFileTo, out, _1, "utf-8")); - + app.write(IO); Logger()->messagef(LOG_DEBUG, "%s: Completed request", __FUNCTION__); } catch (const std::exception & e) { diff --git a/project2/cgi/cgiEnvironment.cpp b/project2/cgi/cgiEnvironment.cpp index f858262..3fdb158 100644 --- a/project2/cgi/cgiEnvironment.cpp +++ b/project2/cgi/cgiEnvironment.cpp @@ -27,12 +27,16 @@ boost::program_options::options_description CgiEnvironment::addOptions(boost::program_options::positional_options_description &) { boost::program_options::options_description cgi("Project2 CGI options"); -#ifndef NDEBUG cgi.add_options() + ("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") +#ifndef NDEBUG ("dumpdatadoc", boost::program_options::value(&dumpdatadoc), "Write a copy of the data document before sending it to the web server") - ; #endif + ; return cgi; } diff --git a/project2/cgi/cgiEnvironment.h b/project2/cgi/cgiEnvironment.h index 1774417..c9b33fa 100644 --- a/project2/cgi/cgiEnvironment.h +++ b/project2/cgi/cgiEnvironment.h @@ -26,10 +26,12 @@ class CgiEnvironment : public Environment, public cgicc::CgiEnvironment { 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 &); -#ifndef NDEBUG public: +#ifndef NDEBUG std::string dumpdatadoc; #endif + Glib::ustring errorContentType; + Glib::ustring errorTransformStyle; }; #endif diff --git a/project2/commonObjects.cpp b/project2/commonObjects.cpp index fcf479c..b6a3b7d 100644 --- a/project2/commonObjects.cpp +++ b/project2/commonObjects.cpp @@ -1,7 +1,6 @@ #include "commonObjects.h" #include "xmlObjectLoader.h" -#include -#include +#include "xmlScriptParser.h" CommonObjects::~CommonObjects() { @@ -22,8 +21,7 @@ CommonObjects::getSource(const std::string & name) const CommonObjects::DataSources::index::type::const_iterator CommonObjects::loadDataSource(const std::string & name) const { - xmlpp::DomParser xml("datasources/" + name + ".xml"); - while (xmlXIncludeProcessFlags(xml.get_document()->cobj(), XML_PARSE_NOXINCNODE) > 0); + XmlScriptParser xml("datasources", name, true); LoaderBase loader("http://project2.randomdan.homeip.net", true); loader.supportedStorers.insert(Storer::into(&datasources)); diff --git a/project2/config.cpp b/project2/config.cpp index c3823ff..a3b9afe 100644 --- a/project2/config.cpp +++ b/project2/config.cpp @@ -2,8 +2,7 @@ #include "exceptions.h" #include #include -#include -#include +#include "xmlScriptParser.h" SimpleMessageException(NoSuchPlatform); SimpleMessageException(NoSuchConfigurationValue); @@ -24,8 +23,7 @@ Configuration::load() const if (!boost::filesystem::exists("config.xml")) { return; } - xmlpp::DomParser configxml("config.xml"); - while (xmlXIncludeProcessFlags(configxml.get_document()->cobj(), XML_PARSE_NOXINCNODE) > 0); + 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); diff --git a/project2/console/consoleAppEngine.cpp b/project2/console/consoleAppEngine.cpp index 7ef1ad0..e126793 100644 --- a/project2/console/consoleAppEngine.cpp +++ b/project2/console/consoleAppEngine.cpp @@ -2,8 +2,7 @@ #include "consoleEnvironment.h" #include "../iterate.h" #include "../xmlObjectLoader.h" -#include -#include +#include "../xmlScriptParser.h" #include SimpleMessageException(UnknownPlatformAlias); @@ -59,8 +58,7 @@ ConsoleApplicationEngine::ConsoleApplicationEngine(const ConsoleEnvironment * en runtime(new ConsoleSession()), out(stdout, true) { - xmlpp::DomParser request(f.string()); - while (xmlXIncludeProcessFlags(request.get_document()->cobj(), XML_PARSE_NOXINCNODE) > 0); + XmlScriptParser request(f.string(), false); LoaderBase loader("http://project2.randomdan.homeip.net", true); loader.supportedStorers.insert(Storer::into(¶meterChecks)); diff --git a/project2/exceptions.h b/project2/exceptions.h index b6c64ae..23faafc 100644 --- a/project2/exceptions.h +++ b/project2/exceptions.h @@ -17,6 +17,11 @@ class Name : public std::runtime_error { \ public: \ Name(const std::string & what) : std::runtime_error(what) { } \ } +#define SimpleMessageExceptionBase(Name, Base) \ +class Name : public Base { \ + public: \ + Name(const std::string & what) : Base(what) { } \ +} #define SimpleNumericException(Name) \ class Name : public numeric_error { \ public: \ diff --git a/project2/presenter.h b/project2/presenter.h index 6b75c5a..2391a29 100644 --- a/project2/presenter.h +++ b/project2/presenter.h @@ -4,7 +4,6 @@ #include #include #include -#include #include "view.h" #include "paramChecker.h" #include "commonObjects.h" diff --git a/project2/sendmailTask.cpp b/project2/sendmailTask.cpp index b1e3bb6..e891fea 100644 --- a/project2/sendmailTask.cpp +++ b/project2/sendmailTask.cpp @@ -135,7 +135,7 @@ class TextContent : public SendMailTask::MailPart { void SendMailTask::execute() const { - XmlPresenterPtr p = new XmlPresenter("emails", present); + XmlPresenterPtr p = new XmlProcessPresenter("emails", present, true); p->execute(); XmlPresenter::XmlDocumentPtr data = p->getDataDocument(); #if DEBUG @@ -144,7 +144,7 @@ SendMailTask::execute() const typedef boost::shared_ptr XsltStyleSheetPtr; // Do transform - XsltStyleSheetPtr cur = XsltStyleSheetPtr(xsltParseStylesheetFile(BAD_CAST p->responseStyle.c_str()), xsltFreeStylesheet); + XsltStyleSheetPtr cur = XsltStyleSheetPtr(xsltParseStylesheetFile(BAD_CAST p->getResponseStyle().c_str()), xsltFreeStylesheet); if (!cur) { throw xmlpp::exception("Failed to load stylesheet"); } diff --git a/project2/xmlPresenter.cpp b/project2/xmlPresenter.cpp index 906d2c9..244c96c 100644 --- a/project2/xmlPresenter.cpp +++ b/project2/xmlPresenter.cpp @@ -1,37 +1,59 @@ #include "xmlPresenter.h" #include "xmlObjectLoader.h" -#include #include "variables.h" +XmlPresenter::XmlPresenter() : + responseDoc(XmlDocumentPtr(new xmlpp::Document("1.0"))) +{ +} + XmlPresenter::~XmlPresenter() { } -XmlPresenter::XmlPresenter(const std::string & group, const std::string & file) : - present(group + "/" + file + ".xml"), +void +XmlPresenter::initDoc() +{ + 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); + } +} + +XmlProcessPresenter::XmlProcessPresenter(const std::string & group, const std::string & file, bool isInclusion) : + present(group, file, isInclusion), responseRootNodeName(present.get_document()->get_root_node()->get_attribute_value("root")), responseStyle(present.get_document()->get_root_node()->get_attribute_value("style")), - contentType(present.get_document()->get_root_node()->get_attribute_value("contenttype")), - responseDoc(XmlDocumentPtr(new xmlpp::Document("1.0"))) + contentType(present.get_document()->get_root_node()->get_attribute_value("contenttype")) { - while (xmlXIncludeProcessFlags(present.get_document()->cobj(), XML_PARSE_NOXINCNODE) > 0); - LoaderBase loader("http://project2.randomdan.homeip.net", 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(); +} - nodeStack.push_back(responseDoc->create_root_node(responseRootNodeName)); - xmlNewNs(nodeStack.back()->cobj(), BAD_CAST "http://project2.randomdan.homeip.net", BAD_CAST "project2"); - // XSLT Style - char * buf; - if (responseStyle.length() && asprintf(&buf, "type=\"text/xsl\" href=\"%s\"", - responseStyle.c_str()) > 0) { - xmlAddPrevSibling(nodeStack.back()->cobj(), - xmlNewDocPI(responseDoc->cobj(), BAD_CAST "xml-stylesheet", BAD_CAST buf)); - free(buf); - } +XmlProcessPresenter::~XmlProcessPresenter() +{ +} + +const Glib::ustring & +XmlProcessPresenter::getResponseRootNodeName() const +{ + return responseRootNodeName; +} + +const Glib::ustring & +XmlProcessPresenter::getResponseStyle() const +{ + return responseStyle; } XmlPresenter::XmlDocumentPtr diff --git a/project2/xmlPresenter.h b/project2/xmlPresenter.h index effa713..8ced38f 100644 --- a/project2/xmlPresenter.h +++ b/project2/xmlPresenter.h @@ -2,11 +2,16 @@ #define XMLPRESENTER_H #include "presenter.h" +#include "xmlScriptParser.h" + +namespace xmlpp { + class Document; +} class XmlPresenter : public Presenter { public: typedef boost::shared_ptr XmlDocumentPtr; - XmlPresenter(const std::string & group, const std::string & file); + XmlPresenter(); ~XmlPresenter(); void pushSub(const Glib::ustring & name, const Glib::ustring & ns) const; @@ -15,22 +20,33 @@ class XmlPresenter : public Presenter { void popSub() const; virtual XmlDocumentPtr getDataDocument() const; + virtual const Glib::ustring & getResponseRootNodeName() const = 0; + virtual const Glib::ustring & getResponseStyle() const = 0; protected: - xmlpp::DomParser present; + void initDoc(); + XmlDocumentPtr responseDoc; + + private: + mutable std::vector nodeStack; +}; +class XmlProcessPresenter : public XmlPresenter { public: - const Glib::ustring responseRootNodeName; - const Glib::ustring responseStyle; - const Glib::ustring contentType; + XmlProcessPresenter(const std::string & group, const std::string & file, bool isInclusion); + ~XmlProcessPresenter(); protected: + const Glib::ustring & getResponseRootNodeName() const; + const Glib::ustring & getResponseStyle() const; + + XmlScriptParser present; typedef Storage::Objects ParamCheckers; ParamCheckers parameterChecks; - private: - XmlDocumentPtr responseDoc; - mutable std::vector nodeStack; + const Glib::ustring responseRootNodeName; + const Glib::ustring responseStyle; + const Glib::ustring contentType; }; typedef boost::intrusive_ptr XmlPresenterPtr; diff --git a/project2/xmlScriptParser.cpp b/project2/xmlScriptParser.cpp new file mode 100644 index 0000000..8db4049 --- /dev/null +++ b/project2/xmlScriptParser.cpp @@ -0,0 +1,40 @@ +#include "xmlScriptParser.h" +#include +#include + +XmlScriptParser::XmlScriptParser(const std::string & group, const std::string & name, bool ii) : + IsInclusion(ii) +{ + loadDocument(group + "/" + name + ".xml"); +} + +XmlScriptParser::XmlScriptParser(const std::string & file, bool ii) : + IsInclusion(ii) +{ + loadDocument(file); +} + +void +XmlScriptParser::loadDocument(const std::string & file) +{ + if (!boost::filesystem::exists(file)) { + if (IsInclusion) { + throw DependencyNotFound(file); + } + else { + throw NotFound(file); + } + } + try { + parse_file(file); + } + catch (const xmlpp::internal_error &) { + throw NotReadable(file); + } + for (int x; (x = xmlXIncludeProcessFlags(get_document()->cobj(), XML_PARSE_NOXINCNODE)); ) { + if (x < 0) { + throw IncludesError(file); + } + } +} + diff --git a/project2/xmlScriptParser.h b/project2/xmlScriptParser.h new file mode 100644 index 0000000..92d1bdb --- /dev/null +++ b/project2/xmlScriptParser.h @@ -0,0 +1,25 @@ +#ifndef XMLSCRIPTPARSER_H +#define XMLSCRIPTPARSER_H + +#include +#include "exceptions.h" + +class XmlScriptParser : public xmlpp::DomParser { + public: + SimpleMessageException(ParseError); + SimpleMessageExceptionBase(NotFound, ParseError); + SimpleMessageExceptionBase(DependencyNotFound, ParseError); + SimpleMessageExceptionBase(NotReadable, ParseError); + SimpleMessageExceptionBase(IncludesError, ParseError); + + XmlScriptParser(const std::string & group, const std::string & name, bool isInclusion); + XmlScriptParser(const std::string & file, bool isInclusion); + + const bool IsInclusion; + + private: + void loadDocument(const std::string & file); +}; + +#endif + -- cgit v1.2.3