diff options
37 files changed, 910 insertions, 86 deletions
diff --git a/project2/FCgiIO.cpp b/project2/FCgiIO.cpp new file mode 100644 index 0000000..7a3dd09 --- /dev/null +++ b/project2/FCgiIO.cpp @@ -0,0 +1,63 @@ +/* + * $Id: FCgiIO.cpp,v 1.6 2007/07/02 18:48:19 sebdiaz Exp $ + * + * Copyright (C) 2002 Steve McAndrewSmith + * Copyright (C) 2002 - 2004 Stephen F. Booth + * 2007 Sebastien DIAZ <sebastien.diaz@gmail.com> + * Part of the GNU cgicc library, http://www.gnu.org/software/cgicc + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + */ + +#ifdef __GNUG__ +# pragma implementation +#endif + +#include <iostream> +#include <stdexcept> +#include <cstdlib> + +#include "FCgiIO.h" + +cgicc::FCgiIO::FCgiIO(FCGX_Request& request) + : std::ostream(&fOutBuf), + fRequest(request), + fOutBuf(request.out), + fErrBuf(request.err), + fErr(&fErrBuf) +{ + rdbuf(&fOutBuf); + fErr.rdbuf(&fErrBuf); + + // Parse environment + for(char **e = fRequest.envp; *e != NULL; ++e) { + std::string s(*e); + std::string::size_type i = s.find('='); + if(i == std::string::npos) + throw std::runtime_error("Illegally formed environment"); + fEnv[s.substr(0, i)] = s.substr(i + 1); + } +} + +cgicc::FCgiIO::FCgiIO(const FCgiIO& io) + : CgiInput(io), + std::ostream(&fOutBuf), + fRequest(io.fRequest), + fErr(&fErrBuf), + fEnv(io.fEnv) +{ + rdbuf(&fOutBuf); + fErr.rdbuf(&fErrBuf); +} diff --git a/project2/FCgiIO.h b/project2/FCgiIO.h new file mode 100644 index 0000000..a8b67f3 --- /dev/null +++ b/project2/FCgiIO.h @@ -0,0 +1,153 @@ +/* -*-c++-*- */ +/* + * $Id: FCgiIO.h,v 1.3 2007/07/02 18:48:19 sebdiaz Exp $ + * + * Copyright (C) 2002 Steve McAndrewSmith + * Copyright (C) 2002 Stephen F. Booth + * 2007 Sebastien DIAZ <sebastien.diaz@gmail.com> + * Part of the GNU cgicc library, http://www.gnu.org/software/cgicc + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA* + */ + +#ifndef _FCGIIO_H_ +#define _FCGIIO_H_ 1 + +#ifdef __GNUG__ +# pragma interface +#endif + +/*! \file FCgiIO.h + * \brief Class that implements input and output through a FastCGI request. + * + * This class provides access to the input byte-stream and environment + * variable interfaces of a FastCGI request. It is fully compatible with the + * Cgicc input API. + * + * It also provides access to the request's output and error streams, using a + * similar interface. + */ + +#include <ostream> +#include <string> +#include <map> + +#include "fcgio.h" + +#include "cgicc/CgiInput.h" + +namespace cgicc { + + // ============================================================ + // Class FCgiIO + // ============================================================ + + /*! \class FCgiIO FCgiIO.h FCgiIO.h + * \brief Class that implements input and output through a FastCGI request. + * + * This class provides access to the input byte-stream and environment + * variable interfaces of a FastCGI request. It is fully compatible with the + * Cgicc input API. + * + * It also provides access to the request's output and error streams, using a + * similar interface. + */ + class CGICC_API FCgiIO : public cgicc::CgiInput, public std::ostream + { + public: + + // ============================================================ + + /*! \name Constructor and Destructor */ + //@{ + + /*! + * \brief Constructor + * + * Create a new FCgiIO object + */ + FCgiIO(FCGX_Request& request); + + /*! + * \brief Copy constructor + * + */ + FCgiIO(const FCgiIO& io); + + /*! + * \brief Destructor + * + * Delete this FCgiIO object + */ + virtual inline + ~FCgiIO() + {} + //@} + + // ============================================================ + + /*! \name Data Sources */ + //@{ + + /*! + * \brief Read data from the request's input stream. + * + * \param data The target buffer + * \param length The number of characters to read + * \return The number of characters read + */ + virtual inline size_t read(char *data, size_t length) + { + return FCGX_GetStr(data, length, fRequest.in); + } + + /*! + * \brief Query the value of an environment variable stored in the request. + * + * \param varName The name of an environment variable + * \return The value of the requested environment variable, or an empty + * string if not found. + */ + virtual inline std::string getenv(const char *varName) + { + return fEnv[varName]; + } + //@} + + // ============================================================ + + /*! \name Data Target Streams */ + //@{ + + /*! + * \brief Provides access to the error stream. + */ + inline std::ostream& err(void) + { + return fErr; + } + //@} + + protected: + FCGX_Request& fRequest; + fcgi_streambuf fOutBuf; + fcgi_streambuf fErrBuf; + std::ostream fErr; + std::map<std::string, std::string> fEnv; + }; + +} // namespace cgicc + +#endif /* ! _FCGIIO_H_ */ diff --git a/project2/Jamfile.jam b/project2/Jamfile.jam index a8cf8ae..4fdd54c 100644 --- a/project2/Jamfile.jam +++ b/project2/Jamfile.jam @@ -5,6 +5,7 @@ alias libxmlpp : : : : <linkflags>"`pkg-config --libs libxml++-2.6`" ; lib fcgi : : <name>fcgi ; +lib fcgi++ : : <name>fcgi++ ; lib odbc : : <name>odbc ; lib boost_regex : : <name>boost_regex ; lib cgicc : : <name>cgicc ; @@ -19,4 +20,5 @@ exe p2web : <library>boost_regex <library>odbc <library>cgicc + <library>fcgi++ <library>fcgi ; diff --git a/project2/appEngine.h b/project2/appEngine.h index cffd44e..d2cff10 100644 --- a/project2/appEngine.h +++ b/project2/appEngine.h @@ -14,6 +14,8 @@ class ApplicationEngine { virtual void process() const = 0; virtual const Environment * env() const = 0; + virtual void SessionSet(const Glib::ustring & name, const Glib::ustring & value) const = 0; + virtual void SessionClear(const Glib::ustring & name) const = 0; template <class DataSourceType> const DataSourceType * dataSource(const std::string & name) const diff --git a/project2/cgiAppEngine.cpp b/project2/cgiAppEngine.cpp index 860ce51..f1c38d7 100644 --- a/project2/cgiAppEngine.cpp +++ b/project2/cgiAppEngine.cpp @@ -1,17 +1,36 @@ #include "cgiAppEngine.h" #include <syslog.h> #include <cgicc/Cgicc.h> +#include <cgicc/HTTPContentHeader.h> +#include "cgiEnvironment.h" #include <libxml++/parsers/domparser.h> #include <libxml/xinclude.h> #include "xmlObjectLoader.h" #include "rdbmsDataSource.h" +#include "iterate.h" #include <boost/bind.hpp> +#include <boost/lexical_cast.hpp> +#include <boost/uuid/uuid_io.hpp> +#include "sessionShm.h" +#include <boost/uuid/uuid_generators.hpp> +const std::string SESSIONID = "sessionID"; +typedef boost::uuids::uuid SIDKey; +typedef std::string SValue; -CgiApplicationEngine::CgiApplicationEngine(const CgiEnvironment * e) : +SessionContainer * sessionsContainer = new SessionContainerShm(); + +CgiApplicationEngine::CgiApplicationEngine(const CgiEnvironment * e, cgicc::HTTPContentHeader * h) : ApplicationEngine(e), - _env(e) + _env(e), + header(h), + sessionID(boost::uuids::nil_generator()()) { + BOOST_FOREACH(const cgicc::HTTPCookie c, e->getCookieList()) { + if (c.getName() == SESSIONID) { + sessionID = boost::uuids::string_generator()(c.getValue()); + } + } if (_env->getRequestMethod() == "POST") { currentStage = new RequestStage(this, e->elems[0]); } @@ -38,6 +57,10 @@ CgiApplicationEngine::process() const currentStage = currentStage->run(); delete prev; } + if (!sessionID.is_nil()) { + header->setCookie(cgicc::HTTPCookie(SESSIONID, boost::lexical_cast<std::string>(sessionID), "Session ID", + _env->getServerName().substr(_env->getServerName().find(".")), 3600, "/", false)); + } } CgiApplicationEngine::Stage::Stage(const CgiApplicationEngine * e) : appEngine(e) @@ -94,6 +117,19 @@ CgiApplicationEngine::PresentStage::run() param->add_child_text(fe.getValue()); param->set_attribute("name", fe.getName()); } + // Sessions variables + if (!appEngine->sessionID.is_nil()) { + xmlpp::Element * sessionXml = responseRoot->add_child("session", "project2"); + sessionXml->set_attribute("id", boost::lexical_cast<Glib::ustring>(appEngine->sessionID)); + syslog(LOG_DEBUG, "> var dump"); + Session::Values session(sessionsContainer->GetSession(appEngine->sessionID)->GetValuesCopy()); + //BOOST_FOREACH(SessionShm::Values::value_type sv, session) { + //xmlpp::Element * param = sessionXml->add_child("var", "project2"); + //param->add_child_text(sv.second); + //param->set_attribute("name", sv.first); + //} + syslog(LOG_DEBUG, "< var dump"); + } // XSLT Style char * buf; if (asprintf(&buf, "type=\"text/xsl\" href=\"%s\"", @@ -103,6 +139,7 @@ CgiApplicationEngine::PresentStage::run() } free(buf); appEngine->doc = responseDoc; + sessionsContainer->CleanUp(); return NULL; } @@ -117,6 +154,7 @@ CgiApplicationEngine::RequestStage::RequestStage(const CgiApplicationEngine * e, _DataSource::AddLoaders(loaders, appEngine->datasources); _ParamChecker::AddLoaders(loaders, parameterChecks); _Task::AddLoaders(loaders, tasks); + _Iterate::AddLoaders(loaders, tasks); _LoaderBase::collectAll(loaders, "project2", requestRoot, true, true); } CgiApplicationEngine::RequestStage::~RequestStage() @@ -130,9 +168,8 @@ CgiApplicationEngine::RequestStage::run() return new PresentStage(appEngine, pc.second->present); } } - syslog(LOG_DEBUG, "Checks passed"); try { - BOOST_FOREACH(OrderedTasks::value_type t, tasks) { + BOOST_FOREACH(NoOutputExecutes::value_type t, tasks) { t.second->execute(appEngine); } // Commit data source transactions (without invoking a connection) @@ -150,3 +187,14 @@ CgiApplicationEngine::RequestStage::run() return new PresentStage(appEngine, present); } +void +CgiApplicationEngine::SessionSet(const Glib::ustring & name, const Glib::ustring & value) const +{ + sessionsContainer->GetSession(sessionID)->SetValue(name, value); +} +void +CgiApplicationEngine::SessionClear(const Glib::ustring & name) const +{ + sessionsContainer->GetSession(sessionID)->ClearValue(name); +} + diff --git a/project2/cgiAppEngine.h b/project2/cgiAppEngine.h index 80707a0..9532ed4 100644 --- a/project2/cgiAppEngine.h +++ b/project2/cgiAppEngine.h @@ -2,15 +2,20 @@ #define CGIAPPENGINE_H #include "appEngine.h" -#include "cgiEnvironment.h" #include "task.h" #include "paramChecker.h" #include <boost/shared_ptr.hpp> +#include <boost/uuid/uuid.hpp> #include <libxml++/document.h> +class CgiEnvironment; +namespace cgicc { + class HTTPContentHeader; +} + class CgiApplicationEngine : public ApplicationEngine { public: - CgiApplicationEngine(const CgiEnvironment *); + CgiApplicationEngine(const CgiEnvironment *, cgicc::HTTPContentHeader *); virtual ~CgiApplicationEngine(); void process() const; @@ -20,7 +25,11 @@ class CgiApplicationEngine : public ApplicationEngine { w(doc->cobj()); } const Environment * env() const; + virtual void SessionSet(const Glib::ustring & name, const Glib::ustring & value) const; + virtual void SessionClear(const Glib::ustring & name) const; const CgiEnvironment * _env; + protected: + cgicc::HTTPContentHeader * header; private: mutable boost::shared_ptr<xmlpp::Document> doc; class Stage { @@ -39,7 +48,7 @@ class CgiApplicationEngine : public ApplicationEngine { virtual Stage * run(); std::string present; protected: - OrderedTasks tasks; + NoOutputExecutes tasks; }; class PresentStage : public Stage { public: @@ -52,6 +61,7 @@ class CgiApplicationEngine : public ApplicationEngine { Glib::ustring responseStyle; }; mutable Stage * currentStage; + mutable boost::uuids::uuid sessionID; }; #endif diff --git a/project2/dataSource.cpp b/project2/dataSource.cpp index 984ea53..9b6bd18 100644 --- a/project2/dataSource.cpp +++ b/project2/dataSource.cpp @@ -4,7 +4,7 @@ #include "rdbmsDataSource.h" _DataSource::_DataSource(const xmlpp::Element * p) : - _Project2SourceObject(p) + _SourceObject(p) { } @@ -15,5 +15,5 @@ _DataSource::~_DataSource() void _DataSource::AddLoaders(Loaders & l, DataSources & dss) { - l.insert(LoadersVT("rdbmsdatasource", _LoaderBase::Make<_RdbmsDataSource, _DataSource, std::string, _Project2SourceObject, &_Project2SourceObject::name>(&dss))); + l.insert(LoadersVT("rdbmsdatasource", _LoaderBase::Make<_RdbmsDataSource, _DataSource, std::string, _SourceObject, &_SourceObject::name>(&dss))); } diff --git a/project2/dataSource.h b/project2/dataSource.h index 9d30d07..0cc0124 100644 --- a/project2/dataSource.h +++ b/project2/dataSource.h @@ -11,7 +11,7 @@ class _DataSource; typedef boost::shared_ptr<_DataSource> DataSource; typedef std::map<std::string, DataSource> DataSources; -class _DataSource : public _Project2SourceObject { +class _DataSource : public virtual _SourceObject { public: _DataSource(const xmlpp::Element * p); virtual ~_DataSource(); diff --git a/project2/iterate.cpp b/project2/iterate.cpp new file mode 100644 index 0000000..02fc149 --- /dev/null +++ b/project2/iterate.cpp @@ -0,0 +1,41 @@ +#include "iterate.h" +#include <boost/foreach.hpp> +#include <syslog.h> +#include "xmlObjectLoader.h" +#include "sqlIterate.h" +#include "task.h" + +_Iterate::_Iterate(const xmlpp::Element * p) : + _SourceObject(p), + _NoOutputExecute(p) +{ + Loaders loaders; + _Iterate::AddLoaders(loaders, subIterates); + _Task::AddLoaders(loaders, subIterates); + _LoaderBase::collectAll(loaders, "project2", p, true, true); +} + +_Iterate::~_Iterate() +{ +} + +void +_Iterate::AddLoaders(Loaders & l, Iterates & iterates) +{ + l.insert(LoadersVT("sqliterate", _LoaderBase::Make<_SqlIterate, _Iterate, std::string, _SourceObject, &_SourceObject::name>(&iterates))); +} + +void +_Iterate::AddLoaders(Loaders & l, NoOutputExecutes & iterates) +{ + l.insert(LoadersVT("sqliterate", _LoaderBase::Make<_SqlIterate, _NoOutputExecute, unsigned int, _SourceObject, &_SourceObject::order>(&iterates))); +} + +void +_Iterate::executeChildren(const ApplicationEngine * ep, const PerRowValues * parent) const +{ + BOOST_FOREACH(NoOutputExecutes::value_type sq, subIterates) { + sq.second->execute(ep, this); + } +} + diff --git a/project2/iterate.h b/project2/iterate.h new file mode 100644 index 0000000..c113585 --- /dev/null +++ b/project2/iterate.h @@ -0,0 +1,33 @@ +#ifndef ITERATE_H +#define ITERATE_H + +#include <libxml++/nodes/element.h> +#include <boost/shared_ptr.hpp> +#include <map> +#include "sourceObject.h" +#include "xmlObjectLoader.h" +#include "perRowValues.h" +#include "noOutputExecute.h" + +class ApplicationEngine; +class _Iterate; +typedef boost::shared_ptr<_Iterate> Iterate; +typedef std::map<std::string, Iterate> Iterates; + +class _Iterate : public virtual _SourceObject, public PerRowValues, public _NoOutputExecute { + public: + _Iterate(const xmlpp::Element * p); + virtual ~_Iterate(); + virtual void execute(const ApplicationEngine *, const PerRowValues * parent = NULL) const = 0; + virtual Glib::ustring getCurrentValue(const Glib::ustring & id) const = 0; + + static void AddLoaders(Loaders & l, Iterates & vs); + static void AddLoaders(Loaders & l, NoOutputExecutes & vs); + protected: + void executeChildren(const ApplicationEngine *, const PerRowValues * parent = NULL) const; + NoOutputExecutes subIterates; +}; + +#endif + + diff --git a/project2/noOutputExecute.h b/project2/noOutputExecute.h new file mode 100644 index 0000000..ad5df92 --- /dev/null +++ b/project2/noOutputExecute.h @@ -0,0 +1,20 @@ +#ifndef NOOUTPUTEXECUTE_H +#define NOOUTPUTEXECUTE_H + +#include "sourceObject.h" + +class ApplicationEngine; +class PerRowValues; + +class _NoOutputExecute; +typedef boost::shared_ptr<_NoOutputExecute> NoOutputExecute; +typedef std::map<unsigned int, NoOutputExecute> NoOutputExecutes; + +class _NoOutputExecute : public virtual _SourceObject { + public: + _NoOutputExecute(const xmlpp::Element * p) : _SourceObject(p) { }; + virtual ~_NoOutputExecute() { } + virtual void execute(const ApplicationEngine *, const PerRowValues * parent = NULL) const = 0; +}; +#endif + diff --git a/project2/p2webMain.cpp b/project2/p2webMain.cpp index 1eafd2d..f424e0a 100644 --- a/project2/p2webMain.cpp +++ b/project2/p2webMain.cpp @@ -1,76 +1,62 @@ #include <libxml/tree.h> #include <cgicc/Cgicc.h> #include <cgicc/CgiEnvironment.h> +#include <cgicc/HTTPContentHeader.h> +FILE * realstdout = stdout; #include <fcgi_stdio.h> #include "cgiEnvironment.h" #include "cgiAppEngine.h" #include <boost/bind.hpp> +#include "FCgiIO.h" int xmlWrite(void * _out, const char * buf, int len) { - return FCGX_PutStr(buf, len, (FCGX_Stream*)_out); + cgicc::FCgiIO & IO = *((cgicc::FCgiIO*)_out); + IO.write(buf, len); + return len; } -class CgiReader : public cgicc::CgiInput { - public: - CgiReader(FCGX_Stream * i, FCGX_ParamArray & e) : - in(i), - envp(e) - { - } - ~CgiReader() { } - - size_t read(char * data, size_t length) - { - return FCGX_GetStr(data, length, in); - } - std::string getenv(const char * env) - { - const char * e = FCGX_GetParam(env, envp); - return e ? e : ""; - } - private: - FCGX_Stream *in; - FCGX_ParamArray envp; -}; int main(void) { if (!FCGX_IsCGI()) { - FCGX_Stream *in, *_out, *err; - FCGX_ParamArray envp; + FCGX_Request request; + + FCGX_Init(); + FCGX_InitRequest(&request, 0, 0); - while (FCGX_Accept(&in, &_out, &err, &envp) >= 0) - { - CgiReader reader(in, envp); - cgicc::Cgicc cgi(&reader); + while (FCGX_Accept_r(&request) == 0) { + cgicc::FCgiIO IO(request); try { + cgicc::Cgicc cgi(&IO); CgiEnvironment env(&cgi); - CgiApplicationEngine app(&env); + cgicc::HTTPContentHeader header("text/xml-xslt"); + CgiApplicationEngine app(&env, &header); app.process(); - FCGX_FPrintF(_out, "Content-type: text/xml-xslt\r\n\r\n"); + header.render(IO); xmlOutputBufferPtr out = xmlOutputBufferCreateIO( - xmlWrite, NULL, _out, xmlGetCharEncodingHandler(XML_CHAR_ENCODING_UTF8)); + xmlWrite, NULL, &IO, xmlGetCharEncodingHandler(XML_CHAR_ENCODING_UTF8)); app.write(boost::bind(xmlSaveFileTo, out, _1, "utf-8")); } catch (const std::exception & e) { - FCGX_FPrintF(_out, "Content-type: text/plain\r\n\r\n"); - FCGX_FPrintF(_out, "Kaboom!\r\n\r\n"); - FCGX_FPrintF(_out, "%s\r\n\r\n", e.what()); + cgicc::HTTPContentHeader header("text/plain"); + header.render(IO); + IO << "Kaboom!" << std::endl << std::endl << e.what(); } catch (...) { - FCGX_FPrintF(_out, "Content-type: text/plain\r\n\r\n"); - FCGX_FPrintF(_out, "Kaboom!\r\n\r\n"); - FCGX_FPrintF(_out, "Unknown exception.\r\n\r\n"); + cgicc::HTTPContentHeader header("text/plain"); + header.render(IO); + IO << "Kaboom!" << std::endl << std::endl << "Unknown exception."; } } } else { cgicc::Cgicc cgi(NULL); CgiEnvironment env(&cgi); - CgiApplicationEngine app(&env); + cgicc::HTTPContentHeader header("text/xml-xslt"); + CgiApplicationEngine app(&env, &header); app.process(); - //app.write(boost::bind(xmlDocDump, stdout, _1)); + app.write(boost::bind(xmlDocDump, realstdout, _1)); } return 0; } diff --git a/project2/paramChecker.cpp b/project2/paramChecker.cpp index 697728a..627f1be 100644 --- a/project2/paramChecker.cpp +++ b/project2/paramChecker.cpp @@ -4,14 +4,11 @@ #include "regexCheck.h" #include "sqlCheck.h" -unsigned int _ParamChecker::loadOrder = 1; - _ParamChecker::_ParamChecker(const xmlpp::Element * p) : - _Project2SourceObject(p), + _SourceObject(p), message(xmlChildText(p, "message")), applyTo(p->get_attribute_value("apply-to")), - present(p->get_attribute_value("present")), - order(loadOrder++) + present(p->get_attribute_value("present")) { } @@ -22,7 +19,7 @@ _ParamChecker::~_ParamChecker() void _ParamChecker::AddLoaders(Loaders & l, OrderedParamCheckers & checks) { - l.insert(LoadersVT("regexcheck", _LoaderBase::Make<_RegexCheck, _ParamChecker, unsigned int, _ParamChecker, &_ParamChecker::order>(&checks))); - l.insert(LoadersVT("sqlcheck", _LoaderBase::Make<_SqlCheck, _ParamChecker, unsigned int, _ParamChecker, &_ParamChecker::order>(&checks))); + l.insert(LoadersVT("regexcheck", _LoaderBase::Make<_RegexCheck, _ParamChecker, unsigned int, _SourceObject, &_SourceObject::order>(&checks))); + l.insert(LoadersVT("sqlcheck", _LoaderBase::Make<_SqlCheck, _ParamChecker, unsigned int, _SourceObject, &_SourceObject::order>(&checks))); } diff --git a/project2/paramChecker.h b/project2/paramChecker.h index 28c0275..1ffe89f 100644 --- a/project2/paramChecker.h +++ b/project2/paramChecker.h @@ -13,7 +13,7 @@ typedef boost::shared_ptr<_ParamChecker> ParamChecker; typedef std::map<std::string, ParamChecker> ParamCheckers; typedef std::map<unsigned int, ParamChecker> OrderedParamCheckers; -class _ParamChecker : public _Project2SourceObject { +class _ParamChecker : public virtual _SourceObject { public: _ParamChecker(const xmlpp::Element * p); virtual ~_ParamChecker(); @@ -23,11 +23,8 @@ class _ParamChecker : public _Project2SourceObject { const Glib::ustring message; const std::string applyTo; const std::string present; - const unsigned int order; static void AddLoaders(Loaders & l, OrderedParamCheckers & vs); - private: - static unsigned int loadOrder; }; #endif diff --git a/project2/perRowValues.h b/project2/perRowValues.h new file mode 100644 index 0000000..2a46763 --- /dev/null +++ b/project2/perRowValues.h @@ -0,0 +1,12 @@ +#ifndef PERROWVALUES_H +#define PERROWVALUES_H + +#include <glibmm/ustring.h> + +class PerRowValues { + public: + virtual Glib::ustring getCurrentValue(const Glib::ustring & id) const = 0; +}; + +#endif + diff --git a/project2/rdbmsDataSource.cpp b/project2/rdbmsDataSource.cpp index dad35a3..1a55fb8 100644 --- a/project2/rdbmsDataSource.cpp +++ b/project2/rdbmsDataSource.cpp @@ -3,6 +3,7 @@ #include <libxml++/nodes/textnode.h> _RdbmsDataSource::_RdbmsDataSource(const xmlpp::Element * p) : + _SourceObject(p), _DataSource(p), masterDsn(xmlChildText(p, "masterdsn")) { diff --git a/project2/regexCheck.cpp b/project2/regexCheck.cpp index abe134c..672194f 100644 --- a/project2/regexCheck.cpp +++ b/project2/regexCheck.cpp @@ -4,6 +4,7 @@ #include <boost/regex.hpp> _RegexCheck::_RegexCheck(const xmlpp::Element * p) : + _SourceObject(p), _ParamChecker(p), regex(xmlChildText(p, "regex").raw()) { diff --git a/project2/session.cpp b/project2/session.cpp new file mode 100644 index 0000000..87bea0c --- /dev/null +++ b/project2/session.cpp @@ -0,0 +1,27 @@ +#include "session.h" +#include <syslog.h> + +Session::Session() +{ +} + +Session::~Session() +{ +} + +SessionContainer::SessionContainer() +{ +} + +SessionContainer::~SessionContainer() +{ +} + +SessionPtr +SessionContainer::GetSession(boost::uuids::uuid & id) +{ + SessionPtr s = getSession(id); + s->ExpiryTime(time(NULL) + 3600); + return s; +} + diff --git a/project2/session.h b/project2/session.h new file mode 100644 index 0000000..de31626 --- /dev/null +++ b/project2/session.h @@ -0,0 +1,42 @@ +#ifndef SESSION_H +#define SESSION_H + +#include <map> +#include <glibmm/ustring.h> +#include <boost/uuid/uuid.hpp> +#include <boost/shared_ptr.hpp> + +class Session { + public: + typedef std::map<Glib::ustring, Glib::ustring> Values; + + Session(); + virtual ~Session() = 0; + + virtual Glib::ustring GetValue(const Glib::ustring & name) const = 0; + virtual Values GetValuesCopy() const = 0; + virtual void SetValue(const Glib::ustring & name, const Glib::ustring & 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::shared_ptr<Session> SessionPtr; + +class SessionContainer { + public: + SessionContainer(); + virtual ~SessionContainer() = 0; + + SessionPtr GetSession(boost::uuids::uuid & sid); + virtual void CleanUp() { } + + protected: + virtual SessionPtr getSession(boost::uuids::uuid & sid) = 0; +}; + + +#endif + diff --git a/project2/sessionClearTask.cpp b/project2/sessionClearTask.cpp new file mode 100644 index 0000000..c5d6d0d --- /dev/null +++ b/project2/sessionClearTask.cpp @@ -0,0 +1,21 @@ +#include <boost/foreach.hpp> +#include "xmlObjectLoader.h" +#include "sessionClearTask.h" +#include "appEngine.h" + +_SessionClearTask::_SessionClearTask(const xmlpp::Element * p) : + _SourceObject(p), + _Task(p) +{ +} + +_SessionClearTask::~_SessionClearTask() +{ +} + +void +_SessionClearTask::execute(const ApplicationEngine * ep, const PerRowValues *) const +{ + ep->SessionClear(key); +} + diff --git a/project2/sessionClearTask.h b/project2/sessionClearTask.h new file mode 100644 index 0000000..f3b779b --- /dev/null +++ b/project2/sessionClearTask.h @@ -0,0 +1,26 @@ +#ifndef SESSIONCLEARTASK_H +#define SESSIONCLEARTASK_H + +#include <libxml++/nodes/element.h> +#include <boost/shared_ptr.hpp> +#include <map> +#include "sourceObject.h" +#include "xmlObjectLoader.h" +#include "task.h" + +class ApplicationEngine; +class _SessionClearTask; +typedef boost::shared_ptr<_SessionClearTask> SessionClearTask; + +class _SessionClearTask : public virtual _Task { + public: + _SessionClearTask(const xmlpp::Element * p); + virtual ~_SessionClearTask(); + void execute(const ApplicationEngine *, const PerRowValues * parent = NULL) const; + + const Glib::ustring key; +}; + +#endif + + diff --git a/project2/sessionSetTask.cpp b/project2/sessionSetTask.cpp new file mode 100644 index 0000000..abd02b0 --- /dev/null +++ b/project2/sessionSetTask.cpp @@ -0,0 +1,33 @@ +#include <syslog.h> +#include <boost/foreach.hpp> +#include "xmlObjectLoader.h" +#include "sessionSetTask.h" +#include "appEngine.h" + +_SessionSetTask::_SessionSetTask(const xmlpp::Element * p) : + _SourceObject(p), + _Task(p), + IHaveParameters(p), + key(p->get_attribute_value("key")) +{ +} + +_SessionSetTask::~_SessionSetTask() +{ +} + +void +_SessionSetTask::execute(const ApplicationEngine * ep, const PerRowValues * parent) const +{ + Parameter p = parameters.find(0)->second; + if (p->source == "uri") { + ep->SessionSet(key, ep->env()->getParamUri(p->id)); + } + else if (p->source == "parent") { + ep->SessionSet(key, parent->getCurrentValue(p->id)); + } + else if (p->source == "query") { + ep->SessionSet(key, ep->env()->getParamQuery(p->id)); + } +} + diff --git a/project2/sessionSetTask.h b/project2/sessionSetTask.h new file mode 100644 index 0000000..32df37b --- /dev/null +++ b/project2/sessionSetTask.h @@ -0,0 +1,27 @@ +#ifndef SESSIONSETTASK_H +#define SESSIONSETTASK_H + +#include <libxml++/nodes/element.h> +#include <boost/shared_ptr.hpp> +#include <map> +#include "sourceObject.h" +#include "xmlObjectLoader.h" +#include "task.h" +#include "iHaveParameters.h" + +class ApplicationEngine; +class _SessionSetTask; +typedef boost::shared_ptr<_SessionSetTask> SessionSetTask; + +class _SessionSetTask : public virtual _Task, public IHaveParameters { + public: + _SessionSetTask(const xmlpp::Element * p); + virtual ~_SessionSetTask(); + void execute(const ApplicationEngine *, const PerRowValues * parent = NULL) const; + + const Glib::ustring key; +}; + +#endif + + diff --git a/project2/sessionShm.cpp b/project2/sessionShm.cpp new file mode 100644 index 0000000..c9f748c --- /dev/null +++ b/project2/sessionShm.cpp @@ -0,0 +1,128 @@ +#include "sessionShm.h" +#include <syslog.h> +#include <set> +#include <boost/uuid/uuid.hpp> +#include <boost/foreach.hpp> +#include <boost/uuid/uuid_generators.hpp> +#include <boost/lexical_cast.hpp> +#include <boost/uuid/uuid_io.hpp> + +using namespace boost::interprocess; +using namespace boost::uuids; +class SessionShmData { + public: + typedef boost::interprocess::string SKey; + typedef boost::interprocess::string SValue; + + typedef std::pair<const SKey, SValue> SValueType; + typedef boost::interprocess::allocator<SValueType, boost::interprocess::managed_mapped_file::segment_manager> AllocatorValueType; + typedef boost::interprocess::map<SKey, SValue, std::less<SKey>, AllocatorValueType> SessionValues; + + SessionShmData(); + ~SessionShmData(); + + SessionValues svs; + time_t expiryTime; + + static boost::interprocess::managed_mapped_file shm; + friend class SessionContainerShm; +}; + +const char * shmFile = "/tmp/project2.sessions"; + +boost::interprocess::managed_mapped_file SessionShmData::shm(open_or_create, shmFile, 1024 * 1024); + +SessionContainerShm::SessionContainerShm() +{ +} + +SessionContainerShm::~SessionContainerShm() +{ +} + +void +SessionContainerShm::CleanUp() +{ + std::set<std::string> toDelete; + for (managed_mapped_file::const_named_iterator i = SessionShmData::shm.named_begin(); + i != SessionShmData::shm.named_end(); i++) { + const SessionShmData * s = static_cast<const SessionShmData *>(i->value()); + if (s) { + if (s->expiryTime < time(NULL)) { + toDelete.insert(i->name()); + } + } + } + for(std::set<std::string>::const_iterator s = toDelete.begin(); s != toDelete.end(); s++) { + SessionShmData::shm.destroy<const SessionShmData>(s->c_str()); + } +} + +SessionPtr +SessionContainerShm::getSession(boost::uuids::uuid & sid) +{ + if (sid.is_nil()) { + sid = boost::uuids::random_generator()(); + } + return SessionPtr(new SessionShm( + SessionShmData::shm.find_or_construct<SessionShmData>(boost::lexical_cast<std::string>(sid).c_str())())); +} + +SessionShm::SessionShm(SessionShmData * d) : data(d) +{ +} + +SessionShm::~SessionShm() +{ +} + +void +SessionShm::ExpiryTime(time_t t) +{ + data->expiryTime = t; +} + +time_t +SessionShm::ExpiryTime() const +{ + return data->expiryTime; +} + +SessionShmData::SessionShmData() : + svs(std::less<SKey>(), AllocatorValueType(shm.get_segment_manager())) +{ +} + +SessionShmData::~SessionShmData() +{ +} + +Glib::ustring +SessionShm::GetValue(const Glib::ustring & name) const +{ + return data->svs.find(name.c_str())->second.c_str(); +} + +void +SessionShm::SetValue(const Glib::ustring & name, const Glib::ustring & value) +{ + data->svs.erase(name.c_str()); + data->svs.insert(std::pair<SessionShmData::SKey, SessionShmData::SValue>(name.c_str(), value.c_str())); +} + +void +SessionShm::ClearValue(const Glib::ustring & name) +{ + data->svs.erase(name.c_str()); +} + +Session::Values +SessionShm::GetValuesCopy() const +{ + Values v; + BOOST_FOREACH(SessionShmData::SessionValues::value_type kvp, data->svs) { + v[kvp.first.c_str()] = kvp.second.c_str(); + } + return v; +} + diff --git a/project2/sessionShm.h b/project2/sessionShm.h new file mode 100644 index 0000000..2794303 --- /dev/null +++ b/project2/sessionShm.h @@ -0,0 +1,38 @@ +#ifndef SESSIONSHM_H +#define SESSIONSHM_H + +#include "session.h" +#include <boost/interprocess/containers/string.hpp> +#include <boost/interprocess/managed_mapped_file.hpp> +#include <boost/interprocess/allocators/allocator.hpp> +#include <boost/interprocess/containers/map.hpp> + +class SessionShmData; +class SessionShm : public Session { + public: + SessionShm(SessionShmData *); + virtual ~SessionShm(); + + Glib::ustring GetValue(const Glib::ustring & name) const; + Values GetValuesCopy() const; + void SetValue(const Glib::ustring & name, const Glib::ustring & value); + void ClearValue(const Glib::ustring & name); + time_t ExpiryTime() const; + void ExpiryTime(time_t); + + private: + SessionShmData * data; +}; + +class SessionContainerShm : public SessionContainer { + public: + SessionContainerShm(); + ~SessionContainerShm(); + + void CleanUp(); + + protected: + SessionPtr getSession(boost::uuids::uuid & sid); +}; + +#endif diff --git a/project2/sourceObject.cpp b/project2/sourceObject.cpp index 9d10f52..bb989b5 100644 --- a/project2/sourceObject.cpp +++ b/project2/sourceObject.cpp @@ -1,11 +1,14 @@ #include "sourceObject.h" -_Project2SourceObject::_Project2SourceObject(const xmlpp::Element * p) : - name(p->get_attribute_value("name")) +unsigned int _SourceObject::loadOrder = 1; + +_SourceObject::_SourceObject(const xmlpp::Element * p) : + name(p->get_attribute_value("name")), + order(loadOrder++) { } -_Project2SourceObject::~_Project2SourceObject() +_SourceObject::~_SourceObject() { } diff --git a/project2/sourceObject.h b/project2/sourceObject.h index 421054d..b4472d4 100644 --- a/project2/sourceObject.h +++ b/project2/sourceObject.h @@ -4,12 +4,15 @@ #include <libxml++/nodes/element.h> #include <boost/shared_ptr.hpp> -class _Project2SourceObject { +class _SourceObject { public: - _Project2SourceObject(const xmlpp::Element * p); - virtual ~_Project2SourceObject() = 0; + _SourceObject(const xmlpp::Element * p); + virtual ~_SourceObject() = 0; const std::string name; + const unsigned int order; + private: + static unsigned int loadOrder; }; -typedef boost::shared_ptr<_Project2SourceObject> Project2SourceObject; +typedef boost::shared_ptr<_SourceObject> Project2SourceObject; #endif diff --git a/project2/sqlCheck.cpp b/project2/sqlCheck.cpp index 25094a6..1dab147 100644 --- a/project2/sqlCheck.cpp +++ b/project2/sqlCheck.cpp @@ -7,6 +7,7 @@ #include <boost/regex.hpp> _SqlCheck::_SqlCheck(const xmlpp::Element * p) : + _SourceObject(p), IHaveParameters(p), _ParamChecker(p), dataSource(p->get_attribute_value("datasource")), diff --git a/project2/sqlIterate.cpp b/project2/sqlIterate.cpp new file mode 100644 index 0000000..90a8bc1 --- /dev/null +++ b/project2/sqlIterate.cpp @@ -0,0 +1,61 @@ +#include "sqlIterate.h" +#include "xml.h" +#include "selectcommand.h" +#include "column.h" +#include <string.h> +#include <syslog.h> +#include <libxml++/nodes/textnode.h> +#include "xmlObjectLoader.h" +#include "environment.h" +#include "appEngine.h" + +_SqlIterate::_SqlIterate(const xmlpp::Element * p) : + _SourceObject(p), + IHaveParameters(p), + _Iterate(p), + dataSource(p->get_attribute_value("datasource")), + sql(xmlChildText(p, "sql")), + query(NULL) +{ +} + +Glib::ustring +_SqlIterate::getCurrentValue(const Glib::ustring & id) const +{ + return (*query)[id].compose(); +} + +void +_SqlIterate::rebindCurrentValue(const Glib::ustring & id, ODBC::Command * cmd, unsigned int bind) const +{ + (*query)[id].rebind(cmd, bind); +} + +void _SqlIterate::execute(const ApplicationEngine * ep, const PerRowValues * parent) const +{ + typedef std::map<std::string, xmlpp::Element *> Columns; + 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->env()->getParamUri(p.second->id)); + } + else if (p.second->source == "query") { + query->bindParamS(p.second->bind, ep->env()->getParamQuery(p.second->id)); + } + else if (parent && p.second->source == "parent") { + const _SqlIterate * psqlIterate = dynamic_cast<const _SqlIterate *>(parent); + if (psqlIterate) { + psqlIterate->rebindCurrentValue(p.second->id, query, p.second->bind); + } + else { + query->bindParamS(p.second->bind, parent->getCurrentValue(p.second->id)); + } + } + } + while (query->fetch()) { + executeChildren(ep, this); + } + delete query; + query = NULL; +} + diff --git a/project2/sqlIterate.h b/project2/sqlIterate.h new file mode 100644 index 0000000..c9cef49 --- /dev/null +++ b/project2/sqlIterate.h @@ -0,0 +1,29 @@ +#ifndef SQLITERATE_H +#define SQLITERATE_H + +#include <libxml++/nodes/element.h> +#include <boost/shared_ptr.hpp> +#include <map> +#include "selectcommand.h" +#include "iterate.h" +#include "rdbmsDataSource.h" +#include "iHaveParameters.h" + +class ApplicationEngine; + +class _SqlIterate : public IHaveParameters, public _Iterate { + public: + _SqlIterate(const xmlpp::Element * p); + void execute(const ApplicationEngine *, const PerRowValues * parent = NULL) const; + Glib::ustring getCurrentValue(const Glib::ustring & id) const; + const std::string dataSource; + const Glib::ustring sql; + void rebindCurrentValue(const Glib::ustring & id, ODBC::Command *, unsigned int) const; + private: + mutable ODBC::SelectCommand * query; +}; +typedef boost::shared_ptr<_SqlIterate> SqlIterate; +typedef std::map<std::string, SqlIterate> SqlIterates; + +#endif + diff --git a/project2/sqlTask.cpp b/project2/sqlTask.cpp index 2832f73..93e656e 100644 --- a/project2/sqlTask.cpp +++ b/project2/sqlTask.cpp @@ -7,6 +7,7 @@ #include "sqlView.h" _SqlTask::_SqlTask(const xmlpp::Element * p) : + _SourceObject(p), _Task(p), IHaveParameters(p), dataSource(p->get_attribute_value("datasource")), @@ -19,7 +20,7 @@ _SqlTask::~_SqlTask() } void -_SqlTask::execute(const ApplicationEngine * ep, const _View * parent) const +_SqlTask::execute(const ApplicationEngine * ep, const PerRowValues * parent) const { ODBC::ModifyCommand modify(ep->dataSource<_RdbmsDataSource>(dataSource)->getWritable(), sql); BOOST_FOREACH(Parameters::value_type p, parameters) { diff --git a/project2/sqlTask.h b/project2/sqlTask.h index 75333e3..a64b837 100644 --- a/project2/sqlTask.h +++ b/project2/sqlTask.h @@ -14,7 +14,7 @@ class _SqlTask : public _Task, public IHaveParameters { public: _SqlTask(const xmlpp::Element * p); virtual ~_SqlTask(); - virtual void execute(const ApplicationEngine *, const _View * parent = NULL) const; + virtual void execute(const ApplicationEngine *, const PerRowValues * parent = NULL) const; const std::string dataSource; const std::string sql; diff --git a/project2/sqlView.cpp b/project2/sqlView.cpp index 1fe0a0d..cab4ca5 100644 --- a/project2/sqlView.cpp +++ b/project2/sqlView.cpp @@ -9,6 +9,7 @@ #include "appEngine.h" _SqlView::_SqlView(const xmlpp::Element * p) : + _SourceObject(p), IHaveParameters(p), _View(p), dataSource(p->get_attribute_value("datasource")), @@ -98,9 +99,7 @@ void _SqlView::execute(xmlpp::Element * par, const ApplicationEngine * ep, const free(name); free(attr); } - BOOST_FOREACH(Views::value_type sq, subViews) { - sq.second->execute(record, ep, this); - } + executeChildren(record, ep, this); } delete query; query = NULL; diff --git a/project2/task.cpp b/project2/task.cpp index 9800b78..a84ad7e 100644 --- a/project2/task.cpp +++ b/project2/task.cpp @@ -2,12 +2,12 @@ #include <boost/foreach.hpp> #include "xmlObjectLoader.h" #include "sqlTask.h" - -unsigned int _Task::loadOrder = 1; +#include "sessionClearTask.h" +#include "sessionSetTask.h" _Task::_Task(const xmlpp::Element * p) : - _Project2SourceObject(p), - order(loadOrder++) + _SourceObject(p), + _NoOutputExecute(p) { } @@ -18,6 +18,16 @@ _Task::~_Task() void _Task::AddLoaders(Loaders & l, OrderedTasks & tasks) { - l.insert(LoadersVT("sqltask", _LoaderBase::Make<_SqlTask, _Task, unsigned int, _Task, &_Task::order>(&tasks))); + l.insert(LoadersVT("sqltask", _LoaderBase::Make<_SqlTask, _Task, unsigned int, _SourceObject, &_SourceObject::order>(&tasks))); + l.insert(LoadersVT("sessionclear", _LoaderBase::Make<_SessionClearTask, _Task, unsigned int, _SourceObject, &_SourceObject::order>(&tasks))); + l.insert(LoadersVT("sessionset", _LoaderBase::Make<_SessionSetTask, _Task, unsigned int, _SourceObject, &_SourceObject::order>(&tasks))); +} + +void +_Task::AddLoaders(Loaders & l, NoOutputExecutes & tasks) +{ + l.insert(LoadersVT("sqltask", _LoaderBase::Make<_SqlTask, _NoOutputExecute, unsigned int, _SourceObject, &_SourceObject::order>(&tasks))); + l.insert(LoadersVT("sessionclear", _LoaderBase::Make<_SessionClearTask, _NoOutputExecute, unsigned int, _SourceObject, &_SourceObject::order>(&tasks))); + l.insert(LoadersVT("sessionset", _LoaderBase::Make<_SessionSetTask, _NoOutputExecute, unsigned int, _SourceObject, &_SourceObject::order>(&tasks))); } diff --git a/project2/task.h b/project2/task.h index 00fce4b..b79687b 100644 --- a/project2/task.h +++ b/project2/task.h @@ -7,6 +7,7 @@ #include "sourceObject.h" #include "xmlObjectLoader.h" #include "view.h" +#include "noOutputExecute.h" class ApplicationEngine; class _Task; @@ -14,16 +15,14 @@ typedef boost::shared_ptr<_Task> Task; typedef std::map<std::string, Task> Tasks; typedef std::map<unsigned int, Task> OrderedTasks; -class _Task : public _Project2SourceObject { +class _Task : public virtual _SourceObject, public _NoOutputExecute { public: _Task(const xmlpp::Element * p); virtual ~_Task(); - virtual void execute(const ApplicationEngine *, const _View * parent = NULL) const = 0; - const unsigned int order; + virtual void execute(const ApplicationEngine *, const PerRowValues * parent = NULL) const = 0; static void AddLoaders(Loaders & l, OrderedTasks & vs); - private: - static unsigned int loadOrder; + static void AddLoaders(Loaders & l, NoOutputExecutes & vs); }; #endif diff --git a/project2/view.cpp b/project2/view.cpp index 31596d5..799d1ae 100644 --- a/project2/view.cpp +++ b/project2/view.cpp @@ -4,7 +4,7 @@ #include "sqlView.h" _View::_View(const xmlpp::Element * p) : - _Project2SourceObject(p), + _SourceObject(p), recordName(p->get_attribute_value("recordname")) { } @@ -16,6 +16,14 @@ _View::~_View() void _View::AddLoaders(Loaders & l, Views & views) { - l.insert(LoadersVT("sqlview", _LoaderBase::Make<_SqlView, _View, std::string, _Project2SourceObject, &_Project2SourceObject::name>(&views))); + l.insert(LoadersVT("sqlview", _LoaderBase::Make<_SqlView, _View, std::string, _SourceObject, &_SourceObject::name>(&views))); +} + +void +_View::executeChildren(xmlpp::Element * record, const ApplicationEngine * ep, const _View * parent) const +{ + BOOST_FOREACH(Views::value_type sq, subViews) { + sq.second->execute(record, ep, this); + } } diff --git a/project2/view.h b/project2/view.h index 43f2792..9bd88ed 100644 --- a/project2/view.h +++ b/project2/view.h @@ -6,13 +6,14 @@ #include <map> #include "sourceObject.h" #include "xmlObjectLoader.h" +#include "perRowValues.h" class ApplicationEngine; class _View; typedef boost::shared_ptr<_View> View; typedef std::map<std::string, View> Views; -class _View : public _Project2SourceObject { +class _View : public virtual _SourceObject, public PerRowValues { public: _View(const xmlpp::Element * p); virtual ~_View(); @@ -22,6 +23,7 @@ class _View : public _Project2SourceObject { static void AddLoaders(Loaders & l, Views & vs); protected: + void executeChildren(xmlpp::Element *, const ApplicationEngine *, const _View * parent = NULL) const; Views subViews; }; |