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