diff options
author | randomdan <randomdan@localhost> | 2011-07-14 19:50:11 +0000 |
---|---|---|
committer | randomdan <randomdan@localhost> | 2011-07-14 19:50:11 +0000 |
commit | d2f60795927647c09acbeceb32efb8a29314c340 (patch) | |
tree | 5dc1f6f9b8331a17e67863c847ea63ca97f5d92c | |
parent | Fix unused_result warning when compiled with optimization enabled (diff) | |
download | project2-d2f60795927647c09acbeceb32efb8a29314c340.tar.bz2 project2-d2f60795927647c09acbeceb32efb8a29314c340.tar.xz project2-d2f60795927647c09acbeceb32efb8a29314c340.zip |
All new dynamic transformations and processing and tidyup and stuff
63 files changed, 1214 insertions, 709 deletions
diff --git a/project2/Jamfile.jam b/project2/Jamfile.jam index 5b9799a..6015b7e 100644 --- a/project2/Jamfile.jam +++ b/project2/Jamfile.jam @@ -43,7 +43,7 @@ feature pq : yes no : propagated ; project : requirements <variant>debug:<cflags>"-W -Wall -Werror -Wwrite-strings" - <variant>debug:<linkflags>-Wl,-z,defs + <variant>debug:<linkflags>"-Wl,-z,defs --warn-once" ; lib p2uuid : @@ -56,10 +56,11 @@ lib p2uuid : lib p2common : appEngine.cpp dataSource.cpp environment.cpp fileStarGlibIoChannel.cpp iHaveParameters.cpp library.cpp - iterate.cpp paramChecker.cpp presenter.cpp rawView.cpp logger.cpp if.cpp xmlScriptParser.cpp + iterate.cpp paramChecker.cpp presenter.cpp rawView.cpp logger.cpp if.cpp xmlScriptParser.cpp viewHost.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 requestHost.cpp + sessionClearTask.cpp session.cpp sessionSetTask.cpp commonObjects.cpp xmlPresenter.cpp taskHost.cpp checkHost.cpp rowView.cpp rowSet.cpp rowUser.cpp rowProcessor.cpp config.cpp fileStrmVarWriter.cpp noOutputExecute.cpp + transform.cpp transformHtml.cpp transformText.cpp ../libmisc/buffer.cpp ../libmisc/misc.cpp : @@ -70,6 +71,7 @@ lib p2common : <library>boost_filesystem <library>boost_date_time <library>boost_program_options + <library>libxslt : : <include>. <include>../libmisc @@ -217,6 +219,13 @@ exe p2fcgi : <include>../libmisc ; +exe testCgi : + cgi/testCgi.cpp + : + <library>p2web + <include>../libmisc + ; + exe p2console : [ glob console/*.cpp ] : diff --git a/project2/cgi/cgiAppEngine.cpp b/project2/cgi/cgiAppEngine.cpp index 52e69cf..f4eb134 100644 --- a/project2/cgi/cgiAppEngine.cpp +++ b/project2/cgi/cgiAppEngine.cpp @@ -8,6 +8,7 @@ #include <boost/regex.hpp> #include <boost/foreach.hpp> #include "../sessionXml.h" +#include "../ostreamWrapper.h" #include <boost/date_time/microsec_time_clock.hpp> const std::string SESSIONID = "sessionID"; @@ -18,29 +19,22 @@ SessionContainer * sessionsContainer = new SessionContainerXml(); SimpleMessageException(UnknownDomain); -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) : +CgiApplicationEngine::CgiApplicationEngine(const CgiEnvironment * e, std::ostream & io) : ApplicationEngine("web/host"), - _env(e) + _env(e), + IO(io) { BOOST_FOREACH(const cgicc::HTTPCookie c, e->getCookieList()) { if (c.getName() == SESSIONID) { sessionID = c.getValue(); } } - currentStage = new InitialStage(e); + currentStage = NextStage(new InitialStage(e)); } CgiApplicationEngine::~CgiApplicationEngine() { + sessionsContainer->CleanUp(); } const Environment * @@ -49,25 +43,14 @@ CgiApplicationEngine::env() const return _env; } -void -CgiApplicationEngine::write(std::ostream & IO) const -{ - 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"); - sessionsContainer->CleanUp(); -#ifndef NDEBUG - if (!_env->dumpdatadoc.empty()) { - currentStage->getDataDocument()->write_to_file_formatted(_env->dumpdatadoc); - } -#endif -} +class TransformXmlToHttpStream : public TransformImpl<xmlpp::Document, ostreamWrapper> { + public: + void transform(const xmlpp::Document * doc, ostreamWrapper * o) const + { + const_cast<xmlpp::Document *>(doc)->write_to_stream_formatted(o->strm, "UTF-8"); + } +}; +DECLARE_TRANSFORM(TransformXmlToHttpStream); void CgiApplicationEngine::process() const @@ -75,34 +58,56 @@ CgiApplicationEngine::process() const startTime = boost::date_time::microsec_clock<boost::posix_time::ptime>::universal_time(); bool triedNotFound = false; bool triedOnError = false; - StagePtr nextStage; do { try { - nextStage = currentStage->run(); + currentStage = currentStage.get<0>()->run(); + } + catch (const CheckHost::CheckFailure & cf) { + currentStage = NextStage(new PresentStage(_env, cf.failedCheck->present)); } catch (const XmlScriptParser::NotFound & nf) { if (_env->notFoundPresent.empty() || triedNotFound) { - nextStage = new DefaultNotFoundStage(_env, nf); + currentStage = NextStage(new DefaultNotFoundStage(_env, nf)); } else { triedNotFound = true; - nextStage = new CustomNotFoundStage(_env, nf); + currentStage = NextStage(new CustomNotFoundStage(_env, nf)); } } catch (const std::exception & ex) { if (_env->onErrorPresent.empty() || triedOnError) { - nextStage = new DefaultErrorStage(_env, ex); + currentStage = NextStage(new DefaultErrorStage(_env, ex)); } else { triedNotFound = true; - nextStage = new CustomErrorStage(_env, ex); + currentStage = NextStage(new CustomErrorStage(_env, ex)); } } - } while (nextStage && (currentStage = nextStage)); + } while (currentStage.get<0>()); endTime = boost::date_time::microsec_clock<boost::posix_time::ptime>::universal_time(); - PresenterPtr p = boost::dynamic_pointer_cast<Presenter>(currentStage); - if (p) { - addAppData(p.get()); + ResponseStagePtr rs = currentStage.get<1>(); + if (currentStage.get<3>()) { + addAppData(currentStage.get<3>().get()); + addEnvData(currentStage.get<3>().get()); + } + HttpHeaderPtr header = rs->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); + if (currentStage.get<2>()) { + TransformSourcePtr ts = currentStage.get<2>(); + std::fstream * ddd = NULL; + if (!_env->dumpdatadoc.empty()) { + ddd = new std::fstream(_env->dumpdatadoc.c_str(), std::fstream::trunc | std::fstream::out); + ts->addTarget(new ostreamWrapper(*ddd)); + } + ts->addTarget(new ostreamWrapper(IO)); + ts->doTransforms(); + if (ddd) { + delete ddd; + } } } @@ -115,18 +120,6 @@ CgiApplicationEngine::Stage::~Stage() { } -CgiApplicationEngine::HttpHeaderPtr -CgiApplicationEngine::Stage::getHeader() const -{ - return CgiApplicationEngine::HttpHeaderPtr(); -} - -CgiApplicationEngine::XmlDocPtr -CgiApplicationEngine::Stage::getDataDocument() const -{ - return XmlDocPtr(); -} - void CgiApplicationEngine::addEnvData(const Presenter * p) const { diff --git a/project2/cgi/cgiAppEngine.h b/project2/cgi/cgiAppEngine.h index 78f796f..e2ad1a2 100644 --- a/project2/cgi/cgiAppEngine.h +++ b/project2/cgi/cgiAppEngine.h @@ -4,11 +4,14 @@ #include "../appEngine.h" #include "../task.h" #include "../paramChecker.h" -#include "../xmlPresenter.h" #include "../commonObjects.h" #include "../uuid.h" -#include "../requestHost.h" +#include "../taskHost.h" +#include "../viewHost.h" +#include "../transform.h" +#include "../xmlPresenter.h" #include <boost/intrusive_ptr.hpp> +#include <boost/tuple/tuple.hpp> class CgiEnvironment; class Session; @@ -19,16 +22,15 @@ namespace xmlpp { class Document; } -class CgiApplicationEngine : public ApplicationEngine { +class CgiApplicationEngine : public ApplicationEngine, public TransformChainLink { public: typedef boost::shared_ptr<xmlpp::Document> XmlDocPtr; typedef boost::shared_ptr<cgicc::HTTPHeader> HttpHeaderPtr; - CgiApplicationEngine(const CgiEnvironment *); + CgiApplicationEngine(const CgiEnvironment *, std::ostream &); virtual ~CgiApplicationEngine(); void process() const; - void write(std::ostream &) const; const Environment * env() const; SessionPtr session() const; virtual Glib::ustring resolveCurrentConfig() const; @@ -45,115 +47,103 @@ class CgiApplicationEngine : public ApplicationEngine { bool checkDomain(const DomainPlatforms::value_type & i) const; void loadEngineSection(const xmlpp::Element *) const; + public: class Stage; + class ResponseStage; typedef boost::intrusive_ptr<Stage> StagePtr; + typedef boost::intrusive_ptr<ResponseStage> ResponseStagePtr; + typedef boost::tuple<StagePtr, ResponseStagePtr, TransformSourcePtr, PresenterPtr> NextStage; /// Base class for a stage iteration that should eventually produce a response for the client - class Stage : public virtual CommonObjects { + class Stage : public virtual IntrusivePtrBase { public: Stage(const CgiEnvironment * e); virtual ~Stage() = 0; - virtual StagePtr run() = 0; - virtual XmlDocPtr getDataDocument() const; - virtual HttpHeaderPtr getHeader() const; + virtual NextStage run() = 0; protected: const CgiEnvironment * e; }; + /// Base class for a stage that can be a response to the client + class ResponseStage : public Stage { + public: + ResponseStage(const CgiEnvironment * e); + virtual HttpHeaderPtr getHeader() const = 0; + }; + /// 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(); + virtual NextStage run(); }; /// Stage to process POST requests - class RequestStage : public Stage, public XmlPresenter, RequestHost { + class RequestStage : public ResponseStage, TaskHost { public: RequestStage(const CgiEnvironment *, const std::string & id); - virtual StagePtr run(); - virtual XmlDocPtr getDataDocument() const; + virtual NextStage run(); 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; - - private: - static const Glib::ustring resp; - static const Glib::ustring style; }; /// Stage to process GET requests and follow up RequestStages - class PresentStage : public virtual Stage, public XmlProcessPresenter { + class PresentStage : public virtual ResponseStage, ViewHost { public: 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 NextStage run(); virtual HttpHeaderPtr getHeader() const; }; /// The built-in fail-safe not found stage - class DefaultNotFoundStage : public virtual Stage, public XmlPresenter { + class DefaultNotFoundStage : public virtual ResponseStage { public: DefaultNotFoundStage(const CgiEnvironment *, const XmlScriptParser::NotFound &); - virtual XmlDocPtr getDataDocument() const; + virtual NextStage run(); 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 XmlScriptParser::NotFound nf; + XmlPresenterPtr pres; }; /// 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; + CustomNotFoundStage(const CgiEnvironment *, const ::XmlScriptParser::NotFound &); + virtual NextStage run(); virtual HttpHeaderPtr getHeader() const; - virtual const Glib::ustring & getResponseRootNodeName() const; - virtual const Glib::ustring & getResponseStyle() const; }; /// The built-in fail-safe unhandled error stage - class DefaultErrorStage : public virtual Stage, public XmlPresenter { + class DefaultErrorStage : public virtual ResponseStage { public: DefaultErrorStage(const CgiEnvironment *, const std::exception &); ~DefaultErrorStage(); - virtual XmlDocPtr getDataDocument() const; + virtual NextStage run(); 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; char * buf; std::string what; + XmlPresenterPtr pres; }; /// Custom unhandled error handling stage class CustomErrorStage : public DefaultErrorStage, public PresentStage { public: CustomErrorStage(const CgiEnvironment *, const std::exception &); - virtual StagePtr run(); - virtual XmlDocPtr getDataDocument() const; + virtual NextStage run(); virtual HttpHeaderPtr getHeader() const; - virtual const Glib::ustring & getResponseRootNodeName() const; - virtual const Glib::ustring & getResponseStyle() const; }; - mutable StagePtr currentStage; + private: + mutable NextStage currentStage; mutable UUID sessionID; + mutable std::ostream & IO; }; #endif diff --git a/project2/cgi/cgiCommon.cpp b/project2/cgi/cgiCommon.cpp index fa40d2b..b8a2b93 100644 --- a/project2/cgi/cgiCommon.cpp +++ b/project2/cgi/cgiCommon.cpp @@ -44,12 +44,10 @@ cgiServe(cgicc::CgiInput * i, std::ostream & IO) CgiEnvironment env(&cgi); env.init(); try { - CgiApplicationEngine app(&env); + CgiApplicationEngine app(&env, IO); Logger()->messagef(LOG_DEBUG, "%s: Processing request", __FUNCTION__); app.process(); - Logger()->messagef(LOG_DEBUG, "%s: Sending request result", __FUNCTION__); - 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 e8d5ba3..2bc3b02 100644 --- a/project2/cgi/cgiEnvironment.cpp +++ b/project2/cgi/cgiEnvironment.cpp @@ -28,6 +28,8 @@ CgiEnvironment::addOptions(boost::program_options::positional_options_descriptio { boost::program_options::options_description cgi("Project2 CGI options"); cgi.add_options() + ("defaultpresenter", boost::program_options::value(&defaultPresenter)->default_value("xml"), + "The default engine for formatting presentations") ("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"), @@ -44,10 +46,8 @@ CgiEnvironment::addOptions(boost::program_options::positional_options_descriptio "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") -#endif ; return cgi; } diff --git a/project2/cgi/cgiEnvironment.h b/project2/cgi/cgiEnvironment.h index ce765bf..abfe78e 100644 --- a/project2/cgi/cgiEnvironment.h +++ b/project2/cgi/cgiEnvironment.h @@ -27,9 +27,7 @@ class CgiEnvironment : public Environment, public cgicc::CgiEnvironment { 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 &); public: -#ifndef NDEBUG std::string dumpdatadoc; -#endif Glib::ustring errorContentType; Glib::ustring errorTransformStyle; std::string defaultPresent; @@ -38,6 +36,7 @@ class CgiEnvironment : public Environment, public cgicc::CgiEnvironment { std::string errorPresentRoot; std::string notFoundPresent; std::string onErrorPresent; + std::string defaultPresenter; }; #endif diff --git a/project2/cgi/cgiStageCustomError.cpp b/project2/cgi/cgiStageCustomError.cpp index a3fbc1f..fb2f0de 100644 --- a/project2/cgi/cgiStageCustomError.cpp +++ b/project2/cgi/cgiStageCustomError.cpp @@ -4,7 +4,9 @@ #include "../logger.h" CgiApplicationEngine::CustomErrorStage::CustomErrorStage(const CgiEnvironment * env, const std::exception & ex) : - CgiApplicationEngine::Stage(env), + CgiApplicationEngine::ResponseStage(env), + ::XmlScriptParser(env->errorPresentRoot, env->onErrorPresent, false), + ::CheckHost(env->errorPresentRoot, env->onErrorPresent), CgiApplicationEngine::DefaultErrorStage(env, ex), CgiApplicationEngine::PresentStage(env, env->errorPresentRoot, env->onErrorPresent) { @@ -16,29 +18,10 @@ CgiApplicationEngine::CustomErrorStage::getHeader() const return CgiApplicationEngine::DefaultErrorStage::getHeader(); } -CgiApplicationEngine::StagePtr +CgiApplicationEngine::NextStage 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 index a2d33dc..7c08a9f 100644 --- a/project2/cgi/cgiStageCustomNotFound.cpp +++ b/project2/cgi/cgiStageCustomNotFound.cpp @@ -3,8 +3,10 @@ #include "cgiHttpHeader.h" #include "../logger.h" -CgiApplicationEngine::CustomNotFoundStage::CustomNotFoundStage(const CgiEnvironment * env, const XmlScriptParser::NotFound & notfound) : - CgiApplicationEngine::Stage(env), +CgiApplicationEngine::CustomNotFoundStage::CustomNotFoundStage(const CgiEnvironment * env, const ::XmlScriptParser::NotFound & notfound) : + CgiApplicationEngine::ResponseStage(env), + ::XmlScriptParser(env->errorPresentRoot, env->notFoundPresent, false), + ::CheckHost(env->errorPresentRoot, env->notFoundPresent), CgiApplicationEngine::DefaultNotFoundStage(env, notfound), CgiApplicationEngine::PresentStage(env, env->errorPresentRoot, env->notFoundPresent) { @@ -16,28 +18,10 @@ CgiApplicationEngine::CustomNotFoundStage::getHeader() const return CgiApplicationEngine::DefaultNotFoundStage::getHeader(); } -CgiApplicationEngine::StagePtr +CgiApplicationEngine::NextStage 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 index c881da1..767a634 100644 --- a/project2/cgi/cgiStageDefaultError.cpp +++ b/project2/cgi/cgiStageDefaultError.cpp @@ -4,12 +4,13 @@ #include "cgiEnvironment.h" #include <cxxabi.h> -const Glib::ustring CgiApplicationEngine::DefaultErrorStage::resp("error"); +static const Glib::ustring DefaultErrorStageResp("error"); CgiApplicationEngine::DefaultErrorStage::DefaultErrorStage(const CgiEnvironment * env, const std::exception & ex) : - CgiApplicationEngine::Stage(env), + CgiApplicationEngine::ResponseStage(env), buf(__cxxabiv1::__cxa_demangle(typeid(ex).name(), NULL, NULL, NULL)), - what(ex.what()) + what(ex.what()), + pres(new XmlPresenter(DefaultErrorStageResp, e->errorTransformStyle, e->errorContentType)) { } @@ -21,32 +22,14 @@ CgiApplicationEngine::DefaultErrorStage::~DefaultErrorStage() CgiApplicationEngine::HttpHeaderPtr CgiApplicationEngine::DefaultErrorStage::getHeader() const { - return HttpHeaderPtr(new Project2HttpHeader("500 Internal Server Error", e->errorContentType)); + return HttpHeaderPtr(new Project2HttpHeader("500 Internal Server Error", pres->contentType)); } -CgiApplicationEngine::StagePtr +CgiApplicationEngine::NextStage 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; + pres->addField("error-type", e->getXmlPrefix(), buf); + pres->addField("error-what", e->getXmlPrefix(), what.c_str()); + return NextStage(NULL, this, pres.get(), pres.get()); } diff --git a/project2/cgi/cgiStageDefaultNotFound.cpp b/project2/cgi/cgiStageDefaultNotFound.cpp index f32ad1f..2e7acb1 100644 --- a/project2/cgi/cgiStageDefaultNotFound.cpp +++ b/project2/cgi/cgiStageDefaultNotFound.cpp @@ -3,9 +3,12 @@ #include "cgiHttpHeader.h" #include "../logger.h" +static const Glib::ustring DefaultNotFoundStageResp("notfound"); + CgiApplicationEngine::DefaultNotFoundStage::DefaultNotFoundStage(const CgiEnvironment * env, const XmlScriptParser::NotFound & notfound) : - CgiApplicationEngine::Stage(env), - nf(notfound) + CgiApplicationEngine::ResponseStage(env), + nf(notfound), + pres(new XmlPresenter(DefaultNotFoundStageResp, e->errorTransformStyle, e->errorContentType)) { Logger()->messagef(LOG_ERR, "%s: Resource not found: %s", __FUNCTION__, nf.what()); } @@ -13,32 +16,13 @@ CgiApplicationEngine::DefaultNotFoundStage::DefaultNotFoundStage(const CgiEnviro CgiApplicationEngine::HttpHeaderPtr CgiApplicationEngine::DefaultNotFoundStage::getHeader() const { - return HttpHeaderPtr(new Project2HttpHeader("404 Not found", e->errorContentType)); + return HttpHeaderPtr(new Project2HttpHeader("404 Not found", pres->contentType)); } -CgiApplicationEngine::StagePtr +CgiApplicationEngine::NextStage 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; + pres->addField("missing-resource", e->getXmlPrefix(), nf.what()); + return NextStage(NULL, this, pres.get(), pres.get()); } diff --git a/project2/cgi/cgiStageInitial.cpp b/project2/cgi/cgiStageInitial.cpp index d302971..1db8f8f 100644 --- a/project2/cgi/cgiStageInitial.cpp +++ b/project2/cgi/cgiStageInitial.cpp @@ -9,17 +9,17 @@ CgiApplicationEngine::InitialStage::InitialStage(const CgiEnvironment * env) : { } -CgiApplicationEngine::StagePtr +CgiApplicationEngine::NextStage CgiApplicationEngine::InitialStage::run() { if (e->getRequestMethod() == "POST") { if (e->elems.empty()) { throw EmptyRequestURL(); } - return new RequestStage(e, e->elems[0]); + return NextStage(new RequestStage(e, e->elems[0])); } else { - return new PresentStage(e, e->elems.empty() ? e->defaultPresent : e->elems[0]); + return NextStage(new PresentStage(e, e->elems.empty() ? e->defaultPresent : e->elems[0])); } } diff --git a/project2/cgi/cgiStagePresent.cpp b/project2/cgi/cgiStagePresent.cpp index 47db567..aaa1092 100644 --- a/project2/cgi/cgiStagePresent.cpp +++ b/project2/cgi/cgiStagePresent.cpp @@ -2,44 +2,45 @@ #include "cgiEnvironment.h" #include "cgiHttpHeader.h" #include <boost/foreach.hpp> +#include <boost/bind.hpp> CgiApplicationEngine::PresentStage::PresentStage(const CgiEnvironment * e, const std::string & id) : - CgiApplicationEngine::Stage(e), - XmlProcessPresenter(e->presentRoot, id, false) + CgiApplicationEngine::ResponseStage(e), + XmlScriptParser(e->presentRoot, id, false), + CheckHost(e->presentRoot, id), + ViewHost(e->presentRoot, id) { + parseDocument(); } CgiApplicationEngine::PresentStage::PresentStage(const CgiEnvironment * e, const std::string & group, const std::string & id) : - CgiApplicationEngine::Stage(e), - XmlProcessPresenter(group, id, false) + CgiApplicationEngine::ResponseStage(e), + XmlScriptParser(group, id, false), + CheckHost(group, id), + ViewHost(group, id) { + parseDocument(); } -CgiApplicationEngine::StagePtr +CgiApplicationEngine::NextStage CgiApplicationEngine::PresentStage::run() { - BOOST_FOREACH(ParamCheckers::value_type pc, parameterChecks.get<bySOOrder>()) { - if (!pc->performCheck()) { - ApplicationEngine::getCurrent()->logMessage(false, pc->group(), pc->message()); - return new PresentStage(e, pc->present); - } - } - execute(); - return NULL; + runChecks(); + executeViews(boost::bind(&PresenterLoader::createFrom, LoaderBase::getLoader<PresenterLoader, NotSupported>(e->defaultPresenter), _1)); + return NextStage(NULL, this, boost::dynamic_pointer_cast<TransformSource>(headPresenter()), headPresenter()); +} + +CgiApplicationEngine::ResponseStage::ResponseStage(const CgiEnvironment * e) : + CgiApplicationEngine::Stage(e) +{ } CgiApplicationEngine::HttpHeaderPtr CgiApplicationEngine::PresentStage::getHeader() const { - Project2HttpHeader * header = new Project2HttpHeader("200 OK", contentType); + ContentPresenter * cp = boost::dynamic_pointer_cast<ContentPresenter>(headPresenter()).get(); + Project2HttpHeader * header = new Project2HttpHeader("200 OK", cp ? cp->contentType : "text/plain"); 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 index 22cb2e8..94f3b49 100644 --- a/project2/cgi/cgiStageRequest.cpp +++ b/project2/cgi/cgiStageRequest.cpp @@ -5,57 +5,32 @@ #include <boost/foreach.hpp> CgiApplicationEngine::RequestStage::RequestStage(const CgiEnvironment * e, const std::string & id) : - CgiApplicationEngine::Stage(e) + XmlScriptParser(e->requestRoot, id, false), + ::CheckHost(e->requestRoot, id), + CgiApplicationEngine::ResponseStage(e), + ::TaskHost(e->requestRoot, id) { - XmlScriptParser request(e->requestRoot, id, false); - xmlpp::Element * requestRoot = request.get_document()->get_root_node(); + xmlpp::Element * requestRoot = 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(true); - loader.supportedStorers.insert(Storer::into(¶meterChecks)); - loader.supportedStorers.insert(Storer::into(&rowSets)); - loader.supportedStorers.insert(new NOEErrorStorer(&normTasks, &errorTasks)); - loader.collectAll(this, requestRoot, true); + parseDocument(); } -CgiApplicationEngine::StagePtr +CgiApplicationEngine::NextStage CgiApplicationEngine::RequestStage::run() { - BOOST_FOREACH(const ParamCheckers::value_type & pc, parameterChecks.get<bySOOrder>()) { - if (!pc->performCheck()) { - ApplicationEngine::getCurrent()->logMessage(false, pc->group(), pc->message()); - return new PresentStage(e, pc->present); - } - } - RequestHost::run(); - return present.empty() ? NULL : new PresentStage(e, present); + runChecks(); + executeTasks(); + return NextStage(present.empty() ? NULL : new PresentStage(e, present), this); } +const std::string contentType = "text/plain"; 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; + Project2HttpHeader * header = new Project2HttpHeader("200 OK", contentType); + header->addHeader("Cache-control", "no-cache"); + return HttpHeaderPtr(header); } -const Glib::ustring & -CgiApplicationEngine::RequestStage::getResponseStyle() const -{ - return style; -} - diff --git a/project2/cgi/testCgi.cpp b/project2/cgi/testCgi.cpp new file mode 100644 index 0000000..438e1b0 --- /dev/null +++ b/project2/cgi/testCgi.cpp @@ -0,0 +1,70 @@ +#include <iostream> +#include <boost/program_options.hpp> +#include <boost/filesystem/convenience.hpp> +#include "cgiCommon.h" + +namespace po = boost::program_options; + +class TestInput : public cgicc::CgiInput { + public: + TestInput(int argc, char ** argv) + { + po::options_description test("Project2 CGI test options"); + test.add_options() + ("help,h", "Print usage and exit") + ("SERVER_NAME", "FQDN of web service") + ("SERVER_SOFTWARE", po::value<std::string>()->default_value("Apache"), "") + ("GATEWAY_INTERFACE", po::value<std::string>()->default_value("CGI/1.1"), "") + ("SERVER_PROTOCOL", po::value<std::string>()->default_value("HTTP/1.1"), "") + ("SERVER_PORT", po::value<std::string>()->default_value("80"), "") + ("REQUEST_METHOD", po::value<std::string>()->default_value("GET"), "") + ("PATH_INFO", "") + ("PATH_TRANSLATED", "") + ("SCRIPT_NAME", po::value<std::string>()->default_value("p2fcgi"), "") + ("QUERY_STRING", "") + ("REMOTE_HOST", "") + ("REMOTE_ADDR", "") + ("AUTH_TYPE", "") + ("REMOTE_USER", "") + ("REMOTE_IDENT", "") + ("CONTENT_TYPE", "") + ("CONTENT_LENGTH", "") + ("HTTP_ACCEPT", po::value<std::string>()->default_value("text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"), "") + ("HTTP_USER_AGENT", po::value<std::string>()->default_value("Mozilla/5.0"), "") + ("REDIRECT_REQUEST", "") + ("REDIRECT_URL", "") + ("REDIRECT_STATUS", "") + ("HTTP_REFERER", "") + ("HTTP_COOKIE", "") + ("HTTPS", po::value<std::string>()->default_value("No"), "") + ; + po::parsed_options parsed = po::command_line_parser(argc, argv).options(test).allow_unregistered().run(); + po::store(parsed, settings); + if (boost::filesystem::exists("testCgi.settings")) { + std::ifstream f("testCgi.settings"); + po::store(po::parse_config_file(f, test, true), settings); + } + po::notify(settings); + if (settings.count("help")) { + std::cout << test; + exit(1); + } + } + virtual std::string getenv(const char *varName) + { + if (settings.count(varName)) { + return settings[varName].as<std::string>(); + } + return ""; + } + private: + po::variables_map settings; +}; + +int +main(int argc, char ** argv) +{ + TestInput ti(argc, argv); + cgiServe(&ti, std::cout); +} + diff --git a/project2/checkHost.cpp b/project2/checkHost.cpp new file mode 100644 index 0000000..05e7d58 --- /dev/null +++ b/project2/checkHost.cpp @@ -0,0 +1,39 @@ +#include "checkHost.h" +#include "appEngine.h" +#include <boost/foreach.hpp> + +CheckHost::CheckHost(const std::string & group, const std::string & name) : + XmlScriptParser(group, name, false) +{ + loader.supportedStorers.insert(Storer::into(¶meterChecks)); +} + +CheckHost::CheckHost(const std::string & file) : + XmlScriptParser(file, false) +{ + loader.supportedStorers.insert(Storer::into(¶meterChecks)); +} + +CheckHost::~CheckHost() +{ +} + +void +CheckHost::runChecks() const +{ + BOOST_FOREACH(const ParamCheckers::value_type & pc, parameterChecks) { + if (!pc->performCheck()) { + ApplicationEngine::getCurrent()->logMessage(false, pc->group(), pc->message()); + throw CheckFailure(pc); + } + } +} + +CheckHost::CheckFailure::CheckFailure(ParamCheckerCPtr fc) : failedCheck(fc) +{ +} + +CheckHost::CheckFailure::~CheckFailure() throw() +{ +} + diff --git a/project2/checkHost.h b/project2/checkHost.h new file mode 100644 index 0000000..759c7a0 --- /dev/null +++ b/project2/checkHost.h @@ -0,0 +1,30 @@ +#ifndef CHECKHOST_H +#define CHECKHOST_H + +#include "xmlScriptParser.h" +#include "paramChecker.h" +#include "xmlStorage.h" +#include <set> +#include <boost/function.hpp> + +class CheckHost : public virtual XmlScriptParser { + public: + class CheckFailure : std::exception { + public: + CheckFailure(ParamCheckerCPtr); + ~CheckFailure() throw(); + const ParamCheckerCPtr failedCheck; + }; + CheckHost(const std::string & group, const std::string & file); + CheckHost(const std::string & file); + ~CheckHost(); + + void runChecks() const; + + typedef ANONORDEREDSTORAGEOF(ParamChecker) ParamCheckers; + ParamCheckers parameterChecks; +}; + +#endif + + diff --git a/project2/commonObjects.cpp b/project2/commonObjects.cpp index 039e105..1d0b13e 100644 --- a/project2/commonObjects.cpp +++ b/project2/commonObjects.cpp @@ -12,14 +12,14 @@ CommonObjects::~CommonObjects() RowSetPtr CommonObjects::getSource(const std::string & name) const { - RowSets::index<bySOName>::type::const_iterator i = rowSets.get<bySOName>().find(name); - if (i != rowSets.get<bySOName>().end()) { - return *i; + RowSets::const_iterator i = rowSets.find(name); + if (i != rowSets.end()) { + return i->second; } throw CommonObjects::DataSourceNotFound(name); } -CommonObjects::DataSources::index<bySOName>::type::const_iterator +CommonObjects::DataSources::const_iterator CommonObjects::loadDataSource(const std::string & name) const { XmlScriptParser xml(ApplicationEngine::getCurrent()->env()->getDatasourceRoot(), name, true); @@ -28,8 +28,8 @@ CommonObjects::loadDataSource(const std::string & name) const loader.supportedStorers.insert(Storer::into(&datasources)); loader.collectAll(xml.get_document()->get_root_node(), false); - DataSources::index<bySOName>::type::const_iterator i = datasources.get<bySOName>().find(name); - if (i == datasources.get<bySOName>().end()) { + DataSources::const_iterator i = datasources.find(name); + if (i == datasources.end()) { throw DataSourceNotFound(name); } return i; diff --git a/project2/commonObjects.h b/project2/commonObjects.h index dccdb20..dae563a 100644 --- a/project2/commonObjects.h +++ b/project2/commonObjects.h @@ -7,8 +7,8 @@ class CommonObjects : public virtual IntrusivePtrBase { public: - typedef Storage<RowSet>::Objects RowSets; - typedef Storage<DataSource>::Objects DataSources; + typedef STORAGEOF(RowSet) RowSets; + typedef STORAGEOF(DataSource) DataSources; SimpleMessageException(DataSourceNotFound); SimpleMessageException(DataSourceNotCompatible); @@ -19,11 +19,11 @@ class CommonObjects : public virtual IntrusivePtrBase { template <class DataSourceType> const DataSourceType * dataSource(const std::string & name) const { - Storage<DataSource>::Objects::index<bySOName>::type::const_iterator i = datasources.get<bySOName>().find(name); - if (i == datasources.get<bySOName>().end()) { + DataSources::const_iterator i = datasources.find(name); + if (i == datasources.end()) { i = loadDataSource(name); } - const DataSourceType * s = dynamic_cast<const DataSourceType *>(i->get()); + const DataSourceType * s = boost::dynamic_pointer_cast<const DataSourceType>(i->second).get(); if (!s) { throw DataSourceNotCompatible(name); } @@ -33,7 +33,7 @@ class CommonObjects : public virtual IntrusivePtrBase { RowSets rowSets; mutable DataSources datasources; private: - DataSources::index<bySOName>::type::const_iterator loadDataSource(const std::string & name) const; + DataSources::const_iterator loadDataSource(const std::string & name) const; }; #endif diff --git a/project2/console/consoleAppEngine.cpp b/project2/console/consoleAppEngine.cpp index 1c4f869..8e95b16 100644 --- a/project2/console/consoleAppEngine.cpp +++ b/project2/console/consoleAppEngine.cpp @@ -3,6 +3,8 @@ #include "../iterate.h" #include "../xmlObjectLoader.h" #include <boost/foreach.hpp> +#include <boost/bind.hpp> +#include <iostream> SimpleMessageException(UnknownPlatformAlias); @@ -52,23 +54,18 @@ class ConsoleSession : public Session { }; ConsoleApplicationEngine::ConsoleApplicationEngine(const ConsoleEnvironment * env, const boost::filesystem::path & f) : + XmlScriptParser(f.string(), false), + CheckHost(f.string()), ApplicationEngine("console/environment"), + TaskHost(f.string()), + ViewHost(f.string()), _env(env), - indent(0), - runtime(new ConsoleSession()), - out(stdout, true), - request(f.string(), false) + runtime(new ConsoleSession()) { - xmlpp::Element * requestRoot = request.get_document()->get_root_node(); + xmlpp::Element * requestRoot = get_document()->get_root_node(); rollbackBeforeHandle = requestRoot->get_attribute_value("rollbackBeforeHandle") == "true"; localErrorHandling = requestRoot->get_attribute_value("errorHandling") == "local"; - - LoaderBase loader(true); - loader.supportedStorers.insert(Storer::into(¶meterChecks)); - loader.supportedStorers.insert(new NOEErrorStorer(&normTasks, &errorTasks)); - loader.supportedStorers.insert(Storer::into(&rowSets)); - loader.supportedStorers.insert(Storer::into(&views)); - loader.collectAll(this, request.get_document()->get_root_node(), true); + parseDocument(); } ConsoleApplicationEngine::~ConsoleApplicationEngine() @@ -76,17 +73,18 @@ ConsoleApplicationEngine::~ConsoleApplicationEngine() } void +onCheckFailureHelper(boost::intrusive_ptr<const ParamChecker> pc) +{ + throw std::runtime_error(pc->message()); +} + +void ConsoleApplicationEngine::process() const { - BOOST_FOREACH(const ParamCheckers::value_type & pc, parameterChecks.get<bySOOrder>()) { - if (!pc->performCheck()) { - ApplicationEngine::getCurrent()->logMessage(false, pc->group(), pc->message()); - throw std::runtime_error("Check failed"); - } - } - RequestHost::run(); - Presenter::execute(); - addAppData(this); + runChecks(); + executeTasks(); + executeViews(boost::bind(&PresenterLoader::createFrom, LoaderBase::getLoader<PresenterLoader, NotSupported>("console"), _1)); + addAppData(headPresenter().get()); } const Environment * @@ -111,66 +109,6 @@ ConsoleApplicationEngine::addAppData(const Presenter *) const { } -void -ConsoleApplicationEngine::declareNamespace(const Glib::ustring &, const Glib::ustring &) const -{ -} -void -ConsoleApplicationEngine::setNamespace(const Glib::ustring &, const Glib::ustring &) const -{ -} - -void -ConsoleApplicationEngine::pushSub(const Glib::ustring & name, const Glib::ustring & ns) const -{ - fprintf(stdout, "%*s", indent, ""); - fprintf(stdout, ">>> "); - if (!ns.empty()) { - fprintf(stdout, "%s::", ns.c_str()); - } - fprintf(stdout, "%s\n", name.c_str()); - indent += 2; -} - -void -ConsoleApplicationEngine::addAttr(const Glib::ustring & name, const Glib::ustring & ns, const VariableType & value) const -{ - fprintf(stdout, "%*s", indent, ""); - if (!ns.empty()) { - fprintf(stdout, "%s::", ns.c_str()); - } - fprintf(stdout, "@%s = ", name.c_str()); - boost::apply_visitor(out, value); - fprintf(stdout, "\n"); -} - -void -ConsoleApplicationEngine::addField(const Glib::ustring & name, const Glib::ustring & ns, const VariableType & value) const -{ - fprintf(stdout, "%*s", indent, ""); - if (!ns.empty()) { - fprintf(stdout, "%s::", ns.c_str()); - } - fprintf(stdout, "%s = ", name.c_str()); - boost::apply_visitor(out, value); - fprintf(stdout, "\n"); -} - -void -ConsoleApplicationEngine::addText(const VariableType & value) const -{ - fprintf(stdout, "%*s<local> = ", indent, ""); - boost::apply_visitor(out, value); - fprintf(stdout, "\n"); -} - -void -ConsoleApplicationEngine::popSub() const -{ - indent -= 2; - fprintf(stdout, "%*s<<<\n", indent, ""); -} - Glib::ustring ConsoleApplicationEngine::resolveCurrentConfig() const { diff --git a/project2/console/consoleAppEngine.h b/project2/console/consoleAppEngine.h index b08dec3..3d54a18 100644 --- a/project2/console/consoleAppEngine.h +++ b/project2/console/consoleAppEngine.h @@ -7,16 +7,14 @@ #include "../presenter.h" #include "../commonObjects.h" #include "../view.h" -#include "../fileStrmVarWriter.h" -#include "../requestHost.h" +#include "../taskHost.h" +#include "../viewHost.h" #include <boost/intrusive_ptr.hpp> -#include <boost/filesystem/path.hpp> #include <libxml++/document.h> -#include "../xmlScriptParser.h" class ConsoleEnvironment; -class ConsoleApplicationEngine : public ApplicationEngine, public Presenter, RequestHost { +class ConsoleApplicationEngine : public ApplicationEngine, TaskHost, ViewHost { public: ConsoleApplicationEngine(const ConsoleEnvironment *, const boost::filesystem::path &); virtual ~ConsoleApplicationEngine(); @@ -36,24 +34,8 @@ class ConsoleApplicationEngine : public ApplicationEngine, public Presenter, Req mutable ConsolePlatforms conplat; void loadEngineSection(const xmlpp::Element *) const; - - // Presenter interface - public: - void declareNamespace(const Glib::ustring & prefix, const Glib::ustring & ns) const; - void setNamespace(const Glib::ustring & prefix, const Glib::ustring & ns) const; - void pushSub(const Glib::ustring & ns, const Glib::ustring & name) const; - void addAttr(const Glib::ustring & name, const Glib::ustring & ns, const VariableType & value) const; - void addField(const Glib::ustring & name, const Glib::ustring & ns, const VariableType & value) const; - void addText(const VariableType & value) const; - void popSub() const; private: - mutable unsigned int indent; - - typedef Storage<ParamChecker>::Objects ParamCheckers; - ParamCheckers parameterChecks; SessionPtr runtime; - FileStreamVariableWriter out; - XmlScriptParser request; }; #endif diff --git a/project2/console/consolePresenter.cpp b/project2/console/consolePresenter.cpp new file mode 100644 index 0000000..d122771 --- /dev/null +++ b/project2/console/consolePresenter.cpp @@ -0,0 +1,72 @@ +#include "consolePresenter.h" + +DECLARE_COMPONENT_LOADER("console", ConsolePresenter, PresenterLoader) + +ConsolePresenter::ConsolePresenter(const xmlpp::Element *) : + indent(0), + out(stdout, true) +{ +} + +void +ConsolePresenter::declareNamespace(const Glib::ustring &, const Glib::ustring &) const +{ +} + +void +ConsolePresenter::setNamespace(const Glib::ustring &, const Glib::ustring &) const +{ +} + +void +ConsolePresenter::pushSub(const Glib::ustring & name, const Glib::ustring & ns) const +{ + fprintf(stdout, "%*s", indent, ""); + fprintf(stdout, ">>> "); + if (!ns.empty()) { + fprintf(stdout, "%s::", ns.c_str()); + } + fprintf(stdout, "%s\n", name.c_str()); + indent += 2; +} + +void +ConsolePresenter::addAttr(const Glib::ustring & name, const Glib::ustring & ns, const VariableType & value) const +{ + fprintf(stdout, "%*s", indent, ""); + if (!ns.empty()) { + fprintf(stdout, "%s::", ns.c_str()); + } + fprintf(stdout, "@%s = ", name.c_str()); + boost::apply_visitor(out, value); + fprintf(stdout, "\n"); +} + +void +ConsolePresenter::addField(const Glib::ustring & name, const Glib::ustring & ns, const VariableType & value) const +{ + fprintf(stdout, "%*s", indent, ""); + if (!ns.empty()) { + fprintf(stdout, "%s::", ns.c_str()); + } + fprintf(stdout, "%s = ", name.c_str()); + boost::apply_visitor(out, value); + fprintf(stdout, "\n"); +} + +void +ConsolePresenter::addText(const VariableType & value) const +{ + fprintf(stdout, "%*s<local> = ", indent, ""); + boost::apply_visitor(out, value); + fprintf(stdout, "\n"); +} + +void +ConsolePresenter::popSub() const +{ + indent -= 2; + fprintf(stdout, "%*s<<<\n", indent, ""); +} + + diff --git a/project2/console/consolePresenter.h b/project2/console/consolePresenter.h new file mode 100644 index 0000000..98cce6d --- /dev/null +++ b/project2/console/consolePresenter.h @@ -0,0 +1,24 @@ +#ifndef CONSOLEPRESENTER_H +#define CONSOLEPRESENTER_H + +#include "../presenter.h" +#include "../fileStrmVarWriter.h" + +class ConsolePresenter : public Presenter { + public: + ConsolePresenter(const xmlpp::Element *); + void declareNamespace(const Glib::ustring & prefix, const Glib::ustring & ns) const; + void setNamespace(const Glib::ustring & prefix, const Glib::ustring & ns) const; + void pushSub(const Glib::ustring & ns, const Glib::ustring & name) const; + void addAttr(const Glib::ustring & name, const Glib::ustring & ns, const VariableType & value) const; + void addField(const Glib::ustring & name, const Glib::ustring & ns, const VariableType & value) const; + void addText(const VariableType & value) const; + void popSub() const; + void write(const boost::function1<std::ostream *, const std::string &> &) const; + private: + mutable unsigned int indent; + FileStreamVariableWriter out; +}; + +#endif + diff --git a/project2/environment.cpp b/project2/environment.cpp index a3a3d5e..69cdde7 100644 --- a/project2/environment.cpp +++ b/project2/environment.cpp @@ -6,6 +6,7 @@ namespace po = boost::program_options; +const Environment * Environment::currentEnv(NULL); int Environment::clLevel(-1); int Environment::slLevel(-1); bool Environment::optionsBuilt(false); @@ -16,6 +17,7 @@ Environment::Environment(int c, char ** v) : argc(c), argv(v) { + currentEnv = this; } void @@ -61,6 +63,7 @@ Environment::init() Environment::~Environment() { + currentEnv = NULL; Logger()->clear(); } @@ -82,3 +85,9 @@ Environment::getXmlPrefix() const return xmlPrefix; } +const Environment * +Environment::getCurrent() +{ + return currentEnv; +} + diff --git a/project2/environment.h b/project2/environment.h index 5c66518..e515741 100644 --- a/project2/environment.h +++ b/project2/environment.h @@ -13,6 +13,8 @@ class Environment { void init(); + static const Environment * getCurrent(); + const std::string & getDatasourceRoot() const; const Glib::ustring & getXmlNamespace() const; const Glib::ustring & getXmlPrefix() const; @@ -23,6 +25,8 @@ class Environment { virtual std::string getServerName() const = 0; virtual std::string getScriptName() const = 0; private: + static const Environment * currentEnv; + virtual boost::program_options::options_description addOptions(boost::program_options::positional_options_description &) = 0; virtual void postinit(const boost::program_options::options_description &, const boost::program_options::variables_map &) = 0; int argc; diff --git a/project2/if.cpp b/project2/if.cpp index 5fa7a8c..ed36bad 100644 --- a/project2/if.cpp +++ b/project2/if.cpp @@ -2,6 +2,7 @@ #include "logger.h" #include "xmlObjectLoader.h" #include <boost/foreach.hpp> +#include <boost/bind.hpp> #include <algorithm> DECLARE_LOADER("if", If); @@ -19,22 +20,22 @@ IfSet::IfSet(const xmlpp::Element * e) : template <class Range, class Pred> bool all(const Range & c, const Pred & p) { - return (std::find_if(c.begin(), c.end(), !p) == c.end()); + return (std::find_if(c.begin(), c.end(), !p) == c.end()); } template <class Range, class Pred> bool any(const Range & c, const Pred & p) { - return (std::find_if(c.begin(), c.end(), p) != c.end()); + return (std::find_if(c.begin(), c.end(), p) != c.end()); } bool IfSet::passes() const { if (mode == And) { - return all(checks.get<bySOOrder>(), boost::bind(&ParamChecker::performCheck, _1)); + return all(checks, boost::bind(&ParamChecker::performCheck, _1)); } else if (mode == Or) { - return any(checks.get<bySOOrder>(), boost::bind(&ParamChecker::performCheck, _1)); + return any(checks, boost::bind(&ParamChecker::performCheck, _1)); } throw IfModeIsNonsense(getName()); } @@ -74,12 +75,12 @@ If::execute() const if (passes()) { Logger()->message(LOG_DEBUG, "IfSet passed"); try { - BOOST_FOREACH(const SubNOEs::value_type & sq, normNOEs.get<bySOOrder>()) { + BOOST_FOREACH(const SubNOEs::value_type & sq, normNOEs) { sq->execute(); } } catch (...) { - BOOST_FOREACH(const SubNOEs::value_type & sq, errorNOEs.get<bySOOrder>()) { + BOOST_FOREACH(const SubNOEs::value_type & sq, errorNOEs) { sq->execute(); } if (!localErrorHandling) { diff --git a/project2/if.h b/project2/if.h index 6482d7c..9c9acd8 100644 --- a/project2/if.h +++ b/project2/if.h @@ -14,7 +14,7 @@ class IfSet : public virtual IntrusivePtrBase { virtual const std::string & getName() const = 0; enum Mode { And, Or }; Mode mode; - typedef Storage<ParamChecker>::Objects ParamCheckers; + typedef ANONORDEREDSTORAGEOF(ParamChecker) ParamCheckers; ParamCheckers checks; }; @@ -30,9 +30,9 @@ class If : public NoOutputExecute, public View, public IfSet { const bool localErrorHandling; private: - typedef Storage<View>::Objects SubViews; + typedef ANONSTORAGEOF(View) SubViews; SubViews subViews; - typedef Storage<NoOutputExecute>::Objects SubNOEs; + typedef ANONORDEREDSTORAGEOF(NoOutputExecute) SubNOEs; SubNOEs normNOEs; SubNOEs errorNOEs; diff --git a/project2/iterate.cpp b/project2/iterate.cpp index e7af8f1..55648eb 100644 --- a/project2/iterate.cpp +++ b/project2/iterate.cpp @@ -55,7 +55,7 @@ Iterate::execute() const void Iterate::executeChildren(bool errs) const { - BOOST_FOREACH(const SubNOEs::value_type & sq, (errs ? errorNOEs : normNOEs).get<bySOOrder>()) { + BOOST_FOREACH(const SubNOEs::value_type & sq, (errs ? errorNOEs : normNOEs)) { if (dynamic_cast<const RowProcessor *>(sq.get())) { sq->execute(); } diff --git a/project2/iterate.h b/project2/iterate.h index e4cd3fe..a60a0a4 100644 --- a/project2/iterate.h +++ b/project2/iterate.h @@ -19,7 +19,7 @@ class Iterate : public NoOutputExecute, public RowProcessor { void rowReady() const; void execute() const; - typedef Storage<NoOutputExecute>::Objects SubNOEs; + typedef ANONORDEREDSTORAGEOF(NoOutputExecute) SubNOEs; SubNOEs normNOEs; SubNOEs errorNOEs; diff --git a/project2/library.cpp b/project2/library.cpp index 1941254..b1e0b9b 100644 --- a/project2/library.cpp +++ b/project2/library.cpp @@ -27,7 +27,7 @@ Library::loadComplete(const CommonObjects*) { } -Storage<Library>::Objects libraries; +STORAGEOF(Library) libraries; class LibraryLoader : public ElementLoaderImpl<Library> { public: void onIteration() diff --git a/project2/library.h b/project2/library.h index 4dfdadd..af8e73f 100644 --- a/project2/library.h +++ b/project2/library.h @@ -11,7 +11,7 @@ class Library : public SourceObject { private: void * handle; }; -extern Storage<Library>::Objects libraries; +extern STORAGEOF(Library) libraries; #endif diff --git a/project2/noOutputExecute.cpp b/project2/noOutputExecute.cpp index 6f599c4..cb12439 100644 --- a/project2/noOutputExecute.cpp +++ b/project2/noOutputExecute.cpp @@ -15,7 +15,8 @@ NOEErrorStorer::NOEErrorStorer(Map m, Map em) : { } -NOEErrorStorer::Map -NOEErrorStorer::getMap(const xmlpp::Element * p) const { - return ((p->get_attribute_value("onerror") == "true") ? errorMap : map); +bool +NOEErrorStorer::insert(const xmlpp::Element * p, NoOutputExecutePtr O) { + ((p->get_attribute_value("onerror") == "true") ? errorMap : map)->push_back(O); + return true; } diff --git a/project2/noOutputExecute.h b/project2/noOutputExecute.h index fe1c638..78245f2 100644 --- a/project2/noOutputExecute.h +++ b/project2/noOutputExecute.h @@ -17,10 +17,10 @@ class NoOutputExecute : public virtual SourceObject { virtual void execute() const = 0; }; -class NOEErrorStorer : public StorerBase<NoOutputExecute> { +class NOEErrorStorer : public StorerBase<NoOutputExecute, ANONORDEREDSTORAGEOF(NoOutputExecute) > { public: NOEErrorStorer(Map m, Map em); - Map getMap(const xmlpp::Element *) const; + bool insert(const xmlpp::Element *, NoOutputExecutePtr); Map map, errorMap; }; diff --git a/project2/ostreamWrapper.h b/project2/ostreamWrapper.h new file mode 100644 index 0000000..ef8596c --- /dev/null +++ b/project2/ostreamWrapper.h @@ -0,0 +1,14 @@ +#ifndef OSTREAMWRAPPER_H +#define OSTREAMWRAPPER_H + +#include <ostream> +#include "transform.h" + +class ostreamWrapper : public TransformChainLink { + public: + ostreamWrapper(std::ostream & s) : strm(s) { } + std::ostream & strm; +}; + +#endif + diff --git a/project2/paramChecker.h b/project2/paramChecker.h index 57addbc..d013fc4 100644 --- a/project2/paramChecker.h +++ b/project2/paramChecker.h @@ -17,6 +17,7 @@ class ParamChecker : public SourceObject { const Variable group; const std::string present; }; +typedef boost::intrusive_ptr<const ParamChecker> ParamCheckerCPtr; #endif diff --git a/project2/presenter.cpp b/project2/presenter.cpp index 005fa2b..9544743 100644 --- a/project2/presenter.cpp +++ b/project2/presenter.cpp @@ -12,17 +12,6 @@ Presenter::~Presenter() } void -Presenter::execute() const -{ - BOOST_FOREACH(const Storage<View>::Objects::value_type & s, views) { - s->execute(this); - } - // These were for debug... but why not pass them on? - ApplicationEngine * appEngine = ApplicationEngine::getCurrent(); - appEngine->addEnvData(this); -} - -void Presenter::pushSub(const Glib::ustring & name) const { pushSub(name, Glib::ustring()); @@ -54,3 +43,8 @@ Presenter::addField(const Glib::ustring & name, const Glib::ustring & ns, const popSub(); } +ContentPresenter::ContentPresenter(const Glib::ustring & ct) : + contentType(ct) +{ +} + diff --git a/project2/presenter.h b/project2/presenter.h index bbfaf82..a4c0a00 100644 --- a/project2/presenter.h +++ b/project2/presenter.h @@ -3,12 +3,13 @@ #include <boost/intrusive_ptr.hpp> #include <boost/shared_ptr.hpp> +#include <boost/function.hpp> #include <glibmm/ustring.h> #include "view.h" #include "paramChecker.h" -#include "commonObjects.h" +#include "xmlObjectLoader.h" -class Presenter : public virtual CommonObjects, public virtual IntrusivePtrBase { +class Presenter : public virtual IntrusivePtrBase { public: Presenter(); virtual ~Presenter() = 0; @@ -23,15 +24,32 @@ class Presenter : public virtual CommonObjects, public virtual IntrusivePtrBase virtual void addField(const Glib::ustring & name, const Glib::ustring & ns, const VariableType & value) const; virtual void addText(const VariableType & value) const = 0; virtual void popSub() const = 0; - void execute() const; +}; - protected: - typedef Storage<View>::Objects Views; - Views views; +class ContentPresenter : public Presenter { + public: + ContentPresenter(const Glib::ustring & contentType); + const Glib::ustring contentType; }; typedef boost::intrusive_ptr<const Presenter> PresenterCPtr; typedef boost::intrusive_ptr<Presenter> PresenterPtr; +/// Base class to implement presenter modules +class PresenterLoader : public ComponentLoader { + public: + virtual PresenterPtr createFrom(const xmlpp::Element * e) const = 0; +}; + +/// Helper implemention for specific presenters +template <class PresenterType> +class PresenterLoaderImpl : public PresenterLoader { + public: + virtual PresenterPtr createFrom(const xmlpp::Element * e) const + { + return new PresenterType(e); + } +}; + #endif diff --git a/project2/requestHost.cpp b/project2/requestHost.cpp deleted file mode 100644 index 7cb3d9c..0000000 --- a/project2/requestHost.cpp +++ /dev/null @@ -1,61 +0,0 @@ -#include "requestHost.h" -#include "noOutputExecute.h" -#include "dataSource.h" -#include <boost/foreach.hpp> - -RequestHost::RequestHost() -{ -} - -RequestHost::~RequestHost() -{ -} - -void -RequestHost::run() const -{ - try { - run(false); - commitAll(); - } - catch (...) { - if (rollbackBeforeHandle) { - rollbackAll(); - } - try { - run(true); - commitAll(); - } - catch (...) { - rollbackAll(); - } - if (!localErrorHandling) { - throw; - } - } -} - -void -RequestHost::run(bool errs) const -{ - BOOST_FOREACH(const Tasks::value_type & t, (errs ? errorTasks : normTasks).get<bySOOrder>()) { - t->execute(); - } -} - -void -RequestHost::commitAll() const -{ - BOOST_FOREACH(const DataSources::value_type & ds, datasources) { - ds->commit(); - } -} - -void -RequestHost::rollbackAll() const -{ - BOOST_FOREACH(const DataSources::value_type & ds, datasources) { - ds->rollback(); - } -} - diff --git a/project2/requestHost.h b/project2/requestHost.h deleted file mode 100644 index bf0e9f0..0000000 --- a/project2/requestHost.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef REQUEST_HOST_H -#define REQUEST_HOST_H - -#include "xmlStorage.h" -#include "commonObjects.h" - -class NoOutputExecute; -class DataSource; - -class RequestHost : virtual CommonObjects { - protected: - typedef Storage<NoOutputExecute>::Objects Tasks; - typedef Storage<DataSource>::Objects DataSources; - - RequestHost(); - virtual ~RequestHost() = 0; - - void run() const; - - Tasks normTasks; - Tasks errorTasks; - bool rollbackBeforeHandle; - bool localErrorHandling; - - private: - void commitAll() const; - void rollbackAll() const; - void run(bool errs) const; -}; - -#endif - diff --git a/project2/rowView.h b/project2/rowView.h index 7cc6fe1..3652e37 100644 --- a/project2/rowView.h +++ b/project2/rowView.h @@ -24,7 +24,7 @@ class RowView : public View, public RowProcessor { Columns viewColumns; void executeChildren() const; - typedef Storage<View>::Objects SubViews; + typedef ANONSTORAGEOF(View) SubViews; SubViews subViews; mutable const Presenter * presenter; }; diff --git a/project2/sendmailTask.cpp b/project2/sendmailTask.cpp index e891fea..ba2f3b0 100644 --- a/project2/sendmailTask.cpp +++ b/project2/sendmailTask.cpp @@ -1,14 +1,14 @@ #include "sendmailTask.h" +#include "logger.h" #include <boost/foreach.hpp> +#include <boost/bind.hpp> #include "xmlObjectLoader.h" -#include "xmlPresenter.h" -#include <libxslt/transform.h> -#include <misc.h> +#include "viewHost.h" #include <stdexcept> #include <libesmtp.h> -#include <libxslt/xsltutils.h> -#include <libxml/HTMLtree.h> -#include <sys/wait.h> +#include "xmlPresenter.h" +#include "transformHtml.h" +#include "transformText.h" DECLARE_LOADER("sendmail", SendMailTask); @@ -56,6 +56,7 @@ class BoundaryBegin : public SendMailTask::MailPart { private: const std::string contentType; }; + class BoundaryEnd : public SendMailTask::MailPart { public: const char * write(char **, int * len) { @@ -63,6 +64,7 @@ class BoundaryEnd : public SendMailTask::MailPart { return "\r\n--<<divider>>--\r\n"; } }; + class Header : public SendMailTask::MailPart { public: Header(const std::string & h, const VariableType & v) : @@ -82,90 +84,89 @@ class Header : public SendMailTask::MailPart { const std::string header; const VariableType value; }; -class HtmlContent : public SendMailTask::MailPart { + +class MimeContent : public SendMailTask::MailPart { public: - HtmlContent(XmlDocumentPtr d) : doc(d) { + MimeContent(const char * s, int l) : str(s), length(l) { } const char * write(char ** buf, int * len) { - xmlDocDumpFormatMemoryEnc(doc.get(), (xmlChar**)buf, len, "utf-8", 0); - return *buf; + *buf = NULL; + *len = length; + return str; } private: - const XmlDocumentPtr doc; + const char * str; + const int length; }; -class TextContent : public SendMailTask::MailPart { + +class TransformHtmlToEmail : public TransformImpl<HtmlDocument, SendMailTask::Parts> { public: - TextContent(XmlDocumentPtr d) : doc(d) { + TransformHtmlToEmail() : buf(NULL) + { } - const char * write(char ** buf, int * pos) { - int fds[2]; - const char * callLynx[] = { -#ifdef STRACE_LYNX - "/usr/bin/strace", "-o", "/tmp/lynx", -#endif - "/usr/bin/lynx", "-dump", "-stdin", "-width=105", NULL }; - popenrw(callLynx, fds); - FILE * lynxIn = fdopen(fds[0], "w"); - FILE * lynxOut = fdopen(fds[1], "r"); - htmlNodeDumpFile(lynxIn, doc.get(), xmlDocGetRootElement(doc.get())); - fclose(lynxIn); - close(fds[0]); - int len = 0; - *pos = 0; - for (int ch ; ((ch = fgetc(lynxOut)) >= 0); ) { - if (*pos >= len) { - len += BUFSIZ; - *buf = (char*)realloc(*buf, len); - } - (*buf)[(*pos)++] = ch; + ~TransformHtmlToEmail() + { + if (buf) { + xmlFree(buf); } - fclose(lynxOut); - close(fds[1]); - int status; - wait(&status); - if (status != 0) { - throw std::runtime_error("Lynx failed"); + } + void transform(const HtmlDocument * cdoc, SendMailTask::Parts * parts) const + { + if (buf) { + xmlFree(buf); + buf = NULL; } - return *buf; + xmlDoc * doc = const_cast<xmlDoc *>(cdoc->doc); + int len = 0; + xmlDocDumpFormatMemoryEnc(doc, &buf, &len, "utf-8", 1); + parts->parts.push_back(new BoundaryBegin("text/html; utf-8")); + parts->parts.push_back(new MimeContent(reinterpret_cast<const char *>(buf), len)); } private: - const XmlDocumentPtr doc; + mutable xmlChar * buf; +}; +DECLARE_TRANSFORM(TransformHtmlToEmail) + +class TransformTextToEmail : public TransformImpl<TextDocument, SendMailTask::Parts> { + public: + void transform(const TextDocument * str, SendMailTask::Parts * parts) const + { + parts->parts.push_back(new BoundaryBegin("text/plain; utf-8")); + parts->parts.push_back(new MimeContent(str->doc.c_str(), str->doc.length())); + } }; +DECLARE_TRANSFORM(TransformTextToEmail) + +PresenterPtr +SendMailTask::createDefaultPresenter(const xmlpp::Element * n) const +{ + Logger()->message(LOG_DEBUG, "Building default email transform chain"); + XmlPresenterPtr xpp = new XmlPresenter(n); + HtmlDocument * hd = new HtmlDocument(); + TextDocument * td = new TextDocument(); + xpp->addTarget(hd, n); + hd->addTarget(parts); + hd->addTarget(td, n); + td->addTarget(parts); + return xpp; +} void SendMailTask::execute() const { - XmlPresenterPtr p = new XmlProcessPresenter("emails", present, true); - p->execute(); - XmlPresenter::XmlDocumentPtr data = p->getDataDocument(); -#if DEBUG - data->write_to_file("/tmp/email.xml"); -#endif - typedef boost::shared_ptr<xsltStylesheet> XsltStyleSheetPtr; - - // Do transform - XsltStyleSheetPtr cur = XsltStyleSheetPtr(xsltParseStylesheetFile(BAD_CAST p->getResponseStyle().c_str()), xsltFreeStylesheet); - if (!cur) { - throw xmlpp::exception("Failed to load stylesheet"); - } - XmlDocumentPtr result = XmlDocumentPtr(xsltApplyStylesheet(cur.get(), data->cobj(), NULL), xmlFreeDoc); - if (!result) { - throw xmlpp::exception("Failed to perform transformation"); - } + parts = new Parts(); + parts->parts.push_back(new Header("To", to)); + parts->parts.push_back(new Header("From", from)); + parts->parts.push_back(new Header("Subject", subject)); + parts->parts.push_back(new Header("Content-Type", "multipart/alternative; boundary=\"<<divider>>\"")); + parts->parts.push_back(new Header("MIME-Version", "1.0")); + parts->parts.push_back(new Header("Content-Transfer-Encoding", "binary")); - parts.clear(); - parts.push_back(new Header("To", to)); - parts.push_back(new Header("From", from)); - parts.push_back(new Header("Subject", subject)); - parts.push_back(new Header("Content-Type", "multipart/alternative; boundary=\"<<divider>>\"")); - parts.push_back(new Header("MIME-Version", "1.0")); - parts.push_back(new Header("Content-Transfer-Encoding", "binary")); - parts.push_back(new BoundaryBegin("text/plain; utf-8")); - parts.push_back(new TextContent(result)); - parts.push_back(new BoundaryBegin("text/html; utf-8")); - parts.push_back(new HtmlContent(result)); - parts.push_back(new BoundaryEnd()); - part = parts.begin(); + ViewHostPtr vsp = new ViewHost("emails", present); + vsp->executeViews(boost::bind(&SendMailTask::createDefaultPresenter, this, _1)); + vsp->doTransforms(); + parts->parts.push_back(new BoundaryEnd()); + part = parts->parts.begin(); // Write email smtp_session_t session = smtp_create_session(); @@ -173,18 +174,19 @@ SendMailTask::execute() const smtp_set_server(session, server()); smtp_set_header(message, "To", NULL, NULL); smtp_add_recipient(message, to()); - smtp_set_messagecb(message, writeMailWrapper, (SendMailTask*)this); + smtp_set_messagecb(message, writeMailWrapper, (SendMailTask*)this); if (!smtp_start_session(session)) { char buf[BUFSIZ]; smtp_strerror(smtp_errno(), buf, sizeof buf); throw SendEmailFailed(buf); } + parts->parts.clear(); } const char * SendMailTask::writeMail(void ** buf, int * len) const { - if (len == NULL || part == parts.end()) { + if (len == NULL || part == parts->parts.end()) { return NULL; } return (*part++)->write((char**)buf, len); diff --git a/project2/sendmailTask.h b/project2/sendmailTask.h index 2f3e088..e57a309 100644 --- a/project2/sendmailTask.h +++ b/project2/sendmailTask.h @@ -5,7 +5,9 @@ #include <boost/intrusive_ptr.hpp> #include <map> #include "task.h" +#include "transform.h" #include "variables.h" +#include "presenter.h" /// Project2 component to send an email class SendMailTask : public Task { @@ -14,6 +16,12 @@ class SendMailTask : public Task { public: virtual const char * write(char ** buf, int * len) = 0; }; + typedef boost::intrusive_ptr<MailPart> MailPartPtr; + typedef std::list<MailPartPtr> PartList; + class Parts : public TransformChainLink { + public: + PartList parts; + }; SendMailTask(const xmlpp::Element * p); virtual ~SendMailTask(); @@ -30,11 +38,10 @@ class SendMailTask : public Task { private: static const char * writeMailWrapper(void ** buf, int * len, void * arg); const char * writeMail(void ** buf, int * len) const; + PresenterPtr createDefaultPresenter(const xmlpp::Element * n) const; - typedef boost::intrusive_ptr<MailPart> MailPartPtr; - typedef std::list<MailPartPtr> Parts; - mutable Parts parts; - mutable Parts::iterator part; + mutable boost::intrusive_ptr<Parts> parts; + mutable PartList::iterator part; }; #endif diff --git a/project2/sqlMergeTask.cpp b/project2/sqlMergeTask.cpp index a4c8611..0a9e07d 100644 --- a/project2/sqlMergeTask.cpp +++ b/project2/sqlMergeTask.cpp @@ -288,10 +288,10 @@ attach(IteratePtr i, ModifyCommand * insert) return; } if (i->normNOEs.empty()) { - i->normNOEs.insert(new Populate(insert)); + i->normNOEs.push_back(new Populate(insert)); } else { - BOOST_FOREACH(const Iterate::SubNOEs::value_type & n, i->normNOEs.get<bySOOrder>()) { + BOOST_FOREACH(const Iterate::SubNOEs::value_type & n, i->normNOEs) { attach(boost::dynamic_pointer_cast<Iterate>(n), insert); attach(boost::dynamic_pointer_cast<SqlMergeInsert>(n), insert); } diff --git a/project2/sqlMergeTask.h b/project2/sqlMergeTask.h index 795e94f..fc72a93 100644 --- a/project2/sqlMergeTask.h +++ b/project2/sqlMergeTask.h @@ -58,7 +58,7 @@ class SqlMergeTask : public Task { void createTempKey() const; mutable bool tempTableCreated; - typedef Storage<Iterate>::Objects Sources; + typedef ANONSTORAGEOF(Iterate) Sources; Sources sources; std::list<std::string> sqls; protected: diff --git a/project2/sqlTask.cpp b/project2/sqlTask.cpp index 0b58423..61bff46 100644 --- a/project2/sqlTask.cpp +++ b/project2/sqlTask.cpp @@ -9,19 +9,20 @@ DECLARE_LOADER("sqltask", SqlTask); StaticMessageException(RunOnNotSpecified, "runon attribute must be specified"); -class SqlIfChangesStorer : public StorerBase<NoOutputExecute> { +class SqlIfChangesStorer : public StorerBase<NoOutputExecute, ANONORDEREDSTORAGEOF(NoOutputExecute)> { public: SqlIfChangesStorer(Map c, Map nc) : changes(c), noChanges(nc) { } - Map getMap(const xmlpp::Element * p) const { + bool insert(const xmlpp::Element * p, NoOutputExecutePtr O) { xmlpp::Attribute * runon = p->get_attribute("runon"); if (!runon) { throw RunOnNotSpecified(); } - return ((runon->get_value() == "changes") ? changes : noChanges); + ((runon->get_value() == "changes") ? changes : noChanges)->push_back(O); + return true; } Map changes, noChanges; }; @@ -58,12 +59,12 @@ SqlTask::execute() const atoi(p.second->name.c_str())), p.second->value); } if (modify->execute() == 0) { - BOOST_FOREACH(const SubNOEs::value_type & sq, noChangesNOEs.get<bySOOrder>()) { + BOOST_FOREACH(const SubNOEs::value_type & sq, noChangesNOEs) { sq->execute(); } } else { - BOOST_FOREACH(const SubNOEs::value_type & sq, changesNOEs.get<bySOOrder>()) { + BOOST_FOREACH(const SubNOEs::value_type & sq, changesNOEs) { sq->execute(); } } diff --git a/project2/sqlTask.h b/project2/sqlTask.h index 83f4062..3815a90 100644 --- a/project2/sqlTask.h +++ b/project2/sqlTask.h @@ -20,7 +20,7 @@ class SqlTask : public Task, IHaveParameters { const Variable dataSource; const std::string sql; - typedef Storage<NoOutputExecute>::Objects SubNOEs; + typedef ANONORDEREDSTORAGEOF(NoOutputExecute) SubNOEs; SubNOEs changesNOEs; SubNOEs noChangesNOEs; diff --git a/project2/taskHost.cpp b/project2/taskHost.cpp new file mode 100644 index 0000000..2955dc0 --- /dev/null +++ b/project2/taskHost.cpp @@ -0,0 +1,76 @@ +#include "taskHost.h" +#include "noOutputExecute.h" +#include "dataSource.h" +#include <boost/foreach.hpp> + +TaskHost::TaskHost(const std::string & group, const std::string & name) : + XmlScriptParser(group, name, false), + CheckHost(group, name) +{ + loader.supportedStorers.insert(new NOEErrorStorer(&normTasks, &errorTasks)); +} + +TaskHost::TaskHost(const std::string & file) : + XmlScriptParser(file, false), + CheckHost(file) +{ + loader.supportedStorers.insert(new NOEErrorStorer(&normTasks, &errorTasks)); +} + +TaskHost::~TaskHost() +{ +} + +void +TaskHost::executeTasks() const +{ + try { + run(normTasks); + commitAll(); + } + catch (...) { + if (!errorTasks.empty()) { + if (rollbackBeforeHandle) { + rollbackAll(); + } + try { + run(errorTasks); + commitAll(); + } + catch (...) { + rollbackAll(); + } + } + else { + rollbackAll(); + } + if (!localErrorHandling) { + throw; + } + } +} + +void +TaskHost::run(const Tasks & tlist) const +{ + BOOST_FOREACH(const Tasks::value_type & t, tlist) { + t->execute(); + } +} + +void +TaskHost::commitAll() const +{ + BOOST_FOREACH(const DataSources::value_type & ds, datasources) { + ds.second->commit(); + } +} + +void +TaskHost::rollbackAll() const +{ + BOOST_FOREACH(const DataSources::value_type & ds, datasources) { + ds.second->rollback(); + } +} + diff --git a/project2/taskHost.h b/project2/taskHost.h new file mode 100644 index 0000000..812760c --- /dev/null +++ b/project2/taskHost.h @@ -0,0 +1,33 @@ +#ifndef TASKHOST_H +#define TASKHOST_H + +#include "xmlStorage.h" +#include "xmlScriptParser.h" +#include "checkHost.h" + +class NoOutputExecute; +class DataSource; + +class TaskHost : virtual public XmlScriptParser, virtual public CheckHost { + protected: + typedef ANONORDEREDSTORAGEOF(NoOutputExecute) Tasks; + + TaskHost(const std::string & group, const std::string & name); + TaskHost(const std::string & file); + virtual ~TaskHost(); + + void executeTasks() const; + + Tasks normTasks; + Tasks errorTasks; + bool rollbackBeforeHandle; + bool localErrorHandling; + + private: + void commitAll() const; + void rollbackAll() const; + void run(const Tasks &) const; +}; + +#endif + diff --git a/project2/transform.cpp b/project2/transform.cpp new file mode 100644 index 0000000..37524a0 --- /dev/null +++ b/project2/transform.cpp @@ -0,0 +1,37 @@ +#include "transform.h" +#include "logger.h" +#include <boost/foreach.hpp> + +TransformChainLink::~TransformChainLink() +{ +} + +typedef std::map<std::string, boost::shared_ptr<TransformLoader> > TransformLoaderMap; +void +TransformSource::addTarget(TransformChainLinkPtr tcl, const xmlpp::Element * e) +{ + BOOST_FOREACH(const TransformLoaderMap::value_type & tl, *LoaderBase::objLoaders<TransformLoader>()) { + TransformPtr t = tl.second->create(); + if (t->canTransform(this, tcl.get())) { + if (e) { + t->configure(e); + } + targets[tcl] = t; + return; + } + } + throw NotSupported("Couldn't find a suitable transformation"); +} + +typedef std::map<TransformChainLinkPtr, TransformPtr> Targets; +void +TransformSource::doTransforms() const +{ + BOOST_FOREACH(const Targets::value_type & t, targets) { + t.second->transform(this, t.first.get()); + if (const TransformSource * tr = dynamic_cast<const TransformSource *>(t.first.get())) { + tr->doTransforms(); + } + } +} + diff --git a/project2/transform.h b/project2/transform.h new file mode 100644 index 0000000..ded356b --- /dev/null +++ b/project2/transform.h @@ -0,0 +1,70 @@ +#ifndef TRANSFORM_H +#define TRANSFORM_H + +#include <boost/intrusive_ptr.hpp> +#include "intrusivePtrBase.h" +#include "xmlObjectLoader.h" +#include <map> + +class TransformChainLink : public virtual IntrusivePtrBase { + public: + virtual ~TransformChainLink() = 0; +}; +typedef boost::intrusive_ptr<TransformChainLink> TransformChainLinkPtr; + +class Transform; +typedef boost::intrusive_ptr<Transform> TransformPtr; + +class TransformSource : public TransformChainLink { + public: + void addTarget(TransformChainLinkPtr, const xmlpp::Element * e = NULL); + void doTransforms() const; + private: + virtual const TransformChainLink * object() const { return this; } + std::map<TransformChainLinkPtr, TransformPtr> targets; +}; +typedef boost::intrusive_ptr<TransformSource> TransformSourcePtr; + +template <class X> +class SourceOf : public virtual TransformSource { + public: + virtual operator const X * () const = 0; +}; + +class Transform : public virtual IntrusivePtrBase { + public: + virtual void transform(const TransformSource * src, TransformChainLink * dest) const = 0; + virtual bool canTransform(const TransformSource * src, TransformChainLink * dest) const = 0; + virtual void configure(const xmlpp::Element *) { }; +}; + +class TransformLoader : public ComponentLoader { + public: + virtual boost::intrusive_ptr<Transform> create() const = 0; +}; + +template <class T> +class TransformLoaderImpl : public TransformLoader { + public: + boost::intrusive_ptr<Transform> create() const { + return new T(); + } +}; +#define DECLARE_TRANSFORM(T) DECLARE_COMPONENT_LOADER(#T, T, TransformLoader) + +template <class Source, class Destination> +class TransformImpl : public Transform { + public: + virtual void transform(const Source *, Destination *) const = 0; + void transform(const TransformSource * src, TransformChainLink * dest) const + { + transform(dynamic_cast<const SourceOf<Source> *>(src)->operator const Source *(), dynamic_cast<Destination *>(dest)); + } + bool canTransform(const TransformSource * src, TransformChainLink * dest) const + { + return (dynamic_cast<const SourceOf<Source> *>(src) && dynamic_cast<Destination *>(dest)); + } +}; + +#endif + diff --git a/project2/transformHtml.cpp b/project2/transformHtml.cpp new file mode 100644 index 0000000..eae1c27 --- /dev/null +++ b/project2/transformHtml.cpp @@ -0,0 +1,30 @@ +#include "transformHtml.h" +#include "logger.h" +#include <libxml++/document.h> +#include <libxslt/xsltutils.h> +#include <libxslt/transform.h> + +class TransformXmlToHtml : public TransformImpl<xmlpp::Document, HtmlDocument> { + public: + void transform(const xmlpp::Document * cdata, HtmlDocument * result) const + { + xmlpp::Document * data = const_cast<xmlpp::Document *>(cdata); + typedef boost::shared_ptr<xsltStylesheet> XsltStyleSheetPtr; + XsltStyleSheetPtr cur = XsltStyleSheetPtr(xsltParseStylesheetFile(BAD_CAST stylesheet.c_str()), xsltFreeStylesheet); + if (!cur) { + throw xmlpp::exception("Failed to load stylesheet"); + } + result->doc = xsltApplyStylesheet(cur.get(), data->cobj(), NULL); + if (!result) { + throw xmlpp::exception("Failed to perform transformation"); + } + } + void configure(const xmlpp::Element * e) + { + stylesheet = e->get_attribute_value("style"); + } + private: + Glib::ustring stylesheet; +}; +DECLARE_TRANSFORM(TransformXmlToHtml) + diff --git a/project2/transformHtml.h b/project2/transformHtml.h new file mode 100644 index 0000000..25bd0d5 --- /dev/null +++ b/project2/transformHtml.h @@ -0,0 +1,15 @@ +#ifndef HTMLDOCUMENT_H +#define HTMLDOCUMENT_H + +#include "transform.h" +#include <libxml/HTMLtree.h> + +class HtmlDocument; +class HtmlDocument : public SourceOf<HtmlDocument> { + public: + htmlDocPtr doc; + operator const HtmlDocument * () const { return this; } +}; + +#endif + diff --git a/project2/transformText.cpp b/project2/transformText.cpp new file mode 100644 index 0000000..5ba03cc --- /dev/null +++ b/project2/transformText.cpp @@ -0,0 +1,38 @@ +#include "transformText.h" +#include <libxml++/document.h> +#include "transformHtml.h" +#include <sys/wait.h> +#include <misc.h> + +class TransformHtmlToText : public TransformImpl<HtmlDocument, TextDocument> { + public: + void transform(const HtmlDocument * cdoc, TextDocument * str) const + { + xmlDoc * doc = const_cast<xmlDoc *>(cdoc->doc); + str->doc.clear(); + int fds[2]; + const char * callLynx[] = { +#ifdef STRACE_LYNX + "/usr/bin/strace", "-o", "/tmp/lynx", +#endif + "/usr/bin/lynx", "-dump", "-stdin", "-width=105", NULL }; + popenrw(callLynx, fds); + FILE * lynxIn = fdopen(fds[0], "w"); + FILE * lynxOut = fdopen(fds[1], "r"); + htmlNodeDumpFile(lynxIn, doc, xmlDocGetRootElement(doc)); + fclose(lynxIn); + close(fds[0]); + for (int ch ; ((ch = fgetc(lynxOut)) >= 0); ) { + str->doc.push_back(ch); + } + fclose(lynxOut); + close(fds[1]); + int status; + wait(&status); + if (status != 0) { + throw std::runtime_error("Lynx failed"); + } + } +}; +DECLARE_TRANSFORM(TransformHtmlToText); + diff --git a/project2/transformText.h b/project2/transformText.h new file mode 100644 index 0000000..9a81c89 --- /dev/null +++ b/project2/transformText.h @@ -0,0 +1,15 @@ +#ifndef TEXTDOCUMENT_H +#define TEXTDOCUMENT_H + +#include "transform.h" +#include <string> + +class TextDocument : public SourceOf<TextDocument> { + public: + std::string doc; + operator const TextDocument * () const { return this; } +}; + + +#endif + diff --git a/project2/variables.cpp b/project2/variables.cpp index a5cfa0d..f633ccd 100644 --- a/project2/variables.cpp +++ b/project2/variables.cpp @@ -4,6 +4,7 @@ #include "appEngine.h" #include "session.h" #include "rowUser.h" +#include "rowSet.h" #include <libxml++/nodes/textnode.h> #include <stdexcept> #include <boost/tokenizer.hpp> diff --git a/project2/variables.h b/project2/variables.h index 5e29547..37aba03 100644 --- a/project2/variables.h +++ b/project2/variables.h @@ -53,6 +53,7 @@ class VariableType : public _VT { operator int32_t() const; operator double() const; operator const boost::posix_time::ptime &() const; + template <typename T> const T * get() const { return boost::get<T>(this); } private: template <typename T> friend const T * set(const VariableType * var, const T * t, Freer); diff --git a/project2/viewHost.cpp b/project2/viewHost.cpp new file mode 100644 index 0000000..1fa8d9b --- /dev/null +++ b/project2/viewHost.cpp @@ -0,0 +1,107 @@ +#include "viewHost.h" +#include "xmlPresenter.h" +#include <boost/foreach.hpp> +#include <iostream> + +#define FOREACH_PRESENTER BOOST_FOREACH (const PresenterPtr & p, presenters) + +ViewHost::ViewHost(const std::string & group, const std::string & name) : + XmlScriptParser(group, name, false), + CheckHost(group, name) +{ + loader.supportedStorers.insert(Storer::into(&views)); + loader.supportedStorers.insert(Storer::into(&pmp.presenters)); +} + +ViewHost::ViewHost(const std::string & file) : + XmlScriptParser(file, false), + CheckHost(file) +{ + loader.supportedStorers.insert(Storer::into(&views)); + loader.supportedStorers.insert(Storer::into(&pmp.presenters)); +} + +ViewHost::~ViewHost() +{ +} + +void +ViewHost::executeViews(const DefaultPresenterProvider & dpp) const +{ + if (pmp.presenters.empty()) { + pmp.presenters.insert(dpp(get_document()->get_root_node())); + } + + BOOST_FOREACH(const Views::value_type & s, views) { + s->execute(&pmp); + } +} + +void +ViewHost::doTransforms() const +{ + BOOST_FOREACH (const PresenterPtr & p, pmp.presenters) { + TransformSourcePtr ts = boost::dynamic_pointer_cast<TransformSource>(p); + if (ts) { + ts->doTransforms(); + } + } +} + +PresenterPtr +ViewHost::headPresenter() const +{ + return *pmp.presenters.begin(); +} + +void +ViewHost::PresenterMultiplexer::declareNamespace(const Glib::ustring & prefix, const Glib::ustring & ns) const +{ + FOREACH_PRESENTER { p->declareNamespace(prefix, ns); } +} +void +ViewHost::PresenterMultiplexer::setNamespace(const Glib::ustring & prefix, const Glib::ustring & ns) const +{ + FOREACH_PRESENTER { p->setNamespace(prefix, ns); } +} +void +ViewHost::PresenterMultiplexer::pushSub(const Glib::ustring & name) const +{ + FOREACH_PRESENTER { p->pushSub(name); } +} +void +ViewHost::PresenterMultiplexer::pushSub(const Glib::ustring & name, const Glib::ustring & ns) const +{ + FOREACH_PRESENTER { p->pushSub(name, ns); } +} +void +ViewHost::PresenterMultiplexer::addAttr(const Glib::ustring & name, const VariableType & value) const +{ + FOREACH_PRESENTER { p->addAttr(name, value); } +} +void +ViewHost::PresenterMultiplexer::addAttr(const Glib::ustring & name, const Glib::ustring & ns, const VariableType & value) const +{ + FOREACH_PRESENTER { p->addAttr(name, ns, value); } +} +void +ViewHost::PresenterMultiplexer::addField(const Glib::ustring & name, const VariableType & value) const +{ + FOREACH_PRESENTER { p->addField(name, value); } +} +void +ViewHost::PresenterMultiplexer::addField(const Glib::ustring & name, const Glib::ustring & ns, const VariableType & value) const +{ + FOREACH_PRESENTER { p->addField(name, ns, value); } +} +void +ViewHost::PresenterMultiplexer::addText(const VariableType & value) const +{ + FOREACH_PRESENTER { p->addText(value); } +} +void +ViewHost::PresenterMultiplexer::popSub() const +{ + FOREACH_PRESENTER { p->popSub(); } +} + diff --git a/project2/viewHost.h b/project2/viewHost.h new file mode 100644 index 0000000..19ff65f --- /dev/null +++ b/project2/viewHost.h @@ -0,0 +1,47 @@ +#ifndef VIEWHOST_H +#define VIEWHOST_H + +#include "xmlScriptParser.h" +#include "paramChecker.h" +#include "xmlStorage.h" +#include "presenter.h" +#include "checkHost.h" +#include <set> +#include <boost/filesystem/path.hpp> + +class ViewHost : virtual public XmlScriptParser, virtual public CheckHost { + public: + class PresenterMultiplexer : public Presenter { + public: + typedef std::set<PresenterPtr> Presenters; + void declareNamespace(const Glib::ustring & prefix, const Glib::ustring & ns) const; + void setNamespace(const Glib::ustring & prefix, const Glib::ustring & ns) const; + void pushSub(const Glib::ustring & name) const; + void pushSub(const Glib::ustring & name, const Glib::ustring & ns) const; + void addAttr(const Glib::ustring & name, const VariableType & value) const; + void addAttr(const Glib::ustring & name, const Glib::ustring & ns, const VariableType & value) const; + void addField(const Glib::ustring & name, const VariableType & value) const; + void addField(const Glib::ustring & name, const Glib::ustring & ns, const VariableType & value) const; + void addText(const VariableType & value) const; + void popSub() const; + Presenters presenters; + }; + typedef boost::function1<PresenterPtr, const xmlpp::Element *> DefaultPresenterProvider; + + ViewHost(const std::string & group, const std::string & file); + ViewHost(const std::string & file); + ~ViewHost(); + + void executeViews(const DefaultPresenterProvider &) const; + void doTransforms() const; + PresenterPtr headPresenter() const; + + private: + mutable PresenterMultiplexer pmp; + typedef ANONSTORAGEOF(View) Views; + Views views; +}; +typedef boost::intrusive_ptr<ViewHost> ViewHostPtr; + +#endif + diff --git a/project2/xmlObjectLoader.cpp b/project2/xmlObjectLoader.cpp index d2f25e7..c41b0c0 100644 --- a/project2/xmlObjectLoader.cpp +++ b/project2/xmlObjectLoader.cpp @@ -27,7 +27,7 @@ typedef std::set<boost::shared_ptr<ComponentLoader> > ComponentLoaderSet; LoaderBase::LoaderBase(bool r) : recursive(r), - ns(ApplicationEngine::getCurrent()->env()->getXmlNamespace()) + ns(Environment::getCurrent()->getXmlNamespace()) { supportedStorers.insert(Storer::into(&libraries)); } diff --git a/project2/xmlPresenter.cpp b/project2/xmlPresenter.cpp index adf7860..c6bb04d 100644 --- a/project2/xmlPresenter.cpp +++ b/project2/xmlPresenter.cpp @@ -2,67 +2,52 @@ #include "xmlObjectLoader.h" #include "variables.h" #include "appEngine.h" +#include <libxml++/document.h> -XmlPresenter::XmlPresenter() : - responseDoc(XmlDocumentPtr(new xmlpp::Document("1.0"))) -{ -} - -XmlPresenter::~XmlPresenter() -{ -} +DECLARE_COMPONENT_LOADER("xml", XmlPresenter, PresenterLoader) -void -XmlPresenter::createDoc() const +XmlPresenter::XmlPresenter(const Glib::ustring & responseRootNodeName, const Glib::ustring & responseStyle, const Glib::ustring & ct) : + ContentPresenter(ct), + responseDoc(XmlDocumentPtr(new xmlpp::Document("1.0"))) { - if (nodeStack.empty()) { - nodeStack.push_back(responseDoc->create_root_node(getResponseRootNodeName())); - declareNamespace(ApplicationEngine::getCurrent()->env()->getXmlPrefix(), - ApplicationEngine::getCurrent()->env()->getXmlNamespace()); - // 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); - } - } + createDoc(responseRootNodeName, responseStyle); } -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")) +XmlPresenter::XmlPresenter(const xmlpp::Element * e) : + ContentPresenter(e->get_attribute_value("contenttype")), + responseDoc(XmlDocumentPtr(new xmlpp::Document("1.0"))) { - LoaderBase loader(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); + createDoc(e->get_attribute_value("root"), e->get_attribute_value("style")); } -XmlProcessPresenter::~XmlProcessPresenter() +XmlPresenter::~XmlPresenter() { } -const Glib::ustring & -XmlProcessPresenter::getResponseRootNodeName() const +void +XmlPresenter::createDoc(const Glib::ustring & responseRootNodeName, const Glib::ustring & responseStyle) const { - return responseRootNodeName; + nodeStack.push_back(responseDoc->create_root_node(responseRootNodeName)); + declareNamespace(Environment::getCurrent()->getXmlPrefix(), + Environment::getCurrent()->getXmlNamespace()); + // XSLT Style + char * buf; + if (!responseStyle.empty() && 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); + } } -const Glib::ustring & -XmlProcessPresenter::getResponseStyle() const +XmlPresenter::operator const xmlpp::Document * () const { - return responseStyle; + return responseDoc.get(); } -XmlPresenter::XmlDocumentPtr -XmlPresenter::getDataDocument() const +XmlPresenter::operator const xmlDoc * () const { - return responseDoc; + return responseDoc->cobj(); } void @@ -80,15 +65,13 @@ XmlPresenter::setNamespace(const Glib::ustring & prefix, const Glib::ustring & n void XmlPresenter::pushSub(const Glib::ustring & name, const Glib::ustring & ns) const { - createDoc(); nodeStack.push_back(nodeStack.back()->add_child(name, ns)); } void XmlPresenter::addAttr(const Glib::ustring & name, const Glib::ustring & ns, const VariableType & value) const { - if (!boost::get<Null>(&value)) { - createDoc(); + if (!value.get<Null>()) { nodeStack.back()->set_attribute(name, value, ns); } } @@ -96,8 +79,7 @@ XmlPresenter::addAttr(const Glib::ustring & name, const Glib::ustring & ns, cons void XmlPresenter::addText(const VariableType & value) const { - if (!boost::get<Null>(&value)) { - createDoc(); + if (!value.get<Null>()) { nodeStack.back()->add_child_text(value); } } diff --git a/project2/xmlPresenter.h b/project2/xmlPresenter.h index cd63f1e..9b32c31 100644 --- a/project2/xmlPresenter.h +++ b/project2/xmlPresenter.h @@ -2,16 +2,17 @@ #define XMLPRESENTER_H #include "presenter.h" -#include "xmlScriptParser.h" +#include "transform.h" namespace xmlpp { class Document; } -class XmlPresenter : public Presenter { +class XmlPresenter : public ContentPresenter, public SourceOf<xmlpp::Document>, public SourceOf<xmlDoc> { public: typedef boost::shared_ptr<xmlpp::Document> XmlDocumentPtr; - XmlPresenter(); + XmlPresenter(const Glib::ustring & responseRootNodeName, const Glib::ustring & responseStyle, const Glib::ustring & contentType); + XmlPresenter(const xmlpp::Element * e); ~XmlPresenter(); void declareNamespace(const Glib::ustring & prefix, const Glib::ustring & ns) const; @@ -21,34 +22,15 @@ class XmlPresenter : public Presenter { void addText(const VariableType & value) const; void popSub() const; - virtual XmlDocumentPtr getDataDocument() const; - virtual const Glib::ustring & getResponseRootNodeName() const = 0; - virtual const Glib::ustring & getResponseStyle() const = 0; + operator const xmlpp::Document * () const; + operator const xmlDoc * () const; private: - void createDoc() const; + void createDoc(const Glib::ustring & responseRootNodeName, const Glib::ustring & responseStyle) const; XmlDocumentPtr responseDoc; mutable std::vector<xmlpp::Element *> nodeStack; }; -class XmlProcessPresenter : public XmlPresenter { - public: - 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; - - const Glib::ustring responseRootNodeName; - const Glib::ustring responseStyle; - const Glib::ustring contentType; -}; - typedef boost::intrusive_ptr<XmlPresenter> XmlPresenterPtr; #endif diff --git a/project2/xmlScriptParser.cpp b/project2/xmlScriptParser.cpp index 8db4049..fad9542 100644 --- a/project2/xmlScriptParser.cpp +++ b/project2/xmlScriptParser.cpp @@ -3,13 +3,15 @@ #include <boost/filesystem/convenience.hpp> XmlScriptParser::XmlScriptParser(const std::string & group, const std::string & name, bool ii) : - IsInclusion(ii) + IsInclusion(ii), + loader(true) { loadDocument(group + "/" + name + ".xml"); } XmlScriptParser::XmlScriptParser(const std::string & file, bool ii) : - IsInclusion(ii) + IsInclusion(ii), + loader(true) { loadDocument(file); } @@ -17,6 +19,7 @@ XmlScriptParser::XmlScriptParser(const std::string & file, bool ii) : void XmlScriptParser::loadDocument(const std::string & file) { + loader.supportedStorers.insert(Storer::into(&rowSets)); if (!boost::filesystem::exists(file)) { if (IsInclusion) { throw DependencyNotFound(file); @@ -38,3 +41,9 @@ XmlScriptParser::loadDocument(const std::string & file) } } +void +XmlScriptParser::parseDocument() +{ + loader.collectAll(this, get_document()->get_root_node(), true, ErrorOnUnsupported); +} + diff --git a/project2/xmlScriptParser.h b/project2/xmlScriptParser.h index 92d1bdb..7b7f644 100644 --- a/project2/xmlScriptParser.h +++ b/project2/xmlScriptParser.h @@ -2,9 +2,13 @@ #define XMLSCRIPTPARSER_H #include <libxml++/parsers/domparser.h> +#include <boost/function.hpp> #include "exceptions.h" +#include "xmlObjectLoader.h" +#include <intrusivePtrBase.h> +#include "commonObjects.h" -class XmlScriptParser : public xmlpp::DomParser { +class XmlScriptParser : public xmlpp::DomParser, virtual public CommonObjects, virtual public IntrusivePtrBase { public: SimpleMessageException(ParseError); SimpleMessageExceptionBase(NotFound, ParseError); @@ -15,11 +19,16 @@ class XmlScriptParser : public xmlpp::DomParser { XmlScriptParser(const std::string & group, const std::string & name, bool isInclusion); XmlScriptParser(const std::string & file, bool isInclusion); + void parseDocument(); const bool IsInclusion; + protected: + LoaderBase loader; + private: void loadDocument(const std::string & file); }; + #endif diff --git a/project2/xmlStorage.h b/project2/xmlStorage.h index 9263b48..73fce0a 100644 --- a/project2/xmlStorage.h +++ b/project2/xmlStorage.h @@ -3,75 +3,115 @@ #include "sourceObject.h" #include "exceptions.h" +#include <set> +#include <list> +#include <map> #include <boost/intrusive_ptr.hpp> -#include <boost/multi_index_container.hpp> -#include <boost/multi_index/member.hpp> -#include <boost/multi_index/ordered_index.hpp> SimpleMessageException(StoreFailed); -struct bySOName { }; -struct bySOOrder { }; +#define STORAGEOF(X) \ + std::map<std::string, boost::intrusive_ptr<X> > +#define ANONORDEREDSTORAGEOF(X) \ + std::list<boost::intrusive_ptr<X> > +#define ANONSTORAGEOF(X) \ + std::set<boost::intrusive_ptr<X> > -template <class X> -class Storage { - public: - typedef boost::multi_index::multi_index_container< - boost::intrusive_ptr<X>, - boost::multi_index::indexed_by< - boost::multi_index::ordered_unique< - boost::multi_index::tag<bySOOrder>, BOOST_MULTI_INDEX_MEMBER(SourceObject, const unsigned int, order)>, - boost::multi_index::ordered_unique< - boost::multi_index::tag<bySOName>, BOOST_MULTI_INDEX_MEMBER(SourceObject, const std::string, name)> - > > Objects; - typedef Objects * ObjectsPtr; -}; class Storer; typedef boost::intrusive_ptr<Storer> StorerPtr; class Storer : public virtual IntrusivePtrBase { public: template <class X> - static StorerPtr into(X * map); + static StorerPtr into(STORAGEOF(X) * map); + template <class X> + static StorerPtr into(ANONSTORAGEOF(X) * set); + template <class X> + static StorerPtr into(ANONORDEREDSTORAGEOF(X) * list); - virtual bool save(SourceObjectPtr o, const xmlpp::Element *) const = 0; + virtual bool save(SourceObjectPtr o, const xmlpp::Element *) = 0; }; -template <class X> +template <class X, class M = STORAGEOF(X)> class StorerBase : public Storer { public: - typedef typename Storage<X>::ObjectsPtr Map; - StorerBase() - { - } - - bool save(SourceObjectPtr obj, const xmlpp::Element * p) const { + typedef M * Map; + bool save(SourceObjectPtr obj, const xmlpp::Element * p) { boost::intrusive_ptr<X> O = boost::dynamic_pointer_cast<X>(obj); if (O) { - if (getMap(p)->insert(O).second) { + if (insert(p, O)) { return true; } throw StoreFailed(obj->name); } return false; } - virtual Map getMap(const xmlpp::Element *) const = 0; + virtual bool insert(const xmlpp::Element *, boost::intrusive_ptr<X>) = 0; }; +template <class X, class M = STORAGEOF(X)> +class StorerImpl : public StorerBase<X, M> { + public: + StorerImpl(M * m); + bool insert(const xmlpp::Element *, boost::intrusive_ptr<X> O); +}; template <class X> -class StorerImpl : public StorerBase<X> { +class StorerImpl<X, STORAGEOF(X)> : public StorerBase<X, STORAGEOF(X)> { public: - StorerImpl(typename StorerBase<X>::Map m) : map(m) + typedef STORAGEOF(X) Map; + StorerImpl(STORAGEOF(X) * m) : map(m) { } - - typename StorerBase<X>::Map getMap(const xmlpp::Element *) const { return map; } - typename StorerBase<X>::Map map; + bool insert(const xmlpp::Element *, boost::intrusive_ptr<X> O) + { + return map->insert(typename Map::value_type(O->name, O)).second; + } + Map * map; +}; +template <class X> +class StorerImpl<X, ANONSTORAGEOF(X)> : public StorerBase<X, ANONSTORAGEOF(X)> { + public: + typedef ANONSTORAGEOF(X) Map; + StorerImpl(ANONSTORAGEOF(X) * m) : map(m) + { + } + bool insert(const xmlpp::Element *, boost::intrusive_ptr<X> O) + { + map->insert(O); + return true; + } + Map * map; +}; +template <class X> +class StorerImpl<X, ANONORDEREDSTORAGEOF(X)> : public StorerBase<X, ANONORDEREDSTORAGEOF(X)> { + public: + typedef ANONORDEREDSTORAGEOF(X) Map; + StorerImpl(ANONORDEREDSTORAGEOF(X) * m) : map(m) + { + } + bool insert(const xmlpp::Element *, boost::intrusive_ptr<X> O) + { + map->push_back(O); + return true; + } + Map * map; }; template <class X> StorerPtr -Storer::into(X * map) { - return new StorerImpl<typename X::value_type::element_type>(map); +Storer::into(STORAGEOF(X) * map) { + return new StorerImpl<X, STORAGEOF(X)>(map); +} + +template <class X> +StorerPtr +Storer::into(ANONSTORAGEOF(X) * set) { + return new StorerImpl<X, ANONSTORAGEOF(X)>(set); +} + +template <class X> +StorerPtr +Storer::into(ANONORDEREDSTORAGEOF(X) * list) { + return new StorerImpl<X, ANONORDEREDSTORAGEOF(X)>(list); } #endif |