From 6564f03c1df962a8fb5fd08f5781e2a8d2121dcd Mon Sep 17 00:00:00 2001 From: randomdan Date: Thu, 28 Jul 2011 23:58:39 +0000 Subject: Half decent error handling in scripts with project2:handler[try/catch/finally] Component to validate a date string Merge some code (fixes sqlmerge missing attachments to ifs) Minor fixes New changelog importer in GB --- project2/Jamfile.jam | 4 +-- project2/cgi/cgiStageRequest.cpp | 10 +++--- project2/console/consoleAppEngine.cpp | 6 ++-- project2/iHaveSubTasks.cpp | 26 ++++++++++++++ project2/iHaveSubTasks.h | 25 +++++++++++++ project2/if.cpp | 21 +++-------- project2/if.h | 9 ++--- project2/iterate.cpp | 19 +++++----- project2/iterate.h | 12 ++----- project2/noOutputExecute.cpp | 9 ++--- project2/noOutputExecute.h | 10 ++---- project2/regexRows.cpp | 6 +++- project2/sqlMergeTask.cpp | 12 +++---- project2/structExceptHandling.cpp | 53 +++++++++++++++++++++++++++ project2/structExceptHandling.h | 18 ++++++++++ project2/taskHost.cpp | 43 +++++++--------------- project2/taskHost.h | 14 +++----- project2/validDateCheck.cpp | 68 +++++++++++++++++++++++++++++++++++ project2/xslPreFetch.cpp | 2 +- project2/xslPreFetch.h | 4 +-- 20 files changed, 251 insertions(+), 120 deletions(-) create mode 100644 project2/iHaveSubTasks.cpp create mode 100644 project2/iHaveSubTasks.h create mode 100644 project2/structExceptHandling.cpp create mode 100644 project2/structExceptHandling.h create mode 100644 project2/validDateCheck.cpp diff --git a/project2/Jamfile.jam b/project2/Jamfile.jam index 5fc26f2..035609b 100644 --- a/project2/Jamfile.jam +++ b/project2/Jamfile.jam @@ -54,12 +54,12 @@ lib p2uuid : ; lib p2common : - appEngine.cpp dataSource.cpp environment.cpp fileStarGlibIoChannel.cpp iHaveParameters.cpp library.cpp + appEngine.cpp dataSource.cpp environment.cpp fileStarGlibIoChannel.cpp iHaveParameters.cpp library.cpp iHaveSubTasks.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 taskHost.cpp checkHost.cpp rowView.cpp rowSet.cpp rowUser.cpp rowProcessor.cpp config.cpp fileStrmVarWriter.cpp noOutputExecute.cpp - transform.cpp transformHtml.cpp transformText.cpp definedColumns.cpp + transform.cpp transformHtml.cpp transformText.cpp definedColumns.cpp structExceptHandling.cpp validDateCheck.cpp variables-modconfig.cpp variables-modlookup.cpp variables-modparam.cpp diff --git a/project2/cgi/cgiStageRequest.cpp b/project2/cgi/cgiStageRequest.cpp index e649551..afef7ab 100644 --- a/project2/cgi/cgiStageRequest.cpp +++ b/project2/cgi/cgiStageRequest.cpp @@ -6,21 +6,19 @@ CgiApplicationEngine::RequestStage::RequestStage(const CgiEnvironment * e, const boost::filesystem::path & path) : XmlScriptParser(path, false), + SourceObject(get_document()->get_root_node()), ::CheckHost(path), CgiApplicationEngine::ResponseStage(e), - ::TaskHost(path) + ::TaskHost(path), + present(get_document()->get_root_node()->get_attribute_value("present")) { - 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"; } CgiApplicationEngine::NextStage CgiApplicationEngine::RequestStage::run() { runChecks(); - executeTasks(); + execute(); return NextStage(present.empty() ? NULL : new PresentStage(e, e->resolveScript(e->presentRoot, present)), this); } diff --git a/project2/console/consoleAppEngine.cpp b/project2/console/consoleAppEngine.cpp index 49a5842..32789be 100644 --- a/project2/console/consoleAppEngine.cpp +++ b/project2/console/consoleAppEngine.cpp @@ -55,6 +55,7 @@ class ConsoleSession : public Session { ConsoleApplicationEngine::ConsoleApplicationEngine(const ConsoleEnvironment * env, const boost::filesystem::path & f) : XmlScriptParser(f, false), + SourceObject(get_document()->get_root_node()), CheckHost(f), ApplicationEngine("console/environment"), TaskHost(f), @@ -62,9 +63,6 @@ ConsoleApplicationEngine::ConsoleApplicationEngine(const ConsoleEnvironment * en _env(env), runtime(new ConsoleSession()) { - xmlpp::Element * requestRoot = get_document()->get_root_node(); - rollbackBeforeHandle = requestRoot->get_attribute_value("rollbackBeforeHandle") == "true"; - localErrorHandling = requestRoot->get_attribute_value("errorHandling") == "local"; } ConsoleApplicationEngine::~ConsoleApplicationEngine() @@ -81,7 +79,7 @@ void ConsoleApplicationEngine::process() const { runChecks(); - executeTasks(); + execute(); executeViews(boost::bind(&PresenterLoader::createFrom, LoaderBase::getLoader("console"), _1)); addAppData(headPresenter().get()); } diff --git a/project2/iHaveSubTasks.cpp b/project2/iHaveSubTasks.cpp new file mode 100644 index 0000000..f78f81e --- /dev/null +++ b/project2/iHaveSubTasks.cpp @@ -0,0 +1,26 @@ +#include "iHaveSubTasks.h" +#include + +IHaveSubTasks::IHaveSubTasks(const xmlpp::Element * e) : + SourceObject(e), + NoOutputExecute(e) +{ +} + +IHaveSubTasks::~IHaveSubTasks() +{ +} + +void +IHaveSubTasks::loadComplete(const CommonObjects *) +{ +} + +void +IHaveSubTasks::run(const Tasks & tlist) const +{ + BOOST_FOREACH(const Tasks::value_type & t, tlist) { + t->execute(); + } +} + diff --git a/project2/iHaveSubTasks.h b/project2/iHaveSubTasks.h new file mode 100644 index 0000000..ee6d173 --- /dev/null +++ b/project2/iHaveSubTasks.h @@ -0,0 +1,25 @@ +#ifndef HASSUBTASKS_H +#define HASSUBTASKS_H + +#include "noOutputExecute.h" + +/// Base class for Project2 compoments that perform actions, but product no output +class IHaveSubTasks : public NoOutputExecute { + public: + typedef ANONORDEREDSTORAGEOF(NoOutputExecute) Tasks; + + IHaveSubTasks(const xmlpp::Element * p); + IHaveSubTasks(const std::string & n); + virtual ~IHaveSubTasks(); + + void loadComplete(const CommonObjects*); + virtual void execute() const = 0; + Tasks normal; + + protected: + void run(const Tasks &) const; +}; + +#endif + + diff --git a/project2/if.cpp b/project2/if.cpp index ed36bad..cf5c156 100644 --- a/project2/if.cpp +++ b/project2/if.cpp @@ -42,13 +42,12 @@ IfSet::passes() const If::If(const xmlpp::Element * e) : SourceObject(e), - NoOutputExecute(e), + IHaveSubTasks(e), View(e), - IfSet(e), - localErrorHandling(e->get_attribute_value("errorHandling") == "local") + IfSet(e) { LoaderBase loader(true); - loader.supportedStorers.insert(new NOEErrorStorer(&normNOEs, &errorNOEs)); + loader.supportedStorers.insert(Storer::into(&normal)); loader.supportedStorers.insert(Storer::into(&subViews)); loader.collectAll(e, true, IgnoreUnsupported); } @@ -74,19 +73,7 @@ If::execute() const { if (passes()) { Logger()->message(LOG_DEBUG, "IfSet passed"); - try { - BOOST_FOREACH(const SubNOEs::value_type & sq, normNOEs) { - sq->execute(); - } - } - catch (...) { - BOOST_FOREACH(const SubNOEs::value_type & sq, errorNOEs) { - sq->execute(); - } - if (!localErrorHandling) { - throw; - } - } + run(normal); } } diff --git a/project2/if.h b/project2/if.h index 9c9acd8..b33bca1 100644 --- a/project2/if.h +++ b/project2/if.h @@ -1,7 +1,7 @@ #ifndef IF_H #define IF_H -#include "noOutputExecute.h" +#include "iHaveSubTasks.h" #include "view.h" #include "paramChecker.h" @@ -19,7 +19,7 @@ class IfSet : public virtual IntrusivePtrBase { }; /// Project2 component to conditionally execute its children -class If : public NoOutputExecute, public View, public IfSet { +class If : public IHaveSubTasks, public View, public IfSet { public: If(const xmlpp::Element *); @@ -27,14 +27,9 @@ class If : public NoOutputExecute, public View, public IfSet { virtual void execute(const Presenter*) const; virtual void execute() const; - const bool localErrorHandling; - private: typedef ANONSTORAGEOF(View) SubViews; SubViews subViews; - typedef ANONORDEREDSTORAGEOF(NoOutputExecute) SubNOEs; - SubNOEs normNOEs; - SubNOEs errorNOEs; const std::string & getName() const; }; diff --git a/project2/iterate.cpp b/project2/iterate.cpp index 55648eb..1f2b12f 100644 --- a/project2/iterate.cpp +++ b/project2/iterate.cpp @@ -1,4 +1,5 @@ #include "iterate.h" +#include "logger.h" #include #include "xmlObjectLoader.h" @@ -6,12 +7,11 @@ DECLARE_LOADER("iterate", Iterate); Iterate::Iterate(const xmlpp::Element * p) : SourceObject(p), - NoOutputExecute(p), - RowProcessor(p), - localErrorHandling(p->get_attribute_value("errorHandling") == "local") + IHaveSubTasks(p), + RowProcessor(p) { LoaderBase loader(true); - loader.supportedStorers.insert(new NOEErrorStorer(&normNOEs, &errorNOEs)); + loader.supportedStorers.insert(Storer::into(&normal)); loader.collectAll(p, true, IgnoreUnsupported); } @@ -28,7 +28,7 @@ Iterate::loadComplete(const CommonObjects * co) void Iterate::rowReady() const { - executeChildren(false); + executeChildren(); source->rowChanged(); } @@ -45,17 +45,14 @@ Iterate::execute() const } catch (...) { RowSet::endRow(source.get()); - executeChildren(true); - if (!localErrorHandling) { - throw; - } + throw; } } void -Iterate::executeChildren(bool errs) const +Iterate::executeChildren() const { - BOOST_FOREACH(const SubNOEs::value_type & sq, (errs ? errorNOEs : normNOEs)) { + BOOST_FOREACH(const Tasks::value_type & sq, normal) { if (dynamic_cast(sq.get())) { sq->execute(); } diff --git a/project2/iterate.h b/project2/iterate.h index a60a0a4..9ea0f94 100644 --- a/project2/iterate.h +++ b/project2/iterate.h @@ -3,14 +3,14 @@ #include #include "rowProcessor.h" -#include "noOutputExecute.h" +#include "iHaveSubTasks.h" #include "xmlStorage.h" class Iterate; typedef boost::intrusive_ptr IteratePtr; /// Project2 component to iterate over a row set, executing its children for each record -class Iterate : public NoOutputExecute, public RowProcessor { +class Iterate : public IHaveSubTasks, public RowProcessor { public: Iterate(const xmlpp::Element * p); virtual ~Iterate(); @@ -19,14 +19,8 @@ class Iterate : public NoOutputExecute, public RowProcessor { void rowReady() const; void execute() const; - typedef ANONORDEREDSTORAGEOF(NoOutputExecute) SubNOEs; - SubNOEs normNOEs; - SubNOEs errorNOEs; - - const bool localErrorHandling; - protected: - void executeChildren(bool errs) const; + void executeChildren() const; }; #endif diff --git a/project2/noOutputExecute.cpp b/project2/noOutputExecute.cpp index cb12439..3bfa0e9 100644 --- a/project2/noOutputExecute.cpp +++ b/project2/noOutputExecute.cpp @@ -1,4 +1,5 @@ #include "noOutputExecute.h" +#include NoOutputExecute::NoOutputExecute(const xmlpp::Element * p) : SourceObject(p) @@ -10,13 +11,7 @@ NoOutputExecute::NoOutputExecute(const std::string & n) : { } -NOEErrorStorer::NOEErrorStorer(Map m, Map em) : - map(m), errorMap(em) +NoOutputExecute::~NoOutputExecute() { } -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 78245f2..1047f38 100644 --- a/project2/noOutputExecute.h +++ b/project2/noOutputExecute.h @@ -12,16 +12,10 @@ class NoOutputExecute : public virtual SourceObject { public: NoOutputExecute(const xmlpp::Element * p); NoOutputExecute(const std::string & n); - virtual ~NoOutputExecute() { } - virtual void execute() const = 0; -}; + virtual ~NoOutputExecute(); -class NOEErrorStorer : public StorerBase { - public: - NOEErrorStorer(Map m, Map em); - bool insert(const xmlpp::Element *, NoOutputExecutePtr); - Map map, errorMap; + virtual void execute() const = 0; }; #endif diff --git a/project2/regexRows.cpp b/project2/regexRows.cpp index b950125..6d75d3a 100644 --- a/project2/regexRows.cpp +++ b/project2/regexRows.cpp @@ -36,9 +36,13 @@ RegexRows::execute(const RowProcessor * rp) const if (reg->match(sourceText(), matches)) { do { unsigned int cols = std::min(matches.get_match_count(), DefinedColumns::columnCount() + 1); - for (unsigned int n = 1; n < cols; n += 1) { + unsigned int n; + for (n = 1; n < cols; n += 1) { *DefinedColumns::columns.get().find(n - 1) = matches.fetch(n); } + for (; n < DefinedColumns::columnCount() + 1; n += 1) { + *DefinedColumns::columns.get().find(n - 1) = Null(); + } rp->rowReady(); rowNum += 1; } while (matches.next()); diff --git a/project2/sqlMergeTask.cpp b/project2/sqlMergeTask.cpp index 0a9e07d..fdc6340 100644 --- a/project2/sqlMergeTask.cpp +++ b/project2/sqlMergeTask.cpp @@ -12,7 +12,7 @@ #include bool SqlMergeTask::defaultUseTempTable = true; -static void attach(IteratePtr i, ModifyCommand * insert); +static void attach(boost::intrusive_ptr i, ModifyCommand * insert); class SqlMergeInsert; typedef boost::intrusive_ptr SqlMergeInsertPtr; @@ -282,17 +282,17 @@ attach(SqlMergeInsertPtr i, ModifyCommand * insert) } static void -attach(IteratePtr i, ModifyCommand * insert) +attach(boost::intrusive_ptr i, ModifyCommand * insert) { if (!i) { return; } - if (i->normNOEs.empty()) { - i->normNOEs.push_back(new Populate(insert)); + if (i->normal.empty()) { + i->normal.push_back(new Populate(insert)); } else { - BOOST_FOREACH(const Iterate::SubNOEs::value_type & n, i->normNOEs) { - attach(boost::dynamic_pointer_cast(n), insert); + BOOST_FOREACH(const IHaveSubTasks::Tasks::value_type & n, i->normal) { + attach(boost::dynamic_pointer_cast(n), insert); attach(boost::dynamic_pointer_cast(n), insert); } } diff --git a/project2/structExceptHandling.cpp b/project2/structExceptHandling.cpp new file mode 100644 index 0000000..f87b870 --- /dev/null +++ b/project2/structExceptHandling.cpp @@ -0,0 +1,53 @@ +#include "structExceptHandling.h" +#include "xmlObjectLoader.h" +#include "xmlStorage.h" +#include + +DECLARE_LOADER("handler", StructuredExceptionHandler); + +static void +loadHelper(const char * name, const xmlpp::Element * root, ANONORDEREDSTORAGEOF(NoOutputExecute) * noes) +{ + LoaderBase loader(true); + loader.supportedStorers.insert(Storer::into(noes)); + BOOST_FOREACH(const xmlpp::Node * node, root->find(name)) { + const xmlpp::Element * elem = dynamic_cast(node); + if (elem) { + loader.collectAll(elem, true, ErrorOnUnsupported); + } + } +} + +StructuredExceptionHandler::StructuredExceptionHandler(const xmlpp::Element * e) : + SourceObject(e), + IHaveSubTasks(e) +{ + loadHelper("try", e, &normal); + loadHelper("catch", e, &catches); + loadHelper("finally", e, &finallies); +} + +void +StructuredExceptionHandler::loadComplete(const CommonObjects * co) +{ + IHaveSubTasks::loadComplete(co); +} + +void +StructuredExceptionHandler::execute() const +{ + try { + run(normal); + } + catch (...) { + try { + run(catches); + } + catch (...) { + } + run(finallies); + throw; + } + run(finallies); +} + diff --git a/project2/structExceptHandling.h b/project2/structExceptHandling.h new file mode 100644 index 0000000..eabd384 --- /dev/null +++ b/project2/structExceptHandling.h @@ -0,0 +1,18 @@ +#ifndef STRUCTUREDEXCEPTIONHANDLER_H +#define STRUCTUREDEXCEPTIONHANDLER_H + +#include "iHaveSubTasks.h" + +class StructuredExceptionHandler : public IHaveSubTasks { + public: + StructuredExceptionHandler(const xmlpp::Element *); + + void loadComplete(const CommonObjects*); + void execute() const; + + private: + Tasks catches, finallies; +}; + +#endif + diff --git a/project2/taskHost.cpp b/project2/taskHost.cpp index 0fc1453..63ab301 100644 --- a/project2/taskHost.cpp +++ b/project2/taskHost.cpp @@ -5,9 +5,11 @@ TaskHost::TaskHost(const boost::filesystem::path & file) : XmlScriptParser(file, false), - CheckHost(file) + SourceObject(get_document()->get_root_node()), + CheckHost(file), + IHaveSubTasks(get_document()->get_root_node()) { - loader.supportedStorers.insert(new NOEErrorStorer(&normTasks, &errorTasks)); + loader.supportedStorers.insert(Storer::into(&tasks)); } TaskHost::~TaskHost() @@ -15,40 +17,21 @@ TaskHost::~TaskHost() } void -TaskHost::executeTasks() const +TaskHost::loadComplete(const CommonObjects * co) +{ + IHaveSubTasks::loadComplete(co); +} + +void +TaskHost::execute() const { parseDocument(); try { - run(normTasks); + run(tasks); 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(); + rollbackAll(); } } diff --git a/project2/taskHost.h b/project2/taskHost.h index 290c841..ca8275c 100644 --- a/project2/taskHost.h +++ b/project2/taskHost.h @@ -4,28 +4,24 @@ #include "xmlStorage.h" #include "xmlScriptParser.h" #include "checkHost.h" +#include "iHaveSubTasks.h" class NoOutputExecute; class DataSource; -class TaskHost : virtual public XmlScriptParser, virtual public CheckHost { +class TaskHost : virtual public XmlScriptParser, public IHaveSubTasks, virtual public CheckHost { protected: - typedef ANONORDEREDSTORAGEOF(NoOutputExecute) Tasks; - TaskHost(const boost::filesystem::path & file); virtual ~TaskHost(); - void executeTasks() const; + void loadComplete(const CommonObjects *); + void execute() const; - Tasks normTasks; - Tasks errorTasks; - bool rollbackBeforeHandle; - bool localErrorHandling; + Tasks tasks; private: void commitAll() const; void rollbackAll() const; - void run(const Tasks &) const; }; #endif diff --git a/project2/validDateCheck.cpp b/project2/validDateCheck.cpp new file mode 100644 index 0000000..410a003 --- /dev/null +++ b/project2/validDateCheck.cpp @@ -0,0 +1,68 @@ +#include "logger.h" +#include "xmlObjectLoader.h" +#include "commonObjects.h" +#include "paramChecker.h" +#include "variables.h" + +class ValidDateCheck : public ParamChecker { + public: + ValidDateCheck(const xmlpp::Element * p) : + ParamChecker(p), + applyTo(p, "apply-to"), + format(p, "format"), + warnLev(p->get_attribute_value("warn") == "no" ? LOG_INFO : LOG_WARNING) + { + } + + ~ValidDateCheck() + { + } + + void + loadComplete(const CommonObjects *) + { + } + + bool + performCheck() const + { + struct tm tm, ftm; + memset(&tm, 0, sizeof(struct tm)); + mktime(&tm); + const char * at = applyTo(); + const char * f = format(); + const char * s = strptime(at, f, &tm); + if (!s || *s) { + Logger()->messagef(warnLev, "%s: check failed (parse) for '%s' against '%s'", + __PRETTY_FUNCTION__, at, f); + return false; + } + ftm = tm; + if (mktime(&ftm) == -1) { + Logger()->messagef(warnLev, "%s: check failed (normalise) for '%s' against '%s'", + __PRETTY_FUNCTION__, at, f); + return false; + } + if (tm.tm_year != ftm.tm_year || + tm.tm_mon != ftm.tm_mon || + tm.tm_mday != ftm.tm_mday || + tm.tm_hour != (ftm.tm_hour - ftm.tm_isdst) || + tm.tm_min != ftm.tm_min || + tm.tm_sec != ftm.tm_sec) { + Logger()->messagef(LOG_INFO, "tm: %d %d %d %d %d %d", + tm.tm_year, tm.tm_mon, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); + Logger()->messagef(LOG_INFO, "ftm: %d %d %d %d %d %d", + ftm.tm_year, ftm.tm_mon, ftm.tm_mday, ftm.tm_hour, ftm.tm_min, ftm.tm_sec); + Logger()->messagef(warnLev, "%s: check failed (verify) for '%s' against '%s'", + __PRETTY_FUNCTION__, at, f); + return false; + } + return true; + } + Variable applyTo; + Variable format; + int warnLev; +}; + +DECLARE_LOADER("validdatecheck", ValidDateCheck); + diff --git a/project2/xslPreFetch.cpp b/project2/xslPreFetch.cpp index 7486c9f..b70d83c 100644 --- a/project2/xslPreFetch.cpp +++ b/project2/xslPreFetch.cpp @@ -6,7 +6,7 @@ DECLARE_LOADER("xslprefetch", XslPreFetch); XslPreFetch::XslPreFetch(const xmlpp::Element * p) : SourceObject(p), View(p), - NoOutputExecute(p), + Task(p), CurlHelper(p), html(p->get_attribute_value("html") == "true"), warnings(p->get_attribute_value("warnings") != "false"), diff --git a/project2/xslPreFetch.h b/project2/xslPreFetch.h index 000166d..c9e6a9a 100644 --- a/project2/xslPreFetch.h +++ b/project2/xslPreFetch.h @@ -4,11 +4,11 @@ #include "xslRowsCache.h" #include "curlHelper.h" #include "view.h" -#include "noOutputExecute.h" +#include "task.h" #include /// Project2 component to queue up CURL objects to be downloaded -class XslPreFetch : public View, public NoOutputExecute, XslRowsCache, CurlHelper { +class XslPreFetch : public View, public Task, XslRowsCache, CurlHelper { public: XslPreFetch(const xmlpp::Element * p); ~XslPreFetch(); -- cgit v1.2.3