Subversion Repositories general

Compare Revisions

No changes between revisions

Ignore whitespace Rev 37 → Rev 38

/sun/PhotoAlbum/trunk/src/ak/photoalbum/webapp/BaseAction.java
0,0 → 1,51
package ak.photoalbum.webapp;
 
import java.util.List;
import java.io.FileNotFoundException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.log4j.Logger;
import ak.photoalbum.util.FileUtils;
 
public abstract class BaseAction
extends Action
{
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception
{
Logger logger = Logger.getLogger(getClass());
 
try {
return executeAction(mapping, form, request, response);
}
catch(LogicSecurityException ex) {
logger.warn("forbidden: " + ex.getMessage());
logger.debug("forbidden", ex);
response.sendError(HttpServletResponse.SC_FORBIDDEN);
 
return null;
}
catch(FileNotFoundException ex) {
logger.warn("not found: " + ex.getMessage());
logger.debug("not found", ex);
response.sendError(HttpServletResponse.SC_NOT_FOUND);
 
return null;
}
catch(Exception ex) {
logger.error("exception", ex);
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
 
return null;
}
}
 
public abstract ActionForward executeAction(ActionMapping mapping,
ActionForm form, HttpServletRequest request, HttpServletResponse response)
throws Exception;
}
Property changes:
Added: svn:keywords
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id
\ No newline at end of property
/sun/PhotoAlbum/trunk/src/ak/photoalbum/webapp/PageAction.java
1,9 → 1,7
package ak.photoalbum.webapp;
 
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
10,11 → 8,11
import org.apache.log4j.Logger;
 
public final class PageAction
extends Action
extends BaseAction
{
private static final Logger logger = Logger.getLogger(IndexAction.class);
 
public ActionForward execute(ActionMapping mapping, ActionForm form,
public ActionForward executeAction(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception
{
29,26 → 27,15
if(page == null) page = ""; // the images root
 
logger.info("get page " + page);
Logic.getLogic().getEntry(page, entry, index, prev, current, next);
 
if(Logic.getLogic().getEntry(page, entry, index, prev, current, next)) {
logger.debug("ok");
request.setAttribute("page", page);
request.setAttribute("entry", entry);
request.setAttribute("index", index);
request.setAttribute("prevEntry", prev);
request.setAttribute("current", current);
request.setAttribute("nextEntry", next);
 
request.setAttribute("page", page);
request.setAttribute("entry", entry);
request.setAttribute("index", index);
request.setAttribute("prevEntry", prev);
request.setAttribute("current", current);
request.setAttribute("nextEntry", next);
 
return mapping.findForward("success");
}
else {
logger.warn("not found [" + page + "]");
 
response.sendError(HttpServletResponse.SC_NOT_FOUND);
 
return null;
}
return mapping.findForward("success");
}
 
}
/sun/PhotoAlbum/trunk/src/ak/photoalbum/webapp/LogicException.java
0,0 → 1,10
package ak.photoalbum.webapp;
 
public class LogicException
extends Exception
{
public LogicException(String message)
{
super(message);
}
}
Property changes:
Added: svn:keywords
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id
\ No newline at end of property
/sun/PhotoAlbum/trunk/src/ak/photoalbum/webapp/Logic.java
10,6 → 10,7
import java.io.FileInputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.io.FileNotFoundException;
import java.net.URLEncoder;
import org.apache.log4j.Logger;
import ak.photoalbum.images.Thumbnailer;
72,6 → 73,8
catch(Exception ex) {
logger.error("init thumbnailer", ex);
}
 
logger.info("started");
}
 
public void buildCache()
80,14 → 83,18
thumbnailer.buildCache();
}
 
public boolean getEntry(String path, IndexEntry page,
public void getEntry(String path, IndexEntry page,
IndexEntry index, IndexEntry prev, IndexEntry current, IndexEntry next)
throws IOException
throws IOException, LogicException
{
File file = new File(imagesRoot, path);
 
if(!file.exists()) return false;
securePath(imagesRoot, file);
 
if(!file.exists())
throw new FileNotFoundException(
"[" + file.getCanonicalPath() + "] not found");
 
File dir = file.getParentFile();
File[] children = dir.listFiles(imagesFilter);
int pos;
95,7 → 102,9
Arrays.sort(children, fileNameComparator);
pos = Arrays.binarySearch(children, file, fileNameComparator);
 
if(pos < 0) return false;
if(pos < 0)
throw new FileNotFoundException("[" + file.getCanonicalPath()
+ "] not found in [" + dir.getCanonicalPath() + "]");
 
setEntryInfo(page, file, false);
setEntryInfo(current, file, true);
102,8 → 111,6
setEntryInfo(index, dir, true);
if(pos > 0) setEntryInfo(prev, children[pos-1], true);
if(pos < children.length-1) setEntryInfo(next, children[pos+1], true);
 
return true;
}
 
protected void setEntryInfo(IndexEntry entry, File file, boolean small)
139,35 → 146,53
}
 
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
throws IOException, LogicException
{
thumbnailer.writeDir(new File(imagesRoot, path), out);
File file = new File(imagesRoot, path);
 
securePath(imagesRoot, file);
thumbnailer.writeDir(file, out);
}
 
public void writeSmall(String path, OutputStream out)
throws IOException
throws IOException, LogicException
{
thumbnailer.writeSmall(new File(imagesRoot, path), out);
File file = new File(imagesRoot, path);
 
securePath(imagesRoot, file);
thumbnailer.writeSmall(file, out);
}
 
public void writeMedium(String path, OutputStream out)
throws IOException
throws IOException, LogicException
{
thumbnailer.writeMedium(new File(imagesRoot, path), out);
File file = new File(imagesRoot, path);
 
securePath(imagesRoot, file);
thumbnailer.writeMedium(file, out);
}
 
public void writeOrigin(String path, OutputStream out)
throws IOException
throws IOException, LogicException
{
FileInputStream in = null;
FileInputStream in = null;
File file = new File(imagesRoot, path);
 
securePath(imagesRoot, file);
 
try {
in = new FileInputStream(new File(imagesRoot, path));
in = new FileInputStream(file);
FileUtils.copyStreams(in, out);
}
finally {
176,10 → 201,11
}
 
public List listDirectory(String dirName)
throws UnsupportedEncodingException, IOException
throws UnsupportedEncodingException, IOException, LogicException
{
File dir = new File(imagesRoot, dirName);
 
securePath(imagesRoot, dir);
if(!dir.exists()) return null;
 
File[] children = dir.listFiles(imagesFilter);
292,4 → 318,25
{
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() + "]");
}
}
/sun/PhotoAlbum/trunk/src/ak/photoalbum/webapp/ImageAction.java
1,10 → 1,8
package ak.photoalbum.webapp;
 
import java.util.List;
import java.io.FileNotFoundException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
11,11 → 9,11
import org.apache.log4j.Logger;
 
public final class ImageAction
extends Action
extends BaseAction
{
private static final Logger logger = Logger.getLogger(ImageAction.class);
 
public ActionForward execute(ActionMapping mapping, ActionForm form,
public ActionForward executeAction(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception
{
25,31 → 23,22
 
logger.info("get image " + mapping.getParameter() + " for " + path);
 
try {
if("dir".equals(mapping.getParameter())) {
response.setContentType(logic.getThumbnailMime());
logic.writeDir(path, response.getOutputStream());
}
else if("small".equals(mapping.getParameter())) {
response.setContentType(logic.getThumbnailMime());
logic.writeSmall(path, response.getOutputStream());
}
else if("medium".equals(mapping.getParameter())) {
response.setContentType(logic.getThumbnailMime());
logic.writeMedium(path, response.getOutputStream());
}
else if("origin".equals(mapping.getParameter())) {
response.setContentType(logic.getOriginMime(path));
logic.writeOrigin(path, response.getOutputStream());
}
if("dir".equals(mapping.getParameter())) {
response.setContentType(logic.getThumbnailMime());
logic.writeDir(path, response.getOutputStream());
}
catch(FileNotFoundException ex) {
logger.warn("not found: " + ex.getMessage());
response.sendError(HttpServletResponse.SC_NOT_FOUND);
else if("small".equals(mapping.getParameter())) {
response.setContentType(logic.getThumbnailMime());
logic.writeSmall(path, response.getOutputStream());
}
catch(Exception ex) {
logger.error("create thumbnail", ex);
else if("medium".equals(mapping.getParameter())) {
response.setContentType(logic.getThumbnailMime());
logic.writeMedium(path, response.getOutputStream());
}
else if("origin".equals(mapping.getParameter())) {
response.setContentType(logic.getOriginMime(path));
logic.writeOrigin(path, response.getOutputStream());
}
 
return null;
}
/sun/PhotoAlbum/trunk/src/ak/photoalbum/webapp/LogicSecurityException.java
0,0 → 1,10
package ak.photoalbum.webapp;
 
public class LogicSecurityException
extends LogicException
{
public LogicSecurityException(String message)
{
super(message);
}
}
Property changes:
Added: svn:keywords
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id
\ No newline at end of property
/sun/PhotoAlbum/trunk/src/ak/photoalbum/webapp/IndexAction.java
3,7 → 3,6
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
11,11 → 10,11
import ak.photoalbum.util.FileUtils;
 
public final class IndexAction
extends Action
extends BaseAction
{
private static final Logger logger = Logger.getLogger(IndexAction.class);
 
public ActionForward execute(ActionMapping mapping, ActionForm form,
public ActionForward executeAction(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception
{
26,31 → 25,21
IndexEntry prev = new IndexEntry();
IndexEntry current = new IndexEntry();
IndexEntry next = new IndexEntry();
List index;
 
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().getEntry(dir, entry, top, prev, current, next)) {
List index = Logic.getLogic().listDirectory(dir);
logger.debug("ok");
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("dir", FileUtils.replaceFileSeparator(dir, " - "));
request.setAttribute("index", index);
request.setAttribute("top", top);
request.setAttribute("prevEntry", prev);
request.setAttribute("current", current);
request.setAttribute("nextEntry", next);
 
return mapping.findForward("success");
}
else {
logger.warn("not found [" + dir + "]");
 
response.sendError(HttpServletResponse.SC_NOT_FOUND);
 
return null;
}
return mapping.findForward("success");
}
 
}
/sun/PhotoAlbum/trunk/src/ak/photoalbum/images/jiu/JiuResizer.java
156,7 → 156,8
/**
* Creates an {@link RGB24Image} from the argument AWT image instance.
* @param image AWT image object to be converted to a {@link RGB24Image}
* @return a {@link RGB24Image} object holding the image data from the argument image
* @return a {@link RGB24Image} object holding the
* image data from the argument image
*/
protected static RGB24Image convertImageToRGB24Image(Image image)
{
171,7 → 172,9
return null;
}
int[] pixels = new int[width * height];
PixelGrabber pg = new PixelGrabber(image, 0, 0, width, height, pixels, 0, width);
PixelGrabber pg = new PixelGrabber(
image, 0, 0, width, height, pixels, 0, width);
 
try
{
pg.grabPixels();
/sun/PhotoAlbum/trunk/src/ak/photoalbum/images/Thumbnailer.java
229,6 → 229,7
 
if(cached.getOriginTimestamp() != imageFile.lastModified()) {
cached.getFile().delete();
cache.remove(imageFile.getCanonicalPath());
logger.debug("timestamps dont match");
return null;
}
357,8 → 358,8
children[i].delete();
 
if(logger.isDebugEnabled())
logger.debug("deleted: "
+ origin.exists() + " " + cachedTimestamp + " " + originTimestamp);
logger.debug("deleted: " + origin.exists()
+ " " + cachedTimestamp + " " + originTimestamp);
}
}
}
463,13 → 464,15
}
}
 
synchronized protected BufferedImage createThumbnail(File imageFile, int width, int height)
synchronized protected BufferedImage createThumbnail(File imageFile,
int width, int height)
throws IOException
{
if(logger.isDebugEnabled())
logger.debug("create thumbnail " + imageFile.getCanonicalPath());
 
Image image = loadImage(imageFile.getCanonicalPath()); //ImageIO.read(imageFile);
Image image = loadImage(imageFile.getCanonicalPath());
// = ImageIO.read(imageFile);
int[] sizes;
 
if(image == null) { // not supported format
478,7 → 481,8
return null;
}
else {
sizes = calcSizes(image.getWidth(null), image.getHeight(null), width, height);
sizes = calcSizes(image.getWidth(null), image.getHeight(null),
width, height);
logger.debug("resize to " + sizes[0] + "x" + sizes[1]);
 
return resizer.resize(image, sizes[0], sizes[1]);
543,6 → 547,8
 
protected Image loadImage(String fileName)
{
// FIXME: probably toolbox reads an image not by every request but
// caches it
Toolkit toolkit = Toolkit.getDefaultToolkit();
Image image = toolkit.getImage(fileName);
 
554,13 → 560,12
if((status & ImageObserver.ALLBITS) != 0) break;
if((status & ImageObserver.ERROR) != 0) return null;
 
//Thread.currentThread().yield();
try {
Thread.currentThread().sleep(100);
}
catch(Exception ex) {
return null;
};
}
}
 
return image;
/sun/PhotoAlbum/trunk/src/ak/photoalbum/util/FileUtils.java
20,7 → 20,10
 
public static String getMime(String ext)
{
return (String)MIME_MAP.get(ext);
if(ext == null)
return null;
else
return (String)MIME_MAP.get(ext.toLowerCase());
}
 
public static void copyStreams(InputStream in, OutputStream out)
/sun/PhotoAlbum/trunk/build.xml
24,6 → 24,8
</copy>
 
<copy todir="webapp/WEB-INF/classes" file="conf/log4j.properties" />
 
<touch file="webapp/WEB-INF/web.xml" />
</target>
 
<target name="clean">
/sun/PhotoAlbum/trunk/todo.txt
0,0 → 1,8
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. Hierarchy of exceptions.
5. Limits for memory caches (?).
6. Design.
Property changes:
Added: svn:keywords
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id
\ No newline at end of property
/sun/PhotoAlbum/trunk/conf/log4j.properties
5,4 → 5,5
log4j.appender.stdout.layout.ConversionPattern=[%t] %-5p %c - %m%n
 
log4j.logger.ak=warn
log4j.logger.ak.photoalbum.webapp=warn
log4j.logger.ak.photoalbum=warn
log4j.logger.ak.photoalbum.webapp=info