From 15f53475ba6e9ad40a28c029263fc1e2a7f62e99 Mon Sep 17 00:00:00 2001
From: randomdan <randomdan@localhost>
Date: Mon, 28 Feb 2011 19:22:20 +0000
Subject: Add support for local error handling

---
 project2/Jamfile.jam                  |  4 +--
 project2/cgi/cgiAppEngine.cpp         | 23 +++----------
 project2/cgi/cgiAppEngine.h           |  5 ++-
 project2/console/consoleAppEngine.cpp | 20 +++--------
 project2/console/consoleAppEngine.h   |  5 ++-
 project2/if.cpp                       | 21 ++++++++++--
 project2/if.h                         |  3 ++
 project2/iterate.cpp                  | 34 +++++++++++--------
 project2/iterate.h                    |  4 ++-
 project2/noOutputExecute.h            |  7 ++--
 project2/requestHost.cpp              | 63 +++++++++++++++++++++++++++++++++++
 project2/requestHost.h                | 31 +++++++++++++++++
 12 files changed, 158 insertions(+), 62 deletions(-)
 create mode 100644 project2/requestHost.cpp
 create mode 100644 project2/requestHost.h

diff --git a/project2/Jamfile.jam b/project2/Jamfile.jam
index f591344..4f8ba1a 100644
--- a/project2/Jamfile.jam
+++ b/project2/Jamfile.jam
@@ -51,8 +51,8 @@ lib p2common :
 	appEngine.cpp dataSource.cpp environment.cpp fileStarGlibIoChannel.cpp iHaveParameters.cpp
 	iterate.cpp paramChecker.cpp presenter.cpp rawView.cpp logger.cpp if.cpp xmlScriptParser.cpp
 	sourceObject.cpp task.cpp variables.cpp variableConvert.cpp view.cpp xmlObjectLoader.cpp exceptions.cpp
-	sessionClearTask.cpp session.cpp sessionSetTask.cpp commonObjects.cpp xmlPresenter.cpp
-	rowView.cpp rowSet.cpp rowUser.cpp rowProcessor.cpp config.cpp fileStrmVarWriter.cpp
+	sessionClearTask.cpp session.cpp sessionSetTask.cpp commonObjects.cpp xmlPresenter.cpp requestHost.cpp
+	rowView.cpp rowSet.cpp rowUser.cpp rowProcessor.cpp config.cpp fileStrmVarWriter.cpp noOutputExecute.cpp
 	:
 	<library>../libmisc//misc
 	<library>libxmlpp
diff --git a/project2/cgi/cgiAppEngine.cpp b/project2/cgi/cgiAppEngine.cpp
index 043da76..9f7665d 100644
--- a/project2/cgi/cgiAppEngine.cpp
+++ b/project2/cgi/cgiAppEngine.cpp
@@ -97,6 +97,7 @@ CgiApplicationEngine::write(std::ostream & IO) const
 	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);
@@ -146,7 +147,6 @@ CgiApplicationEngine::PresentStage::run()
 		}
 	}
 	execute();
-	sessionsContainer->CleanUp();
 	return NULL;
 }
 
@@ -204,6 +204,8 @@ 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(&parameterChecks));
@@ -222,23 +224,8 @@ CgiApplicationEngine::RequestStage::run()
 			return new PresentStage(pc->present);
 		}
 	}
-	try {
-		BOOST_FOREACH(const Tasks::value_type & t, tasks.get<bySOOrder>()) {
-			t->execute();
-		}
-		// Commit data source transactions (without invoking a connection)
-		BOOST_FOREACH(const DataSources::value_type & ds, datasources) {
-			ds->commit();
-		}
-		return present.empty() ? NULL : new PresentStage(present);
-	}
-	catch (...) {
-		// Do something about the error
-		BOOST_FOREACH(const DataSources::value_type & ds, datasources) {
-			ds->rollback();
-		}
-		throw;
-	}
+	RequestHost::run();
+	return present.empty() ? NULL : new PresentStage(present);
 }
 
 CgiApplicationEngine::HttpHeaderPtr
diff --git a/project2/cgi/cgiAppEngine.h b/project2/cgi/cgiAppEngine.h
index 79638f4..65142b6 100644
--- a/project2/cgi/cgiAppEngine.h
+++ b/project2/cgi/cgiAppEngine.h
@@ -7,6 +7,7 @@
 #include "../xmlPresenter.h"
 #include "../commonObjects.h"
 #include "../uuid.h"
+#include "../requestHost.h"
 #include <boost/intrusive_ptr.hpp>
 
 class CgiEnvironment;
@@ -52,7 +53,7 @@ class CgiApplicationEngine : public ApplicationEngine {
 				virtual HttpHeaderPtr getHeader() const = 0;
 		};
 		
-		class RequestStage : public Stage, public XmlPresenter {
+		class RequestStage : public Stage, public XmlPresenter, RequestHost {
 			public:
 				RequestStage(const std::string & id);
 				virtual ~RequestStage();
@@ -67,8 +68,6 @@ class CgiApplicationEngine : public ApplicationEngine {
 				std::string present;
 				typedef Storage<ParamChecker>::Objects ParamCheckers;
 				ParamCheckers parameterChecks;
-				typedef Storage<NoOutputExecute>::Objects Tasks;
-				Tasks tasks;
 
 			private:
 				static const Glib::ustring resp;
diff --git a/project2/console/consoleAppEngine.cpp b/project2/console/consoleAppEngine.cpp
index e126793..eed37fd 100644
--- a/project2/console/consoleAppEngine.cpp
+++ b/project2/console/consoleAppEngine.cpp
@@ -59,6 +59,9 @@ ConsoleApplicationEngine::ConsoleApplicationEngine(const ConsoleEnvironment * en
 	out(stdout, true)
 {
 	XmlScriptParser request(f.string(), false);
+	xmlpp::Element * requestRoot = request.get_document()->get_root_node();
+	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(&parameterChecks));
@@ -80,22 +83,7 @@ ConsoleApplicationEngine::process() const
 			throw std::runtime_error("Check failed");
 		}
 	}
-	try {
-		BOOST_FOREACH(const Tasks::value_type & t, tasks.get<bySOOrder>()) {
-			t->execute();
-		}
-		// Commit data source transactions (without invoking a connection)
-		BOOST_FOREACH(const DataSources::value_type & ds, this->datasources) {
-			ds->commit();
-		}
-	}
-	catch (...) {
-		// Do something about the error
-		BOOST_FOREACH(const DataSources::value_type & ds, this->datasources) {
-			ds->rollback();
-		}
-		throw;
-	}
+	RequestHost::run();
 	BOOST_FOREACH(const Views::value_type & v, views) {
 		v->execute(this);
 	}
diff --git a/project2/console/consoleAppEngine.h b/project2/console/consoleAppEngine.h
index d8cdca5..1e4f1c3 100644
--- a/project2/console/consoleAppEngine.h
+++ b/project2/console/consoleAppEngine.h
@@ -8,13 +8,14 @@
 #include "../commonObjects.h"
 #include "../view.h"
 #include "../fileStrmVarWriter.h"
+#include "../requestHost.h"
 #include <boost/intrusive_ptr.hpp>
 #include <boost/filesystem/path.hpp>
 #include <libxml++/document.h>
 
 class ConsoleEnvironment;
 
-class ConsoleApplicationEngine : public ApplicationEngine, public Presenter {
+class ConsoleApplicationEngine : public ApplicationEngine, public Presenter, RequestHost {
 	public:
 		ConsoleApplicationEngine(const ConsoleEnvironment *, const boost::filesystem::path &);
 		virtual ~ConsoleApplicationEngine();
@@ -46,8 +47,6 @@ class ConsoleApplicationEngine : public ApplicationEngine, public Presenter {
 
 		typedef Storage<ParamChecker>::Objects ParamCheckers;
 		ParamCheckers parameterChecks;
-		typedef Storage<NoOutputExecute>::Objects Tasks;
-		Tasks tasks;
 		typedef Storage<View>::Objects Views;
 		Views views;
 		SessionPtr runtime;
diff --git a/project2/if.cpp b/project2/if.cpp
index fe47059..a69fd8d 100644
--- a/project2/if.cpp
+++ b/project2/if.cpp
@@ -41,7 +41,8 @@ If::If(const xmlpp::Element * e) :
 	SourceObject(e),
 	Iterate(e),
 	RowView(e),
-	IfSet(e)
+	IfSet(e),
+	localErrorHandling(e->get_attribute_value("errorHandling") == "local")
 {
 }
 
@@ -66,8 +67,22 @@ If::execute() const
 {
 	if (passes()) {
 		Logger()->message(LOG_DEBUG, "IfSet passed");
-		BOOST_FOREACH(const SubNOEs::value_type & sq, subNOEs.get<bySOOrder>()) {
-			sq->execute();
+		try {
+			BOOST_FOREACH(const SubNOEs::value_type & sq, subNOEs.get<bySOOrder>()) {
+				if (!sq->isErrorHandler) {
+					sq->execute();
+				}
+			}
+		}
+		catch (...) {
+			BOOST_FOREACH(const SubNOEs::value_type & sq, subNOEs.get<bySOOrder>()) {
+				if (sq->isErrorHandler) {
+					sq->execute();
+				}
+			}
+			if (!localErrorHandling) {
+				throw;
+			}
 		}
 	}
 }
diff --git a/project2/if.h b/project2/if.h
index 87fc1ee..68f6595 100644
--- a/project2/if.h
+++ b/project2/if.h
@@ -25,6 +25,9 @@ class If : public Iterate, public RowView, public IfSet {
 		virtual void loadComplete(const CommonObjects*);
 		virtual void execute(const Presenter*) const;
 		virtual void execute() const;
+
+		const bool localErrorHandling;
+
 	private:
 		const std::string & getName() const;
 };
diff --git a/project2/iterate.cpp b/project2/iterate.cpp
index f0097c8..ccf289e 100644
--- a/project2/iterate.cpp
+++ b/project2/iterate.cpp
@@ -7,7 +7,8 @@ DECLARE_LOADER("iterate", Iterate);
 Iterate::Iterate(const xmlpp::Element * p) :
 	SourceObject(p),
 	NoOutputExecute(p),
-	RowProcessor(p)
+	RowProcessor(p),
+	localErrorHandling(p->get_attribute_value("errorHandling") == "local")
 {
 	LoaderBase loader("http://project2.randomdan.homeip.net", true);
 	loader.supportedStorers.insert(Storer::into(&subNOEs));
@@ -27,7 +28,7 @@ Iterate::loadComplete(const CommonObjects * co)
 void
 Iterate::rowReady() const
 {
-	executeChildren();
+	executeChildren(false);
 	source->rowChanged();
 }
 
@@ -44,26 +45,31 @@ Iterate::execute() const
 	}
 	catch (...) {
 		RowSet::endRow(source.get());
-		throw;
+		executeChildren(true);
+		if (!localErrorHandling) {
+			throw;
+		}
 	}
 }
 
 void
-Iterate::executeChildren() const
+Iterate::executeChildren(bool errs) const
 {
 	BOOST_FOREACH(const SubNOEs::value_type & sq, subNOEs.get<bySOOrder>()) {
-		if (dynamic_cast<const RowProcessor *>(sq.get())) {
-			sq->execute();
-		}
-		else {
-			RowSet::beginRow(NULL);
-			try {
+		if (sq->isErrorHandler == errs) {
+			if (dynamic_cast<const RowProcessor *>(sq.get())) {
 				sq->execute();
-				RowSet::endRow(NULL);
 			}
-			catch (...) {
-				RowSet::endRow(NULL);
-				throw;
+			else {
+				RowSet::beginRow(NULL);
+				try {
+					sq->execute();
+					RowSet::endRow(NULL);
+				}
+				catch (...) {
+					RowSet::endRow(NULL);
+					throw;
+				}
 			}
 		}
 	}
diff --git a/project2/iterate.h b/project2/iterate.h
index 2c7eeba..d5ca824 100644
--- a/project2/iterate.h
+++ b/project2/iterate.h
@@ -21,8 +21,10 @@ class Iterate : public NoOutputExecute, public RowProcessor {
 		typedef Storage<NoOutputExecute>::Objects SubNOEs;
 		SubNOEs subNOEs;
 
+		const bool localErrorHandling;
+
 	protected:
-		void executeChildren() const;
+		void executeChildren(bool errs) const;
 };
 
 #endif
diff --git a/project2/noOutputExecute.h b/project2/noOutputExecute.h
index ec73ce1..f47c118 100644
--- a/project2/noOutputExecute.h
+++ b/project2/noOutputExecute.h
@@ -11,10 +11,13 @@ typedef boost::intrusive_ptr<NoOutputExecute> NoOutputExecutePtr;
 
 class NoOutputExecute : public virtual SourceObject {
 	public:
-		NoOutputExecute(const xmlpp::Element * p) : SourceObject(p) { };
-		NoOutputExecute(const std::string & n) : SourceObject(n) { };
+		NoOutputExecute(const xmlpp::Element * p);
+		NoOutputExecute(const std::string & n);
 		virtual ~NoOutputExecute() { }
+
 		virtual void execute() const = 0;
+
+		const bool isErrorHandler;
 };
 
 #endif
diff --git a/project2/requestHost.cpp b/project2/requestHost.cpp
new file mode 100644
index 0000000..09de71f
--- /dev/null
+++ b/project2/requestHost.cpp
@@ -0,0 +1,63 @@
+#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, tasks.get<bySOOrder>()) {
+		if (t->isErrorHandler == errs) {
+			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
new file mode 100644
index 0000000..7610ac1
--- /dev/null
+++ b/project2/requestHost.h
@@ -0,0 +1,31 @@
+#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 tasks;
+		bool rollbackBeforeHandle;
+		bool localErrorHandling;
+
+	private:
+		void commitAll() const;
+		void rollbackAll() const;
+		void run(bool errs) const;
+};
+
+#endif
+
-- 
cgit v1.2.3