From 1d257b4abd7a20f7ad22c2d45d868e7c86e0bca3 Mon Sep 17 00:00:00 2001 From: Erik Forkalsrud Date: Sat, 17 Jan 2009 15:31:29 -0800 Subject: [PATCH 1/3] nicer status --- src/org/forkalsrud/album/web/AlbumServlet.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/org/forkalsrud/album/web/AlbumServlet.java b/src/org/forkalsrud/album/web/AlbumServlet.java index 16f538c..7eca4ce 100644 --- a/src/org/forkalsrud/album/web/AlbumServlet.java +++ b/src/org/forkalsrud/album/web/AlbumServlet.java @@ -81,10 +81,11 @@ public class AlbumServlet res.setContentType("image/jpeg"); FileEntry e = (FileEntry)DirectoryEntry.getEntry(file); scaleImage(req, res, file, e.getThumbnail(), req.getParameter("size")); + res.setStatus(HttpServletResponse.SC_OK); + return; } catch (Exception e) { throw new RuntimeException("sadness", e); } - return; } res.setStatus(HttpServletResponse.SC_NOT_FOUND); } From 647bae40207b73c0b1b527eb83b8b614d29497eb Mon Sep 17 00:00:00 2001 From: Erik Forkalsrud Date: Sat, 17 Jan 2009 17:22:56 -0800 Subject: [PATCH 2/3] add last-modified headers add flush() at end of scaleImage() --- src/org/forkalsrud/album/web/AlbumServlet.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/org/forkalsrud/album/web/AlbumServlet.java b/src/org/forkalsrud/album/web/AlbumServlet.java index 2fb6925..39414dd 100644 --- a/src/org/forkalsrud/album/web/AlbumServlet.java +++ b/src/org/forkalsrud/album/web/AlbumServlet.java @@ -128,13 +128,26 @@ public class AlbumServlet return false; } + boolean notModified(HttpServletRequest req, File f) { + long reqDate = req.getDateHeader("If-Modified-Since"); + long fDate = f.lastModified(); + return reqDate > 0 && fDate > 0 && fDate <= reqDate; + } + synchronized void scaleImage(HttpServletRequest req, HttpServletResponse res, File file, Thumbnail thumbnail, String size) throws IOException { + if (notModified(req, file)) { + res.setStatus(HttpServletResponse.SC_NOT_MODIFIED); + System.out.println(file.getName() + " not modified (based on date)"); + return; + } String fileEtag = thumbnail.getEtag() + "-" + size; if (etagMatches(req, fileEtag)) { res.setStatus(HttpServletResponse.SC_NOT_MODIFIED); + System.out.println(file.getName() + " not modified (based on etag)"); return; } + res.setDateHeader("Last-Modified", file.lastModified()); res.setHeader("ETag", fileEtag); Dimension orig = thumbnail.getSize(); @@ -213,6 +226,8 @@ public class AlbumServlet writer.setOutput(ios); // writer.write(null, new IIOImage(buf2, null, null), wParam); writer.write(buf2); + ios.flush(); + res.getOutputStream().close(); } From 5c9af5b42d2bdc57ac787aa9be7f504fd8465f21 Mon Sep 17 00:00:00 2001 From: Erik Forkalsrud Date: Mon, 19 Jan 2009 23:14:26 -0800 Subject: [PATCH 3/3] added basic server side image caching --- etc/ehcache-1.5.0.xsd | 123 ++++++++++++++++++ etc/ehcache.xml | 20 +++ pom.xml | 5 + .../forkalsrud/album/web/AlbumServlet.java | 63 +++++++-- 4 files changed, 202 insertions(+), 9 deletions(-) create mode 100644 etc/ehcache-1.5.0.xsd create mode 100644 etc/ehcache.xml diff --git a/etc/ehcache-1.5.0.xsd b/etc/ehcache-1.5.0.xsd new file mode 100644 index 0000000..dd47ef8 --- /dev/null +++ b/etc/ehcache-1.5.0.xsd @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/etc/ehcache.xml b/etc/ehcache.xml new file mode 100644 index 0000000..b2c8fc6 --- /dev/null +++ b/etc/ehcache.xml @@ -0,0 +1,20 @@ + + + + + + + + + + diff --git a/pom.xml b/pom.xml index eea6a79..e4cb460 100644 --- a/pom.xml +++ b/pom.xml @@ -108,6 +108,11 @@ 2.4 provided + + net.sf.ehcache + ehcache + 1.5.0 + diff --git a/src/org/forkalsrud/album/web/AlbumServlet.java b/src/org/forkalsrud/album/web/AlbumServlet.java index 39414dd..d2b3d95 100644 --- a/src/org/forkalsrud/album/web/AlbumServlet.java +++ b/src/org/forkalsrud/album/web/AlbumServlet.java @@ -4,6 +4,7 @@ import java.awt.Graphics2D; import java.awt.RenderingHints; import java.awt.geom.AffineTransform; import java.awt.image.BufferedImage; +import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.util.Iterator; @@ -20,6 +21,10 @@ import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import net.sf.ehcache.Cache; +import net.sf.ehcache.CacheManager; +import net.sf.ehcache.Element; + import org.forkalsrud.album.exif.Dimension; import org.forkalsrud.album.exif.DirectoryEntry; import org.forkalsrud.album.exif.Entry; @@ -31,6 +36,7 @@ public class AlbumServlet { File base; String basePrefix; + Cache imageCache; @Override public void init() @@ -39,6 +45,9 @@ public class AlbumServlet System.out.println("in init of Album"); base = new File(getServletConfig().getInitParameter("base")).getAbsoluteFile(); basePrefix = "/" + base.getName(); + + CacheManager cacheManager = new CacheManager(); + imageCache = cacheManager.getCache("imageCache"); } @Override @@ -75,12 +84,13 @@ public class AlbumServlet return; } - if (req.getParameter("size") != null) { + String size = req.getParameter("size"); + if (size != null) { try { res.setContentType("image/jpeg"); FileEntry e = (FileEntry)DirectoryEntry.getEntry(file); - scaleImage(req, res, file, e.getThumbnail(), req.getParameter("size")); + scaleImage(req, res, file, e.getThumbnail(), size); res.setStatus(HttpServletResponse.SC_OK); return; } catch (Exception e) { @@ -134,7 +144,7 @@ public class AlbumServlet return reqDate > 0 && fDate > 0 && fDate <= reqDate; } - synchronized void scaleImage(HttpServletRequest req, HttpServletResponse res, File file, Thumbnail thumbnail, String size) throws IOException { + void scaleImage(HttpServletRequest req, HttpServletResponse res, File file, Thumbnail thumbnail, String size) throws IOException { if (notModified(req, file)) { res.setStatus(HttpServletResponse.SC_NOT_MODIFIED); @@ -150,6 +160,24 @@ public class AlbumServlet res.setDateHeader("Last-Modified", file.lastModified()); res.setHeader("ETag", fileEtag); + + String key = file.getPath() + ":" + size; + Element element = imageCache.get(key); + if (element != null) { + CachedImage cimg = (CachedImage) element.getObjectValue(); + if (cimg.lastModified == file.lastModified()) { + System.out.println("cache hit on " + key); + //res.setContentType(cimg.mimeType); + res.setContentLength(cimg.bits.length); + res.getOutputStream().write(cimg.bits); + return; + } else { + System.out.println(" " + key + " has changed so cache entry wil be refreshed"); + imageCache.remove(key); + } + } + + synchronized (this) { Dimension orig = thumbnail.getSize(); Dimension outd; if (size.endsWith("h")) { @@ -219,15 +247,26 @@ public class AlbumServlet Iterator writers = ImageIO.getImageWritersByFormatName("jpg"); ImageWriter writer = writers.next(); -// ImageWriteParam wParam = writer.getDefaultWriteParam(); -// wParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT); -// wParam.setCompressionQuality(1.0f); - ImageOutputStream ios = ImageIO.createImageOutputStream(res.getOutputStream()); + + ByteArrayOutputStream bits = new ByteArrayOutputStream(); + + ImageOutputStream ios = ImageIO.createImageOutputStream(bits); writer.setOutput(ios); -// writer.write(null, new IIOImage(buf2, null, null), wParam); writer.write(buf2); ios.flush(); - res.getOutputStream().close(); + + CachedImage cimg = new CachedImage(); + cimg.lastModified = file.lastModified(); + cimg.mimeType = "image/jpeg"; + cimg.bits = bits.toByteArray(); + imageCache.put(new Element(key, cimg)); + + System.out.println(" " + key + " added to the cache with size " + cimg.bits.length + " -- now " + imageCache.getSize() + " entries"); + + //res.setContentType(cimg.mimeType); + res.setContentLength(cimg.bits.length); + res.getOutputStream().write(cimg.bits); + } } @@ -273,6 +312,12 @@ public class AlbumServlet } } } + + static class CachedImage { + long lastModified; + String mimeType; + byte[] bits; + } } // eof