Subversion Repositories general

Compare Revisions

Ignore whitespace Rev 1247 → Rev 1248

/PhotoAlbum/trunk/src/ak/photoalbum/logic/LogicException.java
0,0 → 1,10
package ak.photoalbum.webapp;
 
public class LogicException
extends Exception
{
public LogicException(String message)
{
super(message);
}
}
/PhotoAlbum/trunk/src/ak/photoalbum/logic/Logic.java
0,0 → 1,500
package ak.photoalbum.webapp;
 
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.StringTokenizer;
import java.util.Map;
import java.util.Hashtable;
import java.io.File;
import java.io.IOException;
import java.io.FileInputStream;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.FileNotFoundException;
import java.net.URLEncoder;
import org.xml.sax.SAXException;
import org.apache.commons.digester.Digester;
import org.apache.log4j.Logger;
import ak.photoalbum.images.Thumbnailer;
import ak.photoalbum.images.ThumbnailPosition;
import ak.photoalbum.util.FileUtils;
import ak.photoalbum.util.FileNameComparator;
import ak.photoalbum.util.ImagesFilter;
 
public class Logic
{
protected static final int DEFAULT_COLUMNS = 5;
protected static final int DEFAULT_ROWS = 4;
protected static final String URL_ENCODING = "UTF-8";
protected static final String META_FILE_NAME = "meta.xml"; // FIXME make configurable (?)
 
protected Logger logger;
protected Thumbnailer thumbnailer;
protected ConfigRoot config;
protected File imagesRoot;
protected int columns = DEFAULT_COLUMNS;
protected int rows = DEFAULT_ROWS;
protected ImagesFilter imagesFilter;
protected Comparator fileNameComparator = new FileNameComparator(true);
protected Digester configDigester = createConfigDigester();
protected Digester metaDigester = createMetaDigester();
protected Map metaInfos = new Hashtable(); // <File, MetaInfo>
 
protected Logic()
{
this.logger = Logger.getLogger(this.getClass());
}
 
protected Digester createConfigDigester()
{
/*
4 <uri>children</uri>
5 <images-root>/home/data/photos</images-root>
6 <cache-dir>/home/data/photos/.cache</cache-dir>
7 <thumbnail-format>jpg</thumbnail-format>
8 <columns>6</columns>
9 <rows>5</rows>
10 <images-mask>*.jpeg</images-mask>
11 <images-mask>*.jpg</images-mask>
12 <dir-thumbnail>
13 <template>images/dir_template.gif</template>
14 <thumbnail>
15 <left>5</left>
16 <top>9</top>
17 <width>40</width>
18 <height>40</height>
19 <align>center</align>
20 <valign>center</valign>
*/
Digester digester = new Digester();
digester.setValidating(false);
 
digester.addObjectCreate("photos", ConfigRoot.class);
digester.addObjectCreate("photos/branch", ConfigBranch.class);
digester.addBeanPropertySetter("photos/branch/uri", "uri");
digester.addBeanPropertySetter("photos/branch/images-root", "imagesRoot");
digester.addBeanPropertySetter("photos/branch/cache-dir", "cacheDir");
digester.addBeanPropertySetter("photos/branch/thumbnail-format", "thumbnailFormat");
digester.addBeanPropertySetter("photos/branch/columns", "columns");
digester.addBeanPropertySetter("photos/branch/rows", "rows");
 
// FIXME images-mask
 
digester.addSetNext("photos/branch", "addBranch");
/* digester.addBeanPropertySetter("meta/item/subtitle", "subtitle");
digester.addSetProperties("meta/item/subtitle", "mime", "subtitleMime");
digester.addBeanPropertySetter("meta/item/comment", "comment");
digester.addSetProperties("meta/item/comment", "mime", "commentMime");
digester.addSetNext("photos/branch", "addItem");
*/
return digester;
}
 
protected Digester createMetaDigester()
{
Digester digester = new Digester();
digester.setValidating(false);
 
digester.addObjectCreate("meta", MetaInfo.class);
digester.addObjectCreate("meta/item", MetaInfoItem.class);
digester.addSetProperties("meta/item", "id", "id");
digester.addBeanPropertySetter("meta/item/title", "title");
digester.addBeanPropertySetter("meta/item/subtitle", "subtitle");
digester.addSetProperties("meta/item/subtitle", "mime", "subtitleMime");
digester.addBeanPropertySetter("meta/item/comment", "comment");
digester.addSetProperties("meta/item/comment", "mime", "commentMime");
digester.addSetNext("meta/item", "addItem");
 
return digester;
}
 
public void init(ResourceFactory resourceFactory, String configPath)
{
logger.info("starting");
config = (ConfigRoot)configDigester.parse(resourceFactory.getAsStream(configPath));
/*
this.imagesRoot = new File(imagesRoot);
this.imagesFilter = new ImagesFilter(imagesMask);
if(columns != null) this.columns = columns.intValue();
if(rows != null) this.rows = rows.intValue();
 
this.thumbnailer = new Thumbnailer();
this.thumbnailer.setImagesRoot(this.imagesRoot);
this.thumbnailer.setCacheDir(new File(cacheDir));
 
if(thumbnailFormat != null)
this.thumbnailer.setFormat(thumbnailFormat);
if(smallWidth != null)
this.thumbnailer.setSmallWidth(smallWidth.intValue());
if(smallHeight != null)
this.thumbnailer.setSmallHeight(smallHeight.intValue());
if(mediumWidth != null)
this.thumbnailer.setMediumWidth(mediumWidth.intValue());
if(mediumHeight != null)
this.thumbnailer.setMediumHeight(mediumHeight.intValue());
 
thumbnailer.setResizer(new ak.photoalbum.images.jiu.JiuResizer());
thumbnailer.setImagesFilter(this.imagesFilter);
thumbnailer.setDirTemplate(new File(dirTemplate));
thumbnailer.setDirThumbnailPositions(
parseThumbnailPositions(dirThumbnailPositions));
 
try {
thumbnailer.startup();
}
catch(Exception ex) {
logger.error("init thumbnailer", ex);
}
*/
logger.info("started");
}
 
public void buildCache()
throws IOException
{
thumbnailer.buildCache();
}
 
public void getEntry(String path, IndexEntry page,
IndexEntry index, IndexEntry prev, IndexEntry current, IndexEntry next)
throws IOException, SAXException, LogicException
{
File file = new File(imagesRoot, path);
 
securePath(imagesRoot, file);
 
if(!file.exists())
throw new FileNotFoundException(
"[" + file.getCanonicalPath() + "] not found");
 
File dir = file.getParentFile();
File[] children = dir.listFiles(imagesFilter);
int pos;
 
Arrays.sort(children, fileNameComparator);
pos = Arrays.binarySearch(children, file, fileNameComparator);
 
if(pos < 0)
throw new FileNotFoundException("[" + file.getCanonicalPath()
+ "] not found in [" + dir.getCanonicalPath() + "]");
 
metaInfos.clear(); // FIXME make this more intelligent
setEntryInfo(page, file, false);
setEntryInfo(current, file, true);
setEntryInfo(index, dir, true);
if(pos > 0) setEntryInfo(prev, children[pos-1], true);
if(pos < children.length-1) setEntryInfo(next, children[pos+1], true);
}
 
protected void setEntryInfo(IndexEntry entry, File file, boolean small)
throws IOException, SAXException
{
String title = file.getName();
int[] size;
String path = getPath(file);
 
if(file.isDirectory()) {
size = thumbnailer.getDirSize(file);
}
else {
title = FileUtils.extractFileName(title);
 
if(small)
size = thumbnailer.getSmallSize(file);
else
size = thumbnailer.getMediumSize(file);
}
 
entry.setFile(file);
entry.setPath(path == null ? null : URLEncoder.encode(path, URL_ENCODING));
entry.setTitle(title);
entry.setIsDir(file.isDirectory());
entry.setWidth(size[0]);
entry.setHeight(size[1]);
 
MetaInfoItem meta = findMetaInfo(imagesRoot, file);
if(meta != null) {
if(meta.getTitle() != null) {
entry.setTitle(meta.getTitle());
}
if(meta.getSubtitle() != null) {
entry.setSubtitle(meta.getSubtitle());
entry.setSubtitleMime(meta.getSubtitleMime());
}
if(meta.getComment() != null) {
entry.setComment(meta.getComment());
entry.setCommentMime(meta.getCommentMime());
}
}
}
 
public String getThumbnailMime()
{
return thumbnailer.getMime();
}
 
public String getOriginMime(String path)
throws IOException, LogicException
{
File file = new File(imagesRoot, path);
 
if(!file.exists()) return null;
securePath(imagesRoot, file);
 
return FileUtils.getMime(FileUtils.extractFileExt(path));
}
 
public void writeDir(String path, OutputStream out)
throws IOException, LogicException
{
File file = new File(imagesRoot, path);
 
securePath(imagesRoot, file);
thumbnailer.writeDir(file, out);
}
 
public void writeSmall(String path, OutputStream out)
throws IOException, LogicException
{
File file = new File(imagesRoot, path);
 
securePath(imagesRoot, file);
thumbnailer.writeSmall(file, out);
}
 
public void writeMedium(String path, OutputStream out)
throws IOException, LogicException
{
File file = new File(imagesRoot, path);
 
securePath(imagesRoot, file);
thumbnailer.writeMedium(file, out);
}
 
public void writeOrigin(String path, OutputStream out)
throws IOException, LogicException
{
FileInputStream in = null;
File file = new File(imagesRoot, path);
 
securePath(imagesRoot, file);
 
try {
in = new FileInputStream(file);
FileUtils.copyStreams(in, out);
}
finally {
if(in != null) in.close();
}
}
 
protected MetaInfo getMetaInfo(File dir)
throws IOException, SAXException
{
MetaInfo meta = (MetaInfo)metaInfos.get(dir);
if(meta != null) return meta;
 
File metaFile = new File(dir, META_FILE_NAME);
if(!metaFile.exists()) return null;
 
meta = (MetaInfo)metaDigester.parse(new FileInputStream(metaFile));
meta.setDir(dir);
metaInfos.put(dir, meta);
 
return meta;
}
 
protected MetaInfoItem findMetaInfo(File rootDir, File file)
throws IOException, SAXException
{
file = file.getCanonicalFile();
rootDir = rootDir.getCanonicalFile();
 
File dir = file;
if(!dir.isDirectory())
dir = dir.getParentFile();
 
MetaInfoItem metaItem = null;
for(; metaItem == null; dir = dir.getParentFile()) {
if(dir == null) break;
 
MetaInfo meta = getMetaInfo(dir);
if(meta != null) {
metaItem = meta.findItem(file);
}
if(rootDir.equals(dir)) break;
}
 
return metaItem;
}
 
public boolean listDirectory(String dirName, int page, List table, List pages)
throws IOException, LogicException, SAXException
{
File dir = new File(imagesRoot, dirName);
 
securePath(imagesRoot, dir);
if(!dir.exists()) return false;
 
File[] children = dir.listFiles(imagesFilter);
int pos = page * columns * rows;
 
Arrays.sort(children, fileNameComparator);
metaInfos.clear(); // FIXME do this more intelligent (?)
 
// the pages list
pages.clear();
for(int i = 0; i < (int)Math.ceil((double)children.length / columns / rows); i++) {
pages.add(new PageItem(i, i == page));
}
 
// the main table
table.clear();
while(pos < children.length && pos < (page+1) * columns * rows) {
List row = new ArrayList();
int rowPos = 0;
 
table.add(row);
 
while(rowPos < columns && pos < children.length) {
String path = getPath(children[pos]);
String title = children[pos].getName();
int[] size;
 
if(children[pos].isDirectory()) {
size = thumbnailer.getDirSize(children[pos]);
}
else {
size = thumbnailer.getSmallSize(children[pos]);
title = FileUtils.extractFileName(title);
}
 
IndexEntry entry = new IndexEntry(children[pos],
URLEncoder.encode(path, URL_ENCODING),
title, children[pos].isDirectory(), size[0], size[1]);
 
MetaInfoItem meta = findMetaInfo(imagesRoot, children[pos]);
if(meta != null) {
if(meta.getTitle() != null) {
entry.setTitle(meta.getTitle());
}
if(meta.getSubtitle() != null) {
entry.setSubtitle(meta.getSubtitle());
entry.setSubtitleMime(meta.getSubtitleMime());
}
if(meta.getComment() != null) {
entry.setComment(meta.getComment());
entry.setCommentMime(meta.getCommentMime());
}
}
 
row.add(entry);
rowPos++;
pos++;
}
 
while(rowPos < columns) {
row.add(null);
rowPos++;
}
}
 
return true;
}
 
protected String getPath(File file)
throws IOException
{
String path = file.getCanonicalPath();
String rootPath = imagesRoot.getCanonicalPath();
 
if(path.equals(rootPath)) return "";
if(!rootPath.endsWith(File.separator)) rootPath += File.separator;
 
if(!path.startsWith(rootPath))
return null;
 
return path.substring(rootPath.length());
}
 
protected ThumbnailPosition[] parseThumbnailPositions(String str)
{
List list = new ArrayList();
StringTokenizer tokenizer = new StringTokenizer(str, ";");
 
while(tokenizer.hasMoreTokens()) {
StringTokenizer tokenParser
= new StringTokenizer(tokenizer.nextToken(), ",");
int x = Integer.parseInt(tokenParser.nextToken().trim());
int y = Integer.parseInt(tokenParser.nextToken().trim());
int width = Integer.parseInt(tokenParser.nextToken().trim());
int height = Integer.parseInt(tokenParser.nextToken().trim());
String horAlignStr = tokenParser.nextToken().trim().toLowerCase();
String vertAlignStr = tokenParser.nextToken().trim().toLowerCase();
int horAlign;
int vertAlign;
 
if("l".equals(horAlignStr))
horAlign = ThumbnailPosition.ALIGN_HOR_LEFT;
else if("r".equals(horAlignStr))
horAlign = ThumbnailPosition.ALIGN_HOR_RIGHT;
else if("c".equals(horAlignStr))
horAlign = ThumbnailPosition.ALIGN_HOR_CENTER;
else
throw new RuntimeException(
"Cannot parse " + horAlignStr + " as horizontal alignment");
 
if("t".equals(vertAlignStr))
vertAlign = ThumbnailPosition.ALIGN_VERT_TOP;
else if("b".equals(vertAlignStr))
vertAlign = ThumbnailPosition.ALIGN_VERT_BOTTOM;
else if("c".equals(vertAlignStr))
vertAlign = ThumbnailPosition.ALIGN_VERT_CENTER;
else
throw new RuntimeException(
"Cannot parse " + vertAlignStr + " as vertical alignment");
 
list.add(new ThumbnailPosition(x, y, width, height, horAlign, vertAlign));
}
 
ThumbnailPosition[] res = new ThumbnailPosition[list.size()];
 
for(int i = 0; i < res.length; i++)
res[i] = (ThumbnailPosition)list.get(i);
 
return res;
}
 
protected static final Logic instance = new Logic();
 
public static Logic getLogic()
{
return instance;
}
 
/**
* checks if given file is really under the parent directory
*/
protected void securePath(File parentDir, File file)
throws IOException, LogicException
{
if(parentDir == null || file == null) return;
 
File partFile = file.getCanonicalFile();
 
parentDir = parentDir.getCanonicalFile();
while(partFile != null) {
if(partFile.equals(parentDir)) return;
partFile = partFile.getParentFile();
}
 
throw new LogicSecurityException(
"[" + file.getCanonicalPath() + "] is outside of directory ["
+ parentDir.getCanonicalPath() + "]");
}
}
/PhotoAlbum/trunk/src/ak/photoalbum/logic/ResourceFactory.java
0,0 → 1,9
package ak.photoalbum.webapp;
 
import java.io.InputStream;
 
public interface ResourceFactory
{
public InputStream getAsStream(String path);
}
 
/PhotoAlbum/trunk/src/ak/photoalbum/logic/MetaInfoItem.java
0,0 → 1,76
package ak.photoalbum.webapp;
 
public class MetaInfoItem
{
private String id;
private String title;
private String subtitle;
private String subtitleMime;
private String comment;
private String commentMime;
 
public MetaInfoItem()
{
}
 
public String getId()
{
return id;
}
 
public void setId(String id)
{
this.id = id;
}
 
public String getTitle()
{
return title;
}
 
public void setTitle(String title)
{
this.title = title;
}
 
public String getSubtitle()
{
return subtitle;
}
 
public void setSubtitle(String subtitle)
{
this.subtitle = subtitle;
}
 
public String getSubtitleMime()
{
return subtitleMime;
}
 
public void setSubtitleMime(String subtitleMime)
{
this.subtitleMime = subtitleMime;
}
 
public String getComment()
{
return comment;
}
 
public void setComment(String comment)
{
this.comment = comment;
}
 
public String getCommentMime()
{
return commentMime;
}
 
public void setCommentMime(String commentMime)
{
this.commentMime = commentMime;
}
}
 
/PhotoAlbum/trunk/src/ak/photoalbum/logic/MetaInfo.java
0,0 → 1,56
package ak.photoalbum.webapp;
 
import java.io.File;
import java.io.IOException;
import java.util.Map;
import java.util.Hashtable;
 
public class MetaInfo
{
private File dir;
private String dirPath;
private Map items = new Hashtable(); // <String, MetaInfoItem>
 
public MetaInfo()
{
}
 
public File getDir()
{
return dir;
}
 
public void setDir(File dir)
throws IOException
{
this.dir = dir;
this.dirPath = dir.getCanonicalPath();
if(!this.dirPath.endsWith(File.separator))
this.dirPath += File.separator;
}
 
public void addItem(MetaInfoItem item)
{
items.put(item.getId(), item);
}
 
public MetaInfoItem findItem(File file)
throws IOException
{
String filePath = file.getCanonicalPath();
String id;
if(file.isDirectory() && !filePath.endsWith(File.separator))
filePath += File.separator;
 
if(filePath.length() < dirPath.length())
return null;
else if(filePath.length() == dirPath.length())
id = ".";
else
id = filePath.substring(dirPath.length());
 
return (MetaInfoItem)items.get(id);
}
}
 
/PhotoAlbum/trunk/src/ak/photoalbum/logic/LogicSecurityException.java
0,0 → 1,10
package ak.photoalbum.webapp;
 
public class LogicSecurityException
extends LogicException
{
public LogicSecurityException(String message)
{
super(message);
}
}
/PhotoAlbum/trunk/src/ak/photoalbum/logic/IndexEntry.java
0,0 → 1,138
package ak.photoalbum.webapp;
 
import java.io.File;
 
public class IndexEntry
{
private File file;
private String path;
private String title;
private String subtitle;
private String subtitleMime;
private String comment;
private String commentMime;
private boolean isDir;
private int width;
private int height;
 
public IndexEntry()
{
}
 
public IndexEntry(File file, String path, String title, boolean isDir,
int width, int height)
{
this.file = file;
this.path = path;
this.title = title;
this.isDir = isDir;
this.width = width;
this.height = height;
}
 
public File getFile()
{
return file;
}
 
public void setFile(File file)
{
this.file = file;
}
 
public String getPath()
{
return path;
}
 
public void setPath(String path)
{
this.path = path;
}
 
public String getTitle()
{
return title;
}
 
public void setTitle(String title)
{
this.title = title;
}
 
public String getSubtitle()
{
return subtitle;
}
 
public void setSubtitle(String subtitle)
{
this.subtitle = subtitle;
}
 
public String getSubtitleMime()
{
return subtitleMime;
}
 
public void setSubtitleMime(String subtitleMime)
{
this.subtitleMime = subtitleMime;
}
 
public String getComment()
{
return comment;
}
 
public void setComment(String comment)
{
this.comment = comment;
}
 
public String getCommentMime()
{
return commentMime;
}
 
public void setCommentMime(String commentMime)
{
this.commentMime = commentMime;
}
 
public boolean getIsDir()
{
return isDir;
}
 
public void setIsDir(boolean isDir)
{
this.isDir = isDir;
}
 
public int getWidth()
{
return width;
}
 
public void setWidth(int width)
{
this.width = width;
}
 
public int getHeight()
{
return height;
}
 
public void setHeight(int height)
{
this.height = height;
}
 
public String toString()
{
return super.toString() + ": " + file + " - " + path + " - " + title + "/" + subtitle
+ " (" + comment + ") " + width + "x" + height;
}
}