summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrandomdan <randomdan@localhost>2012-02-12 14:39:28 +0000
committerrandomdan <randomdan@localhost>2012-02-12 14:39:28 +0000
commit722901e3922cda2e53707c84700a309a99ff9d55 (patch)
treedebeb5af1f05909003f8a8ace816f4578e5af587
parentAdd some more aggregates (diff)
downloadproject2-722901e3922cda2e53707c84700a309a99ff9d55.tar.bz2
project2-722901e3922cda2e53707c84700a309a99ff9d55.tar.xz
project2-722901e3922cda2e53707c84700a309a99ff9d55.zip
Adds support for presenter level caching modules and implements a file based one (requires xattr support)
-rw-r--r--project2/cgi/cgiAppEngine.cpp51
-rw-r--r--project2/cgi/cgiAppEngine.h16
-rw-r--r--project2/cgi/cgiEnvironment.cpp6
-rw-r--r--project2/cgi/cgiEnvironment.h1
-rw-r--r--project2/cgi/cgiStageCacheHit.cpp27
-rw-r--r--project2/cgi/cgiStagePresent.cpp12
-rw-r--r--project2/common/environment.h1
-rw-r--r--project2/common/exceptions.cpp23
-rw-r--r--project2/common/exceptions.h14
-rw-r--r--project2/common/presenterCache.cpp25
-rw-r--r--project2/common/presenterCache.h21
-rw-r--r--project2/common/transform.cpp19
-rw-r--r--project2/common/transform.h7
-rw-r--r--project2/console/consoleEnvironment.cpp6
-rw-r--r--project2/console/consoleEnvironment.h1
-rw-r--r--project2/files/Jamfile.jam2
-rw-r--r--project2/files/presenterCache.cpp187
-rw-r--r--project2/json/transformStream.cpp25
-rw-r--r--project2/xml/transformXml.cpp14
19 files changed, 402 insertions, 56 deletions
diff --git a/project2/cgi/cgiAppEngine.cpp b/project2/cgi/cgiAppEngine.cpp
index b92095c..9e91800 100644
--- a/project2/cgi/cgiAppEngine.cpp
+++ b/project2/cgi/cgiAppEngine.cpp
@@ -27,7 +27,8 @@ getSessionID(const std::vector<cgicc::HTTPCookie> & cookies) {
CgiApplicationEngine::CgiApplicationEngine(const CgiEnvironment * e, std::ostream & io) :
_env(e),
sessionsContainer(LoaderBase::getLoader<SessionContainerLoader, NotSupported>(e->sessionModule)->open()),
- IO(io)
+ IO(io),
+ outputCachingActive(false)
{
cursession = sessionsContainer->GetSession(getSessionID(e->getCookieList()));
currentStage = NextStage(new InitialStage(e));
@@ -55,7 +56,7 @@ class CgiResult : public TransformChainLink {
const std::string encoding;
};
-class WriteToCgiResult : public TransformImpl<WritableContent, CgiResult> {
+class WritableToCgiResult : public TransformImpl<WritableContent, CgiResult> {
public:
void transform(const WritableContent * wc, CgiResult * cr) const {
cr->header->addHeader("Content-Type", Glib::ustring::compose("%1; charset=%2", wc->getContentType(), cr->encoding));
@@ -63,23 +64,32 @@ class WriteToCgiResult : public TransformImpl<WritableContent, CgiResult> {
wc->writeTo(cr->stream, cr->encoding);
}
};
-DECLARE_TRANSFORM(WriteToCgiResult);
+DECLARE_TRANSFORM(WritableToCgiResult);
-bool
-addFinalTransformTarget(TransformSourcePtr ts, TransformChainLink * tcl)
+class StaticToCgiResult : public TransformImpl<StaticContent, CgiResult> {
+ public:
+ void transform(const StaticContent * sc, CgiResult * cr) const {
+ cr->header->addHeader("Content-Type", Glib::ustring::compose("%1; charset=%2", sc->getContentType(), sc->getEncoding()));
+ cr->header->render(cr->stream);
+ sc->writeTo(cr->stream);
+ }
+};
+DECLARE_TRANSFORM(StaticToCgiResult);
+
+TransformSourcePtr
+finalTransformSource(TransformSourcePtr ts)
{
if (ts->getTargets().empty()) {
- ts->addTarget(tcl, NULL);
- return true;
+ return ts;
}
BOOST_FOREACH(const Targets::value_type & t, ts->getTargets()) {
if (TransformSource * tr = dynamic_cast<TransformSource *>(t.first.get())) {
- if (addFinalTransformTarget(tr, tcl)) {
- return true;
+ if (TransformSourcePtr f = finalTransformSource(tr)) {
+ return f;
}
}
}
- return false;
+ return NULL;
}
void
@@ -117,6 +127,7 @@ CgiApplicationEngine::process() const
} while (currentStage.get<0>());
endTime = boost::date_time::microsec_clock<boost::posix_time::ptime>::universal_time();
ResponseStagePtr rs = currentStage.get<1>();
+ outputCachingActive = !rs->caches.empty();
if (const MultiRowSetPresenter * p = currentStage.get<3>().get()) {
addAppData(p, rs->outputOptions);
addEnvData(p, rs->outputOptions);
@@ -128,8 +139,12 @@ CgiApplicationEngine::process() const
_env->getServerName().substr(_env->getServerName().find(".")), env()->sessionTimeOut, "/", false));
}
if (TransformSourcePtr ts = currentStage.get<2>()) {
- addFinalTransformTarget(ts, new CgiResult(header, IO,
- rs && rs->root ? rs->root->value("encoding", _env->outputEncoding) : VariableType(_env->outputEncoding)));
+ TransformSourcePtr final = finalTransformSource(ts);
+ final->addTarget(new CgiResult(header, IO,
+ rs && rs->root ? rs->root->value("encoding", _env->outputEncoding) : VariableType(_env->outputEncoding)), NULL);
+ BOOST_FOREACH(const PresenterCachePtr & p, rs->caches) {
+ final->addTarget(p, NULL);
+ }
std::fstream * ddd = NULL;
if (!_env->dumpdatadoc.empty()) {
ddd = new std::fstream(_env->dumpdatadoc.c_str(), std::fstream::trunc | std::fstream::out);
@@ -169,8 +184,10 @@ CgiApplicationEngine::addEnvData(const MultiRowSetPresenter * p, OutputOptionsPt
addEnvToPresenter(p, "serverport", &cgicc::CgiEnvironment::getServerPort);
addEnvToPresenter(p, "serverhttps", &cgicc::CgiEnvironment::usingHTTPS);
// Request stuff
- addEnvToPresenter(p, "referrer", &cgicc::CgiEnvironment::getReferrer);
- addEnvToPresenter(p, "querystring", &cgicc::CgiEnvironment::getQueryString);
+ if (!outputCachingActive) {
+ addEnvToPresenter(p, "referrer", &cgicc::CgiEnvironment::getReferrer);
+ addEnvToPresenter(p, "querystring", &cgicc::CgiEnvironment::getQueryString);
+ }
p->finishRowSet();
}
@@ -186,7 +203,7 @@ CgiApplicationEngine::addEnvData(const MultiRowSetPresenter * p, OutputOptionsPt
p->finishRowSet();
}
- if (!o || o->Parameters()) {
+ if (!outputCachingActive && (!o || o->Parameters())) {
// Parameters
p->addNewRowSet("params", env()->scriptNamespacePrefix);
BOOST_FOREACH(cgicc::FormEntry fe, _env->cgi->getElements()) {
@@ -214,7 +231,7 @@ CgiApplicationEngine::addAppData(const MultiRowSetPresenter * p, OutputOptionsPt
if (!o || o->Core()) {
addCoreAppData(p);
}
- if (!o || o->Session()) {
+ if (!outputCachingActive && (!o || o->Session())) {
// Sessions variables
p->addNewRowSet("session", env()->scriptNamespacePrefix);
p->addAttribute("id", cursession->ID.str());
@@ -222,7 +239,7 @@ CgiApplicationEngine::addAppData(const MultiRowSetPresenter * p, OutputOptionsPt
p->finishRowSet();
}
- if (!o || o->Timing()) {
+ if (!outputCachingActive && (!o || o->Timing())) {
// Timing info
p->addNewRowSet("timing", env()->scriptNamespacePrefix);
p->addAttribute("start", startTime);
diff --git a/project2/cgi/cgiAppEngine.h b/project2/cgi/cgiAppEngine.h
index 64f081d..b362ece 100644
--- a/project2/cgi/cgiAppEngine.h
+++ b/project2/cgi/cgiAppEngine.h
@@ -9,6 +9,7 @@
#include "viewHost.h"
#include "transform.h"
#include "xmlPresenter.h"
+#include "presenterCache.h"
#include "sessionContainer.h"
#include <boost/intrusive_ptr.hpp>
#include <boost/tuple/tuple.hpp>
@@ -67,11 +68,14 @@ class CgiApplicationEngine : public ApplicationEngine, public TransformChainLink
/// Base class for a stage that can be a response to the client
class ResponseStage : public Stage {
public:
+ typedef ANONORDEREDSTORAGEOF(PresenterCache) PresenterCaches;
+
ResponseStage(const CgiEnvironment * e, ScriptNodePtr root);
virtual HttpHeaderPtr getHeader() const = 0;
OutputOptionsPtr outputOptions;
ScriptNodePtr root;
+ PresenterCaches caches;
};
/// Stage implementation used to bootstrap the iteration process based on the CGI environment
@@ -104,6 +108,17 @@ class CgiApplicationEngine : public ApplicationEngine, public TransformChainLink
mutable MultiRowSetPresenterPtr presenter;
};
+ /// Stage to return previous cached output
+ class CacheHitStage : public virtual ResponseStage {
+ public:
+ CacheHitStage(const CgiEnvironment * e, ScriptNodePtr, PresenterCachePtr);
+
+ virtual NextStage run();
+ virtual HttpHeaderPtr getHeader() const;
+ protected:
+ PresenterCachePtr pc;
+ };
+
/// The built-in fail-safe not found stage
class DefaultNotFoundStage : public virtual ResponseStage {
public:
@@ -150,6 +165,7 @@ class CgiApplicationEngine : public ApplicationEngine, public TransformChainLink
mutable NextStage currentStage;
SessionPtr cursession;
mutable std::ostream & IO;
+ mutable bool outputCachingActive;
};
#endif
diff --git a/project2/cgi/cgiEnvironment.cpp b/project2/cgi/cgiEnvironment.cpp
index b1565ad..001d4bd 100644
--- a/project2/cgi/cgiEnvironment.cpp
+++ b/project2/cgi/cgiEnvironment.cpp
@@ -85,6 +85,12 @@ CgiEnvironment::getParamUri(unsigned int p) const
return elems[p];
}
+unsigned int
+CgiEnvironment::getParamUriCount() const
+{
+ return elems.size();
+}
+
Glib::ustring
CgiEnvironment::getParamQuery(const std::string & p) const
{
diff --git a/project2/cgi/cgiEnvironment.h b/project2/cgi/cgiEnvironment.h
index 25ea90f..78f8730 100644
--- a/project2/cgi/cgiEnvironment.h
+++ b/project2/cgi/cgiEnvironment.h
@@ -28,6 +28,7 @@ class CgiEnvironment : public Environment, public cgicc::CgiEnvironment {
virtual ~CgiEnvironment();
Glib::ustring getParamUri(unsigned int idx) const;
+ unsigned int getParamUriCount() const;
Glib::ustring getParamQuery(const std::string & idx) const;
std::string getServerName() const { return cgicc::CgiEnvironment::getServerName(); }
std::string getScriptName() const { return cgicc::CgiEnvironment::getScriptName(); }
diff --git a/project2/cgi/cgiStageCacheHit.cpp b/project2/cgi/cgiStageCacheHit.cpp
new file mode 100644
index 0000000..728cc56
--- /dev/null
+++ b/project2/cgi/cgiStageCacheHit.cpp
@@ -0,0 +1,27 @@
+#include <pch.hpp>
+#include "cgiAppEngine.h"
+#include "cgiEnvironment.h"
+#include "cgiHttpHeader.h"
+#include <boost/foreach.hpp>
+#include <boost/bind.hpp>
+
+CgiApplicationEngine::CacheHitStage::CacheHitStage(const CgiEnvironment * e, ScriptNodePtr s, PresenterCachePtr pcp) :
+ CgiApplicationEngine::ResponseStage(e, s),
+ pc(pcp)
+{
+}
+
+CgiApplicationEngine::NextStage
+CgiApplicationEngine::CacheHitStage::run()
+{
+ return NextStage(NULL, this, pc, NULL);
+}
+
+CgiApplicationEngine::HttpHeaderPtr
+CgiApplicationEngine::CacheHitStage::getHeader() const
+{
+ Project2HttpHeader * header = new Project2HttpHeader("200 OK");
+ header->addHeader("Cache-control", "no-cache");
+ return HttpHeaderPtr(header);
+}
+
diff --git a/project2/cgi/cgiStagePresent.cpp b/project2/cgi/cgiStagePresent.cpp
index 152b906..b5e73b5 100644
--- a/project2/cgi/cgiStagePresent.cpp
+++ b/project2/cgi/cgiStagePresent.cpp
@@ -13,12 +13,24 @@ CgiApplicationEngine::PresentStage::PresentStage(const CgiEnvironment * e, Scrip
{
s->loader.addLoadTarget(s->root(), Storer::into<OutputOptionsLoader>(&outputOptions));
s->loader.addLoadTarget(s->root(), Storer::into<PresenterLoader>(&presenter));
+ s->loader.addLoadTarget(s->root(), Storer::into<ElementLoader>(&caches));
}
CgiApplicationEngine::NextStage
CgiApplicationEngine::PresentStage::run()
{
runChecks();
+ PresenterCaches backFill;
+ BOOST_FOREACH(const PresenterCachePtr & pc, caches) {
+ if (pc->check()) {
+ CacheHitStage * chs = new CacheHitStage(e, root, pc);
+ chs->caches = backFill;
+ return NextStage(NULL, chs, pc, NULL);
+ }
+ else {
+ backFill.push_back(pc);
+ }
+ }
try {
executeViews();
return NextStage(NULL, this, boost::dynamic_pointer_cast<TransformSource>(presenter), presenter);
diff --git a/project2/common/environment.h b/project2/common/environment.h
index 8c6ae61..0c33283 100644
--- a/project2/common/environment.h
+++ b/project2/common/environment.h
@@ -21,6 +21,7 @@ class Environment {
static const Environment * getCurrent();
virtual Glib::ustring getParamUri(unsigned int idx) const = 0;
+ virtual unsigned int getParamUriCount() const = 0;
virtual Glib::ustring getParamQuery(const std::string & idx) const = 0;
virtual std::string getServerName() const = 0;
diff --git a/project2/common/exceptions.cpp b/project2/common/exceptions.cpp
index 2fa5509..4f061ab 100644
--- a/project2/common/exceptions.cpp
+++ b/project2/common/exceptions.cpp
@@ -48,3 +48,26 @@ two_part_error::what() const throw()
return buf;
}
+
+syscall_error::syscall_error(int e) :
+ err(e),
+ buf(NULL)
+{
+}
+
+syscall_error::~syscall_error() throw()
+{
+ free(buf);
+}
+
+const char *
+syscall_error::what() const throw()
+{
+ if (!buf) {
+ if (asprintf(&buf, "%s (%d)", strerror(err), err) < 1) {
+ throw std::bad_alloc();
+ }
+ }
+ return buf;
+}
+
diff --git a/project2/common/exceptions.h b/project2/common/exceptions.h
index a45e53d..6d3410d 100644
--- a/project2/common/exceptions.h
+++ b/project2/common/exceptions.h
@@ -12,6 +12,15 @@ class numeric_error : public std::exception {
int err;
mutable char * buf;
};
+class syscall_error : public std::exception {
+ public:
+ syscall_error(int);
+ ~syscall_error() throw();
+ const char * what() const throw();
+ private:
+ int err;
+ mutable char * buf;
+};
class two_part_error : public std::exception {
public:
two_part_error(const std::string & what1, const std::string & what2);
@@ -47,6 +56,11 @@ class Name : public numeric_error { \
public: \
Name(int e) : numeric_error(e) { } \
}
+#define SimpleSysCallException(Name) \
+class Name : public syscall_error { \
+ public: \
+ Name(int e) : syscall_error(e) { } \
+}
SimpleNumericException(UriElementOutOfRange);
SimpleMessageException(ParamNotFound);
diff --git a/project2/common/presenterCache.cpp b/project2/common/presenterCache.cpp
new file mode 100644
index 0000000..4771eed
--- /dev/null
+++ b/project2/common/presenterCache.cpp
@@ -0,0 +1,25 @@
+#include "presenterCache.h"
+#include <boost/foreach.hpp>
+
+PresenterCache::PresenterCache(ScriptNodePtr s) :
+ SourceObject(s),
+ IHaveParameters(s),
+ encoding(s->value("encoding", "utf-8").as<std::string>())
+{
+}
+
+void
+PresenterCache::applyKeys(const boost::function2<void, const std::string &, const VariableType &> & f) const
+{
+ BOOST_FOREACH(const IHaveParameters::Parameters::value_type & p, allParameters()) {
+ f(p.first, p.second);
+ }
+}
+
+class WriteToCache : public TransformImpl<WritableContent, PresenterCache> {
+ public:
+ void transform(const WritableContent * wc, PresenterCache * pc) const {
+ wc->writeTo(pc->writeCache(wc->getContentType(), pc->encoding), pc->encoding);
+ }
+};
+DECLARE_TRANSFORM(WriteToCache);
diff --git a/project2/common/presenterCache.h b/project2/common/presenterCache.h
new file mode 100644
index 0000000..92de2d2
--- /dev/null
+++ b/project2/common/presenterCache.h
@@ -0,0 +1,21 @@
+#ifndef PRESENTER_CACHE_H
+#define PRESENTER_CACHE_H
+
+#include "transform.h"
+#include "scripts.h"
+#include "iHaveParameters.h"
+
+class PresenterCache : public SourceObject, public virtual TransformSource, public IHaveParameters {
+ public:
+ PresenterCache(ScriptNodePtr);
+ virtual bool check() const = 0;
+
+ virtual std::ostream & writeCache(const std::string & ct, const std::string & encoding) = 0;
+ const std::string encoding;
+
+ protected:
+ void applyKeys(const boost::function2<void, const std::string &, const VariableType &> & f) const;
+};
+typedef boost::intrusive_ptr<PresenterCache> PresenterCachePtr;
+
+#endif
diff --git a/project2/common/transform.cpp b/project2/common/transform.cpp
index 202da6a..5a40ce3 100644
--- a/project2/common/transform.cpp
+++ b/project2/common/transform.cpp
@@ -1,6 +1,7 @@
#include <pch.hpp>
#include "transform.h"
#include "logger.h"
+#include "ostreamWrapper.h"
#include <boost/foreach.hpp>
class TransformTargetStorer : public Storer {
@@ -72,3 +73,21 @@ TransformSource::getTargets() const
return targets;
}
+class TransformWritableContentToStdStream : public TransformImpl<WritableContent, ostreamWrapper> {
+ public:
+ void transform(const WritableContent * wc, ostreamWrapper * o) const
+ {
+ wc->writeTo(o->strm, "UTF-8");
+ }
+};
+DECLARE_TRANSFORM(TransformWritableContentToStdStream);
+
+class TransformStaticContentToStdStream : public TransformImpl<StaticContent, ostreamWrapper> {
+ public:
+ void transform(const StaticContent * wc, ostreamWrapper * o) const
+ {
+ wc->writeTo(o->strm);
+ }
+};
+DECLARE_TRANSFORM(TransformStaticContentToStdStream);
+
diff --git a/project2/common/transform.h b/project2/common/transform.h
index a9dde49..e3bdf4f 100644
--- a/project2/common/transform.h
+++ b/project2/common/transform.h
@@ -98,5 +98,12 @@ class WritableContent {
virtual void writeTo(std::ostream &, const std::string & encoding) const = 0;
};
+class StaticContent {
+ public:
+ virtual Glib::ustring getContentType() const = 0;
+ virtual Glib::ustring getEncoding() const = 0;
+ virtual void writeTo(std::ostream &) const = 0;
+};
+
#endif
diff --git a/project2/console/consoleEnvironment.cpp b/project2/console/consoleEnvironment.cpp
index 25c2f40..8f4465c 100644
--- a/project2/console/consoleEnvironment.cpp
+++ b/project2/console/consoleEnvironment.cpp
@@ -71,6 +71,12 @@ ConsoleEnvironment::getParamUri(unsigned int idx) const
throw UriElementOutOfRange(idx);
}
+unsigned int
+ConsoleEnvironment::getParamUriCount() const
+{
+ return uriParams.size();
+}
+
Glib::ustring
ConsoleEnvironment::getParamQuery(const std::string & p) const
{
diff --git a/project2/console/consoleEnvironment.h b/project2/console/consoleEnvironment.h
index a5530a9..6d57d3c 100644
--- a/project2/console/consoleEnvironment.h
+++ b/project2/console/consoleEnvironment.h
@@ -18,6 +18,7 @@ class ConsoleEnvironment : public Environment {
Glib::ustring getParamUri(unsigned int idx) const;
+ unsigned int getParamUriCount() const;
Glib::ustring getParamQuery(const std::string & idx) const;
std::string getServerName() const;
std::string getScriptName() const;
diff --git a/project2/files/Jamfile.jam b/project2/files/Jamfile.jam
index 54df687..bdb851f 100644
--- a/project2/files/Jamfile.jam
+++ b/project2/files/Jamfile.jam
@@ -4,6 +4,7 @@ alias glibmm : : : :
;
lib boost_system : : <name>boost_system ;
lib boost_filesystem : : <name>boost_filesystem ;
+lib boost_iostreams : : <name>boost_iostreams ;
cpp-pch pch : pch.hpp :
<library>../common//p2common
@@ -16,6 +17,7 @@ lib p2files :
<library>glibmm
<library>boost_filesystem
<library>boost_system
+ <library>boost_iostreams
<library>../common//p2common
: :
<include>.
diff --git a/project2/files/presenterCache.cpp b/project2/files/presenterCache.cpp
new file mode 100644
index 0000000..76a4e86
--- /dev/null
+++ b/project2/files/presenterCache.cpp
@@ -0,0 +1,187 @@
+#include "../common/presenterCache.h"
+#include "../common/exceptions.h"
+#include "../common/options.h"
+#include "../common/environment.h"
+#include <fcntl.h>
+#include <attr/xattr.h>
+#include <sys/stat.h>
+#include <boost/iostreams/device/file_descriptor.hpp>
+#include <boost/iostreams/stream.hpp>
+#include <boost/filesystem/path.hpp>
+#include <boost/filesystem/operations.hpp>
+#include <boost/bind.hpp>
+#include <glibmm/convert.h>
+#include <sys/file.h>
+
+SimpleSysCallException(OpenCacheFile);
+SimpleSysCallException(StatCacheFile);
+SimpleSysCallException(LockCacheFile);
+SimpleSysCallException(CacheFileXAttr);
+
+template <class E>
+int safesys(int n, int r) {
+ if (r == n) {
+ throw E(errno);
+ }
+ return r;
+}
+
+class FilePresenterCache : public PresenterCache, public StaticContent, public SourceOf<StaticContent> {
+ public:
+ FilePresenterCache(ScriptNodePtr s) :
+ PresenterCache(s),
+ readcachefd(0),
+ writecache(NULL) {
+ }
+ ~FilePresenterCache()
+ {
+ if (readcachefd) {
+ close(readcachefd);
+ }
+ delete writecache;
+ }
+ bool check() const
+ {
+ try {
+ readcachefd = safesys<OpenCacheFile>(-1, open(getCacheFile().string().c_str(), O_RDONLY));
+ struct stat st;
+ safesys<CacheFileXAttr>(-1, fstat(readcachefd, &st));
+ if (st.st_mtime < time(NULL) - FilePresenterCache::CacheLife) {
+ unlink(getCacheFile().string().c_str());
+ close(readcachefd);
+ readcachefd = 0;
+ return false;
+ }
+ safesys<LockCacheFile>(-1, ::flock(readcachefd, LOCK_SH));
+ return true;
+ }
+ catch (...) {
+ close(readcachefd);
+ readcachefd = 0;
+ return false;
+ }
+ }
+
+ Glib::ustring getEncoding() const
+ {
+ char buf[BUFSIZ];
+ buf[safesys<CacheFileXAttr>(-1, fgetxattr(readcachefd, "user.encoding", buf, sizeof(buf)))] = 0;
+ return buf;
+ }
+ Glib::ustring getContentType() const
+ {
+ char buf[BUFSIZ];
+ buf[safesys<CacheFileXAttr>(-1, fgetxattr(readcachefd, "user.content-type", buf, sizeof(buf)))] = 0;
+ return buf;
+ }
+ void writeTo(std::ostream & o) const
+ {
+ boost::iostreams::stream<boost::iostreams::file_descriptor_source> cache(readcachefd, boost::iostreams::never_close_handle);
+ cache.seekg(0);
+ o << cache.rdbuf();
+ }
+ operator const StaticContent * () const {
+ return this;
+ }
+ mutable int readcachefd;
+
+ std::ostream & writeCache(const std::string & ct, const std::string & enc)
+ {
+ int fd = safesys<OpenCacheFile>(-1, open(getCacheFile().string().c_str(),
+ O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP));
+ safesys<LockCacheFile>(-1, ::flock(fd, LOCK_EX));
+ safesys<CacheFileXAttr>(-1, fsetxattr(fd, "user.content-type", ct.c_str(), ct.length(), 0));
+ safesys<CacheFileXAttr>(-1, fsetxattr(fd, "user.encoding", enc.c_str(), enc.length(), 0));
+ writecache = new boost::iostreams::stream<boost::iostreams::file_descriptor_sink>(fd, boost::iostreams::close_handle);
+ return *writecache;
+ }
+ std::ostream * writecache;
+
+ private:
+ boost::filesystem::path getCacheFile() const
+ {
+ if (cache.empty()) {
+ cache = Store;
+ unsigned int puc = Environment::getCurrent()->getParamUriCount();
+ for (unsigned int i = 0; i < puc; i += 1) {
+ cache /= Environment::getCurrent()->getParamUri(i).raw();
+ }
+ applyKeys(boost::bind(&appendPath, &cache, _1, _2));
+ boost::filesystem::create_directories(cache);
+ 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 &();
+ }
+ mutable boost::filesystem::path cache;
+
+ static boost::filesystem::path Store;
+ static std::string FileName;
+ static time_t CacheLife;
+ friend class FilePresenterCacheLoader;
+};
+boost::filesystem::path FilePresenterCache::Store;
+std::string FilePresenterCache::FileName;
+time_t FilePresenterCache::CacheLife;
+
+class FilePresenterCacheLoader : public ElementLoaderImpl<FilePresenterCache> {
+ public:
+ FilePresenterCacheLoader() :
+ opts("XML Cache options")
+ {
+ opts
+ ("pcache.file.store", Options::value(&FilePresenterCache::Store, "/tmp/project2.pcache"),
+ "The root folder of the cache storage area")
+ ("pcache.file.filename", Options::value(&FilePresenterCache::FileName, "cache"),
+ "The filename to store the data in")
+ ("pcache.file.life", Options::value(&FilePresenterCache::CacheLife, 3600),
+ "The age of cache entries after which they are removed (seconds)")
+ ;
+ }
+
+ const Options * options() const
+ {
+ return &opts;
+ }
+
+ void onIdle()
+ {
+ emptyDir(FilePresenterCache::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) - FilePresenterCache::CacheLife) {
+ files = true;
+ }
+ else {
+ boost::filesystem::remove(*itr);
+ }
+ }
+ }
+ return files;
+ }
+
+ private:
+ Options opts;
+};
+DECLARE_CUSTOM_LOADER("filecache", FilePresenterCacheLoader);
diff --git a/project2/json/transformStream.cpp b/project2/json/transformStream.cpp
deleted file mode 100644
index fae71b0..0000000
--- a/project2/json/transformStream.cpp
+++ /dev/null
@@ -1,25 +0,0 @@
-#include <pch.hpp>
-#include "transform.h"
-#include "logger.h"
-#include "json.h"
-#include "ostreamWrapper.h"
-
-class TransformJsonToStream : public TransformImpl<json::Object, ostreamWrapper> {
- public:
- TransformJsonToStream() :
- encoding("utf-8") {
- }
- void transform(const json::Object * obj, ostreamWrapper * o) const
- {
- json::serializeObject(*obj, o->strm, encoding);
- }
- void configure(ScriptNodePtr s)
- {
- s->applyValue("encoding", encoding);
- }
- private:
- VariableType encoding;
-};
-DECLARE_TRANSFORM(TransformJsonToStream);
-
-
diff --git a/project2/xml/transformXml.cpp b/project2/xml/transformXml.cpp
deleted file mode 100644
index fb115f1..0000000
--- a/project2/xml/transformXml.cpp
+++ /dev/null
@@ -1,14 +0,0 @@
-#include <pch.hpp>
-#include "transform.h"
-#include <libxml++/document.h>
-#include "ostreamWrapper.h"
-
-class TransformXmlToStdStream : public TransformImpl<xmlpp::Document, ostreamWrapper> {
- public:
- void transform(const xmlpp::Document * doc, ostreamWrapper * o) const
- {
- const_cast<xmlpp::Document *>(doc)->write_to_stream_formatted(o->strm, "UTF-8");
- }
-};
-DECLARE_TRANSFORM(TransformXmlToStdStream);
-