Subversion Repositories general

Compare Revisions

Ignore whitespace Rev 1271 → Rev 1272

/PhotoAlbum/trunk/src/ak/photoalbum/images/Thumbnailer.java
21,6 → 21,7
import javax.imageio.ImageIO;
import org.apache.log4j.Logger;
import marcoschmidt.image.ImageInfo;
import ak.photoalbum.util.TimestampRecipient;
import ak.photoalbum.util.FileUtils;
import ak.photoalbum.util.FileNameComparator;
 
36,6 → 37,10
protected static final int DEFAULT_MEDIUM_WIDTH = 800;
protected static final int DEFAULT_MEDIUM_HEIGHT = 800;
 
protected static final int CACHED_NOT_FOUND = 0;
protected static final int CACHED_NOT_MODIFIED = 1;
protected static final int CACHED_WRITTEN = 2;
 
protected Logger logger;
protected ImageResizer resizer;
protected int smallWidth = DEFAULT_SMALL_WIDTH;
222,12 → 227,12
 
for(int i = 0; i < children.length; i++) {
if(children[i].isDirectory()) {
writeDir(children[i], null);
writeDir(children[i], -1, null, null);
buildCache(children[i]);
}
else {
writeSmall(children[i], null);
writeMedium(children[i], null);
writeSmall(children[i], -1, null, null);
writeMedium(children[i], -1, null, null);
}
}
}
235,9 → 240,11
protected CachedFile getCached(Map cache, File imageFile)
throws IOException
{
CachedFile cached = (CachedFile)cache.get(imageFile.getCanonicalPath());
String key = imageFile.getCanonicalPath();
CachedFile cached = (CachedFile)cache.get(key);
 
if(cached == null || !cached.getFile().exists()) {
cache.remove(key);
logger.debug("not found in cache");
return null;
}
244,7 → 251,7
 
if(cached.getOriginTimestamp() != imageFile.lastModified()) {
cached.getFile().delete();
cache.remove(imageFile.getCanonicalPath());
cache.remove(key);
logger.debug("timestamps dont match");
return null;
}
252,16 → 259,25
return cached;
}
 
protected boolean writeCached(Map cache, File imageFile, OutputStream out)
protected int writeCached(Map cache, File imageFile, long ifModifiedSince,
OutputStream out, TimestampRecipient timestampRecipient)
throws IOException
{
CachedFile cached = getCached(cache, imageFile);
 
if(cached == null) return false;
if(cached == null) return CACHED_NOT_FOUND;
 
if(ifModifiedSince >= 0 && ifModifiedSince <= cached.getTimestamp())
return CACHED_NOT_MODIFIED; // cached image found and not modified
// since given timestamp - do nothing
 
if(logger.isDebugEnabled())
logger.debug("write cached " + imageFile.getCanonicalPath());
 
if(timestampRecipient != null) {
timestampRecipient.setTimestamp(cached.getTimestamp());
}
 
if(out != null) {
FileInputStream in = null;
 
274,7 → 290,7
}
}
 
return true;
return CACHED_WRITTEN;
}
 
protected File getCacheFile(File dir, File imageFile, String suffix)
282,7 → 298,8
return new File(dir, imageFile.getName() + suffix + "." + format);
}
 
protected void cacheThumbnail(Map cache, File imageFile,
// @return last modified timestamp pf the cached thumbnail
protected long cacheThumbnail(Map cache, File imageFile,
BufferedImage thumbnail, String suffix, int width, int height)
throws IOException
{
298,6 → 315,8
cache.put(imageFile.getCanonicalPath(),
new CachedFile(cacheFile, imageFile,
cacheFile.lastModified(), imageFile.lastModified(), width, height));
 
return cacheFile.lastModified();
}
 
public void startup()
439,75 → 458,75
return new File(cacheDir, imagePath.substring(rootPath.length()));
}
 
public void writeSmall(File imageFile, OutputStream out)
protected boolean writeThumbnail(Map cache, String suffix, int width, int height,
File imageFile, long ifModifiedSince, OutputStream out, TimestampRecipient timestampRecipient)
throws IOException
{
if(logger.isInfoEnabled())
logger.info("write small " + imageFile.getCanonicalPath());
int cachedResult = writeCached(cache, imageFile, ifModifiedSince, out, timestampRecipient);
if(cachedResult != CACHED_NOT_FOUND) return (cachedResult == CACHED_WRITTEN);
 
if(writeCached(smallCache, imageFile, out)) return;
 
if(nativeMode) {
File dir = getCacheFileDir(imageFile);
File cacheFile = getCacheFile(dir, imageFile, SMALL_SUFFIX);
File cacheFile = getCacheFile(dir, imageFile, suffix);
 
createThumbnailNative(dir, cacheFile, imageFile, smallWidth, smallHeight);
loadCacheInfo(cacheFile, imageFile, smallCache);
writeCached(smallCache, imageFile, out);
createThumbnailNative(dir, cacheFile, imageFile, width, height);
loadCacheInfo(cacheFile, imageFile, cache);
writeCached(cache, imageFile, -1, out, timestampRecipient);
}
else {
BufferedImage small = createThumbnail(imageFile, smallWidth, smallHeight);
BufferedImage thumbnail = createThumbnail(imageFile, width, height);
 
if(small != null) {
if(thumbnail != null) {
// a thumbnail returned - save it into the cache dir
int sizes[] = calcSizes(
small.getWidth(null), small.getHeight(null), smallWidth, smallHeight);
cacheThumbnail(
smallCache, imageFile, small, SMALL_SUFFIX, sizes[0], sizes[1]);
thumbnail.getWidth(null), thumbnail.getHeight(null), width, height);
long lastModified = cacheThumbnail(
cache, imageFile, thumbnail, suffix, sizes[0], sizes[1]);
 
if(out != null) ImageIO.write(small, format, out);
if(timestampRecipient != null) {
timestampRecipient.setTimestamp(lastModified);
}
 
if(out != null) {
ImageIO.write(thumbnail, format, out);
}
}
}
 
return true; // image written
}
 
public void writeMedium(File imageFile, OutputStream out)
public boolean writeSmall(File imageFile, long ifModifiedSince,
OutputStream out, TimestampRecipient timestampRecipient)
throws IOException
{
if(logger.isInfoEnabled())
logger.info("write medium " + imageFile.getCanonicalPath());
logger.info("write small " + imageFile.getCanonicalPath());
 
if(writeCached(mediumCache, imageFile, out)) return;
return writeThumbnail(smallCache, SMALL_SUFFIX, smallWidth, smallHeight,
imageFile, ifModifiedSince, out, timestampRecipient);
}
 
if(nativeMode) {
File dir = getCacheFileDir(imageFile);
File cacheFile = getCacheFile(dir, imageFile, MEDIUM_SUFFIX);
public boolean writeMedium(File imageFile, long ifModifiedSince,
OutputStream out, TimestampRecipient timestampRecipient)
throws IOException
{
if(logger.isInfoEnabled())
logger.info("write medium " + imageFile.getCanonicalPath());
 
createThumbnailNative(dir, cacheFile, imageFile, mediumWidth, mediumHeight);
loadCacheInfo(cacheFile, imageFile, mediumCache);
writeCached(mediumCache, imageFile, out);
}
else {
BufferedImage medium = createThumbnail(imageFile, mediumWidth, mediumHeight);
 
if(medium != null) {
// a image returned - save it into the cache dir
int sizes[] = calcSizes(medium.getWidth(null), medium.getHeight(null),
mediumWidth, mediumHeight);
cacheThumbnail(
mediumCache, imageFile, medium, MEDIUM_SUFFIX, sizes[0], sizes[1]);
 
if(out != null) ImageIO.write(medium, format, out);
}
}
return writeThumbnail(mediumCache, MEDIUM_SUFFIX, mediumWidth, mediumHeight,
imageFile, ifModifiedSince, out, timestampRecipient);
}
 
public void writeDir(File dir, OutputStream out)
public boolean writeDir(File dir, long ifModifiedSince,
OutputStream out, TimestampRecipient timestampRecipient)
throws IOException
{
if(logger.isInfoEnabled())
logger.info("write dir " + dir.getCanonicalPath());
 
if(writeCached(dirCache, dir, out)) return;
int cachedResult = writeCached(dirCache, dir, ifModifiedSince, out, timestampRecipient);
if(cachedResult != CACHED_NOT_FOUND) return (cachedResult == CACHED_WRITTEN);
 
BufferedImage thumbnail = createDirThumbnail(dir);
 
519,11 → 538,19
dirTemplateTimestamp = dirTemplate.lastModified();
}
 
cacheThumbnail(dirCache, dir, thumbnail, DIR_SUFFIX,
long lastModified = cacheThumbnail(dirCache, dir, thumbnail, DIR_SUFFIX,
dirTemplateSize[0], dirTemplateSize[1]);
 
if(out != null) ImageIO.write(thumbnail, format, out);
if(timestampRecipient != null) {
timestampRecipient.setTimestamp(lastModified);
}
 
if(out != null) {
ImageIO.write(thumbnail, format, out);
}
}
 
return true; // image written
}
 
synchronized protected BufferedImage createThumbnail(File imageFile,
/PhotoAlbum/trunk/src/ak/photoalbum/logic/Logic.java
20,6 → 20,7
import org.apache.log4j.Logger;
 
import ak.photoalbum.util.FileUtils;
import ak.photoalbum.util.TimestampRecipient;
import ak.photoalbum.util.ResourceFactory;
import ak.photoalbum.config.ConfigRoot;
import ak.photoalbum.config.ConfigBranch;
243,7 → 244,8
return FileUtils.getMime(FileUtils.extractFileExt(path));
}
 
public void writeDir(String uri, String path, OutputStream out)
public boolean writeDir(String uri, String path, long ifModifiedSince,
OutputStream out, TimestampRecipient timestampRecipient)
throws IOException, LogicException
{
Branch branch = getBranch(uri);
250,10 → 252,12
File file = new File(branch.getImagesRoot(), path);
 
securePath(branch.getImagesRoot(), file);
branch.getThumbnailer().writeDir(file, out);
 
return branch.getThumbnailer().writeDir(file, ifModifiedSince, out, timestampRecipient);
}
 
public void writeSmall(String uri, String path, OutputStream out)
public boolean writeSmall(String uri, String path, long ifModifiedSince,
OutputStream out, TimestampRecipient timestampRecipient)
throws IOException, LogicException
{
Branch branch = getBranch(uri);
260,10 → 264,12
File file = new File(branch.getImagesRoot(), path);
 
securePath(branch.getImagesRoot(), file);
branch.getThumbnailer().writeSmall(file, out);
return branch.getThumbnailer().writeSmall(file, ifModifiedSince, out, timestampRecipient);
}
 
public void writeMedium(String uri, String path, OutputStream out)
public boolean writeMedium(String uri, String path, long ifModifiedSince,
OutputStream out, TimestampRecipient timestampRecipient)
throws IOException, LogicException
{
Branch branch = getBranch(uri);
270,10 → 276,12
File file = new File(branch.getImagesRoot(), path);
 
securePath(branch.getImagesRoot(), file);
branch.getThumbnailer().writeMedium(file, out);
 
return branch.getThumbnailer().writeMedium(file, ifModifiedSince, out, timestampRecipient);
}
 
public void writeOrigin(String uri, String path, OutputStream out)
public boolean writeOrigin(String uri, String path, long ifModifiedSince,
OutputStream out, TimestampRecipient timestampRecipient)
throws IOException, LogicException
{
Branch branch = getBranch(uri);
282,6 → 290,12
 
securePath(branch.getImagesRoot(), file);
 
if(ifModifiedSince >= 0 && ifModifiedSince <= file.lastModified()) return false;
 
if(timestampRecipient != null) {
timestampRecipient.setTimestamp(file.lastModified());
}
 
try {
in = new FileInputStream(file);
FileUtils.copyStreams(in, out);
289,6 → 303,8
finally {
if(in != null) in.close();
}
 
return true;
}
 
protected MetaInfo getMetaInfo(Branch branch, File dir)
/PhotoAlbum/trunk/src/ak/photoalbum/util/TimestampRecipient.java
0,0 → 1,7
package ak.photoalbum.util;
 
public interface TimestampRecipient
{
public void setTimestamp(long timestamp);
}
 
/PhotoAlbum/trunk/src/ak/photoalbum/webapp/ImageAction.java
8,6 → 8,7
import org.apache.struts.action.ActionForward;
import org.apache.log4j.Logger;
import ak.photoalbum.logic.Logic;
import ak.photoalbum.util.TimestampRecipient;
 
public final class ImageAction
extends BaseAction
18,30 → 19,66
HttpServletRequest request, HttpServletResponse response)
throws Exception
{
PathForm theForm = (PathForm)form;
String branch = theForm.getBranch();
String path = theForm.getPath();
Logic logic = Logic.getLogic();
PathForm theForm = (PathForm)form;
String branch = theForm.getBranch();
String path = theForm.getPath();
Logic logic = Logic.getLogic();
HttpTimestampRecipient timestampRecipient = new HttpTimestampRecipient(response);
long ifModifiedSince;
boolean fileModified = true;
 
try {
ifModifiedSince = request.getDateHeader("If-Modified-Since");
}
catch(Exception ex) {
ifModifiedSince = -1;
}
 
logger.info("get image " + mapping.getParameter() + " for " + path);
 
if("dir".equals(mapping.getParameter())) {
response.setContentType(logic.getThumbnailMime(branch));
logic.writeDir(branch, path, response.getOutputStream());
fileModified = logic.writeDir(branch, path, ifModifiedSince,
response.getOutputStream(), timestampRecipient);
}
else if("small".equals(mapping.getParameter())) {
response.setContentType(logic.getThumbnailMime(branch));
logic.writeSmall(branch, path, response.getOutputStream());
fileModified = logic.writeSmall(branch, path, ifModifiedSince,
response.getOutputStream(), timestampRecipient);
}
else if("medium".equals(mapping.getParameter())) {
response.setContentType(logic.getThumbnailMime(branch));
logic.writeMedium(branch, path, response.getOutputStream());
fileModified = logic.writeMedium(branch, path, ifModifiedSince,
response.getOutputStream(), timestampRecipient);
}
else if("origin".equals(mapping.getParameter())) {
response.setContentType(logic.getOriginMime(branch, path));
logic.writeOrigin(branch, path, response.getOutputStream());
fileModified = logic.writeOrigin(branch, path, ifModifiedSince,
response.getOutputStream(), timestampRecipient);
}
 
// if file was modified comapring to "If-Modified-Since" header, then it's already written
// into to response; otherwise send 304 code
if(!fileModified) {
response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
}
 
return null;
}
 
private class HttpTimestampRecipient
implements TimestampRecipient
{
private HttpServletResponse response;
 
public HttpTimestampRecipient(HttpServletResponse response)
{
this.response = response;
}
 
public void setTimestamp(long timestamp)
{
response.setDateHeader("Last-Modified", timestamp);
}
}
}