Author: michiel
Date: 2009-06-03 17:07:39 +0200 (Wed, 03 Jun 2009)
New Revision: 35628
Modified:
mmbase/trunk/src/org/mmbase/framework/CachedRenderer.java
Log:
Support for Expires headers
Modified: mmbase/trunk/src/org/mmbase/framework/CachedRenderer.java
===================================================================
--- mmbase/trunk/src/org/mmbase/framework/CachedRenderer.java 2009-06-03
15:04:23 UTC (rev 35627)
+++ mmbase/trunk/src/org/mmbase/framework/CachedRenderer.java 2009-06-03
15:07:39 UTC (rev 35628)
@@ -136,6 +136,7 @@
private static final String CACHE_EXTENSION = ".cache";
private static final String ETAG_EXTENSION = ".etag";
+ private static final String EXPIRES_EXTENSION = ".expires";
private static final Pattern INVALID_IN_FILENAME =
Pattern.compile("[\\/\\\\\\s]");
protected File getCacheFile(Parameters blockParameters, RenderHints hints)
{
@@ -171,6 +172,26 @@
return t;
}
+ protected File getExpiresFile(File file) {
+ String name = file.getName();
+ File dir = file.getParentFile();
+ String tagName = name.substring(0, name.length() -
CACHE_EXTENSION.length());
+ return new File(dir, tagName + EXPIRES_EXTENSION);
+ }
+
+ protected void writeExpires(File f, long expires) throws IOException {
+ Writer fw = new OutputStreamWriter(new FileOutputStream(f), "UTF-8");
+ fw.write("" + expires);
+ fw.close();
+ }
+
+ protected long readExpires(File f) throws IOException {
+ BufferedReader fr = new BufferedReader(new InputStreamReader(new
FileInputStream(f), "UTF-8"));
+ long e = Long.parseLong(fr.readLine());
+ fr.close();
+ return e;
+ }
+
protected void renderFile(File f , Writer w) throws FrameworkException,
IOException {
writeRenderTime(new Date(f.lastModified()), w);
BufferedReader reader = new BufferedReader(new InputStreamReader(new
FileInputStream(f), "UTF-8"));
@@ -297,7 +318,20 @@
if (uri == null) throw new FrameworkException("" + getWraps()
+ " did not return an URI, and cannot be cached using getLastModified");
URLConnection connection = uri.toURL().openConnection();
connection.setConnectTimeout(timeout);
+ List<String> cacheControl =
Arrays.asList(connection.getHeaderField("Cache-Control").toLowerCase().split("\\s*,\\s*"));
+ if (cacheControl.contains("no-cache") ||
cacheControl.contains("no-store")) {
+ log.warn("The response for " + uri + " cannot be
implicitely cached (Because of Cache-Control: " + cacheControl + ") Use the
'expires' parameter on " + this + " to override this, because it will _not_ be
cached now.");
+ getWraps().render(blockParameters, w, hints);
+ return;
+ }
+ if (cacheControl.contains("must-revalidate")) {
+ if (cacheFile.exists()) {
+ log.debug("Server indicated that the cache must be
revalidated");
+ cacheFile.delete();
+ }
+ }
final String etag = connection.getHeaderField("ETag");
+ final long expiration = connection.getExpiration();
if (etag != null) {
log.debug("Found an etag header on " + uri + " " + etag);
final File etagFile = getETagFile(cacheFile);
@@ -313,24 +347,33 @@
});
} else {
+ log.debug("" + cacheFile = " up to date");
renderFile(cacheFile, w);
}
+ } else if (expiration > 0) {
+ log.debug("Found an expires header on " + uri + " " +
etag);
+ final File expiresFile = getExpiresFile(cacheFile);
+ if (! cacheFile.exists() || ! expiresFile.exists() ||
System.currentTimeMillis() > readExpires(expiresFile)) {
+ log.service("Rendering " + uri + " because " +
cacheFile + " not existing expired");
+ renderWrappedAndFile(cacheFile, blockParameters, w,
hints, new Runnable() {
+ public void run() {
+ try {
+ writeExpires(expiresFile, expiration);
+ } catch (IOException ioe) {
+ throw new RuntimeException(ioe);
+ }
+ }
+ });
+ renderWrappedAndFile(cacheFile, blockParameters, w,
hints, null);
+ } else {
+ log.debug("Serving cached file because not yet expired
(it's before " + new Date(expiration) + ")");
+ renderFile(cacheFile, w);
+ }
} else {
- List<String> cacheControl =
Arrays.asList(connection.getHeaderField("Cache-Control").toLowerCase().split("\\s*,\\s*"));
- if (cacheControl.contains("no-cache") ||
cacheControl.contains("no-store")) {
- log.warn("The response for " + uri + " cannot be
implicitely cached (Because of Cache-Control: " + cacheControl + ") Use the
'expires' parameter on " + this + " to override this, because it will _not_ be
cached now.");
- getWraps().render(blockParameters, w, hints);
- return;
- }
- if (cacheControl.contains("must-revalidate")) {
- if (cacheFile.exists()) {
- log.debug("Server indicated that the cache must be
revalidated");
- cacheFile.delete();
- }
- }
+
long modified = connection.getLastModified();
- if (modified == 0) {
- log.warn("No last-modified returned by " + uri + "
taking it 5 minutes after last rendering. Consider using 'expires'. Cache
control " + cacheControl);
+ if (modified == 0) {
+ log.warn("No last-modified or expiration returned by "
+ uri + " taking it 5 minutes after last rendering. Consider using 'expires'.
Cache control " + cacheControl);
if (cacheFile.exists()) {
modified = cacheFile.lastModified();
long delay = 5 * 60 * 1000;
@@ -340,16 +383,17 @@
}
}
if (! cacheFile.exists() || (cacheFile.lastModified() <
modified)) {
- log.service("Rendering " + uri + " because " +
cacheFile + " older than " + new Date(modified));
+ log.service("Rendering " + uri + " because " +
cacheFile + " older (" + new Date(cacheFile.lastModified()) + ") than " + new
Date(modified));
renderWrappedAndFile(cacheFile, blockParameters, w,
hints, null);
} else {
if (log.isDebugEnabled()) {
- log.debug("Serving cached file because
modification time of " + uri + " (" + modified + ") before modification time of
" + cacheFile + " (" + cacheFile.lastModified() + ")");
+ log.debug("Serving cached file because
modification time of " + uri + " (" + new Date(modified) + ") after
modification time of " + cacheFile + " (" + cacheFile.lastModified() + ")");
}
renderFile(cacheFile, w);
}
}
}
+
} catch (MalformedURLException mfe) {
throw new FrameworkException(mfe);
} catch (IOException mfe) {
_______________________________________________
Cvs mailing list
[email protected]
http://lists.mmbase.org/mailman/listinfo/cvs