summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrandomdan <randomdan@localhost>2011-02-25 14:53:40 +0000
committerrandomdan <randomdan@localhost>2011-02-25 14:53:40 +0000
commitb5e7fca95a6a29b84d987f61414e0c27cf2a0ddf (patch)
treed79f16f16ecb190edf1cac3d8d2f554e403632f3
parentFinally convert ytfs to use boost stuff (untested, but it does build) (diff)
downloadproject2-b5e7fca95a6a29b84d987f61414e0c27cf2a0ddf.tar.bz2
project2-b5e7fca95a6a29b84d987f61414e0c27cf2a0ddf.tar.xz
project2-b5e7fca95a6a29b84d987f61414e0c27cf2a0ddf.zip
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
-rw-r--r--project2/Jamfile.jam2
-rw-r--r--project2/cgi/cgiAppEngine.cpp238
-rw-r--r--project2/cgi/cgiAppEngine.h83
-rw-r--r--project2/cgi/cgiCommon.cpp17
-rw-r--r--project2/cgi/cgiEnvironment.cpp8
-rw-r--r--project2/cgi/cgiEnvironment.h4
-rw-r--r--project2/commonObjects.cpp6
-rw-r--r--project2/config.cpp6
-rw-r--r--project2/console/consoleAppEngine.cpp6
-rw-r--r--project2/exceptions.h5
-rw-r--r--project2/presenter.h1
-rw-r--r--project2/sendmailTask.cpp4
-rw-r--r--project2/xmlPresenter.cpp56
-rw-r--r--project2/xmlPresenter.h32
-rw-r--r--project2/xmlScriptParser.cpp40
-rw-r--r--project2/xmlScriptParser.h25
16 files changed, 415 insertions, 118 deletions
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 <cgicc/Cgicc.h>
-#include <cgicc/HTTPContentHeader.h>
+#include <cgicc/HTTPStatusHeader.h>
#include "cgiEnvironment.h"
-#include <libxml/xinclude.h>
#include "../xmlObjectLoader.h"
#include "../iterate.h"
+#include "../logger.h"
#include <boost/bind.hpp>
#include <boost/regex.hpp>
#include <boost/foreach.hpp>
#include "../sessionXml.h"
+#include <cxxabi.h>
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<std::string, const Glib::ustring> 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<std::ostream*>(_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<bySOOrder>()) {
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<bySOOrder>()) {
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 <boost/intrusive_ptr.hpp>
-#include <boost/function.hpp>
-#include <libxml++/document.h>
-#include <libxml++/parsers/domparser.h>
class CgiEnvironment;
class Session;
namespace cgicc {
- class HTTPContentHeader;
+ class HTTPHeader;
+}
+namespace xmlpp {
+ class Document;
}
class CgiApplicationEngine : public ApplicationEngine {
public:
typedef boost::shared_ptr<xmlpp::Document> XmlDocPtr;
- typedef boost::function1<void, xmlDocPtr> XmlWriter;
+ typedef boost::shared_ptr<cgicc::HTTPHeader> 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<Glib::ustring, Glib::ustring> DomainPlatform;
typedef std::list<DomainPlatform> 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<Stage> 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<ParamChecker>::Objects ParamCheckers;
ParamCheckers parameterChecks;
typedef Storage<NoOutputExecute>::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 <boost/bind.hpp>
#include <cxxabi.h>
-static
-int
-xmlWrite(void * _out, const char * buf, int len)
-{
- std::ostream * IO = static_cast<std::ostream*>(_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<Glib::ustring>(&errorContentType)->default_value("text/xml"),
+ "The Content-Type to use in HTTP headers in event of an error")
+ ("errortransformstyle", boost::program_options::value<Glib::ustring>(&errorTransformStyle),
+ "The xml-stylesheet to specify in the data document in event of an error")
+#ifndef NDEBUG
("dumpdatadoc", boost::program_options::value<std::string>(&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 <libxml++/parsers/domparser.h>
-#include <libxml/xinclude.h>
+#include "xmlScriptParser.h"
CommonObjects::~CommonObjects()
{
@@ -22,8 +21,7 @@ CommonObjects::getSource(const std::string & name) const
CommonObjects::DataSources::index<bySOName>::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 <boost/filesystem/operations.hpp>
#include <boost/foreach.hpp>
-#include <libxml/xinclude.h>
-#include <libxml++/parsers/domparser.h>
+#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<const xmlpp::Element *>(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 <libxml/xinclude.h>
-#include <libxml++/parsers/domparser.h>
+#include "../xmlScriptParser.h"
#include <boost/foreach.hpp>
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(&parameterChecks));
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 <boost/intrusive_ptr.hpp>
#include <boost/shared_ptr.hpp>
#include <glibmm/ustring.h>
-#include <libxml++/parsers/domparser.h>
#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<xsltStylesheet> 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 <libxml/xinclude.h>
#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(&parameterChecks));
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<xmlpp::Document> 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<xmlpp::Element *> 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<ParamChecker>::Objects ParamCheckers;
ParamCheckers parameterChecks;
- private:
- XmlDocumentPtr responseDoc;
- mutable std::vector<xmlpp::Element *> nodeStack;
+ const Glib::ustring responseRootNodeName;
+ const Glib::ustring responseStyle;
+ const Glib::ustring contentType;
};
typedef boost::intrusive_ptr<XmlPresenter> 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 <libxml/xinclude.h>
+#include <boost/filesystem/convenience.hpp>
+
+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 <libxml++/parsers/domparser.h>
+#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
+