diff options
author | randomdan <randomdan@localhost> | 2010-06-13 15:25:33 +0000 |
---|---|---|
committer | randomdan <randomdan@localhost> | 2010-06-13 15:25:33 +0000 |
commit | f0f3d94f3f7f606c8498611b9283a017222e4274 (patch) | |
tree | 4ba46bcd1157819425c4db45103dd734115e558d | |
parent | Fix odbc select destructor when cursor not opened (diff) | |
download | project2-f0f3d94f3f7f606c8498611b9283a017222e4274.tar.bz2 project2-f0f3d94f3f7f606c8498611b9283a017222e4274.tar.xz project2-f0f3d94f3f7f606c8498611b9283a017222e4274.zip |
Add support for composing Glib::ustrings from columns
Break Project2 components down into generalised classes
Tidy up code
-rw-r--r-- | project2/Jamfile.jam | 2 | ||||
-rw-r--r-- | project2/dataSource.cpp | 13 | ||||
-rw-r--r-- | project2/dataSource.h | 19 | ||||
-rw-r--r-- | project2/envproc.cpp | 27 | ||||
-rw-r--r-- | project2/envproc.h | 24 | ||||
-rw-r--r-- | project2/p2webMain.cpp | 10 | ||||
-rw-r--r-- | project2/rdbmsDataSource.cpp | 8 | ||||
-rw-r--r-- | project2/rdbmsDataSource.h | 10 | ||||
-rw-r--r-- | project2/sqlView.cpp | 54 | ||||
-rw-r--r-- | project2/sqlView.h | 25 | ||||
-rw-r--r-- | project2/view.cpp | 19 | ||||
-rw-r--r-- | project2/view.h | 40 |
12 files changed, 188 insertions, 63 deletions
diff --git a/project2/Jamfile.jam b/project2/Jamfile.jam index c662255..fe900cd 100644 --- a/project2/Jamfile.jam +++ b/project2/Jamfile.jam @@ -8,7 +8,9 @@ lib odbc : : <name>odbc ; exe p2web : p2webMain.cpp sourceObject.cpp + dataSource.cpp rdbmsDataSource.cpp + view.cpp sqlView.cpp envproc.cpp libxmlpp diff --git a/project2/dataSource.cpp b/project2/dataSource.cpp new file mode 100644 index 0000000..f4b72cf --- /dev/null +++ b/project2/dataSource.cpp @@ -0,0 +1,13 @@ +#include "dataSource.h" +#include "xmlObjectLoader.h" +#include <libxml++/nodes/textnode.h> + +_DataSource::_DataSource(const xmlpp::Element * p) : + _Project2SourceObject(p) +{ +} + +_DataSource::~_DataSource() +{ +} + diff --git a/project2/dataSource.h b/project2/dataSource.h new file mode 100644 index 0000000..85bc395 --- /dev/null +++ b/project2/dataSource.h @@ -0,0 +1,19 @@ +#ifndef DATASOURCE_H +#define DATASOURCE_H + +#include <libxml/tree.h> +#include <boost/shared_ptr.hpp> +#include <map> +#include "sourceObject.h" + +class _DataSource : public _Project2SourceObject { + public: + _DataSource(const xmlpp::Element * p); + virtual ~_DataSource(); +}; +typedef boost::shared_ptr<_DataSource> DataSource; +typedef std::map<std::string, DataSource> DataSources; + +#endif + + diff --git a/project2/envproc.cpp b/project2/envproc.cpp index be864a5..feb5ad1 100644 --- a/project2/envproc.cpp +++ b/project2/envproc.cpp @@ -17,25 +17,28 @@ EnvironmentProcessor::init() page = elems.size() > 0 ? elems[0] : "index"; } - -boost::shared_ptr<xmlpp::Document> -EnvironmentProcessor::process() const +void +EnvironmentProcessor::Initialise() { xmlpp::DomParser present("present/" + page + ".xml"); while (xmlXIncludeProcessFlags(present.get_document()->cobj(), XML_PARSE_NOXINCNODE) > 0); xmlpp::Element * presentRoot = present.get_document()->get_root_node(); + responseRootNodeName = presentRoot->get_attribute_value("root"); + responseStyle = presentRoot->get_attribute_value("style"); // Collect datasources - RdbmsDataSources rdbmsDataSources; - collectAll<_RdbmsDataSource>(rdbmsDataSources, presentRoot, "rdbmsdatasource", &_Project2SourceObject::name, true, true); + collectAll<_RdbmsDataSource>(datasources, presentRoot, "rdbmsdatasource", &_Project2SourceObject::name, true, true); // Collect views - SqlViews sqlViews; - collectAll<_SqlView>(sqlViews, presentRoot, "sqlview", &_SqlView::name, true, true); - // + collectAll<_SqlView>(views, presentRoot, "sqlview", &_SqlView::name, true, true); +} + +boost::shared_ptr<xmlpp::Document> +EnvironmentProcessor::process() const +{ boost::shared_ptr<xmlpp::Document> responseDoc = boost::shared_ptr<xmlpp::Document>(new xmlpp::Document("1.0")); - xmlpp::Element * responseRoot = responseDoc->create_root_node(presentRoot->get_attribute_value("root")); + xmlpp::Element * responseRoot = responseDoc->create_root_node(responseRootNodeName); try { - BOOST_FOREACH(SqlViews::value_type s, sqlViews) { - s.second->execute(rdbmsDataSources, responseRoot, this); + BOOST_FOREACH(Views::value_type s, views) { + s.second->execute(responseRoot, this); } } catch (...) { @@ -59,7 +62,7 @@ EnvironmentProcessor::process() const // XSLT Style char * buf; if (asprintf(&buf, "type=\"text/xsl\" href=\"%s\"", - presentRoot->get_attribute_value("style").c_str()) > 0) { + responseStyle.c_str()) > 0) { xmlAddPrevSibling(responseRoot->cobj(), xmlNewDocPI(responseDoc->cobj(), BAD_CAST "xml-stylesheet", BAD_CAST buf)); } diff --git a/project2/envproc.h b/project2/envproc.h index 998899a..44556b7 100644 --- a/project2/envproc.h +++ b/project2/envproc.h @@ -5,9 +5,13 @@ #include <libxml++/document.h> #include <boost/shared_ptr.hpp> #include "regexex.h" +#include "dataSource.h" +#include "view.h" class EnvironmentProcessor { public: + class DataSourceNotFound : std::exception { }; + class DataSourceNotCompatible : std::exception { }; template <class getenvFunc> EnvironmentProcessor(const getenvFunc & getenv) : request_uri(getenv("REQUEST_URI")), @@ -17,7 +21,22 @@ class EnvironmentProcessor { { init(); } + template <class DataSourceType> + const DataSourceType * dataSource(const std::string & name) const + { + DataSources::const_iterator i = datasources.find(name); + if (i == datasources.end()) { + throw DataSourceNotFound(); + } + const DataSourceType * s = dynamic_cast<const DataSourceType *>(i->second.get()); + if (!s) { + throw DataSourceNotCompatible(); + } + return s; + } + void Initialise(); virtual boost::shared_ptr<xmlpp::Document> process() const; + Glib::ustring getParamUri(const std::string & idx) const; Glib::ustring getParamQuery(const std::string & idx) const; private: @@ -31,6 +50,11 @@ class EnvironmentProcessor { StringSet elems; RegMultiMatch params; std::string page; + Glib::ustring responseRootNodeName; + Glib::ustring responseStyle; + + DataSources datasources; + Views views; }; #endif diff --git a/project2/p2webMain.cpp b/project2/p2webMain.cpp index 698cd18..b5d4c59 100644 --- a/project2/p2webMain.cpp +++ b/project2/p2webMain.cpp @@ -26,7 +26,7 @@ int main(void) { try { EnvironmentProcessor ep(boost::bind(FCGX_GetParam, _1, envp)); - + ep.Initialise(); boost::shared_ptr<xmlpp::Document> doc = ep.process(); FCGX_FPrintF(_out, "Content-type: text/xml-xslt\r\n\r\n"); @@ -46,10 +46,10 @@ int main(void) } } #else - EnvironmentProcessor ep(getenv); - - boost::shared_ptr<xmlpp::Document> doc = ep.process(); - xmlDocDump(stdout, doc->cobj()); + EnvironmentProcessor ep(getenv); + ep.Initialise(); + boost::shared_ptr<xmlpp::Document> doc = ep.process(); + xmlDocDump(stdout, doc->cobj()); #endif return 0; } diff --git a/project2/rdbmsDataSource.cpp b/project2/rdbmsDataSource.cpp index d77d016..5e6ad16 100644 --- a/project2/rdbmsDataSource.cpp +++ b/project2/rdbmsDataSource.cpp @@ -3,22 +3,22 @@ #include <libxml++/nodes/textnode.h> _RdbmsDataSource::_RdbmsDataSource(const xmlpp::Element * p) : - _Project2SourceObject(p), + _DataSource(p), masterDsn(xmlChildText(p, "masterdsn")) { } ODBC::Connection & -_RdbmsDataSource::getWritable() +_RdbmsDataSource::getWritable() const { if (!database) { - database = boost::shared_ptr<ODBC::Connection>(new ODBC::Connection(masterDsn.c_str())); + database = boost::shared_ptr<ODBC::Connection>(new ODBC::Connection(masterDsn)); } return *database; } ODBC::Connection & -_RdbmsDataSource::getReadonly() +_RdbmsDataSource::getReadonly() const { // For now :) return getWritable(); diff --git a/project2/rdbmsDataSource.h b/project2/rdbmsDataSource.h index 1fd9fac..622754e 100644 --- a/project2/rdbmsDataSource.h +++ b/project2/rdbmsDataSource.h @@ -4,17 +4,17 @@ #include <libxml/tree.h> #include <boost/shared_ptr.hpp> #include <map> -#include "sourceObject.h" +#include "dataSource.h" #include "connection.h" -class _RdbmsDataSource : public _Project2SourceObject { +class _RdbmsDataSource : public _DataSource { public: _RdbmsDataSource(const xmlpp::Element * p); - ODBC::Connection & getReadonly(); - ODBC::Connection & getWritable(); + ODBC::Connection & getReadonly() const; + ODBC::Connection & getWritable() const; const std::string masterDsn; private: - boost::shared_ptr<ODBC::Connection> database; + mutable boost::shared_ptr<ODBC::Connection> database; }; typedef boost::shared_ptr<_RdbmsDataSource> RdbmsDataSource; typedef std::map<std::string, RdbmsDataSource> RdbmsDataSources; diff --git a/project2/sqlView.cpp b/project2/sqlView.cpp index 71c4f71..928482f 100644 --- a/project2/sqlView.cpp +++ b/project2/sqlView.cpp @@ -6,18 +6,14 @@ #include <libxml++/nodes/textnode.h> #include "xmlObjectLoader.h" #include "envproc.h" +#include <boost/bind.hpp> _SqlView::_SqlView(const xmlpp::Element * p) : - _Project2SourceObject(p), + _View(p), sql(xmlChildText(p, "sql")), - dataSource(p->get_attribute_value("datasource")), - recordName(p->get_attribute_value("recordname")) + query(NULL) { - xmlpp::NodeSet ps = p->find("parameters"); - BOOST_FOREACH(xmlpp::Node * psi, ps) { - collectAll<_Parameter>(parameters, dynamic_cast<xmlpp::Element *>(psi), "param", &_Parameter::bind, true, true); - } - collectAll<_SqlView>(subQueries, p, "sqlview", &_Project2SourceObject::name, true, true); + collectAll<_SqlView>(subViews, p, "sqlview", &_Project2SourceObject::name, true, true); } _SqlView::_Parameter::_Parameter(const xmlpp::Element * p) : @@ -27,28 +23,46 @@ _SqlView::_Parameter::_Parameter(const xmlpp::Element * p) : { } -void _SqlView::execute(RdbmsDataSources s, xmlpp::Element * par, const EnvironmentProcessor * ep, const ODBC::SelectCommand * parent) const +Glib::ustring +_SqlView::getCurrentValue(const Glib::ustring & id) const +{ + return (*query)[id].compose(); +} + +void +_SqlView::rebindCurrentValue(const Glib::ustring & id, ODBC::Command * cmd, unsigned int bind) const +{ + (*query)[id].rebind(cmd, bind); +} + +void _SqlView::execute(xmlpp::Element * par, const EnvironmentProcessor * ep, const _View * parent) const { typedef std::map<std::string, xmlpp::Element *> Columns; - ODBC::SelectCommand query(s[dataSource]->getReadonly(), sql); + query = new ODBC::SelectCommand(ep->dataSource<_RdbmsDataSource>(dataSource)->getReadonly(), sql); BOOST_FOREACH(Parameters::value_type p, parameters) { if (p.second->source == "uri") { - query.bindParamS(p.second->bind, ep->getParamUri(p.second->id)); + query->bindParamS(p.second->bind, ep->getParamUri(p.second->id)); } else if (p.second->source == "query") { - query.bindParamS(p.second->bind, ep->getParamQuery(p.second->id)); + query->bindParamS(p.second->bind, ep->getParamQuery(p.second->id)); } else if (parent && p.second->source == "parent") { - (*parent)[p.second->id].rebind(&query, p.second->bind); + const _SqlView * psqlview = dynamic_cast<const _SqlView *>(parent); + if (psqlview) { + psqlview->rebindCurrentValue(p.second->id, query, p.second->bind); + } + else { + query->bindParamS(p.second->bind, parent->getCurrentValue(p.second->id)); + } } } xmlpp::Element * set = par->add_child(name); - while (query.fetch()) { + while (query->fetch()) { Columns columns; - unsigned int cols = query.columnCount(); + unsigned int cols = query->columnCount(); xmlpp::Element * record = set->add_child(recordName); for (unsigned int col = 0; col < cols; col += 1) { - const Glib::ustring & nameattr = query[col].name; + const Glib::ustring & nameattr = (*query)[col].name; char * name, * attr = NULL; switch (sscanf(nameattr.c_str(), "%a[^_]_%as", &name, &attr)) { @@ -61,7 +75,7 @@ void _SqlView::execute(RdbmsDataSources s, xmlpp::Element * par, const Environme break; } char * buf = NULL; - query[col].writeToBuf(&buf); + (*query)[col].writeToBuf(&buf); if (buf) { if (attr) { if (strcmp(attr, ".") == 0) { @@ -87,9 +101,11 @@ void _SqlView::execute(RdbmsDataSources s, xmlpp::Element * par, const Environme free(name); free(attr); } - BOOST_FOREACH(SqlViews::value_type sq, subQueries) { - sq.second->execute(s, record, ep, &query); + BOOST_FOREACH(Views::value_type sq, subViews) { + sq.second->execute(record, ep, this); } } + delete query; + query = NULL; } diff --git a/project2/sqlView.h b/project2/sqlView.h index 9f132bc..d8efa0f 100644 --- a/project2/sqlView.h +++ b/project2/sqlView.h @@ -4,35 +4,24 @@ #include <libxml++/nodes/element.h> #include <boost/shared_ptr.hpp> #include <map> -#include "sourceObject.h" +#include "selectcommand.h" +#include "view.h" #include "rdbmsDataSource.h" class EnvironmentProcessor; -namespace ODBC { class SelectCommand; } class _SqlView; typedef boost::shared_ptr<_SqlView> SqlView; typedef std::map<std::string, SqlView> SqlViews; -class _SqlView : public _Project2SourceObject { +class _SqlView : public _View { public: - class _Parameter { - public: - _Parameter(const xmlpp::Element * p); - const std::string source; - const std::string id; - const unsigned int bind; - }; - typedef boost::shared_ptr<_Parameter> Parameter; - typedef std::map<unsigned int, Parameter> Parameters; - _SqlView(const xmlpp::Element * p); - void execute(RdbmsDataSources s, xmlpp::Element *, const EnvironmentProcessor *, const ODBC::SelectCommand * parent = NULL) const; + void execute(xmlpp::Element *, const EnvironmentProcessor *, const _View * parent = NULL) const; + Glib::ustring getCurrentValue(const Glib::ustring & id) const; const Glib::ustring sql; - const Glib::ustring dataSource; - const Glib::ustring recordName; private: - Parameters parameters; - SqlViews subQueries; + mutable ODBC::SelectCommand * query; + void rebindCurrentValue(const Glib::ustring & id, ODBC::Command *, unsigned int) const; }; #endif diff --git a/project2/view.cpp b/project2/view.cpp new file mode 100644 index 0000000..e674af8 --- /dev/null +++ b/project2/view.cpp @@ -0,0 +1,19 @@ +#include "view.h" +#include <boost/foreach.hpp> +#include "xmlObjectLoader.h" + +_View::_View(const xmlpp::Element * p) : + _Project2SourceObject(p), + dataSource(p->get_attribute_value("datasource")), + recordName(p->get_attribute_value("recordname")) +{ + xmlpp::NodeSet ps = p->find("parameters"); + BOOST_FOREACH(xmlpp::Node * psi, ps) { + collectAll<_Parameter>(parameters, dynamic_cast<xmlpp::Element *>(psi), "param", &_Parameter::bind, true, true); + } +} + +_View::~_View() +{ +} + diff --git a/project2/view.h b/project2/view.h new file mode 100644 index 0000000..281f9d2 --- /dev/null +++ b/project2/view.h @@ -0,0 +1,40 @@ +#ifndef VIEW_H +#define VIEW_H + +#include <libxml++/nodes/element.h> +#include <boost/shared_ptr.hpp> +#include <boost/any.hpp> +#include <map> +#include "sourceObject.h" + +class EnvironmentProcessor; +class _View; +typedef boost::shared_ptr<_View> View; +typedef std::map<std::string, View> Views; + +class _View : public _Project2SourceObject { + public: + class _Parameter { + public: + _Parameter(const xmlpp::Element * p); + const std::string source; + const std::string id; + const unsigned int bind; + }; + typedef boost::shared_ptr<_Parameter> Parameter; + typedef std::map<unsigned int, Parameter> Parameters; + + _View(const xmlpp::Element * p); + virtual ~_View(); + virtual void execute(xmlpp::Element *, const EnvironmentProcessor *, const _View * parent = NULL) const = 0; + virtual Glib::ustring getCurrentValue(const Glib::ustring & id) const = 0; + const Glib::ustring dataSource; + const Glib::ustring recordName; + protected: + Parameters parameters; + Views subViews; +}; + +#endif + + |