From 05b8bed896e5fe8c1841869e5d6e8e837e72c10a Mon Sep 17 00:00:00 2001 From: randomdan Date: Wed, 31 Aug 2011 21:48:04 +0000 Subject: The big reshuffle --- project2/Jamfile.jam | 241 +-------------- project2/appEngine.cpp | 50 ---- project2/appEngine.h | 44 --- project2/cache.cpp | 42 --- project2/cache.h | 29 -- project2/cgi/Jamfile.jam | 48 +++ project2/cgi/cgiAppEngine.cpp | 6 +- project2/cgi/cgiAppEngine.h | 20 +- project2/cgi/cgiCommon.cpp | 2 +- project2/cgi/cgiEnvironment.cpp | 4 +- project2/cgi/cgiEnvironment.h | 2 +- project2/cgi/cgiStageCustomError.cpp | 2 +- project2/cgi/cgiStageCustomNotFound.cpp | 2 +- project2/cgi/cgiStageDefaultError.cpp | 2 +- project2/cgi/cgiStageDefaultNotFound.cpp | 2 +- project2/cgi/cgiStageInitial.cpp | 2 +- project2/cgi/cgiStageRequest.cpp | 2 +- project2/cgi/p2webCgi.cpp | 2 +- project2/cgi/p2webFCgi.cpp | 2 +- project2/checkHost.cpp | 34 --- project2/checkHost.h | 29 -- project2/columns.cpp | 23 -- project2/columns.h | 33 --- project2/common/Jamfile.jam | 40 +++ project2/common/appEngine.cpp | 50 ++++ project2/common/appEngine.h | 44 +++ project2/common/cache.cpp | 42 +++ project2/common/cache.h | 29 ++ project2/common/checkHost.cpp | 34 +++ project2/common/checkHost.h | 29 ++ project2/common/columns.cpp | 23 ++ project2/common/columns.h | 33 +++ project2/common/commonObjects.cpp | 36 +++ project2/common/commonObjects.h | 40 +++ project2/common/config.cpp | 79 +++++ project2/common/config.h | 43 +++ project2/common/dataSource.cpp | 11 + project2/common/dataSource.h | 22 ++ project2/common/definedColumns.cpp | 31 ++ project2/common/definedColumns.h | 29 ++ project2/common/environment.cpp | 121 ++++++++ project2/common/environment.h | 51 ++++ project2/common/exceptions.cpp | 26 ++ project2/common/exceptions.h | 44 +++ project2/common/fileStarGlibIoChannel.cpp | 65 +++++ project2/common/fileStarGlibIoChannel.h | 26 ++ project2/common/fileStrmVarWriter.cpp | 61 ++++ project2/common/fileStrmVarWriter.h | 31 ++ project2/common/iHaveParameters.cpp | 61 ++++ project2/common/iHaveParameters.h | 33 +++ project2/common/iHaveSubTasks.cpp | 26 ++ project2/common/iHaveSubTasks.h | 25 ++ project2/common/if.cpp | 85 ++++++ project2/common/if.h | 38 +++ project2/common/iterate.cpp | 49 ++++ project2/common/iterate.h | 28 ++ project2/common/library.cpp | 41 +++ project2/common/library.h | 17 ++ project2/common/logger.cpp | 182 ++++++++++++ project2/common/logger.h | 43 +++ project2/common/loggers.h | 60 ++++ project2/common/noOutputExecute.cpp | 17 ++ project2/common/noOutputExecute.h | 22 ++ project2/common/ostreamWrapper.h | 14 + project2/common/paramChecker.cpp | 15 + project2/common/paramChecker.h | 24 ++ project2/common/presenter.cpp | 50 ++++ project2/common/presenter.h | 55 ++++ project2/common/rowProcessor.cpp | 57 ++++ project2/common/rowProcessor.h | 37 +++ project2/common/rowSet.cpp | 99 +++++++ project2/common/rowSet.h | 65 +++++ project2/common/rowView.cpp | 73 +++++ project2/common/rowView.h | 33 +++ project2/common/safeMapFind.h | 27 ++ project2/common/scopeObject.cpp | 23 ++ project2/common/scopeObject.h | 20 ++ project2/common/session.cpp | 10 + project2/common/session.h | 33 +++ project2/common/sessionClearTask.cpp | 30 ++ project2/common/sessionClearTask.h | 26 ++ project2/common/sessionContainer.cpp | 19 ++ project2/common/sessionContainer.h | 37 +++ project2/common/sessionSetTask.cpp | 31 ++ project2/common/sessionSetTask.h | 28 ++ project2/common/sourceObject.cpp | 20 ++ project2/common/sourceObject.h | 26 ++ project2/common/structExceptHandling.cpp | 53 ++++ project2/common/structExceptHandling.h | 18 ++ project2/common/task.cpp | 13 + project2/common/task.h | 18 ++ project2/common/taskHost.cpp | 53 ++++ project2/common/taskHost.h | 28 ++ project2/common/transform.cpp | 37 +++ project2/common/transform.h | 70 +++++ project2/common/validDateCheck.cpp | 68 +++++ project2/common/variableConvert.cpp | 197 +++++++++++++ project2/common/variables-modconfig.cpp | 22 ++ project2/common/variables-modlocalparam.cpp | 31 ++ project2/common/variables-modlookup.cpp | 75 +++++ project2/common/variables-modparam.cpp | 30 ++ project2/common/variables-modsession.cpp | 30 ++ project2/common/variables-moduri.cpp | 30 ++ project2/common/variables.cpp | 381 ++++++++++++++++++++++++ project2/common/variables.h | 120 ++++++++ project2/common/view.cpp | 11 + project2/common/view.h | 19 ++ project2/common/viewHost.cpp | 100 +++++++ project2/common/viewHost.h | 46 +++ project2/common/xmlObjectLoader.cpp | 153 ++++++++++ project2/common/xmlObjectLoader.h | 136 +++++++++ project2/common/xmlScriptParser.cpp | 46 +++ project2/common/xmlScriptParser.h | 35 +++ project2/common/xmlStorage.h | 118 ++++++++ project2/commonObjects.cpp | 36 --- project2/commonObjects.h | 40 --- project2/config.cpp | 79 ----- project2/config.h | 43 --- project2/console/Jamfile.jam | 12 + project2/console/consoleAppEngine.cpp | 4 +- project2/console/consoleAppEngine.h | 16 +- project2/console/consoleEnvironment.cpp | 6 +- project2/console/consoleEnvironment.h | 2 +- project2/console/consolePresenter.h | 4 +- project2/console/p2consoleMain.cpp | 4 +- project2/curlHelper.cpp | 45 --- project2/curlHelper.h | 33 --- project2/dataSource.cpp | 11 - project2/dataSource.h | 22 -- project2/definedColumns.cpp | 31 -- project2/definedColumns.h | 29 -- project2/environment.cpp | 121 -------- project2/environment.h | 51 ---- project2/exceptions.cpp | 26 -- project2/exceptions.h | 44 --- project2/fileRows.cpp | 52 ---- project2/fileRows.h | 27 -- project2/fileStarGlibIoChannel.cpp | 65 ----- project2/fileStarGlibIoChannel.h | 26 -- project2/fileStrmVarWriter.cpp | 61 ---- project2/fileStrmVarWriter.h | 31 -- project2/files/Jamfile.jam | 20 ++ project2/files/fileRows.cpp | 52 ++++ project2/files/fileRows.h | 27 ++ project2/files/fsRows.cpp | 320 ++++++++++++++++++++ project2/files/fsRows.h | 69 +++++ project2/files/streamRows.cpp | 106 +++++++ project2/files/streamRows.h | 46 +++ project2/fsRows.cpp | 320 -------------------- project2/fsRows.h | 69 ----- project2/iHaveParameters.cpp | 61 ---- project2/iHaveParameters.h | 33 --- project2/iHaveSubTasks.cpp | 26 -- project2/iHaveSubTasks.h | 25 -- project2/if.cpp | 85 ------ project2/if.h | 38 --- project2/iterate.cpp | 49 ---- project2/iterate.h | 28 -- project2/library.cpp | 41 --- project2/library.h | 17 -- project2/logger.cpp | 182 ------------ project2/logger.h | 43 --- project2/loggers.h | 60 ---- project2/mail/Jamfile.jam | 15 + project2/mail/sendmailTask.cpp | 252 ++++++++++++++++ project2/mail/sendmailTask.h | 59 ++++ project2/noOutputExecute.cpp | 17 -- project2/noOutputExecute.h | 22 -- project2/ostreamWrapper.h | 14 - project2/paramChecker.cpp | 15 - project2/paramChecker.h | 24 -- project2/presenter.cpp | 50 ---- project2/presenter.h | 55 ---- project2/procRows.cpp | 46 --- project2/procRows.h | 18 -- project2/processes/Jamfile.jam | 13 + project2/processes/procRows.cpp | 46 +++ project2/processes/procRows.h | 18 ++ project2/rawView.cpp | 55 ---- project2/rawView.h | 22 -- project2/rdbmsDataSource.cpp | 219 -------------- project2/rdbmsDataSource.h | 92 ------ project2/regex/Jamfile.jam | 12 + project2/regex/regexCheck.cpp | 30 ++ project2/regex/regexCheck.h | 20 ++ project2/regex/regexRows.cpp | 43 +++ project2/regex/regexRows.h | 21 ++ project2/regexCheck.cpp | 30 -- project2/regexCheck.h | 20 -- project2/regexRows.cpp | 43 --- project2/regexRows.h | 21 -- project2/rowProcessor.cpp | 57 ---- project2/rowProcessor.h | 37 --- project2/rowSet.cpp | 99 ------- project2/rowSet.h | 65 ----- project2/rowView.cpp | 73 ----- project2/rowView.h | 33 --- project2/safeMapFind.h | 27 -- project2/scopeObject.cpp | 23 -- project2/scopeObject.h | 20 -- project2/sendmailTask.cpp | 252 ---------------- project2/sendmailTask.h | 59 ---- project2/session.cpp | 10 - project2/session.h | 33 --- project2/sessionClearTask.cpp | 30 -- project2/sessionClearTask.h | 26 -- project2/sessionContainer.cpp | 19 -- project2/sessionContainer.h | 37 --- project2/sessionSetTask.cpp | 31 -- project2/sessionSetTask.h | 28 -- project2/sessionXml.cpp | 184 ------------ project2/sessionXml.h | 24 -- project2/sourceObject.cpp | 20 -- project2/sourceObject.h | 26 -- project2/sql-modODBC.cpp | 4 - project2/sql-modPQ.cpp | 4 - project2/sql/Jamfile.jam | 38 +++ project2/sql/connectionLoader.h | 19 ++ project2/sql/rdbmsDataSource.cpp | 220 ++++++++++++++ project2/sql/rdbmsDataSource.h | 78 +++++ project2/sql/sql-modODBC.cpp | 4 + project2/sql/sql-modPQ.cpp | 4 + project2/sql/sqlCache.cpp | 300 +++++++++++++++++++ project2/sql/sqlCheck.cpp | 100 +++++++ project2/sql/sqlCheck.h | 29 ++ project2/sql/sqlHandleAsVariableType.cpp | 19 ++ project2/sql/sqlHandleAsVariableType.h | 18 ++ project2/sql/sqlMergeTask.cpp | 329 +++++++++++++++++++++ project2/sql/sqlMergeTask.h | 79 +++++ project2/sql/sqlRows.cpp | 69 +++++ project2/sql/sqlRows.h | 40 +++ project2/sql/sqlTask.cpp | 70 +++++ project2/sql/sqlTask.h | 36 +++ project2/sql/sqlVariableBinder.cpp | 77 +++++ project2/sql/sqlVariableBinder.h | 36 +++ project2/sql/sqlWriter.cpp | 131 +++++++++ project2/sql/sqlWriter.h | 63 ++++ project2/sql/tablepatch.cpp | 438 ++++++++++++++++++++++++++++ project2/sql/tablepatch.h | 42 +++ project2/sqlCache.cpp | 300 ------------------- project2/sqlCheck.cpp | 100 ------- project2/sqlCheck.h | 29 -- project2/sqlHandleAsVariableType.cpp | 19 -- project2/sqlHandleAsVariableType.h | 18 -- project2/sqlMergeTask.cpp | 329 --------------------- project2/sqlMergeTask.h | 79 ----- project2/sqlRows.cpp | 69 ----- project2/sqlRows.h | 40 --- project2/sqlTask.cpp | 70 ----- project2/sqlTask.h | 36 --- project2/sqlVariableBinder.cpp | 77 ----- project2/sqlVariableBinder.h | 36 --- project2/sqlWriter.cpp | 131 --------- project2/sqlWriter.h | 63 ---- project2/streamRows.cpp | 106 ------- project2/streamRows.h | 46 --- project2/structExceptHandling.cpp | 53 ---- project2/structExceptHandling.h | 18 -- project2/tablepatch.cpp | 438 ---------------------------- project2/tablepatch.h | 42 --- project2/task.cpp | 13 - project2/task.h | 18 -- project2/taskHost.cpp | 53 ---- project2/taskHost.h | 28 -- project2/transform.cpp | 37 --- project2/transform.h | 70 ----- project2/transformHtml.cpp | 30 -- project2/transformHtml.h | 15 - project2/transformText.cpp | 38 --- project2/transformText.h | 15 - project2/url/Jamfile.jam | 20 ++ project2/url/curlHelper.cpp | 45 +++ project2/url/curlHelper.h | 33 +++ project2/url/urlRows.cpp | 69 +++++ project2/url/urlRows.h | 34 +++ project2/urlRows.cpp | 69 ----- project2/urlRows.h | 34 --- project2/uuid.cpp | 129 -------- project2/uuid.h | 31 -- project2/uuid/Jamfile.jam | 12 + project2/uuid/uuid.cpp | 129 ++++++++ project2/uuid/uuid.h | 31 ++ project2/validDateCheck.cpp | 68 ----- project2/variableConvert.cpp | 197 ------------- project2/variables-modconfig.cpp | 22 -- project2/variables-modlocalparam.cpp | 31 -- project2/variables-modlookup.cpp | 75 ----- project2/variables-modparam.cpp | 30 -- project2/variables-modsession.cpp | 30 -- project2/variables-moduri.cpp | 30 -- project2/variables.cpp | 381 ------------------------ project2/variables.h | 120 -------- project2/view.cpp | 11 - project2/view.h | 19 -- project2/viewHost.cpp | 100 ------- project2/viewHost.h | 46 --- project2/xml/Jamfile.jam | 25 ++ project2/xml/rawView.cpp | 55 ++++ project2/xml/rawView.h | 22 ++ project2/xml/sessionXml.cpp | 184 ++++++++++++ project2/xml/sessionXml.h | 24 ++ project2/xml/transformHtml.cpp | 30 ++ project2/xml/transformHtml.h | 15 + project2/xml/transformText.cpp | 38 +++ project2/xml/transformText.h | 15 + project2/xml/xmlCache.cpp | 143 +++++++++ project2/xml/xmlMemCache.cpp | 120 ++++++++ project2/xml/xmlPresenter.cpp | 97 ++++++ project2/xml/xmlPresenter.h | 38 +++ project2/xml/xmlRawRows.cpp | 113 +++++++ project2/xml/xmlRawRows.h | 38 +++ project2/xml/xmlRows.cpp | 136 +++++++++ project2/xml/xmlRows.h | 41 +++ project2/xml/xslPreFetch.cpp | 56 ++++ project2/xml/xslPreFetch.h | 30 ++ project2/xml/xslRows.cpp | 159 ++++++++++ project2/xml/xslRows.h | 64 ++++ project2/xml/xslRowsCache.cpp | 85 ++++++ project2/xml/xslRowsCache.h | 35 +++ project2/xmlCache.cpp | 143 --------- project2/xmlMemCache.cpp | 120 -------- project2/xmlObjectLoader.cpp | 153 ---------- project2/xmlObjectLoader.h | 136 --------- project2/xmlPresenter.cpp | 97 ------ project2/xmlPresenter.h | 38 --- project2/xmlRawRows.cpp | 113 ------- project2/xmlRawRows.h | 38 --- project2/xmlRows.cpp | 136 --------- project2/xmlRows.h | 41 --- project2/xmlScriptParser.cpp | 46 --- project2/xmlScriptParser.h | 35 --- project2/xmlStorage.h | 118 -------- project2/xslPreFetch.cpp | 56 ---- project2/xslPreFetch.h | 30 -- project2/xslRows.cpp | 159 ---------- project2/xslRows.h | 64 ---- project2/xslRowsCache.cpp | 85 ------ project2/xslRowsCache.h | 35 --- 338 files changed, 10020 insertions(+), 9968 deletions(-) delete mode 100644 project2/appEngine.cpp delete mode 100644 project2/appEngine.h delete mode 100644 project2/cache.cpp delete mode 100644 project2/cache.h create mode 100644 project2/cgi/Jamfile.jam delete mode 100644 project2/checkHost.cpp delete mode 100644 project2/checkHost.h delete mode 100644 project2/columns.cpp delete mode 100644 project2/columns.h create mode 100644 project2/common/Jamfile.jam create mode 100644 project2/common/appEngine.cpp create mode 100644 project2/common/appEngine.h create mode 100644 project2/common/cache.cpp create mode 100644 project2/common/cache.h create mode 100644 project2/common/checkHost.cpp create mode 100644 project2/common/checkHost.h create mode 100644 project2/common/columns.cpp create mode 100644 project2/common/columns.h create mode 100644 project2/common/commonObjects.cpp create mode 100644 project2/common/commonObjects.h create mode 100644 project2/common/config.cpp create mode 100644 project2/common/config.h create mode 100644 project2/common/dataSource.cpp create mode 100644 project2/common/dataSource.h create mode 100644 project2/common/definedColumns.cpp create mode 100644 project2/common/definedColumns.h create mode 100644 project2/common/environment.cpp create mode 100644 project2/common/environment.h create mode 100644 project2/common/exceptions.cpp create mode 100644 project2/common/exceptions.h create mode 100644 project2/common/fileStarGlibIoChannel.cpp create mode 100644 project2/common/fileStarGlibIoChannel.h create mode 100644 project2/common/fileStrmVarWriter.cpp create mode 100644 project2/common/fileStrmVarWriter.h create mode 100644 project2/common/iHaveParameters.cpp create mode 100644 project2/common/iHaveParameters.h create mode 100644 project2/common/iHaveSubTasks.cpp create mode 100644 project2/common/iHaveSubTasks.h create mode 100644 project2/common/if.cpp create mode 100644 project2/common/if.h create mode 100644 project2/common/iterate.cpp create mode 100644 project2/common/iterate.h create mode 100644 project2/common/library.cpp create mode 100644 project2/common/library.h create mode 100644 project2/common/logger.cpp create mode 100644 project2/common/logger.h create mode 100644 project2/common/loggers.h create mode 100644 project2/common/noOutputExecute.cpp create mode 100644 project2/common/noOutputExecute.h create mode 100644 project2/common/ostreamWrapper.h create mode 100644 project2/common/paramChecker.cpp create mode 100644 project2/common/paramChecker.h create mode 100644 project2/common/presenter.cpp create mode 100644 project2/common/presenter.h create mode 100644 project2/common/rowProcessor.cpp create mode 100644 project2/common/rowProcessor.h create mode 100644 project2/common/rowSet.cpp create mode 100644 project2/common/rowSet.h create mode 100644 project2/common/rowView.cpp create mode 100644 project2/common/rowView.h create mode 100644 project2/common/safeMapFind.h create mode 100644 project2/common/scopeObject.cpp create mode 100644 project2/common/scopeObject.h create mode 100644 project2/common/session.cpp create mode 100644 project2/common/session.h create mode 100644 project2/common/sessionClearTask.cpp create mode 100644 project2/common/sessionClearTask.h create mode 100644 project2/common/sessionContainer.cpp create mode 100644 project2/common/sessionContainer.h create mode 100644 project2/common/sessionSetTask.cpp create mode 100644 project2/common/sessionSetTask.h create mode 100644 project2/common/sourceObject.cpp create mode 100644 project2/common/sourceObject.h create mode 100644 project2/common/structExceptHandling.cpp create mode 100644 project2/common/structExceptHandling.h create mode 100644 project2/common/task.cpp create mode 100644 project2/common/task.h create mode 100644 project2/common/taskHost.cpp create mode 100644 project2/common/taskHost.h create mode 100644 project2/common/transform.cpp create mode 100644 project2/common/transform.h create mode 100644 project2/common/validDateCheck.cpp create mode 100644 project2/common/variableConvert.cpp create mode 100644 project2/common/variables-modconfig.cpp create mode 100644 project2/common/variables-modlocalparam.cpp create mode 100644 project2/common/variables-modlookup.cpp create mode 100644 project2/common/variables-modparam.cpp create mode 100644 project2/common/variables-modsession.cpp create mode 100644 project2/common/variables-moduri.cpp create mode 100644 project2/common/variables.cpp create mode 100644 project2/common/variables.h create mode 100644 project2/common/view.cpp create mode 100644 project2/common/view.h create mode 100644 project2/common/viewHost.cpp create mode 100644 project2/common/viewHost.h create mode 100644 project2/common/xmlObjectLoader.cpp create mode 100644 project2/common/xmlObjectLoader.h create mode 100644 project2/common/xmlScriptParser.cpp create mode 100644 project2/common/xmlScriptParser.h create mode 100644 project2/common/xmlStorage.h delete mode 100644 project2/commonObjects.cpp delete mode 100644 project2/commonObjects.h delete mode 100644 project2/config.cpp delete mode 100644 project2/config.h create mode 100644 project2/console/Jamfile.jam delete mode 100644 project2/curlHelper.cpp delete mode 100644 project2/curlHelper.h delete mode 100644 project2/dataSource.cpp delete mode 100644 project2/dataSource.h delete mode 100644 project2/definedColumns.cpp delete mode 100644 project2/definedColumns.h delete mode 100644 project2/environment.cpp delete mode 100644 project2/environment.h delete mode 100644 project2/exceptions.cpp delete mode 100644 project2/exceptions.h delete mode 100644 project2/fileRows.cpp delete mode 100644 project2/fileRows.h delete mode 100644 project2/fileStarGlibIoChannel.cpp delete mode 100644 project2/fileStarGlibIoChannel.h delete mode 100644 project2/fileStrmVarWriter.cpp delete mode 100644 project2/fileStrmVarWriter.h create mode 100644 project2/files/Jamfile.jam create mode 100644 project2/files/fileRows.cpp create mode 100644 project2/files/fileRows.h create mode 100644 project2/files/fsRows.cpp create mode 100644 project2/files/fsRows.h create mode 100644 project2/files/streamRows.cpp create mode 100644 project2/files/streamRows.h delete mode 100644 project2/fsRows.cpp delete mode 100644 project2/fsRows.h delete mode 100644 project2/iHaveParameters.cpp delete mode 100644 project2/iHaveParameters.h delete mode 100644 project2/iHaveSubTasks.cpp delete mode 100644 project2/iHaveSubTasks.h delete mode 100644 project2/if.cpp delete mode 100644 project2/if.h delete mode 100644 project2/iterate.cpp delete mode 100644 project2/iterate.h delete mode 100644 project2/library.cpp delete mode 100644 project2/library.h delete mode 100644 project2/logger.cpp delete mode 100644 project2/logger.h delete mode 100644 project2/loggers.h create mode 100644 project2/mail/Jamfile.jam create mode 100644 project2/mail/sendmailTask.cpp create mode 100644 project2/mail/sendmailTask.h delete mode 100644 project2/noOutputExecute.cpp delete mode 100644 project2/noOutputExecute.h delete mode 100644 project2/ostreamWrapper.h delete mode 100644 project2/paramChecker.cpp delete mode 100644 project2/paramChecker.h delete mode 100644 project2/presenter.cpp delete mode 100644 project2/presenter.h delete mode 100644 project2/procRows.cpp delete mode 100644 project2/procRows.h create mode 100644 project2/processes/Jamfile.jam create mode 100644 project2/processes/procRows.cpp create mode 100644 project2/processes/procRows.h delete mode 100644 project2/rawView.cpp delete mode 100644 project2/rawView.h delete mode 100644 project2/rdbmsDataSource.cpp delete mode 100644 project2/rdbmsDataSource.h create mode 100644 project2/regex/Jamfile.jam create mode 100644 project2/regex/regexCheck.cpp create mode 100644 project2/regex/regexCheck.h create mode 100644 project2/regex/regexRows.cpp create mode 100644 project2/regex/regexRows.h delete mode 100644 project2/regexCheck.cpp delete mode 100644 project2/regexCheck.h delete mode 100644 project2/regexRows.cpp delete mode 100644 project2/regexRows.h delete mode 100644 project2/rowProcessor.cpp delete mode 100644 project2/rowProcessor.h delete mode 100644 project2/rowSet.cpp delete mode 100644 project2/rowSet.h delete mode 100644 project2/rowView.cpp delete mode 100644 project2/rowView.h delete mode 100644 project2/safeMapFind.h delete mode 100644 project2/scopeObject.cpp delete mode 100644 project2/scopeObject.h delete mode 100644 project2/sendmailTask.cpp delete mode 100644 project2/sendmailTask.h delete mode 100644 project2/session.cpp delete mode 100644 project2/session.h delete mode 100644 project2/sessionClearTask.cpp delete mode 100644 project2/sessionClearTask.h delete mode 100644 project2/sessionContainer.cpp delete mode 100644 project2/sessionContainer.h delete mode 100644 project2/sessionSetTask.cpp delete mode 100644 project2/sessionSetTask.h delete mode 100644 project2/sessionXml.cpp delete mode 100644 project2/sessionXml.h delete mode 100644 project2/sourceObject.cpp delete mode 100644 project2/sourceObject.h delete mode 100644 project2/sql-modODBC.cpp delete mode 100644 project2/sql-modPQ.cpp create mode 100644 project2/sql/Jamfile.jam create mode 100644 project2/sql/connectionLoader.h create mode 100644 project2/sql/rdbmsDataSource.cpp create mode 100644 project2/sql/rdbmsDataSource.h create mode 100644 project2/sql/sql-modODBC.cpp create mode 100644 project2/sql/sql-modPQ.cpp create mode 100644 project2/sql/sqlCache.cpp create mode 100644 project2/sql/sqlCheck.cpp create mode 100644 project2/sql/sqlCheck.h create mode 100644 project2/sql/sqlHandleAsVariableType.cpp create mode 100644 project2/sql/sqlHandleAsVariableType.h create mode 100644 project2/sql/sqlMergeTask.cpp create mode 100644 project2/sql/sqlMergeTask.h create mode 100644 project2/sql/sqlRows.cpp create mode 100644 project2/sql/sqlRows.h create mode 100644 project2/sql/sqlTask.cpp create mode 100644 project2/sql/sqlTask.h create mode 100644 project2/sql/sqlVariableBinder.cpp create mode 100644 project2/sql/sqlVariableBinder.h create mode 100644 project2/sql/sqlWriter.cpp create mode 100644 project2/sql/sqlWriter.h create mode 100644 project2/sql/tablepatch.cpp create mode 100644 project2/sql/tablepatch.h delete mode 100644 project2/sqlCache.cpp delete mode 100644 project2/sqlCheck.cpp delete mode 100644 project2/sqlCheck.h delete mode 100644 project2/sqlHandleAsVariableType.cpp delete mode 100644 project2/sqlHandleAsVariableType.h delete mode 100644 project2/sqlMergeTask.cpp delete mode 100644 project2/sqlMergeTask.h delete mode 100644 project2/sqlRows.cpp delete mode 100644 project2/sqlRows.h delete mode 100644 project2/sqlTask.cpp delete mode 100644 project2/sqlTask.h delete mode 100644 project2/sqlVariableBinder.cpp delete mode 100644 project2/sqlVariableBinder.h delete mode 100644 project2/sqlWriter.cpp delete mode 100644 project2/sqlWriter.h delete mode 100644 project2/streamRows.cpp delete mode 100644 project2/streamRows.h delete mode 100644 project2/structExceptHandling.cpp delete mode 100644 project2/structExceptHandling.h delete mode 100644 project2/tablepatch.cpp delete mode 100644 project2/tablepatch.h delete mode 100644 project2/task.cpp delete mode 100644 project2/task.h delete mode 100644 project2/taskHost.cpp delete mode 100644 project2/taskHost.h delete mode 100644 project2/transform.cpp delete mode 100644 project2/transform.h delete mode 100644 project2/transformHtml.cpp delete mode 100644 project2/transformHtml.h delete mode 100644 project2/transformText.cpp delete mode 100644 project2/transformText.h create mode 100644 project2/url/Jamfile.jam create mode 100644 project2/url/curlHelper.cpp create mode 100644 project2/url/curlHelper.h create mode 100644 project2/url/urlRows.cpp create mode 100644 project2/url/urlRows.h delete mode 100644 project2/urlRows.cpp delete mode 100644 project2/urlRows.h delete mode 100644 project2/uuid.cpp delete mode 100644 project2/uuid.h create mode 100644 project2/uuid/Jamfile.jam create mode 100644 project2/uuid/uuid.cpp create mode 100644 project2/uuid/uuid.h delete mode 100644 project2/validDateCheck.cpp delete mode 100644 project2/variableConvert.cpp delete mode 100644 project2/variables-modconfig.cpp delete mode 100644 project2/variables-modlocalparam.cpp delete mode 100644 project2/variables-modlookup.cpp delete mode 100644 project2/variables-modparam.cpp delete mode 100644 project2/variables-modsession.cpp delete mode 100644 project2/variables-moduri.cpp delete mode 100644 project2/variables.cpp delete mode 100644 project2/variables.h delete mode 100644 project2/view.cpp delete mode 100644 project2/view.h delete mode 100644 project2/viewHost.cpp delete mode 100644 project2/viewHost.h create mode 100644 project2/xml/Jamfile.jam create mode 100644 project2/xml/rawView.cpp create mode 100644 project2/xml/rawView.h create mode 100644 project2/xml/sessionXml.cpp create mode 100644 project2/xml/sessionXml.h create mode 100644 project2/xml/transformHtml.cpp create mode 100644 project2/xml/transformHtml.h create mode 100644 project2/xml/transformText.cpp create mode 100644 project2/xml/transformText.h create mode 100644 project2/xml/xmlCache.cpp create mode 100644 project2/xml/xmlMemCache.cpp create mode 100644 project2/xml/xmlPresenter.cpp create mode 100644 project2/xml/xmlPresenter.h create mode 100644 project2/xml/xmlRawRows.cpp create mode 100644 project2/xml/xmlRawRows.h create mode 100644 project2/xml/xmlRows.cpp create mode 100644 project2/xml/xmlRows.h create mode 100644 project2/xml/xslPreFetch.cpp create mode 100644 project2/xml/xslPreFetch.h create mode 100644 project2/xml/xslRows.cpp create mode 100644 project2/xml/xslRows.h create mode 100644 project2/xml/xslRowsCache.cpp create mode 100644 project2/xml/xslRowsCache.h delete mode 100644 project2/xmlCache.cpp delete mode 100644 project2/xmlMemCache.cpp delete mode 100644 project2/xmlObjectLoader.cpp delete mode 100644 project2/xmlObjectLoader.h delete mode 100644 project2/xmlPresenter.cpp delete mode 100644 project2/xmlPresenter.h delete mode 100644 project2/xmlRawRows.cpp delete mode 100644 project2/xmlRawRows.h delete mode 100644 project2/xmlRows.cpp delete mode 100644 project2/xmlRows.h delete mode 100644 project2/xmlScriptParser.cpp delete mode 100644 project2/xmlScriptParser.h delete mode 100644 project2/xmlStorage.h delete mode 100644 project2/xslPreFetch.cpp delete mode 100644 project2/xslPreFetch.h delete mode 100644 project2/xslRows.cpp delete mode 100644 project2/xslRows.h delete mode 100644 project2/xslRowsCache.cpp delete mode 100644 project2/xslRowsCache.h diff --git a/project2/Jamfile.jam b/project2/Jamfile.jam index 96acca0..e0797a3 100644 --- a/project2/Jamfile.jam +++ b/project2/Jamfile.jam @@ -1,241 +1,32 @@ import package ; import feature : feature ; -alias glibmm : : : : - "`pkg-config --cflags glibmm-2.4`" - "`pkg-config --libs glibmm-2.4`" - ; - -alias libxmlpp : : : : - "`pkg-config --cflags libxml++-2.6`" - "`pkg-config --libs libxml++-2.6`" ; -alias libxslt : : : : - "`pkg-config --cflags libexslt`" - "`pkg-config --libs libexslt`" ; - -lib dl : : dl ; -lib fcgi : : fcgi ; -lib fcgi++ : : fcgi++ ; -lib boost_system : : boost_system ; -lib boost_filesystem : : boost_filesystem ; -lib boost_date_time : : boost_date_time ; -lib boost_program_options : : boost_program_options ; -lib cgicc : : cgicc ; -lib esmtp : : esmtp ; -lib curl : : curl ; -lib osspuuid : : ossp-uuid++ ; - -alias p2parts : : : : - p2url - p2files - p2processes - p2sql - p2mail - p2regex - p2xml - ; - feature uuid : boost ossp : propagated ; feature odbc : yes no : propagated ; feature pq : yes no : propagated ; +alias p2parts : : : : + url//p2url + files//p2files + processes//p2processes + sql//p2sql + mail//p2mail + regex//p2regex + xml//p2xml + ; + project : requirements debug:"-W -Wall -Werror -Wwrite-strings" debug:"-Wl,-z,defs --warn-once" ; -lib p2uuid : - uuid.cpp - : - ossp:OSSP_UUID - boost:BOOST_UUID - ossp:osspuuid - ; - -lib p2common : - appEngine.cpp dataSource.cpp environment.cpp fileStarGlibIoChannel.cpp iHaveParameters.cpp library.cpp iHaveSubTasks.cpp - iterate.cpp paramChecker.cpp presenter.cpp logger.cpp if.cpp xmlScriptParser.cpp viewHost.cpp - sourceObject.cpp task.cpp variables.cpp variableConvert.cpp view.cpp xmlObjectLoader.cpp exceptions.cpp cache.cpp - sessionContainer.cpp sessionClearTask.cpp session.cpp sessionSetTask.cpp commonObjects.cpp taskHost.cpp checkHost.cpp - rowView.cpp rowSet.cpp rowProcessor.cpp config.cpp fileStrmVarWriter.cpp noOutputExecute.cpp columns.cpp scopeObject.cpp - transform.cpp definedColumns.cpp structExceptHandling.cpp validDateCheck.cpp - variables-modconfig.cpp - variables-modlocalparam.cpp - variables-modlookup.cpp - variables-modparam.cpp - variables-modsession.cpp - variables-moduri.cpp - ../libmisc/buffer.cpp - ../libmisc/misc.cpp - : - ../libmisc - libxmlpp - dl - boost_system - boost_filesystem - boost_date_time - boost_program_options - : : - . - ../libmisc - boost_system - boost_program_options - ; - -lib p2xml : - rawView.cpp xmlPresenter.cpp transformHtml.cpp transformText.cpp xmlRows.cpp - xmlRawRows.cpp xslRows.cpp xslRowsCache.cpp xslPreFetch.cpp xmlMemCache.cpp xmlCache.cpp sessionXml.cpp - : - ../libmisc - libxmlpp - p2common - p2uuid - p2url - libxslt - boost_filesystem - : : - p2uuid - ; - -lib p2processes : - procRows.cpp - : - ../libmisc - libxmlpp - p2common - p2files - ; - -lib p2files : - fsRows.cpp - fileRows.cpp - streamRows.cpp - : - ../libmisc - libxmlpp - boost_filesystem - boost_system - p2common - ; - -lib p2regex : - regexCheck.cpp regexRows.cpp - : - ../libmisc - libxmlpp - p2common - ; - -explicit object sql-modODBC ; -obj sql-modODBC : - sql-modODBC.cpp : - ../libodbcpp//odbcpp - libxmlpp - ../libmisc - : : - ../libodbcpp//odbcpp - ; - -explicit object sql-modPQ ; -obj sql-modPQ : - sql-modPQ.cpp : - ../libpqpp//pqpp - libxmlpp - ../libmisc - : : - ../libpqpp//pqpp - ; - -lib p2sql : - sqlCheck.cpp sqlWriter.cpp sqlTask.cpp sqlMergeTask.cpp sqlRows.cpp sqlCache.cpp sqlVariableBinder.cpp tablepatch.cpp rdbmsDataSource.cpp - sqlHandleAsVariableType.cpp - ../libdbpp//dbpp - : - yes:sql-modODBC - yes:sql-modPQ - libxmlpp - p2common - ../libmisc - ; - -lib p2url : - urlRows.cpp - curlHelper.cpp - ../libmisc/curlsup.cpp - : - p2common - p2files - ../libmisc - libxmlpp - curl - : : - curl - ; - -lib p2mail : - sendmailTask.cpp - : - ../libmisc - libxmlpp - libxslt - esmtp - p2common - p2xml - ; - -lib p2web : - [ glob cgi/cgi*.cpp ] - : - ../libmisc - cgicc - glibmm - libxmlpp - p2common - p2uuid - boost_program_options - boost_filesystem - p2xml - : : - p2parts - cgicc - p2common - ; - -exe p2cgi : - cgi/p2webCgi.cpp - : - p2web - ../libmisc - ; - -exe p2fcgi : - cgi/p2webFCgi.cpp cgi/FCgiIO.cpp - fcgi++ - fcgi - : - p2web - ../libmisc - ; - -exe testCgi : - cgi/testCgi.cpp - : - p2web - ../libmisc - ; - -exe p2console : - [ glob console/*.cpp ] - : - p2parts - p2common - ../libmisc - ; +build-project console ; +build-project cgi ; explicit install installp2con installp2cgi installp2fcgi ; -package.install install : : p2console p2cgi p2fcgi ; -package.install installp2con : : p2console ; -package.install installp2cgi : : p2cgi ; -package.install installp2fcgi : : p2fcgi ; +package.install install : : console//p2console cgi//p2cgi cgi//p2fcgi ; +package.install installp2con : : console//p2console ; +package.install installp2cgi : : cgi//p2cgi ; +package.install installp2fcgi : : cgi//p2fcgi ; diff --git a/project2/appEngine.cpp b/project2/appEngine.cpp deleted file mode 100644 index d8c097b..0000000 --- a/project2/appEngine.cpp +++ /dev/null @@ -1,50 +0,0 @@ -#include "appEngine.h" -#include "logger.h" -#include -#include - -ApplicationEngine * ApplicationEngine::currentEngine = NULL; - -ApplicationEngine::ApplicationEngine(const Glib::ustring & engineKeys) : - Configuration(engineKeys) -{ - if (currentEngine) { - throw std::runtime_error("One application at a time, please"); - } - currentEngine = this; -} - -ApplicationEngine::~ApplicationEngine() -{ - currentEngine = NULL; -} - -void -ApplicationEngine::logMessage(bool writeLog, const Glib::ustring & g, const Glib::ustring & m) -{ - if (writeLog) { - Logger()->messagef(LOG_NOTICE, "%s: %s: %s", __PRETTY_FUNCTION__, g.c_str(), m.c_str()); - } - appMessages.push_back(new Message(g, m)); -} - -void -ApplicationEngine::addCoreAppData(const Presenter * p) const -{ - // Message log - p->pushSub("messages", env()->xmlPrefix); - BOOST_FOREACH(const Messages::value_type & m, appMessages) { - p->pushSub("message"); - p->addAttr("group", m->group); - p->addAttr("text", m->message); - p->popSub(); - } - p->popSub(); -} - -ApplicationEngine::Message::Message(const Glib::ustring & g, const Glib::ustring & m) : - group(g), - message(m) -{ -} - diff --git a/project2/appEngine.h b/project2/appEngine.h deleted file mode 100644 index 689f1b5..0000000 --- a/project2/appEngine.h +++ /dev/null @@ -1,44 +0,0 @@ -#ifndef APPENGINE_H -#define APPENGINE_H - -#include "environment.h" -#include "session.h" -#include "presenter.h" -#include "config.h" - -class ApplicationEngine : public Configuration { - public: - class Message : public IntrusivePtrBase { - public: - Message(const Glib::ustring & g, const Glib::ustring & m); - - const Glib::ustring group; - const Glib::ustring message; - }; - typedef boost::intrusive_ptr MessagePtr; - typedef std::list Messages; - - ApplicationEngine(const Glib::ustring & engineKeys); - virtual ~ApplicationEngine() = 0; - - void logMessage(bool writeLog, const Glib::ustring & g, const Glib::ustring & m); - - virtual void process() const = 0; - virtual const Environment * env() const = 0; - virtual SessionPtr session() const = 0; - virtual void addAppData(const Presenter * p) const = 0; - virtual void addEnvData(const Presenter * p) const = 0; - - static ApplicationEngine * getCurrent() { return currentEngine; } - - protected: - void addCoreAppData(const Presenter * p) const; - - Messages appMessages; - - private: - static ApplicationEngine * currentEngine; -}; - -#endif - diff --git a/project2/cache.cpp b/project2/cache.cpp deleted file mode 100644 index 1dc435f..0000000 --- a/project2/cache.cpp +++ /dev/null @@ -1,42 +0,0 @@ -#include "cache.h" -#include "rowSet.h" -#include "rowProcessor.h" -#include "logger.h" -#include - -Cache::Cache(const xmlpp::Element * p) : - IHaveParameters(p), - SourceObject(p), - inherit(p->get_attribute_value("inherit") != "false") -{ -} - -bool Cache::checkAndExecute(const Glib::ustring & n, const Glib::ustring & f, const RowProcessor * rp) -{ - RowSetCPtr cached = getCachedRowSet(n, f, rp); - if (cached) { - try { - Logger()->messagef(LOG_ERR, "Executing from cache"); - cached->execute(f, rp); - return true; - } - catch (...) { - Logger()->messagef(LOG_WARNING, "Cache failed"); - } - } - return false; -} - -void -Cache::applyKeys(const boost::function2 & f, const IHaveParameters * ps) const -{ - BOOST_FOREACH(const IHaveParameters::Parameters::value_type & p, allParameters()) { - f(p.first, p.second); - } - if (inherit) { - BOOST_FOREACH(const IHaveParameters::Parameters::value_type & p, ps->allParameters()) { - f(p.first, p.second); - } - } -} - diff --git a/project2/cache.h b/project2/cache.h deleted file mode 100644 index 899a01e..0000000 --- a/project2/cache.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef CACHE_H -#define CACHE_H - -#include "sourceObject.h" -#include "presenter.h" -#include "iHaveParameters.h" - -class RowProcessor; -class RowSet; -class RowState; -typedef boost::intrusive_ptr RowSetCPtr; - -class Cache : public IHaveParameters, public SourceObject { - public: - Cache(const xmlpp::Element * p); - - bool checkAndExecute(const Glib::ustring &, const Glib::ustring &, const RowProcessor *); - virtual PresenterPtr openFor(const Glib::ustring &, const Glib::ustring &, const IHaveParameters *) = 0; - virtual void close(const Glib::ustring &, const Glib::ustring &, const IHaveParameters *) = 0; - - protected: - virtual RowSetCPtr getCachedRowSet(const Glib::ustring &, const Glib::ustring &, const IHaveParameters *) const = 0; - void applyKeys(const boost::function2 & f, const IHaveParameters *) const; - const bool inherit; -}; -typedef boost::intrusive_ptr CachePtr; - -#endif - diff --git a/project2/cgi/Jamfile.jam b/project2/cgi/Jamfile.jam new file mode 100644 index 0000000..fe5a3d2 --- /dev/null +++ b/project2/cgi/Jamfile.jam @@ -0,0 +1,48 @@ +alias libxmlpp : : : : + "`pkg-config --cflags libxml++-2.6`" + "`pkg-config --libs libxml++-2.6`" ; +lib boost_filesystem : : boost_filesystem ; +lib boost_program_options : : boost_program_options ; +lib cgicc : : cgicc ; +lib fcgi : : fcgi ; +lib fcgi++ : : fcgi++ ; + +lib p2web : + [ glob cgi*.cpp ] + : + ../libmisc + cgicc + libxmlpp + ../common//p2common + boost_program_options + boost_filesystem + ../xml//p2xml + : : + ..//p2parts + cgicc + ../common//p2common + ; + +exe p2cgi : + p2webCgi.cpp + : + p2web + ../../libmisc + ; + +exe p2fcgi : + p2webFCgi.cpp FCgiIO.cpp + fcgi++ + fcgi + : + p2web + ../../libmisc + ; + +exe testCgi : + testCgi.cpp + : + p2web + ../../libmisc + ; + diff --git a/project2/cgi/cgiAppEngine.cpp b/project2/cgi/cgiAppEngine.cpp index aa08559..c01e4ac 100644 --- a/project2/cgi/cgiAppEngine.cpp +++ b/project2/cgi/cgiAppEngine.cpp @@ -2,11 +2,11 @@ #include #include #include "cgiEnvironment.h" -#include "../iterate.h" -#include "../logger.h" +#include "iterate.h" +#include "logger.h" #include #include -#include "../ostreamWrapper.h" +#include "ostreamWrapper.h" #include #include diff --git a/project2/cgi/cgiAppEngine.h b/project2/cgi/cgiAppEngine.h index 2109a31..0f534e8 100644 --- a/project2/cgi/cgiAppEngine.h +++ b/project2/cgi/cgiAppEngine.h @@ -1,16 +1,16 @@ #ifndef CGIAPPENGINE_H #define CGIAPPENGINE_H -#include "../appEngine.h" -#include "../task.h" -#include "../paramChecker.h" -#include "../commonObjects.h" -#include "../uuid.h" -#include "../taskHost.h" -#include "../viewHost.h" -#include "../transform.h" -#include "../xmlPresenter.h" -#include "../sessionContainer.h" +#include "appEngine.h" +#include "task.h" +#include "paramChecker.h" +#include "commonObjects.h" +#include "uuid.h" +#include "taskHost.h" +#include "viewHost.h" +#include "transform.h" +#include "xmlPresenter.h" +#include "sessionContainer.h" #include #include diff --git a/project2/cgi/cgiCommon.cpp b/project2/cgi/cgiCommon.cpp index b8a2b93..89808e1 100644 --- a/project2/cgi/cgiCommon.cpp +++ b/project2/cgi/cgiCommon.cpp @@ -1,5 +1,5 @@ #include "cgiCommon.h" -#include "../logger.h" +#include "logger.h" #include #include #include diff --git a/project2/cgi/cgiEnvironment.cpp b/project2/cgi/cgiEnvironment.cpp index 1382709..039ff98 100644 --- a/project2/cgi/cgiEnvironment.cpp +++ b/project2/cgi/cgiEnvironment.cpp @@ -1,6 +1,6 @@ #include "cgiEnvironment.h" -#include "../appEngine.h" -#include "../exceptions.h" +#include "appEngine.h" +#include "exceptions.h" #include #include diff --git a/project2/cgi/cgiEnvironment.h b/project2/cgi/cgiEnvironment.h index db39da8..fe99f5e 100644 --- a/project2/cgi/cgiEnvironment.h +++ b/project2/cgi/cgiEnvironment.h @@ -3,7 +3,7 @@ #include #include -#include "../environment.h" +#include "environment.h" #include namespace cgicc { diff --git a/project2/cgi/cgiStageCustomError.cpp b/project2/cgi/cgiStageCustomError.cpp index bc53c23..b223323 100644 --- a/project2/cgi/cgiStageCustomError.cpp +++ b/project2/cgi/cgiStageCustomError.cpp @@ -1,7 +1,7 @@ #include "cgiAppEngine.h" #include "cgiEnvironment.h" #include "cgiHttpHeader.h" -#include "../logger.h" +#include "logger.h" CgiApplicationEngine::CustomErrorStage::CustomErrorStage(const CgiEnvironment * env, const std::exception & ex) : CgiApplicationEngine::ResponseStage(env), diff --git a/project2/cgi/cgiStageCustomNotFound.cpp b/project2/cgi/cgiStageCustomNotFound.cpp index e0c6bfc..9575e94 100644 --- a/project2/cgi/cgiStageCustomNotFound.cpp +++ b/project2/cgi/cgiStageCustomNotFound.cpp @@ -1,7 +1,7 @@ #include "cgiAppEngine.h" #include "cgiEnvironment.h" #include "cgiHttpHeader.h" -#include "../logger.h" +#include "logger.h" CgiApplicationEngine::CustomNotFoundStage::CustomNotFoundStage(const CgiEnvironment * env, const ::XmlScriptParser::NotFound & notfound) : CgiApplicationEngine::ResponseStage(env), diff --git a/project2/cgi/cgiStageDefaultError.cpp b/project2/cgi/cgiStageDefaultError.cpp index 1843905..5828831 100644 --- a/project2/cgi/cgiStageDefaultError.cpp +++ b/project2/cgi/cgiStageDefaultError.cpp @@ -1,6 +1,6 @@ #include "cgiAppEngine.h" #include "cgiHttpHeader.h" -#include "../logger.h" +#include "logger.h" #include "cgiEnvironment.h" #include diff --git a/project2/cgi/cgiStageDefaultNotFound.cpp b/project2/cgi/cgiStageDefaultNotFound.cpp index 8359aa7..3407d0e 100644 --- a/project2/cgi/cgiStageDefaultNotFound.cpp +++ b/project2/cgi/cgiStageDefaultNotFound.cpp @@ -1,7 +1,7 @@ #include "cgiAppEngine.h" #include "cgiEnvironment.h" #include "cgiHttpHeader.h" -#include "../logger.h" +#include "logger.h" static const Glib::ustring DefaultNotFoundStageResp("notfound"); diff --git a/project2/cgi/cgiStageInitial.cpp b/project2/cgi/cgiStageInitial.cpp index 348cbb9..92595ef 100644 --- a/project2/cgi/cgiStageInitial.cpp +++ b/project2/cgi/cgiStageInitial.cpp @@ -1,6 +1,6 @@ #include "cgiAppEngine.h" #include "cgiEnvironment.h" -#include "../exceptions.h" +#include "exceptions.h" StaticMessageException(EmptyRequestURL, "Request URL cannot be empty"); diff --git a/project2/cgi/cgiStageRequest.cpp b/project2/cgi/cgiStageRequest.cpp index afef7ab..c17efac 100644 --- a/project2/cgi/cgiStageRequest.cpp +++ b/project2/cgi/cgiStageRequest.cpp @@ -1,7 +1,7 @@ #include "cgiAppEngine.h" #include "cgiEnvironment.h" #include "cgiHttpHeader.h" -#include "../xmlObjectLoader.h" +#include "xmlObjectLoader.h" #include CgiApplicationEngine::RequestStage::RequestStage(const CgiEnvironment * e, const boost::filesystem::path & path) : diff --git a/project2/cgi/p2webCgi.cpp b/project2/cgi/p2webCgi.cpp index 6168819..940717b 100644 --- a/project2/cgi/p2webCgi.cpp +++ b/project2/cgi/p2webCgi.cpp @@ -1,5 +1,5 @@ #include "cgiCommon.h" -#include "../xmlObjectLoader.h" +#include "xmlObjectLoader.h" #include int diff --git a/project2/cgi/p2webFCgi.cpp b/project2/cgi/p2webFCgi.cpp index 9a47b24..c193c1b 100644 --- a/project2/cgi/p2webFCgi.cpp +++ b/project2/cgi/p2webFCgi.cpp @@ -1,6 +1,6 @@ #include "cgiCommon.h" #include "FCgiIO.h" -#include "../xmlObjectLoader.h" +#include "xmlObjectLoader.h" #include time_t lastPeriodic = 0; diff --git a/project2/checkHost.cpp b/project2/checkHost.cpp deleted file mode 100644 index a39c176..0000000 --- a/project2/checkHost.cpp +++ /dev/null @@ -1,34 +0,0 @@ -#include "checkHost.h" -#include "appEngine.h" -#include - -CheckHost::CheckHost(const boost::filesystem::path & file) : - XmlScriptParser(file, false) -{ - loader.supportedStorers.insert(Storer::into(¶meterChecks)); -} - -CheckHost::~CheckHost() -{ -} - -void -CheckHost::runChecks() const -{ - parseDocument(); - 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 deleted file mode 100644 index 54fc96d..0000000 --- a/project2/checkHost.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef CHECKHOST_H -#define CHECKHOST_H - -#include "xmlScriptParser.h" -#include "paramChecker.h" -#include "xmlStorage.h" -#include -#include - -class CheckHost : public virtual XmlScriptParser { - public: - class CheckFailure : std::exception { - public: - CheckFailure(ParamCheckerCPtr); - ~CheckFailure() throw(); - const ParamCheckerCPtr failedCheck; - }; - CheckHost(const boost::filesystem::path & file); - ~CheckHost(); - - void runChecks() const; - - typedef ANONORDEREDSTORAGEOF(ParamChecker) ParamCheckers; - ParamCheckers parameterChecks; -}; - -#endif - - diff --git a/project2/columns.cpp b/project2/columns.cpp deleted file mode 100644 index a2511f6..0000000 --- a/project2/columns.cpp +++ /dev/null @@ -1,23 +0,0 @@ -#include "columns.h" -#include - -Column::Column(unsigned int i, const xmlpp::Element * p) : - idx(i), - name(p->get_attribute("name") ? p->get_attribute_value("name") : p->get_child_text()->get_content()), - defValue(p, "default", false) -{ -} - -Column::Column(unsigned int i, const Glib::ustring & n, const Variable & v) : - idx(i), - name(n), - defValue(v) -{ -} - -Column * -Column::make(unsigned int idx, const xmlpp::Element * p) -{ - return new Column(idx, p); -} - diff --git a/project2/columns.h b/project2/columns.h deleted file mode 100644 index 8b9b9b3..0000000 --- a/project2/columns.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef COLUMNS_H -#define COLUMNS_H - -#include -#include "variables.h" -#include -#include -#include - -class Column : public IntrusivePtrBase { - public: - Column(unsigned int idx, const xmlpp::Element * p); - Column(unsigned int i, const Glib::ustring & n, const Variable & v = Variable(Null())); - - static Column * make(unsigned int idx, const xmlpp::Element * p); - - const unsigned int idx; - const Glib::ustring name; - const Variable defValue; -}; - -struct byColIdx {}; -struct byColName {}; -typedef boost::multi_index::multi_index_container, - boost::multi_index::indexed_by< - boost::multi_index::ordered_unique< - boost::multi_index::tag, BOOST_MULTI_INDEX_MEMBER(Column, const Glib::ustring, name)>, - boost::multi_index::ordered_unique< - boost::multi_index::tag, BOOST_MULTI_INDEX_MEMBER(Column, const unsigned int, idx)> - > > Columns; - -#endif - diff --git a/project2/common/Jamfile.jam b/project2/common/Jamfile.jam new file mode 100644 index 0000000..2d88168 --- /dev/null +++ b/project2/common/Jamfile.jam @@ -0,0 +1,40 @@ +alias libxmlpp : : : : + "`pkg-config --cflags libxml++-2.6`" + "`pkg-config --libs libxml++-2.6`" ; +lib dl : : dl ; +lib boost_system : : boost_system ; +lib boost_filesystem : : boost_filesystem ; +lib boost_date_time : : boost_date_time ; +lib boost_program_options : : boost_program_options ; + +lib p2common : + appEngine.cpp dataSource.cpp environment.cpp fileStarGlibIoChannel.cpp iHaveParameters.cpp library.cpp iHaveSubTasks.cpp + iterate.cpp paramChecker.cpp presenter.cpp logger.cpp if.cpp xmlScriptParser.cpp viewHost.cpp + sourceObject.cpp task.cpp variables.cpp variableConvert.cpp view.cpp xmlObjectLoader.cpp exceptions.cpp cache.cpp + sessionContainer.cpp sessionClearTask.cpp session.cpp sessionSetTask.cpp commonObjects.cpp taskHost.cpp checkHost.cpp + rowView.cpp rowSet.cpp rowProcessor.cpp config.cpp fileStrmVarWriter.cpp noOutputExecute.cpp columns.cpp scopeObject.cpp + transform.cpp definedColumns.cpp structExceptHandling.cpp validDateCheck.cpp + variables-modconfig.cpp + variables-modlocalparam.cpp + variables-modlookup.cpp + variables-modparam.cpp + variables-modsession.cpp + variables-moduri.cpp + ../../libmisc/buffer.cpp + ../../libmisc/misc.cpp + : + ../../libmisc + libxmlpp + dl + boost_system + boost_filesystem + boost_date_time + boost_program_options + ../uuid//p2uuid + : : + . + ../../libmisc + boost_system + boost_program_options + ; + diff --git a/project2/common/appEngine.cpp b/project2/common/appEngine.cpp new file mode 100644 index 0000000..d8c097b --- /dev/null +++ b/project2/common/appEngine.cpp @@ -0,0 +1,50 @@ +#include "appEngine.h" +#include "logger.h" +#include +#include + +ApplicationEngine * ApplicationEngine::currentEngine = NULL; + +ApplicationEngine::ApplicationEngine(const Glib::ustring & engineKeys) : + Configuration(engineKeys) +{ + if (currentEngine) { + throw std::runtime_error("One application at a time, please"); + } + currentEngine = this; +} + +ApplicationEngine::~ApplicationEngine() +{ + currentEngine = NULL; +} + +void +ApplicationEngine::logMessage(bool writeLog, const Glib::ustring & g, const Glib::ustring & m) +{ + if (writeLog) { + Logger()->messagef(LOG_NOTICE, "%s: %s: %s", __PRETTY_FUNCTION__, g.c_str(), m.c_str()); + } + appMessages.push_back(new Message(g, m)); +} + +void +ApplicationEngine::addCoreAppData(const Presenter * p) const +{ + // Message log + p->pushSub("messages", env()->xmlPrefix); + BOOST_FOREACH(const Messages::value_type & m, appMessages) { + p->pushSub("message"); + p->addAttr("group", m->group); + p->addAttr("text", m->message); + p->popSub(); + } + p->popSub(); +} + +ApplicationEngine::Message::Message(const Glib::ustring & g, const Glib::ustring & m) : + group(g), + message(m) +{ +} + diff --git a/project2/common/appEngine.h b/project2/common/appEngine.h new file mode 100644 index 0000000..689f1b5 --- /dev/null +++ b/project2/common/appEngine.h @@ -0,0 +1,44 @@ +#ifndef APPENGINE_H +#define APPENGINE_H + +#include "environment.h" +#include "session.h" +#include "presenter.h" +#include "config.h" + +class ApplicationEngine : public Configuration { + public: + class Message : public IntrusivePtrBase { + public: + Message(const Glib::ustring & g, const Glib::ustring & m); + + const Glib::ustring group; + const Glib::ustring message; + }; + typedef boost::intrusive_ptr MessagePtr; + typedef std::list Messages; + + ApplicationEngine(const Glib::ustring & engineKeys); + virtual ~ApplicationEngine() = 0; + + void logMessage(bool writeLog, const Glib::ustring & g, const Glib::ustring & m); + + virtual void process() const = 0; + virtual const Environment * env() const = 0; + virtual SessionPtr session() const = 0; + virtual void addAppData(const Presenter * p) const = 0; + virtual void addEnvData(const Presenter * p) const = 0; + + static ApplicationEngine * getCurrent() { return currentEngine; } + + protected: + void addCoreAppData(const Presenter * p) const; + + Messages appMessages; + + private: + static ApplicationEngine * currentEngine; +}; + +#endif + diff --git a/project2/common/cache.cpp b/project2/common/cache.cpp new file mode 100644 index 0000000..1dc435f --- /dev/null +++ b/project2/common/cache.cpp @@ -0,0 +1,42 @@ +#include "cache.h" +#include "rowSet.h" +#include "rowProcessor.h" +#include "logger.h" +#include + +Cache::Cache(const xmlpp::Element * p) : + IHaveParameters(p), + SourceObject(p), + inherit(p->get_attribute_value("inherit") != "false") +{ +} + +bool Cache::checkAndExecute(const Glib::ustring & n, const Glib::ustring & f, const RowProcessor * rp) +{ + RowSetCPtr cached = getCachedRowSet(n, f, rp); + if (cached) { + try { + Logger()->messagef(LOG_ERR, "Executing from cache"); + cached->execute(f, rp); + return true; + } + catch (...) { + Logger()->messagef(LOG_WARNING, "Cache failed"); + } + } + return false; +} + +void +Cache::applyKeys(const boost::function2 & f, const IHaveParameters * ps) const +{ + BOOST_FOREACH(const IHaveParameters::Parameters::value_type & p, allParameters()) { + f(p.first, p.second); + } + if (inherit) { + BOOST_FOREACH(const IHaveParameters::Parameters::value_type & p, ps->allParameters()) { + f(p.first, p.second); + } + } +} + diff --git a/project2/common/cache.h b/project2/common/cache.h new file mode 100644 index 0000000..899a01e --- /dev/null +++ b/project2/common/cache.h @@ -0,0 +1,29 @@ +#ifndef CACHE_H +#define CACHE_H + +#include "sourceObject.h" +#include "presenter.h" +#include "iHaveParameters.h" + +class RowProcessor; +class RowSet; +class RowState; +typedef boost::intrusive_ptr RowSetCPtr; + +class Cache : public IHaveParameters, public SourceObject { + public: + Cache(const xmlpp::Element * p); + + bool checkAndExecute(const Glib::ustring &, const Glib::ustring &, const RowProcessor *); + virtual PresenterPtr openFor(const Glib::ustring &, const Glib::ustring &, const IHaveParameters *) = 0; + virtual void close(const Glib::ustring &, const Glib::ustring &, const IHaveParameters *) = 0; + + protected: + virtual RowSetCPtr getCachedRowSet(const Glib::ustring &, const Glib::ustring &, const IHaveParameters *) const = 0; + void applyKeys(const boost::function2 & f, const IHaveParameters *) const; + const bool inherit; +}; +typedef boost::intrusive_ptr CachePtr; + +#endif + diff --git a/project2/common/checkHost.cpp b/project2/common/checkHost.cpp new file mode 100644 index 0000000..a39c176 --- /dev/null +++ b/project2/common/checkHost.cpp @@ -0,0 +1,34 @@ +#include "checkHost.h" +#include "appEngine.h" +#include + +CheckHost::CheckHost(const boost::filesystem::path & file) : + XmlScriptParser(file, false) +{ + loader.supportedStorers.insert(Storer::into(¶meterChecks)); +} + +CheckHost::~CheckHost() +{ +} + +void +CheckHost::runChecks() const +{ + parseDocument(); + 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/common/checkHost.h b/project2/common/checkHost.h new file mode 100644 index 0000000..54fc96d --- /dev/null +++ b/project2/common/checkHost.h @@ -0,0 +1,29 @@ +#ifndef CHECKHOST_H +#define CHECKHOST_H + +#include "xmlScriptParser.h" +#include "paramChecker.h" +#include "xmlStorage.h" +#include +#include + +class CheckHost : public virtual XmlScriptParser { + public: + class CheckFailure : std::exception { + public: + CheckFailure(ParamCheckerCPtr); + ~CheckFailure() throw(); + const ParamCheckerCPtr failedCheck; + }; + CheckHost(const boost::filesystem::path & file); + ~CheckHost(); + + void runChecks() const; + + typedef ANONORDEREDSTORAGEOF(ParamChecker) ParamCheckers; + ParamCheckers parameterChecks; +}; + +#endif + + diff --git a/project2/common/columns.cpp b/project2/common/columns.cpp new file mode 100644 index 0000000..a2511f6 --- /dev/null +++ b/project2/common/columns.cpp @@ -0,0 +1,23 @@ +#include "columns.h" +#include + +Column::Column(unsigned int i, const xmlpp::Element * p) : + idx(i), + name(p->get_attribute("name") ? p->get_attribute_value("name") : p->get_child_text()->get_content()), + defValue(p, "default", false) +{ +} + +Column::Column(unsigned int i, const Glib::ustring & n, const Variable & v) : + idx(i), + name(n), + defValue(v) +{ +} + +Column * +Column::make(unsigned int idx, const xmlpp::Element * p) +{ + return new Column(idx, p); +} + diff --git a/project2/common/columns.h b/project2/common/columns.h new file mode 100644 index 0000000..8b9b9b3 --- /dev/null +++ b/project2/common/columns.h @@ -0,0 +1,33 @@ +#ifndef COLUMNS_H +#define COLUMNS_H + +#include +#include "variables.h" +#include +#include +#include + +class Column : public IntrusivePtrBase { + public: + Column(unsigned int idx, const xmlpp::Element * p); + Column(unsigned int i, const Glib::ustring & n, const Variable & v = Variable(Null())); + + static Column * make(unsigned int idx, const xmlpp::Element * p); + + const unsigned int idx; + const Glib::ustring name; + const Variable defValue; +}; + +struct byColIdx {}; +struct byColName {}; +typedef boost::multi_index::multi_index_container, + boost::multi_index::indexed_by< + boost::multi_index::ordered_unique< + boost::multi_index::tag, BOOST_MULTI_INDEX_MEMBER(Column, const Glib::ustring, name)>, + boost::multi_index::ordered_unique< + boost::multi_index::tag, BOOST_MULTI_INDEX_MEMBER(Column, const unsigned int, idx)> + > > Columns; + +#endif + diff --git a/project2/common/commonObjects.cpp b/project2/common/commonObjects.cpp new file mode 100644 index 0000000..e811fe7 --- /dev/null +++ b/project2/common/commonObjects.cpp @@ -0,0 +1,36 @@ +#include "commonObjects.h" +#include "appEngine.h" +#include "xmlObjectLoader.h" +#include "xmlScriptParser.h" + +CommonObjects::~CommonObjects() +{ +} + +RowSetPtr +CommonObjects::getSource(const std::string & name) const +{ + RowSets::const_iterator i = rowSets.find(name); + if (i != rowSets.end()) { + return i->second; + } + throw CommonObjects::DataSourceNotFound(name); +} + +CommonObjects::DataSources::const_iterator +CommonObjects::loadDataSource(const std::string & name) const +{ + XmlScriptParser xml(Environment::getCurrent()->resolveScript( + Environment::getCurrent()->datasourceRoot, name), true); + + LoaderBase loader(true); + loader.supportedStorers.insert(Storer::into(&datasources)); + loader.collectAll(xml.get_document()->get_root_node(), false); + + DataSources::const_iterator i = datasources.find(name); + if (i == datasources.end()) { + throw DataSourceNotFound(name); + } + return i; +} + diff --git a/project2/common/commonObjects.h b/project2/common/commonObjects.h new file mode 100644 index 0000000..dae563a --- /dev/null +++ b/project2/common/commonObjects.h @@ -0,0 +1,40 @@ +#ifndef COMMONOBJECTS_H +#define COMMONOBJECTS_H + +#include "dataSource.h" +#include "rowSet.h" +#include "xmlStorage.h" + +class CommonObjects : public virtual IntrusivePtrBase { + public: + typedef STORAGEOF(RowSet) RowSets; + typedef STORAGEOF(DataSource) DataSources; + + SimpleMessageException(DataSourceNotFound); + SimpleMessageException(DataSourceNotCompatible); + + virtual ~CommonObjects(); + + RowSetPtr getSource(const std::string &) const; + template + const DataSourceType * dataSource(const std::string & name) const + { + DataSources::const_iterator i = datasources.find(name); + if (i == datasources.end()) { + i = loadDataSource(name); + } + const DataSourceType * s = boost::dynamic_pointer_cast(i->second).get(); + if (!s) { + throw DataSourceNotCompatible(name); + } + return s; + } + protected: + RowSets rowSets; + mutable DataSources datasources; + private: + DataSources::const_iterator loadDataSource(const std::string & name) const; +}; + +#endif + diff --git a/project2/common/config.cpp b/project2/common/config.cpp new file mode 100644 index 0000000..a3b9afe --- /dev/null +++ b/project2/common/config.cpp @@ -0,0 +1,79 @@ +#include "config.h" +#include "exceptions.h" +#include +#include +#include "xmlScriptParser.h" + +SimpleMessageException(NoSuchPlatform); +SimpleMessageException(NoSuchConfigurationValue); + +Configuration::Configuration(const Glib::ustring & ek) : + loaded(false), + engineKeys(ek) +{ +} + +void +Configuration::load() const +{ + if (loaded) { + return; + } + loaded = true; + if (!boost::filesystem::exists("config.xml")) { + return; + } + XmlScriptParser configxml("config.xml", true); + xmlpp::NodeSet ps(configxml.get_document()->get_root_node()->find("platform")); + BOOST_FOREACH(const xmlpp::Node * p, ps) { + const xmlpp::Element * pe = dynamic_cast(p); + if (pe) { + platforms[pe->get_attribute_value("name")] = new Platform(pe); + } + } + xmlpp::NodeSet eks(configxml.get_document()->get_root_node()->find(engineKeys)); + BOOST_FOREACH(const xmlpp::Node * ek, eks) { + const xmlpp::Element * eke = dynamic_cast(ek); + if (eke) { + loadEngineSection(eke); + } + } +} + +Configuration::~Configuration() +{ +} + +Configuration::PlatformPtr +Configuration::getCurrentConfig() const +{ + load(); + Glib::ustring platformName(resolveCurrentConfig()); + Platforms::const_iterator i = platforms.find(platformName); + if (i == platforms.end()) { + throw NoSuchPlatform(platformName); + } + return i->second; +} + +const Glib::ustring & +Configuration::Platform::getValue(const Glib::ustring & key) const +{ + Values::const_iterator i = values.find(key); + if (i == values.end()) { + throw NoSuchConfigurationValue(key); + } + return i->second; +} + +Configuration::Platform::Platform(const xmlpp::Element * e) +{ + xmlpp::NodeSet vs(e->find("variable")); + BOOST_FOREACH(const xmlpp::Node * v, vs) { + const xmlpp::Element * ve = dynamic_cast(v); + if (ve) { + values.insert(Values::value_type(ve->get_attribute_value("name"), ve->get_attribute_value("value"))); + } + } +} + diff --git a/project2/common/config.h b/project2/common/config.h new file mode 100644 index 0000000..9f6cd5d --- /dev/null +++ b/project2/common/config.h @@ -0,0 +1,43 @@ +#ifndef CONFIG_H +#define CONFIG_H + +#include +#include +#include "intrusivePtrBase.h" +#include + +class Configuration { + public: + class Platform : public virtual IntrusivePtrBase { + public: + typedef std::map Values; + + Platform(const xmlpp::Element * instanceRoot); + const Glib::ustring & getValue(const Glib::ustring & key) const; + + private: + Values values; + }; + typedef boost::intrusive_ptr PlatformPtr; + + typedef std::map Platforms; + + Configuration(const Glib::ustring & engineKeys); + virtual ~Configuration() = 0; + + PlatformPtr getCurrentConfig() const; + + protected: + virtual Glib::ustring resolveCurrentConfig() const = 0; + void load() const; + + private: + virtual void loadEngineSection(const xmlpp::Element *) const = 0; + + mutable bool loaded; + mutable Platforms platforms; + const Glib::ustring engineKeys; +}; + +#endif + diff --git a/project2/common/dataSource.cpp b/project2/common/dataSource.cpp new file mode 100644 index 0000000..e40ad64 --- /dev/null +++ b/project2/common/dataSource.cpp @@ -0,0 +1,11 @@ +#include "dataSource.h" + +DataSource::DataSource(const xmlpp::Element * p) : + SourceObject(p) +{ +} + +DataSource::~DataSource() +{ +} + diff --git a/project2/common/dataSource.h b/project2/common/dataSource.h new file mode 100644 index 0000000..d8a5a9a --- /dev/null +++ b/project2/common/dataSource.h @@ -0,0 +1,22 @@ +#ifndef DATASOURCE_H +#define DATASOURCE_H + +#include +#include "sourceObject.h" + +class DataSource; +typedef boost::intrusive_ptr DataSourcePtr; + +/// Base class for data sources providing transaction support +class DataSource : public SourceObject { + public: + DataSource(const xmlpp::Element * p); + virtual ~DataSource(); + + virtual void commit() { }; + virtual void rollback() { }; +}; + +#endif + + diff --git a/project2/common/definedColumns.cpp b/project2/common/definedColumns.cpp new file mode 100644 index 0000000..5260e51 --- /dev/null +++ b/project2/common/definedColumns.cpp @@ -0,0 +1,31 @@ +#include "definedColumns.h" +#include +#include + +DefinedColumns::DefinedColumns(const xmlpp::Element * p, const Glib::ustring & colPath, const ColCreator & func) +{ + unsigned int colNo = 0; + BOOST_FOREACH(const xmlpp::Node * node, p->find(colPath)) { + const xmlpp::Element * elem = dynamic_cast(node); + if (elem) { + columns.insert(func(colNo++, elem)); + } + } +} + +ColumnValues::ColumnValues(const DefinedColumns * rs) : + rowSet(rs) +{ + fields.resize(rs->columns.size()); +} + +ColumnValues::~ColumnValues() +{ +} + +const Columns & +ColumnValues::getColumns() const +{ + return rowSet->columns; +} + diff --git a/project2/common/definedColumns.h b/project2/common/definedColumns.h new file mode 100644 index 0000000..2fc6bbd --- /dev/null +++ b/project2/common/definedColumns.h @@ -0,0 +1,29 @@ +#ifndef DEFINEDCOLUMNS_H +#define DEFINEDCOLUMNS_H + +#include +#include +#include "variables.h" +#include "rowSet.h" +#include "columns.h" + +class DefinedColumns { + public: + typedef boost::function2 ColCreator; + DefinedColumns(const xmlpp::Element * p, const Glib::ustring & colPath, const ColCreator & func); + Columns columns; +}; + +class ColumnValues : public RowState { + public: + ColumnValues(const DefinedColumns *); + virtual ~ColumnValues(); + + virtual const Columns & getColumns() const; + + const DefinedColumns * const rowSet; +}; + +#endif + + diff --git a/project2/common/environment.cpp b/project2/common/environment.cpp new file mode 100644 index 0000000..0c563cc --- /dev/null +++ b/project2/common/environment.cpp @@ -0,0 +1,121 @@ +#include "environment.h" +#include "loggers.h" +#include "xmlObjectLoader.h" +#include +#include +#include +#include +#include + +namespace po = boost::program_options; + +const Environment * Environment::currentEnv(NULL); +int Environment::clLevel(-1); +int Environment::slLevel(-1); +bool Environment::optionsBuilt(false); +po::options_description Environment::allOptions("Project2 options"); +po::positional_options_description Environment::posOptions; + +Environment::Environment(int c, char ** v) : + argc(c), + argv(v) +{ + currentEnv = this; +} + +static +po::variables_map +injectSettingsHelper(int argc, char ** argv, const po::options_description * opts, po::positional_options_description * posOpts) +{ + po::variables_map settings; + if (!opts) { + return settings; + } + if (argc > 0 && argv != NULL) { + if (posOpts) { + po::store(po::command_line_parser(argc, argv).options(*opts).positional(*posOpts).allow_unregistered().run(), settings); + } + else { + po::store(po::command_line_parser(argc, argv).options(*opts).allow_unregistered().run(), settings); + } + } + po::store(po::parse_environment(*opts, "P2_"), settings); + if (boost::filesystem::exists(".p2config")) { + std::ifstream f(".p2config"); + po::store(po::parse_config_file(f, *opts, true), settings); + } + po::notify(settings); + return settings; +} + +void +Environment::init() +{ + if (!optionsBuilt) { + po::options_description common("Project2 Common options"); + common.add_options() + ("sysloglevel,s", po::value(&slLevel)->default_value(-1), + "Log to syslog with level (default OFF)") + ("consoleloglevel,c", po::value(&clLevel)->default_value(LOG_WARNING), + "Log to console with level (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") + ("sessionTimeOut", boost::program_options::value(&sessionTimeOut)->default_value(3600), + "The time after which idle sessions are forgetten") + ; + allOptions.add(common).add(addOptions(posOptions)); + optionsBuilt = true; + } + po::variables_map settings(injectSettingsHelper(argc, argv, &allOptions, &posOptions)); + postinit(allOptions, settings); + LoaderBase::onAllComponents(boost::bind( + injectSettingsHelper, argc, argv, boost::bind(&ComponentLoader::options, _1), (po::positional_options_description*)NULL)); + + Logger()->clear(); + if (clLevel >= 0) { + Logger()->addLogger(new ConsoleLogDriver(stderr, clLevel, false)); + } + if (slLevel >= 0) { + Logger()->addLogger(new SyslogLogDriver(getScriptName().c_str(), slLevel)); + } +} + +Environment::~Environment() +{ + currentEnv = NULL; +} + +const Environment * +Environment::getCurrent() +{ + return currentEnv; +} + +boost::filesystem::path +Environment::resolveScript(const std::string & group, const std::string & name) const +{ + boost::filesystem::path script(boost::filesystem::current_path() / group); + BOOST_FOREACH(const boost::filesystem::path & e, boost::filesystem::path(name)) { + if (boost::filesystem::is_directory(script / e)) { + script /= e; + } + else { + if (boost::filesystem::is_regular_file((script / e).replace_extension(".xml"))) { + return ((script / e).replace_extension(".xml")); + } + } + } + return script; +} + +boost::filesystem::path +Environment::resolveScript(const std::string & path) const +{ + boost::filesystem::path script(boost::filesystem::current_path()); + return script / path; +} + diff --git a/project2/common/environment.h b/project2/common/environment.h new file mode 100644 index 0000000..681a80c --- /dev/null +++ b/project2/common/environment.h @@ -0,0 +1,51 @@ +#ifndef ENVIRONMENT_H +#define ENVIRONMENT_H + +#include +#include +#include +#include +#include + +class Environment { + public: + Environment(int argc, char ** argv); + virtual ~Environment() = 0; + + void init(); + + static const Environment * getCurrent(); + + virtual Glib::ustring getParamUri(unsigned int idx) const = 0; + virtual Glib::ustring getParamQuery(const std::string & idx) const = 0; + + virtual std::string getServerName() const = 0; + virtual std::string getScriptName() const = 0; + + boost::filesystem::path resolveScript(const std::string & group, const std::string & name) const; + boost::filesystem::path resolveScript(const std::string & path) const; + + 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; + char ** argv; + + static bool optionsBuilt; + static boost::program_options::options_description allOptions; + static boost::program_options::positional_options_description posOptions; + + static int clLevel; + static int slLevel; + + public: + std::string datasourceRoot; + Glib::ustring xmlNamespace; + Glib::ustring xmlPrefix; + time_t sessionTimeOut; +}; + +#endif + diff --git a/project2/common/exceptions.cpp b/project2/common/exceptions.cpp new file mode 100644 index 0000000..ddf8e94 --- /dev/null +++ b/project2/common/exceptions.cpp @@ -0,0 +1,26 @@ +#include "exceptions.h" +#include +#include + +numeric_error::numeric_error(int e) : + err(e), + buf(NULL) +{ +} + +numeric_error::~numeric_error() throw() +{ + free(buf); +} + +const char * +numeric_error::what() const throw() +{ + if (!buf) { + if (asprintf(&buf, "%d", err) < 1) { + throw std::bad_alloc(); + } + } + return buf; +} + diff --git a/project2/common/exceptions.h b/project2/common/exceptions.h new file mode 100644 index 0000000..a9d4952 --- /dev/null +++ b/project2/common/exceptions.h @@ -0,0 +1,44 @@ +#ifndef EXCEPTION_H +#define EXCEPTION_H + +#include + +class numeric_error : public std::exception { + public: + numeric_error(int); + ~numeric_error() throw(); + const char * what() const throw(); + private: + int err; + mutable char * buf; +}; +#define StaticMessageException(Name, Text) \ +class Name : public std::runtime_error { \ + public: \ + Name() : std::runtime_error(Text) { } \ +} +#define SimpleMessageException(Name) \ +class Name : public std::runtime_error { \ + public: \ + Name(const std::string & what) : std::runtime_error(what) { } \ +} +#define SimpleMessageExceptionBase(Name, Base) \ +class Name : public Base { \ + public: \ + Name(const std::string & what) : Base(what) { } \ +} +#define SimpleNumericException(Name) \ +class Name : public numeric_error { \ + public: \ + Name(int e) : numeric_error(e) { } \ +} + +SimpleNumericException(UriElementOutOfRange); +SimpleMessageException(ParamNotFound); +SimpleMessageException(NotSupported); +SimpleMessageException(FileNotReadable); +SimpleMessageException(FileNotWritable); +SimpleMessageException(FilterNotFound); + +#endif + diff --git a/project2/common/fileStarGlibIoChannel.cpp b/project2/common/fileStarGlibIoChannel.cpp new file mode 100644 index 0000000..3ec26ce --- /dev/null +++ b/project2/common/fileStarGlibIoChannel.cpp @@ -0,0 +1,65 @@ +#include "fileStarGlibIoChannel.h" +#include +#include +#include +#include + +FileStarChannel::FileStarChannel(FILE * f, bool seekable, int (*closer)(FILE*)) : + Glib::IOChannel(), + file(f, closer) +{ + gobj()->is_seekable = seekable ? 1 : 0; + gobj()->is_readable = 1; + gobj()->is_writeable = 0; +} + +FileStarChannel::~FileStarChannel() +{ +} + +Glib::IOStatus +FileStarChannel::close_vfunc() +{ + if (file) { + file.reset(); + } + return Glib::IO_STATUS_NORMAL; +} + +Glib::IOStatus +FileStarChannel::set_flags_vfunc(Glib::IOFlags) +{ + return Glib::IO_STATUS_NORMAL; +} + +Glib::IOFlags +FileStarChannel::get_flags_vfunc() +{ + return Glib::IO_FLAG_IS_SEEKABLE | Glib::IO_FLAG_IS_READABLE; +} + +Glib::IOStatus +FileStarChannel::seek_vfunc(gint64 offset, Glib::SeekType type) +{ + if (fseek(file.get(), offset, type)) { + return Glib::IO_STATUS_ERROR; + } + return Glib::IO_STATUS_NORMAL; +} + +Glib::IOStatus +FileStarChannel::read_vfunc(char* buf, gsize count, gsize& bytes_read) +{ + bytes_read = fread(buf, 1, count, file.get()); + if (bytes_read == 0) { + if (feof(file.get())) { + return Glib::IO_STATUS_EOF; + } + if (ferror(file.get())) { + return Glib::IO_STATUS_ERROR; + } + return Glib::IO_STATUS_AGAIN; + } + return Glib::IO_STATUS_NORMAL; +} + diff --git a/project2/common/fileStarGlibIoChannel.h b/project2/common/fileStarGlibIoChannel.h new file mode 100644 index 0000000..77b6282 --- /dev/null +++ b/project2/common/fileStarGlibIoChannel.h @@ -0,0 +1,26 @@ +#ifndef FILESTARGLIBIOCHANNEL_H +#define FILESTARGLIBIOCHANNEL_H + +#include +#include +#include +#include +#include "intrusivePtrBase.h" + +class FileStarChannel : public Glib::IOChannel, public virtual IntrusivePtrBase { + public: + FileStarChannel(FILE * f, bool seekable, int (*closer)(FILE *) = fclose); + virtual ~FileStarChannel(); + + virtual Glib::IOStatus close_vfunc(); + virtual Glib::IOStatus set_flags_vfunc(Glib::IOFlags flags); + virtual Glib::IOFlags get_flags_vfunc(); + virtual Glib::IOStatus seek_vfunc(gint64 offset, Glib::SeekType type); + virtual Glib::IOStatus read_vfunc(char* buf, gsize count, gsize& bytes_read); + protected: + typedef boost::shared_ptr FilePtr; + FilePtr file; +}; + +#endif + diff --git a/project2/common/fileStrmVarWriter.cpp b/project2/common/fileStrmVarWriter.cpp new file mode 100644 index 0000000..51fb487 --- /dev/null +++ b/project2/common/fileStrmVarWriter.cpp @@ -0,0 +1,61 @@ +#include "fileStrmVarWriter.h" +#include "rowSet.h" +#include "xmlObjectLoader.h" +#include +#include +#include + +FileStreamVariableWriter::FileStreamVariableWriter(FILE * o, bool q) : + out(o), + quoting(q) +{ +} + +FileStreamVariableWriter::~FileStreamVariableWriter() +{ +} + +void FileStreamVariableWriter::operator()(const Null &) const { + fprintf(out, ""); +} +void FileStreamVariableWriter::operator()(const long long int & i) const { + fprintf(out, "%lld", i); +} +void FileStreamVariableWriter::operator()(const long int & i) const { + fprintf(out, "%ld", i); +} +void FileStreamVariableWriter::operator()(const int & i) const { + fprintf(out, "%d", i); +} +void FileStreamVariableWriter::operator()(const short int & i) const { + fprintf(out, "%hd", i); +} +void FileStreamVariableWriter::operator()(const long long unsigned int & i) const { + fprintf(out, "%llu", i); +} +void FileStreamVariableWriter::operator()(const long unsigned int & i) const { + fprintf(out, "%lu", i); +} +void FileStreamVariableWriter::operator()(const unsigned int & i) const { + fprintf(out, "%u", i); +} +void FileStreamVariableWriter::operator()(const short unsigned int & i) const { + fprintf(out, "%hu", i); +} +void FileStreamVariableWriter::operator()(const float & i) const { + fprintf(out, "%g", i); +} +void FileStreamVariableWriter::operator()(const double & i) const { + fprintf(out, "%g", i); +} +void FileStreamVariableWriter::operator()(const Glib::ustring & i) const { + fputc('\'', out); + if (fwrite(i.c_str(), i.bytes(), 1, out) < 1) { + // Care much? None of the others check. + } + fputc('\'', out); +} +void FileStreamVariableWriter::operator()(const boost::posix_time::ptime & i) const { + fprintf(out, "[%s]", boost::posix_time::to_iso_extended_string(i).c_str()); +} + diff --git a/project2/common/fileStrmVarWriter.h b/project2/common/fileStrmVarWriter.h new file mode 100644 index 0000000..b98691b --- /dev/null +++ b/project2/common/fileStrmVarWriter.h @@ -0,0 +1,31 @@ +#ifndef FILESTREAMVARWRITER_H +#define FILESTREAMVARWRITER_H + +#include "variables.h" + +class FileStreamVariableWriter : public boost::static_visitor<> { + public: + FileStreamVariableWriter(FILE *, bool quoting); + ~FileStreamVariableWriter(); + + void operator()(const Null &) const; + void operator()(const long long int & i) const; + void operator()(const long int & i) const; + void operator()(const int & i) const; + void operator()(const short int & i) const; + void operator()(const long long unsigned int & i) const; + void operator()(const long unsigned int & i) const; + void operator()(const unsigned int & i) const; + void operator()(const short unsigned int & i) const; + void operator()(const float & i) const; + void operator()(const double & i) const; + void operator()(const Glib::ustring & i) const; + void operator()(const boost::posix_time::ptime & i) const; + + private: + FILE * out; + bool quoting; +}; + +#endif + diff --git a/project2/common/iHaveParameters.cpp b/project2/common/iHaveParameters.cpp new file mode 100644 index 0000000..e4f456a --- /dev/null +++ b/project2/common/iHaveParameters.cpp @@ -0,0 +1,61 @@ +#include "iHaveParameters.h" +#include "exceptions.h" +#include "appEngine.h" +#include + +IHaveParameters::Stack IHaveParameters::scope; + +IHaveParameters::IHaveParameters(const xmlpp::Element * p) +{ + BOOST_FOREACH(xmlpp::Node * node, p->find("parameters/*")) { + if (const xmlpp::Element * pelem = dynamic_cast(node)) { + parameters.insert(Parameters::value_type(pelem->get_name(), Variable(pelem, boost::optional()))); + } + } +} + +IHaveParameters::~IHaveParameters() +{ +} + +VariableType +IHaveParameters::getParameter(const Glib::ustring & name) const +{ + Parameters::const_iterator i = parameters.find(name); + if (i != parameters.end()) { + return i->second; + } + throw ParamNotFound(name); +} + +void +IHaveParameters::push(const IHaveParameters * p) +{ + scope.push_back(p); +} + +void +IHaveParameters::pop(const IHaveParameters * p) +{ + assert(scope.back() == p); + scope.pop_back(); +} + +VariableType +IHaveParameters::getScopedParameter(const Glib::ustring & name) +{ + for(Stack::const_reverse_iterator ihp = scope.rbegin(); ihp != scope.rend(); ihp++) { + Parameters::const_iterator i = (*ihp)->parameters.find(name); + if (i != (*ihp)->parameters.end()) { + return i->second; + } + } + throw ParamNotFound(name); +} + +const IHaveParameters::Parameters & +IHaveParameters::allParameters() const +{ + return parameters; +} + diff --git a/project2/common/iHaveParameters.h b/project2/common/iHaveParameters.h new file mode 100644 index 0000000..28dbf7d --- /dev/null +++ b/project2/common/iHaveParameters.h @@ -0,0 +1,33 @@ +#ifndef IHAVEPARAMETERS +#define IHAVEPARAMETERS + +#include +#include +#include +#include "variables.h" +#include "intrusivePtrBase.h" + +/// Mix-in base class to store parameters for component execution +class IHaveParameters { + public: + typedef std::map Parameters; + + IHaveParameters(const xmlpp::Element * p); + virtual ~IHaveParameters() = 0; + + const Parameters & allParameters() const; + VariableType getParameter(const Glib::ustring &) const; + static VariableType getScopedParameter(const Glib::ustring &); + + protected: + Parameters parameters; + + static void push(const IHaveParameters *); + static void pop(const IHaveParameters *); + private: + typedef std::vector Stack; + static Stack scope; +}; + +#endif + diff --git a/project2/common/iHaveSubTasks.cpp b/project2/common/iHaveSubTasks.cpp new file mode 100644 index 0000000..f78f81e --- /dev/null +++ b/project2/common/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/common/iHaveSubTasks.h b/project2/common/iHaveSubTasks.h new file mode 100644 index 0000000..ee6d173 --- /dev/null +++ b/project2/common/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/common/if.cpp b/project2/common/if.cpp new file mode 100644 index 0000000..cf5c156 --- /dev/null +++ b/project2/common/if.cpp @@ -0,0 +1,85 @@ +#include "if.h" +#include "logger.h" +#include "xmlObjectLoader.h" +#include +#include +#include + +DECLARE_LOADER("if", If); + +SimpleMessageException(IfModeIsNonsense); + +IfSet::IfSet(const xmlpp::Element * e) : + mode(e->get_attribute_value("mode") == "or" ? Or : And) +{ + LoaderBase loader(true); + loader.supportedStorers.insert(Storer::into(&checks)); + loader.collectAll(e, true, IgnoreUnsupported); +} + +template +bool all(const Range & c, const Pred & p) +{ + return (std::find_if(c.begin(), c.end(), !p) == c.end()); +} +template +bool any(const Range & c, const Pred & p) +{ + return (std::find_if(c.begin(), c.end(), p) != c.end()); +} + +bool +IfSet::passes() const +{ + if (mode == And) { + return all(checks, boost::bind(&ParamChecker::performCheck, _1)); + } + else if (mode == Or) { + return any(checks, boost::bind(&ParamChecker::performCheck, _1)); + } + throw IfModeIsNonsense(getName()); +} + +If::If(const xmlpp::Element * e) : + SourceObject(e), + IHaveSubTasks(e), + View(e), + IfSet(e) +{ + LoaderBase loader(true); + loader.supportedStorers.insert(Storer::into(&normal)); + loader.supportedStorers.insert(Storer::into(&subViews)); + loader.collectAll(e, true, IgnoreUnsupported); +} + +void +If::loadComplete(const CommonObjects*) +{ +} + +void +If::execute(const Presenter * presenter) const +{ + if (passes()) { + Logger()->messagef(LOG_DEBUG, "IfSet passed, showing %zu views", subViews.size()); + BOOST_FOREACH(const SubViews::value_type & sq, subViews) { + sq->execute(presenter); + } + } +} + +void +If::execute() const +{ + if (passes()) { + Logger()->message(LOG_DEBUG, "IfSet passed"); + run(normal); + } +} + +const std::string & +If::getName() const +{ + return name; +} + diff --git a/project2/common/if.h b/project2/common/if.h new file mode 100644 index 0000000..b33bca1 --- /dev/null +++ b/project2/common/if.h @@ -0,0 +1,38 @@ +#ifndef IF_H +#define IF_H + +#include "iHaveSubTasks.h" +#include "view.h" +#include "paramChecker.h" + +class IfSet : public virtual IntrusivePtrBase { + public: + IfSet(const xmlpp::Element *); + bool passes() const; + + private: + virtual const std::string & getName() const = 0; + enum Mode { And, Or }; + Mode mode; + typedef ANONORDEREDSTORAGEOF(ParamChecker) ParamCheckers; + ParamCheckers checks; +}; + +/// Project2 component to conditionally execute its children +class If : public IHaveSubTasks, public View, public IfSet { + public: + If(const xmlpp::Element *); + + virtual void loadComplete(const CommonObjects*); + virtual void execute(const Presenter*) const; + virtual void execute() const; + + private: + typedef ANONSTORAGEOF(View) SubViews; + SubViews subViews; + + const std::string & getName() const; +}; + +#endif + diff --git a/project2/common/iterate.cpp b/project2/common/iterate.cpp new file mode 100644 index 0000000..119e839 --- /dev/null +++ b/project2/common/iterate.cpp @@ -0,0 +1,49 @@ +#include "iterate.h" +#include "logger.h" +#include +#include +#include "xmlObjectLoader.h" +#include "scopeObject.h" + +DECLARE_LOADER("iterate", Iterate); + +Iterate::Iterate(const xmlpp::Element * p) : + SourceObject(p), + IHaveSubTasks(p), + RowProcessor(p) +{ + LoaderBase loader(true); + loader.supportedStorers.insert(Storer::into(&normal)); + loader.collectAll(p, true, IgnoreUnsupported); +} + +Iterate::~Iterate() +{ +} + +void +Iterate::loadComplete(const CommonObjects * co) +{ + RowProcessor::loadComplete(co); +} + +void +Iterate::rowReady(const RowState *) const +{ + executeChildren(); +} + +void +Iterate::execute() const +{ + RowProcessor::execute(); +} + +void +Iterate::executeChildren() const +{ + BOOST_FOREACH(const Tasks::value_type & sq, normal) { + sq->execute(); + } +} + diff --git a/project2/common/iterate.h b/project2/common/iterate.h new file mode 100644 index 0000000..50fd879 --- /dev/null +++ b/project2/common/iterate.h @@ -0,0 +1,28 @@ +#ifndef ITERATE_H +#define ITERATE_H + +#include +#include "rowProcessor.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 IHaveSubTasks, public RowProcessor { + public: + Iterate(const xmlpp::Element * p); + virtual ~Iterate(); + + void loadComplete(const CommonObjects *); + void rowReady(const RowState *) const; + void execute() const; + + protected: + void executeChildren() const; +}; + +#endif + + diff --git a/project2/common/library.cpp b/project2/common/library.cpp new file mode 100644 index 0000000..b1e0b9b --- /dev/null +++ b/project2/common/library.cpp @@ -0,0 +1,41 @@ +#include +#include "xmlStorage.h" +#include "exceptions.h" +#include "library.h" + +SimpleMessageException(LoadLibraryFailed); +SimpleMessageException(UnloadLibraryFailed); + +Library::Library(const xmlpp::Element * p) : + SourceObject(p), + handle(dlopen(p->get_attribute_value("path").c_str(), RTLD_NOW)) +{ + if (!handle) { + throw LoadLibraryFailed(dlerror()); + } +} + +Library::~Library() +{ + if (dlclose(handle)) { + throw UnloadLibraryFailed(dlerror()); + } +} + +void +Library::loadComplete(const CommonObjects*) +{ +} + +STORAGEOF(Library) libraries; +class LibraryLoader : public ElementLoaderImpl { + public: + void onIteration() + { + libraries.clear(); + } +}; + +DECLARE_CUSTOM_LOADER("library", LibraryLoader); + + diff --git a/project2/common/library.h b/project2/common/library.h new file mode 100644 index 0000000..af8e73f --- /dev/null +++ b/project2/common/library.h @@ -0,0 +1,17 @@ +#ifndef LIBRARY_LOADER_H +#define LIBRARY_LOADER_H + +#include "xmlObjectLoader.h" + +class Library : public SourceObject { + public: + Library(const xmlpp::Element * p); + ~Library(); + void loadComplete(const CommonObjects*); + private: + void * handle; +}; +extern STORAGEOF(Library) libraries; + +#endif + diff --git a/project2/common/logger.cpp b/project2/common/logger.cpp new file mode 100644 index 0000000..6133ce9 --- /dev/null +++ b/project2/common/logger.cpp @@ -0,0 +1,182 @@ +#define SYSLOG_NAMES 1 // Enables the definition of names in syslog.h + +#include "logger.h" +#include "loggers.h" +#include +#include +#include + +const char * const version = "$Id: logger.cpp 8818 2011-01-10 10:09:59Z danielg $"; + +Log Logger::log; + +Log::Log() : + lowestLevel(-1) +{ +} + +Log::~Log() +{ + logs.clear(); +} + +int +Log::addLogger(LogDriverBasePtr log) +{ + logs[++nextId] = log; + if (log->level > lowestLevel) { + lowestLevel = log->level; + } + return nextId; +} + +void +Log::clear() +{ + logs.clear(); +} + +const char * +Log::priorityName(int priority) +{ + const char * name = NULL; + for (CODE * c = prioritynames; c->c_name; c++) { + if (c->c_val == priority) { + name = c->c_name; + } + } + return name; +} + + +void +Log::message(int priority, const char * msg) const +{ + if (priority > lowestLevel) return; + BOOST_FOREACH(const LogDrivers::value_type & l, logs) { + l.second->message(priority, msg); + } +} + +void +Log::messagef(int priority, const char * msgfmt, ...) const +{ + if (priority > lowestLevel) return; + va_list v; + va_start(v, msgfmt); + vmessagef(priority, msgfmt, v); + va_end(v); +} + +void +Log::vmessagef(int priority, const char * msgfmt, va_list va) const +{ + if (priority > lowestLevel) return; + char * msg; + int len = vasprintf(&msg, msgfmt, va); + if (len > 0) { + message(priority, msg); + } + free(msg); +} + +Log * +Logger::operator->() const +{ + return &log; +} + +LogDriverBase::LogDriverBase(int l) : + level(l) +{ +} + +LogDriverBase::~LogDriverBase() +{ +} + +// File based log driver +//---------------------- +FileBasedLogDriver::FileBasedLogDriver(FILE * f, int l, bool ts) : + LogDriverBase(l), + file(f), + timestamp(ts) +{ +} +FileBasedLogDriver::~FileBasedLogDriver() +{ +} +void +FileBasedLogDriver::message(int priority, const char * msg) const +{ + if (priority <= level) { + writeTimestamp(); + writeLevel(priority); + fprintf(file, "%s\n", msg); + fflush(file); + } +} +const char * +FileBasedLogDriver::timeStr() const +{ + struct tm tm; + time_t t = time(NULL); + localtime_r(&t, &tm); + strftime(tmbuf, sizeof(tmbuf), "%F %T", &tm); + return tmbuf; +} +void +FileBasedLogDriver::writeTimestamp() const +{ + if (timestamp) { + fprintf(file, "%s ", timeStr()); + } +} +void +FileBasedLogDriver::writeLevel(int level) const +{ + if (timestamp) { + fprintf(file, "%-6.*s", 5, boost::algorithm::to_upper_copy(std::string(Log::priorityName(level))).c_str()); + } +} + +// Consol driver +//------------------- +ConsoleLogDriver::ConsoleLogDriver(FILE * f, int l, bool ts) : + FileBasedLogDriver(f, l, ts) +{ +} +ConsoleLogDriver::~ConsoleLogDriver() +{ +} + +// File log driver +//------------------- +FileLogDriver::FileLogDriver(const char * path, int l) : + FileBasedLogDriver(fopen(path, "a"), l, true) +{ +} +FileLogDriver::~FileLogDriver() +{ + fclose(file); +} + +// Syslog Log Driver +//------------------- +SyslogLogDriver::SyslogLogDriver(const char * ident, int level, int option, int facility) : + LogDriverBase(level) +{ + openlog(ident, option, facility); +} +SyslogLogDriver::~SyslogLogDriver() +{ + closelog(); +} +void +SyslogLogDriver::message(int priority, const char * msg) const +{ + if (priority <= level) { + syslog(priority, "%s", msg); + } +} + diff --git a/project2/common/logger.h b/project2/common/logger.h new file mode 100644 index 0000000..5d42631 --- /dev/null +++ b/project2/common/logger.h @@ -0,0 +1,43 @@ +#ifndef LOGGER_H +#define LOGGER_H + +#include +#include +#include // Pulled in for easy client lookups of LOG_* priorties +#include +#include "intrusivePtrBase.h" + +class LogDriverBase; + +class Log { + public: + typedef boost::intrusive_ptr LogDriverBasePtr; + typedef std::map LogDrivers; + + Log(); + ~Log(); + + int addLogger(LogDriverBasePtr); + void clear(); + + void message(int priority, const char * msg) const; + void messagef(int priority, const char * msgfmt, ...) const __attribute__ ((format (printf, 3, 4))); + void vmessagef(int priority, const char * msgfmt, va_list) const; + + static const char * priorityName(int priority); // Look up the priority as defined in syslog.h + + private: + LogDrivers logs; + int lowestLevel; + int nextId; +}; + +class Logger { + public: + Log * operator->() const; + private: + static Log log; +}; + +#endif + diff --git a/project2/common/loggers.h b/project2/common/loggers.h new file mode 100644 index 0000000..69b352c --- /dev/null +++ b/project2/common/loggers.h @@ -0,0 +1,60 @@ +#ifndef LOGGERS_H +#define LOGGERS_H + +#include "logger.h" + +/// Base class for classes providing a logging facility +class LogDriverBase : public virtual IntrusivePtrBase { + public: + LogDriverBase(int level); + virtual ~LogDriverBase(); + + virtual void message(int priority, const char * msg) const = 0; + const int level; +}; + +/// Base class for loggers that write to some sort of file handle +class FileBasedLogDriver : public LogDriverBase { + public: + FileBasedLogDriver(FILE *, int level, bool timestamp); + virtual ~FileBasedLogDriver() = 0; + + virtual void message(int priority, const char * msg) const; + + protected: + void writeTimestamp() const; + void writeLevel(int level) const; + FILE * file; + bool timestamp; + + private: + const char * timeStr() const; + mutable char tmbuf[30]; +}; + +/// Logger that writes to the console +class ConsoleLogDriver : public FileBasedLogDriver { + public: + ConsoleLogDriver(FILE *, int level, bool timestamp); + ~ConsoleLogDriver(); + +}; + +/// Logger that writes to a file +class FileLogDriver : public FileBasedLogDriver { + public: + FileLogDriver(const char * path, int level); + ~FileLogDriver(); +}; + +/// Logger that writes to syslog +class SyslogLogDriver : public LogDriverBase { + public: + SyslogLogDriver(const char * ident, int level, int option = 0, int facility = LOG_USER); + virtual ~SyslogLogDriver(); + + virtual void message(int priority, const char * msg) const; +}; + +#endif + diff --git a/project2/common/noOutputExecute.cpp b/project2/common/noOutputExecute.cpp new file mode 100644 index 0000000..3bfa0e9 --- /dev/null +++ b/project2/common/noOutputExecute.cpp @@ -0,0 +1,17 @@ +#include "noOutputExecute.h" +#include + +NoOutputExecute::NoOutputExecute(const xmlpp::Element * p) : + SourceObject(p) +{ +} + +NoOutputExecute::NoOutputExecute(const std::string & n) : + SourceObject(n) +{ +} + +NoOutputExecute::~NoOutputExecute() +{ +} + diff --git a/project2/common/noOutputExecute.h b/project2/common/noOutputExecute.h new file mode 100644 index 0000000..1047f38 --- /dev/null +++ b/project2/common/noOutputExecute.h @@ -0,0 +1,22 @@ +#ifndef NOOUTPUTEXECUTE_H +#define NOOUTPUTEXECUTE_H + +#include "sourceObject.h" +#include "xmlStorage.h" + +class NoOutputExecute; +typedef boost::intrusive_ptr NoOutputExecutePtr; + +/// Base class for Project2 compoments that perform actions, but product no output +class NoOutputExecute : public virtual SourceObject { + public: + NoOutputExecute(const xmlpp::Element * p); + NoOutputExecute(const std::string & n); + + virtual ~NoOutputExecute(); + + virtual void execute() const = 0; +}; + +#endif + diff --git a/project2/common/ostreamWrapper.h b/project2/common/ostreamWrapper.h new file mode 100644 index 0000000..ef8596c --- /dev/null +++ b/project2/common/ostreamWrapper.h @@ -0,0 +1,14 @@ +#ifndef OSTREAMWRAPPER_H +#define OSTREAMWRAPPER_H + +#include +#include "transform.h" + +class ostreamWrapper : public TransformChainLink { + public: + ostreamWrapper(std::ostream & s) : strm(s) { } + std::ostream & strm; +}; + +#endif + diff --git a/project2/common/paramChecker.cpp b/project2/common/paramChecker.cpp new file mode 100644 index 0000000..0781e90 --- /dev/null +++ b/project2/common/paramChecker.cpp @@ -0,0 +1,15 @@ +#include "paramChecker.h" +#include "xmlObjectLoader.h" + +ParamChecker::ParamChecker(const xmlpp::Element * p) : + SourceObject(p), + message(p, "message", false, "Check failed"), + group(p, "group", false, "default"), + present(p->get_attribute_value("present")) +{ +} + +ParamChecker::~ParamChecker() +{ +} + diff --git a/project2/common/paramChecker.h b/project2/common/paramChecker.h new file mode 100644 index 0000000..d013fc4 --- /dev/null +++ b/project2/common/paramChecker.h @@ -0,0 +1,24 @@ +#ifndef PARAMCHECKER_H +#define PARAMCHECKER_H + +#include +#include "sourceObject.h" +#include "variables.h" + +/// Base class for Project2 compoments that perform tests/checks +class ParamChecker : public SourceObject { + public: + ParamChecker(const xmlpp::Element * p); + virtual ~ParamChecker(); + + virtual bool performCheck() const = 0; + + const Variable message; + const Variable group; + const std::string present; +}; +typedef boost::intrusive_ptr ParamCheckerCPtr; + +#endif + + diff --git a/project2/common/presenter.cpp b/project2/common/presenter.cpp new file mode 100644 index 0000000..9544743 --- /dev/null +++ b/project2/common/presenter.cpp @@ -0,0 +1,50 @@ +#include "presenter.h" +#include "dataSource.h" +#include "appEngine.h" +#include + +Presenter::Presenter() +{ +} + +Presenter::~Presenter() +{ +} + +void +Presenter::pushSub(const Glib::ustring & name) const +{ + pushSub(name, Glib::ustring()); +} + +void +Presenter::addAttr(const Glib::ustring & name, const VariableType & value) const +{ + addAttr(name, Glib::ustring(), value); +} + +void +Presenter::addAttr(const Glib::ustring & name, const Glib::ustring & ns, const VariableType & value) const +{ + addField(name, ns, value); +} + +void +Presenter::addField(const Glib::ustring & name, const VariableType & value) const +{ + addField(name, Glib::ustring(), value); +} + +void +Presenter::addField(const Glib::ustring & name, const Glib::ustring & ns, const VariableType & value) const +{ + pushSub(name, ns); + addText(value); + popSub(); +} + +ContentPresenter::ContentPresenter(const Glib::ustring & ct) : + contentType(ct) +{ +} + diff --git a/project2/common/presenter.h b/project2/common/presenter.h new file mode 100644 index 0000000..a4c0a00 --- /dev/null +++ b/project2/common/presenter.h @@ -0,0 +1,55 @@ +#ifndef PRESENTER_H +#define PRESENTER_H + +#include +#include +#include +#include +#include "view.h" +#include "paramChecker.h" +#include "xmlObjectLoader.h" + +class Presenter : public virtual IntrusivePtrBase { + public: + Presenter(); + virtual ~Presenter() = 0; + + virtual void declareNamespace(const Glib::ustring & prefix, const Glib::ustring & ns) const = 0; + virtual void pushSub(const Glib::ustring & name) const; + virtual void pushSub(const Glib::ustring & name, const Glib::ustring & ns) const = 0; + virtual void setNamespace(const Glib::ustring & prefix, const Glib::ustring & ns) const = 0; + virtual void addAttr(const Glib::ustring & name, const VariableType & value) const; + virtual void addAttr(const Glib::ustring & name, const Glib::ustring & ns, const VariableType & value) const; + virtual void addField(const Glib::ustring & name, const VariableType & value) const; + 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; +}; + +class ContentPresenter : public Presenter { + public: + ContentPresenter(const Glib::ustring & contentType); + const Glib::ustring contentType; +}; + +typedef boost::intrusive_ptr PresenterCPtr; +typedef boost::intrusive_ptr 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 PresenterLoaderImpl : public PresenterLoader { + public: + virtual PresenterPtr createFrom(const xmlpp::Element * e) const + { + return new PresenterType(e); + } +}; + +#endif + diff --git a/project2/common/rowProcessor.cpp b/project2/common/rowProcessor.cpp new file mode 100644 index 0000000..4ea89fd --- /dev/null +++ b/project2/common/rowProcessor.cpp @@ -0,0 +1,57 @@ +#include "rowProcessor.h" +#include "logger.h" +#include "commonObjects.h" +#include "scopeObject.h" +#include + +RowProcessor::RowProcessor(const xmlpp::Element * p) : + IHaveParameters(p), + recordSource(p->get_attribute_value("source")), + filter(p->get_attribute_value("filter")) +{ + LoaderBase loader(true); + loader.supportedStorers.insert(Storer::into(&caches)); + loader.collectAll(p, true, IgnoreUnsupported); +} + +void +RowProcessor::loadComplete(const CommonObjects * co) +{ + source = co->getSource(recordSource); +} + +void +RowProcessor::execute() const +{ + IHaveParameters::push(this); + ScopeObject _ihp(boost::bind(&IHaveParameters::pop, this)); + BOOST_FOREACH(const CachePtr & c, caches) { + if (c->checkAndExecute(source->name, filter, this)) { + return; + } + } + BOOST_FOREACH(const CachePtr & c, caches) { + PresenterPtr p = c->openFor(source->name, filter, this); + if (p) { + tc.insert(p); + } + } + source->execute(filter, this); + tc.clear(); + BOOST_FOREACH(const CachePtr & c, caches) { + c->close(source->name, filter, this); + } +} + +void +RowProcessor::rowReadyInternal(const RowState * rs) const +{ + BOOST_FOREACH(const TargetCaches::value_type & c, tc) { + c->pushSub(filter.empty() ? "row" : filter); + rs->foreachColumn(boost::bind(&Presenter::addField, c, _2, _3)); + rs->foreachAttr(boost::bind(&Presenter::addAttr, c, _1, _2)); + c->popSub(); + } + rowReady(rs); +} + diff --git a/project2/common/rowProcessor.h b/project2/common/rowProcessor.h new file mode 100644 index 0000000..c25dc73 --- /dev/null +++ b/project2/common/rowProcessor.h @@ -0,0 +1,37 @@ +#ifndef ROWPROCESSOR_H +#define ROWPROCESSOR_H + +#include +#include "sourceObject.h" +#include "iHaveParameters.h" +#include "rowSet.h" +#include "cache.h" +#include "xmlStorage.h" + +class Presenter; + +/// Base class for Project2 components that work with row sets +class RowProcessor : public IHaveParameters { + public: + RowProcessor(const xmlpp::Element *); + void loadComplete(const CommonObjects *); + + const std::string recordSource; + const Glib::ustring filter; + + protected: + boost::intrusive_ptr source; + void execute() const; + + private: + friend class RowState; + void rowReadyInternal(const RowState *) const; + virtual void rowReady(const RowState *) const = 0; + typedef ANONORDEREDSTORAGEOF(Cache) Caches; + Caches caches; + typedef std::set TargetCaches; + mutable TargetCaches tc; +}; + +#endif + diff --git a/project2/common/rowSet.cpp b/project2/common/rowSet.cpp new file mode 100644 index 0000000..6902fd3 --- /dev/null +++ b/project2/common/rowSet.cpp @@ -0,0 +1,99 @@ +#include "rowSet.h" +#include "commonObjects.h" +#include "scopeObject.h" +#include "logger.h" +#include "variables.h" +#include "rowProcessor.h" +#include +#include + +RowState::RowValuesStack RowState::stack; + +RowSet::RowSet(const xmlpp::Element * p) : + SourceObject(p) +{ +} + +RowSet::~RowSet() +{ +} + +RowState::RowState() : + rowNum(0) +{ +} + +RowState::~RowState() +{ +} + +void +RowState::process(const RowProcessor * rp, bool r) +{ + rowNum += 1; + stack.push_back(this); + ScopeObject s(boost::bind(&RowState::RowValuesStack::pop_back, &stack)); + rp->rowReadyInternal(this); + if (r) { + reset(); + } +} + +void +RowState::reset() +{ + BOOST_FOREACH(FieldValues::value_type & v, fields) { + v = Null(); + } +} + +void +RowState::blankRow() +{ + rowNum += 1; +} + +VariableType +RowState::getRowNum() const +{ + return rowNum; +} + +RowState::RowAttribute +RowState::resolveAttr(const Glib::ustring & attrName) const +{ + if (attrName == "rownum") { + return boost::bind(&RowState::getRowNum, this); + } + throw AttributeDoesNotExist(attrName); +} + +VariableType +RowState::getCurrentValue(const Glib::ustring & col) const +{ + const Columns & columns = getColumns(); + Columns::index::type::iterator di = columns.get().find(col); + if (di != columns.get().end()) { + if (!boost::get(&fields[(*di)->idx])) { + return fields[(*di)->idx]; + } + return (*di)->defValue; + } + throw RowSet::FieldDoesNotExist(col); +} + +void +RowState::foreachColumn(const ColumnAction & action) const +{ + const Columns & columns = getColumns(); + BOOST_FOREACH(const Columns::value_type & col, columns.get()) { + action(col->idx, col->name, (!boost::get(&fields[col->idx])) ? fields[col->idx] : col->defValue()); + } +} + +void +RowState::foreachAttr(const AttrAction &) const +{ + // rowNum is magic, so it doesn't count :) +} + diff --git a/project2/common/rowSet.h b/project2/common/rowSet.h new file mode 100644 index 0000000..a181059 --- /dev/null +++ b/project2/common/rowSet.h @@ -0,0 +1,65 @@ +#ifndef ROWSET_H +#define ROWSET_H + +#include +#include +#include "sourceObject.h" +#include "exceptions.h" +#include "columns.h" +#include + +class RowProcessor; +class RowSet; +class VariableType; +typedef boost::intrusive_ptr RowSetPtr; +typedef boost::intrusive_ptr ConstRowSetPtr; + +class RowState; + +/// Base class for Project2 components that provide a row set representation of data +class RowSet : public SourceObject { + public: + SimpleNumericException(ParentOutOfRange); + SimpleMessageException(FieldDoesNotExist); + SimpleNumericException(FieldOutOfRange); + + RowSet(const xmlpp::Element *); + virtual ~RowSet() = 0; + + virtual void execute(const Glib::ustring &, const RowProcessor *) const = 0; +}; + +class RowState { + public: + RowState(); + virtual ~RowState(); + + typedef boost::function0 RowAttribute; + typedef boost::function3 ColumnAction; + typedef boost::function2 AttrAction; + SimpleMessageException(AttributeDoesNotExist); + + VariableType getRowNum() const; + void process(const RowProcessor *, bool reset = true); + void blankRow(); + void reset(); + virtual VariableType getCurrentValue(const Glib::ustring & id) const; + virtual RowAttribute resolveAttr(const Glib::ustring & attrName) const; + void foreachColumn(const ColumnAction & action) const; + virtual void foreachAttr(const AttrAction & action) const; + virtual const Columns & getColumns() const = 0; + + typedef std::vector FieldValues; + FieldValues fields; + + + typedef std::vector RowValuesStack; + static const RowValuesStack & Stack() { return stack; } + + private: + unsigned int rowNum; + static RowValuesStack stack; +}; + +#endif + diff --git a/project2/common/rowView.cpp b/project2/common/rowView.cpp new file mode 100644 index 0000000..092192f --- /dev/null +++ b/project2/common/rowView.cpp @@ -0,0 +1,73 @@ +#include "rowView.h" +#include "presenter.h" +#include "scopeObject.h" +#include "xmlObjectLoader.h" +#include "scopeObject.h" +#include +#include +#include + +DECLARE_LOADER("view", RowView); + +RowView::RowView(const xmlpp::Element * p) : + SourceObject(p), + View(p), + RowProcessor(p), + rootName(p->get_attribute_value("rootname")), + recordName(p->get_attribute_value("recordname")) +{ + BOOST_FOREACH(xmlpp::Node * node, p->find("columns/column")) { + const xmlpp::Element * elem = dynamic_cast(node); + if (elem) { + viewColumns.insert(Columns::value_type(elem->get_attribute_value("name"), + Variable::makeParent(elem->get_child_text()->get_content(), elem->get_attribute_value("source") == "attribute", 0))); + } + } + LoaderBase loader(true); + loader.supportedStorers.insert(Storer::into(&subViews)); + loader.collectAll(p, true, IgnoreUnsupported); +} + +RowView::~RowView() +{ +} + +void +RowView::loadComplete(const CommonObjects * co) +{ + RowProcessor::loadComplete(co); +} + +void +RowView::rowReady(const RowState * rs) const +{ + presenter->pushSub(recordName); + if (viewColumns.empty()) { + rs->foreachColumn(boost::bind(&Presenter::addField, presenter, _2, _3)); + } + else { + BOOST_FOREACH(const Columns::value_type & col, viewColumns) { + presenter->addField(col.first, col.second); + } + } + executeChildren(); + presenter->popSub(); +} + +void +RowView::execute(const Presenter * p) const +{ + presenter = p; + presenter->pushSub(rootName); + ScopeObject pres(boost::bind(&Presenter::popSub, p)); + RowProcessor::execute(); +} + +void +RowView::executeChildren() const +{ + BOOST_FOREACH(const SubViews::value_type & sq, subViews) { + sq->execute(presenter); + } +} + diff --git a/project2/common/rowView.h b/project2/common/rowView.h new file mode 100644 index 0000000..c065414 --- /dev/null +++ b/project2/common/rowView.h @@ -0,0 +1,33 @@ +#ifndef ROWVIEW_H +#define ROWVIEW_H + +#include +#include +#include "rowProcessor.h" +#include "view.h" + +/// Project2 component to create output based on a records in a row set +class RowView : public View, public RowProcessor { + public: + RowView(const xmlpp::Element *); + virtual ~RowView(); + + void loadComplete(const CommonObjects *); + void execute(const Presenter *) const; + void rowReady(const RowState *) const; + + const Glib::ustring rootName; + const Glib::ustring recordName; + + protected: + typedef std::map Columns; + Columns viewColumns; + + void executeChildren() const; + typedef ANONSTORAGEOF(View) SubViews; + SubViews subViews; + mutable const Presenter * presenter; +}; + +#endif + diff --git a/project2/common/safeMapFind.h b/project2/common/safeMapFind.h new file mode 100644 index 0000000..b27caf3 --- /dev/null +++ b/project2/common/safeMapFind.h @@ -0,0 +1,27 @@ +#ifndef SAFEMAPFIND_H +#define SAFEMAPFIND_H + +template +typename Map::const_iterator +safeMapFind(const Map & map, const typename Map::key_type & key) +{ + typename Map::const_iterator i = map.find(key); + if (i == map.end()) { + throw Ex(key); + } + return i; +} + +template +typename Map::mapped_type +defaultMapFind(const Map & map, const typename Map::key_type & key, const typename Map::mapped_type & def = typename Map::mapped_type()) +{ + typename Map::const_iterator i = map.find(key); + if (i == map.end()) { + return def; + } + return i->second; +} + +#endif + diff --git a/project2/common/scopeObject.cpp b/project2/common/scopeObject.cpp new file mode 100644 index 0000000..268fd2c --- /dev/null +++ b/project2/common/scopeObject.cpp @@ -0,0 +1,23 @@ +#include "scopeObject.h" +#include "logger.h" + +ScopeObject::ScopeObject(const Event & onexitpre, const Event & onsuccess, const Event & onfailure, const Event & onexitpost) : + onExitPre(onexitpre), + onSuccess(onsuccess), + onFailure(onfailure), + onExitPost(onexitpost) +{ +} + +ScopeObject::~ScopeObject() +{ + if (onExitPre) onExitPre(); + if (std::uncaught_exception()) { + if (onFailure) onFailure(); + } + else { + if (onSuccess) onSuccess(); + } + if (onExitPost) onExitPost(); +} + diff --git a/project2/common/scopeObject.h b/project2/common/scopeObject.h new file mode 100644 index 0000000..d019e7d --- /dev/null +++ b/project2/common/scopeObject.h @@ -0,0 +1,20 @@ +#ifndef SCOPE_OBJECT_H +#define SCOPE_OBJECT_H + +#include + +class ScopeObject { + public: + typedef boost::function0 Event; + ScopeObject(const Event &, const Event & = Event(), const Event & = Event(), const Event & = Event()); + ~ScopeObject(); + + private: + const Event onExitPre; + const Event onSuccess; + const Event onFailure; + const Event onExitPost; +}; + +#endif + diff --git a/project2/common/session.cpp b/project2/common/session.cpp new file mode 100644 index 0000000..6246068 --- /dev/null +++ b/project2/common/session.cpp @@ -0,0 +1,10 @@ +#include "session.h" + +Session::Session() +{ +} + +Session::~Session() +{ +} + diff --git a/project2/common/session.h b/project2/common/session.h new file mode 100644 index 0000000..7b66db9 --- /dev/null +++ b/project2/common/session.h @@ -0,0 +1,33 @@ +#ifndef SESSION_H +#define SESSION_H + +#include +#include +#include +#include "intrusivePtrBase.h" +#include "variables.h" +#include "exceptions.h" + +/// Base class for classes implementing session variable storage +class Session : public virtual IntrusivePtrBase { + public: + SimpleMessageException(VariableNotFound); + typedef std::map Values; + + Session(); + virtual ~Session() = 0; + + virtual const VariableType & GetValue(const Glib::ustring & name) const = 0; + virtual Values GetValuesCopy() const = 0; + virtual void SetValue(const Glib::ustring & name, const VariableType & value) = 0; + virtual void ClearValue(const Glib::ustring & name) = 0; + virtual time_t ExpiryTime() const = 0; + + protected: + virtual void ExpiryTime(time_t) = 0; + friend class SessionContainer; +}; +typedef boost::intrusive_ptr SessionPtr; + +#endif + diff --git a/project2/common/sessionClearTask.cpp b/project2/common/sessionClearTask.cpp new file mode 100644 index 0000000..15ba270 --- /dev/null +++ b/project2/common/sessionClearTask.cpp @@ -0,0 +1,30 @@ +#include +#include "xmlObjectLoader.h" +#include "sessionClearTask.h" +#include "appEngine.h" +#include "session.h" + +DECLARE_LOADER("sessionclear", SessionClearTask); + +SessionClearTask::SessionClearTask(const xmlpp::Element * p) : + SourceObject(p), + Task(p), + key(p->get_attribute_value("key")) +{ +} + +SessionClearTask::~SessionClearTask() +{ +} + +void +SessionClearTask::loadComplete(const CommonObjects *) +{ +} + +void +SessionClearTask::execute() const +{ + ApplicationEngine::getCurrent()->session()->ClearValue(key); +} + diff --git a/project2/common/sessionClearTask.h b/project2/common/sessionClearTask.h new file mode 100644 index 0000000..8241f8a --- /dev/null +++ b/project2/common/sessionClearTask.h @@ -0,0 +1,26 @@ +#ifndef SESSIONCLEARTASK_H +#define SESSIONCLEARTASK_H + +#include +#include +#include +#include "sourceObject.h" +#include "xmlObjectLoader.h" +#include "task.h" + +class CommonObjects; + +/// Project2 component to remove a variable from the session +class SessionClearTask : public Task { + public: + SessionClearTask(const xmlpp::Element * p); + virtual ~SessionClearTask(); + virtual void loadComplete(const CommonObjects *); + void execute() const; + + const Glib::ustring key; +}; + +#endif + + diff --git a/project2/common/sessionContainer.cpp b/project2/common/sessionContainer.cpp new file mode 100644 index 0000000..635889b --- /dev/null +++ b/project2/common/sessionContainer.cpp @@ -0,0 +1,19 @@ +#include "sessionContainer.h" +#include "environment.h" + +SessionContainer::SessionContainer() +{ +} + +SessionContainer::~SessionContainer() +{ +} + +SessionPtr +SessionContainer::GetSession(UUID & id) +{ + SessionPtr s = getSession(id); + s->ExpiryTime(time(NULL) + Environment::getCurrent()->sessionTimeOut); + return s; +} + diff --git a/project2/common/sessionContainer.h b/project2/common/sessionContainer.h new file mode 100644 index 0000000..fcad4b9 --- /dev/null +++ b/project2/common/sessionContainer.h @@ -0,0 +1,37 @@ +#ifndef SESSIONCONTAINER_H +#define SESSIONCONTAINER_H + +#include "uuid.h" +#include "session.h" +#include + +class SessionContainer : public IntrusivePtrBase { + public: + SessionContainer(); + virtual ~SessionContainer() = 0; + + SessionPtr GetSession(UUID & sid); + + protected: + virtual SessionPtr getSession(UUID & sid) = 0; +}; +typedef boost::intrusive_ptr SessionContainerPtr; + +/// Base class to implement session container imlpementations +class SessionContainerLoader : public ComponentLoader { + public: + virtual SessionContainerPtr open() const = 0; +}; + +/// Helper implemention for specific container types +template +class SessionContainerLoaderImpl : public SessionContainerLoader { + public: + virtual SessionContainerPtr open() const + { + return new SCType(); + } +}; + +#endif + diff --git a/project2/common/sessionSetTask.cpp b/project2/common/sessionSetTask.cpp new file mode 100644 index 0000000..4ae344f --- /dev/null +++ b/project2/common/sessionSetTask.cpp @@ -0,0 +1,31 @@ +#include +#include "xmlObjectLoader.h" +#include "sessionSetTask.h" +#include "appEngine.h" +#include "session.h" + +DECLARE_LOADER("sessionset", SessionSetTask); + +SessionSetTask::SessionSetTask(const xmlpp::Element * p) : + SourceObject(p), + Task(p), + key(p->get_attribute_value("key")), + value(p, "value") +{ +} + +SessionSetTask::~SessionSetTask() +{ +} + +void +SessionSetTask::loadComplete(const CommonObjects *) +{ +} + +void +SessionSetTask::execute() const +{ + ApplicationEngine::getCurrent()->session()->SetValue(key, value); +} + diff --git a/project2/common/sessionSetTask.h b/project2/common/sessionSetTask.h new file mode 100644 index 0000000..f439768 --- /dev/null +++ b/project2/common/sessionSetTask.h @@ -0,0 +1,28 @@ +#ifndef SESSIONSETTASK_H +#define SESSIONSETTASK_H + +#include +#include +#include +#include "sourceObject.h" +#include "xmlObjectLoader.h" +#include "task.h" +#include "variables.h" + +class CommonObjects; + +/// Project2 component to add/update a variable in the session +class SessionSetTask : public Task { + public: + SessionSetTask(const xmlpp::Element * p); + virtual ~SessionSetTask(); + virtual void loadComplete(const CommonObjects *); + void execute() const; + + const Glib::ustring key; + const Variable value; +}; + +#endif + + diff --git a/project2/common/sourceObject.cpp b/project2/common/sourceObject.cpp new file mode 100644 index 0000000..a5736ba --- /dev/null +++ b/project2/common/sourceObject.cpp @@ -0,0 +1,20 @@ +#include "sourceObject.h" + +unsigned int SourceObject::loadOrder = 1; + +SourceObject::SourceObject(const xmlpp::Element * p) : + name(p ? p->get_attribute_value("name") : "anon"), + order(loadOrder++) +{ +} + +SourceObject::SourceObject(const std::string & n) : + name(n), + order(loadOrder++) +{ +} + +SourceObject::~SourceObject() +{ +} + diff --git a/project2/common/sourceObject.h b/project2/common/sourceObject.h new file mode 100644 index 0000000..3ebae2c --- /dev/null +++ b/project2/common/sourceObject.h @@ -0,0 +1,26 @@ +#ifndef SOURCEOBJECT_H +#define SOURCEOBJECT_H + +#include +#include +#include "intrusivePtrBase.h" + +class CommonObjects; +class SourceObject; +typedef boost::intrusive_ptr SourceObjectPtr; +/// Base class for all Project2 components that can be placed in a Project2 script +class SourceObject : public virtual IntrusivePtrBase { + public: + SourceObject(const xmlpp::Element * p); + SourceObject(const std::string & name); + virtual ~SourceObject() = 0; + + virtual void loadComplete(const CommonObjects *) = 0; + + const std::string name; + const unsigned int order; + private: + static unsigned int loadOrder; +}; + +#endif diff --git a/project2/common/structExceptHandling.cpp b/project2/common/structExceptHandling.cpp new file mode 100644 index 0000000..f87b870 --- /dev/null +++ b/project2/common/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/common/structExceptHandling.h b/project2/common/structExceptHandling.h new file mode 100644 index 0000000..eabd384 --- /dev/null +++ b/project2/common/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/common/task.cpp b/project2/common/task.cpp new file mode 100644 index 0000000..5f828ef --- /dev/null +++ b/project2/common/task.cpp @@ -0,0 +1,13 @@ +#include "task.h" +#include + +Task::Task(const xmlpp::Element * p) : + SourceObject(p), + NoOutputExecute(p) +{ +} + +Task::~Task() +{ +} + diff --git a/project2/common/task.h b/project2/common/task.h new file mode 100644 index 0000000..57697e2 --- /dev/null +++ b/project2/common/task.h @@ -0,0 +1,18 @@ +#ifndef TASK_H +#define TASK_H + +#include +#include "sourceObject.h" +#include "noOutputExecute.h" + +/// Base class for Project2 components that perform some specific task +class Task : public NoOutputExecute { + public: + Task(const xmlpp::Element * p); + virtual ~Task(); + virtual void execute() const = 0; +}; + +#endif + + diff --git a/project2/common/taskHost.cpp b/project2/common/taskHost.cpp new file mode 100644 index 0000000..63ab301 --- /dev/null +++ b/project2/common/taskHost.cpp @@ -0,0 +1,53 @@ +#include "taskHost.h" +#include "noOutputExecute.h" +#include "dataSource.h" +#include + +TaskHost::TaskHost(const boost::filesystem::path & file) : + XmlScriptParser(file, false), + SourceObject(get_document()->get_root_node()), + CheckHost(file), + IHaveSubTasks(get_document()->get_root_node()) +{ + loader.supportedStorers.insert(Storer::into(&tasks)); +} + +TaskHost::~TaskHost() +{ +} + +void +TaskHost::loadComplete(const CommonObjects * co) +{ + IHaveSubTasks::loadComplete(co); +} + +void +TaskHost::execute() const +{ + parseDocument(); + try { + run(tasks); + commitAll(); + } + catch (...) { + rollbackAll(); + } +} + +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/common/taskHost.h b/project2/common/taskHost.h new file mode 100644 index 0000000..ca8275c --- /dev/null +++ b/project2/common/taskHost.h @@ -0,0 +1,28 @@ +#ifndef TASKHOST_H +#define TASKHOST_H + +#include "xmlStorage.h" +#include "xmlScriptParser.h" +#include "checkHost.h" +#include "iHaveSubTasks.h" + +class NoOutputExecute; +class DataSource; + +class TaskHost : virtual public XmlScriptParser, public IHaveSubTasks, virtual public CheckHost { + protected: + TaskHost(const boost::filesystem::path & file); + virtual ~TaskHost(); + + void loadComplete(const CommonObjects *); + void execute() const; + + Tasks tasks; + + private: + void commitAll() const; + void rollbackAll() const; +}; + +#endif + diff --git a/project2/common/transform.cpp b/project2/common/transform.cpp new file mode 100644 index 0000000..37524a0 --- /dev/null +++ b/project2/common/transform.cpp @@ -0,0 +1,37 @@ +#include "transform.h" +#include "logger.h" +#include + +TransformChainLink::~TransformChainLink() +{ +} + +typedef std::map > TransformLoaderMap; +void +TransformSource::addTarget(TransformChainLinkPtr tcl, const xmlpp::Element * e) +{ + BOOST_FOREACH(const TransformLoaderMap::value_type & tl, *LoaderBase::objLoaders()) { + 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 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(t.first.get())) { + tr->doTransforms(); + } + } +} + diff --git a/project2/common/transform.h b/project2/common/transform.h new file mode 100644 index 0000000..ded356b --- /dev/null +++ b/project2/common/transform.h @@ -0,0 +1,70 @@ +#ifndef TRANSFORM_H +#define TRANSFORM_H + +#include +#include "intrusivePtrBase.h" +#include "xmlObjectLoader.h" +#include + +class TransformChainLink : public virtual IntrusivePtrBase { + public: + virtual ~TransformChainLink() = 0; +}; +typedef boost::intrusive_ptr TransformChainLinkPtr; + +class Transform; +typedef boost::intrusive_ptr 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 targets; +}; +typedef boost::intrusive_ptr TransformSourcePtr; + +template +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 create() const = 0; +}; + +template +class TransformLoaderImpl : public TransformLoader { + public: + boost::intrusive_ptr create() const { + return new T(); + } +}; +#define DECLARE_TRANSFORM(T) DECLARE_COMPONENT_LOADER(#T, T, TransformLoader) + +template +class TransformImpl : public Transform { + public: + virtual void transform(const Source *, Destination *) const = 0; + void transform(const TransformSource * src, TransformChainLink * dest) const + { + transform(dynamic_cast *>(src)->operator const Source *(), dynamic_cast(dest)); + } + bool canTransform(const TransformSource * src, TransformChainLink * dest) const + { + return (dynamic_cast *>(src) && dynamic_cast(dest)); + } +}; + +#endif + diff --git a/project2/common/validDateCheck.cpp b/project2/common/validDateCheck.cpp new file mode 100644 index 0000000..410a003 --- /dev/null +++ b/project2/common/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/common/variableConvert.cpp b/project2/common/variableConvert.cpp new file mode 100644 index 0000000..b144175 --- /dev/null +++ b/project2/common/variableConvert.cpp @@ -0,0 +1,197 @@ +#include "variables.h" +#include "exceptions.h" +#include +#include +#include + +template +void +deleter(const void * t) +{ + delete static_cast(t); +} + +template +const T * +set(const VariableType * var, const T * t, VariableType::Freer f = deleter) +{ + if (var->freer) { var->freer(var->convertCache); } + var->convertCache = t; + var->freer = f; + return t; +} +template +const T * +set(const VariableType * var, const T * t) +{ + return ::set(var, t, deleter); +} + +SimpleMessageException(InvalidConversionTo); + +class NullVariable : std::runtime_error { + public: + NullVariable() : std::runtime_error("Variable has null value where one is required") { + } +}; + +// Convert to Glib::ustring +class ConvertVisitorGlibUstring : public boost::static_visitor { + public: + ConvertVisitorGlibUstring(const VariableType * v) : var(v) { + } + const Glib::ustring & operator()(const Glib::ustring & r) const { + return *::set(var, &r, NULL); + } + const Glib::ustring & operator()(const boost::posix_time::ptime & r) const { + return *::set(var, new Glib::ustring(boost::posix_time::to_iso_extended_string(r))); + } + const Glib::ustring & operator()(const Null &) const { + throw NullVariable(); + } + template + const Glib::ustring & operator()(const T & r) const { + return *::set(var, new Glib::ustring(boost::lexical_cast(r))); + } + private: + const VariableType * var; +}; +// Convert to STL std::string +class ConvertVisitorStdString : public boost::static_visitor { + public: + ConvertVisitorStdString(const VariableType * v) : var(v) { + } + const std::string & operator()(const Glib::ustring & r) const { + return *::set(var, new std::string(r)); + } + const std::string & operator()(const boost::posix_time::ptime & r) const { + return *::set(var, new std::string(boost::posix_time::to_iso_extended_string(r))); + } + const std::string & operator()(const Null &) const { + throw NullVariable(); + } + template + const std::string & operator()(const T & r) const { + return *::set(var, new std::string(boost::lexical_cast(r))); + } + private: + const VariableType * var; +}; +// Convert to char * (with std::string storage) +class ConvertVisitorCharStar : public boost::static_visitor { + public: + ConvertVisitorCharStar(const VariableType * v) : var(v) { + } + const char * operator()(const Glib::ustring & r) const { + return ::set(var, &r, NULL)->c_str(); + } + const char * operator()(const boost::posix_time::ptime & r) const { + return ::set(var, new std::string(boost::posix_time::to_iso_extended_string(r)))->c_str(); + } + const char * operator()(const Null &) const { + return ::set(var, NULL, NULL); + } + template + const char * operator()(const T & r) const { + return ::set(var, new std::string(boost::lexical_cast(r)))->c_str(); + } + private: + const VariableType * var; +}; +// Convert to unsigned char * (with std::basic_string storage / std::string) +class ConvertVisitorUCharStar : public boost::static_visitor { + public: + ConvertVisitorUCharStar(const VariableType * v) : var(v) { + } + const unsigned char * operator()(const Glib::ustring & r) const { + return reinterpret_cast(set(var, &r, NULL)->c_str()); + } + const unsigned char * operator()(const boost::posix_time::ptime & r) const { + return reinterpret_cast( + ::set(var, new std::string(boost::posix_time::to_iso_extended_string(r)))->c_str()); + } + const unsigned char * operator()(const Null &) const { + return ::set(var, NULL, NULL); + } + template + const unsigned char * operator()(const T & r) const { + return ::set(var, new std::basic_string(boost::lexical_cast >(r)))->c_str(); + } + private: + const VariableType * var; +}; +// Convert to generic type +template +class ConvertVisitor : public boost::static_visitor { + public: + ConvertVisitor(const VariableType * v) : var(v) { + } + DestType operator()(const Glib::ustring & r) const { + return boost::lexical_cast(r); + } + DestType operator()(const boost::posix_time::ptime &) const { + throw InvalidConversionTo(typeid(DestType).name()); + } + DestType operator()(const Null &) const { + throw NullVariable(); + } + template + DestType operator()(const T & r) const { + return boost::numeric_cast(r); + } + private: + const VariableType * var; +}; +// Convert to ptime +class ConvertVisitorDateTime : public boost::static_visitor { + public: + ConvertVisitorDateTime(const VariableType * v) : var(v) { + } + const boost::posix_time::ptime & operator()(const Glib::ustring & r) const { + return *::set(var, new boost::posix_time::ptime(boost::posix_time::time_from_string(r)), deleter); + } + const boost::posix_time::ptime & operator()(const boost::posix_time::ptime & r) const { + return r; + } + const boost::posix_time::ptime & operator()(const Null &) const { + throw NullVariable(); + } + template + const boost::posix_time::ptime & operator()(const T &) const { + throw InvalidConversionTo("DateTime"); + } + private: + const VariableType * var; +}; +VariableType::operator const Glib::ustring &() const +{ + return boost::apply_visitor(ConvertVisitorGlibUstring(this), *this); +} +VariableType::operator const std::string &() const +{ + return boost::apply_visitor(ConvertVisitorStdString(this), *this); +} +VariableType::operator const char *() const +{ + return boost::apply_visitor(ConvertVisitorCharStar(this), *this); +} +VariableType::operator const unsigned char *() const +{ + return boost::apply_visitor(ConvertVisitorUCharStar(this), *this); +} +VariableType::operator int32_t() const +{ + return boost::apply_visitor(ConvertVisitor(this), *this); +} +VariableType::operator int64_t() const +{ + return boost::apply_visitor(ConvertVisitor(this), *this); +} +VariableType::operator double() const +{ + return boost::apply_visitor(ConvertVisitor(this), *this); +} +VariableType::operator const boost::posix_time::ptime &() const +{ + return boost::apply_visitor(ConvertVisitorDateTime(this), *this); +} diff --git a/project2/common/variables-modconfig.cpp b/project2/common/variables-modconfig.cpp new file mode 100644 index 0000000..88fddd4 --- /dev/null +++ b/project2/common/variables-modconfig.cpp @@ -0,0 +1,22 @@ +#include "variables.h" +#include "xmlObjectLoader.h" +#include "xmlStorage.h" +#include "appEngine.h" + +/// Variable implementation to access platform configuration values +class VariableConfig : public VariableImplDyn { + public: + VariableConfig(const xmlpp::Element * e) : + VariableImplDyn(e), + name(e->get_attribute_value("name")) + { + } + VariableType value() const + { + return ApplicationEngine::getCurrent()->getCurrentConfig()->getValue(name); + } + private: + const Glib::ustring name; +}; +DECLARE_COMPONENT_LOADER("config", VariableConfig, VariableLoader); + diff --git a/project2/common/variables-modlocalparam.cpp b/project2/common/variables-modlocalparam.cpp new file mode 100644 index 0000000..24e1d54 --- /dev/null +++ b/project2/common/variables-modlocalparam.cpp @@ -0,0 +1,31 @@ +#include "variables.h" +#include "xmlObjectLoader.h" +#include "logger.h" +#include "xmlStorage.h" +#include "iHaveParameters.h" + +/// Variable implementation to access call parameters +class VariableLocalParam : public VariableImplDyn { + public: + VariableLocalParam(const xmlpp::Element * e) : + VariableImplDyn(e), + name(e->get_attribute_value("name")) + { + } + VariableType value() const + { + try { + return IHaveParameters::getScopedParameter(name); + } + catch (ParamNotFound) { + if (!defaultValue) { + throw; + } + return (*defaultValue)(); + } + } + private: + const Glib::ustring name; +}; +DECLARE_COMPONENT_LOADER("local", VariableLocalParam, VariableLoader); + diff --git a/project2/common/variables-modlookup.cpp b/project2/common/variables-modlookup.cpp new file mode 100644 index 0000000..85a1fbe --- /dev/null +++ b/project2/common/variables-modlookup.cpp @@ -0,0 +1,75 @@ +#include "variables.h" +#include "safeMapFind.h" +#include "logger.h" +#include "rowProcessor.h" +#include "rowSet.h" +#include +#include "xmlObjectLoader.h" +#include "xmlStorage.h" + + +/// Variable implementation that looks up it's value in a map of key(s)/value pairs +class VariableLookup : public VariableImplDyn, public RowProcessor { + private: + typedef std::vector Key; + typedef std::map Map; + public: + class NotFound : public std::runtime_error { + public: + NotFound(const Key & k) : + std::runtime_error(mklist(k)) { + } + static std::string mklist(const Key & k) { + std::string l("("); + for (Key::const_iterator kp = k.begin(); kp != k.end(); kp++) { + if (kp != k.begin()) l += ", "; + l += kp->operator const std::string &(); + } + l += ")"; + return l; + } + }; + VariableLookup(const xmlpp::Element * e) : + VariableImplDyn(e), + RowProcessor(e), + name(e->get_attribute_value("name")) + { + LoaderBase loader(true); + loader.supportedStorers.insert(Storer::into(&rowSets)); + loader.collectAll(e, false); + } + VariableType value() const + { + if (map.empty()) { + fillCache(); + } + Key k; + k.reserve(parameters.size()); + BOOST_FOREACH(const Parameters::value_type & p, parameters) { + k.push_back(p.second); + } + return safeMapFind(map, k)->second; + } + private: + void fillCache() const + { + BOOST_FOREACH(const RowSets::value_type & rs, rowSets) { + rs->execute(filter, this); + } + Logger()->messagef(LOG_DEBUG, "%s: %s has filled cached with %zu items", + __PRETTY_FUNCTION__, name.c_str(), map.size()); + } + void rowReady(const RowState * rs) const + { + Key k; + BOOST_FOREACH(const Parameters::value_type & p, parameters) { + k.push_back(rs->getCurrentValue(p.first)); + } + map[k] = rs->getCurrentValue(name); + } + mutable Map map; + typedef ANONSTORAGEOF(RowSet) RowSets; + RowSets rowSets; + const Glib::ustring name; +}; +DECLARE_COMPONENT_LOADER("lookup", VariableLookup, VariableLoader); diff --git a/project2/common/variables-modparam.cpp b/project2/common/variables-modparam.cpp new file mode 100644 index 0000000..0b205db --- /dev/null +++ b/project2/common/variables-modparam.cpp @@ -0,0 +1,30 @@ +#include "variables.h" +#include "xmlObjectLoader.h" +#include "xmlStorage.h" +#include "appEngine.h" + +/// Variable implementation to access call parameters +class VariableParam : public VariableImplDyn { + public: + VariableParam(const xmlpp::Element * e) : + VariableImplDyn(e), + name(e->get_attribute_value("name")) + { + } + VariableType value() const + { + try { + return ApplicationEngine::getCurrent()->env()->getParamQuery(name); + } + catch (ParamNotFound) { + if (!defaultValue) { + throw; + } + return (*defaultValue)(); + } + } + private: + const Glib::ustring name; +}; +DECLARE_COMPONENT_LOADER("param", VariableParam, VariableLoader); + diff --git a/project2/common/variables-modsession.cpp b/project2/common/variables-modsession.cpp new file mode 100644 index 0000000..963a105 --- /dev/null +++ b/project2/common/variables-modsession.cpp @@ -0,0 +1,30 @@ +#include "variables.h" +#include "xmlObjectLoader.h" +#include "xmlStorage.h" +#include "appEngine.h" + +/// Variable implementation to access session contents +class VariableSession : public VariableImplDyn { + public: + VariableSession(const xmlpp::Element * e) : + VariableImplDyn(e), + name(e->get_attribute_value("name")) + { + } + VariableType value() const + { + try { + return ApplicationEngine::getCurrent()->session()->GetValue(name); + } + catch (Session::VariableNotFound) { + if (!defaultValue) { + throw; + } + return (*defaultValue)(); + } + } + private: + const Glib::ustring name; +}; +DECLARE_COMPONENT_LOADER("session", VariableSession, VariableLoader); + diff --git a/project2/common/variables-moduri.cpp b/project2/common/variables-moduri.cpp new file mode 100644 index 0000000..00fb7bf --- /dev/null +++ b/project2/common/variables-moduri.cpp @@ -0,0 +1,30 @@ +#include "variables.h" +#include "xmlObjectLoader.h" +#include "xmlStorage.h" +#include "appEngine.h" + +/// Variable implementation to access URI path fragments +class VariableUri : public VariableImplDyn { + public: + VariableUri(const xmlpp::Element * e) : + VariableImplDyn(e), + index(atoi(e->get_attribute_value("index").c_str())) + { + } + VariableType value() const + { + try { + return ApplicationEngine::getCurrent()->env()->getParamUri(index); + } + catch (UriElementOutOfRange) { + if (!defaultValue) { + throw; + } + return (*defaultValue)(); + } + } + private: + unsigned int index; +}; +DECLARE_COMPONENT_LOADER("uri", VariableUri, VariableLoader); + diff --git a/project2/common/variables.cpp b/project2/common/variables.cpp new file mode 100644 index 0000000..9108889 --- /dev/null +++ b/project2/common/variables.cpp @@ -0,0 +1,381 @@ +#include "variables.h" +#include "iHaveParameters.h" +#include "xmlObjectLoader.h" +#include "exceptions.h" +#include "appEngine.h" +#include "session.h" +#include "rowSet.h" +#include +#include +#include +#include +#include +#include +#include +#include + +SimpleMessageException(UnknownVariableType); +SimpleMessageException(UnknownVariableSource); +SimpleMessageException(NoVariableDefinition); + +bool Null::operator<(const Null &) const +{ + return false; +} + +enum VT_typeID { + DefaultType, + String, + Int, + UInt, + LInt, + LUInt, + LLInt, + LLUInt, + Float, + Double, + DateTime, +}; + +static +VT_typeID +getVariableTypeFromName(const std::string & src) +{ + if (src.empty()) return String; + if (src == "string") return String; + if (src == "int") return Int; + if (src == "uint") return UInt; + if (src == "lint") return LInt; + if (src == "luint") return LUInt; + if (src == "llint") return LLInt; + if (src == "lluint") return LLUInt; + if (src == "float") return Float; + if (src == "double") return Double; + if (src == "datetime") return DateTime; + throw UnknownVariableType(src); +} +static +VariableType +makeVariableType(const Glib::ustring & src, const VT_typeID format = DefaultType) +{ + switch (format) { + default: + case DefaultType: + case String: + return src; + case Int: + return boost::lexical_cast(src); + case UInt: + return boost::lexical_cast(src); + case LInt: + return boost::lexical_cast(src); + case LUInt: + return boost::lexical_cast(src); + case LLInt: + return boost::lexical_cast(src); + case LLUInt: + return boost::lexical_cast(src); + case Float: + return boost::lexical_cast(src); + case Double: + return boost::lexical_cast(src); + case DateTime: + return boost::posix_time::time_from_string(src); + } +} + +VariableType::VariableType() : + _VT(), + convertCache(NULL), + freer(NULL) +{ +} + +VariableType::VariableType(const VariableType & vt) : + _VT(*((const _VT *)&vt)), + convertCache(NULL), + freer(NULL) +{ +} + +VariableType::~VariableType() +{ + if (freer && convertCache) { + freer(convertCache); + } +} + +void +VariableType::operator=(const VariableType & vt) +{ + if (freer && convertCache) { + freer(convertCache); + } + freer = NULL; + convertCache = NULL; + _VT::operator=(*((const _VT *)&vt)); +} + +template +class compi : public boost::static_visitor { + public: + compi(const S & s) : _s(s) { } + bool operator()(const S & t) const + { + return _s < t; + } + template + bool operator()(const T &) const + { + // should never be called + throw std::logic_error("Shouldn't ever be comparing variables of different type"); + } + private: + const S & _s; +}; +class comp : public boost::static_visitor { + public: + comp(const VariableType & a) : _a(a) { } + template + bool operator()(const T & t) const + { + return boost::apply_visitor(compi(t), _a); + } + private: + const VariableType & _a; +}; +bool +VariableType::operator<(const VariableType & b) const +{ + if (this->which() < b.which()) { + return true; + } + if (this->which() == b.which()) { + return boost::apply_visitor(comp(*this), b); + } + return false; +} + +/// Variable implementation whose value is a literal value of some known type +class VariableLiteral : public VariableImpl { + public: + VariableLiteral(const Glib::ustring & src, const VT_typeID format = DefaultType) : + val(makeVariableType(src, format)) + { + } + VariableLiteral(const xmlpp::Element * c) + { + if (const xmlpp::Attribute * la = c->get_attribute("value")) { + val = makeVariableType(la->get_value(), getVariableTypeFromName(c->get_attribute_value("type"))); + } + else { + BOOST_FOREACH(const xmlpp::Node * n, c->get_children()) { + if (const xmlpp::Element * e = dynamic_cast(n)) { + vals.push_back(new VarPart(e)); + } + else if (const xmlpp::TextNode * t = dynamic_cast(n)) { + vals.push_back(new TextPart(t)); + } + } + } + } + + virtual VariableType value() const + { + if (vals.empty()) { + return val; + } + if (vals.size() == 1) { + return *vals.front(); + } + Glib::ustring v; + BOOST_FOREACH(PartCPtr p, vals) { + p->appendTo(v); + } + return v; + } + private: + VariableType val; + class Part : public IntrusivePtrBase { + public: + virtual void appendTo(Glib::ustring & str) const = 0; + virtual operator VariableType() const = 0; + }; + class TextPart : public Part { + public: + TextPart(const xmlpp::TextNode * e) : + txt(e->get_content()) + { + } + void appendTo(Glib::ustring & str) const + { + str += txt; + } + operator VariableType() const + { + return txt; + } + const Glib::ustring txt; + }; + class VarPart : public Part, public Variable { + public: + VarPart(const xmlpp::Element * e) : Variable(e, boost::optional()) + { + } + void appendTo(Glib::ustring & str) const + { + str += (*this)().operator const Glib::ustring &(); + } + operator VariableType() const + { + return (*this)(); + } + }; + typedef boost::intrusive_ptr PartCPtr; + std::list vals; +}; +DECLARE_COMPONENT_LOADER("literal", VariableLiteral, VariableLoader); +DECLARE_CUSTOM_COMPONENT_LOADER("", VariableLiteralDef, VariableLoaderImpl, VariableLoader); + +VariableImplDyn::VariableImplDyn(const xmlpp::Element * e) +{ + if (e) { + defaultValue = Variable(e, "default", false); + } +} + +/// Variable implementation to access fields in row sets +class VariableParent : public VariableImplDyn { + public: + VariableParent(const xmlpp::Element * e) : + VariableImplDyn(e), + depth(e->get_attribute("depth") ? atoi(e->get_attribute_value("depth").c_str()) : 1), + attr(e->get_attribute("attribute")), + name(attr ? e->get_attribute_value("attribute") : e->get_attribute_value("name")) + { + } + VariableParent(const Glib::ustring & n, bool a, unsigned int d) : + VariableImplDyn(NULL), + depth(d), + attr(a), + name(n) + { + } + VariableType value() const + { + try { + if (!getValue) { + if (depth > RowState::Stack().size()) { + throw RowSet::ParentOutOfRange(depth); + } + bind(RowState::Stack()[RowState::Stack().size() - depth]); + } + return getValue(); + } + catch (RowSet::ParentOutOfRange) { + if (!defaultValue) { + throw; + } + return (*defaultValue)(); + } + catch (RowSet::FieldDoesNotExist) { + if (!defaultValue) { + throw; + } + return (*defaultValue)(); + } + } + protected: + void bind(const RowState * row) const + { + if (attr) { + getValue = boost::bind(row->resolveAttr(name)); + } + else { + getValue = boost::bind(&RowState::getCurrentValue, row, name); + } + } + const size_t depth; + const bool attr; + const Glib::ustring name; + mutable boost::function0 getValue; +}; +DECLARE_COMPONENT_LOADER("parent", VariableParent, VariableLoader); + +/// Variable implementation which has some fixed value +class VariableFixed : public VariableImpl { + public: + VariableFixed(VariableType v) : + var(v) + { + } + VariableType value() const + { + return var; + } + private: + VariableType var; +}; + +Variable::Variable(VariableType def) : + var(new VariableFixed(def)) +{ +} + +Variable::Variable(const xmlpp::Element * e, const Glib::ustring & n, bool required, VariableType def) +{ + xmlpp::Attribute * a = e->get_attribute(n); + if (a) { + var = new VariableLiteral(a->get_value()); + return; + } + xmlpp::Element::NodeList cs = e->get_children(n); + if (cs.size() == 1) { + const xmlpp::Element * c = dynamic_cast(cs.front()); + if (c) { + xmlpp::Attribute * source = c->get_attribute("source"); + if (source) { + var = LoaderBase::getLoader(source->get_value())->create(c); + } + else { + var = new VariableLiteral(c); + } + return; + } + } + if (!required) { + var = new VariableFixed(def); + return; + } + throw NoVariableDefinition(n); +} + +Variable::Variable(const xmlpp::Element * c, const boost::optional & defaultSource) +{ + xmlpp::Attribute * source = c->get_attribute("source"); + if (source) { + var = LoaderBase::getLoader(source->get_value())->create(c); + } + else if (defaultSource) { + var = LoaderBase::getLoader(defaultSource.get())->create(c); + } + else { + var = new VariableLiteral(c); + } +} + +Variable::Variable(VariableImpl * v) : + var(v) +{ +} + +VariableImpl::~VariableImpl() +{ +} + +Variable +Variable::makeParent(const Glib::ustring & name, bool attr, unsigned int dep) +{ + return Variable(new VariableParent(name, attr, dep)); +} + diff --git a/project2/common/variables.h b/project2/common/variables.h new file mode 100644 index 0000000..6dbbf2b --- /dev/null +++ b/project2/common/variables.h @@ -0,0 +1,120 @@ +#ifndef VARIABLES_H +#define VARIABLES_H + +#include +#include +#include +#include +#include +#include +#include +#include "intrusivePtrBase.h" +#include "xmlObjectLoader.h" +#include +#include + +class Null { + public: + bool operator<(const Null &) const; +}; +typedef boost::variant< + Null, + // Strings + Glib::ustring, + // Numbers + long long unsigned int, + long unsigned int, + unsigned int, + short unsigned int, + long long int, + long int, + int, + short int, + double, + float, + // DateTimes + boost::posix_time::ptime + > _VT; + +class VariableType : public _VT { + public: + typedef void(*Freer)(const void*); + template + VariableType(const T & t) : _VT(t), convertCache(NULL), freer(NULL) { } + VariableType(); + VariableType(const VariableType &); + ~VariableType(); + void operator=(const VariableType &); + bool operator<(const VariableType &) const; + + operator const Glib::ustring &() const; + operator const std::string &() const; + operator const char *() const; + operator const unsigned char *() const; + operator int64_t() const; + operator int32_t() const; + operator double() const; + operator const boost::posix_time::ptime &() const; + template const T * get() const { return boost::get(this); } + + private: + template friend const T * set(const VariableType * var, const T * t, Freer); + mutable const void * convertCache; + mutable Freer freer; +}; + +/// Base class for Project2 variable accessors +class VariableImpl : public IntrusivePtrBase { + public: + virtual VariableType value() const = 0; + + protected: + virtual ~VariableImpl() = 0; +}; + +class Variable { + public: + typedef boost::intrusive_ptr VariableImplPtr; + + Variable(const xmlpp::Element *, const Glib::ustring & n, bool required = true, VariableType def = VariableType()); + Variable(const xmlpp::Element *, const boost::optional &); + Variable(VariableType def); + + static Variable makeParent(const Glib::ustring & name, bool attr, unsigned int depth); + + operator VariableType () const { return var->value(); } + VariableType operator()() const { return var->value(); } + + private: + Variable(VariableImpl *); + friend class VariableParse; + VariableImplPtr var; +}; + +/// Base class for variables whose content is dynamic +class VariableImplDyn : public VariableImpl { + public: + VariableImplDyn(const xmlpp::Element * e); + virtual VariableType value() const = 0; + + protected: + boost::optional defaultValue; +}; + +/// Base class to create variables +class VariableLoader : public ComponentLoader { + public: + virtual VariableImpl * create(const xmlpp::Element *) const = 0; +}; +/// Helper implementation of VariableLoader for specific variable types +template +class VariableLoaderImpl : public VariableLoader { + public: + virtual VariableImpl * create(const xmlpp::Element * e) const + { + return new VarType(e); + } +}; + +#endif + diff --git a/project2/common/view.cpp b/project2/common/view.cpp new file mode 100644 index 0000000..ad9ef1f --- /dev/null +++ b/project2/common/view.cpp @@ -0,0 +1,11 @@ +#include "view.h" + +View::View(const xmlpp::Element * p) : + SourceObject(p) +{ +} + +View::~View() +{ +} + diff --git a/project2/common/view.h b/project2/common/view.h new file mode 100644 index 0000000..80d7b30 --- /dev/null +++ b/project2/common/view.h @@ -0,0 +1,19 @@ +#ifndef VIEW_H +#define VIEW_H + +#include "sourceObject.h" +#include "xmlStorage.h" + +class Presenter; + +/// Base class for Project2 components that output data +class View : public virtual SourceObject { + public: + View(const xmlpp::Element *); + virtual ~View(); + + virtual void execute(const Presenter *) const = 0; +}; + +#endif + diff --git a/project2/common/viewHost.cpp b/project2/common/viewHost.cpp new file mode 100644 index 0000000..3c7f8c6 --- /dev/null +++ b/project2/common/viewHost.cpp @@ -0,0 +1,100 @@ +#include "viewHost.h" +#include "transform.h" +#include +#include + +#define FOREACH_PRESENTER BOOST_FOREACH (const PresenterPtr & p, presenters) + +ViewHost::ViewHost(const boost::filesystem::path & 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 +{ + parseDocument(); + 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(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/common/viewHost.h b/project2/common/viewHost.h new file mode 100644 index 0000000..5995d82 --- /dev/null +++ b/project2/common/viewHost.h @@ -0,0 +1,46 @@ +#ifndef VIEWHOST_H +#define VIEWHOST_H + +#include "xmlScriptParser.h" +#include "paramChecker.h" +#include "xmlStorage.h" +#include "presenter.h" +#include "checkHost.h" +#include +#include + +class ViewHost : virtual public XmlScriptParser, virtual public CheckHost { + public: + class PresenterMultiplexer : public Presenter { + public: + typedef std::set 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 DefaultPresenterProvider; + + ViewHost(const boost::filesystem::path & file); + ~ViewHost(); + + void executeViews(const DefaultPresenterProvider &) const; + void doTransforms() const; + PresenterPtr headPresenter() const; + + private: + mutable PresenterMultiplexer pmp; + typedef ANONORDEREDSTORAGEOF(View) Views; + Views views; +}; +typedef boost::intrusive_ptr ViewHostPtr; + +#endif + diff --git a/project2/common/xmlObjectLoader.cpp b/project2/common/xmlObjectLoader.cpp new file mode 100644 index 0000000..14d2972 --- /dev/null +++ b/project2/common/xmlObjectLoader.cpp @@ -0,0 +1,153 @@ +#include "xmlObjectLoader.h" +#include "xmlStorage.h" +#include "logger.h" +#include "library.h" +#include "appEngine.h" +#include +#include +#include + +unsigned int LoaderBase::depth = 0; +std::set LoaderBase::loadedObjects; + +class DepthCounter { + public: + DepthCounter(unsigned int & c) : counter(c) { + counter += 1; + } + ~DepthCounter() { + counter -= 1; + } + private: + unsigned int & counter; +}; + +typedef std::map > ElementLoaderMap; +typedef std::set > ComponentLoaderSet; + +LoaderBase::LoaderBase(bool r) : + recursive(r), + ns(Environment::getCurrent()->xmlNamespace) +{ + supportedStorers.insert(Storer::into(&libraries)); +} + +LoaderBase::LoaderBase(const Glib::ustring & n, bool r) : + recursive(r), + ns(n) +{ + supportedStorers.insert(Storer::into(&libraries)); +} + +LoaderBase::~LoaderBase() +{ +} + +std::set > * & +LoaderBase::componentLoaders() +{ + static std::set > * _compLoaders = NULL; + if (!_compLoaders) { + _compLoaders = new std::set >(); + } + return _compLoaders; +} + +void +LoaderBase::collectAll(const xmlpp::Element * node, bool childrenOnly, UnsupportedHandling uh) const +{ + if (!node) { + return; + } + DepthCounter dc(depth); + unsigned int created = 0; + if (!childrenOnly && node->get_namespace_uri() == ns) { + Glib::ustring name = node->get_name(); + unsigned int stored = 0; + SourceObjectPtr o = getLoader(name)->go(node); + created += 1; + loadedObjects.insert(o); + BOOST_FOREACH(std::set >::value_type s, supportedStorers) { + if (s->save(o, node)) { + stored += 1; + } + } + if (stored < 1) { + if (uh == ErrorOnUnsupported) { + throw NotSupported(name); + } + else if (uh == WarnOnUnsupported) { + Logger()->messagef(LOG_WARNING, "'%s' unsupported in this location", name.c_str()); + } + } + } + if (created == 0 && (recursive || childrenOnly)) { + BOOST_FOREACH(const xmlpp::Node * child, node->get_children()) { + collectAll(dynamic_cast(child), false, uh); + } + } +} + +void +LoaderBase::collectAll(const CommonObjects * co, const xmlpp::Element * node, bool childrenOnly, UnsupportedHandling uh) const +{ + if (depth != 0) { + throw std::logic_error("Cannot set CommonObjects in subloader"); + } + loadedObjects.clear(); + collectAll(node, childrenOnly, uh); + BOOST_FOREACH(SourceObjectPtr o, loadedObjects) { + o->loadComplete(co); + } + loadedObjects.clear(); +} + +void +LoaderBase::onAllComponents(const boost::function1 & func) +{ + BOOST_FOREACH(ComponentLoaderSet::value_type l, *componentLoaders()) { + try { + func(l.get()); + } + catch (...) { + } + } +} + +Glib::ustring +xmlChildText(const xmlpp::Node * p, const Glib::ustring & t) +{ + Glib::ustring rtn; + BOOST_FOREACH(const xmlpp::Node * child, p->get_children(t)) { + const xmlpp::Element * e = dynamic_cast(child); + if (e) { + const xmlpp::ContentNode * cn = e->get_child_text(); + if (cn) { + rtn += cn->get_content(); + } + } + } + return rtn; +} + +void +ComponentLoader::onIdle() +{ +} + +void +ComponentLoader::onIteration() +{ +} + +void +ComponentLoader::onPeriodic() +{ +} + +boost::program_options::options_description * +ComponentLoader::options() +{ + return NULL; +} + diff --git a/project2/common/xmlObjectLoader.h b/project2/common/xmlObjectLoader.h new file mode 100644 index 0000000..4795717 --- /dev/null +++ b/project2/common/xmlObjectLoader.h @@ -0,0 +1,136 @@ +#ifndef XMLOBJECTLOADER_H +#define XMLOBJECTLOADER_H + +#include +#include +#include +#include +#include +#include "intrusivePtrBase.h" +#include "sourceObject.h" +#include "exceptions.h" + +namespace xmlpp { + class Element; +} +Glib::ustring xmlChildText(const xmlpp::Node * p, const Glib::ustring & n); + +enum UnsupportedHandling { ErrorOnUnsupported, WarnOnUnsupported, IgnoreUnsupported }; +class ElementLoader; +class ComponentLoader; +class CommonObjects; +class Storer; + +class LoaderBase { + public: + LoaderBase(bool recursive); + LoaderBase(const Glib::ustring & ns, bool recursive); + virtual ~LoaderBase(); + void collectAll(const CommonObjects * co, const xmlpp::Element * node, bool childrenOnly, + UnsupportedHandling uh = ErrorOnUnsupported) const; + void collectAll(const xmlpp::Element * node, bool childrenOnly, + UnsupportedHandling uh = ErrorOnUnsupported) const; + + std::set > supportedStorers; + + static void onAllComponents(const boost::function1 &); + + static std::set > * & componentLoaders(); + + template + static std::map > * & objLoaders() + { + static std::map > * _objLoaders = NULL; + if (!_objLoaders) { + _objLoaders = new std::map >(); + } + return _objLoaders; + } + + template + static void newLoader(const std::string & n, T * l) + { + boost::shared_ptr p = boost::shared_ptr(l); + objLoaders()->insert(std::pair >(n, p)); + componentLoaders()->insert(boost::shared_ptr(p)); + } + + template + static void removeLoader(const std::string & n) + { + std::map > * & o = objLoaders(); + std::set > * & c = componentLoaders(); + typename std::map >::iterator i = o->find(n); + c->erase(i->second); + o->erase(i); + if (o->empty()) { + delete o; + o = NULL; + } + if (c->empty()) { + delete c; + c = NULL; + } + } + + template + static boost::shared_ptr getLoader(const std::string & n) + { + typename std::map >::const_iterator i = objLoaders()->find(n); + if (i != objLoaders()->end()) { + return i->second; + } + else { + throw E(n); + } + } + + private: + static unsigned int depth; + static std::set loadedObjects; + + const bool recursive; + + public: + const Glib::ustring ns; +}; + +#define DECLARE_CUSTOM_COMPONENT_LOADER(N, I, T, B) \ + static void init_loader_##I() __attribute__ ((constructor(201))); \ + static void init_loader_##I() { LoaderBase::newLoader(N, new T()); } \ + static void kill_loader_##I() __attribute__ ((destructor(201))); \ + static void kill_loader_##I() { LoaderBase::removeLoader(N); } +#define DECLARE_CUSTOM_LOADER(N, T) \ + DECLARE_CUSTOM_COMPONENT_LOADER(N, T, T, ElementLoader) +#define DECLARE_COMPONENT_LOADER(N, T, B) \ + DECLARE_CUSTOM_COMPONENT_LOADER(N, T, B##Impl, B) +#define DECLARE_LOADER(N, T) \ + DECLARE_COMPONENT_LOADER(N, T, ElementLoader) + +/// Helper for loading and maintaining Project2 components +namespace boost { namespace program_options { class options_description; } } +class ComponentLoader { + public: + virtual void onIdle(); // When the app engine goes idle + virtual void onIteration(); // When the app engine has completed an iteration + virtual void onPeriodic(); // When the app engine feels like it + virtual boost::program_options::options_description * + options(); // Options to be populated from the common config file/env/etc +}; +/// Helper for loading and maintaining Project2 script components +class ElementLoader : public ComponentLoader { + public: + virtual SourceObjectPtr go(const xmlpp::Element * xml) const = 0; +}; + +/// Helper for loading and maintaining Project2 script components (typed implementation) +template +class ElementLoaderImpl : public ElementLoader { + public: + SourceObjectPtr go(const xmlpp::Element * xml) const + { + return new X(xml); + } +}; +#endif + diff --git a/project2/common/xmlScriptParser.cpp b/project2/common/xmlScriptParser.cpp new file mode 100644 index 0000000..9b76316 --- /dev/null +++ b/project2/common/xmlScriptParser.cpp @@ -0,0 +1,46 @@ +#include "xmlScriptParser.h" +#include +#include + +XmlScriptParser::XmlScriptParser(const boost::filesystem::path & file, bool ii) : + IsInclusion(ii), + loader(true), + documentParsed(false) +{ + loadDocument(file); +} + +void +XmlScriptParser::loadDocument(const boost::filesystem::path & file) +{ + if (!boost::filesystem::exists(file)) { + if (IsInclusion) { + throw DependencyNotFound(file.string()); + } + else { + throw NotFound(file.string()); + } + } + try { + parse_file(file.string()); + } + catch (const xmlpp::internal_error &) { + throw NotReadable(file.string()); + } + for (int x; (x = xmlXIncludeProcessFlags(get_document()->cobj(), XML_PARSE_NOXINCNODE)); ) { + if (x < 0) { + throw IncludesError(file.string()); + } + } + loader.supportedStorers.insert(Storer::into(&rowSets)); +} + +void +XmlScriptParser::parseDocument() const +{ + if (!documentParsed) { + loader.collectAll(this, get_document()->get_root_node(), true, ErrorOnUnsupported); + documentParsed = true; + } +} + diff --git a/project2/common/xmlScriptParser.h b/project2/common/xmlScriptParser.h new file mode 100644 index 0000000..9f1406d --- /dev/null +++ b/project2/common/xmlScriptParser.h @@ -0,0 +1,35 @@ +#ifndef XMLSCRIPTPARSER_H +#define XMLSCRIPTPARSER_H + +#include +#include +#include "exceptions.h" +#include "xmlObjectLoader.h" +#include +#include "commonObjects.h" +#include + +class XmlScriptParser : public xmlpp::DomParser, virtual public CommonObjects, virtual public IntrusivePtrBase { + public: + SimpleMessageException(ParseError); + SimpleMessageExceptionBase(NotFound, ParseError); + SimpleMessageExceptionBase(DependencyNotFound, ParseError); + SimpleMessageExceptionBase(NotReadable, ParseError); + SimpleMessageExceptionBase(IncludesError, ParseError); + + XmlScriptParser(const boost::filesystem::path & file, bool isInclusion); + + const bool IsInclusion; + + protected: + LoaderBase loader; + mutable bool documentParsed; + void parseDocument() const; + + private: + void loadDocument(const boost::filesystem::path & file); +}; + + +#endif + diff --git a/project2/common/xmlStorage.h b/project2/common/xmlStorage.h new file mode 100644 index 0000000..73fce0a --- /dev/null +++ b/project2/common/xmlStorage.h @@ -0,0 +1,118 @@ +#ifndef XMLSTORAGE_H +#define XMLSTORAGE_H + +#include "sourceObject.h" +#include "exceptions.h" +#include +#include +#include +#include + +SimpleMessageException(StoreFailed); + +#define STORAGEOF(X) \ + std::map > +#define ANONORDEREDSTORAGEOF(X) \ + std::list > +#define ANONSTORAGEOF(X) \ + std::set > + +class Storer; +typedef boost::intrusive_ptr StorerPtr; +class Storer : public virtual IntrusivePtrBase { + public: + template + static StorerPtr into(STORAGEOF(X) * map); + template + static StorerPtr into(ANONSTORAGEOF(X) * set); + template + static StorerPtr into(ANONORDEREDSTORAGEOF(X) * list); + + virtual bool save(SourceObjectPtr o, const xmlpp::Element *) = 0; +}; + +template +class StorerBase : public Storer { + public: + typedef M * Map; + bool save(SourceObjectPtr obj, const xmlpp::Element * p) { + boost::intrusive_ptr O = boost::dynamic_pointer_cast(obj); + if (O) { + if (insert(p, O)) { + return true; + } + throw StoreFailed(obj->name); + } + return false; + } + virtual bool insert(const xmlpp::Element *, boost::intrusive_ptr) = 0; +}; + +template +class StorerImpl : public StorerBase { + public: + StorerImpl(M * m); + bool insert(const xmlpp::Element *, boost::intrusive_ptr O); +}; +template +class StorerImpl : public StorerBase { + public: + typedef STORAGEOF(X) Map; + StorerImpl(STORAGEOF(X) * m) : map(m) + { + } + bool insert(const xmlpp::Element *, boost::intrusive_ptr O) + { + return map->insert(typename Map::value_type(O->name, O)).second; + } + Map * map; +}; +template +class StorerImpl : public StorerBase { + public: + typedef ANONSTORAGEOF(X) Map; + StorerImpl(ANONSTORAGEOF(X) * m) : map(m) + { + } + bool insert(const xmlpp::Element *, boost::intrusive_ptr O) + { + map->insert(O); + return true; + } + Map * map; +}; +template +class StorerImpl : public StorerBase { + public: + typedef ANONORDEREDSTORAGEOF(X) Map; + StorerImpl(ANONORDEREDSTORAGEOF(X) * m) : map(m) + { + } + bool insert(const xmlpp::Element *, boost::intrusive_ptr O) + { + map->push_back(O); + return true; + } + Map * map; +}; + +template +StorerPtr +Storer::into(STORAGEOF(X) * map) { + return new StorerImpl(map); +} + +template +StorerPtr +Storer::into(ANONSTORAGEOF(X) * set) { + return new StorerImpl(set); +} + +template +StorerPtr +Storer::into(ANONORDEREDSTORAGEOF(X) * list) { + return new StorerImpl(list); +} + +#endif + diff --git a/project2/commonObjects.cpp b/project2/commonObjects.cpp deleted file mode 100644 index e811fe7..0000000 --- a/project2/commonObjects.cpp +++ /dev/null @@ -1,36 +0,0 @@ -#include "commonObjects.h" -#include "appEngine.h" -#include "xmlObjectLoader.h" -#include "xmlScriptParser.h" - -CommonObjects::~CommonObjects() -{ -} - -RowSetPtr -CommonObjects::getSource(const std::string & name) const -{ - RowSets::const_iterator i = rowSets.find(name); - if (i != rowSets.end()) { - return i->second; - } - throw CommonObjects::DataSourceNotFound(name); -} - -CommonObjects::DataSources::const_iterator -CommonObjects::loadDataSource(const std::string & name) const -{ - XmlScriptParser xml(Environment::getCurrent()->resolveScript( - Environment::getCurrent()->datasourceRoot, name), true); - - LoaderBase loader(true); - loader.supportedStorers.insert(Storer::into(&datasources)); - loader.collectAll(xml.get_document()->get_root_node(), false); - - 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 deleted file mode 100644 index dae563a..0000000 --- a/project2/commonObjects.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef COMMONOBJECTS_H -#define COMMONOBJECTS_H - -#include "dataSource.h" -#include "rowSet.h" -#include "xmlStorage.h" - -class CommonObjects : public virtual IntrusivePtrBase { - public: - typedef STORAGEOF(RowSet) RowSets; - typedef STORAGEOF(DataSource) DataSources; - - SimpleMessageException(DataSourceNotFound); - SimpleMessageException(DataSourceNotCompatible); - - virtual ~CommonObjects(); - - RowSetPtr getSource(const std::string &) const; - template - const DataSourceType * dataSource(const std::string & name) const - { - DataSources::const_iterator i = datasources.find(name); - if (i == datasources.end()) { - i = loadDataSource(name); - } - const DataSourceType * s = boost::dynamic_pointer_cast(i->second).get(); - if (!s) { - throw DataSourceNotCompatible(name); - } - return s; - } - protected: - RowSets rowSets; - mutable DataSources datasources; - private: - DataSources::const_iterator loadDataSource(const std::string & name) const; -}; - -#endif - diff --git a/project2/config.cpp b/project2/config.cpp deleted file mode 100644 index a3b9afe..0000000 --- a/project2/config.cpp +++ /dev/null @@ -1,79 +0,0 @@ -#include "config.h" -#include "exceptions.h" -#include -#include -#include "xmlScriptParser.h" - -SimpleMessageException(NoSuchPlatform); -SimpleMessageException(NoSuchConfigurationValue); - -Configuration::Configuration(const Glib::ustring & ek) : - loaded(false), - engineKeys(ek) -{ -} - -void -Configuration::load() const -{ - if (loaded) { - return; - } - loaded = true; - if (!boost::filesystem::exists("config.xml")) { - return; - } - XmlScriptParser configxml("config.xml", true); - xmlpp::NodeSet ps(configxml.get_document()->get_root_node()->find("platform")); - BOOST_FOREACH(const xmlpp::Node * p, ps) { - const xmlpp::Element * pe = dynamic_cast(p); - if (pe) { - platforms[pe->get_attribute_value("name")] = new Platform(pe); - } - } - xmlpp::NodeSet eks(configxml.get_document()->get_root_node()->find(engineKeys)); - BOOST_FOREACH(const xmlpp::Node * ek, eks) { - const xmlpp::Element * eke = dynamic_cast(ek); - if (eke) { - loadEngineSection(eke); - } - } -} - -Configuration::~Configuration() -{ -} - -Configuration::PlatformPtr -Configuration::getCurrentConfig() const -{ - load(); - Glib::ustring platformName(resolveCurrentConfig()); - Platforms::const_iterator i = platforms.find(platformName); - if (i == platforms.end()) { - throw NoSuchPlatform(platformName); - } - return i->second; -} - -const Glib::ustring & -Configuration::Platform::getValue(const Glib::ustring & key) const -{ - Values::const_iterator i = values.find(key); - if (i == values.end()) { - throw NoSuchConfigurationValue(key); - } - return i->second; -} - -Configuration::Platform::Platform(const xmlpp::Element * e) -{ - xmlpp::NodeSet vs(e->find("variable")); - BOOST_FOREACH(const xmlpp::Node * v, vs) { - const xmlpp::Element * ve = dynamic_cast(v); - if (ve) { - values.insert(Values::value_type(ve->get_attribute_value("name"), ve->get_attribute_value("value"))); - } - } -} - diff --git a/project2/config.h b/project2/config.h deleted file mode 100644 index 9f6cd5d..0000000 --- a/project2/config.h +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef CONFIG_H -#define CONFIG_H - -#include -#include -#include "intrusivePtrBase.h" -#include - -class Configuration { - public: - class Platform : public virtual IntrusivePtrBase { - public: - typedef std::map Values; - - Platform(const xmlpp::Element * instanceRoot); - const Glib::ustring & getValue(const Glib::ustring & key) const; - - private: - Values values; - }; - typedef boost::intrusive_ptr PlatformPtr; - - typedef std::map Platforms; - - Configuration(const Glib::ustring & engineKeys); - virtual ~Configuration() = 0; - - PlatformPtr getCurrentConfig() const; - - protected: - virtual Glib::ustring resolveCurrentConfig() const = 0; - void load() const; - - private: - virtual void loadEngineSection(const xmlpp::Element *) const = 0; - - mutable bool loaded; - mutable Platforms platforms; - const Glib::ustring engineKeys; -}; - -#endif - diff --git a/project2/console/Jamfile.jam b/project2/console/Jamfile.jam new file mode 100644 index 0000000..72d2c1f --- /dev/null +++ b/project2/console/Jamfile.jam @@ -0,0 +1,12 @@ +alias libxmlpp : : : : + "`pkg-config --cflags libxml++-2.6`" + "`pkg-config --libs libxml++-2.6`" ; + +exe p2console : + [ glob *.cpp ] + : + ..//p2parts + ../common//p2common + ../../libmisc + ; + diff --git a/project2/console/consoleAppEngine.cpp b/project2/console/consoleAppEngine.cpp index 32789be..ce1cd0a 100644 --- a/project2/console/consoleAppEngine.cpp +++ b/project2/console/consoleAppEngine.cpp @@ -1,7 +1,7 @@ #include "consoleAppEngine.h" #include "consoleEnvironment.h" -#include "../iterate.h" -#include "../xmlObjectLoader.h" +#include "iterate.h" +#include "xmlObjectLoader.h" #include #include #include diff --git a/project2/console/consoleAppEngine.h b/project2/console/consoleAppEngine.h index 5e0a403..f547a99 100644 --- a/project2/console/consoleAppEngine.h +++ b/project2/console/consoleAppEngine.h @@ -1,14 +1,14 @@ #ifndef CONSOLEAPPENGINE_H #define CONSOLEAPPENGINE_H -#include "../appEngine.h" -#include "../task.h" -#include "../paramChecker.h" -#include "../presenter.h" -#include "../commonObjects.h" -#include "../view.h" -#include "../taskHost.h" -#include "../viewHost.h" +#include "appEngine.h" +#include "task.h" +#include "paramChecker.h" +#include "presenter.h" +#include "commonObjects.h" +#include "view.h" +#include "taskHost.h" +#include "viewHost.h" #include #include diff --git a/project2/console/consoleEnvironment.cpp b/project2/console/consoleEnvironment.cpp index 6d1471b..128ecac 100644 --- a/project2/console/consoleEnvironment.cpp +++ b/project2/console/consoleEnvironment.cpp @@ -3,9 +3,9 @@ #include #include #include -#include "../logger.h" -#include "../exceptions.h" -#include "../xmlObjectLoader.h" +#include "logger.h" +#include "exceptions.h" +#include "xmlObjectLoader.h" #include #include #include diff --git a/project2/console/consoleEnvironment.h b/project2/console/consoleEnvironment.h index c72eed5..363090d 100644 --- a/project2/console/consoleEnvironment.h +++ b/project2/console/consoleEnvironment.h @@ -4,7 +4,7 @@ #include #include #include -#include "../environment.h" +#include "environment.h" class ConsoleEnvironment : public Environment { public: diff --git a/project2/console/consolePresenter.h b/project2/console/consolePresenter.h index 98cce6d..dc409ab 100644 --- a/project2/console/consolePresenter.h +++ b/project2/console/consolePresenter.h @@ -1,8 +1,8 @@ #ifndef CONSOLEPRESENTER_H #define CONSOLEPRESENTER_H -#include "../presenter.h" -#include "../fileStrmVarWriter.h" +#include "presenter.h" +#include "fileStrmVarWriter.h" class ConsolePresenter : public Presenter { public: diff --git a/project2/console/p2consoleMain.cpp b/project2/console/p2consoleMain.cpp index 40995d2..bad803f 100644 --- a/project2/console/p2consoleMain.cpp +++ b/project2/console/p2consoleMain.cpp @@ -1,8 +1,8 @@ #include #include "consoleEnvironment.h" #include "consoleAppEngine.h" -#include "../xmlObjectLoader.h" -#include "../logger.h" +#include "xmlObjectLoader.h" +#include "logger.h" #include #include diff --git a/project2/curlHelper.cpp b/project2/curlHelper.cpp deleted file mode 100644 index 7c204aa..0000000 --- a/project2/curlHelper.cpp +++ /dev/null @@ -1,45 +0,0 @@ -#include "curlHelper.h" - -CurlHelper::CurlHelper(const xmlpp::Element * p) : - url(p, "url"), - userAgent(p, "useragent", false, "project2/0.3"), - cookieJar(p, "cookiejar", false), - proxy(p, "proxy", false), - method(p, "method", false), - userName(p, "username", false), - password(p, "password", false), - timeout(p, "timeout", false, Variable(6000)) -{ -} - -CurlHelper::~CurlHelper() -{ -} - -CurlHandle::Ptr -CurlHelper::newCurl() const -{ - CurlHandle::Ptr c = new CurlHandle(); - c->setopt(CURLOPT_FOLLOWLOCATION, 1); - c->setopt(CURLOPT_ENCODING, "deflate, gzip"); - setopt_s(c, CURLOPT_URL, url()); - setopt_s(c, CURLOPT_USERAGENT, userAgent()); - setopt_s(c, CURLOPT_PROXY, proxy()); - setopt_s(c, CURLOPT_COOKIEFILE, cookieJar()); - setopt_s(c, CURLOPT_COOKIEJAR, cookieJar()); - setopt_l(c, CURLOPT_TIMEOUT_MS, timeout()); - return c; -} - -void -CurlHelper::setopt_s(CurlHandle::Ptr c, CURLoption o, const char * v) -{ - c->setopt(o, v); -} - -void -CurlHelper::setopt_l(CurlHandle::Ptr c, CURLoption o, int64_t v) -{ - c->setopt(o, (long)v); -} - diff --git a/project2/curlHelper.h b/project2/curlHelper.h deleted file mode 100644 index afebcdc..0000000 --- a/project2/curlHelper.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef CURLHELPER_H -#define CURLHELPER_H - -#include -#include "variables.h" -#include "../libmisc/curlsup.h" - -/// Project2 helper component to provide common access to remote resources via libcurl -class CurlHelper { - public: - CurlHelper(const xmlpp::Element * p); - ~CurlHelper(); - - const Variable url; - - protected: - CurlHandle::Ptr newCurl() const; - - private: - static void setopt_s(CurlHandle::Ptr, CURLoption, const char *); - static void setopt_l(CurlHandle::Ptr, CURLoption, int64_t); - - const Variable userAgent; - const Variable cookieJar; - const Variable proxy; - const Variable method; - const Variable userName; - const Variable password; - const Variable timeout; -}; - -#endif - diff --git a/project2/dataSource.cpp b/project2/dataSource.cpp deleted file mode 100644 index e40ad64..0000000 --- a/project2/dataSource.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#include "dataSource.h" - -DataSource::DataSource(const xmlpp::Element * p) : - SourceObject(p) -{ -} - -DataSource::~DataSource() -{ -} - diff --git a/project2/dataSource.h b/project2/dataSource.h deleted file mode 100644 index d8a5a9a..0000000 --- a/project2/dataSource.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef DATASOURCE_H -#define DATASOURCE_H - -#include -#include "sourceObject.h" - -class DataSource; -typedef boost::intrusive_ptr DataSourcePtr; - -/// Base class for data sources providing transaction support -class DataSource : public SourceObject { - public: - DataSource(const xmlpp::Element * p); - virtual ~DataSource(); - - virtual void commit() { }; - virtual void rollback() { }; -}; - -#endif - - diff --git a/project2/definedColumns.cpp b/project2/definedColumns.cpp deleted file mode 100644 index 5260e51..0000000 --- a/project2/definedColumns.cpp +++ /dev/null @@ -1,31 +0,0 @@ -#include "definedColumns.h" -#include -#include - -DefinedColumns::DefinedColumns(const xmlpp::Element * p, const Glib::ustring & colPath, const ColCreator & func) -{ - unsigned int colNo = 0; - BOOST_FOREACH(const xmlpp::Node * node, p->find(colPath)) { - const xmlpp::Element * elem = dynamic_cast(node); - if (elem) { - columns.insert(func(colNo++, elem)); - } - } -} - -ColumnValues::ColumnValues(const DefinedColumns * rs) : - rowSet(rs) -{ - fields.resize(rs->columns.size()); -} - -ColumnValues::~ColumnValues() -{ -} - -const Columns & -ColumnValues::getColumns() const -{ - return rowSet->columns; -} - diff --git a/project2/definedColumns.h b/project2/definedColumns.h deleted file mode 100644 index 2fc6bbd..0000000 --- a/project2/definedColumns.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef DEFINEDCOLUMNS_H -#define DEFINEDCOLUMNS_H - -#include -#include -#include "variables.h" -#include "rowSet.h" -#include "columns.h" - -class DefinedColumns { - public: - typedef boost::function2 ColCreator; - DefinedColumns(const xmlpp::Element * p, const Glib::ustring & colPath, const ColCreator & func); - Columns columns; -}; - -class ColumnValues : public RowState { - public: - ColumnValues(const DefinedColumns *); - virtual ~ColumnValues(); - - virtual const Columns & getColumns() const; - - const DefinedColumns * const rowSet; -}; - -#endif - - diff --git a/project2/environment.cpp b/project2/environment.cpp deleted file mode 100644 index 0c563cc..0000000 --- a/project2/environment.cpp +++ /dev/null @@ -1,121 +0,0 @@ -#include "environment.h" -#include "loggers.h" -#include "xmlObjectLoader.h" -#include -#include -#include -#include -#include - -namespace po = boost::program_options; - -const Environment * Environment::currentEnv(NULL); -int Environment::clLevel(-1); -int Environment::slLevel(-1); -bool Environment::optionsBuilt(false); -po::options_description Environment::allOptions("Project2 options"); -po::positional_options_description Environment::posOptions; - -Environment::Environment(int c, char ** v) : - argc(c), - argv(v) -{ - currentEnv = this; -} - -static -po::variables_map -injectSettingsHelper(int argc, char ** argv, const po::options_description * opts, po::positional_options_description * posOpts) -{ - po::variables_map settings; - if (!opts) { - return settings; - } - if (argc > 0 && argv != NULL) { - if (posOpts) { - po::store(po::command_line_parser(argc, argv).options(*opts).positional(*posOpts).allow_unregistered().run(), settings); - } - else { - po::store(po::command_line_parser(argc, argv).options(*opts).allow_unregistered().run(), settings); - } - } - po::store(po::parse_environment(*opts, "P2_"), settings); - if (boost::filesystem::exists(".p2config")) { - std::ifstream f(".p2config"); - po::store(po::parse_config_file(f, *opts, true), settings); - } - po::notify(settings); - return settings; -} - -void -Environment::init() -{ - if (!optionsBuilt) { - po::options_description common("Project2 Common options"); - common.add_options() - ("sysloglevel,s", po::value(&slLevel)->default_value(-1), - "Log to syslog with level (default OFF)") - ("consoleloglevel,c", po::value(&clLevel)->default_value(LOG_WARNING), - "Log to console with level (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") - ("sessionTimeOut", boost::program_options::value(&sessionTimeOut)->default_value(3600), - "The time after which idle sessions are forgetten") - ; - allOptions.add(common).add(addOptions(posOptions)); - optionsBuilt = true; - } - po::variables_map settings(injectSettingsHelper(argc, argv, &allOptions, &posOptions)); - postinit(allOptions, settings); - LoaderBase::onAllComponents(boost::bind( - injectSettingsHelper, argc, argv, boost::bind(&ComponentLoader::options, _1), (po::positional_options_description*)NULL)); - - Logger()->clear(); - if (clLevel >= 0) { - Logger()->addLogger(new ConsoleLogDriver(stderr, clLevel, false)); - } - if (slLevel >= 0) { - Logger()->addLogger(new SyslogLogDriver(getScriptName().c_str(), slLevel)); - } -} - -Environment::~Environment() -{ - currentEnv = NULL; -} - -const Environment * -Environment::getCurrent() -{ - return currentEnv; -} - -boost::filesystem::path -Environment::resolveScript(const std::string & group, const std::string & name) const -{ - boost::filesystem::path script(boost::filesystem::current_path() / group); - BOOST_FOREACH(const boost::filesystem::path & e, boost::filesystem::path(name)) { - if (boost::filesystem::is_directory(script / e)) { - script /= e; - } - else { - if (boost::filesystem::is_regular_file((script / e).replace_extension(".xml"))) { - return ((script / e).replace_extension(".xml")); - } - } - } - return script; -} - -boost::filesystem::path -Environment::resolveScript(const std::string & path) const -{ - boost::filesystem::path script(boost::filesystem::current_path()); - return script / path; -} - diff --git a/project2/environment.h b/project2/environment.h deleted file mode 100644 index 681a80c..0000000 --- a/project2/environment.h +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef ENVIRONMENT_H -#define ENVIRONMENT_H - -#include -#include -#include -#include -#include - -class Environment { - public: - Environment(int argc, char ** argv); - virtual ~Environment() = 0; - - void init(); - - static const Environment * getCurrent(); - - virtual Glib::ustring getParamUri(unsigned int idx) const = 0; - virtual Glib::ustring getParamQuery(const std::string & idx) const = 0; - - virtual std::string getServerName() const = 0; - virtual std::string getScriptName() const = 0; - - boost::filesystem::path resolveScript(const std::string & group, const std::string & name) const; - boost::filesystem::path resolveScript(const std::string & path) const; - - 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; - char ** argv; - - static bool optionsBuilt; - static boost::program_options::options_description allOptions; - static boost::program_options::positional_options_description posOptions; - - static int clLevel; - static int slLevel; - - public: - std::string datasourceRoot; - Glib::ustring xmlNamespace; - Glib::ustring xmlPrefix; - time_t sessionTimeOut; -}; - -#endif - diff --git a/project2/exceptions.cpp b/project2/exceptions.cpp deleted file mode 100644 index ddf8e94..0000000 --- a/project2/exceptions.cpp +++ /dev/null @@ -1,26 +0,0 @@ -#include "exceptions.h" -#include -#include - -numeric_error::numeric_error(int e) : - err(e), - buf(NULL) -{ -} - -numeric_error::~numeric_error() throw() -{ - free(buf); -} - -const char * -numeric_error::what() const throw() -{ - if (!buf) { - if (asprintf(&buf, "%d", err) < 1) { - throw std::bad_alloc(); - } - } - return buf; -} - diff --git a/project2/exceptions.h b/project2/exceptions.h deleted file mode 100644 index a9d4952..0000000 --- a/project2/exceptions.h +++ /dev/null @@ -1,44 +0,0 @@ -#ifndef EXCEPTION_H -#define EXCEPTION_H - -#include - -class numeric_error : public std::exception { - public: - numeric_error(int); - ~numeric_error() throw(); - const char * what() const throw(); - private: - int err; - mutable char * buf; -}; -#define StaticMessageException(Name, Text) \ -class Name : public std::runtime_error { \ - public: \ - Name() : std::runtime_error(Text) { } \ -} -#define SimpleMessageException(Name) \ -class Name : public std::runtime_error { \ - public: \ - Name(const std::string & what) : std::runtime_error(what) { } \ -} -#define SimpleMessageExceptionBase(Name, Base) \ -class Name : public Base { \ - public: \ - Name(const std::string & what) : Base(what) { } \ -} -#define SimpleNumericException(Name) \ -class Name : public numeric_error { \ - public: \ - Name(int e) : numeric_error(e) { } \ -} - -SimpleNumericException(UriElementOutOfRange); -SimpleMessageException(ParamNotFound); -SimpleMessageException(NotSupported); -SimpleMessageException(FileNotReadable); -SimpleMessageException(FileNotWritable); -SimpleMessageException(FilterNotFound); - -#endif - diff --git a/project2/fileRows.cpp b/project2/fileRows.cpp deleted file mode 100644 index d7c8fca..0000000 --- a/project2/fileRows.cpp +++ /dev/null @@ -1,52 +0,0 @@ -#include "fileRows.h" -#include "logger.h" -#include "rowProcessor.h" -#include "xmlObjectLoader.h" -#include "exceptions.h" -#include - -DECLARE_LOADER("filerows", FileRows); - -FileRows::FileRows(const xmlpp::Element * p) : - StreamRows(p), - path(p, "path") -{ -} - -FileRows::~FileRows() -{ -} - -void -FileRows::loadComplete(const CommonObjects *) -{ -} - -void -FileRows::setFilter(const Glib::ustring &) -{ - throw NotSupported(__PRETTY_FUNCTION__); -} - -void -FileRows::execute(const Glib::ustring &, const RowProcessor * rp) const -{ - FileStarChannel c(doOpen()); - c.set_encoding(encoding); - gunichar ch; - ParseState ps(this, rp); - while (c.read(ch) == Glib::IO_STATUS_NORMAL) { - this->pushChar(ch, ps); - } -} - -FileStarChannel -FileRows::doOpen() const -{ - FILE * f = fopen(path(), "r"); - if (!f) { - throw FileNotReadable(path()); - } - return FileStarChannel(f, true, fclose); -} - diff --git a/project2/fileRows.h b/project2/fileRows.h deleted file mode 100644 index 0cf3f1d..0000000 --- a/project2/fileRows.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef FILEROWS_H -#define FILEROWS_H - -#include "streamRows.h" -#include "fileStarGlibIoChannel.h" - -class CommonObjects; - -/// Project2 component to create a row set from the contents of a file on the local filesystem -class FileRows : public StreamRows { - public: - FileRows(const xmlpp::Element * p); - ~FileRows(); - - void execute(const Glib::ustring &, const RowProcessor *) const; - virtual void loadComplete(const CommonObjects *); - virtual void setFilter(const Glib::ustring &); - - const Variable path; - - protected: - virtual FileStarChannel doOpen() const; -}; - -#endif - - diff --git a/project2/fileStarGlibIoChannel.cpp b/project2/fileStarGlibIoChannel.cpp deleted file mode 100644 index 3ec26ce..0000000 --- a/project2/fileStarGlibIoChannel.cpp +++ /dev/null @@ -1,65 +0,0 @@ -#include "fileStarGlibIoChannel.h" -#include -#include -#include -#include - -FileStarChannel::FileStarChannel(FILE * f, bool seekable, int (*closer)(FILE*)) : - Glib::IOChannel(), - file(f, closer) -{ - gobj()->is_seekable = seekable ? 1 : 0; - gobj()->is_readable = 1; - gobj()->is_writeable = 0; -} - -FileStarChannel::~FileStarChannel() -{ -} - -Glib::IOStatus -FileStarChannel::close_vfunc() -{ - if (file) { - file.reset(); - } - return Glib::IO_STATUS_NORMAL; -} - -Glib::IOStatus -FileStarChannel::set_flags_vfunc(Glib::IOFlags) -{ - return Glib::IO_STATUS_NORMAL; -} - -Glib::IOFlags -FileStarChannel::get_flags_vfunc() -{ - return Glib::IO_FLAG_IS_SEEKABLE | Glib::IO_FLAG_IS_READABLE; -} - -Glib::IOStatus -FileStarChannel::seek_vfunc(gint64 offset, Glib::SeekType type) -{ - if (fseek(file.get(), offset, type)) { - return Glib::IO_STATUS_ERROR; - } - return Glib::IO_STATUS_NORMAL; -} - -Glib::IOStatus -FileStarChannel::read_vfunc(char* buf, gsize count, gsize& bytes_read) -{ - bytes_read = fread(buf, 1, count, file.get()); - if (bytes_read == 0) { - if (feof(file.get())) { - return Glib::IO_STATUS_EOF; - } - if (ferror(file.get())) { - return Glib::IO_STATUS_ERROR; - } - return Glib::IO_STATUS_AGAIN; - } - return Glib::IO_STATUS_NORMAL; -} - diff --git a/project2/fileStarGlibIoChannel.h b/project2/fileStarGlibIoChannel.h deleted file mode 100644 index 77b6282..0000000 --- a/project2/fileStarGlibIoChannel.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef FILESTARGLIBIOCHANNEL_H -#define FILESTARGLIBIOCHANNEL_H - -#include -#include -#include -#include -#include "intrusivePtrBase.h" - -class FileStarChannel : public Glib::IOChannel, public virtual IntrusivePtrBase { - public: - FileStarChannel(FILE * f, bool seekable, int (*closer)(FILE *) = fclose); - virtual ~FileStarChannel(); - - virtual Glib::IOStatus close_vfunc(); - virtual Glib::IOStatus set_flags_vfunc(Glib::IOFlags flags); - virtual Glib::IOFlags get_flags_vfunc(); - virtual Glib::IOStatus seek_vfunc(gint64 offset, Glib::SeekType type); - virtual Glib::IOStatus read_vfunc(char* buf, gsize count, gsize& bytes_read); - protected: - typedef boost::shared_ptr FilePtr; - FilePtr file; -}; - -#endif - diff --git a/project2/fileStrmVarWriter.cpp b/project2/fileStrmVarWriter.cpp deleted file mode 100644 index 51fb487..0000000 --- a/project2/fileStrmVarWriter.cpp +++ /dev/null @@ -1,61 +0,0 @@ -#include "fileStrmVarWriter.h" -#include "rowSet.h" -#include "xmlObjectLoader.h" -#include -#include -#include - -FileStreamVariableWriter::FileStreamVariableWriter(FILE * o, bool q) : - out(o), - quoting(q) -{ -} - -FileStreamVariableWriter::~FileStreamVariableWriter() -{ -} - -void FileStreamVariableWriter::operator()(const Null &) const { - fprintf(out, ""); -} -void FileStreamVariableWriter::operator()(const long long int & i) const { - fprintf(out, "%lld", i); -} -void FileStreamVariableWriter::operator()(const long int & i) const { - fprintf(out, "%ld", i); -} -void FileStreamVariableWriter::operator()(const int & i) const { - fprintf(out, "%d", i); -} -void FileStreamVariableWriter::operator()(const short int & i) const { - fprintf(out, "%hd", i); -} -void FileStreamVariableWriter::operator()(const long long unsigned int & i) const { - fprintf(out, "%llu", i); -} -void FileStreamVariableWriter::operator()(const long unsigned int & i) const { - fprintf(out, "%lu", i); -} -void FileStreamVariableWriter::operator()(const unsigned int & i) const { - fprintf(out, "%u", i); -} -void FileStreamVariableWriter::operator()(const short unsigned int & i) const { - fprintf(out, "%hu", i); -} -void FileStreamVariableWriter::operator()(const float & i) const { - fprintf(out, "%g", i); -} -void FileStreamVariableWriter::operator()(const double & i) const { - fprintf(out, "%g", i); -} -void FileStreamVariableWriter::operator()(const Glib::ustring & i) const { - fputc('\'', out); - if (fwrite(i.c_str(), i.bytes(), 1, out) < 1) { - // Care much? None of the others check. - } - fputc('\'', out); -} -void FileStreamVariableWriter::operator()(const boost::posix_time::ptime & i) const { - fprintf(out, "[%s]", boost::posix_time::to_iso_extended_string(i).c_str()); -} - diff --git a/project2/fileStrmVarWriter.h b/project2/fileStrmVarWriter.h deleted file mode 100644 index b98691b..0000000 --- a/project2/fileStrmVarWriter.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef FILESTREAMVARWRITER_H -#define FILESTREAMVARWRITER_H - -#include "variables.h" - -class FileStreamVariableWriter : public boost::static_visitor<> { - public: - FileStreamVariableWriter(FILE *, bool quoting); - ~FileStreamVariableWriter(); - - void operator()(const Null &) const; - void operator()(const long long int & i) const; - void operator()(const long int & i) const; - void operator()(const int & i) const; - void operator()(const short int & i) const; - void operator()(const long long unsigned int & i) const; - void operator()(const long unsigned int & i) const; - void operator()(const unsigned int & i) const; - void operator()(const short unsigned int & i) const; - void operator()(const float & i) const; - void operator()(const double & i) const; - void operator()(const Glib::ustring & i) const; - void operator()(const boost::posix_time::ptime & i) const; - - private: - FILE * out; - bool quoting; -}; - -#endif - diff --git a/project2/files/Jamfile.jam b/project2/files/Jamfile.jam new file mode 100644 index 0000000..ec1e19e --- /dev/null +++ b/project2/files/Jamfile.jam @@ -0,0 +1,20 @@ +alias libxmlpp : : : : + "`pkg-config --cflags libxml++-2.6`" + "`pkg-config --libs libxml++-2.6`" ; +lib boost_system : : boost_system ; +lib boost_filesystem : : boost_filesystem ; + +lib p2files : + fsRows.cpp + fileRows.cpp + streamRows.cpp + : + ../libmisc + libxmlpp + boost_filesystem + boost_system + ../common//p2common + : : + . + ; + diff --git a/project2/files/fileRows.cpp b/project2/files/fileRows.cpp new file mode 100644 index 0000000..d7c8fca --- /dev/null +++ b/project2/files/fileRows.cpp @@ -0,0 +1,52 @@ +#include "fileRows.h" +#include "logger.h" +#include "rowProcessor.h" +#include "xmlObjectLoader.h" +#include "exceptions.h" +#include + +DECLARE_LOADER("filerows", FileRows); + +FileRows::FileRows(const xmlpp::Element * p) : + StreamRows(p), + path(p, "path") +{ +} + +FileRows::~FileRows() +{ +} + +void +FileRows::loadComplete(const CommonObjects *) +{ +} + +void +FileRows::setFilter(const Glib::ustring &) +{ + throw NotSupported(__PRETTY_FUNCTION__); +} + +void +FileRows::execute(const Glib::ustring &, const RowProcessor * rp) const +{ + FileStarChannel c(doOpen()); + c.set_encoding(encoding); + gunichar ch; + ParseState ps(this, rp); + while (c.read(ch) == Glib::IO_STATUS_NORMAL) { + this->pushChar(ch, ps); + } +} + +FileStarChannel +FileRows::doOpen() const +{ + FILE * f = fopen(path(), "r"); + if (!f) { + throw FileNotReadable(path()); + } + return FileStarChannel(f, true, fclose); +} + diff --git a/project2/files/fileRows.h b/project2/files/fileRows.h new file mode 100644 index 0000000..0cf3f1d --- /dev/null +++ b/project2/files/fileRows.h @@ -0,0 +1,27 @@ +#ifndef FILEROWS_H +#define FILEROWS_H + +#include "streamRows.h" +#include "fileStarGlibIoChannel.h" + +class CommonObjects; + +/// Project2 component to create a row set from the contents of a file on the local filesystem +class FileRows : public StreamRows { + public: + FileRows(const xmlpp::Element * p); + ~FileRows(); + + void execute(const Glib::ustring &, const RowProcessor *) const; + virtual void loadComplete(const CommonObjects *); + virtual void setFilter(const Glib::ustring &); + + const Variable path; + + protected: + virtual FileStarChannel doOpen() const; +}; + +#endif + + diff --git a/project2/files/fsRows.cpp b/project2/files/fsRows.cpp new file mode 100644 index 0000000..cb73b04 --- /dev/null +++ b/project2/files/fsRows.cpp @@ -0,0 +1,320 @@ +#include "fsRows.h" +#include "logger.h" +#include "xmlObjectLoader.h" +#include "rowProcessor.h" +#include "exceptions.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef boost::filesystem::directory_iterator DirEnt; + +DECLARE_LOADER("fsrows", FsRows); + +const Glib::ustring field_absPath("absPath"); +const Glib::ustring field_relPath("relPath"); +const Glib::ustring field_size("size"); +const Glib::ustring field_modDate("modifiedDate"); +const Glib::ustring field_user("owningUser"); +const Glib::ustring field_group("owningGroup"); +const Glib::ustring field_mode("mode"); +const Glib::ustring field_perms("perms"); +const Glib::ustring field_type("type"); +static +Columns defCols() { + Columns rtn; + rtn.insert(new Column(0, "absPath")); + return rtn; +} +const Columns FsRows::SearchState::col(defCols()); + +bool FsRows::SpecBase::recurse(const SearchState *) const { return true; } +bool FsRows::SpecBase::matches(const SearchState *) const { return true; } +const boost::filesystem::path & FsRows::SpecBase::curPath(const SearchState * fs) const { return fs->curPath; } +unsigned int FsRows::SpecBase::depth(const SearchState * fs) const { return fs->depth; } +const struct stat & FsRows::SpecBase::curStat(const SearchState * fs) const { return fs->curStat; } + +class FsRowSpecName : public FsRows::SpecBase { + public: + FsRowSpecName(const Glib::ustring & v) : pattern(v) { } + bool matches(const FsRows::SearchState * fs) const { + // Based on code written by Jack Handy - jakkhandy@hotmail.com + // from http://www.codeproject.com/KB/string/wildcmp.aspx + Glib::ustring::const_iterator wild = pattern.begin(); +#if BOOST_VERSION >= 104500 + Glib::ustring leaf(curPath(fs).leaf().string()); +#else + Glib::ustring leaf(curPath(fs).leaf()); +#endif + Glib::ustring::const_iterator string = leaf.begin(); + + while ((string != leaf.end()) && (*wild != '*')) { + if ((*wild != *string) && (*wild != '?')) { + return false; + } + wild++; + string++; + } + + Glib::ustring::const_iterator cp, mp; + while (string != leaf.end()) { + if (*wild == '*') { + if (!*++wild) { + return true; + } + mp = wild; + cp = string; + cp++; + } else if ((*wild == *string) || (*wild == '?')) { + wild++; + string++; + } else { + wild = mp; + string = cp++; + } + } + + while (*wild == '*') { + wild++; + } + return wild == pattern.end(); + } + const Glib::ustring pattern; +}; +class FsRowSpecType : public FsRows::SpecBase { + public: + FsRowSpecType(const Glib::ustring & v) : types(v) { } + bool matches(const FsRows::SearchState * fs) const { + if (S_ISREG(curStat(fs).st_mode)) { + return types.find('f') != Glib::ustring::npos; + } + if (S_ISDIR(curStat(fs).st_mode)) { + return types.find('d') != Glib::ustring::npos; + } + if (S_ISCHR(curStat(fs).st_mode)) { + return types.find('c') != Glib::ustring::npos; + } + if (S_ISBLK(curStat(fs).st_mode)) { + return types.find('b') != Glib::ustring::npos; + } + if (S_ISFIFO(curStat(fs).st_mode)) { + return types.find('p') != Glib::ustring::npos; + } + if (S_ISLNK(curStat(fs).st_mode)) { + return types.find('l') != Glib::ustring::npos; + } + if (S_ISSOCK(curStat(fs).st_mode)) { + return types.find('s') != Glib::ustring::npos; + } + return false; + } + const Glib::ustring types; +}; +class FsRowSpecMaxDepth : public FsRows::SpecBase { + public: + FsRowSpecMaxDepth(const Glib::ustring & v) : maxDepth(boost::lexical_cast(v)) { } + bool recurse(const FsRows::SearchState * fs) const { + return (depth(fs) < maxDepth); + } + const unsigned int maxDepth; +}; + +FsRows::FsRows(const xmlpp::Element * p) : + RowSet(p) +{ +} + +FsRows::~FsRows() +{ +} + +void +FsRows::loadComplete(const CommonObjects *) +{ +} + +FsRows::Path +normalisePath(const std::string & p) +{ + // Ensure there is a trailing / + if (*p.rend() != '/') { + return p + "/"; + } + return p; +} + +void +FsRows::execute(const Glib::ustring &, const RowProcessor * rp) const +{ + SearchState ss(normalisePath(rp->getParameter("root"))); + SpecSpec s; + typedef SpecSpec & (*splitter)(SpecSpec &, const Glib::ustring &, bool (*)(gunichar), boost::algorithm::token_compress_mode_type); + splitter split = &boost::algorithm::split; + split(s, rp->getParameter("spec"), Glib::Unicode::isspace, boost::algorithm::token_compress_on); + for (SpecSpec::const_iterator sf = s.begin(); sf != s.end(); ) { + const Glib::ustring & name = (*sf++); + if (name == "-name") { + ss.specs.insert(new FsRowSpecName(*sf++)); + } + else if (name == "-type") { + ss.specs.insert(new FsRowSpecType(*sf++)); + } + else if (name == "-maxdepth") { + ss.specs.insert(new FsRowSpecMaxDepth(*sf++)); + } + else { + throw NotSupported(name); + } + } + execute(ss, ss.fsRoot, rp); +} + +void +FsRows::execute(SearchState & ss, const Path & dir, const RowProcessor * rp) const +{ + ss.depth += 1; + try { + DirEnt end; + for (DirEnt itr(dir); itr != end; ++itr) { + ss.curPathStr = itr->path().string(); + ss.curPath = itr->path(); + stat(ss.curPathStr.c_str(), &ss.curStat); + + if (boost::algorithm::all(ss.specs, boost::bind(&SpecBase::matches, _1, &ss))) { + ss.process(rp); + } + + if (S_ISDIR(ss.curStat.st_mode) && boost::algorithm::all(ss.specs, boost::bind(&SpecBase::recurse, _1, &ss))) { + execute(ss, *itr, rp); + } + } + } + catch (const boost::filesystem::filesystem_error & e) { + Logger()->messagef(LOG_WARNING, "%s when processing '%s'", e.what(), dir.string().c_str()); + } + ss.depth -= 1; +} + +FsRows::SearchState::SearchState(const Path & dir) : + fsRoot(dir) +{ +} + +const Columns & +FsRows::SearchState::getColumns() const +{ + return col; +} + +RowState::RowAttribute +FsRows::SearchState::resolveAttr(const Glib::ustring & a) const +{ + if (a == field_relPath) { + return boost::bind(&FsRows::SearchState::fileRelPath, this); + } + if (a == field_size) { + return boost::bind(&FsRows::SearchState::fileSize, this); + } + if (a == field_modDate) { + return boost::bind(&FsRows::SearchState::fileModDate, this); + } + if (a == field_user) { + return boost::bind(&FsRows::SearchState::fileUser, this); + } + if (a == field_group) { + return boost::bind(&FsRows::SearchState::fileGroup, this); + } + if (a == field_mode) { + return boost::bind(&FsRows::SearchState::fileMode, this); + } + if (a == field_perms) { + return boost::bind(&FsRows::SearchState::filePerms, this); + } + if (a == field_type) { + return boost::bind(&FsRows::SearchState::fileType, this); + } + return RowState::resolveAttr(a); +} + +void +FsRows::SearchState::foreachAttr(const AttrAction & action) const +{ + action(field_relPath, fileRelPath()); + action(field_size, fileSize()); + action(field_modDate, fileModDate()); + action(field_user, fileUser()); + action(field_group, fileGroup()); + action(field_mode, fileMode()); + action(field_perms, filePerms()); + action(field_type, fileType()); + RowState::foreachAttr(action); +} + +VariableType +FsRows::SearchState::fileRelPath() const +{ + return curPathStr.substr(fsRoot.string().length() - 1); +} + +VariableType +FsRows::SearchState::fileSize() const +{ + return curStat.st_size; +} + +VariableType +FsRows::SearchState::fileModDate() const +{ + return boost::posix_time::from_time_t(curStat.st_mtime); +} + +VariableType +FsRows::SearchState::fileUser() const +{ + struct passwd * p = getpwuid(curStat.st_uid); + if (p) { + return p->pw_name; + } + else { + return curStat.st_uid; + } +} + +VariableType +FsRows::SearchState::fileGroup() const +{ + struct group * g = getgrgid(curStat.st_gid); + if (g) { + return g->gr_name; + } + else { + return curStat.st_gid; + } +} + +VariableType +FsRows::SearchState::fileMode() const +{ + throw NotSupported(__PRETTY_FUNCTION__); +} + +VariableType +FsRows::SearchState::filePerms() const +{ + throw NotSupported(__PRETTY_FUNCTION__); +} + +VariableType +FsRows::SearchState::fileType() const +{ + throw NotSupported(__PRETTY_FUNCTION__); +} + diff --git a/project2/files/fsRows.h b/project2/files/fsRows.h new file mode 100644 index 0000000..3356b37 --- /dev/null +++ b/project2/files/fsRows.h @@ -0,0 +1,69 @@ +#ifndef FSROWS_H +#define FSROWS_H + +#include +#include +#include +#include +#include "variables.h" +#include "rowSet.h" + +class CommonObjects; + +/// Project2 component to create a row set based on files and directories on the local filesystem +class FsRows : public RowSet { + public: + class SearchState; + class SpecBase : public virtual IntrusivePtrBase { + public: + virtual bool recurse(const SearchState * fs) const; + virtual bool matches(const SearchState * fs) const; + protected: + const boost::filesystem::path & curPath(const SearchState * fs) const; + unsigned int depth(const SearchState * fs) const; + const struct stat & curStat(const SearchState * fs) const; + }; + typedef boost::intrusive_ptr SpecBasePtr; + typedef std::set SpecBases; + typedef std::list SpecSpec; + typedef boost::filesystem::path Path; + + FsRows(const xmlpp::Element * p); + ~FsRows(); + + void execute(const Glib::ustring &, const RowProcessor *) const; + virtual void loadComplete(const CommonObjects *); + class SearchState : public RowState { + public: + SearchState(const boost::filesystem::path & r); + + virtual RowAttribute resolveAttr(const Glib::ustring & attrName) const; + virtual void foreachAttr(const AttrAction & action) const; + virtual const Columns & getColumns() const; + + VariableType fileRelPath() const; + VariableType fileSize() const; + VariableType fileModDate() const; + VariableType fileUser() const; + VariableType fileGroup() const; + VariableType fileMode() const; + VariableType filePerms() const; + VariableType fileType() const; + + static const Columns col; + SpecBases specs; + const boost::filesystem::path fsRoot; + boost::filesystem::path curPath; + Glib::ustring curPathStr; + unsigned int depth; + struct stat curStat; + }; + protected: + void execute(SearchState &, const Path & dir, const RowProcessor *) const; + friend class SpecBase; +}; + +#endif + + + diff --git a/project2/files/streamRows.cpp b/project2/files/streamRows.cpp new file mode 100644 index 0000000..0be76cd --- /dev/null +++ b/project2/files/streamRows.cpp @@ -0,0 +1,106 @@ +#include "streamRows.h" +#include "rowProcessor.h" + +StreamRows::StreamRows(const xmlpp::Element * p) : + DefinedColumns(p, "columns/column", boost::bind(&Column::make, _1, _2)), + RowSet(p), + fieldSep(p->get_attribute_value("fieldSep")[0]), + quoteChar(p->get_attribute_value("quoteChar")[0]), + keepBlankRows(p->get_attribute_value("keepBlankRows") == "true"), + countBlankRows(p->get_attribute_value("keepBlankRows") == "count"), + newline(p->get_attribute_value("newline")), + newlin(newline, 0, newline.length() - 1), + encoding(p->get_attribute_value("encoding")), + skipheader(atoi(p->get_attribute_value("skipheader").c_str())) +{ +} + +StreamRows::~StreamRows() +{ +} + +void +StreamRows::pushChar(gunichar c, ParseState & ps) const +{ + if ((!ps.inQuotes) && (c == *newline.rbegin()) && (ps.tok.compare(ps.tok.length() - newlin.length(), newlin.length(), newlin) == 0)) { + if (skipheader) { + ps.skipheader -= 1; + } + else { + ps.tok.erase(ps.tok.length() - newlin.length()); + if (!ps.tok.empty()) { + *ps.curCol++ = VariableType(ps.tok); + } + if (keepBlankRows || ps.curCol != ps.fields.begin()) { + while (ps.curCol != ps.fields.end()) { + *ps.curCol++ = Null(); + } + ps.process(ps.rp); + } + else if (countBlankRows) { + ps.blankRow(); + } + ps.curCol = ps.fields.begin(); + } + ps.tok.clear(); + } + else if (c == quoteChar) { + if (ps.prevWasQuote) { + ps.tok += c; + ps.prevWasQuote = false; + ps.inQuotes = !ps.inQuotes; + } + else { + ps.prevWasQuote = ps.inQuotes; + ps.inQuotes = !ps.inQuotes; + } + } + else if ((!ps.inQuotes) && (c == fieldSep)) { + ps.prevWasQuote = false; + if (skipheader == 0) { + *ps.curCol++ = VariableType(ps.tok); + } + ps.tok.clear(); + } + else { + ps.prevWasQuote = false; + ps.tok += c; + } +} + +StreamRows::ParseState::ParseState(const StreamRows * rows, const RowProcessor * proc) : + ColumnValues(rows), + sr(rows), + rp(proc), + inQuotes(false), + prevWasQuote(false), + curCol(fields.begin()) +{ +} + +StreamRows::ParseState::~ParseState() +{ + if (!std::uncaught_exception()) { + sr->end(*this); + } +} + +void +StreamRows::end(ParseState & ps) const +{ + if (!ps.tok.empty()) { + if (skipheader == 0) { + *ps.curCol++ = VariableType(ps.tok); + } + } + if (keepBlankRows || ps.curCol != ps.fields.begin()) { + while (ps.curCol != ps.fields.end()) { + *ps.curCol++ = Null(); + } + ps.process(ps.rp); + } + else if (countBlankRows) { + ps.blankRow(); + } +} + diff --git a/project2/files/streamRows.h b/project2/files/streamRows.h new file mode 100644 index 0000000..2d10116 --- /dev/null +++ b/project2/files/streamRows.h @@ -0,0 +1,46 @@ +#ifndef STREAMROWS_H +#define STREAMROWS_H + +#include "variables.h" +#include "definedColumns.h" + +class RowProcessor; + +/// Base class for Project2 components that create a row set based on the contents of a byte stream +class StreamRows : public DefinedColumns, public RowSet { + public: + StreamRows(const xmlpp::Element * p); + ~StreamRows(); + + protected: + class ParseState : public ColumnValues { + public: + ParseState(const StreamRows *, const RowProcessor *); + ~ParseState(); + + const StreamRows * sr; + const RowProcessor * rp; + size_t skipheader; + bool inQuotes; + bool prevWasQuote; + Glib::ustring tok; + FieldValues::iterator curCol; + + friend class StreamRows; + }; + void pushChar(gunichar ch, ParseState &) const; + void end(ParseState &) const; + + public: + const gunichar fieldSep; + const gunichar quoteChar; + const bool keepBlankRows; + const bool countBlankRows; + const Glib::ustring newline; + const Glib::ustring newlin; + const std::string encoding; + const size_t skipheader; +}; + +#endif + diff --git a/project2/fsRows.cpp b/project2/fsRows.cpp deleted file mode 100644 index cb73b04..0000000 --- a/project2/fsRows.cpp +++ /dev/null @@ -1,320 +0,0 @@ -#include "fsRows.h" -#include "logger.h" -#include "xmlObjectLoader.h" -#include "rowProcessor.h" -#include "exceptions.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -typedef boost::filesystem::directory_iterator DirEnt; - -DECLARE_LOADER("fsrows", FsRows); - -const Glib::ustring field_absPath("absPath"); -const Glib::ustring field_relPath("relPath"); -const Glib::ustring field_size("size"); -const Glib::ustring field_modDate("modifiedDate"); -const Glib::ustring field_user("owningUser"); -const Glib::ustring field_group("owningGroup"); -const Glib::ustring field_mode("mode"); -const Glib::ustring field_perms("perms"); -const Glib::ustring field_type("type"); -static -Columns defCols() { - Columns rtn; - rtn.insert(new Column(0, "absPath")); - return rtn; -} -const Columns FsRows::SearchState::col(defCols()); - -bool FsRows::SpecBase::recurse(const SearchState *) const { return true; } -bool FsRows::SpecBase::matches(const SearchState *) const { return true; } -const boost::filesystem::path & FsRows::SpecBase::curPath(const SearchState * fs) const { return fs->curPath; } -unsigned int FsRows::SpecBase::depth(const SearchState * fs) const { return fs->depth; } -const struct stat & FsRows::SpecBase::curStat(const SearchState * fs) const { return fs->curStat; } - -class FsRowSpecName : public FsRows::SpecBase { - public: - FsRowSpecName(const Glib::ustring & v) : pattern(v) { } - bool matches(const FsRows::SearchState * fs) const { - // Based on code written by Jack Handy - jakkhandy@hotmail.com - // from http://www.codeproject.com/KB/string/wildcmp.aspx - Glib::ustring::const_iterator wild = pattern.begin(); -#if BOOST_VERSION >= 104500 - Glib::ustring leaf(curPath(fs).leaf().string()); -#else - Glib::ustring leaf(curPath(fs).leaf()); -#endif - Glib::ustring::const_iterator string = leaf.begin(); - - while ((string != leaf.end()) && (*wild != '*')) { - if ((*wild != *string) && (*wild != '?')) { - return false; - } - wild++; - string++; - } - - Glib::ustring::const_iterator cp, mp; - while (string != leaf.end()) { - if (*wild == '*') { - if (!*++wild) { - return true; - } - mp = wild; - cp = string; - cp++; - } else if ((*wild == *string) || (*wild == '?')) { - wild++; - string++; - } else { - wild = mp; - string = cp++; - } - } - - while (*wild == '*') { - wild++; - } - return wild == pattern.end(); - } - const Glib::ustring pattern; -}; -class FsRowSpecType : public FsRows::SpecBase { - public: - FsRowSpecType(const Glib::ustring & v) : types(v) { } - bool matches(const FsRows::SearchState * fs) const { - if (S_ISREG(curStat(fs).st_mode)) { - return types.find('f') != Glib::ustring::npos; - } - if (S_ISDIR(curStat(fs).st_mode)) { - return types.find('d') != Glib::ustring::npos; - } - if (S_ISCHR(curStat(fs).st_mode)) { - return types.find('c') != Glib::ustring::npos; - } - if (S_ISBLK(curStat(fs).st_mode)) { - return types.find('b') != Glib::ustring::npos; - } - if (S_ISFIFO(curStat(fs).st_mode)) { - return types.find('p') != Glib::ustring::npos; - } - if (S_ISLNK(curStat(fs).st_mode)) { - return types.find('l') != Glib::ustring::npos; - } - if (S_ISSOCK(curStat(fs).st_mode)) { - return types.find('s') != Glib::ustring::npos; - } - return false; - } - const Glib::ustring types; -}; -class FsRowSpecMaxDepth : public FsRows::SpecBase { - public: - FsRowSpecMaxDepth(const Glib::ustring & v) : maxDepth(boost::lexical_cast(v)) { } - bool recurse(const FsRows::SearchState * fs) const { - return (depth(fs) < maxDepth); - } - const unsigned int maxDepth; -}; - -FsRows::FsRows(const xmlpp::Element * p) : - RowSet(p) -{ -} - -FsRows::~FsRows() -{ -} - -void -FsRows::loadComplete(const CommonObjects *) -{ -} - -FsRows::Path -normalisePath(const std::string & p) -{ - // Ensure there is a trailing / - if (*p.rend() != '/') { - return p + "/"; - } - return p; -} - -void -FsRows::execute(const Glib::ustring &, const RowProcessor * rp) const -{ - SearchState ss(normalisePath(rp->getParameter("root"))); - SpecSpec s; - typedef SpecSpec & (*splitter)(SpecSpec &, const Glib::ustring &, bool (*)(gunichar), boost::algorithm::token_compress_mode_type); - splitter split = &boost::algorithm::split; - split(s, rp->getParameter("spec"), Glib::Unicode::isspace, boost::algorithm::token_compress_on); - for (SpecSpec::const_iterator sf = s.begin(); sf != s.end(); ) { - const Glib::ustring & name = (*sf++); - if (name == "-name") { - ss.specs.insert(new FsRowSpecName(*sf++)); - } - else if (name == "-type") { - ss.specs.insert(new FsRowSpecType(*sf++)); - } - else if (name == "-maxdepth") { - ss.specs.insert(new FsRowSpecMaxDepth(*sf++)); - } - else { - throw NotSupported(name); - } - } - execute(ss, ss.fsRoot, rp); -} - -void -FsRows::execute(SearchState & ss, const Path & dir, const RowProcessor * rp) const -{ - ss.depth += 1; - try { - DirEnt end; - for (DirEnt itr(dir); itr != end; ++itr) { - ss.curPathStr = itr->path().string(); - ss.curPath = itr->path(); - stat(ss.curPathStr.c_str(), &ss.curStat); - - if (boost::algorithm::all(ss.specs, boost::bind(&SpecBase::matches, _1, &ss))) { - ss.process(rp); - } - - if (S_ISDIR(ss.curStat.st_mode) && boost::algorithm::all(ss.specs, boost::bind(&SpecBase::recurse, _1, &ss))) { - execute(ss, *itr, rp); - } - } - } - catch (const boost::filesystem::filesystem_error & e) { - Logger()->messagef(LOG_WARNING, "%s when processing '%s'", e.what(), dir.string().c_str()); - } - ss.depth -= 1; -} - -FsRows::SearchState::SearchState(const Path & dir) : - fsRoot(dir) -{ -} - -const Columns & -FsRows::SearchState::getColumns() const -{ - return col; -} - -RowState::RowAttribute -FsRows::SearchState::resolveAttr(const Glib::ustring & a) const -{ - if (a == field_relPath) { - return boost::bind(&FsRows::SearchState::fileRelPath, this); - } - if (a == field_size) { - return boost::bind(&FsRows::SearchState::fileSize, this); - } - if (a == field_modDate) { - return boost::bind(&FsRows::SearchState::fileModDate, this); - } - if (a == field_user) { - return boost::bind(&FsRows::SearchState::fileUser, this); - } - if (a == field_group) { - return boost::bind(&FsRows::SearchState::fileGroup, this); - } - if (a == field_mode) { - return boost::bind(&FsRows::SearchState::fileMode, this); - } - if (a == field_perms) { - return boost::bind(&FsRows::SearchState::filePerms, this); - } - if (a == field_type) { - return boost::bind(&FsRows::SearchState::fileType, this); - } - return RowState::resolveAttr(a); -} - -void -FsRows::SearchState::foreachAttr(const AttrAction & action) const -{ - action(field_relPath, fileRelPath()); - action(field_size, fileSize()); - action(field_modDate, fileModDate()); - action(field_user, fileUser()); - action(field_group, fileGroup()); - action(field_mode, fileMode()); - action(field_perms, filePerms()); - action(field_type, fileType()); - RowState::foreachAttr(action); -} - -VariableType -FsRows::SearchState::fileRelPath() const -{ - return curPathStr.substr(fsRoot.string().length() - 1); -} - -VariableType -FsRows::SearchState::fileSize() const -{ - return curStat.st_size; -} - -VariableType -FsRows::SearchState::fileModDate() const -{ - return boost::posix_time::from_time_t(curStat.st_mtime); -} - -VariableType -FsRows::SearchState::fileUser() const -{ - struct passwd * p = getpwuid(curStat.st_uid); - if (p) { - return p->pw_name; - } - else { - return curStat.st_uid; - } -} - -VariableType -FsRows::SearchState::fileGroup() const -{ - struct group * g = getgrgid(curStat.st_gid); - if (g) { - return g->gr_name; - } - else { - return curStat.st_gid; - } -} - -VariableType -FsRows::SearchState::fileMode() const -{ - throw NotSupported(__PRETTY_FUNCTION__); -} - -VariableType -FsRows::SearchState::filePerms() const -{ - throw NotSupported(__PRETTY_FUNCTION__); -} - -VariableType -FsRows::SearchState::fileType() const -{ - throw NotSupported(__PRETTY_FUNCTION__); -} - diff --git a/project2/fsRows.h b/project2/fsRows.h deleted file mode 100644 index 3356b37..0000000 --- a/project2/fsRows.h +++ /dev/null @@ -1,69 +0,0 @@ -#ifndef FSROWS_H -#define FSROWS_H - -#include -#include -#include -#include -#include "variables.h" -#include "rowSet.h" - -class CommonObjects; - -/// Project2 component to create a row set based on files and directories on the local filesystem -class FsRows : public RowSet { - public: - class SearchState; - class SpecBase : public virtual IntrusivePtrBase { - public: - virtual bool recurse(const SearchState * fs) const; - virtual bool matches(const SearchState * fs) const; - protected: - const boost::filesystem::path & curPath(const SearchState * fs) const; - unsigned int depth(const SearchState * fs) const; - const struct stat & curStat(const SearchState * fs) const; - }; - typedef boost::intrusive_ptr SpecBasePtr; - typedef std::set SpecBases; - typedef std::list SpecSpec; - typedef boost::filesystem::path Path; - - FsRows(const xmlpp::Element * p); - ~FsRows(); - - void execute(const Glib::ustring &, const RowProcessor *) const; - virtual void loadComplete(const CommonObjects *); - class SearchState : public RowState { - public: - SearchState(const boost::filesystem::path & r); - - virtual RowAttribute resolveAttr(const Glib::ustring & attrName) const; - virtual void foreachAttr(const AttrAction & action) const; - virtual const Columns & getColumns() const; - - VariableType fileRelPath() const; - VariableType fileSize() const; - VariableType fileModDate() const; - VariableType fileUser() const; - VariableType fileGroup() const; - VariableType fileMode() const; - VariableType filePerms() const; - VariableType fileType() const; - - static const Columns col; - SpecBases specs; - const boost::filesystem::path fsRoot; - boost::filesystem::path curPath; - Glib::ustring curPathStr; - unsigned int depth; - struct stat curStat; - }; - protected: - void execute(SearchState &, const Path & dir, const RowProcessor *) const; - friend class SpecBase; -}; - -#endif - - - diff --git a/project2/iHaveParameters.cpp b/project2/iHaveParameters.cpp deleted file mode 100644 index e4f456a..0000000 --- a/project2/iHaveParameters.cpp +++ /dev/null @@ -1,61 +0,0 @@ -#include "iHaveParameters.h" -#include "exceptions.h" -#include "appEngine.h" -#include - -IHaveParameters::Stack IHaveParameters::scope; - -IHaveParameters::IHaveParameters(const xmlpp::Element * p) -{ - BOOST_FOREACH(xmlpp::Node * node, p->find("parameters/*")) { - if (const xmlpp::Element * pelem = dynamic_cast(node)) { - parameters.insert(Parameters::value_type(pelem->get_name(), Variable(pelem, boost::optional()))); - } - } -} - -IHaveParameters::~IHaveParameters() -{ -} - -VariableType -IHaveParameters::getParameter(const Glib::ustring & name) const -{ - Parameters::const_iterator i = parameters.find(name); - if (i != parameters.end()) { - return i->second; - } - throw ParamNotFound(name); -} - -void -IHaveParameters::push(const IHaveParameters * p) -{ - scope.push_back(p); -} - -void -IHaveParameters::pop(const IHaveParameters * p) -{ - assert(scope.back() == p); - scope.pop_back(); -} - -VariableType -IHaveParameters::getScopedParameter(const Glib::ustring & name) -{ - for(Stack::const_reverse_iterator ihp = scope.rbegin(); ihp != scope.rend(); ihp++) { - Parameters::const_iterator i = (*ihp)->parameters.find(name); - if (i != (*ihp)->parameters.end()) { - return i->second; - } - } - throw ParamNotFound(name); -} - -const IHaveParameters::Parameters & -IHaveParameters::allParameters() const -{ - return parameters; -} - diff --git a/project2/iHaveParameters.h b/project2/iHaveParameters.h deleted file mode 100644 index 28dbf7d..0000000 --- a/project2/iHaveParameters.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef IHAVEPARAMETERS -#define IHAVEPARAMETERS - -#include -#include -#include -#include "variables.h" -#include "intrusivePtrBase.h" - -/// Mix-in base class to store parameters for component execution -class IHaveParameters { - public: - typedef std::map Parameters; - - IHaveParameters(const xmlpp::Element * p); - virtual ~IHaveParameters() = 0; - - const Parameters & allParameters() const; - VariableType getParameter(const Glib::ustring &) const; - static VariableType getScopedParameter(const Glib::ustring &); - - protected: - Parameters parameters; - - static void push(const IHaveParameters *); - static void pop(const IHaveParameters *); - private: - typedef std::vector Stack; - static Stack scope; -}; - -#endif - diff --git a/project2/iHaveSubTasks.cpp b/project2/iHaveSubTasks.cpp deleted file mode 100644 index f78f81e..0000000 --- a/project2/iHaveSubTasks.cpp +++ /dev/null @@ -1,26 +0,0 @@ -#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 deleted file mode 100644 index ee6d173..0000000 --- a/project2/iHaveSubTasks.h +++ /dev/null @@ -1,25 +0,0 @@ -#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 deleted file mode 100644 index cf5c156..0000000 --- a/project2/if.cpp +++ /dev/null @@ -1,85 +0,0 @@ -#include "if.h" -#include "logger.h" -#include "xmlObjectLoader.h" -#include -#include -#include - -DECLARE_LOADER("if", If); - -SimpleMessageException(IfModeIsNonsense); - -IfSet::IfSet(const xmlpp::Element * e) : - mode(e->get_attribute_value("mode") == "or" ? Or : And) -{ - LoaderBase loader(true); - loader.supportedStorers.insert(Storer::into(&checks)); - loader.collectAll(e, true, IgnoreUnsupported); -} - -template -bool all(const Range & c, const Pred & p) -{ - return (std::find_if(c.begin(), c.end(), !p) == c.end()); -} -template -bool any(const Range & c, const Pred & p) -{ - return (std::find_if(c.begin(), c.end(), p) != c.end()); -} - -bool -IfSet::passes() const -{ - if (mode == And) { - return all(checks, boost::bind(&ParamChecker::performCheck, _1)); - } - else if (mode == Or) { - return any(checks, boost::bind(&ParamChecker::performCheck, _1)); - } - throw IfModeIsNonsense(getName()); -} - -If::If(const xmlpp::Element * e) : - SourceObject(e), - IHaveSubTasks(e), - View(e), - IfSet(e) -{ - LoaderBase loader(true); - loader.supportedStorers.insert(Storer::into(&normal)); - loader.supportedStorers.insert(Storer::into(&subViews)); - loader.collectAll(e, true, IgnoreUnsupported); -} - -void -If::loadComplete(const CommonObjects*) -{ -} - -void -If::execute(const Presenter * presenter) const -{ - if (passes()) { - Logger()->messagef(LOG_DEBUG, "IfSet passed, showing %zu views", subViews.size()); - BOOST_FOREACH(const SubViews::value_type & sq, subViews) { - sq->execute(presenter); - } - } -} - -void -If::execute() const -{ - if (passes()) { - Logger()->message(LOG_DEBUG, "IfSet passed"); - run(normal); - } -} - -const std::string & -If::getName() const -{ - return name; -} - diff --git a/project2/if.h b/project2/if.h deleted file mode 100644 index b33bca1..0000000 --- a/project2/if.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef IF_H -#define IF_H - -#include "iHaveSubTasks.h" -#include "view.h" -#include "paramChecker.h" - -class IfSet : public virtual IntrusivePtrBase { - public: - IfSet(const xmlpp::Element *); - bool passes() const; - - private: - virtual const std::string & getName() const = 0; - enum Mode { And, Or }; - Mode mode; - typedef ANONORDEREDSTORAGEOF(ParamChecker) ParamCheckers; - ParamCheckers checks; -}; - -/// Project2 component to conditionally execute its children -class If : public IHaveSubTasks, public View, public IfSet { - public: - If(const xmlpp::Element *); - - virtual void loadComplete(const CommonObjects*); - virtual void execute(const Presenter*) const; - virtual void execute() const; - - private: - typedef ANONSTORAGEOF(View) SubViews; - SubViews subViews; - - const std::string & getName() const; -}; - -#endif - diff --git a/project2/iterate.cpp b/project2/iterate.cpp deleted file mode 100644 index 119e839..0000000 --- a/project2/iterate.cpp +++ /dev/null @@ -1,49 +0,0 @@ -#include "iterate.h" -#include "logger.h" -#include -#include -#include "xmlObjectLoader.h" -#include "scopeObject.h" - -DECLARE_LOADER("iterate", Iterate); - -Iterate::Iterate(const xmlpp::Element * p) : - SourceObject(p), - IHaveSubTasks(p), - RowProcessor(p) -{ - LoaderBase loader(true); - loader.supportedStorers.insert(Storer::into(&normal)); - loader.collectAll(p, true, IgnoreUnsupported); -} - -Iterate::~Iterate() -{ -} - -void -Iterate::loadComplete(const CommonObjects * co) -{ - RowProcessor::loadComplete(co); -} - -void -Iterate::rowReady(const RowState *) const -{ - executeChildren(); -} - -void -Iterate::execute() const -{ - RowProcessor::execute(); -} - -void -Iterate::executeChildren() const -{ - BOOST_FOREACH(const Tasks::value_type & sq, normal) { - sq->execute(); - } -} - diff --git a/project2/iterate.h b/project2/iterate.h deleted file mode 100644 index 50fd879..0000000 --- a/project2/iterate.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef ITERATE_H -#define ITERATE_H - -#include -#include "rowProcessor.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 IHaveSubTasks, public RowProcessor { - public: - Iterate(const xmlpp::Element * p); - virtual ~Iterate(); - - void loadComplete(const CommonObjects *); - void rowReady(const RowState *) const; - void execute() const; - - protected: - void executeChildren() const; -}; - -#endif - - diff --git a/project2/library.cpp b/project2/library.cpp deleted file mode 100644 index b1e0b9b..0000000 --- a/project2/library.cpp +++ /dev/null @@ -1,41 +0,0 @@ -#include -#include "xmlStorage.h" -#include "exceptions.h" -#include "library.h" - -SimpleMessageException(LoadLibraryFailed); -SimpleMessageException(UnloadLibraryFailed); - -Library::Library(const xmlpp::Element * p) : - SourceObject(p), - handle(dlopen(p->get_attribute_value("path").c_str(), RTLD_NOW)) -{ - if (!handle) { - throw LoadLibraryFailed(dlerror()); - } -} - -Library::~Library() -{ - if (dlclose(handle)) { - throw UnloadLibraryFailed(dlerror()); - } -} - -void -Library::loadComplete(const CommonObjects*) -{ -} - -STORAGEOF(Library) libraries; -class LibraryLoader : public ElementLoaderImpl { - public: - void onIteration() - { - libraries.clear(); - } -}; - -DECLARE_CUSTOM_LOADER("library", LibraryLoader); - - diff --git a/project2/library.h b/project2/library.h deleted file mode 100644 index af8e73f..0000000 --- a/project2/library.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef LIBRARY_LOADER_H -#define LIBRARY_LOADER_H - -#include "xmlObjectLoader.h" - -class Library : public SourceObject { - public: - Library(const xmlpp::Element * p); - ~Library(); - void loadComplete(const CommonObjects*); - private: - void * handle; -}; -extern STORAGEOF(Library) libraries; - -#endif - diff --git a/project2/logger.cpp b/project2/logger.cpp deleted file mode 100644 index 6133ce9..0000000 --- a/project2/logger.cpp +++ /dev/null @@ -1,182 +0,0 @@ -#define SYSLOG_NAMES 1 // Enables the definition of names in syslog.h - -#include "logger.h" -#include "loggers.h" -#include -#include -#include - -const char * const version = "$Id: logger.cpp 8818 2011-01-10 10:09:59Z danielg $"; - -Log Logger::log; - -Log::Log() : - lowestLevel(-1) -{ -} - -Log::~Log() -{ - logs.clear(); -} - -int -Log::addLogger(LogDriverBasePtr log) -{ - logs[++nextId] = log; - if (log->level > lowestLevel) { - lowestLevel = log->level; - } - return nextId; -} - -void -Log::clear() -{ - logs.clear(); -} - -const char * -Log::priorityName(int priority) -{ - const char * name = NULL; - for (CODE * c = prioritynames; c->c_name; c++) { - if (c->c_val == priority) { - name = c->c_name; - } - } - return name; -} - - -void -Log::message(int priority, const char * msg) const -{ - if (priority > lowestLevel) return; - BOOST_FOREACH(const LogDrivers::value_type & l, logs) { - l.second->message(priority, msg); - } -} - -void -Log::messagef(int priority, const char * msgfmt, ...) const -{ - if (priority > lowestLevel) return; - va_list v; - va_start(v, msgfmt); - vmessagef(priority, msgfmt, v); - va_end(v); -} - -void -Log::vmessagef(int priority, const char * msgfmt, va_list va) const -{ - if (priority > lowestLevel) return; - char * msg; - int len = vasprintf(&msg, msgfmt, va); - if (len > 0) { - message(priority, msg); - } - free(msg); -} - -Log * -Logger::operator->() const -{ - return &log; -} - -LogDriverBase::LogDriverBase(int l) : - level(l) -{ -} - -LogDriverBase::~LogDriverBase() -{ -} - -// File based log driver -//---------------------- -FileBasedLogDriver::FileBasedLogDriver(FILE * f, int l, bool ts) : - LogDriverBase(l), - file(f), - timestamp(ts) -{ -} -FileBasedLogDriver::~FileBasedLogDriver() -{ -} -void -FileBasedLogDriver::message(int priority, const char * msg) const -{ - if (priority <= level) { - writeTimestamp(); - writeLevel(priority); - fprintf(file, "%s\n", msg); - fflush(file); - } -} -const char * -FileBasedLogDriver::timeStr() const -{ - struct tm tm; - time_t t = time(NULL); - localtime_r(&t, &tm); - strftime(tmbuf, sizeof(tmbuf), "%F %T", &tm); - return tmbuf; -} -void -FileBasedLogDriver::writeTimestamp() const -{ - if (timestamp) { - fprintf(file, "%s ", timeStr()); - } -} -void -FileBasedLogDriver::writeLevel(int level) const -{ - if (timestamp) { - fprintf(file, "%-6.*s", 5, boost::algorithm::to_upper_copy(std::string(Log::priorityName(level))).c_str()); - } -} - -// Consol driver -//------------------- -ConsoleLogDriver::ConsoleLogDriver(FILE * f, int l, bool ts) : - FileBasedLogDriver(f, l, ts) -{ -} -ConsoleLogDriver::~ConsoleLogDriver() -{ -} - -// File log driver -//------------------- -FileLogDriver::FileLogDriver(const char * path, int l) : - FileBasedLogDriver(fopen(path, "a"), l, true) -{ -} -FileLogDriver::~FileLogDriver() -{ - fclose(file); -} - -// Syslog Log Driver -//------------------- -SyslogLogDriver::SyslogLogDriver(const char * ident, int level, int option, int facility) : - LogDriverBase(level) -{ - openlog(ident, option, facility); -} -SyslogLogDriver::~SyslogLogDriver() -{ - closelog(); -} -void -SyslogLogDriver::message(int priority, const char * msg) const -{ - if (priority <= level) { - syslog(priority, "%s", msg); - } -} - diff --git a/project2/logger.h b/project2/logger.h deleted file mode 100644 index 5d42631..0000000 --- a/project2/logger.h +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef LOGGER_H -#define LOGGER_H - -#include -#include -#include // Pulled in for easy client lookups of LOG_* priorties -#include -#include "intrusivePtrBase.h" - -class LogDriverBase; - -class Log { - public: - typedef boost::intrusive_ptr LogDriverBasePtr; - typedef std::map LogDrivers; - - Log(); - ~Log(); - - int addLogger(LogDriverBasePtr); - void clear(); - - void message(int priority, const char * msg) const; - void messagef(int priority, const char * msgfmt, ...) const __attribute__ ((format (printf, 3, 4))); - void vmessagef(int priority, const char * msgfmt, va_list) const; - - static const char * priorityName(int priority); // Look up the priority as defined in syslog.h - - private: - LogDrivers logs; - int lowestLevel; - int nextId; -}; - -class Logger { - public: - Log * operator->() const; - private: - static Log log; -}; - -#endif - diff --git a/project2/loggers.h b/project2/loggers.h deleted file mode 100644 index 69b352c..0000000 --- a/project2/loggers.h +++ /dev/null @@ -1,60 +0,0 @@ -#ifndef LOGGERS_H -#define LOGGERS_H - -#include "logger.h" - -/// Base class for classes providing a logging facility -class LogDriverBase : public virtual IntrusivePtrBase { - public: - LogDriverBase(int level); - virtual ~LogDriverBase(); - - virtual void message(int priority, const char * msg) const = 0; - const int level; -}; - -/// Base class for loggers that write to some sort of file handle -class FileBasedLogDriver : public LogDriverBase { - public: - FileBasedLogDriver(FILE *, int level, bool timestamp); - virtual ~FileBasedLogDriver() = 0; - - virtual void message(int priority, const char * msg) const; - - protected: - void writeTimestamp() const; - void writeLevel(int level) const; - FILE * file; - bool timestamp; - - private: - const char * timeStr() const; - mutable char tmbuf[30]; -}; - -/// Logger that writes to the console -class ConsoleLogDriver : public FileBasedLogDriver { - public: - ConsoleLogDriver(FILE *, int level, bool timestamp); - ~ConsoleLogDriver(); - -}; - -/// Logger that writes to a file -class FileLogDriver : public FileBasedLogDriver { - public: - FileLogDriver(const char * path, int level); - ~FileLogDriver(); -}; - -/// Logger that writes to syslog -class SyslogLogDriver : public LogDriverBase { - public: - SyslogLogDriver(const char * ident, int level, int option = 0, int facility = LOG_USER); - virtual ~SyslogLogDriver(); - - virtual void message(int priority, const char * msg) const; -}; - -#endif - diff --git a/project2/mail/Jamfile.jam b/project2/mail/Jamfile.jam new file mode 100644 index 0000000..8c8f189 --- /dev/null +++ b/project2/mail/Jamfile.jam @@ -0,0 +1,15 @@ +alias libxmlpp : : : : + "`pkg-config --cflags libxml++-2.6`" + "`pkg-config --libs libxml++-2.6`" ; +lib esmtp : : esmtp ; + +lib p2mail : + sendmailTask.cpp + : + ../../libmisc + libxmlpp + esmtp + ../common//p2common + ../xml//p2xml + ; + diff --git a/project2/mail/sendmailTask.cpp b/project2/mail/sendmailTask.cpp new file mode 100644 index 0000000..73afb20 --- /dev/null +++ b/project2/mail/sendmailTask.cpp @@ -0,0 +1,252 @@ +#include "sendmailTask.h" +#include "logger.h" +#include +#include +#include "xmlObjectLoader.h" +#include "viewHost.h" +#include "environment.h" +#include +#include +#include "xmlPresenter.h" +#include "transformHtml.h" +#include "transformText.h" + +std::string SendMailTask::defaultMailServer; + +namespace po = boost::program_options; +class CustomSendMailTaskLoader : public ElementLoaderImpl { + public: + CustomSendMailTaskLoader() : + opts("Send Email Task options") + { + opts.add_options() + ("sendmail.defaultserver", po::value(&SendMailTask::defaultMailServer), + "The address of the default mail relay server") + ; + } + po::options_description * + options() + { + return &opts; + } + + private: + po::options_description opts; +}; +DECLARE_CUSTOM_LOADER("sendmail", CustomSendMailTaskLoader); + +uint8_t SendMailTask::MailPart::mimeIdx; + +class SendEmailFailed : public std::runtime_error { + public: + SendEmailFailed(const std::string & what) : std::runtime_error(what) { } +}; + +typedef boost::shared_ptr XmlDocumentPtr; + +SendMailTask::SendMailTask(const xmlpp::Element * p) : + SourceObject(p), + Task(p), + to(p, "to"), + subject(p, "subject"), + from(p, "from"), + server(p, "server", defaultMailServer.empty(), defaultMailServer), + present(p->get_attribute_value("present").raw()) +{ +} + +SendMailTask::~SendMailTask() +{ +} + +void +SendMailTask::loadComplete(const CommonObjects *) +{ +} + +const char * +SendMailTask::writeMailWrapper(void ** buf, int * len, void * arg) +{ + return static_cast(arg)->writeMail(buf, len); +} + +SendMailTask::MailPart::MailPart(uint8_t s, uint8_t i, uint8_t p) : + sec(s), + ind(i), + prt(p) +{ +} + +SendMailTask::MailPart::~MailPart() +{ +} + +bool +SendMailTask::SortMailParts::operator()(const MailPartPtr & a, const MailPartPtr & b) const +{ + return (a->sec < b->sec) || ((a->sec == b->sec) && (a->ind < b->ind)) + || ((a->sec == b->sec) && (a->ind == b->ind) && (a->prt < b->prt)); +} + +class BoundaryBegin : public SendMailTask::MailPart { + public: + BoundaryBegin(const std::string & ct, uint8_t m) : + MailPart(m, MailPart::mimeIdx, 0), + contentType(ct) { + } + const char * write(char ** buf, int * len) { + *len = asprintf(buf, "\r\n--<>\r\nContent-Type: %s\r\n\r\n", contentType.c_str()); + return *buf; + } + private: + const std::string contentType; +}; + +class BoundaryEnd : public SendMailTask::MailPart { + public: + BoundaryEnd() : + MailPart(255, 0, 0) { + } + const char * write(char **, int * len) { + *len = 19; + return "\r\n--<>--\r\n"; + } +}; + +class Header : public SendMailTask::MailPart { + public: + Header(const std::string & h, const VariableType & v) : + MailPart(0, 0, 0), + header(h), + value(v) { + } + Header(const std::string & h, const char * v) : + MailPart(0, 0, 0), + header(h), + value(v) { + } + const char * write(char ** buf, int * len) { + writeText(buf, len, value); + return (const char *)*buf; + } + private: + void writeText(char ** buf, int * len, const char * text) const { + *len = asprintf(buf, "%s: %s\r\n", header.c_str(), text); + } + const std::string header; + const VariableType value; +}; + +class MimeContent : public SendMailTask::MailPart { + public: + MimeContent(const char * s, int l, uint8_t m) : + MailPart(m, MailPart::mimeIdx, 1), + str(s), + length(l) { + } + const char * write(char ** buf, int * len) { + *buf = NULL; + *len = length; + return str; + } + private: + const char * str; + const int length; +}; + +class TransformHtmlToEmail : public TransformImpl { + public: + TransformHtmlToEmail() : buf(NULL) + { + } + ~TransformHtmlToEmail() + { + if (buf) { + xmlFree(buf); + } + } + void transform(const HtmlDocument * cdoc, SendMailTask::Parts * parts) const + { + if (buf) { + xmlFree(buf); + buf = NULL; + } + xmlDoc * doc = const_cast(cdoc->doc); + int len = 0; + xmlDocDumpFormatMemoryEnc(doc, &buf, &len, "utf-8", 1); + parts->parts.insert(new BoundaryBegin("text/html; utf-8", 2)); + parts->parts.insert(new MimeContent(reinterpret_cast(buf), len, 2)); + SendMailTask::MailPart::mimeIdx += 1; + } + private: + mutable xmlChar * buf; +}; +DECLARE_TRANSFORM(TransformHtmlToEmail); + +class TransformTextToEmail : public TransformImpl { + public: + void transform(const TextDocument * str, SendMailTask::Parts * parts) const + { + parts->parts.insert(new BoundaryBegin("text/plain; utf-8", 1)); + parts->parts.insert(new MimeContent(str->doc.c_str(), str->doc.length(), 1)); + SendMailTask::MailPart::mimeIdx += 1; + } +}; +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 +{ + parts = new Parts(); + MailPart::mimeIdx = 0; + parts->parts.insert(new Header("To", to)); + parts->parts.insert(new Header("From", from)); + parts->parts.insert(new Header("Subject", subject)); + parts->parts.insert(new Header("Content-Type", "multipart/alternative; boundary=\"<>\"")); + parts->parts.insert(new Header("MIME-Version", "1.0")); + parts->parts.insert(new Header("Content-Transfer-Encoding", "binary")); + parts->parts.insert(new BoundaryEnd()); + + ViewHostPtr vsp = new ViewHost(Environment::getCurrent()->resolveScript("emails", present)); + vsp->executeViews(boost::bind(&SendMailTask::createDefaultPresenter, this, _1)); + vsp->doTransforms(); + part = parts->parts.begin(); + + // Write email + smtp_session_t session = smtp_create_session(); + smtp_message_t message = smtp_add_message(session); + smtp_set_server(session, server()); + smtp_set_header(message, "To", NULL, NULL); + smtp_add_recipient(message, to()); + 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.reset(); +} + +const char * +SendMailTask::writeMail(void ** buf, int * len) const +{ + if (len == NULL || part == parts->parts.end()) { + return NULL; + } + return (*part++)->write((char**)buf, len); +} + diff --git a/project2/mail/sendmailTask.h b/project2/mail/sendmailTask.h new file mode 100644 index 0000000..fa8427f --- /dev/null +++ b/project2/mail/sendmailTask.h @@ -0,0 +1,59 @@ +#ifndef SENDMAILTASK_H +#define SENDMAILTASK_H + +#include +#include +#include +#include "task.h" +#include "transform.h" +#include "variables.h" +#include "presenter.h" + +/// Project2 component to send an email +class SendMailTask : public Task { + public: + class MailPart : public IntrusivePtrBase { + public: + MailPart(uint8_t, uint8_t, uint8_t); + ~MailPart(); + virtual const char * write(char ** buf, int * len) = 0; + const uint8_t sec, ind, prt; + static uint8_t mimeIdx; + }; + typedef boost::intrusive_ptr MailPartPtr; + class SortMailParts { + public: + bool operator()(const MailPartPtr &, const MailPartPtr &) const; + }; + typedef std::multiset PartList; + class Parts : public TransformChainLink { + public: + PartList parts; + }; + + SendMailTask(const xmlpp::Element * p); + virtual ~SendMailTask(); + virtual void loadComplete(const CommonObjects *); + virtual void execute() const; + + protected: + const Variable to; + const Variable subject; + const Variable from; + const Variable server; + const std::string present; + + 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; + + mutable boost::intrusive_ptr parts; + mutable PartList::iterator part; + + // Configurables + friend class CustomSendMailTaskLoader; + static std::string defaultMailServer; +}; + +#endif diff --git a/project2/noOutputExecute.cpp b/project2/noOutputExecute.cpp deleted file mode 100644 index 3bfa0e9..0000000 --- a/project2/noOutputExecute.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include "noOutputExecute.h" -#include - -NoOutputExecute::NoOutputExecute(const xmlpp::Element * p) : - SourceObject(p) -{ -} - -NoOutputExecute::NoOutputExecute(const std::string & n) : - SourceObject(n) -{ -} - -NoOutputExecute::~NoOutputExecute() -{ -} - diff --git a/project2/noOutputExecute.h b/project2/noOutputExecute.h deleted file mode 100644 index 1047f38..0000000 --- a/project2/noOutputExecute.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef NOOUTPUTEXECUTE_H -#define NOOUTPUTEXECUTE_H - -#include "sourceObject.h" -#include "xmlStorage.h" - -class NoOutputExecute; -typedef boost::intrusive_ptr NoOutputExecutePtr; - -/// Base class for Project2 compoments that perform actions, but product no output -class NoOutputExecute : public virtual SourceObject { - public: - NoOutputExecute(const xmlpp::Element * p); - NoOutputExecute(const std::string & n); - - virtual ~NoOutputExecute(); - - virtual void execute() const = 0; -}; - -#endif - diff --git a/project2/ostreamWrapper.h b/project2/ostreamWrapper.h deleted file mode 100644 index ef8596c..0000000 --- a/project2/ostreamWrapper.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef OSTREAMWRAPPER_H -#define OSTREAMWRAPPER_H - -#include -#include "transform.h" - -class ostreamWrapper : public TransformChainLink { - public: - ostreamWrapper(std::ostream & s) : strm(s) { } - std::ostream & strm; -}; - -#endif - diff --git a/project2/paramChecker.cpp b/project2/paramChecker.cpp deleted file mode 100644 index 0781e90..0000000 --- a/project2/paramChecker.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include "paramChecker.h" -#include "xmlObjectLoader.h" - -ParamChecker::ParamChecker(const xmlpp::Element * p) : - SourceObject(p), - message(p, "message", false, "Check failed"), - group(p, "group", false, "default"), - present(p->get_attribute_value("present")) -{ -} - -ParamChecker::~ParamChecker() -{ -} - diff --git a/project2/paramChecker.h b/project2/paramChecker.h deleted file mode 100644 index d013fc4..0000000 --- a/project2/paramChecker.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef PARAMCHECKER_H -#define PARAMCHECKER_H - -#include -#include "sourceObject.h" -#include "variables.h" - -/// Base class for Project2 compoments that perform tests/checks -class ParamChecker : public SourceObject { - public: - ParamChecker(const xmlpp::Element * p); - virtual ~ParamChecker(); - - virtual bool performCheck() const = 0; - - const Variable message; - const Variable group; - const std::string present; -}; -typedef boost::intrusive_ptr ParamCheckerCPtr; - -#endif - - diff --git a/project2/presenter.cpp b/project2/presenter.cpp deleted file mode 100644 index 9544743..0000000 --- a/project2/presenter.cpp +++ /dev/null @@ -1,50 +0,0 @@ -#include "presenter.h" -#include "dataSource.h" -#include "appEngine.h" -#include - -Presenter::Presenter() -{ -} - -Presenter::~Presenter() -{ -} - -void -Presenter::pushSub(const Glib::ustring & name) const -{ - pushSub(name, Glib::ustring()); -} - -void -Presenter::addAttr(const Glib::ustring & name, const VariableType & value) const -{ - addAttr(name, Glib::ustring(), value); -} - -void -Presenter::addAttr(const Glib::ustring & name, const Glib::ustring & ns, const VariableType & value) const -{ - addField(name, ns, value); -} - -void -Presenter::addField(const Glib::ustring & name, const VariableType & value) const -{ - addField(name, Glib::ustring(), value); -} - -void -Presenter::addField(const Glib::ustring & name, const Glib::ustring & ns, const VariableType & value) const -{ - pushSub(name, ns); - addText(value); - popSub(); -} - -ContentPresenter::ContentPresenter(const Glib::ustring & ct) : - contentType(ct) -{ -} - diff --git a/project2/presenter.h b/project2/presenter.h deleted file mode 100644 index a4c0a00..0000000 --- a/project2/presenter.h +++ /dev/null @@ -1,55 +0,0 @@ -#ifndef PRESENTER_H -#define PRESENTER_H - -#include -#include -#include -#include -#include "view.h" -#include "paramChecker.h" -#include "xmlObjectLoader.h" - -class Presenter : public virtual IntrusivePtrBase { - public: - Presenter(); - virtual ~Presenter() = 0; - - virtual void declareNamespace(const Glib::ustring & prefix, const Glib::ustring & ns) const = 0; - virtual void pushSub(const Glib::ustring & name) const; - virtual void pushSub(const Glib::ustring & name, const Glib::ustring & ns) const = 0; - virtual void setNamespace(const Glib::ustring & prefix, const Glib::ustring & ns) const = 0; - virtual void addAttr(const Glib::ustring & name, const VariableType & value) const; - virtual void addAttr(const Glib::ustring & name, const Glib::ustring & ns, const VariableType & value) const; - virtual void addField(const Glib::ustring & name, const VariableType & value) const; - 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; -}; - -class ContentPresenter : public Presenter { - public: - ContentPresenter(const Glib::ustring & contentType); - const Glib::ustring contentType; -}; - -typedef boost::intrusive_ptr PresenterCPtr; -typedef boost::intrusive_ptr 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 PresenterLoaderImpl : public PresenterLoader { - public: - virtual PresenterPtr createFrom(const xmlpp::Element * e) const - { - return new PresenterType(e); - } -}; - -#endif - diff --git a/project2/procRows.cpp b/project2/procRows.cpp deleted file mode 100644 index f1d00e0..0000000 --- a/project2/procRows.cpp +++ /dev/null @@ -1,46 +0,0 @@ -#include "procRows.h" -#include "xmlObjectLoader.h" -#include - -DECLARE_LOADER("procrows", ProcRows); - -SimpleMessageException(SubProcessFailedToStart); -SimpleNumericException(SubProcessFailed); - -ProcRows::ProcRows(const xmlpp::Element * p) : - FileRows(p) -{ -} - -ProcRows::~ProcRows() -{ -} - -void -ProcRows::loadComplete(const CommonObjects *) -{ -} - -FileStarChannel -ProcRows::doOpen() const -{ - FILE * f = popen(path(), "re"); - if (!f) { - throw SubProcessFailedToStart(path()); - } - return FileStarChannel(f, false, doClose); -} - -int -ProcRows::doClose(FILE * f) -{ - int pclo = pclose(f); - // pclose returns an error if the application is still running, - // but if there is already an exception being thrown, we don't - // want to throw another. - if (pclo != 0 && !std::uncaught_exception()) { - throw SubProcessFailed(pclo); - } - return 0; -} - diff --git a/project2/procRows.h b/project2/procRows.h deleted file mode 100644 index 63dbb8e..0000000 --- a/project2/procRows.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef PROCROWS_H -#define PROCROWS_H - -#include "fileRows.h" - -/// Project2 component to create a row set from the output of a locally executed program -class ProcRows : public FileRows { - public: - ProcRows(const xmlpp::Element * p); - ~ProcRows(); - - virtual void loadComplete(const CommonObjects *); - virtual FileStarChannel doOpen() const; - static int doClose(FILE*); -}; - -#endif - diff --git a/project2/processes/Jamfile.jam b/project2/processes/Jamfile.jam new file mode 100644 index 0000000..4c0c2b4 --- /dev/null +++ b/project2/processes/Jamfile.jam @@ -0,0 +1,13 @@ +alias libxmlpp : : : : + "`pkg-config --cflags libxml++-2.6`" + "`pkg-config --libs libxml++-2.6`" ; + +lib p2processes : + procRows.cpp + : + ../../libmisc + libxmlpp + ../common//p2common + ../files//p2files + ; + diff --git a/project2/processes/procRows.cpp b/project2/processes/procRows.cpp new file mode 100644 index 0000000..f1d00e0 --- /dev/null +++ b/project2/processes/procRows.cpp @@ -0,0 +1,46 @@ +#include "procRows.h" +#include "xmlObjectLoader.h" +#include + +DECLARE_LOADER("procrows", ProcRows); + +SimpleMessageException(SubProcessFailedToStart); +SimpleNumericException(SubProcessFailed); + +ProcRows::ProcRows(const xmlpp::Element * p) : + FileRows(p) +{ +} + +ProcRows::~ProcRows() +{ +} + +void +ProcRows::loadComplete(const CommonObjects *) +{ +} + +FileStarChannel +ProcRows::doOpen() const +{ + FILE * f = popen(path(), "re"); + if (!f) { + throw SubProcessFailedToStart(path()); + } + return FileStarChannel(f, false, doClose); +} + +int +ProcRows::doClose(FILE * f) +{ + int pclo = pclose(f); + // pclose returns an error if the application is still running, + // but if there is already an exception being thrown, we don't + // want to throw another. + if (pclo != 0 && !std::uncaught_exception()) { + throw SubProcessFailed(pclo); + } + return 0; +} + diff --git a/project2/processes/procRows.h b/project2/processes/procRows.h new file mode 100644 index 0000000..63dbb8e --- /dev/null +++ b/project2/processes/procRows.h @@ -0,0 +1,18 @@ +#ifndef PROCROWS_H +#define PROCROWS_H + +#include "fileRows.h" + +/// Project2 component to create a row set from the output of a locally executed program +class ProcRows : public FileRows { + public: + ProcRows(const xmlpp::Element * p); + ~ProcRows(); + + virtual void loadComplete(const CommonObjects *); + virtual FileStarChannel doOpen() const; + static int doClose(FILE*); +}; + +#endif + diff --git a/project2/rawView.cpp b/project2/rawView.cpp deleted file mode 100644 index 90569c9..0000000 --- a/project2/rawView.cpp +++ /dev/null @@ -1,55 +0,0 @@ -#include "exceptions.h" -#include "rawView.h" -#include "xml.h" -#include "xmlObjectLoader.h" -#include "environment.h" -#include "appEngine.h" -#include -#include - -DECLARE_LOADER("rawview", RawView); - -RawView::RawView(const xmlpp::Element * p) : - SourceObject(p), - View(p), - copyRoot(p) -{ -} - -void -RawView::loadComplete(const CommonObjects *) -{ -} - -void -RawView::execute(const Presenter * p) const -{ - BOOST_FOREACH(xmlpp::Node * node, copyRoot->get_children()) { - const xmlpp::Element * e = dynamic_cast(node); - if (e) { - copyNode(p, e); - } - } -} - -void -RawView::copyNode(const Presenter * p, const xmlpp::Element * n) const -{ - p->pushSub(n->get_name()); - p->setNamespace(n->get_namespace_prefix(), n->get_namespace_uri()); - xmlpp::Element::AttributeList al = n->get_attributes(); - BOOST_FOREACH(const xmlpp::Attribute * a, al) { - p->addAttr(a->get_name(), a->get_value()); - } - const xmlpp::Node::NodeList ch = n->get_children(); - BOOST_FOREACH(const xmlpp::Node * c, ch) { - if (const xmlpp::Element * e = dynamic_cast(c)) { - copyNode(p, e); - } - else if (const xmlpp::TextNode * t = dynamic_cast(c)) { - p->addText(t->get_content()); - } - } - p->popSub(); -} - diff --git a/project2/rawView.h b/project2/rawView.h deleted file mode 100644 index b192c89..0000000 --- a/project2/rawView.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef RAWVIEW_H -#define RAWVIEW_H - -#include -#include -#include -#include "view.h" - -/// Project2 component to create output based on its own XML tree node -class RawView : public View { - public: - RawView(const xmlpp::Element * p); - void execute(const Presenter *) const; - virtual void loadComplete(const CommonObjects *); - private: - void copyNode(const Presenter *, const xmlpp::Element *) const; - const xmlpp::Element * copyRoot; -}; - -#endif - - diff --git a/project2/rdbmsDataSource.cpp b/project2/rdbmsDataSource.cpp deleted file mode 100644 index 97ff64f..0000000 --- a/project2/rdbmsDataSource.cpp +++ /dev/null @@ -1,219 +0,0 @@ -#include "rdbmsDataSource.h" -#include -#include -#include "logger.h" -#include -#include - -SimpleMessageException(UnknownConnectionProvider); - -/// Specialized ElementLoader for instances of RdbmsDataSource; handles persistent DB connections -class RdbmsDataSourceLoader : public ElementLoaderImpl { - public: - void onIdle() - { - // Disconnect all cached database connections - RdbmsDataSource::dbhosts.clear(); - } - static bool isConnectionExpired(const RdbmsDataSource::DBHosts::value_type & con) - { - return con.second->isExpired(); - } - void onPeriodic() - { - // Disconnect expired database connections - RdbmsDataSource::DBHosts::iterator i; - while ((i = std::find_if(RdbmsDataSource::dbhosts.begin(), RdbmsDataSource::dbhosts.end(), isConnectionExpired)) != RdbmsDataSource::dbhosts.end()) { - RdbmsDataSource::dbhosts.erase(i); - } - } - void onIteration() - { - RdbmsDataSource::changedDSNs.clear(); - } -}; -DECLARE_CUSTOM_LOADER("rdbmsdatasource", RdbmsDataSourceLoader); - -RdbmsDataSource::DBHosts RdbmsDataSource::dbhosts; -RdbmsDataSource::FailedHosts RdbmsDataSource::failedhosts; -RdbmsDataSource::DSNSet RdbmsDataSource::changedDSNs; - -RdbmsDataSource::RdbmsDataSource(const xmlpp::Element * p) : - DataSource(p), - masterDsn(dynamic_cast(p->find("masterdsn").front())), - preferLocal(p->get_attribute_value("preferlocal") != "false") -{ - BOOST_FOREACH(const xmlpp::Node * node, p->find("readonly/dsn")) { - const xmlpp::Element * elem = dynamic_cast(node); - if (elem) { - roDSNs.insert(ReadonlyDSNs::value_type(elem->get_attribute_value("host"), elem)); - } - } -} - -RdbmsDataSource::~RdbmsDataSource() -{ -} - -void -RdbmsDataSource::loadComplete(const CommonObjects *) -{ -} - -const DB::Connection & -RdbmsDataSource::getWritable() const -{ - ConnectionPtr master = connectTo(masterDsn); - if (!master->txOpen) { - master->connection->beginTx(); - master->txOpen = true; - } - changedDSNs.insert(name); - return *master->connection; -} - -const DB::Connection & -RdbmsDataSource::getReadonly() const -{ - if (changedDSNs.find(name) != changedDSNs.end()) { - return *connectTo(masterDsn)->connection; - } - if (localhost.length() == 0 && preferLocal) { - struct utsname name; - if (uname(&name)) { - Logger()->messagef(LOG_WARNING, "%s: Unable to determine local host name (%d:%s)", - __PRETTY_FUNCTION__, errno, strerror(errno)); - localhost = "unknown"; - } - else { - localhost = name.nodename; - } - } - if (preferLocal) { - ReadonlyDSNs::const_iterator ro = roDSNs.find(localhost); - try { - if (ro == roDSNs.end()) { - Logger()->messagef(LOG_INFO, "%s: No database host matches local host name (%s) Will use master DSN", - __PRETTY_FUNCTION__, localhost.c_str()); - return *connectTo(masterDsn)->connection; - } - return *connectTo(ro->second)->connection; - } - catch (...) { - // Failed to connect to a preferred DB... carry on and try the others... - } - } - BOOST_FOREACH(ReadonlyDSNs::value_type db, roDSNs) { - try { - return *connectTo(db.second)->connection; - } - catch (...) { - } - } - return *connectTo(masterDsn)->connection; -} - -void -RdbmsDataSource::commit() -{ - DBHosts::const_iterator m = dbhosts.find(masterDsn); - if (m != dbhosts.end() && m->second->txOpen) { - m->second->connection->commitTx(); - m->second->txOpen = false; - } -} - -void -RdbmsDataSource::rollback() -{ - DBHosts::const_iterator m = dbhosts.find(masterDsn); - if (m != dbhosts.end() && m->second->txOpen) { - m->second->connection->rollbackTx(); - m->second->txOpen = false; - } - changedDSNs.erase(name); -} - -RdbmsDataSource::ConnectionPtr -RdbmsDataSource::connectTo(const ConnectionInfo & dsn) -{ - FailedHosts::iterator dbf = failedhosts.find(dsn); - if (dbf != failedhosts.end()) { - if (time(NULL) - 20 > dbf->second.FailureTime) { - failedhosts.erase(dbf); - } - else { - throw dbf->second; - } - } - DBHosts::const_iterator dbi = dbhosts.find(dsn); - if (dbi != dbhosts.end()) { - try { - dbi->second->connection->ping(); - dbi->second->touch(); - return dbi->second; - } - catch (...) { - // Connection in failed state - Logger()->messagef(LOG_DEBUG, "%s: Cached connection failed", __PRETTY_FUNCTION__); - } - } - - try { - ConnectionPtr db = ConnectionPtr(new RdbmsConnection(dsn.connect(), 300)); - dbhosts[dsn] = db; - db->touch(); - return db; - } - catch (const DB::ConnectionError & e) { - failedhosts.insert(FailedHosts::value_type(dsn, e)); - throw; - } -} - -RdbmsDataSource::RdbmsConnection::RdbmsConnection(const DB::Connection * con, time_t kat) : - connection(con), - txOpen(false), - lastUsedTime(0), - keepAliveTime(kat) -{ -} - -RdbmsDataSource::RdbmsConnection::~RdbmsConnection() -{ - connection->finish(); - delete connection; -} - -void -RdbmsDataSource::RdbmsConnection::touch() const -{ - time(&lastUsedTime); -} - -bool -RdbmsDataSource::RdbmsConnection::isExpired() const -{ - return (time(NULL) > lastUsedTime + keepAliveTime); -} - -RdbmsDataSource::ConnectionInfo::ConnectionInfo(const xmlpp::Element * n) -{ - BOOST_FOREACH(const xmlpp::Node * node, n->get_children()) { - typeId = LoaderBase::getLoader(node->get_name()); - dsn = dynamic_cast(node)->get_child_text()->get_content(); - } -} - -DB::Connection * -RdbmsDataSource::ConnectionInfo::connect() const -{ - return typeId->connect(dsn); -} - -bool -RdbmsDataSource::ConnectionInfo::operator<(const RdbmsDataSource::ConnectionInfo & other) const -{ - return ((typeId < other.typeId) || ((typeId == other.typeId) && (dsn < other.dsn))); -} - diff --git a/project2/rdbmsDataSource.h b/project2/rdbmsDataSource.h deleted file mode 100644 index 0e175e7..0000000 --- a/project2/rdbmsDataSource.h +++ /dev/null @@ -1,92 +0,0 @@ -#ifndef RDBMSDATASOURCE_H -#define RDBMSDATASOURCE_H - -#include -#include -#include -#include -#include "dataSource.h" -#include "../libdbpp/connection.h" -#include "../libdbpp/error.h" -#include "xmlObjectLoader.h" - -/// Base class to implement DB connection type modules -class ConnectionLoader : public ComponentLoader { - public: - virtual DB::Connection * connect(const std::string & dsn) const = 0; -}; - -/// Helper implemention for specific DB types -template -class ConnectionLoaderImpl : public ConnectionLoader { - public: - virtual DB::Connection * connect(const std::string & dsn) const - { - return new DBType(dsn); - } -}; - -/// Project2 component to provide access to transactional RDBMS data sources -class RdbmsDataSource : public DataSource { - public: - class RdbmsConnection { - public: - RdbmsConnection(const DB::Connection * connection, time_t kat); - ~RdbmsConnection(); - - void touch() const; - bool isExpired() const; - const DB::Connection * const connection; - bool txOpen; - - private: - mutable time_t lastUsedTime; - const time_t keepAliveTime; - }; - - class ConnectionInfo { - public: - ConnectionInfo(const xmlpp::Element *); - - DB::Connection * connect() const; - - bool operator<(const ConnectionInfo & o) const; - - private: - std::string dsn; - boost::shared_ptr typeId; - }; - - typedef boost::shared_ptr ConnectionPtr; - typedef std::map ReadonlyDSNs; // Map hostname to DSN string - typedef std::map DBHosts; // Map DSN strings to connections - typedef std::map FailedHosts; // Map DSN strings to failures - - RdbmsDataSource(const xmlpp::Element * p); - ~RdbmsDataSource(); - - const DB::Connection & getReadonly() const; - const DB::Connection & getWritable() const; - virtual void loadComplete(const CommonObjects *); - virtual void commit(); - virtual void rollback(); - - const ConnectionInfo masterDsn; - const bool preferLocal; - - protected: - static ConnectionPtr connectTo(const ConnectionInfo & dsn); - ReadonlyDSNs roDSNs; - - private: - mutable std::string localhost; - static DBHosts dbhosts; - static FailedHosts failedhosts; - typedef std::set DSNSet; - static DSNSet changedDSNs; - - friend class RdbmsDataSourceLoader; -}; - -#endif - diff --git a/project2/regex/Jamfile.jam b/project2/regex/Jamfile.jam new file mode 100644 index 0000000..a83697f --- /dev/null +++ b/project2/regex/Jamfile.jam @@ -0,0 +1,12 @@ +alias libxmlpp : : : : + "`pkg-config --cflags libxml++-2.6`" + "`pkg-config --libs libxml++-2.6`" ; + +lib p2regex : + regexCheck.cpp regexRows.cpp + : + ../../libmisc + libxmlpp + ../common//p2common + ; + diff --git a/project2/regex/regexCheck.cpp b/project2/regex/regexCheck.cpp new file mode 100644 index 0000000..b88a44c --- /dev/null +++ b/project2/regex/regexCheck.cpp @@ -0,0 +1,30 @@ +#include "regexCheck.h" +#include "xmlObjectLoader.h" +#include "commonObjects.h" +#include + +DECLARE_LOADER("regexcheck", RegexCheck); + +RegexCheck::RegexCheck(const xmlpp::Element * p) : + ParamChecker(p), + applyTo(p, "apply-to"), + regex(p, "regex") +{ +} + +RegexCheck::~RegexCheck() +{ +} + +void +RegexCheck::loadComplete(const CommonObjects *) +{ +} + +bool +RegexCheck::performCheck() const +{ + Glib::RefPtr reg = Glib::Regex::create(regex()); + return reg->match(applyTo()); +} + diff --git a/project2/regex/regexCheck.h b/project2/regex/regexCheck.h new file mode 100644 index 0000000..17033de --- /dev/null +++ b/project2/regex/regexCheck.h @@ -0,0 +1,20 @@ +#ifndef REGEXCHECK_H +#define REGEXCHECK_H + +#include "paramChecker.h" +#include "variables.h" + +/// Project2 component to test the value of a variable against a regular expression +class RegexCheck : public ParamChecker { + public: + RegexCheck(const xmlpp::Element * p); + virtual ~RegexCheck(); + + virtual void loadComplete(const CommonObjects *); + bool performCheck() const; + + const Variable applyTo; + const Variable regex; +}; + +#endif diff --git a/project2/regex/regexRows.cpp b/project2/regex/regexRows.cpp new file mode 100644 index 0000000..1dab636 --- /dev/null +++ b/project2/regex/regexRows.cpp @@ -0,0 +1,43 @@ +#include "regexRows.h" +#include "xmlObjectLoader.h" +#include "rowProcessor.h" +#include +#include + +DECLARE_LOADER("regexrows", RegexRows); + +RegexRows::RegexRows(const xmlpp::Element * p) : + DefinedColumns(p, "columns/column", boost::bind(&Column::make, _1, _2)), + RowSet(p), + sourceText(p, "sourceText"), + regex(p, "regex") +{ +} + +RegexRows::~RegexRows() +{ +} + +void +RegexRows::loadComplete(const CommonObjects*) +{ +} + +void +RegexRows::execute(const Glib::ustring&, const RowProcessor * rp) const +{ + Glib::RefPtr reg = Glib::Regex::create(regex(), Glib::REGEX_CASELESS | Glib::REGEX_DOTALL); + Glib::MatchInfo matches; + if (reg->match(sourceText(), matches)) { + ColumnValues cv(this); + do { + unsigned int cols = std::min(matches.get_match_count(), cv.rowSet->columns.size() + 1); + unsigned int n; + for (n = 1; n < cols; n += 1) { + cv.fields[n - 1] = matches.fetch(n); + } + cv.process(rp); + } while (matches.next()); + } +} + diff --git a/project2/regex/regexRows.h b/project2/regex/regexRows.h new file mode 100644 index 0000000..cef2e71 --- /dev/null +++ b/project2/regex/regexRows.h @@ -0,0 +1,21 @@ +#ifndef REGEXROWS_H +#define REGEXROWS_H + +#include "definedColumns.h" +#include "variables.h" + +/// Base class for Project2 components that create a row set based on the contents of a byte stream +class RegexRows : public DefinedColumns, public RowSet { + public: + RegexRows(const xmlpp::Element * p); + ~RegexRows(); + void loadComplete(const CommonObjects*); + void execute(const Glib::ustring&, const RowProcessor*) const; + + private: + const Variable sourceText; + const Variable regex; +}; + +#endif + diff --git a/project2/regexCheck.cpp b/project2/regexCheck.cpp deleted file mode 100644 index b88a44c..0000000 --- a/project2/regexCheck.cpp +++ /dev/null @@ -1,30 +0,0 @@ -#include "regexCheck.h" -#include "xmlObjectLoader.h" -#include "commonObjects.h" -#include - -DECLARE_LOADER("regexcheck", RegexCheck); - -RegexCheck::RegexCheck(const xmlpp::Element * p) : - ParamChecker(p), - applyTo(p, "apply-to"), - regex(p, "regex") -{ -} - -RegexCheck::~RegexCheck() -{ -} - -void -RegexCheck::loadComplete(const CommonObjects *) -{ -} - -bool -RegexCheck::performCheck() const -{ - Glib::RefPtr reg = Glib::Regex::create(regex()); - return reg->match(applyTo()); -} - diff --git a/project2/regexCheck.h b/project2/regexCheck.h deleted file mode 100644 index 17033de..0000000 --- a/project2/regexCheck.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef REGEXCHECK_H -#define REGEXCHECK_H - -#include "paramChecker.h" -#include "variables.h" - -/// Project2 component to test the value of a variable against a regular expression -class RegexCheck : public ParamChecker { - public: - RegexCheck(const xmlpp::Element * p); - virtual ~RegexCheck(); - - virtual void loadComplete(const CommonObjects *); - bool performCheck() const; - - const Variable applyTo; - const Variable regex; -}; - -#endif diff --git a/project2/regexRows.cpp b/project2/regexRows.cpp deleted file mode 100644 index 1dab636..0000000 --- a/project2/regexRows.cpp +++ /dev/null @@ -1,43 +0,0 @@ -#include "regexRows.h" -#include "xmlObjectLoader.h" -#include "rowProcessor.h" -#include -#include - -DECLARE_LOADER("regexrows", RegexRows); - -RegexRows::RegexRows(const xmlpp::Element * p) : - DefinedColumns(p, "columns/column", boost::bind(&Column::make, _1, _2)), - RowSet(p), - sourceText(p, "sourceText"), - regex(p, "regex") -{ -} - -RegexRows::~RegexRows() -{ -} - -void -RegexRows::loadComplete(const CommonObjects*) -{ -} - -void -RegexRows::execute(const Glib::ustring&, const RowProcessor * rp) const -{ - Glib::RefPtr reg = Glib::Regex::create(regex(), Glib::REGEX_CASELESS | Glib::REGEX_DOTALL); - Glib::MatchInfo matches; - if (reg->match(sourceText(), matches)) { - ColumnValues cv(this); - do { - unsigned int cols = std::min(matches.get_match_count(), cv.rowSet->columns.size() + 1); - unsigned int n; - for (n = 1; n < cols; n += 1) { - cv.fields[n - 1] = matches.fetch(n); - } - cv.process(rp); - } while (matches.next()); - } -} - diff --git a/project2/regexRows.h b/project2/regexRows.h deleted file mode 100644 index cef2e71..0000000 --- a/project2/regexRows.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef REGEXROWS_H -#define REGEXROWS_H - -#include "definedColumns.h" -#include "variables.h" - -/// Base class for Project2 components that create a row set based on the contents of a byte stream -class RegexRows : public DefinedColumns, public RowSet { - public: - RegexRows(const xmlpp::Element * p); - ~RegexRows(); - void loadComplete(const CommonObjects*); - void execute(const Glib::ustring&, const RowProcessor*) const; - - private: - const Variable sourceText; - const Variable regex; -}; - -#endif - diff --git a/project2/rowProcessor.cpp b/project2/rowProcessor.cpp deleted file mode 100644 index 4ea89fd..0000000 --- a/project2/rowProcessor.cpp +++ /dev/null @@ -1,57 +0,0 @@ -#include "rowProcessor.h" -#include "logger.h" -#include "commonObjects.h" -#include "scopeObject.h" -#include - -RowProcessor::RowProcessor(const xmlpp::Element * p) : - IHaveParameters(p), - recordSource(p->get_attribute_value("source")), - filter(p->get_attribute_value("filter")) -{ - LoaderBase loader(true); - loader.supportedStorers.insert(Storer::into(&caches)); - loader.collectAll(p, true, IgnoreUnsupported); -} - -void -RowProcessor::loadComplete(const CommonObjects * co) -{ - source = co->getSource(recordSource); -} - -void -RowProcessor::execute() const -{ - IHaveParameters::push(this); - ScopeObject _ihp(boost::bind(&IHaveParameters::pop, this)); - BOOST_FOREACH(const CachePtr & c, caches) { - if (c->checkAndExecute(source->name, filter, this)) { - return; - } - } - BOOST_FOREACH(const CachePtr & c, caches) { - PresenterPtr p = c->openFor(source->name, filter, this); - if (p) { - tc.insert(p); - } - } - source->execute(filter, this); - tc.clear(); - BOOST_FOREACH(const CachePtr & c, caches) { - c->close(source->name, filter, this); - } -} - -void -RowProcessor::rowReadyInternal(const RowState * rs) const -{ - BOOST_FOREACH(const TargetCaches::value_type & c, tc) { - c->pushSub(filter.empty() ? "row" : filter); - rs->foreachColumn(boost::bind(&Presenter::addField, c, _2, _3)); - rs->foreachAttr(boost::bind(&Presenter::addAttr, c, _1, _2)); - c->popSub(); - } - rowReady(rs); -} - diff --git a/project2/rowProcessor.h b/project2/rowProcessor.h deleted file mode 100644 index c25dc73..0000000 --- a/project2/rowProcessor.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef ROWPROCESSOR_H -#define ROWPROCESSOR_H - -#include -#include "sourceObject.h" -#include "iHaveParameters.h" -#include "rowSet.h" -#include "cache.h" -#include "xmlStorage.h" - -class Presenter; - -/// Base class for Project2 components that work with row sets -class RowProcessor : public IHaveParameters { - public: - RowProcessor(const xmlpp::Element *); - void loadComplete(const CommonObjects *); - - const std::string recordSource; - const Glib::ustring filter; - - protected: - boost::intrusive_ptr source; - void execute() const; - - private: - friend class RowState; - void rowReadyInternal(const RowState *) const; - virtual void rowReady(const RowState *) const = 0; - typedef ANONORDEREDSTORAGEOF(Cache) Caches; - Caches caches; - typedef std::set TargetCaches; - mutable TargetCaches tc; -}; - -#endif - diff --git a/project2/rowSet.cpp b/project2/rowSet.cpp deleted file mode 100644 index 6902fd3..0000000 --- a/project2/rowSet.cpp +++ /dev/null @@ -1,99 +0,0 @@ -#include "rowSet.h" -#include "commonObjects.h" -#include "scopeObject.h" -#include "logger.h" -#include "variables.h" -#include "rowProcessor.h" -#include -#include - -RowState::RowValuesStack RowState::stack; - -RowSet::RowSet(const xmlpp::Element * p) : - SourceObject(p) -{ -} - -RowSet::~RowSet() -{ -} - -RowState::RowState() : - rowNum(0) -{ -} - -RowState::~RowState() -{ -} - -void -RowState::process(const RowProcessor * rp, bool r) -{ - rowNum += 1; - stack.push_back(this); - ScopeObject s(boost::bind(&RowState::RowValuesStack::pop_back, &stack)); - rp->rowReadyInternal(this); - if (r) { - reset(); - } -} - -void -RowState::reset() -{ - BOOST_FOREACH(FieldValues::value_type & v, fields) { - v = Null(); - } -} - -void -RowState::blankRow() -{ - rowNum += 1; -} - -VariableType -RowState::getRowNum() const -{ - return rowNum; -} - -RowState::RowAttribute -RowState::resolveAttr(const Glib::ustring & attrName) const -{ - if (attrName == "rownum") { - return boost::bind(&RowState::getRowNum, this); - } - throw AttributeDoesNotExist(attrName); -} - -VariableType -RowState::getCurrentValue(const Glib::ustring & col) const -{ - const Columns & columns = getColumns(); - Columns::index::type::iterator di = columns.get().find(col); - if (di != columns.get().end()) { - if (!boost::get(&fields[(*di)->idx])) { - return fields[(*di)->idx]; - } - return (*di)->defValue; - } - throw RowSet::FieldDoesNotExist(col); -} - -void -RowState::foreachColumn(const ColumnAction & action) const -{ - const Columns & columns = getColumns(); - BOOST_FOREACH(const Columns::value_type & col, columns.get()) { - action(col->idx, col->name, (!boost::get(&fields[col->idx])) ? fields[col->idx] : col->defValue()); - } -} - -void -RowState::foreachAttr(const AttrAction &) const -{ - // rowNum is magic, so it doesn't count :) -} - diff --git a/project2/rowSet.h b/project2/rowSet.h deleted file mode 100644 index a181059..0000000 --- a/project2/rowSet.h +++ /dev/null @@ -1,65 +0,0 @@ -#ifndef ROWSET_H -#define ROWSET_H - -#include -#include -#include "sourceObject.h" -#include "exceptions.h" -#include "columns.h" -#include - -class RowProcessor; -class RowSet; -class VariableType; -typedef boost::intrusive_ptr RowSetPtr; -typedef boost::intrusive_ptr ConstRowSetPtr; - -class RowState; - -/// Base class for Project2 components that provide a row set representation of data -class RowSet : public SourceObject { - public: - SimpleNumericException(ParentOutOfRange); - SimpleMessageException(FieldDoesNotExist); - SimpleNumericException(FieldOutOfRange); - - RowSet(const xmlpp::Element *); - virtual ~RowSet() = 0; - - virtual void execute(const Glib::ustring &, const RowProcessor *) const = 0; -}; - -class RowState { - public: - RowState(); - virtual ~RowState(); - - typedef boost::function0 RowAttribute; - typedef boost::function3 ColumnAction; - typedef boost::function2 AttrAction; - SimpleMessageException(AttributeDoesNotExist); - - VariableType getRowNum() const; - void process(const RowProcessor *, bool reset = true); - void blankRow(); - void reset(); - virtual VariableType getCurrentValue(const Glib::ustring & id) const; - virtual RowAttribute resolveAttr(const Glib::ustring & attrName) const; - void foreachColumn(const ColumnAction & action) const; - virtual void foreachAttr(const AttrAction & action) const; - virtual const Columns & getColumns() const = 0; - - typedef std::vector FieldValues; - FieldValues fields; - - - typedef std::vector RowValuesStack; - static const RowValuesStack & Stack() { return stack; } - - private: - unsigned int rowNum; - static RowValuesStack stack; -}; - -#endif - diff --git a/project2/rowView.cpp b/project2/rowView.cpp deleted file mode 100644 index 092192f..0000000 --- a/project2/rowView.cpp +++ /dev/null @@ -1,73 +0,0 @@ -#include "rowView.h" -#include "presenter.h" -#include "scopeObject.h" -#include "xmlObjectLoader.h" -#include "scopeObject.h" -#include -#include -#include - -DECLARE_LOADER("view", RowView); - -RowView::RowView(const xmlpp::Element * p) : - SourceObject(p), - View(p), - RowProcessor(p), - rootName(p->get_attribute_value("rootname")), - recordName(p->get_attribute_value("recordname")) -{ - BOOST_FOREACH(xmlpp::Node * node, p->find("columns/column")) { - const xmlpp::Element * elem = dynamic_cast(node); - if (elem) { - viewColumns.insert(Columns::value_type(elem->get_attribute_value("name"), - Variable::makeParent(elem->get_child_text()->get_content(), elem->get_attribute_value("source") == "attribute", 0))); - } - } - LoaderBase loader(true); - loader.supportedStorers.insert(Storer::into(&subViews)); - loader.collectAll(p, true, IgnoreUnsupported); -} - -RowView::~RowView() -{ -} - -void -RowView::loadComplete(const CommonObjects * co) -{ - RowProcessor::loadComplete(co); -} - -void -RowView::rowReady(const RowState * rs) const -{ - presenter->pushSub(recordName); - if (viewColumns.empty()) { - rs->foreachColumn(boost::bind(&Presenter::addField, presenter, _2, _3)); - } - else { - BOOST_FOREACH(const Columns::value_type & col, viewColumns) { - presenter->addField(col.first, col.second); - } - } - executeChildren(); - presenter->popSub(); -} - -void -RowView::execute(const Presenter * p) const -{ - presenter = p; - presenter->pushSub(rootName); - ScopeObject pres(boost::bind(&Presenter::popSub, p)); - RowProcessor::execute(); -} - -void -RowView::executeChildren() const -{ - BOOST_FOREACH(const SubViews::value_type & sq, subViews) { - sq->execute(presenter); - } -} - diff --git a/project2/rowView.h b/project2/rowView.h deleted file mode 100644 index c065414..0000000 --- a/project2/rowView.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef ROWVIEW_H -#define ROWVIEW_H - -#include -#include -#include "rowProcessor.h" -#include "view.h" - -/// Project2 component to create output based on a records in a row set -class RowView : public View, public RowProcessor { - public: - RowView(const xmlpp::Element *); - virtual ~RowView(); - - void loadComplete(const CommonObjects *); - void execute(const Presenter *) const; - void rowReady(const RowState *) const; - - const Glib::ustring rootName; - const Glib::ustring recordName; - - protected: - typedef std::map Columns; - Columns viewColumns; - - void executeChildren() const; - typedef ANONSTORAGEOF(View) SubViews; - SubViews subViews; - mutable const Presenter * presenter; -}; - -#endif - diff --git a/project2/safeMapFind.h b/project2/safeMapFind.h deleted file mode 100644 index b27caf3..0000000 --- a/project2/safeMapFind.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef SAFEMAPFIND_H -#define SAFEMAPFIND_H - -template -typename Map::const_iterator -safeMapFind(const Map & map, const typename Map::key_type & key) -{ - typename Map::const_iterator i = map.find(key); - if (i == map.end()) { - throw Ex(key); - } - return i; -} - -template -typename Map::mapped_type -defaultMapFind(const Map & map, const typename Map::key_type & key, const typename Map::mapped_type & def = typename Map::mapped_type()) -{ - typename Map::const_iterator i = map.find(key); - if (i == map.end()) { - return def; - } - return i->second; -} - -#endif - diff --git a/project2/scopeObject.cpp b/project2/scopeObject.cpp deleted file mode 100644 index 268fd2c..0000000 --- a/project2/scopeObject.cpp +++ /dev/null @@ -1,23 +0,0 @@ -#include "scopeObject.h" -#include "logger.h" - -ScopeObject::ScopeObject(const Event & onexitpre, const Event & onsuccess, const Event & onfailure, const Event & onexitpost) : - onExitPre(onexitpre), - onSuccess(onsuccess), - onFailure(onfailure), - onExitPost(onexitpost) -{ -} - -ScopeObject::~ScopeObject() -{ - if (onExitPre) onExitPre(); - if (std::uncaught_exception()) { - if (onFailure) onFailure(); - } - else { - if (onSuccess) onSuccess(); - } - if (onExitPost) onExitPost(); -} - diff --git a/project2/scopeObject.h b/project2/scopeObject.h deleted file mode 100644 index d019e7d..0000000 --- a/project2/scopeObject.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef SCOPE_OBJECT_H -#define SCOPE_OBJECT_H - -#include - -class ScopeObject { - public: - typedef boost::function0 Event; - ScopeObject(const Event &, const Event & = Event(), const Event & = Event(), const Event & = Event()); - ~ScopeObject(); - - private: - const Event onExitPre; - const Event onSuccess; - const Event onFailure; - const Event onExitPost; -}; - -#endif - diff --git a/project2/sendmailTask.cpp b/project2/sendmailTask.cpp deleted file mode 100644 index 73afb20..0000000 --- a/project2/sendmailTask.cpp +++ /dev/null @@ -1,252 +0,0 @@ -#include "sendmailTask.h" -#include "logger.h" -#include -#include -#include "xmlObjectLoader.h" -#include "viewHost.h" -#include "environment.h" -#include -#include -#include "xmlPresenter.h" -#include "transformHtml.h" -#include "transformText.h" - -std::string SendMailTask::defaultMailServer; - -namespace po = boost::program_options; -class CustomSendMailTaskLoader : public ElementLoaderImpl { - public: - CustomSendMailTaskLoader() : - opts("Send Email Task options") - { - opts.add_options() - ("sendmail.defaultserver", po::value(&SendMailTask::defaultMailServer), - "The address of the default mail relay server") - ; - } - po::options_description * - options() - { - return &opts; - } - - private: - po::options_description opts; -}; -DECLARE_CUSTOM_LOADER("sendmail", CustomSendMailTaskLoader); - -uint8_t SendMailTask::MailPart::mimeIdx; - -class SendEmailFailed : public std::runtime_error { - public: - SendEmailFailed(const std::string & what) : std::runtime_error(what) { } -}; - -typedef boost::shared_ptr XmlDocumentPtr; - -SendMailTask::SendMailTask(const xmlpp::Element * p) : - SourceObject(p), - Task(p), - to(p, "to"), - subject(p, "subject"), - from(p, "from"), - server(p, "server", defaultMailServer.empty(), defaultMailServer), - present(p->get_attribute_value("present").raw()) -{ -} - -SendMailTask::~SendMailTask() -{ -} - -void -SendMailTask::loadComplete(const CommonObjects *) -{ -} - -const char * -SendMailTask::writeMailWrapper(void ** buf, int * len, void * arg) -{ - return static_cast(arg)->writeMail(buf, len); -} - -SendMailTask::MailPart::MailPart(uint8_t s, uint8_t i, uint8_t p) : - sec(s), - ind(i), - prt(p) -{ -} - -SendMailTask::MailPart::~MailPart() -{ -} - -bool -SendMailTask::SortMailParts::operator()(const MailPartPtr & a, const MailPartPtr & b) const -{ - return (a->sec < b->sec) || ((a->sec == b->sec) && (a->ind < b->ind)) - || ((a->sec == b->sec) && (a->ind == b->ind) && (a->prt < b->prt)); -} - -class BoundaryBegin : public SendMailTask::MailPart { - public: - BoundaryBegin(const std::string & ct, uint8_t m) : - MailPart(m, MailPart::mimeIdx, 0), - contentType(ct) { - } - const char * write(char ** buf, int * len) { - *len = asprintf(buf, "\r\n--<>\r\nContent-Type: %s\r\n\r\n", contentType.c_str()); - return *buf; - } - private: - const std::string contentType; -}; - -class BoundaryEnd : public SendMailTask::MailPart { - public: - BoundaryEnd() : - MailPart(255, 0, 0) { - } - const char * write(char **, int * len) { - *len = 19; - return "\r\n--<>--\r\n"; - } -}; - -class Header : public SendMailTask::MailPart { - public: - Header(const std::string & h, const VariableType & v) : - MailPart(0, 0, 0), - header(h), - value(v) { - } - Header(const std::string & h, const char * v) : - MailPart(0, 0, 0), - header(h), - value(v) { - } - const char * write(char ** buf, int * len) { - writeText(buf, len, value); - return (const char *)*buf; - } - private: - void writeText(char ** buf, int * len, const char * text) const { - *len = asprintf(buf, "%s: %s\r\n", header.c_str(), text); - } - const std::string header; - const VariableType value; -}; - -class MimeContent : public SendMailTask::MailPart { - public: - MimeContent(const char * s, int l, uint8_t m) : - MailPart(m, MailPart::mimeIdx, 1), - str(s), - length(l) { - } - const char * write(char ** buf, int * len) { - *buf = NULL; - *len = length; - return str; - } - private: - const char * str; - const int length; -}; - -class TransformHtmlToEmail : public TransformImpl { - public: - TransformHtmlToEmail() : buf(NULL) - { - } - ~TransformHtmlToEmail() - { - if (buf) { - xmlFree(buf); - } - } - void transform(const HtmlDocument * cdoc, SendMailTask::Parts * parts) const - { - if (buf) { - xmlFree(buf); - buf = NULL; - } - xmlDoc * doc = const_cast(cdoc->doc); - int len = 0; - xmlDocDumpFormatMemoryEnc(doc, &buf, &len, "utf-8", 1); - parts->parts.insert(new BoundaryBegin("text/html; utf-8", 2)); - parts->parts.insert(new MimeContent(reinterpret_cast(buf), len, 2)); - SendMailTask::MailPart::mimeIdx += 1; - } - private: - mutable xmlChar * buf; -}; -DECLARE_TRANSFORM(TransformHtmlToEmail); - -class TransformTextToEmail : public TransformImpl { - public: - void transform(const TextDocument * str, SendMailTask::Parts * parts) const - { - parts->parts.insert(new BoundaryBegin("text/plain; utf-8", 1)); - parts->parts.insert(new MimeContent(str->doc.c_str(), str->doc.length(), 1)); - SendMailTask::MailPart::mimeIdx += 1; - } -}; -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 -{ - parts = new Parts(); - MailPart::mimeIdx = 0; - parts->parts.insert(new Header("To", to)); - parts->parts.insert(new Header("From", from)); - parts->parts.insert(new Header("Subject", subject)); - parts->parts.insert(new Header("Content-Type", "multipart/alternative; boundary=\"<>\"")); - parts->parts.insert(new Header("MIME-Version", "1.0")); - parts->parts.insert(new Header("Content-Transfer-Encoding", "binary")); - parts->parts.insert(new BoundaryEnd()); - - ViewHostPtr vsp = new ViewHost(Environment::getCurrent()->resolveScript("emails", present)); - vsp->executeViews(boost::bind(&SendMailTask::createDefaultPresenter, this, _1)); - vsp->doTransforms(); - part = parts->parts.begin(); - - // Write email - smtp_session_t session = smtp_create_session(); - smtp_message_t message = smtp_add_message(session); - smtp_set_server(session, server()); - smtp_set_header(message, "To", NULL, NULL); - smtp_add_recipient(message, to()); - 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.reset(); -} - -const char * -SendMailTask::writeMail(void ** buf, int * len) const -{ - 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 deleted file mode 100644 index fa8427f..0000000 --- a/project2/sendmailTask.h +++ /dev/null @@ -1,59 +0,0 @@ -#ifndef SENDMAILTASK_H -#define SENDMAILTASK_H - -#include -#include -#include -#include "task.h" -#include "transform.h" -#include "variables.h" -#include "presenter.h" - -/// Project2 component to send an email -class SendMailTask : public Task { - public: - class MailPart : public IntrusivePtrBase { - public: - MailPart(uint8_t, uint8_t, uint8_t); - ~MailPart(); - virtual const char * write(char ** buf, int * len) = 0; - const uint8_t sec, ind, prt; - static uint8_t mimeIdx; - }; - typedef boost::intrusive_ptr MailPartPtr; - class SortMailParts { - public: - bool operator()(const MailPartPtr &, const MailPartPtr &) const; - }; - typedef std::multiset PartList; - class Parts : public TransformChainLink { - public: - PartList parts; - }; - - SendMailTask(const xmlpp::Element * p); - virtual ~SendMailTask(); - virtual void loadComplete(const CommonObjects *); - virtual void execute() const; - - protected: - const Variable to; - const Variable subject; - const Variable from; - const Variable server; - const std::string present; - - 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; - - mutable boost::intrusive_ptr parts; - mutable PartList::iterator part; - - // Configurables - friend class CustomSendMailTaskLoader; - static std::string defaultMailServer; -}; - -#endif diff --git a/project2/session.cpp b/project2/session.cpp deleted file mode 100644 index 6246068..0000000 --- a/project2/session.cpp +++ /dev/null @@ -1,10 +0,0 @@ -#include "session.h" - -Session::Session() -{ -} - -Session::~Session() -{ -} - diff --git a/project2/session.h b/project2/session.h deleted file mode 100644 index 7b66db9..0000000 --- a/project2/session.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef SESSION_H -#define SESSION_H - -#include -#include -#include -#include "intrusivePtrBase.h" -#include "variables.h" -#include "exceptions.h" - -/// Base class for classes implementing session variable storage -class Session : public virtual IntrusivePtrBase { - public: - SimpleMessageException(VariableNotFound); - typedef std::map Values; - - Session(); - virtual ~Session() = 0; - - virtual const VariableType & GetValue(const Glib::ustring & name) const = 0; - virtual Values GetValuesCopy() const = 0; - virtual void SetValue(const Glib::ustring & name, const VariableType & value) = 0; - virtual void ClearValue(const Glib::ustring & name) = 0; - virtual time_t ExpiryTime() const = 0; - - protected: - virtual void ExpiryTime(time_t) = 0; - friend class SessionContainer; -}; -typedef boost::intrusive_ptr SessionPtr; - -#endif - diff --git a/project2/sessionClearTask.cpp b/project2/sessionClearTask.cpp deleted file mode 100644 index 15ba270..0000000 --- a/project2/sessionClearTask.cpp +++ /dev/null @@ -1,30 +0,0 @@ -#include -#include "xmlObjectLoader.h" -#include "sessionClearTask.h" -#include "appEngine.h" -#include "session.h" - -DECLARE_LOADER("sessionclear", SessionClearTask); - -SessionClearTask::SessionClearTask(const xmlpp::Element * p) : - SourceObject(p), - Task(p), - key(p->get_attribute_value("key")) -{ -} - -SessionClearTask::~SessionClearTask() -{ -} - -void -SessionClearTask::loadComplete(const CommonObjects *) -{ -} - -void -SessionClearTask::execute() const -{ - ApplicationEngine::getCurrent()->session()->ClearValue(key); -} - diff --git a/project2/sessionClearTask.h b/project2/sessionClearTask.h deleted file mode 100644 index 8241f8a..0000000 --- a/project2/sessionClearTask.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef SESSIONCLEARTASK_H -#define SESSIONCLEARTASK_H - -#include -#include -#include -#include "sourceObject.h" -#include "xmlObjectLoader.h" -#include "task.h" - -class CommonObjects; - -/// Project2 component to remove a variable from the session -class SessionClearTask : public Task { - public: - SessionClearTask(const xmlpp::Element * p); - virtual ~SessionClearTask(); - virtual void loadComplete(const CommonObjects *); - void execute() const; - - const Glib::ustring key; -}; - -#endif - - diff --git a/project2/sessionContainer.cpp b/project2/sessionContainer.cpp deleted file mode 100644 index 635889b..0000000 --- a/project2/sessionContainer.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "sessionContainer.h" -#include "environment.h" - -SessionContainer::SessionContainer() -{ -} - -SessionContainer::~SessionContainer() -{ -} - -SessionPtr -SessionContainer::GetSession(UUID & id) -{ - SessionPtr s = getSession(id); - s->ExpiryTime(time(NULL) + Environment::getCurrent()->sessionTimeOut); - return s; -} - diff --git a/project2/sessionContainer.h b/project2/sessionContainer.h deleted file mode 100644 index fcad4b9..0000000 --- a/project2/sessionContainer.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef SESSIONCONTAINER_H -#define SESSIONCONTAINER_H - -#include "uuid.h" -#include "session.h" -#include - -class SessionContainer : public IntrusivePtrBase { - public: - SessionContainer(); - virtual ~SessionContainer() = 0; - - SessionPtr GetSession(UUID & sid); - - protected: - virtual SessionPtr getSession(UUID & sid) = 0; -}; -typedef boost::intrusive_ptr SessionContainerPtr; - -/// Base class to implement session container imlpementations -class SessionContainerLoader : public ComponentLoader { - public: - virtual SessionContainerPtr open() const = 0; -}; - -/// Helper implemention for specific container types -template -class SessionContainerLoaderImpl : public SessionContainerLoader { - public: - virtual SessionContainerPtr open() const - { - return new SCType(); - } -}; - -#endif - diff --git a/project2/sessionSetTask.cpp b/project2/sessionSetTask.cpp deleted file mode 100644 index 4ae344f..0000000 --- a/project2/sessionSetTask.cpp +++ /dev/null @@ -1,31 +0,0 @@ -#include -#include "xmlObjectLoader.h" -#include "sessionSetTask.h" -#include "appEngine.h" -#include "session.h" - -DECLARE_LOADER("sessionset", SessionSetTask); - -SessionSetTask::SessionSetTask(const xmlpp::Element * p) : - SourceObject(p), - Task(p), - key(p->get_attribute_value("key")), - value(p, "value") -{ -} - -SessionSetTask::~SessionSetTask() -{ -} - -void -SessionSetTask::loadComplete(const CommonObjects *) -{ -} - -void -SessionSetTask::execute() const -{ - ApplicationEngine::getCurrent()->session()->SetValue(key, value); -} - diff --git a/project2/sessionSetTask.h b/project2/sessionSetTask.h deleted file mode 100644 index f439768..0000000 --- a/project2/sessionSetTask.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef SESSIONSETTASK_H -#define SESSIONSETTASK_H - -#include -#include -#include -#include "sourceObject.h" -#include "xmlObjectLoader.h" -#include "task.h" -#include "variables.h" - -class CommonObjects; - -/// Project2 component to add/update a variable in the session -class SessionSetTask : public Task { - public: - SessionSetTask(const xmlpp::Element * p); - virtual ~SessionSetTask(); - virtual void loadComplete(const CommonObjects *); - void execute() const; - - const Glib::ustring key; - const Variable value; -}; - -#endif - - diff --git a/project2/sessionXml.cpp b/project2/sessionXml.cpp deleted file mode 100644 index c1e2158..0000000 --- a/project2/sessionXml.cpp +++ /dev/null @@ -1,184 +0,0 @@ -#include "sessionXml.h" -#include "uuid.h" -#include -#include -#include -#include -#include -#include -#include -#include - -/// Session implementation that stores its contents in an XML file on the local filesystem -class SessionXml : public Session { - public: - SessionXml(UUID & sid); - SessionXml(const xmlpp::Element *); - virtual ~SessionXml(); - - const VariableType & GetValue(const Glib::ustring & name) const; - Values GetValuesCopy() const; - void SetValue(const Glib::ustring & name, const VariableType & value); - void ClearValue(const Glib::ustring & name); - time_t ExpiryTime() const; - void ExpiryTime(time_t); - - const UUID sessionID; - - private: - Values vars; - time_t expires; - - friend class SessionContainerXml; -}; - -namespace po = boost::program_options; -class CustomSessionContainerLoaderXml : public SessionContainerLoaderImpl { - public: - CustomSessionContainerLoaderXml() : - opts("SessionXML options") - { - opts.add_options() - ("session.xml.path", po::value(&SessionContainerXml::xmlFile)->default_value("/tmp/project2sessions.xml"), - "Path of the XML file in which to store session information") - ; - } - po::options_description * - options() - { - return &opts; - } - - private: - po::options_description opts; -}; - -std::string SessionContainerXml::xmlFile; -DECLARE_CUSTOM_COMPONENT_LOADER("xml", SessionContainerXml, CustomSessionContainerLoaderXml, SessionContainerLoader); - -SessionContainerXml::SessionContainerXml() -{ -} - -SessionContainerXml::~SessionContainerXml() -{ - if (currentSession) { - xmlpp::DomParser parser; - xmlpp::Document * doc; - try { - parser.parse_file(xmlFile); - doc = parser.get_document(); - char xpath[200]; - snprintf(xpath, 200, "/sessions/session[@id='%s' or @expires < %lu]", - currentSession->sessionID.str().c_str(), time(NULL)); - xmlpp::NodeSet sess = doc->get_root_node()->find(xpath); - BOOST_FOREACH(xmlpp::Node * n, sess) { - n->get_parent()->remove_child(n); - } - } - catch (...) { - doc = new xmlpp::Document(); - doc->create_root_node("sessions"); - } - xmlpp::Element * sess = doc->get_root_node()->add_child("session"); - sess->set_attribute("id", currentSession->sessionID.str()); - sess->set_attribute("expires", boost::lexical_cast(currentSession->expires)); - BOOST_FOREACH(const SessionXml::Values::value_type & nvp, currentSession->vars) { - xmlpp::Element * v = sess->add_child("var"); - v->add_child_text(nvp.second); - v->set_attribute("name", nvp.first); - } - doc->write_to_file(xmlFile); - if (!parser) { - delete doc; - } - currentSession = NULL; - } -} - -SessionPtr -SessionContainerXml::getSession(UUID & sid) -{ - if (!currentSession || currentSession->sessionID != sid) { - try { - xmlpp::DomParser sessions(xmlFile); - char xpath[200]; - snprintf(xpath, 200, "/sessions/session[@id='%s' and @expires > %lu]", - sid.str().c_str(), time(NULL)); - xmlpp::NodeSet sess = sessions.get_document()->get_root_node()->find(xpath); - if (sess.size() == 1) { - currentSession = new SessionXml(dynamic_cast(sess[0])); - } - else { - currentSession = new SessionXml(sid); - } - } - catch (...) { - currentSession = new SessionXml(sid); - } - } - return currentSession; -} - -SessionXml::SessionXml(UUID & sid) : - sessionID(sid.is_nil() ? sid = UUID::generate_random() : sid) -{ -} - -SessionXml::SessionXml(const xmlpp::Element * p) : - sessionID(p->get_attribute_value("id")), - expires(boost::lexical_cast(p->get_attribute_value("expires"))) -{ - xmlpp::NodeSet xvars = p->find("var"); - BOOST_FOREACH(const xmlpp::Node * n, xvars) { - const xmlpp::Element * e = dynamic_cast(n); - if (e) { - vars[e->get_attribute_value("name")] = e->get_child_text() ? e->get_child_text()->get_content() : ""; - } - } -} - -SessionXml::~SessionXml() -{ -} - -void -SessionXml::ExpiryTime(time_t t) -{ - expires = t; -} - -time_t -SessionXml::ExpiryTime() const -{ - return expires; -} - -const VariableType & -SessionXml::GetValue(const Glib::ustring & name) const -{ - Values::const_iterator i = vars.find(name); - if (i == vars.end()) { - throw Session::VariableNotFound(name); - } - return i->second; -} - -void -SessionXml::SetValue(const Glib::ustring & name, const VariableType & value) -{ - vars[name] = value; -} - -void -SessionXml::ClearValue(const Glib::ustring & name) -{ - vars.erase(name); -} - -Session::Values -SessionXml::GetValuesCopy() const -{ - return vars; -} - diff --git a/project2/sessionXml.h b/project2/sessionXml.h deleted file mode 100644 index 9b5c3e1..0000000 --- a/project2/sessionXml.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef SESSIONXML_H -#define SESSIONXML_H - -#include "sessionContainer.h" -#include - -class SessionXml; -class SessionContainerXml : public SessionContainer { - public: - SessionContainerXml(); - ~SessionContainerXml(); - - protected: - SessionPtr getSession(UUID & sid); - typedef boost::intrusive_ptr SessionXmlPtr; - SessionXmlPtr currentSession; - - private: - // Configurables - static std::string xmlFile; - friend class CustomSessionContainerLoaderXml; -}; - -#endif diff --git a/project2/sourceObject.cpp b/project2/sourceObject.cpp deleted file mode 100644 index a5736ba..0000000 --- a/project2/sourceObject.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include "sourceObject.h" - -unsigned int SourceObject::loadOrder = 1; - -SourceObject::SourceObject(const xmlpp::Element * p) : - name(p ? p->get_attribute_value("name") : "anon"), - order(loadOrder++) -{ -} - -SourceObject::SourceObject(const std::string & n) : - name(n), - order(loadOrder++) -{ -} - -SourceObject::~SourceObject() -{ -} - diff --git a/project2/sourceObject.h b/project2/sourceObject.h deleted file mode 100644 index 3ebae2c..0000000 --- a/project2/sourceObject.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef SOURCEOBJECT_H -#define SOURCEOBJECT_H - -#include -#include -#include "intrusivePtrBase.h" - -class CommonObjects; -class SourceObject; -typedef boost::intrusive_ptr SourceObjectPtr; -/// Base class for all Project2 components that can be placed in a Project2 script -class SourceObject : public virtual IntrusivePtrBase { - public: - SourceObject(const xmlpp::Element * p); - SourceObject(const std::string & name); - virtual ~SourceObject() = 0; - - virtual void loadComplete(const CommonObjects *) = 0; - - const std::string name; - const unsigned int order; - private: - static unsigned int loadOrder; -}; - -#endif diff --git a/project2/sql-modODBC.cpp b/project2/sql-modODBC.cpp deleted file mode 100644 index ca57731..0000000 --- a/project2/sql-modODBC.cpp +++ /dev/null @@ -1,4 +0,0 @@ -#include "rdbmsDataSource.h" -#include "../libodbcpp/connection.h" -typedef ODBC::Connection ODBCConnection; -DECLARE_COMPONENT_LOADER("odbc", ODBCConnection, ConnectionLoader) diff --git a/project2/sql-modPQ.cpp b/project2/sql-modPQ.cpp deleted file mode 100644 index 499d8e7..0000000 --- a/project2/sql-modPQ.cpp +++ /dev/null @@ -1,4 +0,0 @@ -#include "rdbmsDataSource.h" -#include "../libpqpp/connection.h" -typedef PQ::Connection PQConnection; -DECLARE_COMPONENT_LOADER("postgresql", PQConnection, ConnectionLoader) diff --git a/project2/sql/Jamfile.jam b/project2/sql/Jamfile.jam new file mode 100644 index 0000000..b05fd34 --- /dev/null +++ b/project2/sql/Jamfile.jam @@ -0,0 +1,38 @@ +alias libxmlpp : : : : + "`pkg-config --cflags libxml++-2.6`" + "`pkg-config --libs libxml++-2.6`" ; + +explicit object sql-modODBC ; +obj sql-modODBC : + sql-modODBC.cpp : + ../../libodbcpp//odbcpp + libxmlpp + ../../libmisc + ../common + : : + ../../libodbcpp//odbcpp + ; + +explicit object sql-modPQ ; +obj sql-modPQ : + sql-modPQ.cpp : + ../../libpqpp//pqpp + libxmlpp + ../../libmisc + ../common + : : + ../../libpqpp//pqpp + ; + +lib p2sql : + sqlCheck.cpp sqlWriter.cpp sqlTask.cpp sqlMergeTask.cpp sqlRows.cpp sqlCache.cpp sqlVariableBinder.cpp tablepatch.cpp rdbmsDataSource.cpp + sqlHandleAsVariableType.cpp + ../../libdbpp//dbpp + : + yes:sql-modODBC + yes:sql-modPQ + libxmlpp + ../common//p2common + ../../libmisc + ; + diff --git a/project2/sql/connectionLoader.h b/project2/sql/connectionLoader.h new file mode 100644 index 0000000..841b425 --- /dev/null +++ b/project2/sql/connectionLoader.h @@ -0,0 +1,19 @@ +#include "xmlObjectLoader.h" +#include "../libdbpp/connection.h" + +/// Base class to implement DB connection type modules +class ConnectionLoader : public ComponentLoader { + public: + virtual DB::Connection * connect(const std::string & dsn) const = 0; +}; + +/// Helper implemention for specific DB types +template +class ConnectionLoaderImpl : public ConnectionLoader { + public: + virtual DB::Connection * connect(const std::string & dsn) const + { + return new DBType(dsn); + } +}; + diff --git a/project2/sql/rdbmsDataSource.cpp b/project2/sql/rdbmsDataSource.cpp new file mode 100644 index 0000000..dac6cb1 --- /dev/null +++ b/project2/sql/rdbmsDataSource.cpp @@ -0,0 +1,220 @@ +#include "rdbmsDataSource.h" +#include "connectionLoader.h" +#include +#include +#include "logger.h" +#include +#include + +SimpleMessageException(UnknownConnectionProvider); + +/// Specialized ElementLoader for instances of RdbmsDataSource; handles persistent DB connections +class RdbmsDataSourceLoader : public ElementLoaderImpl { + public: + void onIdle() + { + // Disconnect all cached database connections + RdbmsDataSource::dbhosts.clear(); + } + static bool isConnectionExpired(const RdbmsDataSource::DBHosts::value_type & con) + { + return con.second->isExpired(); + } + void onPeriodic() + { + // Disconnect expired database connections + RdbmsDataSource::DBHosts::iterator i; + while ((i = std::find_if(RdbmsDataSource::dbhosts.begin(), RdbmsDataSource::dbhosts.end(), isConnectionExpired)) != RdbmsDataSource::dbhosts.end()) { + RdbmsDataSource::dbhosts.erase(i); + } + } + void onIteration() + { + RdbmsDataSource::changedDSNs.clear(); + } +}; +DECLARE_CUSTOM_LOADER("rdbmsdatasource", RdbmsDataSourceLoader); + +RdbmsDataSource::DBHosts RdbmsDataSource::dbhosts; +RdbmsDataSource::FailedHosts RdbmsDataSource::failedhosts; +RdbmsDataSource::DSNSet RdbmsDataSource::changedDSNs; + +RdbmsDataSource::RdbmsDataSource(const xmlpp::Element * p) : + DataSource(p), + masterDsn(dynamic_cast(p->find("masterdsn").front())), + preferLocal(p->get_attribute_value("preferlocal") != "false") +{ + BOOST_FOREACH(const xmlpp::Node * node, p->find("readonly/dsn")) { + const xmlpp::Element * elem = dynamic_cast(node); + if (elem) { + roDSNs.insert(ReadonlyDSNs::value_type(elem->get_attribute_value("host"), elem)); + } + } +} + +RdbmsDataSource::~RdbmsDataSource() +{ +} + +void +RdbmsDataSource::loadComplete(const CommonObjects *) +{ +} + +const DB::Connection & +RdbmsDataSource::getWritable() const +{ + ConnectionPtr master = connectTo(masterDsn); + if (!master->txOpen) { + master->connection->beginTx(); + master->txOpen = true; + } + changedDSNs.insert(name); + return *master->connection; +} + +const DB::Connection & +RdbmsDataSource::getReadonly() const +{ + if (changedDSNs.find(name) != changedDSNs.end()) { + return *connectTo(masterDsn)->connection; + } + if (localhost.length() == 0 && preferLocal) { + struct utsname name; + if (uname(&name)) { + Logger()->messagef(LOG_WARNING, "%s: Unable to determine local host name (%d:%s)", + __PRETTY_FUNCTION__, errno, strerror(errno)); + localhost = "unknown"; + } + else { + localhost = name.nodename; + } + } + if (preferLocal) { + ReadonlyDSNs::const_iterator ro = roDSNs.find(localhost); + try { + if (ro == roDSNs.end()) { + Logger()->messagef(LOG_INFO, "%s: No database host matches local host name (%s) Will use master DSN", + __PRETTY_FUNCTION__, localhost.c_str()); + return *connectTo(masterDsn)->connection; + } + return *connectTo(ro->second)->connection; + } + catch (...) { + // Failed to connect to a preferred DB... carry on and try the others... + } + } + BOOST_FOREACH(ReadonlyDSNs::value_type db, roDSNs) { + try { + return *connectTo(db.second)->connection; + } + catch (...) { + } + } + return *connectTo(masterDsn)->connection; +} + +void +RdbmsDataSource::commit() +{ + DBHosts::const_iterator m = dbhosts.find(masterDsn); + if (m != dbhosts.end() && m->second->txOpen) { + m->second->connection->commitTx(); + m->second->txOpen = false; + } +} + +void +RdbmsDataSource::rollback() +{ + DBHosts::const_iterator m = dbhosts.find(masterDsn); + if (m != dbhosts.end() && m->second->txOpen) { + m->second->connection->rollbackTx(); + m->second->txOpen = false; + } + changedDSNs.erase(name); +} + +RdbmsDataSource::ConnectionPtr +RdbmsDataSource::connectTo(const ConnectionInfo & dsn) +{ + FailedHosts::iterator dbf = failedhosts.find(dsn); + if (dbf != failedhosts.end()) { + if (time(NULL) - 20 > dbf->second.FailureTime) { + failedhosts.erase(dbf); + } + else { + throw dbf->second; + } + } + DBHosts::const_iterator dbi = dbhosts.find(dsn); + if (dbi != dbhosts.end()) { + try { + dbi->second->connection->ping(); + dbi->second->touch(); + return dbi->second; + } + catch (...) { + // Connection in failed state + Logger()->messagef(LOG_DEBUG, "%s: Cached connection failed", __PRETTY_FUNCTION__); + } + } + + try { + ConnectionPtr db = ConnectionPtr(new RdbmsConnection(dsn.connect(), 300)); + dbhosts[dsn] = db; + db->touch(); + return db; + } + catch (const DB::ConnectionError & e) { + failedhosts.insert(FailedHosts::value_type(dsn, e)); + throw; + } +} + +RdbmsDataSource::RdbmsConnection::RdbmsConnection(const DB::Connection * con, time_t kat) : + connection(con), + txOpen(false), + lastUsedTime(0), + keepAliveTime(kat) +{ +} + +RdbmsDataSource::RdbmsConnection::~RdbmsConnection() +{ + connection->finish(); + delete connection; +} + +void +RdbmsDataSource::RdbmsConnection::touch() const +{ + time(&lastUsedTime); +} + +bool +RdbmsDataSource::RdbmsConnection::isExpired() const +{ + return (time(NULL) > lastUsedTime + keepAliveTime); +} + +RdbmsDataSource::ConnectionInfo::ConnectionInfo(const xmlpp::Element * n) +{ + BOOST_FOREACH(const xmlpp::Node * node, n->get_children()) { + typeId = LoaderBase::getLoader(node->get_name()); + dsn = dynamic_cast(node)->get_child_text()->get_content(); + } +} + +DB::Connection * +RdbmsDataSource::ConnectionInfo::connect() const +{ + return typeId->connect(dsn); +} + +bool +RdbmsDataSource::ConnectionInfo::operator<(const RdbmsDataSource::ConnectionInfo & other) const +{ + return ((typeId < other.typeId) || ((typeId == other.typeId) && (dsn < other.dsn))); +} + diff --git a/project2/sql/rdbmsDataSource.h b/project2/sql/rdbmsDataSource.h new file mode 100644 index 0000000..fdcfbe7 --- /dev/null +++ b/project2/sql/rdbmsDataSource.h @@ -0,0 +1,78 @@ +#ifndef RDBMSDATASOURCE_H +#define RDBMSDATASOURCE_H + +#include +#include +#include +#include +#include "dataSource.h" +#include "../libdbpp/connection.h" +#include "../libdbpp/error.h" +#include "xmlObjectLoader.h" + +class ConnectionLoader; + +/// Project2 component to provide access to transactional RDBMS data sources +class RdbmsDataSource : public DataSource { + public: + class RdbmsConnection { + public: + RdbmsConnection(const DB::Connection * connection, time_t kat); + ~RdbmsConnection(); + + void touch() const; + bool isExpired() const; + const DB::Connection * const connection; + bool txOpen; + + private: + mutable time_t lastUsedTime; + const time_t keepAliveTime; + }; + + class ConnectionInfo { + public: + ConnectionInfo(const xmlpp::Element *); + + DB::Connection * connect() const; + + bool operator<(const ConnectionInfo & o) const; + + private: + std::string dsn; + boost::shared_ptr typeId; + }; + + typedef boost::shared_ptr ConnectionPtr; + typedef std::map ReadonlyDSNs; // Map hostname to DSN string + typedef std::map DBHosts; // Map DSN strings to connections + typedef std::map FailedHosts; // Map DSN strings to failures + + RdbmsDataSource(const xmlpp::Element * p); + ~RdbmsDataSource(); + + const DB::Connection & getReadonly() const; + const DB::Connection & getWritable() const; + virtual void loadComplete(const CommonObjects *); + virtual void commit(); + virtual void rollback(); + + const ConnectionInfo masterDsn; + const bool preferLocal; + + protected: + static ConnectionPtr connectTo(const ConnectionInfo & dsn); + ReadonlyDSNs roDSNs; + + private: + mutable std::string localhost; + static DBHosts dbhosts; + static FailedHosts failedhosts; + typedef std::set DSNSet; + static DSNSet changedDSNs; + + friend class RdbmsDataSourceLoader; +}; + +#endif + diff --git a/project2/sql/sql-modODBC.cpp b/project2/sql/sql-modODBC.cpp new file mode 100644 index 0000000..1703cb6 --- /dev/null +++ b/project2/sql/sql-modODBC.cpp @@ -0,0 +1,4 @@ +#include "connectionLoader.h" +#include "../libodbcpp/connection.h" +typedef ODBC::Connection ODBCConnection; +DECLARE_COMPONENT_LOADER("odbc", ODBCConnection, ConnectionLoader) diff --git a/project2/sql/sql-modPQ.cpp b/project2/sql/sql-modPQ.cpp new file mode 100644 index 0000000..5991754 --- /dev/null +++ b/project2/sql/sql-modPQ.cpp @@ -0,0 +1,4 @@ +#include "connectionLoader.h" +#include "../libpqpp/connection.h" +typedef PQ::Connection PQConnection; +DECLARE_COMPONENT_LOADER("postgresql", PQConnection, ConnectionLoader) diff --git a/project2/sql/sqlCache.cpp b/project2/sql/sqlCache.cpp new file mode 100644 index 0000000..13bc23d --- /dev/null +++ b/project2/sql/sqlCache.cpp @@ -0,0 +1,300 @@ +#include "cache.h" +#include "sqlVariableBinder.h" +#include "sqlHandleAsVariableType.h" +#include "buffer.h" +#include "selectcommand.h" +#include "modifycommand.h" +#include "column.h" +#include "commonObjects.h" +#include "rdbmsDataSource.h" +#include "logger.h" +#include "xmlObjectLoader.h" +#include "iHaveParameters.h" +#include "rowSet.h" +#include +#include +#include + +typedef boost::shared_ptr SelectPtr; +typedef boost::shared_ptr ModifyPtr; + +class SqlCache : public Cache { + public: + SqlCache(const xmlpp::Element * p) : + Cache(p) + { + } + + void loadComplete(const CommonObjects * co) + { + db = co->dataSource(DataSource); + } + + static void appendKeyCols(Buffer * sql, unsigned int * off, const Glib::ustring & col) + { + if ((*off)++) { + sql->append(", "); + } + sql->append(col.c_str()); + } + + static void appendKeyBinds(Buffer * sql, unsigned int * off) + { + if ((*off)++) { + sql->append(", "); + } + sql->append("?"); + } + + static void appendKeyAnds(Buffer * sql, const Glib::ustring & col) + { + sql->appendf(" AND h.%s = ?", col.c_str()); + } + + static void bindKeyValues(DB::Command * cmd, unsigned int * offset, const VariableType & v) + { + boost::apply_visitor(SqlVariableBinder(cmd, (*offset)++), v); + } + + class SqlCacheRowSet : public RowSet { + public: + SqlCacheRowSet(SelectPtr r) : + RowSet(NULL), + s(r) { + } + void loadComplete(const CommonObjects *) { + } + class SqlCacheRowState : public RowState { + public: + SqlCacheRowState(const SqlCacheRowSet * s) : + sc(s) { + } + const Columns & getColumns() const { + return columns; + } + RowAttribute resolveAttr(const Glib::ustring & attrName) const { + return boost::bind(&SqlCacheRowState::getAttrCol, this, "p2attr_" + attrName); + } + private: + VariableType getAttrCol(const Glib::ustring & col) const { + HandleAsVariableType h; + (*sc->s)[col].apply(h); + return h.variable; + } + mutable Columns columns; + friend class SqlCacheRowSet; + const SqlCacheRowSet * sc; + }; + void execute(const Glib::ustring&, const RowProcessor * rp) const { + SqlCacheRowState ss(this); + HandleAsVariableType h; + do { + if (!(*s)["p2_cacheid"].isNull()) { + if (colCols.empty()) { + (*s)["p2_cacheid"].apply(h); + cacheId = h.variable; + unsigned int colNo = 0; + for (unsigned int c = 0; c < s->columnCount(); c++) { + const DB::Column & col = (*s)[c]; + if (!boost::algorithm::starts_with(col.name, "p2attr_") && + !boost::algorithm::starts_with(col.name, "p2_")) { + ss.columns.insert(new Column(colNo++, col.name)); + colCols.push_back(c); + } + } + ss.fields.resize(colCols.size()); + } + else { + (*s)["p2_cacheid"].apply(h); + if (cacheId != (int64_t)h.variable) { + break; + } + } + BOOST_FOREACH(const unsigned int & c, colCols) { + const DB::Column & col = (*s)[c]; + col.apply(h); + ss.fields[&c - &colCols.front()] = h.variable; + } + ss.process(rp); + } + } while (s->fetch()); + } + private: + SelectPtr s; + mutable std::vector colCols; + mutable int64_t cacheId; + }; + + RowSetCPtr getCachedRowSet(const Glib::ustring & n, const Glib::ustring & f, const IHaveParameters * ps) const + { + Buffer sql; + sql.appendf("SELECT r.* \ + FROM %s p, %s_%s_%s h LEFT OUTER JOIN %s_%s_%s_rows r \ + ON h.p2_cacheid = r.p2_cacheid \ + WHERE p.p2_time > ? \ + AND p.p2_cacheid = h.p2_cacheid", + HeaderTable.c_str(), + HeaderTable.c_str(), n.c_str(), f.c_str(), + HeaderTable.c_str(),n.c_str(), f.c_str()); + applyKeys(boost::bind(appendKeyAnds, &sql, _1), ps); + sql.appendf(" ORDER BY r.p2_cacheid DESC, r.p2_row"); + SelectPtr gh(db->getReadonly().newSelectCommand(sql)); + unsigned int offset = 0; + gh->bindParamT(offset++, time(NULL) - CacheLife); + applyKeys(boost::bind(bindKeyValues, gh.get(), &offset, _2), ps); + if (gh->fetch()) { + return new SqlCacheRowSet(gh); + } + return NULL; + } + + class SqlCachePresenter : public Presenter { + public: + SqlCachePresenter(const Glib::ustring & name, const Glib::ustring & filter, const RdbmsDataSource * d) : + depth(0), + row(1), + db(d), + n(name), + f(filter) { + } + void declareNamespace(const Glib::ustring &, const Glib::ustring &) const { } + void setNamespace(const Glib::ustring &, const Glib::ustring &) const { } + void pushSub(const Glib::ustring & name, const Glib::ustring &) const { + depth += 1; + if (depth == 2) { + col = name; + } + else if (depth == 1) { + } + } + void addAttr(const Glib::ustring & name, const Glib::ustring &, const VariableType & value) const { + attrs.insert(Values::value_type(name, value)); + } + void addText(const VariableType & value) const { + cols.insert(Values::value_type(col, value)); + } + void popSub() const { + if (depth == 2) { + col.clear(); + } + else if (depth == 1) { + Buffer sql; + sql.appendf("INSERT INTO %s_%s_%s_rows(p2_row", HeaderTable.c_str(), n.c_str(), f.c_str()); + BOOST_FOREACH(const Values::value_type & a, attrs) { + sql.appendf(", p2attr_%s", a.first.c_str()); + } + BOOST_FOREACH(const Values::value_type & v, cols) { + sql.appendf(", %s", v.first.c_str()); + } + sql.appendf(") VALUES(?"); + for (size_t x = attrs.size(); x > 0; x -= 1) { + sql.append(", ?"); + } + for (size_t x = cols.size(); x > 0; x -= 1) { + sql.append(", ?"); + } + sql.appendf(")"); + ModifyPtr m(db->getReadonly().newModifyCommand(sql)); + unsigned int offset = 0; + m->bindParamI(offset++, row++); + BOOST_FOREACH(const Values::value_type & a, attrs) { + boost::apply_visitor(SqlVariableBinder(m.get(), offset++), a.second); + } + BOOST_FOREACH(const Values::value_type & v, cols) { + boost::apply_visitor(SqlVariableBinder(m.get(), offset++), v.second); + } + m->execute(); + cols.clear(); + attrs.clear(); + } + depth -= 1; + } + private: + mutable unsigned int depth; + mutable unsigned int row; + const RdbmsDataSource * db; + mutable Glib::ustring col; + const Glib::ustring n, f; + typedef std::map Values; + mutable Values cols, attrs; + }; + + PresenterPtr openFor(const Glib::ustring & n, const Glib::ustring & f, const IHaveParameters * ps) + { + // Header + Buffer del; + del.appendf("INSERT INTO %s(p2_time) VALUES(?)", HeaderTable.c_str()); + ModifyPtr h = ModifyPtr(db->getReadonly().newModifyCommand(del)); + h->bindParamT(0, time(NULL)); + h->execute(); + // Record set header + Buffer sql; + sql.appendf("INSERT INTO %s_%s_%s(", HeaderTable.c_str(), n.c_str(), f.c_str()); + unsigned int offset = 0; + applyKeys(boost::bind(appendKeyCols, &sql, &offset, _1), ps); + sql.appendf(") VALUES("); + offset = 0; + applyKeys(boost::bind(appendKeyBinds, &sql, &offset), ps); + sql.appendf(")"); + ModifyPtr m(db->getReadonly().newModifyCommand(sql)); + offset = 0; + applyKeys(boost::bind(bindKeyValues, m.get(), &offset, _2), ps); + m->execute(); + return new SqlCachePresenter(n, f, db); + } + + void close(const Glib::ustring & , const Glib::ustring & , const IHaveParameters * ) + { + } + + private: + friend class CustomSqlCacheLoader; + const RdbmsDataSource * db; + static std::string DataSource; + static std::string HeaderTable; + static time_t CacheLife; +}; + +std::string SqlCache::DataSource; +std::string SqlCache::HeaderTable; +time_t SqlCache::CacheLife; + +namespace po = boost::program_options; +class CustomSqlCacheLoader : public ElementLoaderImpl { + public: + CustomSqlCacheLoader() : + opts("SQL Cache options") + { + opts.add_options() + ("cache.sql.datasource", po::value(&SqlCache::DataSource), + "The default datasource to connect to") + ("cache.sql.headertable", po::value(&SqlCache::HeaderTable)->default_value("p2cache"), + "The filename to store the data in") + ("cache.sql.life", po::value(&SqlCache::CacheLife)->default_value(3600), + "The age of cache entries after which they are removed (seconds)") + ; + } + + po::options_description * options() + { + return &opts; + } + + void onIdle() + { + if (!SqlCache::DataSource.empty()) { + boost::intrusive_ptr co = new CommonObjects(); + const RdbmsDataSource * db = co->dataSource(SqlCache::DataSource); + Buffer del; + del.appendf("DELETE FROM %s WHERE p2_time < ?", SqlCache::HeaderTable.c_str()); + ModifyPtr m(db->getReadonly().newModifyCommand(del)); + m->bindParamT(0, time(NULL) - SqlCache::CacheLife); + m->execute(); + } + } + + private: + po::options_description opts; +}; +DECLARE_CUSTOM_LOADER("sqlcache", CustomSqlCacheLoader); + diff --git a/project2/sql/sqlCheck.cpp b/project2/sql/sqlCheck.cpp new file mode 100644 index 0000000..d86eb3b --- /dev/null +++ b/project2/sql/sqlCheck.cpp @@ -0,0 +1,100 @@ +#include "sqlCheck.h" +#include "xmlObjectLoader.h" +#include "selectcommand.h" +#include "column.h" +#include "rdbmsDataSource.h" +#include "commonObjects.h" +#include "sqlVariableBinder.h" +#include +#include + +DECLARE_LOADER("sqlcheck", SqlCheck); + +class CantCompareNulls : public std::exception { }; + +SqlCheck::SqlCheck(const xmlpp::Element * p) : + ParamChecker(p), + dataSource(p, "datasource"), + filter(p, "filter", false, ""), + testOp(p, "testOp", false, "=="), + testValue(p, "testValue"), + sqlCommand(dynamic_cast(p->get_children("sql").front())) +{ +} + +SqlCheck::~SqlCheck() +{ +} + +void +SqlCheck::loadComplete(const CommonObjects * co) +{ + db = co->dataSource(dataSource()); +} + +class HandleDoCompare : public DB::HandleField { + public: + HandleDoCompare(const VariableType & tV, const std::string & tO) : + retVal(false), + testValue(tV), + testOp(tO) { + } + void null() { + throw CantCompareNulls(); + } + void string(const char *c , size_t l) { + doTest(Glib::ustring(c, c + l)); + } + void integer(int64_t val) { + doTest(val); + } + void floatingpoint(double val) { + doTest(val); + } + void timestamp(const struct tm & val) { + doTest(boost::posix_time::ptime_from_tm(val)); + } + bool operator()() const { + return retVal; + } + private: + template + void doTest(const TV & val) { + TV tv = testValue; + if ((testOp == "==" || testOp == "=") && val == tv) { + retVal = true; + } + else if (testOp == "<" && val < tv) { + retVal = true; + } + else if (testOp == ">" && val > tv) { + retVal = true; + } + else if (testOp == "!=" && val != tv) { + retVal = true; + } + else if ((testOp == "<=" || testOp == "=<") && val <= tv) { + retVal = true; + } + else if ((testOp == ">=" || testOp == "=>") && val >= tv) { + retVal = true; + } + } + bool retVal; + const VariableType & testValue; + std::string testOp; +}; +bool +SqlCheck::performCheck() const +{ + boost::shared_ptr query = boost::shared_ptr( + db->getWritable().newSelectCommand(sqlCommand.getSqlFor(filter()))); + unsigned int offset = 0; + sqlCommand.bindParams(query.get(), offset); + HandleDoCompare h(testValue, testOp()); + while (query->fetch()) { + (*query)[0].apply(h); + } + return h(); +} + diff --git a/project2/sql/sqlCheck.h b/project2/sql/sqlCheck.h new file mode 100644 index 0000000..c9933d7 --- /dev/null +++ b/project2/sql/sqlCheck.h @@ -0,0 +1,29 @@ +#ifndef SQLCHECK_H +#define SQLCHECK_H + +#include "paramChecker.h" +#include "sqlWriter.h" + +namespace DB { class SelectCommand; } +class RdbmsDataSource; + +/// Project2 component to check the value of a variable against an RDBMS data source +class SqlCheck : public ParamChecker { + public: + SqlCheck(const xmlpp::Element * p); + virtual ~SqlCheck(); + + virtual void loadComplete(const CommonObjects *); + bool performCheck() const; + + const Variable dataSource; + const Variable filter; + const Variable testOp; + const Variable testValue; + + private: + const DynamicSql::SqlCommand sqlCommand; + const RdbmsDataSource * db; +}; + +#endif diff --git a/project2/sql/sqlHandleAsVariableType.cpp b/project2/sql/sqlHandleAsVariableType.cpp new file mode 100644 index 0000000..f084a14 --- /dev/null +++ b/project2/sql/sqlHandleAsVariableType.cpp @@ -0,0 +1,19 @@ +#include "sqlHandleAsVariableType.h" +#include + +void HandleAsVariableType::null() { + variable = Null(); +} +void HandleAsVariableType::string(const char * c, size_t l) { + variable = Glib::ustring(c, c + l); +} +void HandleAsVariableType::integer(int64_t i) { + variable = i; +} +void HandleAsVariableType::floatingpoint(double d) { + variable = d; +} +void HandleAsVariableType::timestamp(const struct tm & t) { + variable = boost::posix_time::ptime(boost::posix_time::ptime_from_tm(t)); +} + diff --git a/project2/sql/sqlHandleAsVariableType.h b/project2/sql/sqlHandleAsVariableType.h new file mode 100644 index 0000000..c874b7c --- /dev/null +++ b/project2/sql/sqlHandleAsVariableType.h @@ -0,0 +1,18 @@ +#ifndef SQLHANDLEASVARIABLETYPE +#define SQLHANDLEASVARIABLETYPE + +#include "column.h" +#include "variables.h" + +class HandleAsVariableType : public DB::HandleField { + public: + void null(); + void string(const char * c, size_t l); + void integer(int64_t i); + void floatingpoint(double d); + void timestamp(const struct tm & t); + VariableType variable; +}; + +#endif + diff --git a/project2/sql/sqlMergeTask.cpp b/project2/sql/sqlMergeTask.cpp new file mode 100644 index 0000000..09657f8 --- /dev/null +++ b/project2/sql/sqlMergeTask.cpp @@ -0,0 +1,329 @@ +#include "sqlMergeTask.h" +#include "columns.h" +#include "commonObjects.h" +#include "rdbmsDataSource.h" +#include "exceptions.h" +#include "sqlVariableBinder.h" +#include "xmlObjectLoader.h" +#include +#include +#include +#include +#include +#include +#include + +bool SqlMergeTask::defaultUseTempTable = true; +static void attach(boost::intrusive_ptr i, DB::ModifyCommand * insert); + +class SqlMergeInsert; +typedef boost::intrusive_ptr SqlMergeInsertPtr; +/// Project2 component insert custom constructed records during an SQL Merge task +class SqlMergeInsert : IHaveParameters, public Task { + public: + SqlMergeInsert(const xmlpp::Element * p) : + SourceObject(p), + IHaveParameters(p), + Task(p) { + } + void loadComplete(const CommonObjects*) { + } + void execute() const { + unsigned int col = 0; + BOOST_FOREACH(const Parameters::value_type & v, parameters) { + boost::apply_visitor(SqlVariableBinder(insert, col++), v.second); + } + insert->execute(); + } + private: + friend void attach(SqlMergeInsertPtr i, DB::ModifyCommand * insert); + DB::ModifyCommand * insert; +}; + +DECLARE_LOADER("sqlmerge", SqlMergeTask); +DECLARE_LOADER("sqlmergeinsert", SqlMergeInsert); + +// Conversion logic +SqlMergeTask::SqlMergeTask(const xmlpp::Element * p) : + SourceObject(p), + Task(p), + updateWhere(p, "updatewhere", false), + patchOrder(p->get_attribute_value("patchorder")), + earlyKeys(p->get_attribute_value("earlykeys") == "yes"), + useView(p->get_attribute_value("useview") == "yes"), + tempTableCreated(false), + insCmd(NULL), + destdb(NULL), + dataSource(p, "datasource"), + dtable(p->get_attribute_value("targettable")), + dtablet(stringf("tmp_%s_%d", dtable.c_str(), getpid())) +{ + LoaderBase loader(true); + loader.supportedStorers.insert(Storer::into(&sources)); + loader.collectAll(p, true); + + if (!sources.empty() && useView) { + throw NotSupported("useview not supported with iterate fillers"); + } + + BOOST_FOREACH(xmlpp::Node * psi, p->find("columns/column")) { + xmlpp::Element * e = static_cast(psi); + TargetColumnPtr tcp(new TargetColumn(e->get_child_text()->get_content())); + tcp->maptable = e->get_attribute_value("maptable"); + if (!tcp->maptable.empty()) { + if (useView) { + throw NotSupported("useview not supported with mapped columns"); + } + tcp->mapcolumn = e->get_attribute_value("mapcolumn"); + } + cols.insert(tcp); + } + BOOST_FOREACH(xmlpp::Node * psi, p->find("columns/column[@key='true']")) { + keys.insert(static_cast(psi)->get_child_text()->get_content()); + } + BOOST_FOREACH(xmlpp::Node * psi, p->find("sql")) { + sqls.push_back(static_cast(psi)->get_child_text()->get_content()); + } +} + +SqlMergeTask::~SqlMergeTask() +{ + delete insCmd; +} + +void +SqlMergeTask::loadComplete(const CommonObjects * co) +{ + destdb = &co->dataSource(dataSource())->getWritable(); + insCmd = insertCommand(); + BOOST_FOREACH(const Sources::value_type & i, sources) { + attach(i, insCmd); + } +} + +SqlMergeTask::TargetColumn::TargetColumn(const Column & c) : + column(c), + mapcolumn(c) +{ +} + +bool +SqlMergeTask::TargetColumn::Sort::operator()(const TargetColumnPtr & a, const TargetColumnPtr & b) const +{ + return a->column < b->column; +} + +void +SqlMergeTask::execute() const +{ + createTempTable(); + if (earlyKeys) { + createTempKey(); + copyToTempTable(); + } + else { + copyToTempTable(); + createTempKey(); + } + std::set colNames; + BOOST_FOREACH(const TargetColumnPtr & c, cols) { + colNames.insert(c->column); + } + TablePatch tp(*destdb, dtablet, dtable, colNames); + BOOST_FOREACH(const Keys::value_type & k, keys) { + tp.addKey(k); + } + tp.patch(updateWhere(), patchOrder.c_str()); + dropTempTable(); +} + +void +SqlMergeTask::createTempTable() const +{ + if (useView) { + DB::ModifyCommand * cv = destdb->newModifyCommand(stringf( + "CREATE VIEW %s AS %s", + dtablet.c_str(), + boost::algorithm::join(sqls, " UNION ").c_str())); + cv->execute(); + delete cv; + } + else { + DB::ModifyCommand * ctt = destdb->newModifyCommand(stringf( + "CREATE TEMPORARY TABLE %s AS SELECT * FROM %s WHERE 0=1", + dtablet.c_str(), + dtable.c_str())); + ctt->execute(); + delete ctt; + BOOST_FOREACH(Columns::value_type c, cols) { + if (!c->maptable.empty()) { + DB::ModifyCommand * at = destdb->newModifyCommand(stringf( + "ALTER TABLE %s ADD COLUMN %s VARCHAR(1000)", + dtablet.c_str(), + c->mapcolumn.c_str())); + at->execute(); + delete at; + } + } + } + tempTableCreated = true; +} +void +SqlMergeTask::dropTempTable() const +{ + if (tempTableCreated) { + DB::ModifyCommand * d; + if (useView) { + d = destdb->newModifyCommand("DROP VIEW " + dtablet); + } + else { + d = destdb->newModifyCommand("DROP TABLE " + dtablet); + } + d->execute(); + delete d; + } +} +void +SqlMergeTask::createTempKey() const +{ + if (useView) return; + /* Primary key */ + Buffer idx; + idx.appendf("ALTER TABLE %s ADD CONSTRAINT pk_%s PRIMARY KEY(%s)", + dtablet.c_str(), dtablet.c_str(), + boost::algorithm::join(keys, ", ").c_str()); + DB::ModifyCommand * at = destdb->newModifyCommand(idx); + at->execute(); + delete at; + /* Indexes */ + int n = 0; + BOOST_FOREACH(const Keys::value_type & i, indexes) { + DB::ModifyCommand * ci = destdb->newModifyCommand(stringf( + "CREATE INDEX idx_%s_%d ON %s(%s)", + dtablet.c_str(), n, dtablet.c_str(), i.c_str())); + ci->execute(); + delete ci; + n += 1; + } +} +DB::ModifyCommand * +SqlMergeTask::insertCommand() const +{ + Buffer ins; + ins.appendf("INSERT INTO %s(", dtablet.c_str()); + foreach(Columns::const_iterator, cols, c) { + if (c != cols.begin()) { + ins.append(", "); + } + ins.append((*c)->mapcolumn); + } + ins.append(") VALUES ("); + foreach(Columns::const_iterator, cols, c) { + if (c == cols.begin()) { + ins.append("?"); + } + else { + ins.append(", ?"); + } + } + ins.append(")"); + return destdb->newModifyCommand(ins); +} + +class Populate : public NoOutputExecute { + public: + Populate(DB::ModifyCommand * c) : + SourceObject(__FUNCTION__), + NoOutputExecute(__FUNCTION__), + cmd(c) + { + } + virtual void loadComplete(const CommonObjects *) + { + } + void execute() const + { + unsigned int idx = 0; + RowState::Stack().back()->foreachColumn(boost::bind(&Populate::bind, this, boost::ref(idx), _3)); + cmd->execute(); + } + private: + void bind(unsigned int & idx, const VariableType & value) const + { + boost::apply_visitor(SqlVariableBinder(cmd, idx++), value); + } + DB::ModifyCommand * cmd; +}; +typedef boost::intrusive_ptr PopulatePtr; + +void +attach(SqlMergeInsertPtr i, DB::ModifyCommand * insert) +{ + if (i) { + i->insert = insert; + } +} + +static void +attach(boost::intrusive_ptr i, DB::ModifyCommand * insert) +{ + if (!i) { + return; + } + if (i->normal.empty()) { + i->normal.push_back(new Populate(insert)); + } + else { + BOOST_FOREACH(const IHaveSubTasks::Tasks::value_type & n, i->normal) { + attach(boost::dynamic_pointer_cast(n), insert); + attach(boost::dynamic_pointer_cast(n), insert); + } + } +} + +void +SqlMergeTask::copyToTempTable() const +{ + if (useView) return; + BOOST_FOREACH(const Sources::value_type & i, sources) { + i->execute(); + } + BOOST_FOREACH(const std::string & sql, sqls) { + Buffer ins; + ins.appendf("INSERT INTO %s(", dtablet.c_str()); + foreach(Columns::const_iterator, cols, c) { + if (c != cols.begin()) { + ins.append(", "); + } + ins.append((*c)->column); + } + ins.append(") SELECT "); + foreach(Columns::const_iterator, cols, c) { + if (c != cols.begin()) { + ins.append(", "); + } + ins.append((*c)->column); + } + ins.appendf(" FROM (%s) tmp_src", sql.c_str()); + DB::ModifyCommand * cttt = destdb->newModifyCommand(ins); + cttt->execute(); + delete cttt; + } + BOOST_FOREACH(Columns::value_type c, cols) { + if (!c->maptable.empty()) { + DB::ModifyCommand * utt = destdb->newModifyCommand( + stringf( + "UPDATE %s d SET %s = (SELECT m.%s FROM %s m WHERE m.%s = d.%s) WHERE %s IS NULL", + dtablet.c_str(), + c->column.c_str(), + c->column.c_str(), + c->maptable.c_str(), + c->mapcolumn.c_str(), + c->mapcolumn.c_str(), + c->column.c_str())); + utt->execute(); + delete utt; + } + } +} + diff --git a/project2/sql/sqlMergeTask.h b/project2/sql/sqlMergeTask.h new file mode 100644 index 0000000..c9e206c --- /dev/null +++ b/project2/sql/sqlMergeTask.h @@ -0,0 +1,79 @@ +#ifndef SQLMERGETASK_H +#define SQLMERGETASK_H + +#include +#include +#include +#include +#include "tablepatch.h" +#include "task.h" +#include "iterate.h" +#include "variables.h" +#include +#include +#include +#include + +/// Project2 component merge arbitrary data into an RDBMS table +class SqlMergeTask : public Task { + public: + typedef std::string Table; + typedef std::string Column; + class TargetColumn; + typedef boost::intrusive_ptr TargetColumnPtr; + class TargetColumn : public virtual IntrusivePtrBase { + public: + class Sort { + public: + bool operator()(const TargetColumnPtr & a, const TargetColumnPtr & b) const; + }; + TargetColumn(const Column &); + + Column column; + Column mapcolumn; + Table maptable; + + }; + typedef std::set Columns; + + typedef std::set Keys; + + SqlMergeTask(const xmlpp::Element * p); + virtual ~SqlMergeTask(); + + virtual void loadComplete(const CommonObjects *); + void execute() const; + Columns cols; + Keys keys; + Keys indexes; + const Variable updateWhere; + const std::string patchOrder; + const bool earlyKeys; + const bool useView; + + private: + virtual void copyToTempTable() const; + void createTempTable() const; + void dropTempTable() const; + void createTempKey() const; + + mutable bool tempTableCreated; + typedef ANONSTORAGEOF(Iterate) Sources; + Sources sources; + std::list sqls; + protected: + DB::ModifyCommand * insertCommand() const; + DB::ModifyCommand * insCmd; + + public: + const DB::Connection * destdb; + const Variable dataSource; + const Table dtable; + const Table dtablet; + + static unsigned int defaultVerbosity; + static bool defaultUseTempTable; +}; + +#endif + diff --git a/project2/sql/sqlRows.cpp b/project2/sql/sqlRows.cpp new file mode 100644 index 0000000..6e506d7 --- /dev/null +++ b/project2/sql/sqlRows.cpp @@ -0,0 +1,69 @@ +#include "sqlRows.h" +#include "sqlHandleAsVariableType.h" +#include "rowProcessor.h" +#include "xml.h" +#include "selectcommand.h" +#include "rdbmsDataSource.h" +#include "column.h" +#include +#include "xmlObjectLoader.h" +#include "commonObjects.h" +#include +#include + +DECLARE_LOADER("sqlrows", SqlRows); + +SqlRows::SqlRows(const xmlpp::Element * p) : + RowSet(p), + dataSource(p, "datasource"), + sqlCommand(dynamic_cast(p->get_children("sql").front())), + db(NULL) +{ +} + +SqlRows::~SqlRows() +{ +} + +void +SqlRows::loadComplete(const CommonObjects * co) +{ + db = co->dataSource(dataSource()); +} + +SqlRows::SqlState::SqlState(SelectPtr s) : + query(s) +{ +} + +const Columns & +SqlRows::SqlState::getColumns() const +{ + if (columns.empty()) { + for (unsigned int c = 0; c < query->columnCount(); c++) { + columns.insert(new Column(c, (*query)[c].name)); + } + } + return columns; +} + +void +SqlRows::execute(const Glib::ustring & filter, const RowProcessor * rp) const +{ + unsigned int offset = 0; + SqlState ss(SelectPtr(db->getReadonly().newSelectCommand(sqlCommand.getSqlFor(filter)))); + sqlCommand.bindParams(ss.query.get(), offset); + while (ss.query->fetch()) { + HandleAsVariableType h; + if (ss.fields.empty()) { + ss.fields.resize(ss.query->columnCount()); + } + for (unsigned int c = 0; c < ss.query->columnCount(); c++) { + const DB::Column & col = (*ss.query)[c]; + col.apply(h); + ss.fields[c] = h.variable; + } + ss.process(rp); + } +} + diff --git a/project2/sql/sqlRows.h b/project2/sql/sqlRows.h new file mode 100644 index 0000000..5614fa1 --- /dev/null +++ b/project2/sql/sqlRows.h @@ -0,0 +1,40 @@ +#ifndef SQLROWS_H +#define SQLROWS_H + +#include +#include +#include +#include "selectcommand.h" +#include "iHaveParameters.h" +#include "rowSet.h" +#include "sqlWriter.h" + +class RdbmsDataSource; + +/// Project2 component to create a row set based on an SQL SELECT statement issued against an RDBMS data source +class SqlRows : public RowSet { + public: + SqlRows(const xmlpp::Element * p); + ~SqlRows(); + + void execute(const Glib::ustring &, const RowProcessor *) const; + virtual void loadComplete(const CommonObjects *); + + const Variable dataSource; + + private: + const DynamicSql::SqlCommand sqlCommand; + typedef boost::shared_ptr SelectPtr; + class SqlState : public RowState { + public: + SqlState(SelectPtr query); + const Columns & getColumns() const; + SelectPtr query; + mutable Columns columns; + friend class SqlRows; + }; + const RdbmsDataSource * db; +}; + +#endif + diff --git a/project2/sql/sqlTask.cpp b/project2/sql/sqlTask.cpp new file mode 100644 index 0000000..3a1d334 --- /dev/null +++ b/project2/sql/sqlTask.cpp @@ -0,0 +1,70 @@ +#include "sqlTask.h" +#include +#include "xmlObjectLoader.h" +#include "modifycommand.h" +#include "rdbmsDataSource.h" +#include "commonObjects.h" +#include "sqlVariableBinder.h" + +DECLARE_LOADER("sqltask", SqlTask); +StaticMessageException(RunOnNotSpecified, "runon attribute must be specified"); + +class SqlIfChangesStorer : public StorerBase { + public: + SqlIfChangesStorer(Map c, Map nc) : + changes(c), + noChanges(nc) + { + } + bool insert(const xmlpp::Element * p, NoOutputExecutePtr O) { + xmlpp::Attribute * runon = p->get_attribute("runon"); + if (!runon) { + throw RunOnNotSpecified(); + } + ((runon->get_value() == "changes") ? changes : noChanges)->push_back(O); + return true; + } + Map changes, noChanges; +}; + +SqlTask::SqlTask(const xmlpp::Element * p) : + SourceObject(p), + Task(p), + dataSource(p, "datasource"), + filter(p, "filter", false, ""), + sqlCommand(dynamic_cast(p->get_children("sql").front())) +{ + LoaderBase loader(true); + loader.supportedStorers.insert(new SqlIfChangesStorer(&changesNOEs, &noChangesNOEs)); + loader.collectAll(p, true, IgnoreUnsupported); +} + +SqlTask::~SqlTask() +{ +} + +void +SqlTask::loadComplete(const CommonObjects * co) +{ + db = co->dataSource(dataSource()); +} + +void +SqlTask::execute() const +{ + boost::shared_ptr modify = boost::shared_ptr( + db->getWritable().newModifyCommand(sqlCommand.getSqlFor(filter()))); + unsigned int offset = 0; + sqlCommand.bindParams(modify.get(), offset); + if (modify->execute() == 0) { + BOOST_FOREACH(const SubNOEs::value_type & sq, noChangesNOEs) { + sq->execute(); + } + } + else { + BOOST_FOREACH(const SubNOEs::value_type & sq, changesNOEs) { + sq->execute(); + } + } +} + diff --git a/project2/sql/sqlTask.h b/project2/sql/sqlTask.h new file mode 100644 index 0000000..384b000 --- /dev/null +++ b/project2/sql/sqlTask.h @@ -0,0 +1,36 @@ +#ifndef SQLTASK_H +#define SQLTASK_H + +#include +#include +#include +#include "task.h" +#include "variables.h" +#include "sqlWriter.h" + +namespace DB { class ModifyCommand; } +class RdbmsDataSource; + +/// Project2 component to execute a modifying SQL statement against an RDBMS data source +class SqlTask : public Task { + public: + SqlTask(const xmlpp::Element * p); + virtual ~SqlTask(); + virtual void loadComplete(const CommonObjects *); + virtual void execute() const; + + const Variable dataSource; + const Variable filter; + + typedef ANONORDEREDSTORAGEOF(NoOutputExecute) SubNOEs; + SubNOEs changesNOEs; + SubNOEs noChangesNOEs; + + protected: + const DynamicSql::SqlCommand sqlCommand; + const RdbmsDataSource * db; +}; + +#endif + + diff --git a/project2/sql/sqlVariableBinder.cpp b/project2/sql/sqlVariableBinder.cpp new file mode 100644 index 0000000..23c24f2 --- /dev/null +++ b/project2/sql/sqlVariableBinder.cpp @@ -0,0 +1,77 @@ +#include "sqlVariableBinder.h" +#include "command.h" +#include "variables.h" +#include + +SqlVariableBinder::SqlVariableBinder(DB::Command * c, unsigned int i) : + cmd(c), + idx(i) +{ +} +void +SqlVariableBinder::operator()(const Null &) const +{ + cmd->bindNull(idx); +} +void +SqlVariableBinder::operator()(const Glib::ustring & i) const +{ + cmd->bindParamS(idx, i); +} +void +SqlVariableBinder::operator()(const long long unsigned int & i) const +{ + cmd->bindParamI(idx, i); +} +void +SqlVariableBinder::operator()(const long unsigned int & i) const +{ + cmd->bindParamI(idx, i); +} +void +SqlVariableBinder::operator()(const unsigned int & i) const +{ + cmd->bindParamI(idx, i); +} +void +SqlVariableBinder::operator()(const short unsigned int & i) const +{ + cmd->bindParamI(idx, i); +} +void +SqlVariableBinder::operator()(const long long int & i) const +{ + cmd->bindParamI(idx, i); +} +void +SqlVariableBinder::operator()(const long int & i) const +{ + cmd->bindParamI(idx, i); +} +void +SqlVariableBinder::operator()(const int & i) const +{ + cmd->bindParamI(idx, i); +} +void +SqlVariableBinder::operator()(const short int & i) const +{ + cmd->bindParamI(idx, i); +} +void +SqlVariableBinder::operator()(const double & i) const +{ + cmd->bindParamF(idx, i); +} +void +SqlVariableBinder::operator()(const float & i) const +{ + cmd->bindParamF(idx, i); +} +void +SqlVariableBinder::operator()(const boost::posix_time::ptime & i) const +{ + struct tm tm(boost::posix_time::to_tm(i)); + cmd->bindParamT(idx, &tm); +} + diff --git a/project2/sql/sqlVariableBinder.h b/project2/sql/sqlVariableBinder.h new file mode 100644 index 0000000..df3879a --- /dev/null +++ b/project2/sql/sqlVariableBinder.h @@ -0,0 +1,36 @@ +#ifndef SQLVARIABLEBINDER_H +#define SQLVARIABLEBINDER_H + +#include +#include +#include +#include + +namespace DB { + class Command; +} +class Null; +class SqlVariableBinder : public boost::static_visitor<> { + public: + SqlVariableBinder(DB::Command * c, unsigned int i); + void operator()(const Null & i) const; + void operator()(const Glib::ustring & i) const; + void operator()(const long long unsigned int & i) const; + void operator()(const long unsigned int & i) const; + void operator()(const unsigned int & i) const; + void operator()(const short unsigned int & i) const; + void operator()(const long long int & i) const; + void operator()(const long int & i) const; + void operator()(const int & i) const; + void operator()(const short int & i) const; + void operator()(const double & i) const; + void operator()(const float & i) const; + void operator()(const boost::posix_time::ptime & i) const; + + private: + DB::Command * cmd; + unsigned int idx; +}; + +#endif + diff --git a/project2/sql/sqlWriter.cpp b/project2/sql/sqlWriter.cpp new file mode 100644 index 0000000..88d9801 --- /dev/null +++ b/project2/sql/sqlWriter.cpp @@ -0,0 +1,131 @@ +#include "sqlWriter.h" +#include +#include "sqlVariableBinder.h" + +DynamicSql::SqlWriter::SqlWriter() +{ +} + +DynamicSql::SqlWriter::~SqlWriter() +{ +} + +DynamicSql::SqlCommand::SqlCommand(const xmlpp::Element * N) +{ + BOOST_FOREACH(xmlpp::Node * n, N->get_children()) { + const xmlpp::TextNode * t = dynamic_cast(n); + if (t) { + writers.push_back(new SqlText(t)); + } + const xmlpp::Element * e = dynamic_cast(n); + if (e) { + if (e->get_name() == "filter") { + SqlFilterPtr f = new SqlFilter(e); + writers.push_back(f); + filters.insert(Filters::value_type(f->name, f)); + } + else if (e->get_name() == "param") { + writers.push_back(new SqlParameter(e)); + } + } + } +} + +Glib::ustring +DynamicSql::SqlCommand::getSqlFor(const Glib::ustring & f) const +{ + BOOST_FOREACH(const SqlCommand::Filters::value_type & filter, filters) { + filter.second->active = (filter.second->name == f); + } + Glib::ustring sql; + writeSql(sql); + return sql; +} + +void +DynamicSql::SqlCommand::writeSql(Glib::ustring & sql) const +{ + BOOST_FOREACH(const SqlWriterPtr & w, writers) { + w->writeSql(sql); + } +} + +void +DynamicSql::SqlCommand::bindParams(DB::Command * cmd, unsigned int & offset) const +{ + BOOST_FOREACH(const SqlWriterPtr & w, writers) { + w->bindParams(cmd, offset); + } +} + +DynamicSql::SqlFilter::SqlFilter(const xmlpp::Element * N) : + name(N->get_attribute_value("name")), + active(false) +{ + BOOST_FOREACH(xmlpp::Node * n, N->get_children()) { + const xmlpp::TextNode * t = dynamic_cast(n); + if (t) { + writers.push_back(new SqlText(t)); + } + const xmlpp::Element * e = dynamic_cast(n); + if (e) { + if (e->get_name() == "param") { + writers.push_back(new SqlParameter(e)); + } + } + } +} + +void +DynamicSql::SqlFilter::writeSql(Glib::ustring & sql) const +{ + if (active) { + BOOST_FOREACH(const SqlWriterPtr & w, writers) { + w->writeSql(sql); + } + } +} + +void +DynamicSql::SqlFilter::bindParams(DB::Command * cmd, unsigned int & offset) const +{ + if (active) { + BOOST_FOREACH(const SqlWriterPtr & w, writers) { + w->bindParams(cmd, offset); + } + } +} + +DynamicSql::SqlParameter::SqlParameter(const xmlpp::Element * n) : + Variable(n, boost::optional("local")) +{ +} + +void +DynamicSql::SqlParameter::writeSql(Glib::ustring & sql) const +{ + sql.append("?"); +} + +void +DynamicSql::SqlParameter::bindParams(DB::Command * cmd, unsigned int & offset) const +{ + boost::apply_visitor(SqlVariableBinder(cmd, offset++), (*this)); +} + +DynamicSql::SqlText::SqlText(const xmlpp::TextNode * n) : + text(n->get_content()) +{ +} + +void +DynamicSql::SqlText::writeSql(Glib::ustring & sql) const +{ + sql.append(text); +} + +void +DynamicSql::SqlText::bindParams(DB::Command *, unsigned int &) const +{ +} + diff --git a/project2/sql/sqlWriter.h b/project2/sql/sqlWriter.h new file mode 100644 index 0000000..7693e19 --- /dev/null +++ b/project2/sql/sqlWriter.h @@ -0,0 +1,63 @@ +#ifndef SQLWRITER_H +#define SQLWRITER_H + +#include +#include +#include +#include +#include +#include +#include "variables.h" + +namespace DynamicSql { + class SqlWriter; + typedef boost::intrusive_ptr SqlWriterPtr; + typedef std::list Writers; + class SqlWriter : public IntrusivePtrBase { + public: + SqlWriter(); + virtual ~SqlWriter(); + virtual void writeSql(Glib::ustring & sql) const = 0; + virtual void bindParams(DB::Command *, unsigned int & offset) const = 0; + }; + class SqlText : public SqlWriter { + public: + SqlText(const xmlpp::TextNode *); + virtual void writeSql(Glib::ustring & sql) const; + virtual void bindParams(DB::Command *, unsigned int & offset) const; + + const Glib::ustring text; + }; + class SqlParameter : public SqlWriter, Variable { + public: + SqlParameter(const xmlpp::Element *); + virtual void writeSql(Glib::ustring & sql) const; + virtual void bindParams(DB::Command *, unsigned int & offset) const; + }; + class SqlFilter : public SqlWriter { + public: + SqlFilter(const xmlpp::Element *); + virtual void writeSql(Glib::ustring & sql) const; + virtual void bindParams(DB::Command *, unsigned int & offset) const; + + const Glib::ustring name; + bool active; + private: + Writers writers; + }; + typedef boost::intrusive_ptr SqlFilterPtr; + class SqlCommand : public SqlWriter { + public: + SqlCommand(const xmlpp::Element *); + virtual void writeSql(Glib::ustring & sql) const; + virtual void bindParams(DB::Command *, unsigned int & offset) const; + typedef std::multimap Filters; + Glib::ustring getSqlFor(const Glib::ustring & f) const; + private: + Filters filters; + Writers writers; + }; +} + +#endif + diff --git a/project2/sql/tablepatch.cpp b/project2/sql/tablepatch.cpp new file mode 100644 index 0000000..f87f60e --- /dev/null +++ b/project2/sql/tablepatch.cpp @@ -0,0 +1,438 @@ +#include "tablepatch.h" +#include +#include +#include +#include +#include +#include + +using namespace DB; + +TablePatch::TablePatch(const Connection & wdb, const TablePatch::Table & s, const TablePatch::Table & d, + const TablePatch::Columns & c) : + src(s), + dest(d), + cols(c), + db(wdb) +{ + if (!src.length()) { + throw PatchCheckFailure(); + } + if (!dest.length()) { + throw PatchCheckFailure(); + } + if (!db.inTx()) { + throw PatchCheckFailure(); + } +} + +void +TablePatch::addKey(const TablePatch::Column & c) +{ + pk.insert(c); +} + +void +TablePatch::patch(const char * where, const char * order) +{ + if (pk.size() == 0) { + throw PatchCheckFailure(); + } + doDeletes(where, order); + doUpdates(where, order); + doInserts(order); +} + +void +TablePatch::doDeletes(const char * where, const char * order) +{ + switch (db.bulkDeleteStyle()) { + case BulkDeleteUsingSubSelect: + { + // ----------------------------------------------------------------- + // Build SQL to delete keys ---------------------------------------- + // ----------------------------------------------------------------- + Buffer toDelSql; + toDelSql.appendf("DELETE FROM %s WHERE (", + dest.c_str()); + foreach (PKI, pk, pki) { + if (pki != pk.begin()) { + toDelSql.append(", "); + } + toDelSql.appendf("%s.%s", + dest.c_str(), + pki->c_str()); + } + // ----------------------------------------------------------------- + // Build SQL to select keys to delete ------------------------------ + // ----------------------------------------------------------------- + toDelSql.append(") IN (SELECT "); + foreach (PKI, pk, pki) { + if (pki != pk.begin()) { + toDelSql.append(", "); + } + toDelSql.appendf("a.%s", + pki->c_str()); + } + toDelSql.appendf(" FROM %s a LEFT OUTER JOIN %s b ON ", + dest.c_str(), src.c_str()); + foreach (PKI, pk, pki) { + if (pki != pk.begin()) { + toDelSql.append(" AND "); + } + toDelSql.appendf(" a.%s = b.%s", + pki->c_str(), pki->c_str()); + } + foreach (PKI, pk, pki) { + if (pki == pk.begin()) { + toDelSql.append(" WHERE "); + } + else { + toDelSql.append(" AND "); + } + toDelSql.appendf(" b.%s IS NULL", + pki->c_str()); + } + if (where && *where) { + toDelSql.appendf(" AND %s", where); + } + if (order && *order) { + toDelSql.appendf(" ORDER BY %s", order); + } + toDelSql.append(")"); + ModifyCommand * del = db.newModifyCommand(toDelSql); + del->execute(); + delete del; + break; + } + case BulkDeleteUsingUsingAlias: + case BulkDeleteUsingUsing: + { + Buffer toDelSql; + toDelSql.appendf("DELETE FROM %s USING %s a LEFT OUTER JOIN %s b ", + (db.bulkDeleteStyle() == BulkDeleteUsingUsingAlias ? "a" : dest.c_str()), + dest.c_str(), src.c_str()); + foreach (PKI, pk, pki) { + if (pki != pk.begin()) { + toDelSql.append(" AND "); + } + else { + toDelSql.append(" ON "); + } + toDelSql.appendf(" a.%s = b.%s", + pki->c_str(), pki->c_str()); + } + foreach (PKI, pk, pki) { + if (pki != pk.begin()) { + toDelSql.append(" AND "); + } + else { + toDelSql.append(" WHERE "); + } + toDelSql.appendf(" b.%s IS NULL", + pki->c_str()); + } + if (where && *where) { + toDelSql.appendf(" AND %s", where); + } + if (order && *order) { + toDelSql.appendf(" ORDER BY %s", order); + } + ModifyCommand * del = db.newModifyCommand(toDelSql); + del->execute(); + delete del; + break; + } + } +} + +void +TablePatch::doUpdates(const char * where, const char * order) +{ + if (cols.size() == pk.size()) { + // Can't "change" anything... it's all part of the key + return; + } + switch (db.bulkUpdateStyle()) { + case BulkUpdateByIteration: + { + // ----------------------------------------------------------------- + // Build SQL for list of updates to perform ------------------------ + // ----------------------------------------------------------------- + Buffer toUpdSel; + toUpdSel.append("SELECT "); + foreach (Columns::const_iterator, cols, col) { + if (pk.find(*col) == pk.end()) { + toUpdSel.appendf("b.%s, ", + col->c_str()); + } + } + foreach (Columns::const_iterator, cols, col) { + if (pk.find(*col) != pk.end()) { + toUpdSel.appendf("b.%s, ", + col->c_str()); + } + } + toUpdSel.appendf("0 FROM %s a, %s b", + dest.c_str(), src.c_str()); + foreach (PKI, pk, pki) { + if (pki == pk.begin()) { + toUpdSel.append(" WHERE "); + } + else { + toUpdSel.append(" AND "); + } + toUpdSel.appendf(" a.%s = b.%s", + pki->c_str(), pki->c_str()); + } + if (where && *where) { + toUpdSel.appendf(" AND %s", where); + } + toUpdSel.append(" AND ("); + bool first = true; + foreach (Columns::const_iterator, cols, col) { + if (pk.find(*col) == pk.end()) { + if (!first) { + toUpdSel.append(" OR "); + } + first = false; + toUpdSel.appendf( + " (((CASE WHEN (a.%s IS NULL AND b.%s IS NULL) THEN 1 ELSE 0 END) \ + + (CASE WHEN(a.%s = b.%s) THEN 1 ELSE 0 END)) = 0)", + col->c_str(), col->c_str(), col->c_str(), col->c_str()); + } + } + toUpdSel.append(")"); + if (order && *order) { + toUpdSel.appendf(" ORDER BY %s", order); + } + // ----------------------------------------------------------------- + // Build SQL to perform updates ------------------------------------ + // ----------------------------------------------------------------- + Buffer updSql; + updSql.appendf("UPDATE %s SET ", + dest.c_str()); + first = true; + foreach (Columns::const_iterator, cols, col) { + if (pk.find(*col) == pk.end()) { + if (!first) { + updSql.append(", "); + } + first = false; + updSql.appendf(" %s = ?", + col->c_str()); + } + } + foreach (PKI, pk, pki) { + if (pki == pk.begin()) { + updSql.append(" WHERE "); + } + else { + updSql.append(" AND "); + } + updSql.appendf(" %s = ?", + pki->c_str()); + } + // ----------------------------------------------------------------- + // Iterator over update list make changes -------------------------- + // ----------------------------------------------------------------- + SelectCommand * toUpd = db.newSelectCommand(toUpdSel); + ModifyCommand * upd = db.newModifyCommand(updSql); + int cs = cols.size(); + toUpd->execute(); + for (int c = 0; c < cs; c += 1) { + (*toUpd)[c].rebind(upd, c); + } + while (toUpd->fetch()) { + upd->execute(false); + } + delete toUpd; + delete upd; + } + break; + case BulkUpdateUsingFromSrc: + { + // ----------------------------------------------------------------- + // Build SQL for list of updates to perform ------------------------ + // ----------------------------------------------------------------- + Buffer updSql; + updSql.appendf("UPDATE %s a SET ", + dest.c_str()); + bool first = true; + foreach (Columns::const_iterator, cols, col) { + if (pk.find(*col) == pk.end()) { + if (!first) { + updSql.append(", "); + } + first = false; + updSql.appendf(" %s = b.%s ", + col->c_str(), col->c_str()); + } + } + updSql.appendf(" FROM %s b ", + src.c_str()); + foreach (PKI, pk, pki) { + if (pki == pk.begin()) { + updSql.append(" WHERE "); + } + else { + updSql.append(" AND "); + } + updSql.appendf(" a.%s = b.%s ", + pki->c_str(), pki->c_str()); + } + updSql.append(" AND ("); + first = true; + foreach (Columns::const_iterator, cols, col) { + if (pk.find(*col) == pk.end()) { + if (!first) { + updSql.append(" OR "); + } + first = false; + updSql.appendf( + " (((CASE WHEN (a.%s IS NULL AND b.%s IS NULL) THEN 1 ELSE 0 END) \ + + (CASE WHEN(a.%s = b.%s) THEN 1 ELSE 0 END)) = 0)", + col->c_str(), col->c_str(), + col->c_str(), col->c_str()); + } + } + updSql.append(")"); + if (where && *where) { + updSql.appendf(" AND %s ", where); + } + if (order && *order) { + updSql.appendf(" ORDER BY %s", order); + } + // ----------------------------------------------------------------- + // Execute the bulk update command --------------------------------- + // ----------------------------------------------------------------- + ModifyCommand * upd = db.newModifyCommand(updSql); + upd->execute(true); + delete upd; + break; + } + case BulkUpdateUsingJoin: + { + // ----------------------------------------------------------------- + // Build SQL for list of updates to perform ------------------------ + // ----------------------------------------------------------------- + Buffer updSql; + updSql.appendf("UPDATE %s a, %s b SET ", + dest.c_str(), src.c_str()); + bool first = true; + foreach (Columns::const_iterator, cols, col) { + if (pk.find(*col) == pk.end()) { + if (!first) { + updSql.append(", "); + } + first = false; + updSql.appendf(" a.%s = b.%s ", + col->c_str(), col->c_str()); + } + } + foreach (PKI, pk, pki) { + if (pki == pk.begin()) { + updSql.append(" WHERE "); + } + else { + updSql.append(" AND "); + } + updSql.appendf(" a.%s = b.%s ", + pki->c_str(), pki->c_str()); + } + updSql.append(" AND ("); + first = true; + foreach (Columns::const_iterator, cols, col) { + if (pk.find(*col) == pk.end()) { + if (!first) { + updSql.append(" OR "); + } + first = false; + updSql.appendf( + " (((CASE WHEN (a.%s IS NULL AND b.%s IS NULL) THEN 1 ELSE 0 END) \ + + (CASE WHEN(a.%s = b.%s) THEN 1 ELSE 0 END)) = 0)", + col->c_str(), col->c_str(), + col->c_str(), col->c_str()); + } + } + updSql.append(")"); + if (where && *where) { + updSql.appendf(" AND %s ", where); + } + if (order && *order) { + updSql.appendf(" ORDER BY %s", order); + } + // ----------------------------------------------------------------- + // Execute the bulk update command --------------------------------- + // ----------------------------------------------------------------- + ModifyCommand * upd = db.newModifyCommand(updSql); + upd->execute(true); + delete upd; + break; + } + } +} + +void +TablePatch::doInserts(const char * order) +{ + // ----------------------------------------------------------------- + // Build SQL for copying new records ------------------------------- + // ----------------------------------------------------------------- + Buffer toInsSql; + toInsSql.appendf("INSERT INTO %s", + dest.c_str()); + foreach (Columns::const_iterator, cols, col) { + if (col == cols.begin()) { + toInsSql.append("("); + } + else { + toInsSql.append(", "); + } + toInsSql.appendf("%s", + col->c_str()); + } + toInsSql.append(") SELECT "); + foreach (Columns::const_iterator, cols, col) { + if (col != cols.begin()) { + toInsSql.append(", "); + } + toInsSql.appendf("b.%s", + col->c_str()); + } + toInsSql.appendf(" FROM %s b LEFT OUTER JOIN %s a", + src.c_str(), dest.c_str()); + foreach (PKI, pk, pki) { + if (pki == pk.begin()) { + toInsSql.append(" ON "); + } + else { + toInsSql.append(" AND "); + } + toInsSql.appendf(" a.%s = b.%s", + pki->c_str(), pki->c_str()); + } + foreach (PKI, pk, pki) { + if (pki == pk.begin()) { + toInsSql.append(" WHERE "); + } + else { + toInsSql.append(" AND "); + } + toInsSql.appendf(" a.%s IS NULL", + pki->c_str()); + } + if (order && *order) { + toInsSql.appendf(" ORDER BY %s", order); + } + ModifyCommand * ins = db.newModifyCommand(toInsSql); + ins->execute(); + delete ins; +} + +const char * +TablePatch::PatchCheckFailure::what() const throw() +{ + return "Santiy checks failed: check table names and keys"; +} + diff --git a/project2/sql/tablepatch.h b/project2/sql/tablepatch.h new file mode 100644 index 0000000..0174294 --- /dev/null +++ b/project2/sql/tablepatch.h @@ -0,0 +1,42 @@ +#ifndef TABLEPATCH_H +#define TABLEPATCH_H + +#include +#include +#include +#include +#include +#include + +class TablePatch { + public: + typedef std::string Table; + typedef std::string Column; + typedef std::set Columns; + typedef Columns PrimaryKey; + typedef PrimaryKey::const_iterator PKI; + + class PatchCheckFailure : public std::exception { + public: + const char * what() const throw(); + }; + + TablePatch(const DB::Connection & db, const Table & src, const Table & dest, const Columns & cols); + + void addKey(const Column & col); + void patch(const char * where, const char * order); + + private: + void doDeletes(const char * where, const char * order); + void doUpdates(const char * where, const char * order); + void doInserts(const char * order); + + Table src; + Table dest; + PrimaryKey pk; + Columns cols; + const DB::Connection &db; +}; + +#endif + diff --git a/project2/sqlCache.cpp b/project2/sqlCache.cpp deleted file mode 100644 index 13bc23d..0000000 --- a/project2/sqlCache.cpp +++ /dev/null @@ -1,300 +0,0 @@ -#include "cache.h" -#include "sqlVariableBinder.h" -#include "sqlHandleAsVariableType.h" -#include "buffer.h" -#include "selectcommand.h" -#include "modifycommand.h" -#include "column.h" -#include "commonObjects.h" -#include "rdbmsDataSource.h" -#include "logger.h" -#include "xmlObjectLoader.h" -#include "iHaveParameters.h" -#include "rowSet.h" -#include -#include -#include - -typedef boost::shared_ptr SelectPtr; -typedef boost::shared_ptr ModifyPtr; - -class SqlCache : public Cache { - public: - SqlCache(const xmlpp::Element * p) : - Cache(p) - { - } - - void loadComplete(const CommonObjects * co) - { - db = co->dataSource(DataSource); - } - - static void appendKeyCols(Buffer * sql, unsigned int * off, const Glib::ustring & col) - { - if ((*off)++) { - sql->append(", "); - } - sql->append(col.c_str()); - } - - static void appendKeyBinds(Buffer * sql, unsigned int * off) - { - if ((*off)++) { - sql->append(", "); - } - sql->append("?"); - } - - static void appendKeyAnds(Buffer * sql, const Glib::ustring & col) - { - sql->appendf(" AND h.%s = ?", col.c_str()); - } - - static void bindKeyValues(DB::Command * cmd, unsigned int * offset, const VariableType & v) - { - boost::apply_visitor(SqlVariableBinder(cmd, (*offset)++), v); - } - - class SqlCacheRowSet : public RowSet { - public: - SqlCacheRowSet(SelectPtr r) : - RowSet(NULL), - s(r) { - } - void loadComplete(const CommonObjects *) { - } - class SqlCacheRowState : public RowState { - public: - SqlCacheRowState(const SqlCacheRowSet * s) : - sc(s) { - } - const Columns & getColumns() const { - return columns; - } - RowAttribute resolveAttr(const Glib::ustring & attrName) const { - return boost::bind(&SqlCacheRowState::getAttrCol, this, "p2attr_" + attrName); - } - private: - VariableType getAttrCol(const Glib::ustring & col) const { - HandleAsVariableType h; - (*sc->s)[col].apply(h); - return h.variable; - } - mutable Columns columns; - friend class SqlCacheRowSet; - const SqlCacheRowSet * sc; - }; - void execute(const Glib::ustring&, const RowProcessor * rp) const { - SqlCacheRowState ss(this); - HandleAsVariableType h; - do { - if (!(*s)["p2_cacheid"].isNull()) { - if (colCols.empty()) { - (*s)["p2_cacheid"].apply(h); - cacheId = h.variable; - unsigned int colNo = 0; - for (unsigned int c = 0; c < s->columnCount(); c++) { - const DB::Column & col = (*s)[c]; - if (!boost::algorithm::starts_with(col.name, "p2attr_") && - !boost::algorithm::starts_with(col.name, "p2_")) { - ss.columns.insert(new Column(colNo++, col.name)); - colCols.push_back(c); - } - } - ss.fields.resize(colCols.size()); - } - else { - (*s)["p2_cacheid"].apply(h); - if (cacheId != (int64_t)h.variable) { - break; - } - } - BOOST_FOREACH(const unsigned int & c, colCols) { - const DB::Column & col = (*s)[c]; - col.apply(h); - ss.fields[&c - &colCols.front()] = h.variable; - } - ss.process(rp); - } - } while (s->fetch()); - } - private: - SelectPtr s; - mutable std::vector colCols; - mutable int64_t cacheId; - }; - - RowSetCPtr getCachedRowSet(const Glib::ustring & n, const Glib::ustring & f, const IHaveParameters * ps) const - { - Buffer sql; - sql.appendf("SELECT r.* \ - FROM %s p, %s_%s_%s h LEFT OUTER JOIN %s_%s_%s_rows r \ - ON h.p2_cacheid = r.p2_cacheid \ - WHERE p.p2_time > ? \ - AND p.p2_cacheid = h.p2_cacheid", - HeaderTable.c_str(), - HeaderTable.c_str(), n.c_str(), f.c_str(), - HeaderTable.c_str(),n.c_str(), f.c_str()); - applyKeys(boost::bind(appendKeyAnds, &sql, _1), ps); - sql.appendf(" ORDER BY r.p2_cacheid DESC, r.p2_row"); - SelectPtr gh(db->getReadonly().newSelectCommand(sql)); - unsigned int offset = 0; - gh->bindParamT(offset++, time(NULL) - CacheLife); - applyKeys(boost::bind(bindKeyValues, gh.get(), &offset, _2), ps); - if (gh->fetch()) { - return new SqlCacheRowSet(gh); - } - return NULL; - } - - class SqlCachePresenter : public Presenter { - public: - SqlCachePresenter(const Glib::ustring & name, const Glib::ustring & filter, const RdbmsDataSource * d) : - depth(0), - row(1), - db(d), - n(name), - f(filter) { - } - void declareNamespace(const Glib::ustring &, const Glib::ustring &) const { } - void setNamespace(const Glib::ustring &, const Glib::ustring &) const { } - void pushSub(const Glib::ustring & name, const Glib::ustring &) const { - depth += 1; - if (depth == 2) { - col = name; - } - else if (depth == 1) { - } - } - void addAttr(const Glib::ustring & name, const Glib::ustring &, const VariableType & value) const { - attrs.insert(Values::value_type(name, value)); - } - void addText(const VariableType & value) const { - cols.insert(Values::value_type(col, value)); - } - void popSub() const { - if (depth == 2) { - col.clear(); - } - else if (depth == 1) { - Buffer sql; - sql.appendf("INSERT INTO %s_%s_%s_rows(p2_row", HeaderTable.c_str(), n.c_str(), f.c_str()); - BOOST_FOREACH(const Values::value_type & a, attrs) { - sql.appendf(", p2attr_%s", a.first.c_str()); - } - BOOST_FOREACH(const Values::value_type & v, cols) { - sql.appendf(", %s", v.first.c_str()); - } - sql.appendf(") VALUES(?"); - for (size_t x = attrs.size(); x > 0; x -= 1) { - sql.append(", ?"); - } - for (size_t x = cols.size(); x > 0; x -= 1) { - sql.append(", ?"); - } - sql.appendf(")"); - ModifyPtr m(db->getReadonly().newModifyCommand(sql)); - unsigned int offset = 0; - m->bindParamI(offset++, row++); - BOOST_FOREACH(const Values::value_type & a, attrs) { - boost::apply_visitor(SqlVariableBinder(m.get(), offset++), a.second); - } - BOOST_FOREACH(const Values::value_type & v, cols) { - boost::apply_visitor(SqlVariableBinder(m.get(), offset++), v.second); - } - m->execute(); - cols.clear(); - attrs.clear(); - } - depth -= 1; - } - private: - mutable unsigned int depth; - mutable unsigned int row; - const RdbmsDataSource * db; - mutable Glib::ustring col; - const Glib::ustring n, f; - typedef std::map Values; - mutable Values cols, attrs; - }; - - PresenterPtr openFor(const Glib::ustring & n, const Glib::ustring & f, const IHaveParameters * ps) - { - // Header - Buffer del; - del.appendf("INSERT INTO %s(p2_time) VALUES(?)", HeaderTable.c_str()); - ModifyPtr h = ModifyPtr(db->getReadonly().newModifyCommand(del)); - h->bindParamT(0, time(NULL)); - h->execute(); - // Record set header - Buffer sql; - sql.appendf("INSERT INTO %s_%s_%s(", HeaderTable.c_str(), n.c_str(), f.c_str()); - unsigned int offset = 0; - applyKeys(boost::bind(appendKeyCols, &sql, &offset, _1), ps); - sql.appendf(") VALUES("); - offset = 0; - applyKeys(boost::bind(appendKeyBinds, &sql, &offset), ps); - sql.appendf(")"); - ModifyPtr m(db->getReadonly().newModifyCommand(sql)); - offset = 0; - applyKeys(boost::bind(bindKeyValues, m.get(), &offset, _2), ps); - m->execute(); - return new SqlCachePresenter(n, f, db); - } - - void close(const Glib::ustring & , const Glib::ustring & , const IHaveParameters * ) - { - } - - private: - friend class CustomSqlCacheLoader; - const RdbmsDataSource * db; - static std::string DataSource; - static std::string HeaderTable; - static time_t CacheLife; -}; - -std::string SqlCache::DataSource; -std::string SqlCache::HeaderTable; -time_t SqlCache::CacheLife; - -namespace po = boost::program_options; -class CustomSqlCacheLoader : public ElementLoaderImpl { - public: - CustomSqlCacheLoader() : - opts("SQL Cache options") - { - opts.add_options() - ("cache.sql.datasource", po::value(&SqlCache::DataSource), - "The default datasource to connect to") - ("cache.sql.headertable", po::value(&SqlCache::HeaderTable)->default_value("p2cache"), - "The filename to store the data in") - ("cache.sql.life", po::value(&SqlCache::CacheLife)->default_value(3600), - "The age of cache entries after which they are removed (seconds)") - ; - } - - po::options_description * options() - { - return &opts; - } - - void onIdle() - { - if (!SqlCache::DataSource.empty()) { - boost::intrusive_ptr co = new CommonObjects(); - const RdbmsDataSource * db = co->dataSource(SqlCache::DataSource); - Buffer del; - del.appendf("DELETE FROM %s WHERE p2_time < ?", SqlCache::HeaderTable.c_str()); - ModifyPtr m(db->getReadonly().newModifyCommand(del)); - m->bindParamT(0, time(NULL) - SqlCache::CacheLife); - m->execute(); - } - } - - private: - po::options_description opts; -}; -DECLARE_CUSTOM_LOADER("sqlcache", CustomSqlCacheLoader); - diff --git a/project2/sqlCheck.cpp b/project2/sqlCheck.cpp deleted file mode 100644 index d86eb3b..0000000 --- a/project2/sqlCheck.cpp +++ /dev/null @@ -1,100 +0,0 @@ -#include "sqlCheck.h" -#include "xmlObjectLoader.h" -#include "selectcommand.h" -#include "column.h" -#include "rdbmsDataSource.h" -#include "commonObjects.h" -#include "sqlVariableBinder.h" -#include -#include - -DECLARE_LOADER("sqlcheck", SqlCheck); - -class CantCompareNulls : public std::exception { }; - -SqlCheck::SqlCheck(const xmlpp::Element * p) : - ParamChecker(p), - dataSource(p, "datasource"), - filter(p, "filter", false, ""), - testOp(p, "testOp", false, "=="), - testValue(p, "testValue"), - sqlCommand(dynamic_cast(p->get_children("sql").front())) -{ -} - -SqlCheck::~SqlCheck() -{ -} - -void -SqlCheck::loadComplete(const CommonObjects * co) -{ - db = co->dataSource(dataSource()); -} - -class HandleDoCompare : public DB::HandleField { - public: - HandleDoCompare(const VariableType & tV, const std::string & tO) : - retVal(false), - testValue(tV), - testOp(tO) { - } - void null() { - throw CantCompareNulls(); - } - void string(const char *c , size_t l) { - doTest(Glib::ustring(c, c + l)); - } - void integer(int64_t val) { - doTest(val); - } - void floatingpoint(double val) { - doTest(val); - } - void timestamp(const struct tm & val) { - doTest(boost::posix_time::ptime_from_tm(val)); - } - bool operator()() const { - return retVal; - } - private: - template - void doTest(const TV & val) { - TV tv = testValue; - if ((testOp == "==" || testOp == "=") && val == tv) { - retVal = true; - } - else if (testOp == "<" && val < tv) { - retVal = true; - } - else if (testOp == ">" && val > tv) { - retVal = true; - } - else if (testOp == "!=" && val != tv) { - retVal = true; - } - else if ((testOp == "<=" || testOp == "=<") && val <= tv) { - retVal = true; - } - else if ((testOp == ">=" || testOp == "=>") && val >= tv) { - retVal = true; - } - } - bool retVal; - const VariableType & testValue; - std::string testOp; -}; -bool -SqlCheck::performCheck() const -{ - boost::shared_ptr query = boost::shared_ptr( - db->getWritable().newSelectCommand(sqlCommand.getSqlFor(filter()))); - unsigned int offset = 0; - sqlCommand.bindParams(query.get(), offset); - HandleDoCompare h(testValue, testOp()); - while (query->fetch()) { - (*query)[0].apply(h); - } - return h(); -} - diff --git a/project2/sqlCheck.h b/project2/sqlCheck.h deleted file mode 100644 index c9933d7..0000000 --- a/project2/sqlCheck.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef SQLCHECK_H -#define SQLCHECK_H - -#include "paramChecker.h" -#include "sqlWriter.h" - -namespace DB { class SelectCommand; } -class RdbmsDataSource; - -/// Project2 component to check the value of a variable against an RDBMS data source -class SqlCheck : public ParamChecker { - public: - SqlCheck(const xmlpp::Element * p); - virtual ~SqlCheck(); - - virtual void loadComplete(const CommonObjects *); - bool performCheck() const; - - const Variable dataSource; - const Variable filter; - const Variable testOp; - const Variable testValue; - - private: - const DynamicSql::SqlCommand sqlCommand; - const RdbmsDataSource * db; -}; - -#endif diff --git a/project2/sqlHandleAsVariableType.cpp b/project2/sqlHandleAsVariableType.cpp deleted file mode 100644 index f084a14..0000000 --- a/project2/sqlHandleAsVariableType.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "sqlHandleAsVariableType.h" -#include - -void HandleAsVariableType::null() { - variable = Null(); -} -void HandleAsVariableType::string(const char * c, size_t l) { - variable = Glib::ustring(c, c + l); -} -void HandleAsVariableType::integer(int64_t i) { - variable = i; -} -void HandleAsVariableType::floatingpoint(double d) { - variable = d; -} -void HandleAsVariableType::timestamp(const struct tm & t) { - variable = boost::posix_time::ptime(boost::posix_time::ptime_from_tm(t)); -} - diff --git a/project2/sqlHandleAsVariableType.h b/project2/sqlHandleAsVariableType.h deleted file mode 100644 index c874b7c..0000000 --- a/project2/sqlHandleAsVariableType.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef SQLHANDLEASVARIABLETYPE -#define SQLHANDLEASVARIABLETYPE - -#include "column.h" -#include "variables.h" - -class HandleAsVariableType : public DB::HandleField { - public: - void null(); - void string(const char * c, size_t l); - void integer(int64_t i); - void floatingpoint(double d); - void timestamp(const struct tm & t); - VariableType variable; -}; - -#endif - diff --git a/project2/sqlMergeTask.cpp b/project2/sqlMergeTask.cpp deleted file mode 100644 index 09657f8..0000000 --- a/project2/sqlMergeTask.cpp +++ /dev/null @@ -1,329 +0,0 @@ -#include "sqlMergeTask.h" -#include "columns.h" -#include "commonObjects.h" -#include "rdbmsDataSource.h" -#include "exceptions.h" -#include "sqlVariableBinder.h" -#include "xmlObjectLoader.h" -#include -#include -#include -#include -#include -#include -#include - -bool SqlMergeTask::defaultUseTempTable = true; -static void attach(boost::intrusive_ptr i, DB::ModifyCommand * insert); - -class SqlMergeInsert; -typedef boost::intrusive_ptr SqlMergeInsertPtr; -/// Project2 component insert custom constructed records during an SQL Merge task -class SqlMergeInsert : IHaveParameters, public Task { - public: - SqlMergeInsert(const xmlpp::Element * p) : - SourceObject(p), - IHaveParameters(p), - Task(p) { - } - void loadComplete(const CommonObjects*) { - } - void execute() const { - unsigned int col = 0; - BOOST_FOREACH(const Parameters::value_type & v, parameters) { - boost::apply_visitor(SqlVariableBinder(insert, col++), v.second); - } - insert->execute(); - } - private: - friend void attach(SqlMergeInsertPtr i, DB::ModifyCommand * insert); - DB::ModifyCommand * insert; -}; - -DECLARE_LOADER("sqlmerge", SqlMergeTask); -DECLARE_LOADER("sqlmergeinsert", SqlMergeInsert); - -// Conversion logic -SqlMergeTask::SqlMergeTask(const xmlpp::Element * p) : - SourceObject(p), - Task(p), - updateWhere(p, "updatewhere", false), - patchOrder(p->get_attribute_value("patchorder")), - earlyKeys(p->get_attribute_value("earlykeys") == "yes"), - useView(p->get_attribute_value("useview") == "yes"), - tempTableCreated(false), - insCmd(NULL), - destdb(NULL), - dataSource(p, "datasource"), - dtable(p->get_attribute_value("targettable")), - dtablet(stringf("tmp_%s_%d", dtable.c_str(), getpid())) -{ - LoaderBase loader(true); - loader.supportedStorers.insert(Storer::into(&sources)); - loader.collectAll(p, true); - - if (!sources.empty() && useView) { - throw NotSupported("useview not supported with iterate fillers"); - } - - BOOST_FOREACH(xmlpp::Node * psi, p->find("columns/column")) { - xmlpp::Element * e = static_cast(psi); - TargetColumnPtr tcp(new TargetColumn(e->get_child_text()->get_content())); - tcp->maptable = e->get_attribute_value("maptable"); - if (!tcp->maptable.empty()) { - if (useView) { - throw NotSupported("useview not supported with mapped columns"); - } - tcp->mapcolumn = e->get_attribute_value("mapcolumn"); - } - cols.insert(tcp); - } - BOOST_FOREACH(xmlpp::Node * psi, p->find("columns/column[@key='true']")) { - keys.insert(static_cast(psi)->get_child_text()->get_content()); - } - BOOST_FOREACH(xmlpp::Node * psi, p->find("sql")) { - sqls.push_back(static_cast(psi)->get_child_text()->get_content()); - } -} - -SqlMergeTask::~SqlMergeTask() -{ - delete insCmd; -} - -void -SqlMergeTask::loadComplete(const CommonObjects * co) -{ - destdb = &co->dataSource(dataSource())->getWritable(); - insCmd = insertCommand(); - BOOST_FOREACH(const Sources::value_type & i, sources) { - attach(i, insCmd); - } -} - -SqlMergeTask::TargetColumn::TargetColumn(const Column & c) : - column(c), - mapcolumn(c) -{ -} - -bool -SqlMergeTask::TargetColumn::Sort::operator()(const TargetColumnPtr & a, const TargetColumnPtr & b) const -{ - return a->column < b->column; -} - -void -SqlMergeTask::execute() const -{ - createTempTable(); - if (earlyKeys) { - createTempKey(); - copyToTempTable(); - } - else { - copyToTempTable(); - createTempKey(); - } - std::set colNames; - BOOST_FOREACH(const TargetColumnPtr & c, cols) { - colNames.insert(c->column); - } - TablePatch tp(*destdb, dtablet, dtable, colNames); - BOOST_FOREACH(const Keys::value_type & k, keys) { - tp.addKey(k); - } - tp.patch(updateWhere(), patchOrder.c_str()); - dropTempTable(); -} - -void -SqlMergeTask::createTempTable() const -{ - if (useView) { - DB::ModifyCommand * cv = destdb->newModifyCommand(stringf( - "CREATE VIEW %s AS %s", - dtablet.c_str(), - boost::algorithm::join(sqls, " UNION ").c_str())); - cv->execute(); - delete cv; - } - else { - DB::ModifyCommand * ctt = destdb->newModifyCommand(stringf( - "CREATE TEMPORARY TABLE %s AS SELECT * FROM %s WHERE 0=1", - dtablet.c_str(), - dtable.c_str())); - ctt->execute(); - delete ctt; - BOOST_FOREACH(Columns::value_type c, cols) { - if (!c->maptable.empty()) { - DB::ModifyCommand * at = destdb->newModifyCommand(stringf( - "ALTER TABLE %s ADD COLUMN %s VARCHAR(1000)", - dtablet.c_str(), - c->mapcolumn.c_str())); - at->execute(); - delete at; - } - } - } - tempTableCreated = true; -} -void -SqlMergeTask::dropTempTable() const -{ - if (tempTableCreated) { - DB::ModifyCommand * d; - if (useView) { - d = destdb->newModifyCommand("DROP VIEW " + dtablet); - } - else { - d = destdb->newModifyCommand("DROP TABLE " + dtablet); - } - d->execute(); - delete d; - } -} -void -SqlMergeTask::createTempKey() const -{ - if (useView) return; - /* Primary key */ - Buffer idx; - idx.appendf("ALTER TABLE %s ADD CONSTRAINT pk_%s PRIMARY KEY(%s)", - dtablet.c_str(), dtablet.c_str(), - boost::algorithm::join(keys, ", ").c_str()); - DB::ModifyCommand * at = destdb->newModifyCommand(idx); - at->execute(); - delete at; - /* Indexes */ - int n = 0; - BOOST_FOREACH(const Keys::value_type & i, indexes) { - DB::ModifyCommand * ci = destdb->newModifyCommand(stringf( - "CREATE INDEX idx_%s_%d ON %s(%s)", - dtablet.c_str(), n, dtablet.c_str(), i.c_str())); - ci->execute(); - delete ci; - n += 1; - } -} -DB::ModifyCommand * -SqlMergeTask::insertCommand() const -{ - Buffer ins; - ins.appendf("INSERT INTO %s(", dtablet.c_str()); - foreach(Columns::const_iterator, cols, c) { - if (c != cols.begin()) { - ins.append(", "); - } - ins.append((*c)->mapcolumn); - } - ins.append(") VALUES ("); - foreach(Columns::const_iterator, cols, c) { - if (c == cols.begin()) { - ins.append("?"); - } - else { - ins.append(", ?"); - } - } - ins.append(")"); - return destdb->newModifyCommand(ins); -} - -class Populate : public NoOutputExecute { - public: - Populate(DB::ModifyCommand * c) : - SourceObject(__FUNCTION__), - NoOutputExecute(__FUNCTION__), - cmd(c) - { - } - virtual void loadComplete(const CommonObjects *) - { - } - void execute() const - { - unsigned int idx = 0; - RowState::Stack().back()->foreachColumn(boost::bind(&Populate::bind, this, boost::ref(idx), _3)); - cmd->execute(); - } - private: - void bind(unsigned int & idx, const VariableType & value) const - { - boost::apply_visitor(SqlVariableBinder(cmd, idx++), value); - } - DB::ModifyCommand * cmd; -}; -typedef boost::intrusive_ptr PopulatePtr; - -void -attach(SqlMergeInsertPtr i, DB::ModifyCommand * insert) -{ - if (i) { - i->insert = insert; - } -} - -static void -attach(boost::intrusive_ptr i, DB::ModifyCommand * insert) -{ - if (!i) { - return; - } - if (i->normal.empty()) { - i->normal.push_back(new Populate(insert)); - } - else { - BOOST_FOREACH(const IHaveSubTasks::Tasks::value_type & n, i->normal) { - attach(boost::dynamic_pointer_cast(n), insert); - attach(boost::dynamic_pointer_cast(n), insert); - } - } -} - -void -SqlMergeTask::copyToTempTable() const -{ - if (useView) return; - BOOST_FOREACH(const Sources::value_type & i, sources) { - i->execute(); - } - BOOST_FOREACH(const std::string & sql, sqls) { - Buffer ins; - ins.appendf("INSERT INTO %s(", dtablet.c_str()); - foreach(Columns::const_iterator, cols, c) { - if (c != cols.begin()) { - ins.append(", "); - } - ins.append((*c)->column); - } - ins.append(") SELECT "); - foreach(Columns::const_iterator, cols, c) { - if (c != cols.begin()) { - ins.append(", "); - } - ins.append((*c)->column); - } - ins.appendf(" FROM (%s) tmp_src", sql.c_str()); - DB::ModifyCommand * cttt = destdb->newModifyCommand(ins); - cttt->execute(); - delete cttt; - } - BOOST_FOREACH(Columns::value_type c, cols) { - if (!c->maptable.empty()) { - DB::ModifyCommand * utt = destdb->newModifyCommand( - stringf( - "UPDATE %s d SET %s = (SELECT m.%s FROM %s m WHERE m.%s = d.%s) WHERE %s IS NULL", - dtablet.c_str(), - c->column.c_str(), - c->column.c_str(), - c->maptable.c_str(), - c->mapcolumn.c_str(), - c->mapcolumn.c_str(), - c->column.c_str())); - utt->execute(); - delete utt; - } - } -} - diff --git a/project2/sqlMergeTask.h b/project2/sqlMergeTask.h deleted file mode 100644 index c9e206c..0000000 --- a/project2/sqlMergeTask.h +++ /dev/null @@ -1,79 +0,0 @@ -#ifndef SQLMERGETASK_H -#define SQLMERGETASK_H - -#include -#include -#include -#include -#include "tablepatch.h" -#include "task.h" -#include "iterate.h" -#include "variables.h" -#include -#include -#include -#include - -/// Project2 component merge arbitrary data into an RDBMS table -class SqlMergeTask : public Task { - public: - typedef std::string Table; - typedef std::string Column; - class TargetColumn; - typedef boost::intrusive_ptr TargetColumnPtr; - class TargetColumn : public virtual IntrusivePtrBase { - public: - class Sort { - public: - bool operator()(const TargetColumnPtr & a, const TargetColumnPtr & b) const; - }; - TargetColumn(const Column &); - - Column column; - Column mapcolumn; - Table maptable; - - }; - typedef std::set Columns; - - typedef std::set Keys; - - SqlMergeTask(const xmlpp::Element * p); - virtual ~SqlMergeTask(); - - virtual void loadComplete(const CommonObjects *); - void execute() const; - Columns cols; - Keys keys; - Keys indexes; - const Variable updateWhere; - const std::string patchOrder; - const bool earlyKeys; - const bool useView; - - private: - virtual void copyToTempTable() const; - void createTempTable() const; - void dropTempTable() const; - void createTempKey() const; - - mutable bool tempTableCreated; - typedef ANONSTORAGEOF(Iterate) Sources; - Sources sources; - std::list sqls; - protected: - DB::ModifyCommand * insertCommand() const; - DB::ModifyCommand * insCmd; - - public: - const DB::Connection * destdb; - const Variable dataSource; - const Table dtable; - const Table dtablet; - - static unsigned int defaultVerbosity; - static bool defaultUseTempTable; -}; - -#endif - diff --git a/project2/sqlRows.cpp b/project2/sqlRows.cpp deleted file mode 100644 index 6e506d7..0000000 --- a/project2/sqlRows.cpp +++ /dev/null @@ -1,69 +0,0 @@ -#include "sqlRows.h" -#include "sqlHandleAsVariableType.h" -#include "rowProcessor.h" -#include "xml.h" -#include "selectcommand.h" -#include "rdbmsDataSource.h" -#include "column.h" -#include -#include "xmlObjectLoader.h" -#include "commonObjects.h" -#include -#include - -DECLARE_LOADER("sqlrows", SqlRows); - -SqlRows::SqlRows(const xmlpp::Element * p) : - RowSet(p), - dataSource(p, "datasource"), - sqlCommand(dynamic_cast(p->get_children("sql").front())), - db(NULL) -{ -} - -SqlRows::~SqlRows() -{ -} - -void -SqlRows::loadComplete(const CommonObjects * co) -{ - db = co->dataSource(dataSource()); -} - -SqlRows::SqlState::SqlState(SelectPtr s) : - query(s) -{ -} - -const Columns & -SqlRows::SqlState::getColumns() const -{ - if (columns.empty()) { - for (unsigned int c = 0; c < query->columnCount(); c++) { - columns.insert(new Column(c, (*query)[c].name)); - } - } - return columns; -} - -void -SqlRows::execute(const Glib::ustring & filter, const RowProcessor * rp) const -{ - unsigned int offset = 0; - SqlState ss(SelectPtr(db->getReadonly().newSelectCommand(sqlCommand.getSqlFor(filter)))); - sqlCommand.bindParams(ss.query.get(), offset); - while (ss.query->fetch()) { - HandleAsVariableType h; - if (ss.fields.empty()) { - ss.fields.resize(ss.query->columnCount()); - } - for (unsigned int c = 0; c < ss.query->columnCount(); c++) { - const DB::Column & col = (*ss.query)[c]; - col.apply(h); - ss.fields[c] = h.variable; - } - ss.process(rp); - } -} - diff --git a/project2/sqlRows.h b/project2/sqlRows.h deleted file mode 100644 index 5614fa1..0000000 --- a/project2/sqlRows.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef SQLROWS_H -#define SQLROWS_H - -#include -#include -#include -#include "selectcommand.h" -#include "iHaveParameters.h" -#include "rowSet.h" -#include "sqlWriter.h" - -class RdbmsDataSource; - -/// Project2 component to create a row set based on an SQL SELECT statement issued against an RDBMS data source -class SqlRows : public RowSet { - public: - SqlRows(const xmlpp::Element * p); - ~SqlRows(); - - void execute(const Glib::ustring &, const RowProcessor *) const; - virtual void loadComplete(const CommonObjects *); - - const Variable dataSource; - - private: - const DynamicSql::SqlCommand sqlCommand; - typedef boost::shared_ptr SelectPtr; - class SqlState : public RowState { - public: - SqlState(SelectPtr query); - const Columns & getColumns() const; - SelectPtr query; - mutable Columns columns; - friend class SqlRows; - }; - const RdbmsDataSource * db; -}; - -#endif - diff --git a/project2/sqlTask.cpp b/project2/sqlTask.cpp deleted file mode 100644 index 3a1d334..0000000 --- a/project2/sqlTask.cpp +++ /dev/null @@ -1,70 +0,0 @@ -#include "sqlTask.h" -#include -#include "xmlObjectLoader.h" -#include "modifycommand.h" -#include "rdbmsDataSource.h" -#include "commonObjects.h" -#include "sqlVariableBinder.h" - -DECLARE_LOADER("sqltask", SqlTask); -StaticMessageException(RunOnNotSpecified, "runon attribute must be specified"); - -class SqlIfChangesStorer : public StorerBase { - public: - SqlIfChangesStorer(Map c, Map nc) : - changes(c), - noChanges(nc) - { - } - bool insert(const xmlpp::Element * p, NoOutputExecutePtr O) { - xmlpp::Attribute * runon = p->get_attribute("runon"); - if (!runon) { - throw RunOnNotSpecified(); - } - ((runon->get_value() == "changes") ? changes : noChanges)->push_back(O); - return true; - } - Map changes, noChanges; -}; - -SqlTask::SqlTask(const xmlpp::Element * p) : - SourceObject(p), - Task(p), - dataSource(p, "datasource"), - filter(p, "filter", false, ""), - sqlCommand(dynamic_cast(p->get_children("sql").front())) -{ - LoaderBase loader(true); - loader.supportedStorers.insert(new SqlIfChangesStorer(&changesNOEs, &noChangesNOEs)); - loader.collectAll(p, true, IgnoreUnsupported); -} - -SqlTask::~SqlTask() -{ -} - -void -SqlTask::loadComplete(const CommonObjects * co) -{ - db = co->dataSource(dataSource()); -} - -void -SqlTask::execute() const -{ - boost::shared_ptr modify = boost::shared_ptr( - db->getWritable().newModifyCommand(sqlCommand.getSqlFor(filter()))); - unsigned int offset = 0; - sqlCommand.bindParams(modify.get(), offset); - if (modify->execute() == 0) { - BOOST_FOREACH(const SubNOEs::value_type & sq, noChangesNOEs) { - sq->execute(); - } - } - else { - BOOST_FOREACH(const SubNOEs::value_type & sq, changesNOEs) { - sq->execute(); - } - } -} - diff --git a/project2/sqlTask.h b/project2/sqlTask.h deleted file mode 100644 index 384b000..0000000 --- a/project2/sqlTask.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef SQLTASK_H -#define SQLTASK_H - -#include -#include -#include -#include "task.h" -#include "variables.h" -#include "sqlWriter.h" - -namespace DB { class ModifyCommand; } -class RdbmsDataSource; - -/// Project2 component to execute a modifying SQL statement against an RDBMS data source -class SqlTask : public Task { - public: - SqlTask(const xmlpp::Element * p); - virtual ~SqlTask(); - virtual void loadComplete(const CommonObjects *); - virtual void execute() const; - - const Variable dataSource; - const Variable filter; - - typedef ANONORDEREDSTORAGEOF(NoOutputExecute) SubNOEs; - SubNOEs changesNOEs; - SubNOEs noChangesNOEs; - - protected: - const DynamicSql::SqlCommand sqlCommand; - const RdbmsDataSource * db; -}; - -#endif - - diff --git a/project2/sqlVariableBinder.cpp b/project2/sqlVariableBinder.cpp deleted file mode 100644 index 23c24f2..0000000 --- a/project2/sqlVariableBinder.cpp +++ /dev/null @@ -1,77 +0,0 @@ -#include "sqlVariableBinder.h" -#include "command.h" -#include "variables.h" -#include - -SqlVariableBinder::SqlVariableBinder(DB::Command * c, unsigned int i) : - cmd(c), - idx(i) -{ -} -void -SqlVariableBinder::operator()(const Null &) const -{ - cmd->bindNull(idx); -} -void -SqlVariableBinder::operator()(const Glib::ustring & i) const -{ - cmd->bindParamS(idx, i); -} -void -SqlVariableBinder::operator()(const long long unsigned int & i) const -{ - cmd->bindParamI(idx, i); -} -void -SqlVariableBinder::operator()(const long unsigned int & i) const -{ - cmd->bindParamI(idx, i); -} -void -SqlVariableBinder::operator()(const unsigned int & i) const -{ - cmd->bindParamI(idx, i); -} -void -SqlVariableBinder::operator()(const short unsigned int & i) const -{ - cmd->bindParamI(idx, i); -} -void -SqlVariableBinder::operator()(const long long int & i) const -{ - cmd->bindParamI(idx, i); -} -void -SqlVariableBinder::operator()(const long int & i) const -{ - cmd->bindParamI(idx, i); -} -void -SqlVariableBinder::operator()(const int & i) const -{ - cmd->bindParamI(idx, i); -} -void -SqlVariableBinder::operator()(const short int & i) const -{ - cmd->bindParamI(idx, i); -} -void -SqlVariableBinder::operator()(const double & i) const -{ - cmd->bindParamF(idx, i); -} -void -SqlVariableBinder::operator()(const float & i) const -{ - cmd->bindParamF(idx, i); -} -void -SqlVariableBinder::operator()(const boost::posix_time::ptime & i) const -{ - struct tm tm(boost::posix_time::to_tm(i)); - cmd->bindParamT(idx, &tm); -} - diff --git a/project2/sqlVariableBinder.h b/project2/sqlVariableBinder.h deleted file mode 100644 index df3879a..0000000 --- a/project2/sqlVariableBinder.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef SQLVARIABLEBINDER_H -#define SQLVARIABLEBINDER_H - -#include -#include -#include -#include - -namespace DB { - class Command; -} -class Null; -class SqlVariableBinder : public boost::static_visitor<> { - public: - SqlVariableBinder(DB::Command * c, unsigned int i); - void operator()(const Null & i) const; - void operator()(const Glib::ustring & i) const; - void operator()(const long long unsigned int & i) const; - void operator()(const long unsigned int & i) const; - void operator()(const unsigned int & i) const; - void operator()(const short unsigned int & i) const; - void operator()(const long long int & i) const; - void operator()(const long int & i) const; - void operator()(const int & i) const; - void operator()(const short int & i) const; - void operator()(const double & i) const; - void operator()(const float & i) const; - void operator()(const boost::posix_time::ptime & i) const; - - private: - DB::Command * cmd; - unsigned int idx; -}; - -#endif - diff --git a/project2/sqlWriter.cpp b/project2/sqlWriter.cpp deleted file mode 100644 index 88d9801..0000000 --- a/project2/sqlWriter.cpp +++ /dev/null @@ -1,131 +0,0 @@ -#include "sqlWriter.h" -#include -#include "sqlVariableBinder.h" - -DynamicSql::SqlWriter::SqlWriter() -{ -} - -DynamicSql::SqlWriter::~SqlWriter() -{ -} - -DynamicSql::SqlCommand::SqlCommand(const xmlpp::Element * N) -{ - BOOST_FOREACH(xmlpp::Node * n, N->get_children()) { - const xmlpp::TextNode * t = dynamic_cast(n); - if (t) { - writers.push_back(new SqlText(t)); - } - const xmlpp::Element * e = dynamic_cast(n); - if (e) { - if (e->get_name() == "filter") { - SqlFilterPtr f = new SqlFilter(e); - writers.push_back(f); - filters.insert(Filters::value_type(f->name, f)); - } - else if (e->get_name() == "param") { - writers.push_back(new SqlParameter(e)); - } - } - } -} - -Glib::ustring -DynamicSql::SqlCommand::getSqlFor(const Glib::ustring & f) const -{ - BOOST_FOREACH(const SqlCommand::Filters::value_type & filter, filters) { - filter.second->active = (filter.second->name == f); - } - Glib::ustring sql; - writeSql(sql); - return sql; -} - -void -DynamicSql::SqlCommand::writeSql(Glib::ustring & sql) const -{ - BOOST_FOREACH(const SqlWriterPtr & w, writers) { - w->writeSql(sql); - } -} - -void -DynamicSql::SqlCommand::bindParams(DB::Command * cmd, unsigned int & offset) const -{ - BOOST_FOREACH(const SqlWriterPtr & w, writers) { - w->bindParams(cmd, offset); - } -} - -DynamicSql::SqlFilter::SqlFilter(const xmlpp::Element * N) : - name(N->get_attribute_value("name")), - active(false) -{ - BOOST_FOREACH(xmlpp::Node * n, N->get_children()) { - const xmlpp::TextNode * t = dynamic_cast(n); - if (t) { - writers.push_back(new SqlText(t)); - } - const xmlpp::Element * e = dynamic_cast(n); - if (e) { - if (e->get_name() == "param") { - writers.push_back(new SqlParameter(e)); - } - } - } -} - -void -DynamicSql::SqlFilter::writeSql(Glib::ustring & sql) const -{ - if (active) { - BOOST_FOREACH(const SqlWriterPtr & w, writers) { - w->writeSql(sql); - } - } -} - -void -DynamicSql::SqlFilter::bindParams(DB::Command * cmd, unsigned int & offset) const -{ - if (active) { - BOOST_FOREACH(const SqlWriterPtr & w, writers) { - w->bindParams(cmd, offset); - } - } -} - -DynamicSql::SqlParameter::SqlParameter(const xmlpp::Element * n) : - Variable(n, boost::optional("local")) -{ -} - -void -DynamicSql::SqlParameter::writeSql(Glib::ustring & sql) const -{ - sql.append("?"); -} - -void -DynamicSql::SqlParameter::bindParams(DB::Command * cmd, unsigned int & offset) const -{ - boost::apply_visitor(SqlVariableBinder(cmd, offset++), (*this)); -} - -DynamicSql::SqlText::SqlText(const xmlpp::TextNode * n) : - text(n->get_content()) -{ -} - -void -DynamicSql::SqlText::writeSql(Glib::ustring & sql) const -{ - sql.append(text); -} - -void -DynamicSql::SqlText::bindParams(DB::Command *, unsigned int &) const -{ -} - diff --git a/project2/sqlWriter.h b/project2/sqlWriter.h deleted file mode 100644 index 7693e19..0000000 --- a/project2/sqlWriter.h +++ /dev/null @@ -1,63 +0,0 @@ -#ifndef SQLWRITER_H -#define SQLWRITER_H - -#include -#include -#include -#include -#include -#include -#include "variables.h" - -namespace DynamicSql { - class SqlWriter; - typedef boost::intrusive_ptr SqlWriterPtr; - typedef std::list Writers; - class SqlWriter : public IntrusivePtrBase { - public: - SqlWriter(); - virtual ~SqlWriter(); - virtual void writeSql(Glib::ustring & sql) const = 0; - virtual void bindParams(DB::Command *, unsigned int & offset) const = 0; - }; - class SqlText : public SqlWriter { - public: - SqlText(const xmlpp::TextNode *); - virtual void writeSql(Glib::ustring & sql) const; - virtual void bindParams(DB::Command *, unsigned int & offset) const; - - const Glib::ustring text; - }; - class SqlParameter : public SqlWriter, Variable { - public: - SqlParameter(const xmlpp::Element *); - virtual void writeSql(Glib::ustring & sql) const; - virtual void bindParams(DB::Command *, unsigned int & offset) const; - }; - class SqlFilter : public SqlWriter { - public: - SqlFilter(const xmlpp::Element *); - virtual void writeSql(Glib::ustring & sql) const; - virtual void bindParams(DB::Command *, unsigned int & offset) const; - - const Glib::ustring name; - bool active; - private: - Writers writers; - }; - typedef boost::intrusive_ptr SqlFilterPtr; - class SqlCommand : public SqlWriter { - public: - SqlCommand(const xmlpp::Element *); - virtual void writeSql(Glib::ustring & sql) const; - virtual void bindParams(DB::Command *, unsigned int & offset) const; - typedef std::multimap Filters; - Glib::ustring getSqlFor(const Glib::ustring & f) const; - private: - Filters filters; - Writers writers; - }; -} - -#endif - diff --git a/project2/streamRows.cpp b/project2/streamRows.cpp deleted file mode 100644 index 0be76cd..0000000 --- a/project2/streamRows.cpp +++ /dev/null @@ -1,106 +0,0 @@ -#include "streamRows.h" -#include "rowProcessor.h" - -StreamRows::StreamRows(const xmlpp::Element * p) : - DefinedColumns(p, "columns/column", boost::bind(&Column::make, _1, _2)), - RowSet(p), - fieldSep(p->get_attribute_value("fieldSep")[0]), - quoteChar(p->get_attribute_value("quoteChar")[0]), - keepBlankRows(p->get_attribute_value("keepBlankRows") == "true"), - countBlankRows(p->get_attribute_value("keepBlankRows") == "count"), - newline(p->get_attribute_value("newline")), - newlin(newline, 0, newline.length() - 1), - encoding(p->get_attribute_value("encoding")), - skipheader(atoi(p->get_attribute_value("skipheader").c_str())) -{ -} - -StreamRows::~StreamRows() -{ -} - -void -StreamRows::pushChar(gunichar c, ParseState & ps) const -{ - if ((!ps.inQuotes) && (c == *newline.rbegin()) && (ps.tok.compare(ps.tok.length() - newlin.length(), newlin.length(), newlin) == 0)) { - if (skipheader) { - ps.skipheader -= 1; - } - else { - ps.tok.erase(ps.tok.length() - newlin.length()); - if (!ps.tok.empty()) { - *ps.curCol++ = VariableType(ps.tok); - } - if (keepBlankRows || ps.curCol != ps.fields.begin()) { - while (ps.curCol != ps.fields.end()) { - *ps.curCol++ = Null(); - } - ps.process(ps.rp); - } - else if (countBlankRows) { - ps.blankRow(); - } - ps.curCol = ps.fields.begin(); - } - ps.tok.clear(); - } - else if (c == quoteChar) { - if (ps.prevWasQuote) { - ps.tok += c; - ps.prevWasQuote = false; - ps.inQuotes = !ps.inQuotes; - } - else { - ps.prevWasQuote = ps.inQuotes; - ps.inQuotes = !ps.inQuotes; - } - } - else if ((!ps.inQuotes) && (c == fieldSep)) { - ps.prevWasQuote = false; - if (skipheader == 0) { - *ps.curCol++ = VariableType(ps.tok); - } - ps.tok.clear(); - } - else { - ps.prevWasQuote = false; - ps.tok += c; - } -} - -StreamRows::ParseState::ParseState(const StreamRows * rows, const RowProcessor * proc) : - ColumnValues(rows), - sr(rows), - rp(proc), - inQuotes(false), - prevWasQuote(false), - curCol(fields.begin()) -{ -} - -StreamRows::ParseState::~ParseState() -{ - if (!std::uncaught_exception()) { - sr->end(*this); - } -} - -void -StreamRows::end(ParseState & ps) const -{ - if (!ps.tok.empty()) { - if (skipheader == 0) { - *ps.curCol++ = VariableType(ps.tok); - } - } - if (keepBlankRows || ps.curCol != ps.fields.begin()) { - while (ps.curCol != ps.fields.end()) { - *ps.curCol++ = Null(); - } - ps.process(ps.rp); - } - else if (countBlankRows) { - ps.blankRow(); - } -} - diff --git a/project2/streamRows.h b/project2/streamRows.h deleted file mode 100644 index 2d10116..0000000 --- a/project2/streamRows.h +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef STREAMROWS_H -#define STREAMROWS_H - -#include "variables.h" -#include "definedColumns.h" - -class RowProcessor; - -/// Base class for Project2 components that create a row set based on the contents of a byte stream -class StreamRows : public DefinedColumns, public RowSet { - public: - StreamRows(const xmlpp::Element * p); - ~StreamRows(); - - protected: - class ParseState : public ColumnValues { - public: - ParseState(const StreamRows *, const RowProcessor *); - ~ParseState(); - - const StreamRows * sr; - const RowProcessor * rp; - size_t skipheader; - bool inQuotes; - bool prevWasQuote; - Glib::ustring tok; - FieldValues::iterator curCol; - - friend class StreamRows; - }; - void pushChar(gunichar ch, ParseState &) const; - void end(ParseState &) const; - - public: - const gunichar fieldSep; - const gunichar quoteChar; - const bool keepBlankRows; - const bool countBlankRows; - const Glib::ustring newline; - const Glib::ustring newlin; - const std::string encoding; - const size_t skipheader; -}; - -#endif - diff --git a/project2/structExceptHandling.cpp b/project2/structExceptHandling.cpp deleted file mode 100644 index f87b870..0000000 --- a/project2/structExceptHandling.cpp +++ /dev/null @@ -1,53 +0,0 @@ -#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 deleted file mode 100644 index eabd384..0000000 --- a/project2/structExceptHandling.h +++ /dev/null @@ -1,18 +0,0 @@ -#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/tablepatch.cpp b/project2/tablepatch.cpp deleted file mode 100644 index f87f60e..0000000 --- a/project2/tablepatch.cpp +++ /dev/null @@ -1,438 +0,0 @@ -#include "tablepatch.h" -#include -#include -#include -#include -#include -#include - -using namespace DB; - -TablePatch::TablePatch(const Connection & wdb, const TablePatch::Table & s, const TablePatch::Table & d, - const TablePatch::Columns & c) : - src(s), - dest(d), - cols(c), - db(wdb) -{ - if (!src.length()) { - throw PatchCheckFailure(); - } - if (!dest.length()) { - throw PatchCheckFailure(); - } - if (!db.inTx()) { - throw PatchCheckFailure(); - } -} - -void -TablePatch::addKey(const TablePatch::Column & c) -{ - pk.insert(c); -} - -void -TablePatch::patch(const char * where, const char * order) -{ - if (pk.size() == 0) { - throw PatchCheckFailure(); - } - doDeletes(where, order); - doUpdates(where, order); - doInserts(order); -} - -void -TablePatch::doDeletes(const char * where, const char * order) -{ - switch (db.bulkDeleteStyle()) { - case BulkDeleteUsingSubSelect: - { - // ----------------------------------------------------------------- - // Build SQL to delete keys ---------------------------------------- - // ----------------------------------------------------------------- - Buffer toDelSql; - toDelSql.appendf("DELETE FROM %s WHERE (", - dest.c_str()); - foreach (PKI, pk, pki) { - if (pki != pk.begin()) { - toDelSql.append(", "); - } - toDelSql.appendf("%s.%s", - dest.c_str(), - pki->c_str()); - } - // ----------------------------------------------------------------- - // Build SQL to select keys to delete ------------------------------ - // ----------------------------------------------------------------- - toDelSql.append(") IN (SELECT "); - foreach (PKI, pk, pki) { - if (pki != pk.begin()) { - toDelSql.append(", "); - } - toDelSql.appendf("a.%s", - pki->c_str()); - } - toDelSql.appendf(" FROM %s a LEFT OUTER JOIN %s b ON ", - dest.c_str(), src.c_str()); - foreach (PKI, pk, pki) { - if (pki != pk.begin()) { - toDelSql.append(" AND "); - } - toDelSql.appendf(" a.%s = b.%s", - pki->c_str(), pki->c_str()); - } - foreach (PKI, pk, pki) { - if (pki == pk.begin()) { - toDelSql.append(" WHERE "); - } - else { - toDelSql.append(" AND "); - } - toDelSql.appendf(" b.%s IS NULL", - pki->c_str()); - } - if (where && *where) { - toDelSql.appendf(" AND %s", where); - } - if (order && *order) { - toDelSql.appendf(" ORDER BY %s", order); - } - toDelSql.append(")"); - ModifyCommand * del = db.newModifyCommand(toDelSql); - del->execute(); - delete del; - break; - } - case BulkDeleteUsingUsingAlias: - case BulkDeleteUsingUsing: - { - Buffer toDelSql; - toDelSql.appendf("DELETE FROM %s USING %s a LEFT OUTER JOIN %s b ", - (db.bulkDeleteStyle() == BulkDeleteUsingUsingAlias ? "a" : dest.c_str()), - dest.c_str(), src.c_str()); - foreach (PKI, pk, pki) { - if (pki != pk.begin()) { - toDelSql.append(" AND "); - } - else { - toDelSql.append(" ON "); - } - toDelSql.appendf(" a.%s = b.%s", - pki->c_str(), pki->c_str()); - } - foreach (PKI, pk, pki) { - if (pki != pk.begin()) { - toDelSql.append(" AND "); - } - else { - toDelSql.append(" WHERE "); - } - toDelSql.appendf(" b.%s IS NULL", - pki->c_str()); - } - if (where && *where) { - toDelSql.appendf(" AND %s", where); - } - if (order && *order) { - toDelSql.appendf(" ORDER BY %s", order); - } - ModifyCommand * del = db.newModifyCommand(toDelSql); - del->execute(); - delete del; - break; - } - } -} - -void -TablePatch::doUpdates(const char * where, const char * order) -{ - if (cols.size() == pk.size()) { - // Can't "change" anything... it's all part of the key - return; - } - switch (db.bulkUpdateStyle()) { - case BulkUpdateByIteration: - { - // ----------------------------------------------------------------- - // Build SQL for list of updates to perform ------------------------ - // ----------------------------------------------------------------- - Buffer toUpdSel; - toUpdSel.append("SELECT "); - foreach (Columns::const_iterator, cols, col) { - if (pk.find(*col) == pk.end()) { - toUpdSel.appendf("b.%s, ", - col->c_str()); - } - } - foreach (Columns::const_iterator, cols, col) { - if (pk.find(*col) != pk.end()) { - toUpdSel.appendf("b.%s, ", - col->c_str()); - } - } - toUpdSel.appendf("0 FROM %s a, %s b", - dest.c_str(), src.c_str()); - foreach (PKI, pk, pki) { - if (pki == pk.begin()) { - toUpdSel.append(" WHERE "); - } - else { - toUpdSel.append(" AND "); - } - toUpdSel.appendf(" a.%s = b.%s", - pki->c_str(), pki->c_str()); - } - if (where && *where) { - toUpdSel.appendf(" AND %s", where); - } - toUpdSel.append(" AND ("); - bool first = true; - foreach (Columns::const_iterator, cols, col) { - if (pk.find(*col) == pk.end()) { - if (!first) { - toUpdSel.append(" OR "); - } - first = false; - toUpdSel.appendf( - " (((CASE WHEN (a.%s IS NULL AND b.%s IS NULL) THEN 1 ELSE 0 END) \ - + (CASE WHEN(a.%s = b.%s) THEN 1 ELSE 0 END)) = 0)", - col->c_str(), col->c_str(), col->c_str(), col->c_str()); - } - } - toUpdSel.append(")"); - if (order && *order) { - toUpdSel.appendf(" ORDER BY %s", order); - } - // ----------------------------------------------------------------- - // Build SQL to perform updates ------------------------------------ - // ----------------------------------------------------------------- - Buffer updSql; - updSql.appendf("UPDATE %s SET ", - dest.c_str()); - first = true; - foreach (Columns::const_iterator, cols, col) { - if (pk.find(*col) == pk.end()) { - if (!first) { - updSql.append(", "); - } - first = false; - updSql.appendf(" %s = ?", - col->c_str()); - } - } - foreach (PKI, pk, pki) { - if (pki == pk.begin()) { - updSql.append(" WHERE "); - } - else { - updSql.append(" AND "); - } - updSql.appendf(" %s = ?", - pki->c_str()); - } - // ----------------------------------------------------------------- - // Iterator over update list make changes -------------------------- - // ----------------------------------------------------------------- - SelectCommand * toUpd = db.newSelectCommand(toUpdSel); - ModifyCommand * upd = db.newModifyCommand(updSql); - int cs = cols.size(); - toUpd->execute(); - for (int c = 0; c < cs; c += 1) { - (*toUpd)[c].rebind(upd, c); - } - while (toUpd->fetch()) { - upd->execute(false); - } - delete toUpd; - delete upd; - } - break; - case BulkUpdateUsingFromSrc: - { - // ----------------------------------------------------------------- - // Build SQL for list of updates to perform ------------------------ - // ----------------------------------------------------------------- - Buffer updSql; - updSql.appendf("UPDATE %s a SET ", - dest.c_str()); - bool first = true; - foreach (Columns::const_iterator, cols, col) { - if (pk.find(*col) == pk.end()) { - if (!first) { - updSql.append(", "); - } - first = false; - updSql.appendf(" %s = b.%s ", - col->c_str(), col->c_str()); - } - } - updSql.appendf(" FROM %s b ", - src.c_str()); - foreach (PKI, pk, pki) { - if (pki == pk.begin()) { - updSql.append(" WHERE "); - } - else { - updSql.append(" AND "); - } - updSql.appendf(" a.%s = b.%s ", - pki->c_str(), pki->c_str()); - } - updSql.append(" AND ("); - first = true; - foreach (Columns::const_iterator, cols, col) { - if (pk.find(*col) == pk.end()) { - if (!first) { - updSql.append(" OR "); - } - first = false; - updSql.appendf( - " (((CASE WHEN (a.%s IS NULL AND b.%s IS NULL) THEN 1 ELSE 0 END) \ - + (CASE WHEN(a.%s = b.%s) THEN 1 ELSE 0 END)) = 0)", - col->c_str(), col->c_str(), - col->c_str(), col->c_str()); - } - } - updSql.append(")"); - if (where && *where) { - updSql.appendf(" AND %s ", where); - } - if (order && *order) { - updSql.appendf(" ORDER BY %s", order); - } - // ----------------------------------------------------------------- - // Execute the bulk update command --------------------------------- - // ----------------------------------------------------------------- - ModifyCommand * upd = db.newModifyCommand(updSql); - upd->execute(true); - delete upd; - break; - } - case BulkUpdateUsingJoin: - { - // ----------------------------------------------------------------- - // Build SQL for list of updates to perform ------------------------ - // ----------------------------------------------------------------- - Buffer updSql; - updSql.appendf("UPDATE %s a, %s b SET ", - dest.c_str(), src.c_str()); - bool first = true; - foreach (Columns::const_iterator, cols, col) { - if (pk.find(*col) == pk.end()) { - if (!first) { - updSql.append(", "); - } - first = false; - updSql.appendf(" a.%s = b.%s ", - col->c_str(), col->c_str()); - } - } - foreach (PKI, pk, pki) { - if (pki == pk.begin()) { - updSql.append(" WHERE "); - } - else { - updSql.append(" AND "); - } - updSql.appendf(" a.%s = b.%s ", - pki->c_str(), pki->c_str()); - } - updSql.append(" AND ("); - first = true; - foreach (Columns::const_iterator, cols, col) { - if (pk.find(*col) == pk.end()) { - if (!first) { - updSql.append(" OR "); - } - first = false; - updSql.appendf( - " (((CASE WHEN (a.%s IS NULL AND b.%s IS NULL) THEN 1 ELSE 0 END) \ - + (CASE WHEN(a.%s = b.%s) THEN 1 ELSE 0 END)) = 0)", - col->c_str(), col->c_str(), - col->c_str(), col->c_str()); - } - } - updSql.append(")"); - if (where && *where) { - updSql.appendf(" AND %s ", where); - } - if (order && *order) { - updSql.appendf(" ORDER BY %s", order); - } - // ----------------------------------------------------------------- - // Execute the bulk update command --------------------------------- - // ----------------------------------------------------------------- - ModifyCommand * upd = db.newModifyCommand(updSql); - upd->execute(true); - delete upd; - break; - } - } -} - -void -TablePatch::doInserts(const char * order) -{ - // ----------------------------------------------------------------- - // Build SQL for copying new records ------------------------------- - // ----------------------------------------------------------------- - Buffer toInsSql; - toInsSql.appendf("INSERT INTO %s", - dest.c_str()); - foreach (Columns::const_iterator, cols, col) { - if (col == cols.begin()) { - toInsSql.append("("); - } - else { - toInsSql.append(", "); - } - toInsSql.appendf("%s", - col->c_str()); - } - toInsSql.append(") SELECT "); - foreach (Columns::const_iterator, cols, col) { - if (col != cols.begin()) { - toInsSql.append(", "); - } - toInsSql.appendf("b.%s", - col->c_str()); - } - toInsSql.appendf(" FROM %s b LEFT OUTER JOIN %s a", - src.c_str(), dest.c_str()); - foreach (PKI, pk, pki) { - if (pki == pk.begin()) { - toInsSql.append(" ON "); - } - else { - toInsSql.append(" AND "); - } - toInsSql.appendf(" a.%s = b.%s", - pki->c_str(), pki->c_str()); - } - foreach (PKI, pk, pki) { - if (pki == pk.begin()) { - toInsSql.append(" WHERE "); - } - else { - toInsSql.append(" AND "); - } - toInsSql.appendf(" a.%s IS NULL", - pki->c_str()); - } - if (order && *order) { - toInsSql.appendf(" ORDER BY %s", order); - } - ModifyCommand * ins = db.newModifyCommand(toInsSql); - ins->execute(); - delete ins; -} - -const char * -TablePatch::PatchCheckFailure::what() const throw() -{ - return "Santiy checks failed: check table names and keys"; -} - diff --git a/project2/tablepatch.h b/project2/tablepatch.h deleted file mode 100644 index 0174294..0000000 --- a/project2/tablepatch.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef TABLEPATCH_H -#define TABLEPATCH_H - -#include -#include -#include -#include -#include -#include - -class TablePatch { - public: - typedef std::string Table; - typedef std::string Column; - typedef std::set Columns; - typedef Columns PrimaryKey; - typedef PrimaryKey::const_iterator PKI; - - class PatchCheckFailure : public std::exception { - public: - const char * what() const throw(); - }; - - TablePatch(const DB::Connection & db, const Table & src, const Table & dest, const Columns & cols); - - void addKey(const Column & col); - void patch(const char * where, const char * order); - - private: - void doDeletes(const char * where, const char * order); - void doUpdates(const char * where, const char * order); - void doInserts(const char * order); - - Table src; - Table dest; - PrimaryKey pk; - Columns cols; - const DB::Connection &db; -}; - -#endif - diff --git a/project2/task.cpp b/project2/task.cpp deleted file mode 100644 index 5f828ef..0000000 --- a/project2/task.cpp +++ /dev/null @@ -1,13 +0,0 @@ -#include "task.h" -#include - -Task::Task(const xmlpp::Element * p) : - SourceObject(p), - NoOutputExecute(p) -{ -} - -Task::~Task() -{ -} - diff --git a/project2/task.h b/project2/task.h deleted file mode 100644 index 57697e2..0000000 --- a/project2/task.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef TASK_H -#define TASK_H - -#include -#include "sourceObject.h" -#include "noOutputExecute.h" - -/// Base class for Project2 components that perform some specific task -class Task : public NoOutputExecute { - public: - Task(const xmlpp::Element * p); - virtual ~Task(); - virtual void execute() const = 0; -}; - -#endif - - diff --git a/project2/taskHost.cpp b/project2/taskHost.cpp deleted file mode 100644 index 63ab301..0000000 --- a/project2/taskHost.cpp +++ /dev/null @@ -1,53 +0,0 @@ -#include "taskHost.h" -#include "noOutputExecute.h" -#include "dataSource.h" -#include - -TaskHost::TaskHost(const boost::filesystem::path & file) : - XmlScriptParser(file, false), - SourceObject(get_document()->get_root_node()), - CheckHost(file), - IHaveSubTasks(get_document()->get_root_node()) -{ - loader.supportedStorers.insert(Storer::into(&tasks)); -} - -TaskHost::~TaskHost() -{ -} - -void -TaskHost::loadComplete(const CommonObjects * co) -{ - IHaveSubTasks::loadComplete(co); -} - -void -TaskHost::execute() const -{ - parseDocument(); - try { - run(tasks); - commitAll(); - } - catch (...) { - rollbackAll(); - } -} - -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 deleted file mode 100644 index ca8275c..0000000 --- a/project2/taskHost.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef TASKHOST_H -#define TASKHOST_H - -#include "xmlStorage.h" -#include "xmlScriptParser.h" -#include "checkHost.h" -#include "iHaveSubTasks.h" - -class NoOutputExecute; -class DataSource; - -class TaskHost : virtual public XmlScriptParser, public IHaveSubTasks, virtual public CheckHost { - protected: - TaskHost(const boost::filesystem::path & file); - virtual ~TaskHost(); - - void loadComplete(const CommonObjects *); - void execute() const; - - Tasks tasks; - - private: - void commitAll() const; - void rollbackAll() const; -}; - -#endif - diff --git a/project2/transform.cpp b/project2/transform.cpp deleted file mode 100644 index 37524a0..0000000 --- a/project2/transform.cpp +++ /dev/null @@ -1,37 +0,0 @@ -#include "transform.h" -#include "logger.h" -#include - -TransformChainLink::~TransformChainLink() -{ -} - -typedef std::map > TransformLoaderMap; -void -TransformSource::addTarget(TransformChainLinkPtr tcl, const xmlpp::Element * e) -{ - BOOST_FOREACH(const TransformLoaderMap::value_type & tl, *LoaderBase::objLoaders()) { - 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 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(t.first.get())) { - tr->doTransforms(); - } - } -} - diff --git a/project2/transform.h b/project2/transform.h deleted file mode 100644 index ded356b..0000000 --- a/project2/transform.h +++ /dev/null @@ -1,70 +0,0 @@ -#ifndef TRANSFORM_H -#define TRANSFORM_H - -#include -#include "intrusivePtrBase.h" -#include "xmlObjectLoader.h" -#include - -class TransformChainLink : public virtual IntrusivePtrBase { - public: - virtual ~TransformChainLink() = 0; -}; -typedef boost::intrusive_ptr TransformChainLinkPtr; - -class Transform; -typedef boost::intrusive_ptr 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 targets; -}; -typedef boost::intrusive_ptr TransformSourcePtr; - -template -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 create() const = 0; -}; - -template -class TransformLoaderImpl : public TransformLoader { - public: - boost::intrusive_ptr create() const { - return new T(); - } -}; -#define DECLARE_TRANSFORM(T) DECLARE_COMPONENT_LOADER(#T, T, TransformLoader) - -template -class TransformImpl : public Transform { - public: - virtual void transform(const Source *, Destination *) const = 0; - void transform(const TransformSource * src, TransformChainLink * dest) const - { - transform(dynamic_cast *>(src)->operator const Source *(), dynamic_cast(dest)); - } - bool canTransform(const TransformSource * src, TransformChainLink * dest) const - { - return (dynamic_cast *>(src) && dynamic_cast(dest)); - } -}; - -#endif - diff --git a/project2/transformHtml.cpp b/project2/transformHtml.cpp deleted file mode 100644 index eae1c27..0000000 --- a/project2/transformHtml.cpp +++ /dev/null @@ -1,30 +0,0 @@ -#include "transformHtml.h" -#include "logger.h" -#include -#include -#include - -class TransformXmlToHtml : public TransformImpl { - public: - void transform(const xmlpp::Document * cdata, HtmlDocument * result) const - { - xmlpp::Document * data = const_cast(cdata); - typedef boost::shared_ptr 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 deleted file mode 100644 index 25bd0d5..0000000 --- a/project2/transformHtml.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef HTMLDOCUMENT_H -#define HTMLDOCUMENT_H - -#include "transform.h" -#include - -class HtmlDocument; -class HtmlDocument : public SourceOf { - public: - htmlDocPtr doc; - operator const HtmlDocument * () const { return this; } -}; - -#endif - diff --git a/project2/transformText.cpp b/project2/transformText.cpp deleted file mode 100644 index 5ba03cc..0000000 --- a/project2/transformText.cpp +++ /dev/null @@ -1,38 +0,0 @@ -#include "transformText.h" -#include -#include "transformHtml.h" -#include -#include - -class TransformHtmlToText : public TransformImpl { - public: - void transform(const HtmlDocument * cdoc, TextDocument * str) const - { - xmlDoc * doc = const_cast(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 deleted file mode 100644 index 9a81c89..0000000 --- a/project2/transformText.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef TEXTDOCUMENT_H -#define TEXTDOCUMENT_H - -#include "transform.h" -#include - -class TextDocument : public SourceOf { - public: - std::string doc; - operator const TextDocument * () const { return this; } -}; - - -#endif - diff --git a/project2/url/Jamfile.jam b/project2/url/Jamfile.jam new file mode 100644 index 0000000..6e6dc36 --- /dev/null +++ b/project2/url/Jamfile.jam @@ -0,0 +1,20 @@ +alias libxmlpp : : : : + "`pkg-config --cflags libxml++-2.6`" + "`pkg-config --libs libxml++-2.6`" ; +lib curl : : curl ; + +lib p2url : + urlRows.cpp + curlHelper.cpp + ../../libmisc/curlsup.cpp + : + ../common//p2common + ../files//p2files + ../../libmisc + libxmlpp + curl + : : + . + curl + ; + diff --git a/project2/url/curlHelper.cpp b/project2/url/curlHelper.cpp new file mode 100644 index 0000000..7c204aa --- /dev/null +++ b/project2/url/curlHelper.cpp @@ -0,0 +1,45 @@ +#include "curlHelper.h" + +CurlHelper::CurlHelper(const xmlpp::Element * p) : + url(p, "url"), + userAgent(p, "useragent", false, "project2/0.3"), + cookieJar(p, "cookiejar", false), + proxy(p, "proxy", false), + method(p, "method", false), + userName(p, "username", false), + password(p, "password", false), + timeout(p, "timeout", false, Variable(6000)) +{ +} + +CurlHelper::~CurlHelper() +{ +} + +CurlHandle::Ptr +CurlHelper::newCurl() const +{ + CurlHandle::Ptr c = new CurlHandle(); + c->setopt(CURLOPT_FOLLOWLOCATION, 1); + c->setopt(CURLOPT_ENCODING, "deflate, gzip"); + setopt_s(c, CURLOPT_URL, url()); + setopt_s(c, CURLOPT_USERAGENT, userAgent()); + setopt_s(c, CURLOPT_PROXY, proxy()); + setopt_s(c, CURLOPT_COOKIEFILE, cookieJar()); + setopt_s(c, CURLOPT_COOKIEJAR, cookieJar()); + setopt_l(c, CURLOPT_TIMEOUT_MS, timeout()); + return c; +} + +void +CurlHelper::setopt_s(CurlHandle::Ptr c, CURLoption o, const char * v) +{ + c->setopt(o, v); +} + +void +CurlHelper::setopt_l(CurlHandle::Ptr c, CURLoption o, int64_t v) +{ + c->setopt(o, (long)v); +} + diff --git a/project2/url/curlHelper.h b/project2/url/curlHelper.h new file mode 100644 index 0000000..afebcdc --- /dev/null +++ b/project2/url/curlHelper.h @@ -0,0 +1,33 @@ +#ifndef CURLHELPER_H +#define CURLHELPER_H + +#include +#include "variables.h" +#include "../libmisc/curlsup.h" + +/// Project2 helper component to provide common access to remote resources via libcurl +class CurlHelper { + public: + CurlHelper(const xmlpp::Element * p); + ~CurlHelper(); + + const Variable url; + + protected: + CurlHandle::Ptr newCurl() const; + + private: + static void setopt_s(CurlHandle::Ptr, CURLoption, const char *); + static void setopt_l(CurlHandle::Ptr, CURLoption, int64_t); + + const Variable userAgent; + const Variable cookieJar; + const Variable proxy; + const Variable method; + const Variable userName; + const Variable password; + const Variable timeout; +}; + +#endif + diff --git a/project2/url/urlRows.cpp b/project2/url/urlRows.cpp new file mode 100644 index 0000000..f8f7eed --- /dev/null +++ b/project2/url/urlRows.cpp @@ -0,0 +1,69 @@ +#include "urlRows.h" +#include "rowProcessor.h" +#include "xmlObjectLoader.h" +#include "exceptions.h" +#include "../libmisc/curlsup.h" +#include +#include + +DECLARE_LOADER("urlrows", UrlRows); + +UrlRows::UrlRows(const xmlpp::Element * p) : + StreamRows(p), + CurlHelper(p), + convertRequired(encoding != "utf-8") +{ +} + +UrlRows::~UrlRows() +{ +} + +void +UrlRows::loadComplete(const CommonObjects *) +{ +} + +size_t +UrlRows::handleDataHelper(const char * ptr, size_t size, size_t nmemb, void *stream) +{ + const callback * cb = static_cast(stream); + size_t used = cb->urlRows->handleData(cb->ps, ptr, size * nmemb); + return used; +} + +size_t +UrlRows::handleData(ParseState & ps, const char * bytes, size_t bytesLen) const +{ + size_t used = 0, len = 0; + const gchar * utf8 = convertRequired ? g_convert(bytes, bytesLen, "utf-8", encoding.c_str(), &used, &len, NULL) : bytes; + for (const gchar * iter = utf8; *iter; iter = g_utf8_next_char(iter)) { + this->pushChar(*iter, ps); + } + if (convertRequired) { + // We allocated it.. sooo.... + free(const_cast(utf8)); + return used; + } + else { + return bytesLen; + } +} + +void +UrlRows::execute(const Glib::ustring &, const RowProcessor * rp) const +{ + CurlHandle::Ptr c = newCurl(); + callback cb(this, rp); + c->setopt(CURLOPT_WRITEDATA, &cb); + c->setopt(CURLOPT_WRITEFUNCTION, &handleDataHelper); + c->perform(); +} + +UrlRows::callback::callback(const UrlRows * u, const RowProcessor * r) : + urlRows(u), + rp(r), + ps(u, r) +{ +} + diff --git a/project2/url/urlRows.h b/project2/url/urlRows.h new file mode 100644 index 0000000..98273bd --- /dev/null +++ b/project2/url/urlRows.h @@ -0,0 +1,34 @@ +#ifndef URLROWS_H +#define URLROWS_H + +#include +#include +#include +#include +#include "streamRows.h" +#include "curlHelper.h" + +/// Project2 component to create a row set from the contents of a file accessible via libcurl +class UrlRows : public StreamRows, CurlHelper { + public: + UrlRows(const xmlpp::Element * p); + ~UrlRows(); + + virtual void loadComplete(const CommonObjects *); + void execute(const Glib::ustring &, const RowProcessor *) const; + + private: + struct callback { + callback(const UrlRows * urlRows, const RowProcessor * rp); + const UrlRows * urlRows; + const RowProcessor * rp; + mutable ParseState ps; + }; + static size_t handleDataHelper(const char * ptr, size_t size, size_t nmemb, void * stream); + size_t handleData(ParseState &, const char * bytes, size_t bytesLen) const; + bool convertRequired; + +}; + +#endif + diff --git a/project2/urlRows.cpp b/project2/urlRows.cpp deleted file mode 100644 index f8f7eed..0000000 --- a/project2/urlRows.cpp +++ /dev/null @@ -1,69 +0,0 @@ -#include "urlRows.h" -#include "rowProcessor.h" -#include "xmlObjectLoader.h" -#include "exceptions.h" -#include "../libmisc/curlsup.h" -#include -#include - -DECLARE_LOADER("urlrows", UrlRows); - -UrlRows::UrlRows(const xmlpp::Element * p) : - StreamRows(p), - CurlHelper(p), - convertRequired(encoding != "utf-8") -{ -} - -UrlRows::~UrlRows() -{ -} - -void -UrlRows::loadComplete(const CommonObjects *) -{ -} - -size_t -UrlRows::handleDataHelper(const char * ptr, size_t size, size_t nmemb, void *stream) -{ - const callback * cb = static_cast(stream); - size_t used = cb->urlRows->handleData(cb->ps, ptr, size * nmemb); - return used; -} - -size_t -UrlRows::handleData(ParseState & ps, const char * bytes, size_t bytesLen) const -{ - size_t used = 0, len = 0; - const gchar * utf8 = convertRequired ? g_convert(bytes, bytesLen, "utf-8", encoding.c_str(), &used, &len, NULL) : bytes; - for (const gchar * iter = utf8; *iter; iter = g_utf8_next_char(iter)) { - this->pushChar(*iter, ps); - } - if (convertRequired) { - // We allocated it.. sooo.... - free(const_cast(utf8)); - return used; - } - else { - return bytesLen; - } -} - -void -UrlRows::execute(const Glib::ustring &, const RowProcessor * rp) const -{ - CurlHandle::Ptr c = newCurl(); - callback cb(this, rp); - c->setopt(CURLOPT_WRITEDATA, &cb); - c->setopt(CURLOPT_WRITEFUNCTION, &handleDataHelper); - c->perform(); -} - -UrlRows::callback::callback(const UrlRows * u, const RowProcessor * r) : - urlRows(u), - rp(r), - ps(u, r) -{ -} - diff --git a/project2/urlRows.h b/project2/urlRows.h deleted file mode 100644 index 98273bd..0000000 --- a/project2/urlRows.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef URLROWS_H -#define URLROWS_H - -#include -#include -#include -#include -#include "streamRows.h" -#include "curlHelper.h" - -/// Project2 component to create a row set from the contents of a file accessible via libcurl -class UrlRows : public StreamRows, CurlHelper { - public: - UrlRows(const xmlpp::Element * p); - ~UrlRows(); - - virtual void loadComplete(const CommonObjects *); - void execute(const Glib::ustring &, const RowProcessor *) const; - - private: - struct callback { - callback(const UrlRows * urlRows, const RowProcessor * rp); - const UrlRows * urlRows; - const RowProcessor * rp; - mutable ParseState ps; - }; - static size_t handleDataHelper(const char * ptr, size_t size, size_t nmemb, void * stream); - size_t handleData(ParseState &, const char * bytes, size_t bytesLen) const; - bool convertRequired; - -}; - -#endif - diff --git a/project2/uuid.cpp b/project2/uuid.cpp deleted file mode 100644 index ddc0e50..0000000 --- a/project2/uuid.cpp +++ /dev/null @@ -1,129 +0,0 @@ -#ifdef BOOST_UUID -# include -# if BOOST_VERSION < 104200 -# error "Boost UUIDs required v1.42 or above" -# else -# include -# endif -#include -#include -#include -#define uuid_impl boost::uuids::uuid -#include "uuid.h" - -UUID::UUID() -{ - _uuid = new boost::uuids::uuid(boost::uuids::nil_generator()()); -} - -UUID::UUID(const UUID & other) -{ - _uuid = new boost::uuids::uuid(*other._uuid); -} - -UUID::UUID(const std::string & str) -{ - _uuid = new boost::uuids::uuid(boost::uuids::string_generator()(str)); -} - -UUID -UUID::generate_random() -{ - UUID u; - u._uuid = new boost::uuids::uuid(boost::uuids::random_generator()()); - return u; -} - -bool -UUID::is_nil() const -{ - return _uuid->is_nil(); -} - -std::string -UUID::str() const -{ - return boost::lexical_cast(*_uuid); -} - -UUID & -UUID::operator=(const std::string & str) -{ - *_uuid = boost::uuids::string_generator()(str); - return *this; -} - -#endif - -#ifdef OSSP_UUID -# include -#define uuid_impl uuid -#include "uuid.h" - -UUID::UUID() -{ - _uuid = new uuid(); -} - -UUID::UUID(const UUID & other) -{ - _uuid = new uuid(*other._uuid); -} - -UUID::UUID(const std::string & str) -{ - _uuid = new uuid(); - _uuid->import(str.c_str()); -} - -UUID -UUID::generate_random() -{ - UUID u; - u._uuid->make(UUID_MAKE_V4); - return u; -} - -bool -UUID::is_nil() const -{ - return _uuid->isnil(); -} - -std::string -UUID::str() const -{ - char * s = _uuid->string(); - std::string r(s); - free(s); - return r; -} - -UUID & -UUID::operator=(const std::string & str) -{ - _uuid->import(str.c_str()); - return *this; -} - -#endif - -// Shared implementation -UUID::~UUID() -{ - delete _uuid; -} - -bool -UUID::operator!=(const UUID & other) const -{ - return *_uuid != *other._uuid; -} - -UUID & -UUID::operator=(const UUID & other) -{ - *_uuid = *other._uuid; - return *this; -} - diff --git a/project2/uuid.h b/project2/uuid.h deleted file mode 100644 index 4c60ae5..0000000 --- a/project2/uuid.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef UUID_H -#define UUID_H - -#include - -#ifndef uuid_impl -class uuid_impl; -#endif - -class UUID { - public: - UUID(); - ~UUID(); - UUID(const UUID &); - UUID(const std::string &); - - static UUID generate_random(); - - UUID & operator=(const UUID & other); - UUID & operator=(const std::string &); - - bool operator!=(const UUID & other) const; - bool is_nil() const; - - std::string str() const; - - private: - uuid_impl * _uuid; -}; - -#endif diff --git a/project2/uuid/Jamfile.jam b/project2/uuid/Jamfile.jam new file mode 100644 index 0000000..a0d160b --- /dev/null +++ b/project2/uuid/Jamfile.jam @@ -0,0 +1,12 @@ +lib osspuuid : : ossp-uuid++ ; + +lib p2uuid : + uuid.cpp + : + ossp:OSSP_UUID + boost:BOOST_UUID + ossp:osspuuid + : : + . + ; + diff --git a/project2/uuid/uuid.cpp b/project2/uuid/uuid.cpp new file mode 100644 index 0000000..ddc0e50 --- /dev/null +++ b/project2/uuid/uuid.cpp @@ -0,0 +1,129 @@ +#ifdef BOOST_UUID +# include +# if BOOST_VERSION < 104200 +# error "Boost UUIDs required v1.42 or above" +# else +# include +# endif +#include +#include +#include +#define uuid_impl boost::uuids::uuid +#include "uuid.h" + +UUID::UUID() +{ + _uuid = new boost::uuids::uuid(boost::uuids::nil_generator()()); +} + +UUID::UUID(const UUID & other) +{ + _uuid = new boost::uuids::uuid(*other._uuid); +} + +UUID::UUID(const std::string & str) +{ + _uuid = new boost::uuids::uuid(boost::uuids::string_generator()(str)); +} + +UUID +UUID::generate_random() +{ + UUID u; + u._uuid = new boost::uuids::uuid(boost::uuids::random_generator()()); + return u; +} + +bool +UUID::is_nil() const +{ + return _uuid->is_nil(); +} + +std::string +UUID::str() const +{ + return boost::lexical_cast(*_uuid); +} + +UUID & +UUID::operator=(const std::string & str) +{ + *_uuid = boost::uuids::string_generator()(str); + return *this; +} + +#endif + +#ifdef OSSP_UUID +# include +#define uuid_impl uuid +#include "uuid.h" + +UUID::UUID() +{ + _uuid = new uuid(); +} + +UUID::UUID(const UUID & other) +{ + _uuid = new uuid(*other._uuid); +} + +UUID::UUID(const std::string & str) +{ + _uuid = new uuid(); + _uuid->import(str.c_str()); +} + +UUID +UUID::generate_random() +{ + UUID u; + u._uuid->make(UUID_MAKE_V4); + return u; +} + +bool +UUID::is_nil() const +{ + return _uuid->isnil(); +} + +std::string +UUID::str() const +{ + char * s = _uuid->string(); + std::string r(s); + free(s); + return r; +} + +UUID & +UUID::operator=(const std::string & str) +{ + _uuid->import(str.c_str()); + return *this; +} + +#endif + +// Shared implementation +UUID::~UUID() +{ + delete _uuid; +} + +bool +UUID::operator!=(const UUID & other) const +{ + return *_uuid != *other._uuid; +} + +UUID & +UUID::operator=(const UUID & other) +{ + *_uuid = *other._uuid; + return *this; +} + diff --git a/project2/uuid/uuid.h b/project2/uuid/uuid.h new file mode 100644 index 0000000..4c60ae5 --- /dev/null +++ b/project2/uuid/uuid.h @@ -0,0 +1,31 @@ +#ifndef UUID_H +#define UUID_H + +#include + +#ifndef uuid_impl +class uuid_impl; +#endif + +class UUID { + public: + UUID(); + ~UUID(); + UUID(const UUID &); + UUID(const std::string &); + + static UUID generate_random(); + + UUID & operator=(const UUID & other); + UUID & operator=(const std::string &); + + bool operator!=(const UUID & other) const; + bool is_nil() const; + + std::string str() const; + + private: + uuid_impl * _uuid; +}; + +#endif diff --git a/project2/validDateCheck.cpp b/project2/validDateCheck.cpp deleted file mode 100644 index 410a003..0000000 --- a/project2/validDateCheck.cpp +++ /dev/null @@ -1,68 +0,0 @@ -#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/variableConvert.cpp b/project2/variableConvert.cpp deleted file mode 100644 index b144175..0000000 --- a/project2/variableConvert.cpp +++ /dev/null @@ -1,197 +0,0 @@ -#include "variables.h" -#include "exceptions.h" -#include -#include -#include - -template -void -deleter(const void * t) -{ - delete static_cast(t); -} - -template -const T * -set(const VariableType * var, const T * t, VariableType::Freer f = deleter) -{ - if (var->freer) { var->freer(var->convertCache); } - var->convertCache = t; - var->freer = f; - return t; -} -template -const T * -set(const VariableType * var, const T * t) -{ - return ::set(var, t, deleter); -} - -SimpleMessageException(InvalidConversionTo); - -class NullVariable : std::runtime_error { - public: - NullVariable() : std::runtime_error("Variable has null value where one is required") { - } -}; - -// Convert to Glib::ustring -class ConvertVisitorGlibUstring : public boost::static_visitor { - public: - ConvertVisitorGlibUstring(const VariableType * v) : var(v) { - } - const Glib::ustring & operator()(const Glib::ustring & r) const { - return *::set(var, &r, NULL); - } - const Glib::ustring & operator()(const boost::posix_time::ptime & r) const { - return *::set(var, new Glib::ustring(boost::posix_time::to_iso_extended_string(r))); - } - const Glib::ustring & operator()(const Null &) const { - throw NullVariable(); - } - template - const Glib::ustring & operator()(const T & r) const { - return *::set(var, new Glib::ustring(boost::lexical_cast(r))); - } - private: - const VariableType * var; -}; -// Convert to STL std::string -class ConvertVisitorStdString : public boost::static_visitor { - public: - ConvertVisitorStdString(const VariableType * v) : var(v) { - } - const std::string & operator()(const Glib::ustring & r) const { - return *::set(var, new std::string(r)); - } - const std::string & operator()(const boost::posix_time::ptime & r) const { - return *::set(var, new std::string(boost::posix_time::to_iso_extended_string(r))); - } - const std::string & operator()(const Null &) const { - throw NullVariable(); - } - template - const std::string & operator()(const T & r) const { - return *::set(var, new std::string(boost::lexical_cast(r))); - } - private: - const VariableType * var; -}; -// Convert to char * (with std::string storage) -class ConvertVisitorCharStar : public boost::static_visitor { - public: - ConvertVisitorCharStar(const VariableType * v) : var(v) { - } - const char * operator()(const Glib::ustring & r) const { - return ::set(var, &r, NULL)->c_str(); - } - const char * operator()(const boost::posix_time::ptime & r) const { - return ::set(var, new std::string(boost::posix_time::to_iso_extended_string(r)))->c_str(); - } - const char * operator()(const Null &) const { - return ::set(var, NULL, NULL); - } - template - const char * operator()(const T & r) const { - return ::set(var, new std::string(boost::lexical_cast(r)))->c_str(); - } - private: - const VariableType * var; -}; -// Convert to unsigned char * (with std::basic_string storage / std::string) -class ConvertVisitorUCharStar : public boost::static_visitor { - public: - ConvertVisitorUCharStar(const VariableType * v) : var(v) { - } - const unsigned char * operator()(const Glib::ustring & r) const { - return reinterpret_cast(set(var, &r, NULL)->c_str()); - } - const unsigned char * operator()(const boost::posix_time::ptime & r) const { - return reinterpret_cast( - ::set(var, new std::string(boost::posix_time::to_iso_extended_string(r)))->c_str()); - } - const unsigned char * operator()(const Null &) const { - return ::set(var, NULL, NULL); - } - template - const unsigned char * operator()(const T & r) const { - return ::set(var, new std::basic_string(boost::lexical_cast >(r)))->c_str(); - } - private: - const VariableType * var; -}; -// Convert to generic type -template -class ConvertVisitor : public boost::static_visitor { - public: - ConvertVisitor(const VariableType * v) : var(v) { - } - DestType operator()(const Glib::ustring & r) const { - return boost::lexical_cast(r); - } - DestType operator()(const boost::posix_time::ptime &) const { - throw InvalidConversionTo(typeid(DestType).name()); - } - DestType operator()(const Null &) const { - throw NullVariable(); - } - template - DestType operator()(const T & r) const { - return boost::numeric_cast(r); - } - private: - const VariableType * var; -}; -// Convert to ptime -class ConvertVisitorDateTime : public boost::static_visitor { - public: - ConvertVisitorDateTime(const VariableType * v) : var(v) { - } - const boost::posix_time::ptime & operator()(const Glib::ustring & r) const { - return *::set(var, new boost::posix_time::ptime(boost::posix_time::time_from_string(r)), deleter); - } - const boost::posix_time::ptime & operator()(const boost::posix_time::ptime & r) const { - return r; - } - const boost::posix_time::ptime & operator()(const Null &) const { - throw NullVariable(); - } - template - const boost::posix_time::ptime & operator()(const T &) const { - throw InvalidConversionTo("DateTime"); - } - private: - const VariableType * var; -}; -VariableType::operator const Glib::ustring &() const -{ - return boost::apply_visitor(ConvertVisitorGlibUstring(this), *this); -} -VariableType::operator const std::string &() const -{ - return boost::apply_visitor(ConvertVisitorStdString(this), *this); -} -VariableType::operator const char *() const -{ - return boost::apply_visitor(ConvertVisitorCharStar(this), *this); -} -VariableType::operator const unsigned char *() const -{ - return boost::apply_visitor(ConvertVisitorUCharStar(this), *this); -} -VariableType::operator int32_t() const -{ - return boost::apply_visitor(ConvertVisitor(this), *this); -} -VariableType::operator int64_t() const -{ - return boost::apply_visitor(ConvertVisitor(this), *this); -} -VariableType::operator double() const -{ - return boost::apply_visitor(ConvertVisitor(this), *this); -} -VariableType::operator const boost::posix_time::ptime &() const -{ - return boost::apply_visitor(ConvertVisitorDateTime(this), *this); -} diff --git a/project2/variables-modconfig.cpp b/project2/variables-modconfig.cpp deleted file mode 100644 index 88fddd4..0000000 --- a/project2/variables-modconfig.cpp +++ /dev/null @@ -1,22 +0,0 @@ -#include "variables.h" -#include "xmlObjectLoader.h" -#include "xmlStorage.h" -#include "appEngine.h" - -/// Variable implementation to access platform configuration values -class VariableConfig : public VariableImplDyn { - public: - VariableConfig(const xmlpp::Element * e) : - VariableImplDyn(e), - name(e->get_attribute_value("name")) - { - } - VariableType value() const - { - return ApplicationEngine::getCurrent()->getCurrentConfig()->getValue(name); - } - private: - const Glib::ustring name; -}; -DECLARE_COMPONENT_LOADER("config", VariableConfig, VariableLoader); - diff --git a/project2/variables-modlocalparam.cpp b/project2/variables-modlocalparam.cpp deleted file mode 100644 index 24e1d54..0000000 --- a/project2/variables-modlocalparam.cpp +++ /dev/null @@ -1,31 +0,0 @@ -#include "variables.h" -#include "xmlObjectLoader.h" -#include "logger.h" -#include "xmlStorage.h" -#include "iHaveParameters.h" - -/// Variable implementation to access call parameters -class VariableLocalParam : public VariableImplDyn { - public: - VariableLocalParam(const xmlpp::Element * e) : - VariableImplDyn(e), - name(e->get_attribute_value("name")) - { - } - VariableType value() const - { - try { - return IHaveParameters::getScopedParameter(name); - } - catch (ParamNotFound) { - if (!defaultValue) { - throw; - } - return (*defaultValue)(); - } - } - private: - const Glib::ustring name; -}; -DECLARE_COMPONENT_LOADER("local", VariableLocalParam, VariableLoader); - diff --git a/project2/variables-modlookup.cpp b/project2/variables-modlookup.cpp deleted file mode 100644 index 85a1fbe..0000000 --- a/project2/variables-modlookup.cpp +++ /dev/null @@ -1,75 +0,0 @@ -#include "variables.h" -#include "safeMapFind.h" -#include "logger.h" -#include "rowProcessor.h" -#include "rowSet.h" -#include -#include "xmlObjectLoader.h" -#include "xmlStorage.h" - - -/// Variable implementation that looks up it's value in a map of key(s)/value pairs -class VariableLookup : public VariableImplDyn, public RowProcessor { - private: - typedef std::vector Key; - typedef std::map Map; - public: - class NotFound : public std::runtime_error { - public: - NotFound(const Key & k) : - std::runtime_error(mklist(k)) { - } - static std::string mklist(const Key & k) { - std::string l("("); - for (Key::const_iterator kp = k.begin(); kp != k.end(); kp++) { - if (kp != k.begin()) l += ", "; - l += kp->operator const std::string &(); - } - l += ")"; - return l; - } - }; - VariableLookup(const xmlpp::Element * e) : - VariableImplDyn(e), - RowProcessor(e), - name(e->get_attribute_value("name")) - { - LoaderBase loader(true); - loader.supportedStorers.insert(Storer::into(&rowSets)); - loader.collectAll(e, false); - } - VariableType value() const - { - if (map.empty()) { - fillCache(); - } - Key k; - k.reserve(parameters.size()); - BOOST_FOREACH(const Parameters::value_type & p, parameters) { - k.push_back(p.second); - } - return safeMapFind(map, k)->second; - } - private: - void fillCache() const - { - BOOST_FOREACH(const RowSets::value_type & rs, rowSets) { - rs->execute(filter, this); - } - Logger()->messagef(LOG_DEBUG, "%s: %s has filled cached with %zu items", - __PRETTY_FUNCTION__, name.c_str(), map.size()); - } - void rowReady(const RowState * rs) const - { - Key k; - BOOST_FOREACH(const Parameters::value_type & p, parameters) { - k.push_back(rs->getCurrentValue(p.first)); - } - map[k] = rs->getCurrentValue(name); - } - mutable Map map; - typedef ANONSTORAGEOF(RowSet) RowSets; - RowSets rowSets; - const Glib::ustring name; -}; -DECLARE_COMPONENT_LOADER("lookup", VariableLookup, VariableLoader); diff --git a/project2/variables-modparam.cpp b/project2/variables-modparam.cpp deleted file mode 100644 index 0b205db..0000000 --- a/project2/variables-modparam.cpp +++ /dev/null @@ -1,30 +0,0 @@ -#include "variables.h" -#include "xmlObjectLoader.h" -#include "xmlStorage.h" -#include "appEngine.h" - -/// Variable implementation to access call parameters -class VariableParam : public VariableImplDyn { - public: - VariableParam(const xmlpp::Element * e) : - VariableImplDyn(e), - name(e->get_attribute_value("name")) - { - } - VariableType value() const - { - try { - return ApplicationEngine::getCurrent()->env()->getParamQuery(name); - } - catch (ParamNotFound) { - if (!defaultValue) { - throw; - } - return (*defaultValue)(); - } - } - private: - const Glib::ustring name; -}; -DECLARE_COMPONENT_LOADER("param", VariableParam, VariableLoader); - diff --git a/project2/variables-modsession.cpp b/project2/variables-modsession.cpp deleted file mode 100644 index 963a105..0000000 --- a/project2/variables-modsession.cpp +++ /dev/null @@ -1,30 +0,0 @@ -#include "variables.h" -#include "xmlObjectLoader.h" -#include "xmlStorage.h" -#include "appEngine.h" - -/// Variable implementation to access session contents -class VariableSession : public VariableImplDyn { - public: - VariableSession(const xmlpp::Element * e) : - VariableImplDyn(e), - name(e->get_attribute_value("name")) - { - } - VariableType value() const - { - try { - return ApplicationEngine::getCurrent()->session()->GetValue(name); - } - catch (Session::VariableNotFound) { - if (!defaultValue) { - throw; - } - return (*defaultValue)(); - } - } - private: - const Glib::ustring name; -}; -DECLARE_COMPONENT_LOADER("session", VariableSession, VariableLoader); - diff --git a/project2/variables-moduri.cpp b/project2/variables-moduri.cpp deleted file mode 100644 index 00fb7bf..0000000 --- a/project2/variables-moduri.cpp +++ /dev/null @@ -1,30 +0,0 @@ -#include "variables.h" -#include "xmlObjectLoader.h" -#include "xmlStorage.h" -#include "appEngine.h" - -/// Variable implementation to access URI path fragments -class VariableUri : public VariableImplDyn { - public: - VariableUri(const xmlpp::Element * e) : - VariableImplDyn(e), - index(atoi(e->get_attribute_value("index").c_str())) - { - } - VariableType value() const - { - try { - return ApplicationEngine::getCurrent()->env()->getParamUri(index); - } - catch (UriElementOutOfRange) { - if (!defaultValue) { - throw; - } - return (*defaultValue)(); - } - } - private: - unsigned int index; -}; -DECLARE_COMPONENT_LOADER("uri", VariableUri, VariableLoader); - diff --git a/project2/variables.cpp b/project2/variables.cpp deleted file mode 100644 index 9108889..0000000 --- a/project2/variables.cpp +++ /dev/null @@ -1,381 +0,0 @@ -#include "variables.h" -#include "iHaveParameters.h" -#include "xmlObjectLoader.h" -#include "exceptions.h" -#include "appEngine.h" -#include "session.h" -#include "rowSet.h" -#include -#include -#include -#include -#include -#include -#include -#include - -SimpleMessageException(UnknownVariableType); -SimpleMessageException(UnknownVariableSource); -SimpleMessageException(NoVariableDefinition); - -bool Null::operator<(const Null &) const -{ - return false; -} - -enum VT_typeID { - DefaultType, - String, - Int, - UInt, - LInt, - LUInt, - LLInt, - LLUInt, - Float, - Double, - DateTime, -}; - -static -VT_typeID -getVariableTypeFromName(const std::string & src) -{ - if (src.empty()) return String; - if (src == "string") return String; - if (src == "int") return Int; - if (src == "uint") return UInt; - if (src == "lint") return LInt; - if (src == "luint") return LUInt; - if (src == "llint") return LLInt; - if (src == "lluint") return LLUInt; - if (src == "float") return Float; - if (src == "double") return Double; - if (src == "datetime") return DateTime; - throw UnknownVariableType(src); -} -static -VariableType -makeVariableType(const Glib::ustring & src, const VT_typeID format = DefaultType) -{ - switch (format) { - default: - case DefaultType: - case String: - return src; - case Int: - return boost::lexical_cast(src); - case UInt: - return boost::lexical_cast(src); - case LInt: - return boost::lexical_cast(src); - case LUInt: - return boost::lexical_cast(src); - case LLInt: - return boost::lexical_cast(src); - case LLUInt: - return boost::lexical_cast(src); - case Float: - return boost::lexical_cast(src); - case Double: - return boost::lexical_cast(src); - case DateTime: - return boost::posix_time::time_from_string(src); - } -} - -VariableType::VariableType() : - _VT(), - convertCache(NULL), - freer(NULL) -{ -} - -VariableType::VariableType(const VariableType & vt) : - _VT(*((const _VT *)&vt)), - convertCache(NULL), - freer(NULL) -{ -} - -VariableType::~VariableType() -{ - if (freer && convertCache) { - freer(convertCache); - } -} - -void -VariableType::operator=(const VariableType & vt) -{ - if (freer && convertCache) { - freer(convertCache); - } - freer = NULL; - convertCache = NULL; - _VT::operator=(*((const _VT *)&vt)); -} - -template -class compi : public boost::static_visitor { - public: - compi(const S & s) : _s(s) { } - bool operator()(const S & t) const - { - return _s < t; - } - template - bool operator()(const T &) const - { - // should never be called - throw std::logic_error("Shouldn't ever be comparing variables of different type"); - } - private: - const S & _s; -}; -class comp : public boost::static_visitor { - public: - comp(const VariableType & a) : _a(a) { } - template - bool operator()(const T & t) const - { - return boost::apply_visitor(compi(t), _a); - } - private: - const VariableType & _a; -}; -bool -VariableType::operator<(const VariableType & b) const -{ - if (this->which() < b.which()) { - return true; - } - if (this->which() == b.which()) { - return boost::apply_visitor(comp(*this), b); - } - return false; -} - -/// Variable implementation whose value is a literal value of some known type -class VariableLiteral : public VariableImpl { - public: - VariableLiteral(const Glib::ustring & src, const VT_typeID format = DefaultType) : - val(makeVariableType(src, format)) - { - } - VariableLiteral(const xmlpp::Element * c) - { - if (const xmlpp::Attribute * la = c->get_attribute("value")) { - val = makeVariableType(la->get_value(), getVariableTypeFromName(c->get_attribute_value("type"))); - } - else { - BOOST_FOREACH(const xmlpp::Node * n, c->get_children()) { - if (const xmlpp::Element * e = dynamic_cast(n)) { - vals.push_back(new VarPart(e)); - } - else if (const xmlpp::TextNode * t = dynamic_cast(n)) { - vals.push_back(new TextPart(t)); - } - } - } - } - - virtual VariableType value() const - { - if (vals.empty()) { - return val; - } - if (vals.size() == 1) { - return *vals.front(); - } - Glib::ustring v; - BOOST_FOREACH(PartCPtr p, vals) { - p->appendTo(v); - } - return v; - } - private: - VariableType val; - class Part : public IntrusivePtrBase { - public: - virtual void appendTo(Glib::ustring & str) const = 0; - virtual operator VariableType() const = 0; - }; - class TextPart : public Part { - public: - TextPart(const xmlpp::TextNode * e) : - txt(e->get_content()) - { - } - void appendTo(Glib::ustring & str) const - { - str += txt; - } - operator VariableType() const - { - return txt; - } - const Glib::ustring txt; - }; - class VarPart : public Part, public Variable { - public: - VarPart(const xmlpp::Element * e) : Variable(e, boost::optional()) - { - } - void appendTo(Glib::ustring & str) const - { - str += (*this)().operator const Glib::ustring &(); - } - operator VariableType() const - { - return (*this)(); - } - }; - typedef boost::intrusive_ptr PartCPtr; - std::list vals; -}; -DECLARE_COMPONENT_LOADER("literal", VariableLiteral, VariableLoader); -DECLARE_CUSTOM_COMPONENT_LOADER("", VariableLiteralDef, VariableLoaderImpl, VariableLoader); - -VariableImplDyn::VariableImplDyn(const xmlpp::Element * e) -{ - if (e) { - defaultValue = Variable(e, "default", false); - } -} - -/// Variable implementation to access fields in row sets -class VariableParent : public VariableImplDyn { - public: - VariableParent(const xmlpp::Element * e) : - VariableImplDyn(e), - depth(e->get_attribute("depth") ? atoi(e->get_attribute_value("depth").c_str()) : 1), - attr(e->get_attribute("attribute")), - name(attr ? e->get_attribute_value("attribute") : e->get_attribute_value("name")) - { - } - VariableParent(const Glib::ustring & n, bool a, unsigned int d) : - VariableImplDyn(NULL), - depth(d), - attr(a), - name(n) - { - } - VariableType value() const - { - try { - if (!getValue) { - if (depth > RowState::Stack().size()) { - throw RowSet::ParentOutOfRange(depth); - } - bind(RowState::Stack()[RowState::Stack().size() - depth]); - } - return getValue(); - } - catch (RowSet::ParentOutOfRange) { - if (!defaultValue) { - throw; - } - return (*defaultValue)(); - } - catch (RowSet::FieldDoesNotExist) { - if (!defaultValue) { - throw; - } - return (*defaultValue)(); - } - } - protected: - void bind(const RowState * row) const - { - if (attr) { - getValue = boost::bind(row->resolveAttr(name)); - } - else { - getValue = boost::bind(&RowState::getCurrentValue, row, name); - } - } - const size_t depth; - const bool attr; - const Glib::ustring name; - mutable boost::function0 getValue; -}; -DECLARE_COMPONENT_LOADER("parent", VariableParent, VariableLoader); - -/// Variable implementation which has some fixed value -class VariableFixed : public VariableImpl { - public: - VariableFixed(VariableType v) : - var(v) - { - } - VariableType value() const - { - return var; - } - private: - VariableType var; -}; - -Variable::Variable(VariableType def) : - var(new VariableFixed(def)) -{ -} - -Variable::Variable(const xmlpp::Element * e, const Glib::ustring & n, bool required, VariableType def) -{ - xmlpp::Attribute * a = e->get_attribute(n); - if (a) { - var = new VariableLiteral(a->get_value()); - return; - } - xmlpp::Element::NodeList cs = e->get_children(n); - if (cs.size() == 1) { - const xmlpp::Element * c = dynamic_cast(cs.front()); - if (c) { - xmlpp::Attribute * source = c->get_attribute("source"); - if (source) { - var = LoaderBase::getLoader(source->get_value())->create(c); - } - else { - var = new VariableLiteral(c); - } - return; - } - } - if (!required) { - var = new VariableFixed(def); - return; - } - throw NoVariableDefinition(n); -} - -Variable::Variable(const xmlpp::Element * c, const boost::optional & defaultSource) -{ - xmlpp::Attribute * source = c->get_attribute("source"); - if (source) { - var = LoaderBase::getLoader(source->get_value())->create(c); - } - else if (defaultSource) { - var = LoaderBase::getLoader(defaultSource.get())->create(c); - } - else { - var = new VariableLiteral(c); - } -} - -Variable::Variable(VariableImpl * v) : - var(v) -{ -} - -VariableImpl::~VariableImpl() -{ -} - -Variable -Variable::makeParent(const Glib::ustring & name, bool attr, unsigned int dep) -{ - return Variable(new VariableParent(name, attr, dep)); -} - diff --git a/project2/variables.h b/project2/variables.h deleted file mode 100644 index 6dbbf2b..0000000 --- a/project2/variables.h +++ /dev/null @@ -1,120 +0,0 @@ -#ifndef VARIABLES_H -#define VARIABLES_H - -#include -#include -#include -#include -#include -#include -#include -#include "intrusivePtrBase.h" -#include "xmlObjectLoader.h" -#include -#include - -class Null { - public: - bool operator<(const Null &) const; -}; -typedef boost::variant< - Null, - // Strings - Glib::ustring, - // Numbers - long long unsigned int, - long unsigned int, - unsigned int, - short unsigned int, - long long int, - long int, - int, - short int, - double, - float, - // DateTimes - boost::posix_time::ptime - > _VT; - -class VariableType : public _VT { - public: - typedef void(*Freer)(const void*); - template - VariableType(const T & t) : _VT(t), convertCache(NULL), freer(NULL) { } - VariableType(); - VariableType(const VariableType &); - ~VariableType(); - void operator=(const VariableType &); - bool operator<(const VariableType &) const; - - operator const Glib::ustring &() const; - operator const std::string &() const; - operator const char *() const; - operator const unsigned char *() const; - operator int64_t() const; - operator int32_t() const; - operator double() const; - operator const boost::posix_time::ptime &() const; - template const T * get() const { return boost::get(this); } - - private: - template friend const T * set(const VariableType * var, const T * t, Freer); - mutable const void * convertCache; - mutable Freer freer; -}; - -/// Base class for Project2 variable accessors -class VariableImpl : public IntrusivePtrBase { - public: - virtual VariableType value() const = 0; - - protected: - virtual ~VariableImpl() = 0; -}; - -class Variable { - public: - typedef boost::intrusive_ptr VariableImplPtr; - - Variable(const xmlpp::Element *, const Glib::ustring & n, bool required = true, VariableType def = VariableType()); - Variable(const xmlpp::Element *, const boost::optional &); - Variable(VariableType def); - - static Variable makeParent(const Glib::ustring & name, bool attr, unsigned int depth); - - operator VariableType () const { return var->value(); } - VariableType operator()() const { return var->value(); } - - private: - Variable(VariableImpl *); - friend class VariableParse; - VariableImplPtr var; -}; - -/// Base class for variables whose content is dynamic -class VariableImplDyn : public VariableImpl { - public: - VariableImplDyn(const xmlpp::Element * e); - virtual VariableType value() const = 0; - - protected: - boost::optional defaultValue; -}; - -/// Base class to create variables -class VariableLoader : public ComponentLoader { - public: - virtual VariableImpl * create(const xmlpp::Element *) const = 0; -}; -/// Helper implementation of VariableLoader for specific variable types -template -class VariableLoaderImpl : public VariableLoader { - public: - virtual VariableImpl * create(const xmlpp::Element * e) const - { - return new VarType(e); - } -}; - -#endif - diff --git a/project2/view.cpp b/project2/view.cpp deleted file mode 100644 index ad9ef1f..0000000 --- a/project2/view.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#include "view.h" - -View::View(const xmlpp::Element * p) : - SourceObject(p) -{ -} - -View::~View() -{ -} - diff --git a/project2/view.h b/project2/view.h deleted file mode 100644 index 80d7b30..0000000 --- a/project2/view.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef VIEW_H -#define VIEW_H - -#include "sourceObject.h" -#include "xmlStorage.h" - -class Presenter; - -/// Base class for Project2 components that output data -class View : public virtual SourceObject { - public: - View(const xmlpp::Element *); - virtual ~View(); - - virtual void execute(const Presenter *) const = 0; -}; - -#endif - diff --git a/project2/viewHost.cpp b/project2/viewHost.cpp deleted file mode 100644 index c240f76..0000000 --- a/project2/viewHost.cpp +++ /dev/null @@ -1,100 +0,0 @@ -#include "viewHost.h" -#include "xmlPresenter.h" -#include -#include - -#define FOREACH_PRESENTER BOOST_FOREACH (const PresenterPtr & p, presenters) - -ViewHost::ViewHost(const boost::filesystem::path & 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 -{ - parseDocument(); - 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(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 deleted file mode 100644 index 5995d82..0000000 --- a/project2/viewHost.h +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef VIEWHOST_H -#define VIEWHOST_H - -#include "xmlScriptParser.h" -#include "paramChecker.h" -#include "xmlStorage.h" -#include "presenter.h" -#include "checkHost.h" -#include -#include - -class ViewHost : virtual public XmlScriptParser, virtual public CheckHost { - public: - class PresenterMultiplexer : public Presenter { - public: - typedef std::set 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 DefaultPresenterProvider; - - ViewHost(const boost::filesystem::path & file); - ~ViewHost(); - - void executeViews(const DefaultPresenterProvider &) const; - void doTransforms() const; - PresenterPtr headPresenter() const; - - private: - mutable PresenterMultiplexer pmp; - typedef ANONORDEREDSTORAGEOF(View) Views; - Views views; -}; -typedef boost::intrusive_ptr ViewHostPtr; - -#endif - diff --git a/project2/xml/Jamfile.jam b/project2/xml/Jamfile.jam new file mode 100644 index 0000000..0cd4e1e --- /dev/null +++ b/project2/xml/Jamfile.jam @@ -0,0 +1,25 @@ +alias libxmlpp : : : : + "`pkg-config --cflags libxml++-2.6`" + "`pkg-config --libs libxml++-2.6`" ; +alias libxslt : : : : + "`pkg-config --cflags libexslt`" + "`pkg-config --libs libexslt`" ; +lib boost_filesystem : : boost_filesystem ; + +lib p2xml : + rawView.cpp xmlPresenter.cpp transformHtml.cpp transformText.cpp xmlRows.cpp + xmlRawRows.cpp xslRows.cpp xslRowsCache.cpp xslPreFetch.cpp xmlMemCache.cpp xmlCache.cpp sessionXml.cpp + : + ../libmisc + libxmlpp + ../common//p2common + ../uuid//p2uuid + ../url//p2url + libxslt + boost_filesystem + : : + ../uuid//p2uuid + . + ; + + diff --git a/project2/xml/rawView.cpp b/project2/xml/rawView.cpp new file mode 100644 index 0000000..90569c9 --- /dev/null +++ b/project2/xml/rawView.cpp @@ -0,0 +1,55 @@ +#include "exceptions.h" +#include "rawView.h" +#include "xml.h" +#include "xmlObjectLoader.h" +#include "environment.h" +#include "appEngine.h" +#include +#include + +DECLARE_LOADER("rawview", RawView); + +RawView::RawView(const xmlpp::Element * p) : + SourceObject(p), + View(p), + copyRoot(p) +{ +} + +void +RawView::loadComplete(const CommonObjects *) +{ +} + +void +RawView::execute(const Presenter * p) const +{ + BOOST_FOREACH(xmlpp::Node * node, copyRoot->get_children()) { + const xmlpp::Element * e = dynamic_cast(node); + if (e) { + copyNode(p, e); + } + } +} + +void +RawView::copyNode(const Presenter * p, const xmlpp::Element * n) const +{ + p->pushSub(n->get_name()); + p->setNamespace(n->get_namespace_prefix(), n->get_namespace_uri()); + xmlpp::Element::AttributeList al = n->get_attributes(); + BOOST_FOREACH(const xmlpp::Attribute * a, al) { + p->addAttr(a->get_name(), a->get_value()); + } + const xmlpp::Node::NodeList ch = n->get_children(); + BOOST_FOREACH(const xmlpp::Node * c, ch) { + if (const xmlpp::Element * e = dynamic_cast(c)) { + copyNode(p, e); + } + else if (const xmlpp::TextNode * t = dynamic_cast(c)) { + p->addText(t->get_content()); + } + } + p->popSub(); +} + diff --git a/project2/xml/rawView.h b/project2/xml/rawView.h new file mode 100644 index 0000000..b192c89 --- /dev/null +++ b/project2/xml/rawView.h @@ -0,0 +1,22 @@ +#ifndef RAWVIEW_H +#define RAWVIEW_H + +#include +#include +#include +#include "view.h" + +/// Project2 component to create output based on its own XML tree node +class RawView : public View { + public: + RawView(const xmlpp::Element * p); + void execute(const Presenter *) const; + virtual void loadComplete(const CommonObjects *); + private: + void copyNode(const Presenter *, const xmlpp::Element *) const; + const xmlpp::Element * copyRoot; +}; + +#endif + + diff --git a/project2/xml/sessionXml.cpp b/project2/xml/sessionXml.cpp new file mode 100644 index 0000000..c1e2158 --- /dev/null +++ b/project2/xml/sessionXml.cpp @@ -0,0 +1,184 @@ +#include "sessionXml.h" +#include "uuid.h" +#include +#include +#include +#include +#include +#include +#include +#include + +/// Session implementation that stores its contents in an XML file on the local filesystem +class SessionXml : public Session { + public: + SessionXml(UUID & sid); + SessionXml(const xmlpp::Element *); + virtual ~SessionXml(); + + const VariableType & GetValue(const Glib::ustring & name) const; + Values GetValuesCopy() const; + void SetValue(const Glib::ustring & name, const VariableType & value); + void ClearValue(const Glib::ustring & name); + time_t ExpiryTime() const; + void ExpiryTime(time_t); + + const UUID sessionID; + + private: + Values vars; + time_t expires; + + friend class SessionContainerXml; +}; + +namespace po = boost::program_options; +class CustomSessionContainerLoaderXml : public SessionContainerLoaderImpl { + public: + CustomSessionContainerLoaderXml() : + opts("SessionXML options") + { + opts.add_options() + ("session.xml.path", po::value(&SessionContainerXml::xmlFile)->default_value("/tmp/project2sessions.xml"), + "Path of the XML file in which to store session information") + ; + } + po::options_description * + options() + { + return &opts; + } + + private: + po::options_description opts; +}; + +std::string SessionContainerXml::xmlFile; +DECLARE_CUSTOM_COMPONENT_LOADER("xml", SessionContainerXml, CustomSessionContainerLoaderXml, SessionContainerLoader); + +SessionContainerXml::SessionContainerXml() +{ +} + +SessionContainerXml::~SessionContainerXml() +{ + if (currentSession) { + xmlpp::DomParser parser; + xmlpp::Document * doc; + try { + parser.parse_file(xmlFile); + doc = parser.get_document(); + char xpath[200]; + snprintf(xpath, 200, "/sessions/session[@id='%s' or @expires < %lu]", + currentSession->sessionID.str().c_str(), time(NULL)); + xmlpp::NodeSet sess = doc->get_root_node()->find(xpath); + BOOST_FOREACH(xmlpp::Node * n, sess) { + n->get_parent()->remove_child(n); + } + } + catch (...) { + doc = new xmlpp::Document(); + doc->create_root_node("sessions"); + } + xmlpp::Element * sess = doc->get_root_node()->add_child("session"); + sess->set_attribute("id", currentSession->sessionID.str()); + sess->set_attribute("expires", boost::lexical_cast(currentSession->expires)); + BOOST_FOREACH(const SessionXml::Values::value_type & nvp, currentSession->vars) { + xmlpp::Element * v = sess->add_child("var"); + v->add_child_text(nvp.second); + v->set_attribute("name", nvp.first); + } + doc->write_to_file(xmlFile); + if (!parser) { + delete doc; + } + currentSession = NULL; + } +} + +SessionPtr +SessionContainerXml::getSession(UUID & sid) +{ + if (!currentSession || currentSession->sessionID != sid) { + try { + xmlpp::DomParser sessions(xmlFile); + char xpath[200]; + snprintf(xpath, 200, "/sessions/session[@id='%s' and @expires > %lu]", + sid.str().c_str(), time(NULL)); + xmlpp::NodeSet sess = sessions.get_document()->get_root_node()->find(xpath); + if (sess.size() == 1) { + currentSession = new SessionXml(dynamic_cast(sess[0])); + } + else { + currentSession = new SessionXml(sid); + } + } + catch (...) { + currentSession = new SessionXml(sid); + } + } + return currentSession; +} + +SessionXml::SessionXml(UUID & sid) : + sessionID(sid.is_nil() ? sid = UUID::generate_random() : sid) +{ +} + +SessionXml::SessionXml(const xmlpp::Element * p) : + sessionID(p->get_attribute_value("id")), + expires(boost::lexical_cast(p->get_attribute_value("expires"))) +{ + xmlpp::NodeSet xvars = p->find("var"); + BOOST_FOREACH(const xmlpp::Node * n, xvars) { + const xmlpp::Element * e = dynamic_cast(n); + if (e) { + vars[e->get_attribute_value("name")] = e->get_child_text() ? e->get_child_text()->get_content() : ""; + } + } +} + +SessionXml::~SessionXml() +{ +} + +void +SessionXml::ExpiryTime(time_t t) +{ + expires = t; +} + +time_t +SessionXml::ExpiryTime() const +{ + return expires; +} + +const VariableType & +SessionXml::GetValue(const Glib::ustring & name) const +{ + Values::const_iterator i = vars.find(name); + if (i == vars.end()) { + throw Session::VariableNotFound(name); + } + return i->second; +} + +void +SessionXml::SetValue(const Glib::ustring & name, const VariableType & value) +{ + vars[name] = value; +} + +void +SessionXml::ClearValue(const Glib::ustring & name) +{ + vars.erase(name); +} + +Session::Values +SessionXml::GetValuesCopy() const +{ + return vars; +} + diff --git a/project2/xml/sessionXml.h b/project2/xml/sessionXml.h new file mode 100644 index 0000000..9b5c3e1 --- /dev/null +++ b/project2/xml/sessionXml.h @@ -0,0 +1,24 @@ +#ifndef SESSIONXML_H +#define SESSIONXML_H + +#include "sessionContainer.h" +#include + +class SessionXml; +class SessionContainerXml : public SessionContainer { + public: + SessionContainerXml(); + ~SessionContainerXml(); + + protected: + SessionPtr getSession(UUID & sid); + typedef boost::intrusive_ptr SessionXmlPtr; + SessionXmlPtr currentSession; + + private: + // Configurables + static std::string xmlFile; + friend class CustomSessionContainerLoaderXml; +}; + +#endif diff --git a/project2/xml/transformHtml.cpp b/project2/xml/transformHtml.cpp new file mode 100644 index 0000000..eae1c27 --- /dev/null +++ b/project2/xml/transformHtml.cpp @@ -0,0 +1,30 @@ +#include "transformHtml.h" +#include "logger.h" +#include +#include +#include + +class TransformXmlToHtml : public TransformImpl { + public: + void transform(const xmlpp::Document * cdata, HtmlDocument * result) const + { + xmlpp::Document * data = const_cast(cdata); + typedef boost::shared_ptr 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/xml/transformHtml.h b/project2/xml/transformHtml.h new file mode 100644 index 0000000..25bd0d5 --- /dev/null +++ b/project2/xml/transformHtml.h @@ -0,0 +1,15 @@ +#ifndef HTMLDOCUMENT_H +#define HTMLDOCUMENT_H + +#include "transform.h" +#include + +class HtmlDocument; +class HtmlDocument : public SourceOf { + public: + htmlDocPtr doc; + operator const HtmlDocument * () const { return this; } +}; + +#endif + diff --git a/project2/xml/transformText.cpp b/project2/xml/transformText.cpp new file mode 100644 index 0000000..5ba03cc --- /dev/null +++ b/project2/xml/transformText.cpp @@ -0,0 +1,38 @@ +#include "transformText.h" +#include +#include "transformHtml.h" +#include +#include + +class TransformHtmlToText : public TransformImpl { + public: + void transform(const HtmlDocument * cdoc, TextDocument * str) const + { + xmlDoc * doc = const_cast(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/xml/transformText.h b/project2/xml/transformText.h new file mode 100644 index 0000000..9a81c89 --- /dev/null +++ b/project2/xml/transformText.h @@ -0,0 +1,15 @@ +#ifndef TEXTDOCUMENT_H +#define TEXTDOCUMENT_H + +#include "transform.h" +#include + +class TextDocument : public SourceOf { + public: + std::string doc; + operator const TextDocument * () const { return this; } +}; + + +#endif + diff --git a/project2/xml/xmlCache.cpp b/project2/xml/xmlCache.cpp new file mode 100644 index 0000000..86b098a --- /dev/null +++ b/project2/xml/xmlCache.cpp @@ -0,0 +1,143 @@ +#include "cache.h" +#include "logger.h" +#include "xmlObjectLoader.h" +#include "iHaveParameters.h" +#include "xmlRawRows.h" +#include "xmlPresenter.h" +#include +#include +#include +#include +#include +#include + +class XmlCache : public Cache { + public: + XmlCache(const xmlpp::Element * p) : + Cache(p) + { + } + + void loadComplete(const CommonObjects*) + { + } + + RowSetCPtr getCachedRowSet(const Glib::ustring & n, const Glib::ustring & f, const IHaveParameters * ps) const + { + boost::filesystem::path cache = getCacheFile(n, f, ps); + struct stat st; + if (stat(cache.string().c_str(), &st) == 0) { + if (st.st_mtime < time(NULL) - CacheLife) { + boost::filesystem::remove(cache); + return NULL; + } + return new XmlRawRows(cache.string()); + } + return NULL; + } + + PresenterPtr openFor(const Glib::ustring & n, const Glib::ustring &, const IHaveParameters *) + { + writeTo = new XmlPresenter(n, Glib::ustring(), Glib::ustring()); + return writeTo; + } + + void close(const Glib::ustring & n, const Glib::ustring & f, const IHaveParameters * ps) + { + boost::filesystem::path target = getCacheFile(n, f, ps); + try { + boost::filesystem::create_directories(target.parent_path()); + const xmlpp::Document * d = *writeTo; + const_cast(d)->write_to_file(target.string()); + writeTo.reset(); + } + catch (...) { + Logger()->messagef(LOG_WARNING, "Failed to save cache (%s)", target.string().c_str()); + } + } + + private: + boost::filesystem::path getCacheFile(const Glib::ustring & n, const Glib::ustring & f, const IHaveParameters * ps) const + { + boost::filesystem::path cache = Store / n.raw() / f.raw(); + applyKeys(boost::bind(&appendPath, &cache, _1, _2), ps); + cache /= FileName; + return cache; + } + + static void appendPath(boost::filesystem::path * cache, const std::string & n, const VariableType & v) + { + *cache /= n; + *cache /= v.operator const std::string &(); + } + + XmlPresenterPtr writeTo; + + friend class CustomXmlCacheLoader; + static boost::filesystem::path Store; + static std::string FileName; + static time_t CacheLife; +}; + +boost::filesystem::path XmlCache::Store; +std::string XmlCache::FileName; +time_t XmlCache::CacheLife; + +namespace po = boost::program_options; +class CustomXmlCacheLoader : public ElementLoaderImpl { + public: + CustomXmlCacheLoader() : + opts("XML Cache options") + { + opts.add_options() + ("cache.xml.store", po::value(&XmlCache::Store)->default_value("/tmp/project2.cache"), + "The root folder of the cache storage area") + ("cache.xml.filename", po::value(&XmlCache::FileName)->default_value("cache.xml"), + "The filename to store the data in") + ("cache.xml.life", po::value(&XmlCache::CacheLife)->default_value(3600), + "The age of cache entries after which they are removed (seconds)") + ; + } + + po::options_description * options() + { + return &opts; + } + + void onIdle() + { + emptyDir(XmlCache::Store); + } + + bool emptyDir(const boost::filesystem::path & dir) + { + bool files = false; + boost::filesystem::directory_iterator end; + for (boost::filesystem::directory_iterator itr(dir); itr != end; ++itr) { + struct stat st; + stat(itr->path().string().c_str(), &st); + if (S_ISDIR(st.st_mode)) { + if (emptyDir(*itr)) { + files = true; + } + else { + boost::filesystem::remove(*itr); + } + } + else { + if (st.st_mtime > time(NULL) - XmlCache::CacheLife) { + files = true; + } + else { + boost::filesystem::remove(*itr); + } + } + } + return files; + } + + private: + po::options_description opts; +}; +DECLARE_CUSTOM_LOADER("xmlcache", CustomXmlCacheLoader); + diff --git a/project2/xml/xmlMemCache.cpp b/project2/xml/xmlMemCache.cpp new file mode 100644 index 0000000..af54eb5 --- /dev/null +++ b/project2/xml/xmlMemCache.cpp @@ -0,0 +1,120 @@ +#include "cache.h" +#include "logger.h" +#include "xmlObjectLoader.h" +#include "iHaveParameters.h" +#include "xmlRawRows.h" +#include "xmlPresenter.h" +#include +#include +#include +#include +#include +#include +#include + +class XmlMemCache : public Cache { + public: + class CacheEntry : public IntrusivePtrBase { + public: + std::vector key; + time_t createdAt; + boost::shared_ptr doc; + }; + typedef boost::intrusive_ptr CacheEntryPtr; + typedef boost::intrusive_ptr CacheEntryCPtr; + + struct IndexByKey { }; + struct IndexByTime { }; + typedef boost::multi_index::multi_index_container< + boost::intrusive_ptr, + boost::multi_index::indexed_by< + boost::multi_index::ordered_unique< + boost::multi_index::tag, BOOST_MULTI_INDEX_MEMBER(CacheEntry, const std::vector, key)>, + boost::multi_index::ordered_non_unique< + boost::multi_index::tag, BOOST_MULTI_INDEX_MEMBER(CacheEntry, const time_t, createdAt)> + > > CacheStore; + + XmlMemCache(const xmlpp::Element * p) : + Cache(p) + { + } + + void loadComplete(const CommonObjects*) + { + } + + RowSetCPtr getCachedRowSet(const Glib::ustring & n, const Glib::ustring & f, const IHaveParameters * ps) const + { + std::vector key; + key.push_back(n); + key.push_back(f); + applyKeys(boost::bind(&std::vector::push_back, &key, _2), ps); + CacheStore::index::type::const_iterator i = Store.get().find(key); + if (i == Store.get().end()) { + return NULL; + } + if ((*i)->createdAt < (time(NULL) - CacheLife)) { + Store.erase(i); + return NULL; + } + return new XmlMemRawRows((*i)->doc); + } + + PresenterPtr openFor(const Glib::ustring & n, const Glib::ustring &, const IHaveParameters *) + { + writeTo = new XmlPresenter(n, Glib::ustring(), Glib::ustring()); + return writeTo; + } + + void close(const Glib::ustring & n, const Glib::ustring & f, const IHaveParameters * ps) + { + CacheEntryPtr ce = new CacheEntry(); + ce->key.push_back(n); + ce->key.push_back(f); + applyKeys(boost::bind(&std::vector::push_back, &ce->key, _2), ps); + time(&ce->createdAt); + ce->doc = *(const boost::shared_ptr*)(*writeTo); + Store.insert(ce); + } + + private: + XmlPresenterPtr writeTo; + + friend class CustomXmlMemCacheLoader; + static time_t CacheLife; + static CacheStore Store; +}; + +time_t XmlMemCache::CacheLife; +XmlMemCache::CacheStore XmlMemCache::Store; + +namespace po = boost::program_options; +class CustomXmlMemCacheLoader : public ElementLoaderImpl { + public: + CustomXmlMemCacheLoader() : + opts("XML Memory Cache options") + { + opts.add_options() + ("cache.xmlmem.life", po::value(&XmlMemCache::CacheLife)->default_value(3600), + "The age of cache entries after which they are removed (seconds)") + ; + } + + po::options_description * options() + { + return &opts; + } + + void onIdle() + { + typedef XmlMemCache::CacheStore::index::type::iterator iter; + iter x = XmlMemCache::Store.get().begin(); + iter y = XmlMemCache::Store.get().upper_bound(time(NULL) - XmlMemCache::CacheLife); + XmlMemCache::Store.get().erase(x, y); + } + + private: + po::options_description opts; +}; +DECLARE_CUSTOM_LOADER("xmlmemcache", CustomXmlMemCacheLoader); + diff --git a/project2/xml/xmlPresenter.cpp b/project2/xml/xmlPresenter.cpp new file mode 100644 index 0000000..adaed38 --- /dev/null +++ b/project2/xml/xmlPresenter.cpp @@ -0,0 +1,97 @@ +#include "xmlPresenter.h" +#include "xmlObjectLoader.h" +#include "variables.h" +#include "appEngine.h" +#include + +DECLARE_COMPONENT_LOADER("xml", XmlPresenter, PresenterLoader) + +XmlPresenter::XmlPresenter(const Glib::ustring & responseRootNodeName, const Glib::ustring & responseStyle, const Glib::ustring & ct) : + ContentPresenter(ct), + responseDoc(XmlDocumentPtr(new xmlpp::Document("1.0"))) +{ + createDoc(responseRootNodeName, responseStyle); +} + +XmlPresenter::XmlPresenter(const xmlpp::Element * e) : + ContentPresenter(e->get_attribute_value("contenttype")), + responseDoc(XmlDocumentPtr(new xmlpp::Document("1.0"))) +{ + createDoc(e->get_attribute_value("root"), e->get_attribute_value("style")); +} + +XmlPresenter::~XmlPresenter() +{ +} + +void +XmlPresenter::createDoc(const Glib::ustring & responseRootNodeName, const Glib::ustring & responseStyle) const +{ + nodeStack.push_back(responseDoc->create_root_node(responseRootNodeName)); + declareNamespace(Environment::getCurrent()->xmlPrefix, + Environment::getCurrent()->xmlNamespace); + // 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); + } +} + +XmlPresenter::operator const boost::shared_ptr * () const +{ + return &responseDoc; +} + +XmlPresenter::operator const xmlpp::Document * () const +{ + return responseDoc.get(); +} + +XmlPresenter::operator const xmlDoc * () const +{ + return responseDoc->cobj(); +} + +void +XmlPresenter::declareNamespace(const Glib::ustring & prefix, const Glib::ustring & ns) const +{ + xmlNewNs(nodeStack.back()->cobj(), BAD_CAST ns.c_str(), BAD_CAST prefix.c_str()); +} + +void +XmlPresenter::setNamespace(const Glib::ustring & prefix, const Glib::ustring & ns) const +{ + nodeStack.back()->set_namespace_declaration(ns, prefix); +} + +void +XmlPresenter::pushSub(const Glib::ustring & name, const Glib::ustring & ns) const +{ + 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 (!value.get()) { + nodeStack.back()->set_attribute(name, value, ns); + } +} + +void +XmlPresenter::addText(const VariableType & value) const +{ + if (!value.get()) { + nodeStack.back()->add_child_text(value); + } +} + +void +XmlPresenter::popSub() const +{ + nodeStack.pop_back(); +} + diff --git a/project2/xml/xmlPresenter.h b/project2/xml/xmlPresenter.h new file mode 100644 index 0000000..ae40470 --- /dev/null +++ b/project2/xml/xmlPresenter.h @@ -0,0 +1,38 @@ +#ifndef XMLPRESENTER_H +#define XMLPRESENTER_H + +#include "presenter.h" +#include "transform.h" + +namespace xmlpp { + class Document; +} + +class XmlPresenter : public ContentPresenter, public SourceOf, public SourceOf, public SourceOf > { + public: + typedef boost::shared_ptr XmlDocumentPtr; + 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; + void setNamespace(const Glib::ustring & prefix, const Glib::ustring & ns) const; + void pushSub(const Glib::ustring & name, const Glib::ustring & ns) const; + void addAttr(const Glib::ustring & name, const Glib::ustring & ns, const VariableType & value) const; + void addText(const VariableType & value) const; + void popSub() const; + + operator const xmlpp::Document * () const; + operator const xmlDoc * () const; + operator const boost::shared_ptr * () const; + + private: + void createDoc(const Glib::ustring & responseRootNodeName, const Glib::ustring & responseStyle) const; + XmlDocumentPtr responseDoc; + mutable std::vector nodeStack; +}; + +typedef boost::intrusive_ptr XmlPresenterPtr; + +#endif + diff --git a/project2/xml/xmlRawRows.cpp b/project2/xml/xmlRawRows.cpp new file mode 100644 index 0000000..68a4e8c --- /dev/null +++ b/project2/xml/xmlRawRows.cpp @@ -0,0 +1,113 @@ +#include "xmlRawRows.h" +#include +#include +#include + +DECLARE_LOADER("xmlrawrows", XmlRawRows); + +class XmlRowState : public RowState { + public: + const Columns & getColumns() const + { + return cols; + } + + void foreachAttr(const AttrAction & action) const + { + BOOST_FOREACH(const xmlpp::Attribute * a, e->get_attributes()) { + action(a->get_name(), a->get_value()); + } + RowState::foreachAttr(action); + } + + RowState::RowAttribute resolveAttr(const Glib::ustring & n) const + { + if (e->get_attribute(n)) { + return boost::bind(&XmlRowState::getAttr, this, n); + } + return RowState::resolveAttr(n); + } + + VariableType getAttr(const Glib::ustring & n) const + { + if (const xmlpp::Attribute * a = e->get_attribute(n)) { + return a->get_value(); + } + throw AttributeDoesNotExist(n); + } + + Columns cols; + const xmlpp::Element * e; +}; + + +XmlRawRowsBase::XmlRawRowsBase(const xmlpp::Element * p) : + RowSet(p) +{ +} + +XmlRawRowsBase::XmlRawRowsBase() : + RowSet(NULL) +{ +} + +void XmlRawRowsBase::loadComplete(const CommonObjects*) +{ +} + +void XmlRawRowsBase::execute(const xmlpp::Document * doc, const RowProcessor * rp) const +{ + XmlRowState rs; + BOOST_FOREACH(const xmlpp::Node * n, doc->get_root_node()->get_children()) { + if ((rs.e = dynamic_cast(n))) { + if (rs.cols.empty()) { + unsigned int col = 0; + BOOST_FOREACH(const xmlpp::Node * in, rs.e->get_children()) { + if (const xmlpp::Element * ie = dynamic_cast(in)) { + rs.cols.insert(new Column(col++, ie->get_name())); + } + } + rs.fields.resize(col); + } + unsigned int col = 0; + BOOST_FOREACH(const xmlpp::Node * in, rs.e->get_children()) { + if (const xmlpp::Element * ie = dynamic_cast(in)) { + const xmlpp::TextNode * t = ie->get_child_text(); + if (t) { + rs.fields[col] = t->get_content(); + } + col++; + } + } + rs.process(rp); + } + } +} + +XmlRawRows::XmlRawRows(const xmlpp::Element * p) : + XmlRawRowsBase(p), + path(p, "path") +{ +} + +XmlRawRows::XmlRawRows(const Glib::ustring & p) : + path(p) +{ +} + +void XmlRawRows::execute(const Glib::ustring&, const RowProcessor * rp) const +{ + xmlpp::DomParser x(path()); + XmlRawRowsBase::execute(x.get_document(), rp); +} + +XmlMemRawRows::XmlMemRawRows(boost::shared_ptr d) : + doc(d) +{ +} + +void XmlMemRawRows::execute(const Glib::ustring&, const RowProcessor * rp) const +{ + XmlRawRowsBase::execute(doc.get(), rp); +} + diff --git a/project2/xml/xmlRawRows.h b/project2/xml/xmlRawRows.h new file mode 100644 index 0000000..a4e7899 --- /dev/null +++ b/project2/xml/xmlRawRows.h @@ -0,0 +1,38 @@ +#include "rowSet.h" + +namespace xmlpp { + class Document; +} + +class XmlRawRowsBase : public RowSet { + public: + XmlRawRowsBase(const xmlpp::Element * p); + XmlRawRowsBase(); + + void loadComplete(const CommonObjects*); + + protected: + void execute(const xmlpp::Document *, const RowProcessor * rp) const; +}; + +class XmlRawRows : public XmlRawRowsBase { + public: + XmlRawRows(const xmlpp::Element * p); + XmlRawRows(const Glib::ustring & p); + + void execute(const Glib::ustring&, const RowProcessor * rp) const; + + private: + const Variable path; +}; + +class XmlMemRawRows : public XmlRawRowsBase { + public: + XmlMemRawRows(boost::shared_ptr d); + + void execute(const Glib::ustring&, const RowProcessor * rp) const; + + private: + boost::shared_ptr doc; +}; + diff --git a/project2/xml/xmlRows.cpp b/project2/xml/xmlRows.cpp new file mode 100644 index 0000000..8982945 --- /dev/null +++ b/project2/xml/xmlRows.cpp @@ -0,0 +1,136 @@ +#include "xmlRows.h" +#include "rowProcessor.h" +#include "xml.h" +#include "exceptions.h" +#include +#include +#include "xmlObjectLoader.h" +#include +#include +#include +#include +#include + +DECLARE_LOADER("xmlrows", XmlRows); + +XmlRows::XmlRows(const xmlpp::Element * p) : + RowSet(p), + recordRoot(p->get_attribute_value("recordroot")), + recordTrigger(p->get_attribute_value("recordtrigger")), + filename(p->get_attribute_value("filename")), + anyInterestingAttributes(false) +{ + typedef boost::split_iterator ssi; + + boost::split(root, recordRoot, boost::is_any_of("/")); + boost::split(trigger, recordTrigger, boost::is_any_of("/")); + + unsigned int col = 0; + BOOST_FOREACH(const xmlpp::Node * node, p->find("fields/field")) { + const xmlpp::Element * elem = dynamic_cast(node); + if (elem) { + Path p(root); + Glib::ustring path(elem->get_child_text()->get_content()); + + for(ssi It = make_split_iterator(path, first_finder("/", boost::is_equal())); It!=ssi(); ++It) { + if (It->front() == '@') { + anyInterestingAttributes = true; + } + p.push_back(Glib::ustring(It->begin(), It->end())); + } + + fields[p] = col; + fieldNames.insert(new Column(col++, elem->get_attribute_value("name"))); + } + } +} + +XmlRows::~XmlRows() +{ +} + +void +XmlRows::loadComplete(const CommonObjects *) +{ +} + +static +void +store(const XmlRows::Path & position, RowState::FieldValues & values, const XmlRows::Interests & fields, const xmlChar * val) +{ + XmlRows::Interests::const_iterator i = fields.find(position); + if (i != fields.end()) { + values[i->second] = (const char *)val; + } +} + +void +XmlRows::execute(const Glib::ustring &, const RowProcessor * rp) const +{ + xmlTextReaderPtr reader = xmlReaderForFile(filename.c_str(), NULL, 0); + if (reader == NULL) { + throw std::runtime_error("Failed to open file"); + } + + XmlState xs(this); + Path position; + bool enableCapture = false; + while (xmlTextReaderRead(reader) == 1) { + switch (xmlTextReaderNodeType(reader)) { + case XML_READER_TYPE_ELEMENT: + { + position.push_back((const char *)xmlTextReaderConstName(reader)); + enableCapture = (boost::algorithm::starts_with(position, root)); + bool empty = xmlTextReaderIsEmptyElement(reader); + if (enableCapture && anyInterestingAttributes && xmlTextReaderHasAttributes(reader)) { + while (xmlTextReaderMoveToNextAttribute(reader) == 1) { + Path p(position); + std::string attr("@"); + attr += (const char *)xmlTextReaderConstName(reader); + p.push_back(attr); + store(p, xs.fields, fields, xmlTextReaderConstValue(reader)); + } + } + if (empty) { + if (position == trigger) { + xs.process(rp, false); + } + if (position == root) { + xs.reset(); + } + position.pop_back(); + } + } + break; + case XML_READER_TYPE_TEXT: + if (enableCapture) { + store(position, xs.fields, fields, xmlTextReaderConstValue(reader)); + } + break; + case XML_READER_TYPE_END_ELEMENT: + if (enableCapture) { + if (position == trigger) { + xs.process(rp, false); + } + if (position == root) { + xs.reset(); + } + } + position.pop_back(); + break; + } + } + xmlFreeTextReader(reader); + xmlCleanupParser(); +} + +XmlRows::XmlState::XmlState(const XmlRows * rows) : + rs(rows) +{ +} +const Columns & +XmlRows::XmlState::getColumns() const +{ + return rs->fieldNames; +} + diff --git a/project2/xml/xmlRows.h b/project2/xml/xmlRows.h new file mode 100644 index 0000000..3ab889e --- /dev/null +++ b/project2/xml/xmlRows.h @@ -0,0 +1,41 @@ +#ifndef XMLROWS_H +#define XMLROWS_H + +#include +#include +#include +#include "rowSet.h" + +/// Project2 component to create a row set based on the contents of an XML file +class XmlRows : public RowSet { + public: + typedef std::vector Path; + typedef std::map Interests; + + XmlRows(const xmlpp::Element * p); + ~XmlRows(); + + void execute(const Glib::ustring &, const RowProcessor *) const; + virtual void loadComplete(const CommonObjects *); + + const Glib::ustring recordRoot; + const Glib::ustring recordTrigger; + const std::string filename; + + private: + class XmlState : public RowState { + public: + XmlState(const XmlRows *); + const Columns & getColumns() const; + const XmlRows * rs; + }; + + Path root; + Path trigger; + Interests fields; + bool anyInterestingAttributes; + Columns fieldNames; +}; + +#endif + diff --git a/project2/xml/xslPreFetch.cpp b/project2/xml/xslPreFetch.cpp new file mode 100644 index 0000000..b70d83c --- /dev/null +++ b/project2/xml/xslPreFetch.cpp @@ -0,0 +1,56 @@ +#include "xslPreFetch.h" +#include "xmlObjectLoader.h" + +DECLARE_LOADER("xslprefetch", XslPreFetch); + +XslPreFetch::XslPreFetch(const xmlpp::Element * p) : + SourceObject(p), + View(p), + Task(p), + CurlHelper(p), + html(p->get_attribute_value("html") == "true"), + warnings(p->get_attribute_value("warnings") != "false"), + encoding(p, "encoding", false) +{ +} + +XslPreFetch::~XslPreFetch() +{ +} + +void +XslPreFetch::execute(const Presenter*) const +{ + execute(); +} + +void +XslPreFetch::execute() const +{ + queue(url(), encoding()); +} + +void +XslPreFetch::loadComplete(const CommonObjects *) +{ +} + + +CurlHandle::Ptr +XslPreFetch::newCurl() const +{ + return CurlHelper::newCurl(); +} + +bool +XslPreFetch::asHtml() const +{ + return html; +} + +bool +XslPreFetch::withWarnings() const +{ + return warnings; +} + diff --git a/project2/xml/xslPreFetch.h b/project2/xml/xslPreFetch.h new file mode 100644 index 0000000..c9e6a9a --- /dev/null +++ b/project2/xml/xslPreFetch.h @@ -0,0 +1,30 @@ +#ifndef XSLPREFETCH_H +#define XSLPREFETCH_H + +#include "xslRowsCache.h" +#include "curlHelper.h" +#include "view.h" +#include "task.h" +#include + +/// Project2 component to queue up CURL objects to be downloaded +class XslPreFetch : public View, public Task, XslRowsCache, CurlHelper { + public: + XslPreFetch(const xmlpp::Element * p); + ~XslPreFetch(); + + void execute(const Presenter*) const; + void execute() const; + void loadComplete(const CommonObjects *); + + const bool html; + const bool warnings; + const Variable encoding; + + CurlHandle::Ptr newCurl() const; + bool asHtml() const; + bool withWarnings() const; +}; + +#endif + diff --git a/project2/xml/xslRows.cpp b/project2/xml/xslRows.cpp new file mode 100644 index 0000000..07d57b6 --- /dev/null +++ b/project2/xml/xslRows.cpp @@ -0,0 +1,159 @@ +#include "xslRows.h" +#include "safeMapFind.h" +#include "rowProcessor.h" +#include "logger.h" +#include "xml.h" +#include "exceptions.h" +#include "xmlObjectLoader.h" +#include +#include +#include +#include "../libmisc/curlsup.h" +#include + +DECLARE_LOADER("xslrows", XslRows); + +SimpleMessageException(XpathInitError); +SimpleMessageException(XpathEvalError); + +XslRows::XslRows(const xmlpp::Element * p) : + RowSet(p), + CurlHelper(p), + html(p->get_attribute_value("html") == "true"), + warnings(p->get_attribute_value("warnings") != "false"), + encoding(p, "encoding", false) +{ + BOOST_FOREACH(const xmlpp::Node * node, p->find("filterview")) { + const xmlpp::Element * elem = dynamic_cast(node); + if (elem) { + FilterViewPtr fv = new FilterView(elem); + fvs[fv->name] = fv; + } + } + BOOST_FOREACH(const xmlpp::Node * node, p->find("namespace")) { + const xmlpp::Element * elem = dynamic_cast(node); + if (elem) { + namespaces[elem->get_attribute_value("prefix")] = elem->get_attribute_value("url"); + } + } +} + +XslRows::~XslRows() +{ +} + +void +XslRows::loadComplete(const CommonObjects *) +{ +} + +bool +XslRows::asHtml() const +{ + return html; +} + +bool +XslRows::withWarnings() const +{ + return warnings; +} + +CurlHandle::Ptr +XslRows::newCurl() const +{ + return CurlHelper::newCurl(); +} + +void +XslRows::execute(const Glib::ustring & filter, const RowProcessor * rp) const +{ + FilterViewPtr fv = safeMapFind(fvs, filter)->second; + + typedef boost::shared_ptr xmlXPathObjectSPtr; + typedef boost::shared_ptr xmlXPathContextSPtr; + xmlDocPtr doc = getDocument(url(), encoding()); + xmlXPathContextSPtr xpathCtx = xmlXPathContextSPtr(xmlXPathNewContext(doc), xmlXPathFreeContext); + if (!xpathCtx) { + throw XpathInitError(xmlGetLastError()->message); + } + BOOST_FOREACH(const Namespaces::value_type & ns, namespaces) { + xmlXPathRegisterNs(xpathCtx.get(), BAD_CAST ns.first.c_str(), BAD_CAST ns.second.c_str()); + } + xmlXPathObjectSPtr xpathObj = xmlXPathObjectSPtr(xmlXPathEvalExpression(fv->root(), xpathCtx.get()), xmlXPathFreeObject); + if (!xpathObj || !xpathObj->nodesetval) { + throw XpathEvalError(xmlGetLastError()->message); + } + Logger()->messagef(LOG_INFO, "%d nodes matched %s", xpathObj->nodesetval->nodeNr, (const char *)(fv->root())); + XslState xs(fv); + for (int row = 0; row < xpathObj->nodesetval->nodeNr; row += 1) { + xmlNodePtr rowRoot = xpathObj->nodesetval->nodeTab[row]; + xpathCtx->node = rowRoot; + BOOST_FOREACH(const Columns::value_type & _xp, fv->columns.get()) { + const FilterViewColumn * xp = static_cast(_xp.get()); + const VariableType & path(xp->path); + if (boost::get(&path)) { + continue; + } + xmlXPathObjectSPtr xpathObjI = xmlXPathObjectSPtr(xmlXPathEvalExpression(path, xpathCtx.get()), xmlXPathFreeObject); + if (!xpathObjI) { + throw XpathEvalError(xmlGetLastError()->message); + } + if (xpathObjI->floatval) { + xs.fields[xp->idx] = xpathObjI->floatval; + } + else if (xpathObjI->stringval) { + xs.fields[xp->idx] = Glib::ustring((const char *)xpathObjI->stringval); + } + else if (xpathObjI->nodesetval) { + Glib::ustring str; + for (int i = 0; i < xpathObjI->nodesetval->nodeNr; i += 1) { + xmlNodePtr n = xpathObjI->nodesetval->nodeTab[i]; + if (n->content) { + str += (const char *)n->content; + } + for (n = n->children; n; n = n->next) { + xmlChar * val = n->content; + if (val) { + str += (const char *)val; + } + } + } + xs.fields[xp->idx] = str; + } + } + xs.process(rp); + } +} + +XslRows::FilterView::FilterView(const xmlpp::Element * p) : + DefinedColumns(p, "field", boost::bind(XslRows::FilterViewColumn::make, _1, _2)), + name(p->get_attribute_value("name")), + root(p, "root") +{ +} + +XslRows::FilterViewColumn::FilterViewColumn(unsigned int idx, const xmlpp::Element * p) : + Column(idx, p), + path(p, "xpath") +{ +} + +XslRows::FilterViewColumn * +XslRows::FilterViewColumn::make(unsigned int idx, const xmlpp::Element * p) +{ + return new FilterViewColumn(idx, p); +} + +XslRows::XslState::XslState(FilterViewCPtr f) : + fv(f) +{ + fields.resize(f->columns.size()); +} + +const Columns & +XslRows::XslState::getColumns() const +{ + return fv->columns; +} + diff --git a/project2/xml/xslRows.h b/project2/xml/xslRows.h new file mode 100644 index 0000000..e33932f --- /dev/null +++ b/project2/xml/xslRows.h @@ -0,0 +1,64 @@ +#ifndef XSLROWS_H +#define XSLROWS_H + +#include +#include +#include +#include +#include "rowSet.h" +#include "variables.h" +#include "xslRowsCache.h" +#include "curlHelper.h" +#include "definedColumns.h" + +/// Project2 component to create a row set based on the contents of an XML resource and specific XPaths with its hierarchy +class XslRows : public RowSet, XslRowsCache, CurlHelper { + public: + XslRows(const xmlpp::Element * p); + ~XslRows(); + + void execute(const Glib::ustring &, const RowProcessor *) const; + virtual void loadComplete(const CommonObjects *); + + const bool html; + const bool warnings; + + private: + class FilterViewColumn : public Column { + public: + FilterViewColumn(unsigned int, const xmlpp::Element *); + static FilterViewColumn * make(unsigned int, const xmlpp::Element *); + const Variable path; + }; + class FilterView : public DefinedColumns, public virtual IntrusivePtrBase { + public: + typedef std::map XPaths; + + FilterView(const xmlpp::Element * p); + + const Glib::ustring name; + const Variable root; + }; + typedef boost::intrusive_ptr FilterViewPtr; + typedef boost::intrusive_ptr FilterViewCPtr; + typedef std::map FilterViews; + FilterViews fvs; + + virtual CurlHandle::Ptr newCurl() const; + virtual bool asHtml() const; + virtual bool withWarnings() const; + + typedef std::map Namespaces; + Namespaces namespaces; + class XslState : public RowState { + public: + XslState(FilterViewCPtr); + const Columns & getColumns() const; + private: + const FilterViewCPtr fv; + }; + const Variable encoding; +}; + +#endif + diff --git a/project2/xml/xslRowsCache.cpp b/project2/xml/xslRowsCache.cpp new file mode 100644 index 0000000..5cbc44c --- /dev/null +++ b/project2/xml/xslRowsCache.cpp @@ -0,0 +1,85 @@ +#include "xslRowsCache.h" +#include +#include +#include "exceptions.h" + +XslRowsCache::Documents XslRowsCache::documents; +XslRowsCache::Queued XslRowsCache::queued; +CurlBulkFetcher XslRowsCache::cbf; + +SimpleMessageException(XmlParseError); +SimpleMessageException(DownloadFailed); + +class XslCachePopulator : public CurlCompleteCallback { + public: + XslCachePopulator(CurlHandle::Ptr ch, const Glib::ustring & u, bool h, bool w, const char * e) : + CurlCompleteCallback(ch), + url(u), + html(h), + warnings(w), + encoding(e ? strdup(e) : NULL) + { + curl->setopt(CURLOPT_WRITEDATA, &buf); + curl->setopt(CURLOPT_WRITEFUNCTION, &XslRowsCache::handleDataHelper); + } + ~XslCachePopulator() + { + free(encoding); + } + void call(CurlBulkFetcher *) + { + int flags = 0; + flags |= warnings ? 0 : XML_PARSE_NOWARNING | XML_PARSE_NOERROR; + xmlDocPtr doc = html ? + htmlReadMemory(buf.c_str(), buf.length(), url.c_str(), encoding, flags) : + xmlReadMemory(buf.c_str(), buf.length(), url.c_str(), encoding, flags); + if (!doc) { + throw XmlParseError(xmlGetLastError()->message); + } + XslRowsCache::documents.insert(XslRowsCache::Documents::value_type(url, + XslRowsCache::Documents::value_type::second_type(doc, xmlFreeDoc))); + } + + std::string buf; + const Glib::ustring url; + const bool html; + const bool warnings; + char * encoding; +}; + +size_t +XslRowsCache::handleDataHelper(const char * ptr, size_t size, size_t nmemb, void *stream) +{ + std::string * buf = static_cast(stream); + buf->append(ptr, size * nmemb); + return size * nmemb; +} + +xmlDocPtr +XslRowsCache::getDocument(const Glib::ustring & url, const char * encoding) const +{ + Documents::const_iterator i = documents.find(url); + if (i == documents.end()) { + queue(url, encoding); + cbf.perform(); + queued.clear(); + } + i = documents.find(url); + if (i == documents.end()) { + // This should never happen + throw DownloadFailed(url); + } + else { + return i->second.get(); + } +} + +void +XslRowsCache::queue(const Glib::ustring & url, const char * encoding) const +{ + if (queued.find(url) == queued.end()) { + cbf.curls.insert(new XslCachePopulator(newCurl(), url, asHtml(), withWarnings(), encoding)); + queued.insert(url); + } +} + diff --git a/project2/xml/xslRowsCache.h b/project2/xml/xslRowsCache.h new file mode 100644 index 0000000..55b8674 --- /dev/null +++ b/project2/xml/xslRowsCache.h @@ -0,0 +1,35 @@ +#ifndef XSLROWSCACHE_H +#define XSLROWSCACHE_H + +#include +#include +#include +#include +#include "../libmisc/curlsup.h" +#include + +class XslRowsCache { + protected: + typedef std::set Queued; + typedef std::map > Documents; + + static Queued queued; + static Documents documents; + + void queue(const Glib::ustring & url, const char * encoding) const; + + virtual CurlHandle::Ptr newCurl() const = 0; + virtual bool asHtml() const = 0; + virtual bool withWarnings() const = 0; + + protected: + xmlDocPtr getDocument(const Glib::ustring & url, const char * encoding) const; + + private: + static size_t handleDataHelper(const char * ptr, size_t size, size_t nmemb, void *stream); + static CurlBulkFetcher cbf; + + friend class XslCachePopulator; +}; + +#endif diff --git a/project2/xmlCache.cpp b/project2/xmlCache.cpp deleted file mode 100644 index 86b098a..0000000 --- a/project2/xmlCache.cpp +++ /dev/null @@ -1,143 +0,0 @@ -#include "cache.h" -#include "logger.h" -#include "xmlObjectLoader.h" -#include "iHaveParameters.h" -#include "xmlRawRows.h" -#include "xmlPresenter.h" -#include -#include -#include -#include -#include -#include - -class XmlCache : public Cache { - public: - XmlCache(const xmlpp::Element * p) : - Cache(p) - { - } - - void loadComplete(const CommonObjects*) - { - } - - RowSetCPtr getCachedRowSet(const Glib::ustring & n, const Glib::ustring & f, const IHaveParameters * ps) const - { - boost::filesystem::path cache = getCacheFile(n, f, ps); - struct stat st; - if (stat(cache.string().c_str(), &st) == 0) { - if (st.st_mtime < time(NULL) - CacheLife) { - boost::filesystem::remove(cache); - return NULL; - } - return new XmlRawRows(cache.string()); - } - return NULL; - } - - PresenterPtr openFor(const Glib::ustring & n, const Glib::ustring &, const IHaveParameters *) - { - writeTo = new XmlPresenter(n, Glib::ustring(), Glib::ustring()); - return writeTo; - } - - void close(const Glib::ustring & n, const Glib::ustring & f, const IHaveParameters * ps) - { - boost::filesystem::path target = getCacheFile(n, f, ps); - try { - boost::filesystem::create_directories(target.parent_path()); - const xmlpp::Document * d = *writeTo; - const_cast(d)->write_to_file(target.string()); - writeTo.reset(); - } - catch (...) { - Logger()->messagef(LOG_WARNING, "Failed to save cache (%s)", target.string().c_str()); - } - } - - private: - boost::filesystem::path getCacheFile(const Glib::ustring & n, const Glib::ustring & f, const IHaveParameters * ps) const - { - boost::filesystem::path cache = Store / n.raw() / f.raw(); - applyKeys(boost::bind(&appendPath, &cache, _1, _2), ps); - cache /= FileName; - return cache; - } - - static void appendPath(boost::filesystem::path * cache, const std::string & n, const VariableType & v) - { - *cache /= n; - *cache /= v.operator const std::string &(); - } - - XmlPresenterPtr writeTo; - - friend class CustomXmlCacheLoader; - static boost::filesystem::path Store; - static std::string FileName; - static time_t CacheLife; -}; - -boost::filesystem::path XmlCache::Store; -std::string XmlCache::FileName; -time_t XmlCache::CacheLife; - -namespace po = boost::program_options; -class CustomXmlCacheLoader : public ElementLoaderImpl { - public: - CustomXmlCacheLoader() : - opts("XML Cache options") - { - opts.add_options() - ("cache.xml.store", po::value(&XmlCache::Store)->default_value("/tmp/project2.cache"), - "The root folder of the cache storage area") - ("cache.xml.filename", po::value(&XmlCache::FileName)->default_value("cache.xml"), - "The filename to store the data in") - ("cache.xml.life", po::value(&XmlCache::CacheLife)->default_value(3600), - "The age of cache entries after which they are removed (seconds)") - ; - } - - po::options_description * options() - { - return &opts; - } - - void onIdle() - { - emptyDir(XmlCache::Store); - } - - bool emptyDir(const boost::filesystem::path & dir) - { - bool files = false; - boost::filesystem::directory_iterator end; - for (boost::filesystem::directory_iterator itr(dir); itr != end; ++itr) { - struct stat st; - stat(itr->path().string().c_str(), &st); - if (S_ISDIR(st.st_mode)) { - if (emptyDir(*itr)) { - files = true; - } - else { - boost::filesystem::remove(*itr); - } - } - else { - if (st.st_mtime > time(NULL) - XmlCache::CacheLife) { - files = true; - } - else { - boost::filesystem::remove(*itr); - } - } - } - return files; - } - - private: - po::options_description opts; -}; -DECLARE_CUSTOM_LOADER("xmlcache", CustomXmlCacheLoader); - diff --git a/project2/xmlMemCache.cpp b/project2/xmlMemCache.cpp deleted file mode 100644 index af54eb5..0000000 --- a/project2/xmlMemCache.cpp +++ /dev/null @@ -1,120 +0,0 @@ -#include "cache.h" -#include "logger.h" -#include "xmlObjectLoader.h" -#include "iHaveParameters.h" -#include "xmlRawRows.h" -#include "xmlPresenter.h" -#include -#include -#include -#include -#include -#include -#include - -class XmlMemCache : public Cache { - public: - class CacheEntry : public IntrusivePtrBase { - public: - std::vector key; - time_t createdAt; - boost::shared_ptr doc; - }; - typedef boost::intrusive_ptr CacheEntryPtr; - typedef boost::intrusive_ptr CacheEntryCPtr; - - struct IndexByKey { }; - struct IndexByTime { }; - typedef boost::multi_index::multi_index_container< - boost::intrusive_ptr, - boost::multi_index::indexed_by< - boost::multi_index::ordered_unique< - boost::multi_index::tag, BOOST_MULTI_INDEX_MEMBER(CacheEntry, const std::vector, key)>, - boost::multi_index::ordered_non_unique< - boost::multi_index::tag, BOOST_MULTI_INDEX_MEMBER(CacheEntry, const time_t, createdAt)> - > > CacheStore; - - XmlMemCache(const xmlpp::Element * p) : - Cache(p) - { - } - - void loadComplete(const CommonObjects*) - { - } - - RowSetCPtr getCachedRowSet(const Glib::ustring & n, const Glib::ustring & f, const IHaveParameters * ps) const - { - std::vector key; - key.push_back(n); - key.push_back(f); - applyKeys(boost::bind(&std::vector::push_back, &key, _2), ps); - CacheStore::index::type::const_iterator i = Store.get().find(key); - if (i == Store.get().end()) { - return NULL; - } - if ((*i)->createdAt < (time(NULL) - CacheLife)) { - Store.erase(i); - return NULL; - } - return new XmlMemRawRows((*i)->doc); - } - - PresenterPtr openFor(const Glib::ustring & n, const Glib::ustring &, const IHaveParameters *) - { - writeTo = new XmlPresenter(n, Glib::ustring(), Glib::ustring()); - return writeTo; - } - - void close(const Glib::ustring & n, const Glib::ustring & f, const IHaveParameters * ps) - { - CacheEntryPtr ce = new CacheEntry(); - ce->key.push_back(n); - ce->key.push_back(f); - applyKeys(boost::bind(&std::vector::push_back, &ce->key, _2), ps); - time(&ce->createdAt); - ce->doc = *(const boost::shared_ptr*)(*writeTo); - Store.insert(ce); - } - - private: - XmlPresenterPtr writeTo; - - friend class CustomXmlMemCacheLoader; - static time_t CacheLife; - static CacheStore Store; -}; - -time_t XmlMemCache::CacheLife; -XmlMemCache::CacheStore XmlMemCache::Store; - -namespace po = boost::program_options; -class CustomXmlMemCacheLoader : public ElementLoaderImpl { - public: - CustomXmlMemCacheLoader() : - opts("XML Memory Cache options") - { - opts.add_options() - ("cache.xmlmem.life", po::value(&XmlMemCache::CacheLife)->default_value(3600), - "The age of cache entries after which they are removed (seconds)") - ; - } - - po::options_description * options() - { - return &opts; - } - - void onIdle() - { - typedef XmlMemCache::CacheStore::index::type::iterator iter; - iter x = XmlMemCache::Store.get().begin(); - iter y = XmlMemCache::Store.get().upper_bound(time(NULL) - XmlMemCache::CacheLife); - XmlMemCache::Store.get().erase(x, y); - } - - private: - po::options_description opts; -}; -DECLARE_CUSTOM_LOADER("xmlmemcache", CustomXmlMemCacheLoader); - diff --git a/project2/xmlObjectLoader.cpp b/project2/xmlObjectLoader.cpp deleted file mode 100644 index 14d2972..0000000 --- a/project2/xmlObjectLoader.cpp +++ /dev/null @@ -1,153 +0,0 @@ -#include "xmlObjectLoader.h" -#include "xmlStorage.h" -#include "logger.h" -#include "library.h" -#include "appEngine.h" -#include -#include -#include - -unsigned int LoaderBase::depth = 0; -std::set LoaderBase::loadedObjects; - -class DepthCounter { - public: - DepthCounter(unsigned int & c) : counter(c) { - counter += 1; - } - ~DepthCounter() { - counter -= 1; - } - private: - unsigned int & counter; -}; - -typedef std::map > ElementLoaderMap; -typedef std::set > ComponentLoaderSet; - -LoaderBase::LoaderBase(bool r) : - recursive(r), - ns(Environment::getCurrent()->xmlNamespace) -{ - supportedStorers.insert(Storer::into(&libraries)); -} - -LoaderBase::LoaderBase(const Glib::ustring & n, bool r) : - recursive(r), - ns(n) -{ - supportedStorers.insert(Storer::into(&libraries)); -} - -LoaderBase::~LoaderBase() -{ -} - -std::set > * & -LoaderBase::componentLoaders() -{ - static std::set > * _compLoaders = NULL; - if (!_compLoaders) { - _compLoaders = new std::set >(); - } - return _compLoaders; -} - -void -LoaderBase::collectAll(const xmlpp::Element * node, bool childrenOnly, UnsupportedHandling uh) const -{ - if (!node) { - return; - } - DepthCounter dc(depth); - unsigned int created = 0; - if (!childrenOnly && node->get_namespace_uri() == ns) { - Glib::ustring name = node->get_name(); - unsigned int stored = 0; - SourceObjectPtr o = getLoader(name)->go(node); - created += 1; - loadedObjects.insert(o); - BOOST_FOREACH(std::set >::value_type s, supportedStorers) { - if (s->save(o, node)) { - stored += 1; - } - } - if (stored < 1) { - if (uh == ErrorOnUnsupported) { - throw NotSupported(name); - } - else if (uh == WarnOnUnsupported) { - Logger()->messagef(LOG_WARNING, "'%s' unsupported in this location", name.c_str()); - } - } - } - if (created == 0 && (recursive || childrenOnly)) { - BOOST_FOREACH(const xmlpp::Node * child, node->get_children()) { - collectAll(dynamic_cast(child), false, uh); - } - } -} - -void -LoaderBase::collectAll(const CommonObjects * co, const xmlpp::Element * node, bool childrenOnly, UnsupportedHandling uh) const -{ - if (depth != 0) { - throw std::logic_error("Cannot set CommonObjects in subloader"); - } - loadedObjects.clear(); - collectAll(node, childrenOnly, uh); - BOOST_FOREACH(SourceObjectPtr o, loadedObjects) { - o->loadComplete(co); - } - loadedObjects.clear(); -} - -void -LoaderBase::onAllComponents(const boost::function1 & func) -{ - BOOST_FOREACH(ComponentLoaderSet::value_type l, *componentLoaders()) { - try { - func(l.get()); - } - catch (...) { - } - } -} - -Glib::ustring -xmlChildText(const xmlpp::Node * p, const Glib::ustring & t) -{ - Glib::ustring rtn; - BOOST_FOREACH(const xmlpp::Node * child, p->get_children(t)) { - const xmlpp::Element * e = dynamic_cast(child); - if (e) { - const xmlpp::ContentNode * cn = e->get_child_text(); - if (cn) { - rtn += cn->get_content(); - } - } - } - return rtn; -} - -void -ComponentLoader::onIdle() -{ -} - -void -ComponentLoader::onIteration() -{ -} - -void -ComponentLoader::onPeriodic() -{ -} - -boost::program_options::options_description * -ComponentLoader::options() -{ - return NULL; -} - diff --git a/project2/xmlObjectLoader.h b/project2/xmlObjectLoader.h deleted file mode 100644 index 4795717..0000000 --- a/project2/xmlObjectLoader.h +++ /dev/null @@ -1,136 +0,0 @@ -#ifndef XMLOBJECTLOADER_H -#define XMLOBJECTLOADER_H - -#include -#include -#include -#include -#include -#include "intrusivePtrBase.h" -#include "sourceObject.h" -#include "exceptions.h" - -namespace xmlpp { - class Element; -} -Glib::ustring xmlChildText(const xmlpp::Node * p, const Glib::ustring & n); - -enum UnsupportedHandling { ErrorOnUnsupported, WarnOnUnsupported, IgnoreUnsupported }; -class ElementLoader; -class ComponentLoader; -class CommonObjects; -class Storer; - -class LoaderBase { - public: - LoaderBase(bool recursive); - LoaderBase(const Glib::ustring & ns, bool recursive); - virtual ~LoaderBase(); - void collectAll(const CommonObjects * co, const xmlpp::Element * node, bool childrenOnly, - UnsupportedHandling uh = ErrorOnUnsupported) const; - void collectAll(const xmlpp::Element * node, bool childrenOnly, - UnsupportedHandling uh = ErrorOnUnsupported) const; - - std::set > supportedStorers; - - static void onAllComponents(const boost::function1 &); - - static std::set > * & componentLoaders(); - - template - static std::map > * & objLoaders() - { - static std::map > * _objLoaders = NULL; - if (!_objLoaders) { - _objLoaders = new std::map >(); - } - return _objLoaders; - } - - template - static void newLoader(const std::string & n, T * l) - { - boost::shared_ptr p = boost::shared_ptr(l); - objLoaders()->insert(std::pair >(n, p)); - componentLoaders()->insert(boost::shared_ptr(p)); - } - - template - static void removeLoader(const std::string & n) - { - std::map > * & o = objLoaders(); - std::set > * & c = componentLoaders(); - typename std::map >::iterator i = o->find(n); - c->erase(i->second); - o->erase(i); - if (o->empty()) { - delete o; - o = NULL; - } - if (c->empty()) { - delete c; - c = NULL; - } - } - - template - static boost::shared_ptr getLoader(const std::string & n) - { - typename std::map >::const_iterator i = objLoaders()->find(n); - if (i != objLoaders()->end()) { - return i->second; - } - else { - throw E(n); - } - } - - private: - static unsigned int depth; - static std::set loadedObjects; - - const bool recursive; - - public: - const Glib::ustring ns; -}; - -#define DECLARE_CUSTOM_COMPONENT_LOADER(N, I, T, B) \ - static void init_loader_##I() __attribute__ ((constructor(201))); \ - static void init_loader_##I() { LoaderBase::newLoader(N, new T()); } \ - static void kill_loader_##I() __attribute__ ((destructor(201))); \ - static void kill_loader_##I() { LoaderBase::removeLoader(N); } -#define DECLARE_CUSTOM_LOADER(N, T) \ - DECLARE_CUSTOM_COMPONENT_LOADER(N, T, T, ElementLoader) -#define DECLARE_COMPONENT_LOADER(N, T, B) \ - DECLARE_CUSTOM_COMPONENT_LOADER(N, T, B##Impl, B) -#define DECLARE_LOADER(N, T) \ - DECLARE_COMPONENT_LOADER(N, T, ElementLoader) - -/// Helper for loading and maintaining Project2 components -namespace boost { namespace program_options { class options_description; } } -class ComponentLoader { - public: - virtual void onIdle(); // When the app engine goes idle - virtual void onIteration(); // When the app engine has completed an iteration - virtual void onPeriodic(); // When the app engine feels like it - virtual boost::program_options::options_description * - options(); // Options to be populated from the common config file/env/etc -}; -/// Helper for loading and maintaining Project2 script components -class ElementLoader : public ComponentLoader { - public: - virtual SourceObjectPtr go(const xmlpp::Element * xml) const = 0; -}; - -/// Helper for loading and maintaining Project2 script components (typed implementation) -template -class ElementLoaderImpl : public ElementLoader { - public: - SourceObjectPtr go(const xmlpp::Element * xml) const - { - return new X(xml); - } -}; -#endif - diff --git a/project2/xmlPresenter.cpp b/project2/xmlPresenter.cpp deleted file mode 100644 index adaed38..0000000 --- a/project2/xmlPresenter.cpp +++ /dev/null @@ -1,97 +0,0 @@ -#include "xmlPresenter.h" -#include "xmlObjectLoader.h" -#include "variables.h" -#include "appEngine.h" -#include - -DECLARE_COMPONENT_LOADER("xml", XmlPresenter, PresenterLoader) - -XmlPresenter::XmlPresenter(const Glib::ustring & responseRootNodeName, const Glib::ustring & responseStyle, const Glib::ustring & ct) : - ContentPresenter(ct), - responseDoc(XmlDocumentPtr(new xmlpp::Document("1.0"))) -{ - createDoc(responseRootNodeName, responseStyle); -} - -XmlPresenter::XmlPresenter(const xmlpp::Element * e) : - ContentPresenter(e->get_attribute_value("contenttype")), - responseDoc(XmlDocumentPtr(new xmlpp::Document("1.0"))) -{ - createDoc(e->get_attribute_value("root"), e->get_attribute_value("style")); -} - -XmlPresenter::~XmlPresenter() -{ -} - -void -XmlPresenter::createDoc(const Glib::ustring & responseRootNodeName, const Glib::ustring & responseStyle) const -{ - nodeStack.push_back(responseDoc->create_root_node(responseRootNodeName)); - declareNamespace(Environment::getCurrent()->xmlPrefix, - Environment::getCurrent()->xmlNamespace); - // 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); - } -} - -XmlPresenter::operator const boost::shared_ptr * () const -{ - return &responseDoc; -} - -XmlPresenter::operator const xmlpp::Document * () const -{ - return responseDoc.get(); -} - -XmlPresenter::operator const xmlDoc * () const -{ - return responseDoc->cobj(); -} - -void -XmlPresenter::declareNamespace(const Glib::ustring & prefix, const Glib::ustring & ns) const -{ - xmlNewNs(nodeStack.back()->cobj(), BAD_CAST ns.c_str(), BAD_CAST prefix.c_str()); -} - -void -XmlPresenter::setNamespace(const Glib::ustring & prefix, const Glib::ustring & ns) const -{ - nodeStack.back()->set_namespace_declaration(ns, prefix); -} - -void -XmlPresenter::pushSub(const Glib::ustring & name, const Glib::ustring & ns) const -{ - 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 (!value.get()) { - nodeStack.back()->set_attribute(name, value, ns); - } -} - -void -XmlPresenter::addText(const VariableType & value) const -{ - if (!value.get()) { - nodeStack.back()->add_child_text(value); - } -} - -void -XmlPresenter::popSub() const -{ - nodeStack.pop_back(); -} - diff --git a/project2/xmlPresenter.h b/project2/xmlPresenter.h deleted file mode 100644 index ae40470..0000000 --- a/project2/xmlPresenter.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef XMLPRESENTER_H -#define XMLPRESENTER_H - -#include "presenter.h" -#include "transform.h" - -namespace xmlpp { - class Document; -} - -class XmlPresenter : public ContentPresenter, public SourceOf, public SourceOf, public SourceOf > { - public: - typedef boost::shared_ptr XmlDocumentPtr; - 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; - void setNamespace(const Glib::ustring & prefix, const Glib::ustring & ns) const; - void pushSub(const Glib::ustring & name, const Glib::ustring & ns) const; - void addAttr(const Glib::ustring & name, const Glib::ustring & ns, const VariableType & value) const; - void addText(const VariableType & value) const; - void popSub() const; - - operator const xmlpp::Document * () const; - operator const xmlDoc * () const; - operator const boost::shared_ptr * () const; - - private: - void createDoc(const Glib::ustring & responseRootNodeName, const Glib::ustring & responseStyle) const; - XmlDocumentPtr responseDoc; - mutable std::vector nodeStack; -}; - -typedef boost::intrusive_ptr XmlPresenterPtr; - -#endif - diff --git a/project2/xmlRawRows.cpp b/project2/xmlRawRows.cpp deleted file mode 100644 index 68a4e8c..0000000 --- a/project2/xmlRawRows.cpp +++ /dev/null @@ -1,113 +0,0 @@ -#include "xmlRawRows.h" -#include -#include -#include - -DECLARE_LOADER("xmlrawrows", XmlRawRows); - -class XmlRowState : public RowState { - public: - const Columns & getColumns() const - { - return cols; - } - - void foreachAttr(const AttrAction & action) const - { - BOOST_FOREACH(const xmlpp::Attribute * a, e->get_attributes()) { - action(a->get_name(), a->get_value()); - } - RowState::foreachAttr(action); - } - - RowState::RowAttribute resolveAttr(const Glib::ustring & n) const - { - if (e->get_attribute(n)) { - return boost::bind(&XmlRowState::getAttr, this, n); - } - return RowState::resolveAttr(n); - } - - VariableType getAttr(const Glib::ustring & n) const - { - if (const xmlpp::Attribute * a = e->get_attribute(n)) { - return a->get_value(); - } - throw AttributeDoesNotExist(n); - } - - Columns cols; - const xmlpp::Element * e; -}; - - -XmlRawRowsBase::XmlRawRowsBase(const xmlpp::Element * p) : - RowSet(p) -{ -} - -XmlRawRowsBase::XmlRawRowsBase() : - RowSet(NULL) -{ -} - -void XmlRawRowsBase::loadComplete(const CommonObjects*) -{ -} - -void XmlRawRowsBase::execute(const xmlpp::Document * doc, const RowProcessor * rp) const -{ - XmlRowState rs; - BOOST_FOREACH(const xmlpp::Node * n, doc->get_root_node()->get_children()) { - if ((rs.e = dynamic_cast(n))) { - if (rs.cols.empty()) { - unsigned int col = 0; - BOOST_FOREACH(const xmlpp::Node * in, rs.e->get_children()) { - if (const xmlpp::Element * ie = dynamic_cast(in)) { - rs.cols.insert(new Column(col++, ie->get_name())); - } - } - rs.fields.resize(col); - } - unsigned int col = 0; - BOOST_FOREACH(const xmlpp::Node * in, rs.e->get_children()) { - if (const xmlpp::Element * ie = dynamic_cast(in)) { - const xmlpp::TextNode * t = ie->get_child_text(); - if (t) { - rs.fields[col] = t->get_content(); - } - col++; - } - } - rs.process(rp); - } - } -} - -XmlRawRows::XmlRawRows(const xmlpp::Element * p) : - XmlRawRowsBase(p), - path(p, "path") -{ -} - -XmlRawRows::XmlRawRows(const Glib::ustring & p) : - path(p) -{ -} - -void XmlRawRows::execute(const Glib::ustring&, const RowProcessor * rp) const -{ - xmlpp::DomParser x(path()); - XmlRawRowsBase::execute(x.get_document(), rp); -} - -XmlMemRawRows::XmlMemRawRows(boost::shared_ptr d) : - doc(d) -{ -} - -void XmlMemRawRows::execute(const Glib::ustring&, const RowProcessor * rp) const -{ - XmlRawRowsBase::execute(doc.get(), rp); -} - diff --git a/project2/xmlRawRows.h b/project2/xmlRawRows.h deleted file mode 100644 index a4e7899..0000000 --- a/project2/xmlRawRows.h +++ /dev/null @@ -1,38 +0,0 @@ -#include "rowSet.h" - -namespace xmlpp { - class Document; -} - -class XmlRawRowsBase : public RowSet { - public: - XmlRawRowsBase(const xmlpp::Element * p); - XmlRawRowsBase(); - - void loadComplete(const CommonObjects*); - - protected: - void execute(const xmlpp::Document *, const RowProcessor * rp) const; -}; - -class XmlRawRows : public XmlRawRowsBase { - public: - XmlRawRows(const xmlpp::Element * p); - XmlRawRows(const Glib::ustring & p); - - void execute(const Glib::ustring&, const RowProcessor * rp) const; - - private: - const Variable path; -}; - -class XmlMemRawRows : public XmlRawRowsBase { - public: - XmlMemRawRows(boost::shared_ptr d); - - void execute(const Glib::ustring&, const RowProcessor * rp) const; - - private: - boost::shared_ptr doc; -}; - diff --git a/project2/xmlRows.cpp b/project2/xmlRows.cpp deleted file mode 100644 index 8982945..0000000 --- a/project2/xmlRows.cpp +++ /dev/null @@ -1,136 +0,0 @@ -#include "xmlRows.h" -#include "rowProcessor.h" -#include "xml.h" -#include "exceptions.h" -#include -#include -#include "xmlObjectLoader.h" -#include -#include -#include -#include -#include - -DECLARE_LOADER("xmlrows", XmlRows); - -XmlRows::XmlRows(const xmlpp::Element * p) : - RowSet(p), - recordRoot(p->get_attribute_value("recordroot")), - recordTrigger(p->get_attribute_value("recordtrigger")), - filename(p->get_attribute_value("filename")), - anyInterestingAttributes(false) -{ - typedef boost::split_iterator ssi; - - boost::split(root, recordRoot, boost::is_any_of("/")); - boost::split(trigger, recordTrigger, boost::is_any_of("/")); - - unsigned int col = 0; - BOOST_FOREACH(const xmlpp::Node * node, p->find("fields/field")) { - const xmlpp::Element * elem = dynamic_cast(node); - if (elem) { - Path p(root); - Glib::ustring path(elem->get_child_text()->get_content()); - - for(ssi It = make_split_iterator(path, first_finder("/", boost::is_equal())); It!=ssi(); ++It) { - if (It->front() == '@') { - anyInterestingAttributes = true; - } - p.push_back(Glib::ustring(It->begin(), It->end())); - } - - fields[p] = col; - fieldNames.insert(new Column(col++, elem->get_attribute_value("name"))); - } - } -} - -XmlRows::~XmlRows() -{ -} - -void -XmlRows::loadComplete(const CommonObjects *) -{ -} - -static -void -store(const XmlRows::Path & position, RowState::FieldValues & values, const XmlRows::Interests & fields, const xmlChar * val) -{ - XmlRows::Interests::const_iterator i = fields.find(position); - if (i != fields.end()) { - values[i->second] = (const char *)val; - } -} - -void -XmlRows::execute(const Glib::ustring &, const RowProcessor * rp) const -{ - xmlTextReaderPtr reader = xmlReaderForFile(filename.c_str(), NULL, 0); - if (reader == NULL) { - throw std::runtime_error("Failed to open file"); - } - - XmlState xs(this); - Path position; - bool enableCapture = false; - while (xmlTextReaderRead(reader) == 1) { - switch (xmlTextReaderNodeType(reader)) { - case XML_READER_TYPE_ELEMENT: - { - position.push_back((const char *)xmlTextReaderConstName(reader)); - enableCapture = (boost::algorithm::starts_with(position, root)); - bool empty = xmlTextReaderIsEmptyElement(reader); - if (enableCapture && anyInterestingAttributes && xmlTextReaderHasAttributes(reader)) { - while (xmlTextReaderMoveToNextAttribute(reader) == 1) { - Path p(position); - std::string attr("@"); - attr += (const char *)xmlTextReaderConstName(reader); - p.push_back(attr); - store(p, xs.fields, fields, xmlTextReaderConstValue(reader)); - } - } - if (empty) { - if (position == trigger) { - xs.process(rp, false); - } - if (position == root) { - xs.reset(); - } - position.pop_back(); - } - } - break; - case XML_READER_TYPE_TEXT: - if (enableCapture) { - store(position, xs.fields, fields, xmlTextReaderConstValue(reader)); - } - break; - case XML_READER_TYPE_END_ELEMENT: - if (enableCapture) { - if (position == trigger) { - xs.process(rp, false); - } - if (position == root) { - xs.reset(); - } - } - position.pop_back(); - break; - } - } - xmlFreeTextReader(reader); - xmlCleanupParser(); -} - -XmlRows::XmlState::XmlState(const XmlRows * rows) : - rs(rows) -{ -} -const Columns & -XmlRows::XmlState::getColumns() const -{ - return rs->fieldNames; -} - diff --git a/project2/xmlRows.h b/project2/xmlRows.h deleted file mode 100644 index 3ab889e..0000000 --- a/project2/xmlRows.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef XMLROWS_H -#define XMLROWS_H - -#include -#include -#include -#include "rowSet.h" - -/// Project2 component to create a row set based on the contents of an XML file -class XmlRows : public RowSet { - public: - typedef std::vector Path; - typedef std::map Interests; - - XmlRows(const xmlpp::Element * p); - ~XmlRows(); - - void execute(const Glib::ustring &, const RowProcessor *) const; - virtual void loadComplete(const CommonObjects *); - - const Glib::ustring recordRoot; - const Glib::ustring recordTrigger; - const std::string filename; - - private: - class XmlState : public RowState { - public: - XmlState(const XmlRows *); - const Columns & getColumns() const; - const XmlRows * rs; - }; - - Path root; - Path trigger; - Interests fields; - bool anyInterestingAttributes; - Columns fieldNames; -}; - -#endif - diff --git a/project2/xmlScriptParser.cpp b/project2/xmlScriptParser.cpp deleted file mode 100644 index 9b76316..0000000 --- a/project2/xmlScriptParser.cpp +++ /dev/null @@ -1,46 +0,0 @@ -#include "xmlScriptParser.h" -#include -#include - -XmlScriptParser::XmlScriptParser(const boost::filesystem::path & file, bool ii) : - IsInclusion(ii), - loader(true), - documentParsed(false) -{ - loadDocument(file); -} - -void -XmlScriptParser::loadDocument(const boost::filesystem::path & file) -{ - if (!boost::filesystem::exists(file)) { - if (IsInclusion) { - throw DependencyNotFound(file.string()); - } - else { - throw NotFound(file.string()); - } - } - try { - parse_file(file.string()); - } - catch (const xmlpp::internal_error &) { - throw NotReadable(file.string()); - } - for (int x; (x = xmlXIncludeProcessFlags(get_document()->cobj(), XML_PARSE_NOXINCNODE)); ) { - if (x < 0) { - throw IncludesError(file.string()); - } - } - loader.supportedStorers.insert(Storer::into(&rowSets)); -} - -void -XmlScriptParser::parseDocument() const -{ - if (!documentParsed) { - loader.collectAll(this, get_document()->get_root_node(), true, ErrorOnUnsupported); - documentParsed = true; - } -} - diff --git a/project2/xmlScriptParser.h b/project2/xmlScriptParser.h deleted file mode 100644 index 9f1406d..0000000 --- a/project2/xmlScriptParser.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef XMLSCRIPTPARSER_H -#define XMLSCRIPTPARSER_H - -#include -#include -#include "exceptions.h" -#include "xmlObjectLoader.h" -#include -#include "commonObjects.h" -#include - -class XmlScriptParser : public xmlpp::DomParser, virtual public CommonObjects, virtual public IntrusivePtrBase { - public: - SimpleMessageException(ParseError); - SimpleMessageExceptionBase(NotFound, ParseError); - SimpleMessageExceptionBase(DependencyNotFound, ParseError); - SimpleMessageExceptionBase(NotReadable, ParseError); - SimpleMessageExceptionBase(IncludesError, ParseError); - - XmlScriptParser(const boost::filesystem::path & file, bool isInclusion); - - const bool IsInclusion; - - protected: - LoaderBase loader; - mutable bool documentParsed; - void parseDocument() const; - - private: - void loadDocument(const boost::filesystem::path & file); -}; - - -#endif - diff --git a/project2/xmlStorage.h b/project2/xmlStorage.h deleted file mode 100644 index 73fce0a..0000000 --- a/project2/xmlStorage.h +++ /dev/null @@ -1,118 +0,0 @@ -#ifndef XMLSTORAGE_H -#define XMLSTORAGE_H - -#include "sourceObject.h" -#include "exceptions.h" -#include -#include -#include -#include - -SimpleMessageException(StoreFailed); - -#define STORAGEOF(X) \ - std::map > -#define ANONORDEREDSTORAGEOF(X) \ - std::list > -#define ANONSTORAGEOF(X) \ - std::set > - -class Storer; -typedef boost::intrusive_ptr StorerPtr; -class Storer : public virtual IntrusivePtrBase { - public: - template - static StorerPtr into(STORAGEOF(X) * map); - template - static StorerPtr into(ANONSTORAGEOF(X) * set); - template - static StorerPtr into(ANONORDEREDSTORAGEOF(X) * list); - - virtual bool save(SourceObjectPtr o, const xmlpp::Element *) = 0; -}; - -template -class StorerBase : public Storer { - public: - typedef M * Map; - bool save(SourceObjectPtr obj, const xmlpp::Element * p) { - boost::intrusive_ptr O = boost::dynamic_pointer_cast(obj); - if (O) { - if (insert(p, O)) { - return true; - } - throw StoreFailed(obj->name); - } - return false; - } - virtual bool insert(const xmlpp::Element *, boost::intrusive_ptr) = 0; -}; - -template -class StorerImpl : public StorerBase { - public: - StorerImpl(M * m); - bool insert(const xmlpp::Element *, boost::intrusive_ptr O); -}; -template -class StorerImpl : public StorerBase { - public: - typedef STORAGEOF(X) Map; - StorerImpl(STORAGEOF(X) * m) : map(m) - { - } - bool insert(const xmlpp::Element *, boost::intrusive_ptr O) - { - return map->insert(typename Map::value_type(O->name, O)).second; - } - Map * map; -}; -template -class StorerImpl : public StorerBase { - public: - typedef ANONSTORAGEOF(X) Map; - StorerImpl(ANONSTORAGEOF(X) * m) : map(m) - { - } - bool insert(const xmlpp::Element *, boost::intrusive_ptr O) - { - map->insert(O); - return true; - } - Map * map; -}; -template -class StorerImpl : public StorerBase { - public: - typedef ANONORDEREDSTORAGEOF(X) Map; - StorerImpl(ANONORDEREDSTORAGEOF(X) * m) : map(m) - { - } - bool insert(const xmlpp::Element *, boost::intrusive_ptr O) - { - map->push_back(O); - return true; - } - Map * map; -}; - -template -StorerPtr -Storer::into(STORAGEOF(X) * map) { - return new StorerImpl(map); -} - -template -StorerPtr -Storer::into(ANONSTORAGEOF(X) * set) { - return new StorerImpl(set); -} - -template -StorerPtr -Storer::into(ANONORDEREDSTORAGEOF(X) * list) { - return new StorerImpl(list); -} - -#endif - diff --git a/project2/xslPreFetch.cpp b/project2/xslPreFetch.cpp deleted file mode 100644 index b70d83c..0000000 --- a/project2/xslPreFetch.cpp +++ /dev/null @@ -1,56 +0,0 @@ -#include "xslPreFetch.h" -#include "xmlObjectLoader.h" - -DECLARE_LOADER("xslprefetch", XslPreFetch); - -XslPreFetch::XslPreFetch(const xmlpp::Element * p) : - SourceObject(p), - View(p), - Task(p), - CurlHelper(p), - html(p->get_attribute_value("html") == "true"), - warnings(p->get_attribute_value("warnings") != "false"), - encoding(p, "encoding", false) -{ -} - -XslPreFetch::~XslPreFetch() -{ -} - -void -XslPreFetch::execute(const Presenter*) const -{ - execute(); -} - -void -XslPreFetch::execute() const -{ - queue(url(), encoding()); -} - -void -XslPreFetch::loadComplete(const CommonObjects *) -{ -} - - -CurlHandle::Ptr -XslPreFetch::newCurl() const -{ - return CurlHelper::newCurl(); -} - -bool -XslPreFetch::asHtml() const -{ - return html; -} - -bool -XslPreFetch::withWarnings() const -{ - return warnings; -} - diff --git a/project2/xslPreFetch.h b/project2/xslPreFetch.h deleted file mode 100644 index c9e6a9a..0000000 --- a/project2/xslPreFetch.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef XSLPREFETCH_H -#define XSLPREFETCH_H - -#include "xslRowsCache.h" -#include "curlHelper.h" -#include "view.h" -#include "task.h" -#include - -/// Project2 component to queue up CURL objects to be downloaded -class XslPreFetch : public View, public Task, XslRowsCache, CurlHelper { - public: - XslPreFetch(const xmlpp::Element * p); - ~XslPreFetch(); - - void execute(const Presenter*) const; - void execute() const; - void loadComplete(const CommonObjects *); - - const bool html; - const bool warnings; - const Variable encoding; - - CurlHandle::Ptr newCurl() const; - bool asHtml() const; - bool withWarnings() const; -}; - -#endif - diff --git a/project2/xslRows.cpp b/project2/xslRows.cpp deleted file mode 100644 index 07d57b6..0000000 --- a/project2/xslRows.cpp +++ /dev/null @@ -1,159 +0,0 @@ -#include "xslRows.h" -#include "safeMapFind.h" -#include "rowProcessor.h" -#include "logger.h" -#include "xml.h" -#include "exceptions.h" -#include "xmlObjectLoader.h" -#include -#include -#include -#include "../libmisc/curlsup.h" -#include - -DECLARE_LOADER("xslrows", XslRows); - -SimpleMessageException(XpathInitError); -SimpleMessageException(XpathEvalError); - -XslRows::XslRows(const xmlpp::Element * p) : - RowSet(p), - CurlHelper(p), - html(p->get_attribute_value("html") == "true"), - warnings(p->get_attribute_value("warnings") != "false"), - encoding(p, "encoding", false) -{ - BOOST_FOREACH(const xmlpp::Node * node, p->find("filterview")) { - const xmlpp::Element * elem = dynamic_cast(node); - if (elem) { - FilterViewPtr fv = new FilterView(elem); - fvs[fv->name] = fv; - } - } - BOOST_FOREACH(const xmlpp::Node * node, p->find("namespace")) { - const xmlpp::Element * elem = dynamic_cast(node); - if (elem) { - namespaces[elem->get_attribute_value("prefix")] = elem->get_attribute_value("url"); - } - } -} - -XslRows::~XslRows() -{ -} - -void -XslRows::loadComplete(const CommonObjects *) -{ -} - -bool -XslRows::asHtml() const -{ - return html; -} - -bool -XslRows::withWarnings() const -{ - return warnings; -} - -CurlHandle::Ptr -XslRows::newCurl() const -{ - return CurlHelper::newCurl(); -} - -void -XslRows::execute(const Glib::ustring & filter, const RowProcessor * rp) const -{ - FilterViewPtr fv = safeMapFind(fvs, filter)->second; - - typedef boost::shared_ptr xmlXPathObjectSPtr; - typedef boost::shared_ptr xmlXPathContextSPtr; - xmlDocPtr doc = getDocument(url(), encoding()); - xmlXPathContextSPtr xpathCtx = xmlXPathContextSPtr(xmlXPathNewContext(doc), xmlXPathFreeContext); - if (!xpathCtx) { - throw XpathInitError(xmlGetLastError()->message); - } - BOOST_FOREACH(const Namespaces::value_type & ns, namespaces) { - xmlXPathRegisterNs(xpathCtx.get(), BAD_CAST ns.first.c_str(), BAD_CAST ns.second.c_str()); - } - xmlXPathObjectSPtr xpathObj = xmlXPathObjectSPtr(xmlXPathEvalExpression(fv->root(), xpathCtx.get()), xmlXPathFreeObject); - if (!xpathObj || !xpathObj->nodesetval) { - throw XpathEvalError(xmlGetLastError()->message); - } - Logger()->messagef(LOG_INFO, "%d nodes matched %s", xpathObj->nodesetval->nodeNr, (const char *)(fv->root())); - XslState xs(fv); - for (int row = 0; row < xpathObj->nodesetval->nodeNr; row += 1) { - xmlNodePtr rowRoot = xpathObj->nodesetval->nodeTab[row]; - xpathCtx->node = rowRoot; - BOOST_FOREACH(const Columns::value_type & _xp, fv->columns.get()) { - const FilterViewColumn * xp = static_cast(_xp.get()); - const VariableType & path(xp->path); - if (boost::get(&path)) { - continue; - } - xmlXPathObjectSPtr xpathObjI = xmlXPathObjectSPtr(xmlXPathEvalExpression(path, xpathCtx.get()), xmlXPathFreeObject); - if (!xpathObjI) { - throw XpathEvalError(xmlGetLastError()->message); - } - if (xpathObjI->floatval) { - xs.fields[xp->idx] = xpathObjI->floatval; - } - else if (xpathObjI->stringval) { - xs.fields[xp->idx] = Glib::ustring((const char *)xpathObjI->stringval); - } - else if (xpathObjI->nodesetval) { - Glib::ustring str; - for (int i = 0; i < xpathObjI->nodesetval->nodeNr; i += 1) { - xmlNodePtr n = xpathObjI->nodesetval->nodeTab[i]; - if (n->content) { - str += (const char *)n->content; - } - for (n = n->children; n; n = n->next) { - xmlChar * val = n->content; - if (val) { - str += (const char *)val; - } - } - } - xs.fields[xp->idx] = str; - } - } - xs.process(rp); - } -} - -XslRows::FilterView::FilterView(const xmlpp::Element * p) : - DefinedColumns(p, "field", boost::bind(XslRows::FilterViewColumn::make, _1, _2)), - name(p->get_attribute_value("name")), - root(p, "root") -{ -} - -XslRows::FilterViewColumn::FilterViewColumn(unsigned int idx, const xmlpp::Element * p) : - Column(idx, p), - path(p, "xpath") -{ -} - -XslRows::FilterViewColumn * -XslRows::FilterViewColumn::make(unsigned int idx, const xmlpp::Element * p) -{ - return new FilterViewColumn(idx, p); -} - -XslRows::XslState::XslState(FilterViewCPtr f) : - fv(f) -{ - fields.resize(f->columns.size()); -} - -const Columns & -XslRows::XslState::getColumns() const -{ - return fv->columns; -} - diff --git a/project2/xslRows.h b/project2/xslRows.h deleted file mode 100644 index e33932f..0000000 --- a/project2/xslRows.h +++ /dev/null @@ -1,64 +0,0 @@ -#ifndef XSLROWS_H -#define XSLROWS_H - -#include -#include -#include -#include -#include "rowSet.h" -#include "variables.h" -#include "xslRowsCache.h" -#include "curlHelper.h" -#include "definedColumns.h" - -/// Project2 component to create a row set based on the contents of an XML resource and specific XPaths with its hierarchy -class XslRows : public RowSet, XslRowsCache, CurlHelper { - public: - XslRows(const xmlpp::Element * p); - ~XslRows(); - - void execute(const Glib::ustring &, const RowProcessor *) const; - virtual void loadComplete(const CommonObjects *); - - const bool html; - const bool warnings; - - private: - class FilterViewColumn : public Column { - public: - FilterViewColumn(unsigned int, const xmlpp::Element *); - static FilterViewColumn * make(unsigned int, const xmlpp::Element *); - const Variable path; - }; - class FilterView : public DefinedColumns, public virtual IntrusivePtrBase { - public: - typedef std::map XPaths; - - FilterView(const xmlpp::Element * p); - - const Glib::ustring name; - const Variable root; - }; - typedef boost::intrusive_ptr FilterViewPtr; - typedef boost::intrusive_ptr FilterViewCPtr; - typedef std::map FilterViews; - FilterViews fvs; - - virtual CurlHandle::Ptr newCurl() const; - virtual bool asHtml() const; - virtual bool withWarnings() const; - - typedef std::map Namespaces; - Namespaces namespaces; - class XslState : public RowState { - public: - XslState(FilterViewCPtr); - const Columns & getColumns() const; - private: - const FilterViewCPtr fv; - }; - const Variable encoding; -}; - -#endif - diff --git a/project2/xslRowsCache.cpp b/project2/xslRowsCache.cpp deleted file mode 100644 index 5cbc44c..0000000 --- a/project2/xslRowsCache.cpp +++ /dev/null @@ -1,85 +0,0 @@ -#include "xslRowsCache.h" -#include -#include -#include "exceptions.h" - -XslRowsCache::Documents XslRowsCache::documents; -XslRowsCache::Queued XslRowsCache::queued; -CurlBulkFetcher XslRowsCache::cbf; - -SimpleMessageException(XmlParseError); -SimpleMessageException(DownloadFailed); - -class XslCachePopulator : public CurlCompleteCallback { - public: - XslCachePopulator(CurlHandle::Ptr ch, const Glib::ustring & u, bool h, bool w, const char * e) : - CurlCompleteCallback(ch), - url(u), - html(h), - warnings(w), - encoding(e ? strdup(e) : NULL) - { - curl->setopt(CURLOPT_WRITEDATA, &buf); - curl->setopt(CURLOPT_WRITEFUNCTION, &XslRowsCache::handleDataHelper); - } - ~XslCachePopulator() - { - free(encoding); - } - void call(CurlBulkFetcher *) - { - int flags = 0; - flags |= warnings ? 0 : XML_PARSE_NOWARNING | XML_PARSE_NOERROR; - xmlDocPtr doc = html ? - htmlReadMemory(buf.c_str(), buf.length(), url.c_str(), encoding, flags) : - xmlReadMemory(buf.c_str(), buf.length(), url.c_str(), encoding, flags); - if (!doc) { - throw XmlParseError(xmlGetLastError()->message); - } - XslRowsCache::documents.insert(XslRowsCache::Documents::value_type(url, - XslRowsCache::Documents::value_type::second_type(doc, xmlFreeDoc))); - } - - std::string buf; - const Glib::ustring url; - const bool html; - const bool warnings; - char * encoding; -}; - -size_t -XslRowsCache::handleDataHelper(const char * ptr, size_t size, size_t nmemb, void *stream) -{ - std::string * buf = static_cast(stream); - buf->append(ptr, size * nmemb); - return size * nmemb; -} - -xmlDocPtr -XslRowsCache::getDocument(const Glib::ustring & url, const char * encoding) const -{ - Documents::const_iterator i = documents.find(url); - if (i == documents.end()) { - queue(url, encoding); - cbf.perform(); - queued.clear(); - } - i = documents.find(url); - if (i == documents.end()) { - // This should never happen - throw DownloadFailed(url); - } - else { - return i->second.get(); - } -} - -void -XslRowsCache::queue(const Glib::ustring & url, const char * encoding) const -{ - if (queued.find(url) == queued.end()) { - cbf.curls.insert(new XslCachePopulator(newCurl(), url, asHtml(), withWarnings(), encoding)); - queued.insert(url); - } -} - diff --git a/project2/xslRowsCache.h b/project2/xslRowsCache.h deleted file mode 100644 index 55b8674..0000000 --- a/project2/xslRowsCache.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef XSLROWSCACHE_H -#define XSLROWSCACHE_H - -#include -#include -#include -#include -#include "../libmisc/curlsup.h" -#include - -class XslRowsCache { - protected: - typedef std::set Queued; - typedef std::map > Documents; - - static Queued queued; - static Documents documents; - - void queue(const Glib::ustring & url, const char * encoding) const; - - virtual CurlHandle::Ptr newCurl() const = 0; - virtual bool asHtml() const = 0; - virtual bool withWarnings() const = 0; - - protected: - xmlDocPtr getDocument(const Glib::ustring & url, const char * encoding) const; - - private: - static size_t handleDataHelper(const char * ptr, size_t size, size_t nmemb, void *stream); - static CurlBulkFetcher cbf; - - friend class XslCachePopulator; -}; - -#endif -- cgit v1.2.3