Subversion Repositories general

Compare Revisions

No changes between revisions

Ignore whitespace Rev 1074 → Rev 1242

/PhotoAlbum/trunk/todo.txt
1,9 → 1,29
PhotoAlbum TODO
 
1. Sometimes by changing image size (or image rotation) the cached thumbnail is not recreated.
2. Cached files are not deleted where origins are.
3. Split thumbnal and cache.
4. Limits for memory caches (?).
5. Design.
6. Speed up thumbnals creation (m.b. by decreasing quality).
PhotoAlbum TODO
===============================
 
Sometimes by changing image size (or image rotation) the cached thumbnail is not recreated.
 
Cached files are not deleted when origins are.
 
Split thumbnal and cache.
 
Limits for memory caches (?).
 
Design.
 
Speed up thumbnals creation (m.b. by decreasing quality).
 
How to handle exceptions from the logic?
 
I18n.
 
Skins + styles.
 
Use the meta mime information.
 
Config to separate file.
 
Multiple roots.
 
Good caching strategy at HTTP level.
 
/PhotoAlbum/trunk/src/ak/photoalbum/webapp/IndexAction.java
1,6 → 1,7
package ak.photoalbum.webapp;
 
import java.util.List;
import java.util.ArrayList;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.ActionMapping;
18,27 → 19,35
HttpServletRequest request, HttpServletResponse response)
throws Exception
{
PathForm theForm = (PathForm)form;
IndexForm theForm = (IndexForm)form;
String dir = theForm.getPath();
int page = theForm.getPageInt();
IndexEntry entry = new IndexEntry();
IndexEntry top = new IndexEntry();
IndexEntry prev = new IndexEntry();
IndexEntry current = new IndexEntry();
IndexEntry next = new IndexEntry();
List index;
List index = new ArrayList();
List pages = new ArrayList();
 
if(dir == null) dir = ""; // the images root
 
logger.info("get index for " + dir);
Logic.getLogic().getEntry(dir, entry, top, prev, current, next);
index = Logic.getLogic().listDirectory(dir);
if(!Logic.getLogic().listDirectory(dir, page, index, pages))
return mapping.findForward("error");
 
request.setAttribute("dir", FileUtils.replaceFileSeparator(dir, " - "));
request.setAttribute("dir", FileUtils.replaceFileSeparator(dir, " - "));
request.setAttribute("index", index);
request.setAttribute("top", top);
request.setAttribute("prevEntry", prev);
request.setAttribute("current", current);
request.setAttribute("nextEntry", next);
request.setAttribute("pages", pages);
request.setAttribute("firstPage", pages.get(0));
request.setAttribute("lastPage", pages.get(pages.size() - 1));
request.setAttribute("prevPage", (page == 0) ? null : pages.get(page-1));
request.setAttribute("nextPage", (page == pages.size() - 1) ? null : pages.get(page+1));
 
return mapping.findForward("success");
}
/PhotoAlbum/trunk/src/ak/photoalbum/webapp/InitServlet.java
21,6 → 21,7
Integer mediumWidth = null;
Integer mediumHeight = null;
Integer columns = null;
Integer rows = null;
String dirTemplate;
String dirThumbnailPositions;
 
39,12 → 40,14
mediumHeight = new Integer(config.getInitParameter("medium heught"));
if(config.getInitParameter("columns") != null)
columns = new Integer(config.getInitParameter("columns"));
if(config.getInitParameter("rows") != null)
rows = new Integer(config.getInitParameter("rows"));
 
dirTemplate = config.getInitParameter("dir template");
dirThumbnailPositions = config.getInitParameter("dir thumbnails positions");
 
Logic.getLogic().init(imagesRoot, imagesMask, cacheDir, thumbnailFormat,
smallWidth, smallHeight, mediumWidth, mediumHeight, columns,
smallWidth, smallHeight, mediumWidth, mediumHeight, columns, rows,
dirTemplate, dirThumbnailPositions);
}
}
/PhotoAlbum/trunk/src/ak/photoalbum/webapp/IndexEntry.java
7,6 → 7,10
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;
56,6 → 60,46
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;
88,7 → 132,7
 
public String toString()
{
return super.toString() + ": " + file + " - " + path + " - " + title
+ " " + width + "x" + height;
return super.toString() + ": " + file + " - " + path + " - " + title + "/" + subtitle
+ " (" + comment + ") " + width + "x" + height;
}
}
/PhotoAlbum/trunk/src/ak/photoalbum/webapp/IndexForm.java
0,0 → 1,49
package ak.photoalbum.webapp;
 
import javax.servlet.http.HttpServletRequest;
import org.apache.struts.action.ActionError;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionMapping;
 
public class IndexForm
extends PathForm
{
protected String page;
protected int pageInt;
 
public String getPage()
{
return page;
}
 
public int getPageInt()
{
return pageInt;
}
 
public void setPage(String page)
{
this.page = page;
}
 
public ActionErrors validate(ActionMapping mapping,
HttpServletRequest request)
{
ActionErrors errors = new ActionErrors();
 
try {
pageInt = (page == null) ? 0 : Integer.parseInt(page);
}
catch(Exception ex) {
errors.add(null, new ActionError("Cannot parse page number"));
}
 
if(errors.size() == 0) {
if(pageInt < 0)
errors.add(null, new ActionError("Wrong page number"));
}
 
return errors;
}
}
/PhotoAlbum/trunk/src/ak/photoalbum/webapp/PageItem.java
0,0 → 1,30
package ak.photoalbum.webapp;
 
import java.io.File;
 
public class PageItem
{
private int number;
private boolean isCurrent;
 
public PageItem(int number, boolean isCurrent)
{
this.number = number;
this.isCurrent = isCurrent;
}
 
public int getNumber()
{
return number;
}
 
public int getDisplayNumber()
{
return (number+1);
}
 
public boolean getIsCurrent()
{
return isCurrent;
}
}
/PhotoAlbum/trunk/src/ak/photoalbum/webapp/Logic.java
5,13 → 5,18
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.UnsupportedEncodingException;
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;
21,15 → 26,20
 
public class Logic
{
protected static final int DEFAULT_COLUMNS = 4;
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 File imagesRoot;
protected int columns = DEFAULT_COLUMNS;
protected int rows = DEFAULT_ROWS;
protected ImagesFilter imagesFilter;
protected Comparator fileNameComparator = new FileNameComparator(true);
protected Digester metaDigester = createMetaDigester();
protected Map metaInfos = new Hashtable(); // <File, MetaInfo>
 
protected Logic()
{
39,12 → 49,14
public void init(String imagesRoot, String imagesMask,
String cacheDir, String thumbnailFormat,
Integer smallWidth, Integer smallHeight,
Integer mediumWidth, Integer mediumHeight, Integer columns,
Integer mediumWidth, Integer mediumHeight,
Integer columns, Integer rows,
String dirTemplate, String dirThumbnailPositions)
{
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);
85,7 → 97,7
 
public void getEntry(String path, IndexEntry page,
IndexEntry index, IndexEntry prev, IndexEntry current, IndexEntry next)
throws IOException, LogicException
throws IOException, SAXException, LogicException
{
File file = new File(imagesRoot, path);
 
106,15 → 118,16
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);
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
throws IOException, SAXException
{
String title = file.getName();
int[] size;
124,11 → 137,11
size = thumbnailer.getDirSize(file);
}
else {
title = FileUtils.extractFileName(title);
title = FileUtils.extractFileName(title);
 
if(small)
size = thumbnailer.getSmallSize(file);
else
else
size = thumbnailer.getMediumSize(file);
}
 
138,6 → 151,21
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()
200,25 → 228,92
}
}
 
public List listDirectory(String dirName)
throws UnsupportedEncodingException, IOException, LogicException
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;
}
 
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 null;
if(!dir.exists()) return false;
 
File[] children = dir.listFiles(imagesFilter);
List rows = new ArrayList();
int pos = 0;
File[] children = dir.listFiles(imagesFilter);
int pos = page * columns * rows;
 
Arrays.sort(children, fileNameComparator);
metaInfos.clear(); // FIXME do this more intelligent (?)
 
while(pos < children.length) {
// 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;
 
rows.add(row);
table.add(row);
 
while(rowPos < columns && pos < children.length) {
String path = getPath(children[pos]);
233,9 → 328,26
title = FileUtils.extractFileName(title);
}
 
row.add(new IndexEntry(children[pos],
IndexEntry entry = new IndexEntry(children[pos],
URLEncoder.encode(path, URL_ENCODING),
title, children[pos].isDirectory(), size[0], size[1]));
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++;
}
246,7 → 358,7
}
}
 
return rows;
return true;
}
 
protected String getPath(File file)
/PhotoAlbum/trunk/src/ak/photoalbum/webapp/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/webapp/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/webapp/WEB-INF/lib/log4j.jar
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Deleted: svn:mime-type
-application/octet-stream
\ No newline at end of property
/PhotoAlbum/trunk/webapp/WEB-INF/lib/commons-lang.jar
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Deleted: svn:mime-type
-application/octet-stream
\ No newline at end of property
/PhotoAlbum/trunk/webapp/WEB-INF/lib/commons-fileupload.jar
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Deleted: svn:mime-type
-application/octet-stream
\ No newline at end of property
/PhotoAlbum/trunk/webapp/WEB-INF/lib/commons-dbcp.jar
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Deleted: svn:mime-type
-application/octet-stream
\ No newline at end of property
/PhotoAlbum/trunk/webapp/WEB-INF/lib/commons-validator.jar
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Deleted: svn:mime-type
-application/octet-stream
\ No newline at end of property
/PhotoAlbum/trunk/webapp/WEB-INF/lib/jakarta-oro.jar
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Deleted: svn:mime-type
-application/octet-stream
\ No newline at end of property
/PhotoAlbum/trunk/webapp/WEB-INF/lib/commons-beanutils.jar
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Deleted: svn:mime-type
-application/octet-stream
\ No newline at end of property
/PhotoAlbum/trunk/webapp/WEB-INF/lib/commons-pool.jar
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Deleted: svn:mime-type
-application/octet-stream
\ No newline at end of property
/PhotoAlbum/trunk/webapp/WEB-INF/lib/commons-logging.jar
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Deleted: svn:mime-type
-application/octet-stream
\ No newline at end of property
/PhotoAlbum/trunk/webapp/WEB-INF/lib/struts.jar
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Deleted: svn:mime-type
-application/octet-stream
\ No newline at end of property
/PhotoAlbum/trunk/webapp/WEB-INF/lib/commons-digester.jar
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Deleted: svn:mime-type
-application/octet-stream
\ No newline at end of property
/PhotoAlbum/trunk/webapp/WEB-INF/lib/commons-collections.jar
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Deleted: svn:mime-type
-application/octet-stream
\ No newline at end of property
/PhotoAlbum/trunk/webapp/WEB-INF/lib/commons-dbcp-1.2.1.jar
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/PhotoAlbum/trunk/webapp/WEB-INF/lib/commons-pool-1.2.jar
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/PhotoAlbum/trunk/webapp/WEB-INF/lib/struts-1.1.jar
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/PhotoAlbum/trunk/webapp/WEB-INF/lib/commons-digester-1.7.jar
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/PhotoAlbum/trunk/webapp/WEB-INF/lib/log4j-1.2.8.jar
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/PhotoAlbum/trunk/webapp/WEB-INF/lib/commons-collections-2.1.1.jar
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/PhotoAlbum/trunk/webapp/WEB-INF/lib/commons-lang-1.0.1.jar
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/PhotoAlbum/trunk/webapp/WEB-INF/lib/commons-beanutils-core-1.7.0.jar
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/PhotoAlbum/trunk/webapp/WEB-INF/lib/commons-fileupload-1.1.jar
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/PhotoAlbum/trunk/webapp/WEB-INF/lib/commons-validator-1.1.3.jar
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/PhotoAlbum/trunk/webapp/WEB-INF/lib/jakarta-oro-2.0.8.jar
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/PhotoAlbum/trunk/webapp/WEB-INF/lib/commons-logging-1.0.4.jar
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property