# HG changeset patch
# User robcast
# Date 1098384817 -7200
# Node ID 5d0c0da080ecfef3149cf92c5ab1ae7c30dbe797
# Parent 9f7b864f955f07e2d905416e5e22bd9e02d875e2
digilib servlet version 2 ("scaleable digilib")
- first stab at using thread pools to limit resource use
- using Dug Leas util.concurrent
- doesn't mix with tomcat :-(
diff -r 9f7b864f955f -r 5d0c0da080ec servlet/src/digilib/image/ImageLoaderDocuImage.java
--- a/servlet/src/digilib/image/ImageLoaderDocuImage.java Mon Oct 18 15:40:54 2004 +0200
+++ b/servlet/src/digilib/image/ImageLoaderDocuImage.java Thu Oct 21 20:53:37 2004 +0200
@@ -1,164 +1,480 @@
/* ImageLoaderDocuImage -- Image class implementation using JDK 1.4 ImageLoader
- Digital Image Library servlet components
+ Digital Image Library servlet components
- Copyright (C) 2001, 2002 Robert Casties (robcast@mail.berlios.de)
+ Copyright (C) 2002, 2003 Robert Casties (robcast@mail.berlios.de)
- This program is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published by the
- Free Software Foundation; either version 2 of the License, or (at your
- option) any later version.
-
- Please read license.txt for the full details. A copy of the GPL
- may be found at http://www.gnu.org/copyleft/lgpl.html
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ Please read license.txt for the full details. A copy of the GPL
+ may be found at http://www.gnu.org/copyleft/lgpl.html
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-
-*/
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
package digilib.image;
-import javax.servlet.*;
-import javax.servlet.http.*;
-import java.io.*;
-import java.util.*;
+import java.awt.Rectangle;
+import java.awt.RenderingHints;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.AffineTransformOp;
+import java.awt.image.BufferedImage;
+import java.awt.image.ConvolveOp;
+import java.awt.image.Kernel;
+import java.awt.image.RescaleOp;
+import java.io.File;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.RandomAccessFile;
+import java.util.Iterator;
-import java.awt.*;
-import java.awt.image.*;
-import java.awt.geom.*;
-import java.awt.image.renderable.*;
+import javax.imageio.ImageIO;
+import javax.imageio.ImageReadParam;
+import javax.imageio.ImageReader;
+import javax.imageio.stream.FileImageInputStream;
+import javax.imageio.stream.ImageInputStream;
-import javax.imageio.*;
+import digilib.io.FileOpException;
+import digilib.io.ImageFile;
-import digilib.*;
-import digilib.io.*;
-
+/** Implementation of DocuImage using the ImageLoader API of Java 1.4 and Java2D. */
public class ImageLoaderDocuImage extends DocuImageImpl {
- private BufferedImage img;
+ /** image object */
+ protected BufferedImage img;
+
+ /** interpolation type */
+ protected RenderingHints renderHint;
+
+ /** ImageIO image reader */
+ protected ImageReader reader;
+
+ /** File that was read */
+ protected File imgFile;
+
+ /* loadSubimage is supported. */
+ public boolean isSubimageSupported() {
+ return true;
+ }
+
+ public void setQuality(int qual) {
+ quality = qual;
+ renderHint = new RenderingHints(null);
+ //hint.put(RenderingHints.KEY_ANTIALIASING,
+ // RenderingHints.VALUE_ANTIALIAS_OFF);
+ // setup interpolation quality
+ if (qual > 0) {
+ logger.debug("quality q1");
+ renderHint.put(RenderingHints.KEY_INTERPOLATION,
+ RenderingHints.VALUE_INTERPOLATION_BICUBIC);
+ } else {
+ logger.debug("quality q0");
+ renderHint.put(RenderingHints.KEY_INTERPOLATION,
+ RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR);
+ }
+ }
- public ImageLoaderDocuImage() {
- }
+ public int getHeight() {
+ int h = 0;
+ try {
+ if (img == null) {
+ h = reader.getHeight(0);
+ } else {
+ h = img.getHeight();
+ }
+ } catch (IOException e) {
+ logger.debug("error in getHeight", e);
+ }
+ return h;
+ }
- public ImageLoaderDocuImage(Utils u) {
- util = u;
- }
+ public int getWidth() {
+ int w = 0;
+ try {
+ if (img == null) {
+ w = reader.getWidth(0);
+ } else {
+ w = img.getWidth();
+ }
+ } catch (IOException e) {
+ logger.debug("error in getHeight", e);
+ }
+ return w;
+ }
+
+ /* load image file */
+ public void loadImage(ImageFile f) throws FileOpException {
+ logger.debug("loadImage " + f.getFile());
+ //System.gc();
+ try {
+ img = ImageIO.read(f.getFile());
+ if (img == null) {
+ throw new FileOpException("Unable to load File!");
+ }
+ } catch (IOException e) {
+ throw new FileOpException("Error reading image.");
+ }
+ }
- /**
- * load image file
- */
- public void loadImage(File f) throws FileOpException {
- util.dprintln(10, "loadImage!");
- System.gc();
- try {
- for (int i = 0; i < ImageIO.getReaderFormatNames().length; i++) {
- System.out.println("ImageLoader reader:"+ImageIO.getReaderFormatNames()[i]);
- }
- for (int i = 0; i < ImageIO.getWriterFormatNames().length; i++) {
- System.out.println("ImageLoader writer:"+ImageIO.getWriterFormatNames()[i]);
- }
- img = ImageIO.read(f);
- if (img == null) {
- util.dprintln(3, "ERROR(loadImage): unable to load file");
- throw new FileOpException("Unable to load File!");
- }
- }
- catch (IOException e) {
- throw new FileOpException("Error reading image.");
- }
- }
+ /**
+ * Get an ImageReader for the image file.
+ *
+ * @return
+ */
+ public ImageReader getReader(ImageFile f) throws IOException {
+ logger.debug("preloadImage " + f.getFile());
+ if (reader != null) {
+ logger.debug("Reader was not null!");
+ // clean up old reader
+ dispose();
+ }
+ //System.gc();
+ RandomAccessFile rf = new RandomAccessFile(f.getFile(), "r");
+ ImageInputStream istream = new FileImageInputStream(rf);
+ //Iterator readers = ImageIO.getImageReaders(istream);
+ String mt = f.getMimetype();
+ logger.debug("File type:" + mt);
+ Iterator readers = ImageIO.getImageReadersByMIMEType(mt);
+ if (!readers.hasNext()) {
+ throw new FileOpException("Unable to load File!");
+ }
+ reader = (ImageReader) readers.next();
+ /* are there more readers? */
+ logger.debug("ImageIO: this reader: " + reader.getClass());
+ while (readers.hasNext()) {
+ logger.debug("ImageIO: next reader: " + readers.next().getClass());
+ }
+ //*/
+ reader.setInput(istream);
+ imgFile = f.getFile();
+ return reader;
+ }
+
+ /* Load an image file into the Object. */
+ public void loadSubimage(ImageFile f, Rectangle region, int prescale)
+ throws FileOpException {
+ logger.debug("loadSubimage");
+ //System.gc();
+ try {
+ if ((reader == null) || (imgFile != f.getFile())) {
+ getReader(f);
+ }
+ // set up reader parameters
+ ImageReadParam readParam = reader.getDefaultReadParam();
+ readParam.setSourceRegion(region);
+ if (prescale > 1) {
+ readParam.setSourceSubsampling(prescale, prescale, 0, 0);
+ }
+ // read image
+ logger.debug("loading..");
+ img = reader.read(0, readParam);
+ logger.debug("loaded");
+ } catch (IOException e) {
+ throw new FileOpException("Unable to load File!");
+ }
+ if (img == null) {
+ throw new FileOpException("Unable to load File!");
+ }
+ }
+
+ /* write image of type mt to Stream */
+ public void writeImage(String mt, OutputStream ostream)
+ throws FileOpException {
+ logger.debug("writeImage");
+ try {
+ // setup output
+ String type = "png";
+ if (mt == "image/jpeg") {
+ type = "jpeg";
+ } else if (mt == "image/png") {
+ type = "png";
+ } else {
+ // unknown mime type
+ throw new FileOpException("Unknown mime type: " + mt);
+ }
+
+ /*
+ * JPEG doesn't do transparency so we have to convert any RGBA image
+ * to RGB :-( *Java2D BUG*
+ */
+ if ((type == "jpeg") && (img.getColorModel().hasAlpha())) {
+ logger.debug("BARF: JPEG with transparency!!");
+ int w = img.getWidth();
+ int h = img.getHeight();
+ // BufferedImage.TYPE_INT_RGB seems to be fastest (JDK1.4.1,
+ // OSX)
+ int destType = BufferedImage.TYPE_INT_RGB;
+ BufferedImage img2 = new BufferedImage(w, h, destType);
+ img2.createGraphics().drawImage(img, null, 0, 0);
+ img = img2;
+ }
+
+ // render output
+ logger.debug("writing");
+ if (ImageIO.write(img, type, ostream)) {
+ // writing was OK
+ return;
+ } else {
+ throw new FileOpException(
+ "Error writing image: Unknown image format!");
+ }
+ } catch (IOException e) {
+ throw new FileOpException("Error writing image.");
+ }
+ }
- /**
- * write image of type mt to Stream
- */
- public void writeImage(String mt, ServletResponse res)
- throws FileOpException {
- util.dprintln(10, "writeImage!");
- try {
- // setup output
- String type = "png";
- if (mt == "image/jpeg") {
- type = "jpeg";
- } else if (mt == "image/png") {
- type = "png";
- } else {
- // unknown mime type
- util.dprintln(2, "ERROR(writeImage): Unknown mime type "+mt);
- throw new FileOpException("Unknown mime type: "+mt);
- }
- res.setContentType(mt);
- // render output
- if (ImageIO.write(img, type, res.getOutputStream())) {
- // writing was OK
- return;
- } else {
- throw new FileOpException("Error writing image: Unknown image format!");
- }
- } catch (IOException e) {
- // e.printStackTrace();
- throw new FileOpException("Error writing image.");
- }
- }
+ public void scale(double scale, double scaleY) throws ImageOpException {
+ logger.debug("scale");
+ /* for downscaling in high quality the image is blurred first */
+ if ((scale <= 0.5) && (quality > 1)) {
+ int bl = (int) Math.floor(1 / scale);
+ blur(bl);
+ }
+ /* then scaled */
+ AffineTransformOp scaleOp = new AffineTransformOp(AffineTransform
+ .getScaleInstance(scale, scale), renderHint);
+ BufferedImage scaledImg = null;
+ // enforce destination image type (*Java2D BUG*)
+ int type = img.getType();
+ // FIXME: which type would be best?
+ if ((quality > 0) && (type != 0)) {
+ logger.debug("creating destination image");
+ Rectangle2D dstBounds = scaleOp.getBounds2D(img);
+ scaledImg = new BufferedImage((int) dstBounds.getWidth(),
+ (int) dstBounds.getHeight(), type);
+ }
+ logger.debug("scaling...");
+ scaledImg = scaleOp.filter(img, scaledImg);
+ logger.debug("destination image type " + scaledImg.getType());
+ if (scaledImg == null) {
+ throw new ImageOpException("Unable to scale");
+ }
+ //DEBUG
+ logger.debug("SCALE: " + scale + " ->" + scaledImg.getWidth() + "x"
+ + scaledImg.getHeight());
+ img = scaledImg;
+ scaledImg = null;
+ }
- public int getWidth() {
- if (img != null) {
- return img.getWidth();
- }
- return 0;
- }
+ public void blur(int radius) throws ImageOpException {
+ //DEBUG
+ logger.debug("blur: " + radius);
+ // minimum radius is 2
+ int klen = Math.max(radius, 2);
+ // FIXME: use constant kernels for most common sizes
+ int ksize = klen * klen;
+ // kernel is constant 1/k
+ float f = 1f / ksize;
+ float[] kern = new float[ksize];
+ for (int i = 0; i < ksize; i++) {
+ kern[i] = f;
+ }
+ Kernel blur = new Kernel(klen, klen, kern);
+ // blur with convolve operation
+ ConvolveOp blurOp = new ConvolveOp(blur, ConvolveOp.EDGE_NO_OP,
+ renderHint);
+ // blur needs explicit destination image type for color *Java2D BUG*
+ BufferedImage blurredImg = null;
+ if (img.getType() == BufferedImage.TYPE_3BYTE_BGR) {
+ blurredImg = new BufferedImage(img.getWidth(), img.getHeight(), img
+ .getType());
+ }
+ blurredImg = blurOp.filter(img, blurredImg);
+ if (blurredImg == null) {
+ throw new ImageOpException("Unable to scale");
+ }
+ img = blurredImg;
+ }
+
+ public void crop(int x_off, int y_off, int width, int height)
+ throws ImageOpException {
+ // setup Crop
+ BufferedImage croppedImg = img.getSubimage(x_off, y_off, width, height);
+ logger.debug("CROP:" + croppedImg.getWidth() + "x"
+ + croppedImg.getHeight());
+ //DEBUG
+ // util.dprintln(2, " time
+ // "+(System.currentTimeMillis()-startTime)+"ms");
+ if (croppedImg == null) {
+ throw new ImageOpException("Unable to crop");
+ }
+ img = croppedImg;
+ }
+
+ public void enhance(float mult, float add) throws ImageOpException {
+ /*
+ * Only one constant should work regardless of the number of bands
+ * according to the JDK spec. Doesn't work on JDK 1.4 for OSX and Linux
+ * (at least). RescaleOp scaleOp = new RescaleOp( (float)mult,
+ * (float)add, null); scaleOp.filter(img, img);
+ */
+
+ /* The number of constants must match the number of bands in the image. */
+ int ncol = img.getColorModel().getNumComponents();
+ float[] dm = new float[ncol];
+ float[] da = new float[ncol];
+ for (int i = 0; i < ncol; i++) {
+ dm[i] = (float) mult;
+ da[i] = (float) add;
+ }
+ RescaleOp scaleOp = new RescaleOp(dm, da, null);
+ scaleOp.filter(img, img);
+ }
+
+ public void enhanceRGB(float[] rgbm, float[] rgba) throws ImageOpException {
+
+ /*
+ * The number of constants must match the number of bands in the image.
+ * We do only 3 (RGB) bands.
+ */
+
+ int ncol = img.getColorModel().getNumColorComponents();
+ if ((ncol != 3) || (rgbm.length != 3) || (rgba.length != 3)) {
+ logger
+ .debug("ERROR(enhance): unknown number of color bands or coefficients ("
+ + ncol + ")");
+ return;
+ }
+ RescaleOp scaleOp = new RescaleOp(rgbOrdered(rgbm), rgbOrdered(rgba),
+ null);
+ scaleOp.filter(img, img);
+ }
- public int getHeight() {
- if (img != null) {
- return img.getHeight();
- }
- return 0;
- }
-
- /**
- * crop and scale image
- * take rectangle width,height at position x_off,y_off
- * and scale by scale
- */
- public void cropAndScale(int x_off, int y_off, int width, int height,
- float scale, int qual) throws ImageOpException {
- util.dprintln(10, "cropAndScale!");
-
- int scaleInt = 0;
- // setup interpolation quality
- if (qual > 0) {
- util.dprintln(4, "quality q1");
- scaleInt = AffineTransformOp.TYPE_BILINEAR;
- } else {
- util.dprintln(4, "quality q0");
- scaleInt = AffineTransformOp.TYPE_NEAREST_NEIGHBOR;
- }
+ /**
+ * Ensures that the array f is in the right order to map the images RGB
+ * components. (not shure what happens
+ */
+ public float[] rgbOrdered(float[] fa) {
+ /*
+ * TODO: this is UGLY, UGLY!!
+ */
+ float[] fb;
+ int t = img.getType();
+ if (img.getColorModel().hasAlpha()) {
+ fb = new float[4];
+ if ((t == BufferedImage.TYPE_INT_ARGB)
+ || (t == BufferedImage.TYPE_INT_ARGB_PRE)) {
+ // RGB Type
+ fb[0] = fa[0];
+ fb[1] = fa[1];
+ fb[2] = fa[2];
+ fb[3] = 1f;
+ } else {
+ // this isn't tested :-(
+ fb[0] = 1f;
+ fb[1] = fa[0];
+ fb[2] = fa[1];
+ fb[3] = fa[2];
+ }
+ } else {
+ fb = new float[3];
+ if (t == BufferedImage.TYPE_3BYTE_BGR) {
+ // BGR Type (actually it looks like RBG...)
+ fb[0] = fa[0];
+ fb[1] = fa[2];
+ fb[2] = fa[1];
+ } else {
+ fb[0] = fa[0];
+ fb[1] = fa[1];
+ fb[2] = fa[2];
+ }
+ }
+ return fb;
+ }
- // setup Crop
- BufferedImage croppedImg = img.getSubimage(x_off, y_off, width, height);
-
- img = null; // free img
- util.dprintln(3, "CROP:"+croppedImg.getWidth()+"x"+croppedImg.getHeight()); //DEBUG
-// util.dprintln(2, " time "+(System.currentTimeMillis()-startTime)+"ms");
-
- if (croppedImg == null) {
- util.dprintln(2, "ERROR(cropAndScale): error in crop");
- throw new ImageOpException("Unable to crop");
- }
+ public void rotate(double angle) throws ImageOpException {
+ // setup rotation
+ double rangle = Math.toRadians(angle);
+ // create offset to make shure the rotated image has no negative
+ // coordinates
+ double w = img.getWidth();
+ double h = img.getHeight();
+ AffineTransform trafo = new AffineTransform();
+ // center of rotation
+ double x = (w / 2);
+ double y = (h / 2);
+ trafo.rotate(rangle, x, y);
+ // try rotation to see how far we're out of bounds
+ AffineTransformOp rotOp = new AffineTransformOp(trafo, renderHint);
+ Rectangle2D rotbounds = rotOp.getBounds2D(img);
+ double xoff = rotbounds.getX();
+ double yoff = rotbounds.getY();
+ // move image back in line
+ trafo
+ .preConcatenate(AffineTransform.getTranslateInstance(-xoff,
+ -yoff));
+ // transform image
+ rotOp = new AffineTransformOp(trafo, renderHint);
+ BufferedImage rotImg = rotOp.filter(img, null);
+ // calculate new bounding box
+ //Rectangle2D bounds = rotOp.getBounds2D(img);
+ if (rotImg == null) {
+ throw new ImageOpException("Unable to rotate");
+ }
+ img = rotImg;
+ // crop new image (with self-made rounding)
+ /*
+ * img = rotImg.getSubimage( (int) (bounds.getX()+0.5), (int)
+ * (bounds.getY()+0.5), (int) (bounds.getWidth()+0.5), (int)
+ * (bounds.getHeight()+0.5));
+ */
+ }
- // setup scale
- AffineTransformOp scaleOp = new AffineTransformOp(
- AffineTransform.getScaleInstance(scale, scale),
- scaleInt);
- BufferedImage scaledImg = scaleOp.filter(croppedImg, null);
- croppedImg = null; // free opCrop
+ public void mirror(double angle) throws ImageOpException {
+ // setup mirror
+ double mx = 1;
+ double my = 1;
+ double tx = 0;
+ double ty = 0;
+ if (Math.abs(angle - 0) < epsilon) { // 0 degree
+ mx = -1;
+ tx = getWidth();
+ } else if (Math.abs(angle - 90) < epsilon) { // 90 degree
+ my = -1;
+ ty = getHeight();
+ } else if (Math.abs(angle - 180) < epsilon) { // 180 degree
+ mx = -1;
+ tx = getWidth();
+ } else if (Math.abs(angle - 270) < epsilon) { // 270 degree
+ my = -1;
+ ty = getHeight();
+ } else if (Math.abs(angle - 360) < epsilon) { // 360 degree
+ mx = -1;
+ tx = getWidth();
+ }
+ AffineTransformOp mirOp = new AffineTransformOp(new AffineTransform(mx,
+ 0, 0, my, tx, ty), renderHint);
+ BufferedImage mirImg = mirOp.filter(img, null);
+ if (mirImg == null) {
+ throw new ImageOpException("Unable to mirror");
+ }
+ img = mirImg;
+ }
- if (scaledImg == null) {
- util.dprintln(2, "ERROR(cropAndScale): error in scale");
- throw new ImageOpException("Unable to scale");
- }
- img = scaledImg;
- }
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Object#finalize()
+ */
+ protected void finalize() throws Throwable {
+ dispose();
+ super.finalize();
+ }
+
+ public void dispose() {
+ // we must dispose the ImageReader because it keeps the filehandle
+ // open!
+ if (reader != null) {
+ reader.dispose();
+ reader = null;
+ }
+ img = null;
+ }
}
diff -r 9f7b864f955f -r 5d0c0da080ec servlet/src/digilib/image/ImageSize.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/servlet/src/digilib/image/ImageSize.java Thu Oct 21 20:53:37 2004 +0200
@@ -0,0 +1,220 @@
+/*
+ * ImageFile.java -- digilib image file class.
+ * Digital Image Library servlet components
+ * Copyright (C) 2003 Robert Casties (robcast@mail.berlios.de)
+ * This program is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any later
+ * version. Please read license.txt for the full details. A copy of the GPL may
+ * be found at http://www.gnu.org/copyleft/lgpl.html You should have received a
+ * copy of the GNU General Public License along with this program; if not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307 USA Created on 26.08.2003
+ */
+
+package digilib.image;
+
+/** Class for image size (width, height).
+ *
+ * A width or height of 0 is treated as a 'wildcard' that matches any size.
+ *
+ * @author casties
+ *
+ */
+public class ImageSize {
+ public int width;
+ public int height;
+
+ public ImageSize() {
+ super();
+ }
+
+ public ImageSize(int width, int height) {
+ this.width = width;
+ this.height = height;
+ }
+
+ public ImageSize(ImageSize i) {
+ this.width = i.width;
+ this.height = i.height;
+ }
+
+ public void setSize(int width, int height) {
+ this.width = width;
+ this.height = height;
+ }
+
+ /**
+ * Returns if the size of this image is smaller in every dimension than the
+ * other image.
+ *
+ *
+ *
+ * @param is
+ * @return
+ */
+ public boolean isTotallySmallerThan(ImageSize is) {
+ if ((this.width == 0)||(is.width == 0)) {
+ // width wildcard
+ return (this.height <= is.height);
+ }
+ if ((this.height == 0)||(is.height == 0)) {
+ // height wildcard
+ return (this.width <= is.width);
+ }
+ return ((this.width <= is.width)&&(this.height <= is.height));
+ }
+
+ /**
+ * Returns if the size of this image is smaller in at least one dimension
+ * than the other image.
+ *
+ * @param is
+ * @return
+ */
+ public boolean isSmallerThan(ImageSize is) {
+ if ((this.width == 0)||(is.width == 0)) {
+ // width wildcard
+ return (this.height <= is.height);
+ }
+ if ((this.height == 0)||(is.height == 0)) {
+ // height wildcard
+ return (this.width <= is.width);
+ }
+ return ((this.width <= is.width) || (this.height <= is.height));
+ }
+
+ /**
+ * Returns if the size of this image is bigger in every dimension than the
+ * other image.
+ *
+ *
+ *
+ * @param is
+ * @return
+ */
+ public boolean isTotallyBiggerThan(ImageSize is) {
+ if ((this.width == 0)||(is.width == 0)) {
+ // width wildcard
+ return (this.height >= is.height);
+ }
+ if ((this.height == 0)||(is.height == 0)) {
+ // height wildcard
+ return (this.width >= is.width);
+ }
+ return ((this.width >= is.width) && (this.height >= is.height));
+ }
+
+ /**
+ * Returns if the size of this image is bigger in at least one dimension
+ * than the other image.
+ *
+ *
+ *
+ * @param is
+ * @return
+ */
+ public boolean isBiggerThan(ImageSize is) {
+ if ((this.width == 0)||(is.width == 0)) {
+ // width wildcard
+ return (this.height >= is.height);
+ }
+ if ((this.height == 0)||(is.height == 0)) {
+ // height wildcard
+ return (this.width >= is.width);
+ }
+ return ((this.width >= is.width) || (this.height >= is.height));
+ }
+
+ /**
+ * Returns if this image has the same size or height as the other image.
+ *
+ *
+ *
+ * @param is
+ * @return
+ */
+ public boolean fitsIn(ImageSize is) {
+ if ((this.width == 0)||(is.width == 0)) {
+ // width wildcard
+ return (this.height == is.height);
+ }
+ if ((this.height == 0)||(is.height == 0)) {
+ // height wildcard
+ return (this.width == is.width);
+ }
+ return (
+ (this.width == is.width)
+ && (this.height <= is.height)
+ || (this.width <= is.width)
+ && (this.height == is.height));
+ }
+
+ /**
+ * Returns if the size of this image is the same as the other image.
+ *
+ *
+ *
+ * @param is
+ * @return
+ */
+ public boolean equals(ImageSize is) {
+ if ((this.width == 0)||(is.width == 0)) {
+ // width wildcard
+ return (this.height == is.height);
+ }
+ if ((this.height == 0)||(is.height == 0)) {
+ // height wildcard
+ return (this.width == is.width);
+ }
+ return ((this.width == is.width) && (this.height == is.height));
+ }
+
+ /**
+ * @return
+ */
+ public int getHeight() {
+ return height;
+ }
+
+ /**
+ * @param height
+ */
+ public void setHeight(int height) {
+ this.height = height;
+ }
+
+ /**
+ * @return
+ */
+ public int getWidth() {
+ return width;
+ }
+
+ /**
+ * @param width
+ */
+ public void setWidth(int width) {
+ this.width = width;
+ }
+
+ /**
+ * Returns the aspect ratio.
+ *
+ * Aspect ratio is (width/height). So it's <1 for portrait and >1 for
+ * landscape.
+ *
+ * @return
+ */
+ public float getAspect() {
+ return (height > 0) ? ((float) width / (float) height) : 0;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#toString()
+ */
+ public String toString() {
+ String s = "[" + width + "x" + height + "]";
+ return s;
+ }
+}
diff -r 9f7b864f955f -r 5d0c0da080ec servlet/src/digilib/image/JAIImageLoaderDocuImage.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/servlet/src/digilib/image/JAIImageLoaderDocuImage.java Thu Oct 21 20:53:37 2004 +0200
@@ -0,0 +1,184 @@
+/* JAIImageLoaderDocuImage -- Image class implementation using JAI's ImageLoader Plugin
+
+ Digital Image Library servlet components
+
+ Copyright (C) 2002, 2003 Robert Casties (robcast@mail.berlios.de)
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ Please read license.txt for the full details. A copy of the GPL
+ may be found at http://www.gnu.org/copyleft/lgpl.html
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+*/
+
+package digilib.image;
+
+import java.awt.Rectangle;
+import java.awt.image.renderable.ParameterBlock;
+import java.io.File;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.RandomAccessFile;
+import java.util.Iterator;
+
+import javax.imageio.ImageIO;
+import javax.imageio.ImageReadParam;
+import javax.imageio.ImageReader;
+import javax.imageio.stream.FileImageInputStream;
+import javax.imageio.stream.ImageInputStream;
+import javax.media.jai.JAI;
+
+import digilib.io.FileOpException;
+import digilib.io.ImageFile;
+
+/** DocuImage implementation using the Java Advanced Imaging API and the ImageLoader
+ * API of Java 1.4.
+ */
+public class JAIImageLoaderDocuImage extends JAIDocuImage {
+
+ /** ImageIO image reader */
+ protected ImageReader reader;
+ /** current image file */
+ protected File imgFile;
+
+ /* loadSubimage is supported. */
+ public boolean isSubimageSupported() {
+ return true;
+ }
+
+ public int getHeight() {
+ int h = 0;
+ try {
+ if (img == null) {
+ h = reader.getHeight(0);
+ } else {
+ h = img.getHeight();
+ }
+ } catch (IOException e) {
+ logger.debug("error in getHeight", e);
+ }
+ return h;
+ }
+
+ public int getWidth() {
+ int w = 0;
+ try {
+ if (img == null) {
+ w = reader.getWidth(0);
+ } else {
+ w = img.getWidth();
+ }
+ } catch (IOException e) {
+ logger.debug("error in getHeight", e);
+ }
+ return w;
+ }
+
+ /* Load an image file into the Object. */
+ public void loadImage(ImageFile f) throws FileOpException {
+ logger.debug("loadImage: "+f.getFile());
+ //System.gc();
+ img = JAI.create("ImageRead", f.getFile().getAbsolutePath());
+ if (img == null) {
+ throw new FileOpException("Unable to load File!");
+ }
+ }
+
+ /* Get an ImageReader for the image file. */
+ public ImageReader getReader(ImageFile f) throws IOException {
+ logger.debug("preloadImage: "+f.getFile());
+ //System.gc();
+ RandomAccessFile rf = new RandomAccessFile(f.getFile(), "r");
+ ImageInputStream istream = new FileImageInputStream(rf);
+ //Iterator readers = ImageIO.getImageReaders(istream);
+ Iterator readers = ImageIO.getImageReadersByMIMEType(f.getMimetype());
+ if (! readers.hasNext()) {
+ throw new FileOpException("Unable to load File!");
+ }
+ reader = (ImageReader) readers.next();
+ logger.debug("JAIImageIO: this reader: " + reader.getClass());
+ while (readers.hasNext()) {
+ logger.debug(" next reader: " + readers.next().getClass());
+ }
+ reader.setInput(istream);
+ return reader;
+ }
+
+ /* Load an image file into the Object. */
+ public void loadSubimage(ImageFile f, Rectangle region, int prescale)
+ throws FileOpException {
+ logger.debug("loadSubimage: "+f.getFile());
+ //System.gc();
+ try {
+ if ((reader == null) || (imgFile != f.getFile())) {
+ getReader(f);
+ }
+ ImageReadParam readParam = reader.getDefaultReadParam();
+ readParam.setSourceRegion(region);
+ readParam.setSourceSubsampling(prescale, prescale, 0, 0);
+ img = reader.read(0, readParam);
+ /* JAI imageread seems to ignore the readParam :-(
+ ImageInputStream istream = (ImageInputStream) reader.getInput();
+ ParameterBlockJAI pb = new ParameterBlockJAI("imageread");
+ pb.setParameter("Input", istream);
+ pb.setParameter("ReadParam", readParam);
+ pb.setParameter("Reader", reader);
+ img = JAI.create("imageread", pb);
+ */
+ } catch (IOException e) {
+ throw new FileOpException("Unable to load File!");
+ }
+ if (img == null) {
+ throw new FileOpException("Unable to load File!");
+ }
+ imgFile = f.getFile();
+ }
+
+
+ /* Write the current image to an OutputStream. */
+ public void writeImage(String mt, OutputStream ostream)
+ throws FileOpException {
+ logger.debug("writeImage");
+ try {
+ // setup output
+ ParameterBlock pb3 = new ParameterBlock();
+ pb3.addSource(img);
+ pb3.add(ostream);
+ if (mt == "image/jpeg") {
+ pb3.add("JPEG");
+ } else if (mt == "image/png") {
+ pb3.add("PNG");
+ } else {
+ // unknown mime type
+ throw new FileOpException("Unknown mime type: " + mt);
+ }
+ // render output
+ JAI.create("ImageWrite", pb3);
+ } catch (IOException e) {
+ throw new FileOpException("Error writing image.");
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#finalize()
+ */
+ protected void finalize() throws Throwable {
+ dispose();
+ super.finalize();
+ }
+
+ public void dispose() {
+ // we must dispose the ImageReader because it keeps the filehandle open!
+ reader.dispose();
+ reader = null;
+ img = null;
+ }
+
+}
diff -r 9f7b864f955f -r 5d0c0da080ec servlet/src/digilib/io/Directory.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/servlet/src/digilib/io/Directory.java Thu Oct 21 20:53:37 2004 +0200
@@ -0,0 +1,139 @@
+/* Directory -- Filesystem directory object
+
+ Digital Image Library servlet components
+
+ Copyright (C) 2003 Robert Casties (robcast@mail.berlios.de)
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ Please read license.txt for the full details. A copy of the GPL
+ may be found at http://www.gnu.org/copyleft/lgpl.html
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ * Created on 26.08.2003
+ *
+ */
+package digilib.io;
+
+import java.io.File;
+import java.util.Arrays;
+
+import org.apache.log4j.Logger;
+
+/** Class for filesystem directories
+ * @author casties
+ *
+ */
+public class Directory {
+
+ protected Logger logger = Logger.getLogger(this.getClass());
+
+ /** File object pointing to the directory */
+ protected File dir = null;
+ /** parent directory */
+ protected Directory parent = null;
+ /** list of filenames in the directory */
+ protected String[] list = null;
+
+ /** Default constructor.
+ *
+ */
+ public Directory() {
+ super();
+ }
+
+ /** Constructor taking a File object.
+ *
+ * @param d
+ */
+ public Directory(File d) {
+ dir = d;
+ }
+
+ /** Constructor taking a File object and a parent.
+ *
+ * @param dir
+ * @param parent
+ */
+ public Directory(File dir, Directory parent) {
+ this.dir = dir;
+ this.parent = parent;
+ }
+
+ /** Constructor taking a directory name.
+ *
+ * @param d
+ */
+ public Directory(String dn) {
+ dir = new File(dn);
+ }
+
+
+ /** Reads the names of the files in the directory.
+ * Fills the filenames array. Returns if the operation was successful.
+ *
+ * @return
+ */
+ public boolean readDir() {
+ if (dir != null) {
+ //logger.debug("reading dir: "+dir.getPath());
+ list = dir.list();
+ Arrays.sort(list);
+ //logger.debug(" done");
+ }
+ return (list != null);
+ }
+
+ /**
+ * @return
+ */
+ public File getDir() {
+ return dir;
+ }
+
+ /**
+ * @param dir
+ */
+ public void setDir(File dir) {
+ this.dir = dir;
+ }
+
+ /**
+ * @return
+ */
+ Directory getParent() {
+ return parent;
+ }
+
+ /**
+ * @param parent
+ */
+ void setParent(Directory parent) {
+ this.parent = parent;
+ }
+
+
+ /**
+ * @return Returns the filenames.
+ */
+ public String[] getFilenames() {
+ return list;
+ }
+
+ /**
+ * @param filenames The filenames to set.
+ */
+ public void setFilenames(String[] filenames) {
+ this.list = filenames;
+ }
+
+ public void clearFilenames() {
+ this.list = null;
+ }
+}
diff -r 9f7b864f955f -r 5d0c0da080ec servlet/src/digilib/io/DocuDirCache.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/servlet/src/digilib/io/DocuDirCache.java Thu Oct 21 20:53:37 2004 +0200
@@ -0,0 +1,355 @@
+/*
+ * DocuDirCache.java
+ *
+ * Digital Image Library servlet components
+ *
+ * Copyright (C) 2003 Robert Casties (robcast@mail.berlios.de)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * Please read license.txt for the full details. A copy of the GPL may be found
+ * at http://www.gnu.org/copyleft/lgpl.html
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Created on 03.03.2003
+ */
+
+package digilib.io;
+
+import java.io.File;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.log4j.Logger;
+
+import digilib.servlet.DigilibConfiguration;
+
+/**
+ * @author casties
+ */
+public class DocuDirCache {
+
+ /** general logger for this class */
+ Logger logger = Logger.getLogger(this.getClass());
+
+ /** HashMap of directories */
+ Map map = null;
+
+ /** names of base directories */
+ String[] baseDirNames = null;
+
+ /** array of allowed file classes (image/text) */
+ private int[] fileClasses = null;
+
+ /** number of files in the whole cache (approximate) */
+ long numFiles = 0;
+
+ /** number of cache hits */
+ long hits = 0;
+
+ /** number of cache misses */
+ long misses = 0;
+
+ /** use safe (but slow) indexing */
+ boolean safeDirIndex = false;
+
+ /** the root directory element */
+ public static Directory ROOT = null;
+
+ /**
+ * Constructor with array of base directory names and file classes.
+ *
+ * @param bd
+ * base directory names
+ */
+ public DocuDirCache(String[] bd, int[] fileClasses,
+ DigilibConfiguration dlConfig) {
+ baseDirNames = bd;
+ map = new HashMap();
+ this.fileClasses = fileClasses;
+ safeDirIndex = dlConfig.getAsBoolean("safe-dir-index");
+ }
+
+ /**
+ * Constructor with array of base directory names.
+ *
+ * @param bd
+ * base directory names
+ */
+ public DocuDirCache(String[] bd) {
+ baseDirNames = bd;
+ map = new HashMap();
+ // default file class is CLASS_IMAGE
+ fileClasses = new int[1];
+ fileClasses[0] = FileOps.CLASS_IMAGE;
+ }
+
+ /**
+ * The number of directories in the cache.
+ *
+ * @return
+ */
+ public int size() {
+ return (map != null) ? map.size() : 0;
+ }
+
+ /**
+ * Add a DocuDirectory to the cache.
+ *
+ * @param newdir
+ */
+ public void put(DocuDirectory newdir) {
+ String s = newdir.getDirName();
+ if (map.containsKey(s)) {
+ logger.warn("Duplicate key in DocuDirCache.put -- ignoring!");
+ } else {
+ map.put(s, newdir);
+ numFiles += newdir.size();
+ }
+ }
+
+ /**
+ * Add a directory to the cache and check its parents.
+ *
+ * @param newDir
+ */
+ public synchronized void putDir(DocuDirectory newDir) {
+ put(newDir);
+ String parent = FileOps.parent(newDir.getDirName());
+ if (parent != "") {
+ // check the parent in the cache
+ DocuDirectory pd = (DocuDirectory) map.get(parent);
+ if (pd == null) {
+ // the parent is unknown
+ pd = new DocuDirectory(parent, this);
+ putDir(pd);
+ }
+ newDir.setParent(pd);
+ }
+ }
+
+ /**
+ * Get a list with all children of a directory.
+ *
+ * Returns a List of DocuDirectory's. Returns an empty List if the directory
+ * has no children. If recurse is false then only direct children are
+ * returned.
+ *
+ * @param dirname
+ * @param recurse
+ * find all children and their children.
+ * @return
+ */
+ public List getChildren(String dirname, boolean recurse) {
+ List l = new LinkedList();
+ for (Iterator i = map.keySet().iterator(); i.hasNext();) {
+ String n = (String) i.next();
+ DocuDirectory dd = (DocuDirectory) map.get(n);
+ if (recurse) {
+ if (dd.getDirName().startsWith(dirname)) {
+ l.add(dd);
+ }
+ } else {
+ if (FileOps.parent(dd.getDirName()).equals(dirname)) {
+ l.add(dd);
+ }
+ }
+ }
+ return l;
+ }
+
+ /**
+ * Returns the DocuDirent with the pathname fn
and the index
+ * in
and the class fc
.
+ *
+ * If fn
is a file then the corresponding DocuDirent is
+ * returned and the index is ignored.
+ *
+ * @param fn
+ * digilib pathname
+ * @param in
+ * file index
+ * @param fc
+ * file class
+ * @return
+ */
+ public DocuDirent getFile(String fn, int in, int fc) {
+ DocuDirectory dd;
+ // file number is 1-based, vector index is 0-based
+ int n = in - 1;
+ // first, assume fn is a directory and look in the cache
+ dd = (DocuDirectory) map.get(fn);
+ if (dd == null) {
+ // cache miss
+ misses++;
+ /*
+ * see if fn is a directory
+ */
+ File f = new File(baseDirNames[0], fn);
+ if (f.isDirectory()) {
+ dd = new DocuDirectory(fn, this);
+ if (dd.isValid()) {
+ // add to the cache
+ putDir(dd);
+ }
+ } else {
+ /*
+ * maybe it's a file
+ */
+ // get the parent directory string (like we store it in the
+ // cache)
+ String d = FileOps.parent(fn);
+ // try it in the cache
+ dd = (DocuDirectory) map.get(d);
+ if (dd == null) {
+ // try to read from disk
+ dd = new DocuDirectory(d, this);
+ if (dd.isValid()) {
+ // add to the cache
+ putDir(dd);
+ } else {
+ // invalid path
+ return null;
+ }
+ } else {
+ // it was not a real cache miss
+ misses--;
+ }
+ // get the file's index
+ n = dd.indexOf(f.getName(), fc);
+ }
+ } else {
+ // cache hit
+ hits++;
+ }
+ dd.refresh();
+ if (dd.isValid()) {
+ try {
+ return dd.get(n, fc);
+ } catch (IndexOutOfBoundsException e) {
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns the DocuDirectory indicated by the pathname fn
.
+ *
+ * If fn
is a file then its parent directory is returned.
+ *
+ * @param fn
+ * digilib pathname
+ * @return
+ */
+ public DocuDirectory getDirectory(String fn) {
+ DocuDirectory dd;
+ // first, assume fn is a directory and look in the cache
+ dd = (DocuDirectory) map.get(fn);
+ if (dd == null) {
+ // cache miss
+ misses++;
+ // see if it's a directory
+ File f = new File(baseDirNames[0], fn);
+ if (f.isDirectory()) {
+ dd = new DocuDirectory(fn, this);
+ if (dd.isValid()) {
+ // add to the cache
+ putDir(dd);
+ }
+ } else {
+ // maybe it's a file
+ if (f.canRead()) {
+ // try the parent directory in the cache
+ dd = (DocuDirectory) map.get(f.getParent());
+ if (dd == null) {
+ // try to read from disk
+ dd = new DocuDirectory(f.getParent(), this);
+ if (dd.isValid()) {
+ // add to the cache
+ putDir(dd);
+ } else {
+ // invalid path
+ return null;
+ }
+ } else {
+ // not a real cache miss then
+ misses--;
+ }
+ } else {
+ // it's not even a file :-(
+ return null;
+ }
+ }
+ } else {
+ // cache hit
+ hits++;
+ }
+ dd.refresh();
+ if (dd.isValid()) {
+ return dd;
+ }
+ return null;
+ }
+
+ /**
+ * @return String[]
+ */
+ public String[] getBaseDirNames() {
+ return baseDirNames;
+ }
+
+ /**
+ * @return long
+ */
+ public long getNumFiles() {
+ return numFiles;
+ }
+
+ /**
+ * Sets the baseDirNames.
+ *
+ * @param baseDirNames
+ * The baseDirNames to set
+ */
+ public void setBaseDirNames(String[] baseDirNames) {
+ this.baseDirNames = baseDirNames;
+ }
+
+ /**
+ * @return long
+ */
+ public long getHits() {
+ return hits;
+ }
+
+ /**
+ * @return long
+ */
+ public long getMisses() {
+ return misses;
+ }
+
+ /**
+ * @return
+ */
+ public int[] getFileClasses() {
+ return fileClasses;
+ }
+
+ /**
+ * @param fileClasses
+ */
+ public void setFileClasses(int[] fileClasses) {
+ this.fileClasses = fileClasses;
+ }
+
+}
diff -r 9f7b864f955f -r 5d0c0da080ec servlet/src/digilib/io/DocuDirectory.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/servlet/src/digilib/io/DocuDirectory.java Thu Oct 21 20:53:37 2004 +0200
@@ -0,0 +1,563 @@
+/* DocuDirectory -- Directory of DocuFilesets.
+
+ Digital Image Library servlet components
+
+ Copyright (C) 2003 Robert Casties (robcast@mail.berlios.de)
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ Please read license.txt for the full details. A copy of the GPL
+ may be found at http://www.gnu.org/copyleft/lgpl.html
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ * Created on 25.02.2003
+ */
+
+package digilib.io;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.xml.sax.SAXException;
+
+/**
+ * @author casties
+ */
+public class DocuDirectory extends Directory {
+
+ /** list of files (DocuDirent) */
+ private ArrayList[] list = null;
+
+ /** directory object is valid (exists on disk) */
+ private boolean isValid = false;
+
+ /** reference of the parent DocuDirCache */
+ private DocuDirCache cache = null;
+
+ /** directory name (digilib canonical form) */
+ private String dirName = null;
+
+ /** directory metadata */
+ private Map dirMeta = null;
+
+ /** state of metadata is valid */
+ private boolean metaChecked = false;
+
+ /** unresolved file metadata */
+ private Map unresolvedFileMeta = null;
+
+ /** time of last access of this object (not the filesystem) */
+ private long objectATime = 0;
+
+ /** time directory was last modified on the file system */
+ private long dirMTime = 0;
+
+ /**
+ * Constructor with digilib directory path and a parent DocuDirCache.
+ *
+ * Directory names at the given path are appended to the base directories
+ * from the cache. The directory is checked on disk and isValid is set.
+ *
+ * @see readDir
+ *
+ * @param path
+ * digilib directory path name
+ * @param cache
+ * parent DocuDirCache
+ */
+ public DocuDirectory(String path, DocuDirCache cache) {
+ this.dirName = path;
+ this.cache = cache;
+ initDir();
+ checkDir();
+ }
+
+ /**
+ * Sets and checks the dir object.
+ *
+ */
+ protected void initDir() {
+ String baseDirName = cache.getBaseDirNames()[0];
+ // clear directory first
+ list = new ArrayList[FileOps.NUM_CLASSES];
+ isValid = false;
+ dirMTime = 0;
+ // the first directory has to exist
+ dir = new File(baseDirName, dirName);
+ }
+
+ /**
+ * number of DocuFiles in this directory.
+ *
+ */
+ public int size() {
+ return ((list != null) && (list[0] != null)) ? list[0].size() : 0;
+ }
+
+ /**
+ * number of files of this class in this directory.
+ *
+ * @param fc
+ * fileClass
+ */
+ public int size(int fc) {
+ return ((list != null) && (list[fc] != null)) ? list[fc].size() : 0;
+ }
+
+ /**
+ * Returns the ImageFile at the index.
+ *
+ * @param index
+ * @return
+ */
+ public ImageFileset get(int index) {
+ if ((list == null) || (list[0] == null) || (index >= list[0].size())) {
+ return null;
+ }
+ return (ImageFileset) list[0].get(index);
+ }
+
+ /**
+ * Returns the file of the class at the index.
+ *
+ * @param index
+ * @param fc
+ * fileClass
+ * @return
+ */
+ public DocuDirent get(int index, int fc) {
+ if ((list == null) || (list[fc] == null) || (index >= list[fc].size())) {
+ return null;
+ }
+ return (DocuDirent) list[fc].get(index);
+ }
+
+ /**
+ * Checks if the directory exists on the filesystem.
+ *
+ * Sets isValid.
+ *
+ * @return
+ */
+ public boolean checkDir() {
+ if (dir == null) {
+ initDir();
+ }
+ isValid = dir.isDirectory();
+ return isValid;
+ }
+
+ /**
+ * Read the filesystem directory and fill this object.
+ *
+ * Clears the List and (re)reads all files.
+ *
+ * @return boolean the directory exists
+ */
+ public synchronized boolean readDir() {
+ // check directory first
+ checkDir();
+ if (!isValid) {
+ return false;
+ }
+ // first file extension to try for scaled directories
+ String scalext = null;
+ // read all filenames
+ //logger.debug("reading directory " + dir.getPath());
+ /*
+ * using ReadableFileFilter is safer (we won't get directories with file
+ * extensions) but slower.
+ */
+ File[] allFiles = null;
+ if (cache.safeDirIndex) {
+ allFiles = dir.listFiles(new FileOps.ReadableFileFilter());
+ } else {
+ allFiles = dir.listFiles();
+ }
+ //logger.debug(" done");
+ if (allFiles == null) {
+ // not a directory
+ return false;
+ }
+ // list of base dirs from the parent cache
+ String[] baseDirNames = cache.getBaseDirNames();
+ // number of base dirs
+ int nb = baseDirNames.length;
+ // array of base dirs
+ Directory[] dirs = new Directory[nb];
+ // first entry is this directory
+ dirs[0] = this;
+ // fill array with the remaining directories
+ for (int j = 1; j < nb; j++) {
+ File d = new File(baseDirNames[j], dirName);
+ if (d.isDirectory()) {
+ dirs[j] = new Directory(d);
+ //logger.debug(" reading scaled directory " + d.getPath());
+ dirs[j].readDir();
+ //logger.debug(" done");
+ }
+ }
+
+ // go through all file classes
+ for (int classIdx = 0; classIdx < FileOps.NUM_CLASSES; classIdx++) {
+ int fileClass = cache.getFileClasses()[classIdx];
+ //logger.debug("filtering directory "+dir.getPath()+" for class
+ // "+fc);
+ File[] fileList = FileOps.listFiles(allFiles, FileOps
+ .filterForClass(fileClass));
+ //logger.debug(" done");
+ // number of files in the directory
+ int numFiles = fileList.length;
+ if (numFiles > 0) {
+ // create new list
+ list[fileClass] = new ArrayList(numFiles);
+ // sort the file names alphabetically and iterate the list
+ Arrays.sort(fileList);
+ Map hints = FileOps.newHints(FileOps.HINT_BASEDIRS, dirs);
+ hints.put(FileOps.HINT_FILEEXT, scalext);
+ for (int i = 0; i < numFiles; i++) {
+ DocuDirent f = FileOps.fileForClass(fileClass, fileList[i],
+ hints);
+ // add the file to our list
+ list[fileClass].add(f);
+ f.setParent(this);
+ }
+ }
+ }
+ // clear the scaled directories
+ for (int j = 1; j < nb; j++) {
+ if (dirs[j] != null) {
+ dirs[j].clearFilenames();
+ }
+ }
+ // update number of cached files if this was the first time
+ if (dirMTime == 0) {
+ cache.numFiles += size();
+ }
+ dirMTime = dir.lastModified();
+ // read metadata as well
+ readMeta();
+ return isValid;
+ }
+
+ /**
+ * Check to see if the directory has been modified and reread if necessary.
+ *
+ * @return boolean the directory is valid
+ */
+ public boolean refresh() {
+ if (isValid) {
+ if (dir.lastModified() > dirMTime) {
+ // on-disk modification time is more recent
+ readDir();
+ }
+ touch();
+ }
+ return isValid;
+ }
+
+ /**
+ * Read directory metadata.
+ *
+ */
+ public void readMeta() {
+ // check for directory metadata...
+ File mf = new File(dir, "index.meta");
+ if (mf.canRead()) {
+ XMLMetaLoader ml = new XMLMetaLoader();
+ try {
+ // read directory meta file
+ Map fileMeta = ml.loadURL(mf.getAbsolutePath());
+ if (fileMeta == null) {
+ return;
+ }
+ // meta for the directory itself is in the "" bin
+ dirMeta = (Map) fileMeta.remove("");
+ // read meta for files in this directory
+ readFileMeta(fileMeta, null);
+ // is there meta for other files left?
+ if (fileMeta.size() > 0) {
+ unresolvedFileMeta = fileMeta;
+ }
+ } catch (SAXException e) {
+ logger.warn("error parsing index.meta", e);
+ } catch (IOException e) {
+ logger.warn("error reading index.meta", e);
+ }
+ }
+ readParentMeta();
+ metaChecked = true;
+ }
+
+ /**
+ * Read metadata from all known parent directories.
+ *
+ */
+ public void readParentMeta() {
+ // check the parent directories for additional file meta
+ Directory dd = parent;
+ String path = dir.getName();
+ while (dd != null) {
+ if (((DocuDirectory) dd).hasUnresolvedFileMeta()) {
+ readFileMeta(((DocuDirectory) dd).unresolvedFileMeta, path);
+ }
+ // prepend parent dir path
+ path = dd.dir.getName() + "/" + path;
+ // become next parent
+ dd = dd.parent;
+ }
+ }
+
+ /**
+ * Read metadata for the files in this directory.
+ *
+ * Takes a Map with meta-information, adding the relative path before the
+ * lookup.
+ *
+ * @param fileMeta
+ * @param relPath
+ * @param fc
+ * fileClass
+ */
+ protected void readFileMeta(Map fileMeta, String relPath) {
+ if (list == null) {
+ // there are no files
+ return;
+ }
+ String path = (relPath != null) ? (relPath + "/") : "";
+ // go through all file classes
+ for (int nc = 0; nc < list.length; nc++) {
+ int fc = cache.getFileClasses()[nc];
+ if (list[fc] == null) {
+ continue;
+ }
+ // iterate through the list of files in this directory
+ for (Iterator i = list[fc].iterator(); i.hasNext();) {
+ DocuDirent f = (DocuDirent) i.next();
+ // prepend path to the filename
+ String fn = path + f.getName();
+ // look up meta for this file and remove from dir
+ Map meta = (Map) fileMeta.remove(fn);
+ if (meta != null) {
+ // store meta in file
+ f.setFileMeta(meta);
+ }
+ }
+ }
+ }
+
+ protected void notifyChildMeta(Map childmeta) {
+ List children = cache.getChildren(this.dirName, true);
+ if (children.size() > 0) {
+ for (Iterator i = children.iterator(); i.hasNext();) {
+ // TODO: finish this!
+ //((DocuDirectory) i.next()).readFileMeta()
+ }
+ }
+ }
+
+ /**
+ * Update access time.
+ *
+ * @return long time of last access.
+ */
+ public long touch() {
+ long t = objectATime;
+ objectATime = System.currentTimeMillis();
+ return t;
+ }
+
+ /**
+ * Searches for the file with the name fn
.
+ *
+ * Searches the directory for the file with the name fn
and
+ * returns its index. Returns -1 if the file cannot be found.
+ *
+ * @param fn
+ * filename
+ * @param fc
+ * file class
+ * @return int index of file fn
+ */
+ public int indexOf(String fn) {
+ int fc = FileOps.classForFilename(fn);
+ return indexOf(fn, fc);
+ }
+
+ /**
+ * Searches for the file with the name fn
and class fc.
+ *
+ * Searches the directory for the file with the name fn
and
+ * returns its index. Returns -1 if the file cannot be found.
+ *
+ * @param fn
+ * filename
+ * @return int index of file fn
+ */
+ public int indexOf(String fn, int fc) {
+ if (!isRead()) {
+ // read directory now
+ if (!readDir()) {
+ return -1;
+ }
+ }
+ List fileList = list[fc];
+ // empty directory?
+ if (fileList == null) {
+ return -1;
+ }
+ // search for exact match
+ int idx = Collections.binarySearch(fileList, fn);
+ if (idx >= 0) {
+ return idx;
+ } else {
+ // try closest matches without extension
+ idx = -idx - 1;
+ String fb = FileOps.basename(fn);
+ DocuDirent fs;
+ if ((idx < fileList.size())
+ && (FileOps.basename(((DocuDirent) fileList.get(idx))
+ .getName()).equals(fb))) {
+ // idx matches
+ return idx;
+ } else if ((idx > 0)
+ && (FileOps.basename(((DocuDirent) fileList.get(idx - 1))
+ .getName()).equals(fb))) {
+ // idx-1 matches
+ return idx - 1;
+ } else if ((idx + 1 < fileList.size())
+ && (FileOps.basename(((DocuDirent) fileList.get(idx - 1))
+ .getName()).equals(fb))) {
+ // idx+1 matches
+ return idx + 1;
+ }
+
+ }
+ return -1;
+ }
+
+ /**
+ * Finds the DocuDirent with the name fn
.
+ *
+ * Searches the directory for the DocuDirent with the name fn
+ * and returns it. Returns null if the file cannot be found.
+ *
+ * @param fn
+ * filename
+ * @return DocuDirent
+ */
+ public DocuDirent find(String fn) {
+ int fc = FileOps.classForFilename(fn);
+ int i = indexOf(fn, fc);
+ if (i >= 0) {
+ return (DocuDirent) list[0].get(i);
+ }
+ return null;
+ }
+
+ /**
+ * Finds the DocuDirent with the name fn
and class
+ * fc
.
+ *
+ * Searches the directory for the DocuDirent with the name fn
+ * and returns it. Returns null if the file cannot be found.
+ *
+ * @param fn
+ * filename
+ * @return DocuDirent
+ */
+ public DocuDirent find(String fn, int fc) {
+ int i = indexOf(fn, fc);
+ if (i >= 0) {
+ return (DocuDirent) list[fc].get(i);
+ }
+ return null;
+ }
+
+ /**
+ * Returns the digilib canonical name.
+ *
+ * @return
+ */
+ public String getDirName() {
+ return dirName;
+ }
+
+ /**
+ * The directory is valid (exists on disk).
+ *
+ * @return boolean
+ */
+ public boolean isValid() {
+ return isValid;
+ }
+
+ /**
+ * The directory has been read from disk.
+ *
+ * @return
+ */
+ public boolean isRead() {
+ return (dirMTime != 0);
+ }
+
+ /**
+ * @return long
+ */
+ public long getAccessTime() {
+ return objectATime;
+ }
+
+ /**
+ * @return Hashtable
+ */
+ public Map getDirMeta() {
+ return dirMeta;
+ }
+
+ /**
+ * Checks metadata
+ *
+ */
+ public void checkMeta() {
+ if (metaChecked) {
+ return;
+ } else {
+ readMeta();
+ }
+ }
+
+ /**
+ * @return long
+ */
+ public long getDirMTime() {
+ return dirMTime;
+ }
+
+ /**
+ * Sets the dirMeta.
+ *
+ * @param dirMeta
+ * The dirMeta to set
+ */
+ public void setDirMeta(Map dirMeta) {
+ this.dirMeta = dirMeta;
+ }
+
+ public boolean hasUnresolvedFileMeta() {
+ return (this.unresolvedFileMeta != null);
+ }
+
+}
diff -r 9f7b864f955f -r 5d0c0da080ec servlet/src/digilib/io/ImageFile.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/servlet/src/digilib/io/ImageFile.java Thu Oct 21 20:53:37 2004 +0200
@@ -0,0 +1,136 @@
+/* ImageFile.java -- digilib image file class.
+
+ Digital Image Library servlet components
+
+ Copyright (C) 2003 Robert Casties (robcast@mail.berlios.de)
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ Please read license.txt for the full details. A copy of the GPL
+ may be found at http://www.gnu.org/copyleft/lgpl.html
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ * Created on 25.02.2003
+ */
+
+package digilib.io;
+
+import java.io.File;
+
+import digilib.image.ImageSize;
+
+/**
+ * @author casties
+ */
+public class ImageFile {
+
+ // file name
+ private String filename = null;
+ // parent ImageFileset
+ private ImageFileset parent = null;
+ // parent directory
+ private Directory dir = null;
+ // mime file type
+ private String mimetype = null;
+ // image size in pixels
+ private ImageSize pixelSize = null;
+
+ public ImageFile(String fn, ImageFileset parent, Directory dir) {
+ this.filename = fn;
+ this.parent = parent;
+ this.dir = dir;
+ }
+
+ public ImageFile(String fn) {
+ File f = new File(fn);
+ this.dir = new Directory(f.getParentFile());
+ this.filename = f.getName();
+ }
+
+ /** Returns the file name (without path).
+ *
+ * @return
+ */
+ public String getName() {
+ return filename;
+ }
+
+
+ /**
+ * @return File
+ */
+ public File getFile() {
+ if (dir == null) {
+ return null;
+ }
+ File f = new File(dir.getDir(), filename);
+ return f;
+ }
+
+ /**
+ * @return ImageSize
+ */
+ public ImageSize getSize() {
+ return pixelSize;
+ }
+
+ /**
+ * @return String
+ */
+ public String getMimetype() {
+ return mimetype;
+ }
+
+ /**
+ * Sets the imageSize.
+ * @param imageSize The imageSize to set
+ */
+ public void setSize(ImageSize imageSize) {
+ this.pixelSize = imageSize;
+ }
+
+ /**
+ * Sets the mimetype.
+ * @param mimetype The mimetype to set
+ */
+ public void setMimetype(String filetype) {
+ this.mimetype = filetype;
+ }
+
+ /**
+ * @return ImageFileset
+ */
+ public ImageFileset getParent() {
+ return parent;
+ }
+
+ /**
+ * Sets the parent.
+ * @param parent The parent to set
+ */
+ public void setParent(ImageFileset parent) {
+ this.parent = parent;
+ }
+
+ /**
+ * @return boolean
+ */
+ public boolean isChecked() {
+ return (pixelSize != null);
+ }
+
+ /** Returns the aspect ratio of the image (width/height).
+ *
+ * @return
+ */
+ public float getAspect() {
+ return (pixelSize != null) ? pixelSize.getAspect() : 0;
+ }
+
+}
diff -r 9f7b864f955f -r 5d0c0da080ec servlet/src/digilib/io/ImageFileset.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/servlet/src/digilib/io/ImageFileset.java Thu Oct 21 20:53:37 2004 +0200
@@ -0,0 +1,418 @@
+/* ImageFileset -- digilib image file info class.
+ * Digital Image Library servlet components
+ * Copyright (C) 2003 Robert Casties (robcast@mail.berlios.de)
+ *
+ * This program is free software; you can
+ * redistribute it and/or modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * Please read license.txt for the full details. A copy of the GPL may be
+ * found at http://www.gnu.org/copyleft/lgpl.html
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+package digilib.io;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.ListIterator;
+import java.util.Map;
+
+import org.apache.log4j.Logger;
+
+import digilib.image.ImageOps;
+import digilib.image.ImageSize;
+
+/**
+ * @author casties
+ */
+public class ImageFileset extends DocuDirent {
+
+ /** this is an image file */
+ protected static int fileClass = FileOps.CLASS_IMAGE;
+
+ /** logger for this class */
+ private static Logger logger = Logger.getLogger(ImageFileset.class);
+
+ /** list of files (ImageFile) */
+ private ArrayList list = null;
+
+ /** aspect ratio (width/height) */
+ private float aspect = 0;
+
+ /** resolution of the biggest image (DPI) */
+ private float resX = 0;
+
+ /** resolution of the biggest image (DPI) */
+ private float resY = 0;
+
+ /**
+ * Creator for empty fileset.
+ *
+ *
+ * @param initialCapacity
+ */
+ public ImageFileset() {
+ list = new ArrayList();
+ }
+
+ /**
+ * Constructor with a file and hints.
+ *
+ * The hints are expected to contain 'basedirs' and 'scaledfilext' keys.
+ *
+ * @param file
+ * @param hints
+ */
+ public ImageFileset(File file, Map hints) {
+ Directory[] dirs = (Directory[]) hints.get(FileOps.HINT_BASEDIRS);
+ int nb = dirs.length;
+ list = new ArrayList(nb);
+ parent = dirs[0];
+ fill(dirs, file, hints);
+ }
+
+ /**
+ * Adds an ImageFile to this Fileset.
+ *
+ * The files should be added in the order of higher to lower resolutions.
+ * The first file is considered the hires "original".
+ *
+ *
+ * @param f
+ * file to add
+ * @return true (always)
+ */
+ public boolean add(ImageFile f) {
+ f.setParent(this);
+ return list.add(f);
+ }
+
+ /**
+ * The number of image files in this Fileset.
+ *
+ *
+ * @return number of image files
+ */
+ public int size() {
+ return (list != null) ? list.size() : 0;
+ }
+
+ /**
+ * Gets the default File.
+ *
+ */
+ public File getFile() {
+ return (list != null) ? ((ImageFile) list.get(0)).getFile() : null;
+ }
+
+ /**
+ * Get the ImageFile at the index.
+ *
+ *
+ * @param index
+ * @return
+ */
+ public ImageFile get(int index) {
+ return (ImageFile) list.get(index);
+ }
+
+ /**
+ * Get the next smaller ImageFile than the given size.
+ *
+ * Returns the ImageFile from the set that has a width and height smaller or
+ * equal the given size. Returns null if there isn't any smaller image.
+ * Needs DocuInfo instance to checkFile().
+ *
+ *
+ * @param size
+ * @param info
+ * @return
+ */
+ public ImageFile getNextSmaller(ImageSize size) {
+ for (Iterator i = getHiresIterator(); i.hasNext();) {
+ ImageFile f = (ImageFile) i.next();
+ try {
+ if (!f.isChecked()) {
+ ImageOps.checkFile(f);
+ }
+ if (f.getSize().isTotallySmallerThan(size)) {
+ return f;
+ }
+ } catch (IOException e) {
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Get the next bigger ImageFile than the given size.
+ *
+ * Returns the ImageFile from the set that has a width or height bigger or
+ * equal the given size. Returns null if there isn't any bigger image. Needs
+ * DocuInfo instance to checkFile().
+ *
+ *
+ * @param size
+ * @param info
+ * @return
+ */
+ public ImageFile getNextBigger(ImageSize size) {
+ for (ListIterator i = getLoresIterator(); i.hasPrevious();) {
+ ImageFile f = (ImageFile) i.previous();
+ try {
+ if (!f.isChecked()) {
+ ImageOps.checkFile(f);
+ }
+ if (f.getSize().isBiggerThan(size)) {
+ return f;
+ }
+ } catch (IOException e) {
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns the biggest ImageFile in the set.
+ *
+ *
+ * @return
+ */
+ public ImageFile getBiggest() {
+ return this.get(0);
+ }
+
+ /**
+ * Returns the biggest ImageFile in the set.
+ *
+ *
+ * @return
+ */
+ public ImageFile getSmallest() {
+ return this.get(this.size() - 1);
+ }
+
+ /**
+ * Get an Iterator for this Fileset starting at the highest resolution
+ * images.
+ *
+ *
+ * @return
+ */
+ public ListIterator getHiresIterator() {
+ return list.listIterator();
+ }
+
+ /**
+ * Get an Iterator for this Fileset starting at the lowest resolution
+ * images.
+ *
+ * The Iterator starts at the last element, so you have to use it backwards
+ * with hasPrevious() and previous().
+ *
+ *
+ * @return
+ */
+ public ListIterator getLoresIterator() {
+ return list.listIterator(list.size());
+ }
+
+ /**
+ * Fill the ImageFileset with files from different base directories.
+ *
+ *
+ * @param dirs
+ * list of base directories
+ * @param fl
+ * file (from first base dir)
+ * @param hints
+ *
+ */
+ void fill(Directory[] dirs, File fl, Map hints) {
+ String scalext = (String) hints.get(FileOps.HINT_FILEEXT);
+ int nb = dirs.length;
+ String fn = fl.getName();
+ String baseFn = FileOps.basename(fn);
+ // add the first ImageFile to the ImageFileset
+ add(new ImageFile(fn, this, parent));
+ // iterate the remaining base directories
+ for (int dirIdx = 1; dirIdx < nb; dirIdx++) {
+ if (dirs[dirIdx] == null) {
+ continue;
+ }
+ // read the directory
+ if (dirs[dirIdx].getFilenames() == null) {
+ dirs[dirIdx].readDir();
+ }
+ String[] dirFiles = dirs[dirIdx].getFilenames();
+ // try the same filename as the original
+ int fileIdx = Arrays.binarySearch(dirFiles, fn);
+ if (fileIdx < 0) {
+ // try closest matches without extension
+ fileIdx = -fileIdx - 1;
+ // try idx
+ if ((fileIdx < dirFiles.length)
+ && (FileOps.basename(dirFiles[fileIdx]).equals(baseFn))) {
+ // idx ok
+ } else if ((fileIdx > 0)
+ && (FileOps.basename(dirFiles[fileIdx - 1])
+ .equals(baseFn))) {
+ // idx-1 ok
+ fileIdx = fileIdx - 1;
+ } else if ((fileIdx+1 < dirFiles.length)
+ && (FileOps.basename(dirFiles[fileIdx + 1])
+ .equals(baseFn))) {
+ // idx+1 ok
+ fileIdx = fileIdx + 1;
+ } else {
+ // basename doesn't match
+ continue;
+ }
+ }
+ if (FileOps.classForFilename(dirFiles[fileIdx]) == FileOps.CLASS_IMAGE) {
+ /* logger.debug("adding file " + dirFiles[fileIdx]
+ + " to Fileset " + this.getName()); */
+ add(new ImageFile(dirFiles[fileIdx], this, dirs[dirIdx]));
+ }
+ }
+ }
+
+ /**
+ * Checks metadata and sets resolution in resX and resY.
+ *
+ */
+ public void checkMeta() {
+ if (metaChecked) {
+ return;
+ }
+ if (fileMeta == null) {
+ // try to read metadata file
+ readMeta();
+ if (fileMeta == null) {
+ // try directory metadata
+ ((DocuDirectory) parent).checkMeta();
+ if (((DocuDirectory) parent).getDirMeta() != null) {
+ fileMeta = ((DocuDirectory) parent).getDirMeta();
+ } else {
+ // try parent directory metadata
+ DocuDirectory gp = (DocuDirectory) parent.getParent();
+ if (gp != null) {
+ gp.checkMeta();
+ if (gp.getDirMeta() != null) {
+ fileMeta = gp.getDirMeta();
+ } else {
+ // no metadata available
+ metaChecked = true;
+ return;
+ }
+ }
+ }
+ }
+ }
+ metaChecked = true;
+ String s;
+ float dpi = 0;
+ float dpix = 0;
+ float dpiy = 0;
+ float sizex = 0;
+ float sizey = 0;
+ float pixx = 0;
+ float pixy = 0;
+ // DPI is valid for X and Y
+ if (fileMeta.containsKey("original-dpi")) {
+ try {
+ dpi = Float.parseFloat((String) fileMeta.get("original-dpi"));
+ } catch (NumberFormatException e) {
+ }
+ if (dpi != 0) {
+ resX = dpi;
+ resY = dpi;
+ return;
+ }
+ }
+ // DPI-X and DPI-Y
+ if (fileMeta.containsKey("original-dpi-x")
+ && fileMeta.containsKey("original-dpi-y")) {
+ try {
+ dpix = Float.parseFloat((String) fileMeta
+ .get("original-dpi-x"));
+ dpiy = Float.parseFloat((String) fileMeta
+ .get("original-dpi-y"));
+ } catch (NumberFormatException e) {
+ }
+ if ((dpix != 0) && (dpiy != 0)) {
+ resX = dpix;
+ resY = dpiy;
+ return;
+ }
+ }
+ // SIZE-X and SIZE-Y and PIXEL-X and PIXEL-Y
+ if (fileMeta.containsKey("original-size-x")
+ && fileMeta.containsKey("original-size-y")
+ && fileMeta.containsKey("original-pixel-x")
+ && fileMeta.containsKey("original-pixel-y")) {
+ try {
+ sizex = Float.parseFloat((String) fileMeta
+ .get("original-size-x"));
+ sizey = Float.parseFloat((String) fileMeta
+ .get("original-size-y"));
+ pixx = Float.parseFloat((String) fileMeta
+ .get("original-pixel-x"));
+ pixy = Float.parseFloat((String) fileMeta
+ .get("original-pixel-y"));
+ } catch (NumberFormatException e) {
+ }
+ if ((sizex != 0) && (sizey != 0) && (pixx != 0) && (pixy != 0)) {
+ resX = pixx / (sizex * 100 / 2.54f);
+ resY = pixy / (sizey * 100 / 2.54f);
+ return;
+ }
+ }
+ }
+
+ /**
+ * @return
+ */
+ public float getResX() {
+ return resX;
+ }
+
+ /**
+ * @return
+ */
+ public float getResY() {
+ return resY;
+ }
+
+ /**
+ * Sets the aspect ratio from an ImageSize.
+ *
+ *
+ * @param f
+ */
+ public void setAspect(ImageSize s) {
+ aspect = s.getAspect();
+ }
+
+ /**
+ * Returns the aspect ratio.
+ *
+ * Aspect ratio is (width/height). So it's <1 for portrait and >1 for
+ * landscape.
+ *
+ *
+ * @return
+ */
+ public float getAspect() {
+ return aspect;
+ }
+
+}
\ No newline at end of file
diff -r 9f7b864f955f -r 5d0c0da080ec servlet/src/digilib/servlet/DigilibConfiguration.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/servlet/src/digilib/servlet/DigilibConfiguration.java Thu Oct 21 20:53:37 2004 +0200
@@ -0,0 +1,267 @@
+/*
+ * DigilibConfiguration -- Holding all parameters for digilib servlet.
+ *
+ * Digital Image Library servlet components
+ *
+ * Copyright (C) 2001, 2002 Robert Casties (robcast@mail.berlios.de)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * Please read license.txt for the full details. A copy of the GPL may be found
+ * at http://www.gnu.org/copyleft/lgpl.html
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+package digilib.servlet;
+
+import java.io.File;
+import java.util.Iterator;
+import java.util.Map;
+
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
+
+import org.apache.log4j.BasicConfigurator;
+import org.apache.log4j.Logger;
+
+import digilib.image.DocuImage;
+import digilib.image.DocuImageImpl;
+import digilib.io.FileOps;
+import digilib.io.XMLListLoader;
+
+/**
+ * Class to hold the digilib servlet configuration parameters. The parameters
+ * can be read from the digilib-config file and be passed to other servlets or
+ * beans.
errorImgFileName: image file to send in case of error.
+ * denyImgFileName: image file to send if access is denied.
baseDirs:
+ * array of base directories in order of preference (prescaled versions first).
+ *
useAuth: use authentication information.
authConfPath:
+ * authentication configuration file.
...
+ *
+ * @author casties
+ *
+ */
+public class DigilibConfiguration extends ParameterMap {
+
+ private static final long serialVersionUID = -6630487070791637120L;
+
+ /** DocuImage class instance */
+ private Class docuImageClass = null;
+
+ /** Log4J logger */
+ private Logger logger = Logger.getLogger("digilib.config");
+
+ /**
+ * Default constructor defines all parameters and their default values.
+ *
+ */
+ public DigilibConfiguration() {
+ // create HashMap(20)
+ super(20);
+ // we start with a default logger config
+ BasicConfigurator.configure();
+
+ /*
+ * Definition of parameters and default values. System parameters that
+ * are not read from config file have a type 's'.
+ */
+
+ // digilib servlet version
+ newParameter(
+ "servlet.version",
+ digilib.servlet.Scaler.dlVersion,
+ null,
+ 's');
+ // configuration file location
+ newParameter("servlet.config.file", null, null, 's');
+ // DocuDirCache instance
+ newParameter("servlet.dir.cache", null, null, 's');
+ // DocuImage class instance
+ newParameter(
+ "servlet.docuimage.class",
+ digilib.image.JAIDocuImage.class,
+ null,
+ 's');
+ // AuthOps instance for authentication
+ newParameter("servlet.auth.op", null, null, 's');
+ // worker queues
+ newParameter("servlet.fast.queue", null, null, 's');
+ newParameter("servlet.slow.queue", null, null, 's');
+
+ /*
+ * parameters that can be read from config file have a type 'f'
+ */
+
+ // image file to send in case of error
+ newParameter(
+ "error-image",
+ new File("/docuserver/images/icons/scalerror.gif"),
+ null,
+ 'f');
+ // image file to send if access is denied
+ newParameter(
+ "denied-image",
+ new File("/docuserver/images/icons/denied.gif"),
+ null,
+ 'f');
+ // base directories in order of preference (prescaled versions last)
+ String[] bd = { "/docuserver/images", "/docuserver/scaled/small" };
+ newParameter("basedir-list", bd, null, 'f');
+ // use authentication information
+ newParameter("use-authorization", Boolean.FALSE, null, 'f');
+ // authentication configuration file
+ newParameter("auth-file", new File("digilib-auth.xml"), null, 'f');
+ // sending image files as-is allowed
+ newParameter("sendfile-allowed", Boolean.TRUE, null, 'f');
+ // Debug level
+ newParameter("debug-level", new Integer(5), null, 'f');
+ // Type of DocuImage instance
+ newParameter(
+ "docuimage-class",
+ "digilib.image.JAIDocuImage",
+ null,
+ 'f');
+ // part of URL used to indicate authorized access
+ newParameter("auth-url-path", "authenticated/", null, 'f');
+ // degree of subsampling on image load
+ newParameter("subsample-minimum", new Float(2f), null, 'f');
+ // default scaling quality
+ newParameter("default-quality", new Integer(1), null, 'f');
+ // use mapping file to translate paths
+ newParameter("use-mapping", Boolean.FALSE, null, 'f');
+ // mapping file location
+ newParameter("mapping-file", new File("digilib-map.xml"), null, 'f');
+ // log4j config file location
+ newParameter("log-config-file", new File("log4j-config.xml"), null, 'f');
+ // maximum destination image size (0 means no limit)
+ newParameter("max-image-size", new Integer(0), null, 'f');
+ // use safe (but slower) directory indexing
+ newParameter("safe-dir-index", Boolean.FALSE, null, 'f');
+ // number of fast worker threads
+ newParameter("worker-fast-lanes", new Integer(2), null, 'f');
+ // length of fast worker queue
+ newParameter("worker-fast-queue", new Integer(100), null, 'f');
+ // number of slow worker threads
+ newParameter("worker-slow-lanes", new Integer(2), null, 'f');
+ // length of slow worker queue
+ newParameter("worker-slow-queue", new Integer(100), null, 'f');
+
+ }
+
+ /**
+ * Constructor taking a ServletConfig. Reads the config file location from
+ * an init parameter and loads the config file. Calls readConfig()
.
+ *
+ * @see readConfig()
+ */
+ public DigilibConfiguration(ServletConfig c) throws Exception {
+ this();
+ readConfig(c);
+ }
+
+ /**
+ * read parameter list from the XML file in init parameter "config-file"
+ */
+ public void readConfig(ServletConfig c) throws Exception {
+
+ /*
+ * Get config file name. The file name is first looked for as an init
+ * parameter, then in a fixed location in the webapp.
+ */
+ if (c == null) {
+ // no config no file...
+ return;
+ }
+ String fn = c.getInitParameter("config-file");
+ if (fn == null) {
+ fn = ServletOps.getConfigFile("digilib-config.xml", c);
+ if (fn == null) {
+ logger.fatal("readConfig: no param config-file");
+ throw new ServletException("ERROR: no digilib config file!");
+ }
+ }
+ File f = new File(fn);
+ // setup config file list reader
+ XMLListLoader lilo =
+ new XMLListLoader("digilib-config", "parameter", "name", "value");
+ // read config file into HashMap
+ Map confTable = lilo.loadURL(f.toURL().toString());
+
+ // set config file path parameter
+ setValue("servlet.config.file", f.getCanonicalPath());
+
+ /*
+ * read parameters
+ */
+
+ for (Iterator i = confTable.keySet().iterator(); i.hasNext();) {
+ String key = (String) i.next();
+ String val = (String) confTable.get(key);
+ Parameter p = get(key);
+ if (p != null) {
+ if (p.getType() == 's') {
+ // type 's' Parameters are not overwritten.
+ continue;
+ }
+ if (!p.setValueFromString(val)) {
+ /*
+ * automatic conversion failed -- try special cases
+ */
+
+ // basedir-list
+ if (key.equals("basedir-list")) {
+ // split list into directories
+ String[] sa = FileOps.pathToArray(val);
+ if (sa != null) {
+ p.setValue(sa);
+ }
+ }
+
+ }
+ } else {
+ // parameter unknown -- just add
+ newParameter(key, null, val, 'f');
+ }
+ }
+
+ }
+
+ /**
+ * Creates a new DocuImage instance.
+ *
+ * The type of DocuImage is specified by docuImageType.
+ *
+ * @return DocuImage
+ */
+ public DocuImage getDocuImageInstance() {
+ DocuImageImpl di = null;
+ try {
+ if (docuImageClass == null) {
+ docuImageClass = Class.forName(getAsString("docuimage-class"));
+ }
+ di = (DocuImageImpl) docuImageClass.newInstance();
+ } catch (Exception e) {
+ }
+ return di;
+ }
+
+ /**
+ * @return Returns the docuImageClass.
+ */
+ public Class getDocuImageClass() {
+ return docuImageClass;
+ }
+ /**
+ * @param docuImageClass The docuImageClass to set.
+ */
+ public void setDocuImageClass(Class docuImageClass) {
+ this.docuImageClass = docuImageClass;
+ }
+}
diff -r 9f7b864f955f -r 5d0c0da080ec servlet/src/digilib/servlet/DigilibImageWorker.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/servlet/src/digilib/servlet/DigilibImageWorker.java Thu Oct 21 20:53:37 2004 +0200
@@ -0,0 +1,263 @@
+/* DigilibImageWorker.java -- worker for image operations
+ *
+ * Digital Image Library servlet components
+ *
+ * Copyright (C) 2004 Robert Casties (robcast@mail.berlios.de)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * Please read license.txt for the full details. A copy of the GPL may be found
+ * at http://www.gnu.org/copyleft/lgpl.html
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Created on 19.10.2004
+ */
+
+package digilib.servlet;
+
+import java.awt.geom.Rectangle2D;
+import java.io.IOException;
+
+import javax.servlet.http.HttpServletResponse;
+
+import digilib.image.DocuImage;
+import digilib.image.ImageOpException;
+import digilib.io.FileOpException;
+import digilib.io.ImageFile;
+
+/**
+ * worker for image operations.
+ *
+ * @author casties
+ *
+ */
+public class DigilibImageWorker extends DigilibWorker {
+
+ private DigilibConfiguration dlConfig;
+
+ HttpServletResponse response;
+
+ long startTime;
+
+ String mimeType;
+
+ int scaleQual;
+
+ DigilibRequest dlRequest;
+
+ float paramROT;
+
+ float paramCONT;
+
+ float paramBRGT;
+
+ float[] paramRGBM;
+
+ float[] paramRGBA;
+
+ ImageFile fileToLoad;
+
+ float areaXoff;
+
+ float areaYoff;
+
+ float areaWidth;
+
+ float areaHeight;
+
+ float scaleXY;
+
+ Rectangle2D outerUserImgArea;
+
+ Rectangle2D innerUserImgArea;
+
+ float minSubsample;
+
+ boolean wholeRotArea;
+
+ /**
+ * @param dlConfig
+ * @param response
+ * @param mimeType
+ * @param scaleQual
+ * @param dlRequest
+ * @param paramROT
+ * @param paramCONT
+ * @param paramBRGT
+ * @param paramRGBM
+ * @param paramRGBA
+ * @param fileToLoad
+ * @param areaXoff
+ * @param outerUserImgArea
+ * @param innerUserImgArea
+ * @param minSubsample
+ * @param wholeRotArea
+ */
+ public DigilibImageWorker(DigilibConfiguration dlConfig,
+ HttpServletResponse response, String mimeType, int scaleQual,
+ DigilibRequest dlRequest, float paramROT, float paramCONT,
+ float paramBRGT, float[] paramRGBM, float[] paramRGBA,
+ ImageFile fileToLoad, float scaleXY, Rectangle2D outerUserImgArea,
+ Rectangle2D innerUserImgArea, float minSubsample,
+ boolean wholeRotArea) {
+ super();
+ this.dlConfig = dlConfig;
+ this.response = response;
+ this.mimeType = mimeType;
+ this.scaleQual = scaleQual;
+ this.dlRequest = dlRequest;
+ this.paramROT = paramROT;
+ this.paramCONT = paramCONT;
+ this.paramBRGT = paramBRGT;
+ this.paramRGBM = paramRGBM;
+ this.paramRGBA = paramRGBA;
+ this.fileToLoad = fileToLoad;
+ this.scaleXY = scaleXY;
+ this.outerUserImgArea = outerUserImgArea;
+ this.innerUserImgArea = innerUserImgArea;
+ this.minSubsample = minSubsample;
+ this.wholeRotArea = wholeRotArea;
+ }
+
+ /*
+ * do the work
+ */
+ public void work() throws FileOpException, IOException, ImageOpException {
+ ;
+ logger.debug("image worker " + this.getName() + " working");
+ startTime = System.currentTimeMillis();
+
+ /* crop and scale image */
+
+ // new DocuImage instance
+ DocuImage docuImage = dlConfig.getDocuImageInstance();
+ if (docuImage == null) {
+ throw new ImageOpException("Unable to load DocuImage class!");
+ }
+
+ // set interpolation quality
+ docuImage.setQuality(scaleQual);
+
+ // use subimage loading if possible
+ if (docuImage.isSubimageSupported()) {
+ logger.debug("Subimage: scale " + scaleXY + " = " + (1 / scaleXY));
+ float subf = 1f;
+ float subsamp = 1f;
+ if (scaleXY < 1) {
+ subf = 1 / scaleXY;
+ // for higher quality reduce subsample factor by
+ // minSubsample
+ if (scaleQual > 0) {
+ subsamp = (float) Math.max(Math.floor(subf / minSubsample),
+ 1d);
+ } else {
+ subsamp = (float) Math.floor(subf);
+ }
+ scaleXY = subsamp / subf;
+ logger.debug("Using subsampling: " + subsamp + " rest "
+ + scaleXY);
+ }
+
+ docuImage.loadSubimage(fileToLoad, outerUserImgArea.getBounds(),
+ (int) subsamp);
+
+ logger.debug("SUBSAMP: " + subsamp + " -> " + docuImage.getWidth()
+ + "x" + docuImage.getHeight());
+
+ docuImage.scale(scaleXY, scaleXY);
+
+ } else {
+ // else load and crop the whole file
+ docuImage.loadImage(fileToLoad);
+ docuImage.crop((int) areaXoff, (int) areaYoff, (int) areaWidth,
+ (int) areaHeight);
+
+ docuImage.scale(scaleXY, scaleXY);
+ }
+
+ // mirror image
+ // operation mode: "hmir": mirror horizontally, "vmir": mirror
+ // vertically
+ if (dlRequest.hasOption("mo", "hmir")) {
+ docuImage.mirror(0);
+ }
+ if (dlRequest.hasOption("mo", "vmir")) {
+ docuImage.mirror(90);
+ }
+
+ // rotate image
+ if (paramROT != 0d) {
+ docuImage.rotate(paramROT);
+ if (wholeRotArea) {
+ // crop to the inner bounding box
+ float xcrop = (float) (docuImage.getWidth() - innerUserImgArea
+ .getWidth()
+ * scaleXY);
+ float ycrop = (float) (docuImage.getHeight() - innerUserImgArea
+ .getHeight()
+ * scaleXY);
+ if ((xcrop > 0) || (ycrop > 0)) {
+ // only crop smaller
+ xcrop = (xcrop > 0) ? xcrop : 0;
+ ycrop = (ycrop > 0) ? ycrop : 0;
+ // crop image
+ docuImage.crop((int) (xcrop / 2), (int) (ycrop / 2),
+ (int) (docuImage.getWidth() - xcrop),
+ (int) (docuImage.getHeight() - ycrop));
+ }
+ }
+
+ }
+
+ // color modification
+ if ((paramRGBM != null) || (paramRGBA != null)) {
+ // make shure we actually have two arrays
+ if (paramRGBM == null) {
+ paramRGBM = new float[3];
+ }
+ if (paramRGBA == null) {
+ paramRGBA = new float[3];
+ }
+ // calculate "contrast" values (c=2^x)
+ float[] mult = new float[3];
+ for (int i = 0; i < 3; i++) {
+ mult[i] = (float) Math.pow(2, (float) paramRGBM[i]);
+ }
+ docuImage.enhanceRGB(mult, paramRGBA);
+ }
+
+ // contrast and brightness enhancement
+ if ((paramCONT != 0f) || (paramBRGT != 0f)) {
+ float mult = (float) Math.pow(2, paramCONT);
+ docuImage.enhance(mult, paramBRGT);
+ }
+
+ logger.debug("time " + (System.currentTimeMillis() - startTime) + "ms");
+
+ /* write the resulting image */
+
+ // setup output -- if source is JPG then dest will be JPG else it's
+ // PNG
+ if (mimeType.equals("image/jpeg") || mimeType.equals("image/jp2")) {
+ mimeType = "image/jpeg";
+ } else {
+ mimeType = "image/png";
+ }
+ response.setContentType(mimeType);
+
+ // write the image
+ docuImage.writeImage(mimeType, response.getOutputStream());
+ response.flushBuffer();
+
+ logger.info("image worker " + this.getName() + " done in "
+ + (System.currentTimeMillis() - startTime));
+
+ docuImage.dispose();
+ }
+}
diff -r 9f7b864f955f -r 5d0c0da080ec servlet/src/digilib/servlet/DigilibJob.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/servlet/src/digilib/servlet/DigilibJob.java Thu Oct 21 20:53:37 2004 +0200
@@ -0,0 +1,75 @@
+/* DigilibJob.java -- digilib job for worker
+ *
+ * Digital Image Library servlet components
+ *
+ * Copyright (C) 2004 Robert Casties (robcast@mail.berlios.de)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * Please read license.txt for the full details. A copy of the GPL may be found
+ * at http://www.gnu.org/copyleft/lgpl.html
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Created on 18.10.2004
+ */
+package digilib.servlet;
+
+import digilib.image.DocuImage;
+
+/** digilib job for worker.
+ *
+ * @author casties
+ *
+ */
+public class DigilibJob {
+
+ private DigilibConfiguration config;
+
+ private DigilibRequest request;
+
+ private DocuImage image;
+
+
+ /**
+ * @return Returns the config.
+ */
+ public DigilibConfiguration getConfig() {
+ return config;
+ }
+ /**
+ * @param config The config to set.
+ */
+ public void setConfig(DigilibConfiguration config) {
+ this.config = config;
+ }
+ /**
+ * @return Returns the image.
+ */
+ public DocuImage getImage() {
+ return image;
+ }
+ /**
+ * @param image The image to set.
+ */
+ public void setImage(DocuImage image) {
+ this.image = image;
+ }
+ /**
+ * @return Returns the request.
+ */
+ public DigilibRequest getRequest() {
+ return request;
+ }
+ /**
+ * @param request The request to set.
+ */
+ public void setRequest(DigilibRequest request) {
+ this.request = request;
+ }
+}
diff -r 9f7b864f955f -r 5d0c0da080ec servlet/src/digilib/servlet/DigilibManager.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/servlet/src/digilib/servlet/DigilibManager.java Thu Oct 21 20:53:37 2004 +0200
@@ -0,0 +1,62 @@
+/* DigilibManager.java -- work queue manager
+ *
+ * Digital Image Library servlet components
+ *
+ * Copyright (C) 2004 Robert Casties (robcast@mail.berlios.de)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * Please read license.txt for the full details. A copy of the GPL may be found
+ * at http://www.gnu.org/copyleft/lgpl.html
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Created on 18.10.2004
+ */
+
+package digilib.servlet;
+
+import EDU.oswego.cs.dl.util.concurrent.BoundedBuffer;
+import EDU.oswego.cs.dl.util.concurrent.Executor;
+import EDU.oswego.cs.dl.util.concurrent.PooledExecutor;
+
+/** work queue manager.
+ *
+ * @author casties
+ *
+ */
+public class DigilibManager implements Executor {
+
+ private PooledExecutor workerQueue = null;
+
+ private BoundedBuffer jobQueue = null;
+
+ /**
+ * @param numFastLanes
+ * @param numSlowLanes
+ */
+ public DigilibManager(int numLanes, int queueMax) {
+ super();
+
+ // create job queue
+ jobQueue = new BoundedBuffer(queueMax);
+ // create work queue
+ workerQueue = new PooledExecutor(jobQueue, numLanes);
+ workerQueue.abortWhenBlocked();
+
+ }
+
+
+ public void execute(Runnable worker) throws InterruptedException {
+ workerQueue.execute(worker);
+ }
+
+ public int getQueueSize() {
+ return jobQueue.size();
+ }
+}
diff -r 9f7b864f955f -r 5d0c0da080ec servlet/src/digilib/servlet/DigilibSender.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/servlet/src/digilib/servlet/DigilibSender.java Thu Oct 21 20:53:37 2004 +0200
@@ -0,0 +1,73 @@
+/* DigilibSender.java -- image file send worker
+ *
+ * Digital Image Library servlet components
+ *
+ * Copyright (C) 2004 Robert Casties (robcast@mail.berlios.de)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * Please read license.txt for the full details. A copy of the GPL may be found
+ * at http://www.gnu.org/copyleft/lgpl.html
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Created on 18.10.2004
+ */
+package digilib.servlet;
+
+import java.io.File;
+
+import javax.servlet.http.HttpServletResponse;
+
+import digilib.io.FileOpException;
+
+/**
+ * image file send worker.
+ *
+ * @author casties
+ *
+ */
+public class DigilibSender extends DigilibWorker {
+
+ private File file;
+
+ private String mimetype;
+
+ private HttpServletResponse response;
+
+ /**
+ * @param file
+ * @param mimetype
+ * @param response
+ */
+ public DigilibSender(File file, String mimetype,
+ HttpServletResponse response) {
+ super();
+ this.file = file;
+ this.mimetype = mimetype;
+ this.response = response;
+ }
+
+ /**
+ * Actually send the file.
+ *
+ */
+ public void work() {
+ logger.debug("worker " + this.getName() + " sending file:"
+ + file.getName());
+ try {
+ //sleep(2000);
+ ServletOps.sendFileImmediately(file, mimetype, response);
+ } catch (FileOpException e) {
+ logger.error("Unable to send file " + file.getPath() + " because "
+ + e);
+ }
+ logger.debug("worker "+this.getName()+" done");
+ }
+
+}
diff -r 9f7b864f955f -r 5d0c0da080ec servlet/src/digilib/servlet/DigilibWorker.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/servlet/src/digilib/servlet/DigilibWorker.java Thu Oct 21 20:53:37 2004 +0200
@@ -0,0 +1,107 @@
+/* DigilibWorker.java -- image operation worker
+ *
+ * Digital Image Library servlet components
+ *
+ * Copyright (C) 2004 Robert Casties (robcast@mail.berlios.de)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * Please read license.txt for the full details. A copy of the GPL may be found
+ * at http://www.gnu.org/copyleft/lgpl.html
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Created on 18.10.2004
+ */
+package digilib.servlet;
+
+import org.apache.log4j.Logger;
+
+import EDU.oswego.cs.dl.util.concurrent.FIFOSemaphore;
+import EDU.oswego.cs.dl.util.concurrent.Semaphore;
+
+
+
+/** image operation worker.
+ *
+ * @author casties
+ *
+ */
+public abstract class DigilibWorker extends Thread {
+
+ protected static Logger logger = Logger.getLogger(DigilibWorker.class);
+
+ private static int runningThreads = 0;
+
+ public static Semaphore lock = new FIFOSemaphore(4);
+
+ protected boolean busy = false;
+
+ protected Exception error;
+
+ /**
+ * @param job
+ */
+ public DigilibWorker() {
+ super();
+ busy = true;
+ error = null;
+ }
+
+
+ public abstract void work() throws Exception;
+
+ /** Actually do the work.
+ *
+ * @see java.lang.Runnable#run()
+ */
+ public void run() {
+ try {
+ lock.acquire();
+ logger.debug((++runningThreads)+" running threads");
+ try {
+ work();
+ } catch (Exception e) {
+ error = e;
+ logger.error(e);
+ }
+ synchronized (this) {
+ busy = false;
+ this.notify();
+ }
+ runningThreads--;
+ lock.release();
+ } catch (InterruptedException e1) {
+ // TODO Auto-generated catch block
+ e1.printStackTrace();
+ }
+ }
+
+ /**
+ * @return Returns the busy.
+ */
+ public boolean isBusy() {
+ return busy;
+ }
+
+ /** returns if an error occurred.
+ *
+ * @return
+ */
+ public boolean hasError() {
+ return (error != null);
+ }
+
+ /**
+ * @return Returns the error.
+ */
+ public Exception getError() {
+ return error;
+ }
+
+}
diff -r 9f7b864f955f -r 5d0c0da080ec servlet/src/digilib/servlet/DocumentBean.java
--- a/servlet/src/digilib/servlet/DocumentBean.java Mon Oct 18 15:40:54 2004 +0200
+++ b/servlet/src/digilib/servlet/DocumentBean.java Thu Oct 21 20:53:37 2004 +0200
@@ -1,198 +1,295 @@
-/* DocumentBean -- Access control bean for JSP
-
- Digital Image Library servlet components
-
- Copyright (C) 2001, 2002 Robert Casties (robcast@mail.berlios.de)
-
- This program is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published by the
- Free Software Foundation; either version 2 of the License, or (at your
- option) any later version.
-
- Please read license.txt for the full details. A copy of the GPL
- may be found at http://www.gnu.org/copyleft/lgpl.html
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-
-*/
+/*
+ * DocumentBean -- Access control bean for JSP
+ *
+ * Digital Image Library servlet components
+ *
+ * Copyright (C) 2001, 2002, 2003 Robert Casties (robcast@mail.berlios.de)
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * Please read license.txt for the full details. A copy of the GPL may be found
+ * at http://www.gnu.org/copyleft/lgpl.html
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
package digilib.servlet;
+import java.util.List;
-import java.util.*;
-import javax.servlet.*;
-import javax.servlet.http.*;
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.log4j.Logger;
-import digilib.*;
-import digilib.io.*;
-import digilib.auth.*;
+import digilib.auth.AuthOpException;
+import digilib.auth.AuthOps;
+import digilib.io.DocuDirCache;
+import digilib.io.DocuDirectory;
+import digilib.io.FileOps;
+import digilib.io.ImageFileset;
-public class DocumentBean implements AuthOps {
+public class DocumentBean {
+
+ // general logger
+ private static Logger logger = Logger.getLogger("digilib.docubean");
+
+ // AuthOps object to check authorization
+ private AuthOps authOp;
- // Utils object for logging
- private Utils util = new Utils(5);
- // AuthOps object to check authorization
- private AuthOps authOp;
- // FileOps object
- private FileOps fileOp = new FileOps(util);
+ // use authorization database
+ private boolean useAuthentication = true;
+
+ // path to add for authenticated access
+ private String authURLPath = "";
+
+ // DocuDirCache
+ private DocuDirCache dirCache = null;
+
+ // DigilibConfiguration object
+ private DigilibConfiguration dlConfig;
+
+ // DigilibRequest object
+ private DigilibRequest dlRequest = null;
- // base directories in order of preference (prescaled versions first)
- private String[] baseDirs = {"/docuserver/scaled/small", "/docuserver/images", "/docuserver/scans/quellen"};
- // part of URL path to prepend for authenticated access
- private String authURLpath = "authenticated/";
+ /**
+ * Constructor for DocumentBean.
+ */
+ public DocumentBean() {
+ super();
+ }
-
- public DocumentBean() {
- }
+ public DocumentBean(ServletConfig conf) {
+ try {
+ setConfig(conf);
+ } catch (Exception e) {
+ logger.fatal("ERROR: Unable to read config: ", e);
+ }
+ }
- public void setConfig(ServletConfig conf) throws ServletException {
- util.dprintln(10, "setConfig");
- // servletOps takes a ServletConfig to get the config file name
- ServletOps servletOp = new ServletOps(util, conf);
- /**
- * basedir-list : List of document directories
- */
- String bl = servletOp.tryToGetInitParam("basedir-list", null);
- if ((bl != null)&&(bl.length() > 0)) {
- // split list into directories
- StringTokenizer dirs = new StringTokenizer(bl, ":");
- int n = dirs.countTokens();
- if (n > 0) {
- // add directories into array
- baseDirs = new String[n];
- for (int i = 0; i < n; i++) {
- baseDirs[i] = dirs.nextToken();
- }
- }
- util.dprintln(3, "basedir-list: "+bl);
- }
- /**
- * auth-url-path : part of URL to indicate authenticated access
- */
- String au = servletOp.tryToGetInitParam("auth-url-path", null);
- if ((au != null)&&(au.length() > 0)) {
- authURLpath = au;
- util.dprintln(3, "auth-url-path: "+au);
- }
- /**
- * authentication
- */
- try {
- // DB version
- //private AuthOps authOp = new DBAuthOpsImpl(util);
- // XML version
- String cp = servletOp.tryToGetInitParam("auth-file", "/docuserver/www/digitallibrary/WEB-INF/digilib-auth.xml");
- util.dprintln(3, "auth-file: "+cp);
- authOp = new XMLAuthOps(util, cp);
- } catch (AuthOpException e) {
- throw new ServletException(e);
- }
- }
+ public void setConfig(ServletConfig conf) throws ServletException {
+ logger.debug("setConfig");
+ // get our ServletContext
+ ServletContext context = conf.getServletContext();
+ // see if there is a Configuration instance
+ dlConfig = (DigilibConfiguration) context
+ .getAttribute("digilib.servlet.configuration");
+ if (dlConfig == null) {
+ // create new Configuration
+ throw new ServletException("ERROR: No configuration!");
+ }
+
+ // get cache
+ dirCache = (DocuDirCache) dlConfig.getValue("servlet.dir.cache");
+
+ /*
+ * authentication
+ */
+ useAuthentication = dlConfig.getAsBoolean("use-authorization");
+ authOp = (AuthOps) dlConfig.getValue("servlet.auth.op");
+ authURLPath = dlConfig.getAsString("auth-url-path");
+ if (useAuthentication && (authOp == null)) {
+ throw new ServletException(
+ "ERROR: use-authorization configured but no AuthOp!");
+ }
+ }
+
+ /**
+ * check if the request must be authorized to access filepath
+ */
+ public boolean isAuthRequired(DigilibRequest request)
+ throws AuthOpException {
+ logger.debug("isAuthRequired");
+ return useAuthentication ? authOp.isAuthRequired(request) : false;
+ }
+
+ /**
+ * check if the request is allowed to access filepath
+ */
+ public boolean isAuthorized(DigilibRequest request) throws AuthOpException {
+ logger.debug("isAuthorized");
+ return useAuthentication ? authOp.isAuthorized(request) : true;
+ }
+
+ /**
+ * return a list of authorization roles needed for request to access the
+ * specified path
+ */
+ public List rolesForPath(DigilibRequest request) throws AuthOpException {
+ logger.debug("rolesForPath");
+ return useAuthentication ? authOp.rolesForPath(request) : null;
+ }
+
+ /**
+ * check request authorization against a list of roles
+ */
+ public boolean isRoleAuthorized(List roles, DigilibRequest request) {
+ logger.debug("isRoleAuthorized");
+ return useAuthentication ? authOp.isRoleAuthorized(roles, request)
+ : true;
+ }
+
+ /**
+ * check for authenticated access and redirect if necessary
+ */
+ public boolean doAuthentication(HttpServletResponse response)
+ throws Exception {
+ return doAuthentication(dlRequest, response);
+ }
- public String getDocuPath(HttpServletRequest request) {
- util.dprintln(10, "getDocuPath");
- // fetch query string
- String qs = request.getQueryString();
- String fn = "";
- if (qs != null && qs.length() > 0) {
- // the file name is in the request before the first "+"
- int endfn = qs.indexOf("+");
- if (endfn > 0) {
- fn = qs.substring(0, endfn);
- } else {
- fn = qs;
- }
- }
- util.dprintln(4, "docuPath: "+fn);
- return fn;
- }
-
- /**
- * check if the request must be authorized to access filepath
- */
- public boolean isAuthRequired(HttpServletRequest request) throws AuthOpException {
- util.dprintln(10, "isAuthRequired");
- return authOp.isAuthRequired(getDocuPath(request), request);
- }
+ /**
+ * check for authenticated access and redirect if necessary
+ */
+ public boolean doAuthentication(DigilibRequest request,
+ HttpServletResponse response) throws Exception {
+ logger.debug("doAuthentication");
+ if (!useAuthentication) {
+ // shortcut if no authentication
+ return true;
+ }
+ // check if we are already authenticated
+ if (((HttpServletRequest) request.getServletRequest()).getRemoteUser() == null) {
+ logger.debug("unauthenticated so far");
+ // if not maybe we must?
+ if (isAuthRequired(request)) {
+ logger.debug("auth required, redirect");
+ // we are not yet authenticated -> redirect
+ response.sendRedirect(authURLPath
+ + ((HttpServletRequest) request.getServletRequest())
+ .getServletPath()
+ + "?"
+ + ((HttpServletRequest) request.getServletRequest())
+ .getQueryString());
+ }
+ }
+ return true;
+ }
- public boolean isAuthRequired(String filepath, HttpServletRequest request) throws AuthOpException {
- util.dprintln(10, "isAuthRequired");
- return authOp.isAuthRequired(filepath, request);
- }
-
- /**
- * check if the request is allowed to access filepath
- */
- public boolean isAuthorized(HttpServletRequest request) throws AuthOpException {
- util.dprintln(10, "isAuthorized");
- return authOp.isAuthorized(getDocuPath(request), request);
- }
+ /**
+ * Sets the current DigilibRequest. Also completes information in the request.
+ *
+ * @param dlRequest
+ * The dlRequest to set.
+ */
+ public void setRequest(DigilibRequest dlRequest) throws Exception {
+ this.dlRequest = dlRequest;
+ if (dirCache == null) {
+ return;
+ }
+ String fn = dlRequest.getFilePath();
+ // get information about the file
+ ImageFileset fileset = (ImageFileset) dirCache.getFile(fn, dlRequest
+ .getAsInt("pn"), FileOps.CLASS_IMAGE);
+ if (fileset == null) {
+ return;
+ }
+ // add file name
+ dlRequest.setValue("img.fn", fileset.getName());
+ // add dpi
+ dlRequest.setValue("img.dpix", new Double(fileset.getResX()));
+ dlRequest.setValue("img.dpiy", new Double(fileset.getResY()));
+ // get number of pages in directory
+ DocuDirectory dd = dirCache.getDirectory(fn);
+ if (dd != null) {
+ dlRequest.setValue("pt", dd.size());
+ }
+ }
- public boolean isAuthorized(String filepath, HttpServletRequest request) throws AuthOpException {
- util.dprintln(10, "isAuthorized");
- return authOp.isAuthorized(filepath, request);
- }
+ /**
+ * get the first page number in the directory (not yet functional)
+ */
+ public int getFirstPage(DigilibRequest request) {
+ logger.debug("getFirstPage");
+ return 1;
+ }
- /**
- * return a list of authorization roles needed for request
- * to access the specified path
- */
- public List rolesForPath(String filepath, HttpServletRequest request) throws AuthOpException {
- util.dprintln(10, "rolesForPath");
- return authOp.rolesForPath(filepath, request);
- }
+ /**
+ * get the number of pages/files in the directory
+ */
+ public int getNumPages() throws Exception {
+ return getNumPages(dlRequest);
+ }
- /**
- * check request authorization against a list of roles
- */
- public boolean isRoleAuthorized(List roles, HttpServletRequest request) {
- util.dprintln(10, "isRoleAuthorized");
- return authOp.isRoleAuthorized(roles, request);
- }
+ /**
+ * get the number of pages/files in the directory
+ */
+ public int getNumPages(DigilibRequest request) throws Exception {
+ logger.debug("getNumPages");
+ DocuDirectory dd = (dirCache != null) ? dirCache.getDirectory(request
+ .getFilePath()) : null;
+ if (dd != null) {
+ return dd.size();
+ }
+ return 0;
+ }
- /**
- * check for authenticated access and redirect if necessary
- */
- public boolean doAuthentication(HttpServletRequest request, HttpServletResponse response) throws Exception {
- util.dprintln(10, "doAuthentication");
- // check if we are already authenticated
- if (request.getRemoteUser() == null) {
- util.dprintln(3, "unauthenticated so far");
- // if not maybe we must?
- if (isAuthRequired(request)) {
- util.dprintln(3, "auth required, redirect");
- // we are not yet authenticated -> redirect
- response.sendRedirect(authURLpath+request.getServletPath()+"?"+request.getQueryString());
- }
- }
- return true;
- }
+ /**
+ * Returns the dlConfig.
+ *
+ * @return DigilibConfiguration
+ */
+ public DigilibConfiguration getDlConfig() {
+ return dlConfig;
+ }
+
+ /**
+ * returns if the zoom area in the request can be moved
+ *
+ * @return
+ */
+ public boolean canMoveRight() {
+ float ww = dlRequest.getAsFloat("ww");
+ float wx = dlRequest.getAsFloat("wx");
+ return (ww + wx < 1.0);
+ }
- /**
- * get the first page number in the directory
- * (not yet functional)
- */
- public int getFirstPage(HttpServletRequest request) {
- return getFirstPage(getDocuPath(request), request);
- }
-
- public int getFirstPage(String filepath, HttpServletRequest request) {
- util.dprintln(10, "getFirstPage");
- return 1;
- }
+ /**
+ * returns if the zoom area in the request can be moved
+ *
+ * @return
+ */
+ public boolean canMoveLeft() {
+ float ww = dlRequest.getAsFloat("ww");
+ float wx = dlRequest.getAsFloat("wx");
+ return ((ww < 1.0) && (wx > 0));
+ }
- /**
- * get the number of pages/files in the directory
- */
- public int getNumPages(HttpServletRequest request) throws Exception {
- return getNumPages(getDocuPath(request), request);
- }
+ /**
+ * returns if the zoom area in the request can be moved
+ *
+ * @return
+ */
+ public boolean canMoveUp() {
+ float wh = dlRequest.getAsFloat("wh");
+ float wy = dlRequest.getAsFloat("wy");
+ return ((wh < 1.0) && (wy > 0));
+ }
- public int getNumPages(String filepath, HttpServletRequest request) throws Exception {
- util.dprintln(10, "getNumPages");
- return fileOp.getNumFilesVariant(baseDirs, "/"+filepath, true);
- }
+ /**
+ * returns if the zoom area in the request can be moved
+ *
+ * @return
+ */
+ public boolean canMoveDown() {
+ float wh = dlRequest.getAsFloat("wh");
+ float wy = dlRequest.getAsFloat("wy");
+ return (wh + wy < 1.0);
+ }
-}
+ /**
+ * @return Returns the dlRequest.
+ */
+ public DigilibRequest getRequest() {
+ return dlRequest;
+ }
+
+}
\ No newline at end of file
diff -r 9f7b864f955f -r 5d0c0da080ec servlet/src/digilib/servlet/Initialiser.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/servlet/src/digilib/servlet/Initialiser.java Thu Oct 21 20:53:37 2004 +0200
@@ -0,0 +1,173 @@
+/* Initialiser.java -- initalisation servlet for setup tasks
+ *
+ * Digital Image Library servlet components
+ *
+ * Copyright (C) 2004 Robert Casties (robcast@mail.berlios.de)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * Please read license.txt for the full details. A copy of the GPL may be found
+ * at http://www.gnu.org/copyleft/lgpl.html
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Created on 18.10.2004
+ */
+package digilib.servlet;
+
+import java.io.File;
+
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+
+import org.apache.log4j.Logger;
+import org.apache.log4j.xml.DOMConfigurator;
+
+import digilib.auth.AuthOps;
+import digilib.auth.XMLAuthOps;
+import digilib.io.AliasingDocuDirCache;
+import digilib.io.DocuDirCache;
+import digilib.io.FileOps;
+
+/**
+ * Initalisation servlet for setup tasks.
+ *
+ * @author casties
+ *
+ */
+public class Initialiser extends HttpServlet {
+
+ private static final long serialVersionUID = -5126621114382549343L;
+
+ /** servlet version */
+ public static final String iniVersion = "0.1a1";
+
+ /** gengeral logger for this class */
+ private static Logger logger = Logger.getLogger("digilib.init");
+
+ /** AuthOps instance */
+ AuthOps authOp;
+
+ /** DocuDirCache instance */
+ DocuDirCache dirCache;
+
+ /** DigilibConfiguration instance */
+ DigilibConfiguration dlConfig;
+
+ /** use authorization database */
+ boolean useAuthentication = false;
+
+ private DigilibManager fastQueue;
+
+ private DigilibManager slowQueue;
+
+ /**
+ * Initialisation on first run.
+ *
+ * @see javax.servlet.Servlet#init(javax.servlet.ServletConfig)
+ */
+ public void init(ServletConfig config) throws ServletException {
+ super.init(config);
+
+ System.out
+ .println("***** Digital Image Library Initialisation Servlet (version "
+ + iniVersion + ") *****");
+
+ // get our ServletContext
+ ServletContext context = config.getServletContext();
+ // see if there is a Configuration instance
+ dlConfig = (DigilibConfiguration) context
+ .getAttribute("digilib.servlet.configuration");
+ if (dlConfig == null) {
+ // create new Configuration
+ try {
+ dlConfig = new DigilibConfiguration(config);
+
+ /*
+ * further initialization
+ */
+
+ // set up the logger
+ File logConf = ServletOps.getConfigFile((File) dlConfig
+ .getValue("log-config-file"), config);
+ DOMConfigurator.configure(logConf.getAbsolutePath());
+ dlConfig.setValue("log-config-file", logConf);
+ // say hello in the log file
+ logger
+ .info("***** Digital Image Library Initialisation Servlet (version "
+ + iniVersion + ") *****");
+ // directory cache
+ String[] bd = (String[]) dlConfig.getValue("basedir-list");
+ int[] fcs = { FileOps.CLASS_IMAGE, FileOps.CLASS_TEXT,
+ FileOps.CLASS_SVG };
+ if (dlConfig.getAsBoolean("use-mapping")) {
+ // with mapping file
+ File mapConf = ServletOps.getConfigFile((File) dlConfig
+ .getValue("mapping-file"), config);
+ dirCache = new AliasingDocuDirCache(bd, fcs, mapConf,
+ dlConfig);
+ dlConfig.setValue("mapping-file", mapConf);
+ } else {
+ // without mapping
+ dirCache = new DocuDirCache(bd, fcs, dlConfig);
+ }
+ dlConfig.setValue("servlet.dir.cache", dirCache);
+ // useAuthentication
+ if (dlConfig.getAsBoolean("use-authorization")) {
+ // DB version
+ //authOp = new DBAuthOpsImpl(util);
+ // XML version
+ File authConf = ServletOps.getConfigFile((File) dlConfig
+ .getValue("auth-file"), config);
+ authOp = new XMLAuthOps(authConf);
+ dlConfig.setValue("servlet.auth.op", authOp);
+ dlConfig.setValue("auth-file", authConf);
+ }
+ // DocuImage class
+ Class cl = Class.forName(dlConfig
+ .getAsString("docuimage-class"));
+ dlConfig.setDocuImageClass(cl);
+ dlConfig.setValue("servlet.docuimage.class", cl.getName());
+ // DigilibManager work queue
+ int fl = dlConfig.getAsInt("worker-fast-lanes");
+ int fq = dlConfig.getAsInt("worker-fast-queue");
+ fastQueue = new DigilibManager(fl, fq);
+ dlConfig.setValue("servlet.fast.queue", fastQueue);
+ int sl = dlConfig.getAsInt("worker-slow-lanes");
+ int sq = dlConfig.getAsInt("worker-slow-queue");
+ slowQueue = new DigilibManager(sl, sq);
+ dlConfig.setValue("servlet.slow.queue", slowQueue);
+ // set as the servlets main config
+ context.setAttribute("digilib.servlet.configuration", dlConfig);
+
+ } catch (Exception e) {
+ throw new ServletException(e);
+ }
+ } else {
+ // say hello in the log file
+ logger
+ .info("***** Digital Image Library Initialisation Servlet (version "
+ + iniVersion + ") *****");
+ logger.warn("Already initialised?");
+ // set our AuthOps
+ useAuthentication = dlConfig.getAsBoolean("use-authorization");
+ // AuthOps instance
+ authOp = (AuthOps) dlConfig.getValue("servlet.auth.op");
+ // DocuDirCache instance
+ dirCache = (DocuDirCache) dlConfig.getValue("servlet.dir.cache");
+ // work queues
+ fastQueue = (DigilibManager) dlConfig
+ .getValue("servlet.fast.queue");
+ slowQueue = (DigilibManager) dlConfig
+ .getValue("servlet.slow.queue");
+ }
+ }
+
+}
diff -r 9f7b864f955f -r 5d0c0da080ec servlet/src/digilib/servlet/Mapper.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/servlet/src/digilib/servlet/Mapper.java Thu Oct 21 20:53:37 2004 +0200
@@ -0,0 +1,399 @@
+/*
+ * Mapper -- Servlet for creating image-maps from SVG graphics
+ *
+ * Digital Image Library servlet components
+ *
+ * Copyright (C) 2003 Robert Casties (robcast@mail.berlios.de)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * Please read license.txt for the full details. A copy of the GPL may be found
+ * at http://www.gnu.org/copyleft/lgpl.html You should have received a copy of
+ * the GNU General Public License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 USA
+ *
+ * Created on 25.11.2003 by casties
+ */
+
+package digilib.servlet;
+
+import java.awt.geom.Rectangle2D;
+import java.io.IOException;
+
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.xml.parsers.SAXParserFactory;
+
+import org.apache.batik.dom.svg.SAXSVGDocumentFactory;
+import org.apache.batik.transcoder.SVGAbstractTranscoder;
+import org.apache.batik.transcoder.TranscoderException;
+import org.apache.batik.transcoder.TranscoderInput;
+import org.apache.batik.transcoder.TranscoderOutput;
+import org.apache.batik.transcoder.image.PNGTranscoder;
+import org.apache.batik.util.XMLResourceDescriptor;
+import org.apache.log4j.Logger;
+import org.w3c.dom.svg.SVGDocument;
+import org.w3c.dom.svg.SVGSVGElement;
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.XMLFilterImpl;
+
+import digilib.auth.AuthOps;
+import digilib.io.DocuDirCache;
+import digilib.io.FileOpException;
+import digilib.io.FileOps;
+import digilib.io.SVGFile;
+
+/**
+ * Servlet for creating image-maps from SVG graphics
+ *
+ * @author casties
+ *
+ */
+public class Mapper extends HttpServlet {
+
+ private static final long serialVersionUID = 6134014474526638223L;
+
+ /** Servlet version */
+ public static String servletVersion = "0.1a0";
+ /** DigilibConfiguration instance */
+ DigilibConfiguration dlConfig = null;
+ /** general logger */
+ Logger logger = Logger.getLogger("digilib.mapper");
+ /** AuthOps instance */
+ AuthOps authOp;
+ /** DocuDirCache instance */
+ DocuDirCache dirCache;
+ /** SVG document factory */
+ SAXSVGDocumentFactory docFactory;
+
+ /** use authentication */
+ boolean useAuthentication = false;
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see javax.servlet.Servlet#init(javax.servlet.ServletConfig)
+ */
+ public void init(ServletConfig config) throws ServletException {
+ super.init(config);
+
+ System.out.println(
+ "***** Digital Image Library Image Map Servlet (version "
+ + servletVersion
+ + ") *****");
+
+ // get our ServletContext
+ ServletContext context = config.getServletContext();
+ // see if there is a Configuration instance
+ dlConfig =
+ (DigilibConfiguration) context.getAttribute(
+ "digilib.servlet.configuration");
+ if (dlConfig == null) {
+ // no Configuration
+ throw new ServletException("ERROR: No Configuration!");
+ }
+ // say hello in the log file
+ logger.info(
+ "***** Digital Image Library Image Map Servlet (version "
+ + servletVersion
+ + ") *****");
+
+ // set our AuthOps
+ useAuthentication = dlConfig.getAsBoolean("use-authorization");
+ authOp = (AuthOps) dlConfig.getValue("servlet.auth.op");
+ // DocuDirCache instance
+ dirCache = (DocuDirCache) dlConfig.getValue("servlet.dir.cache");
+ // parser name as a String (I hate you for not using JAXP, Batik!)
+ String parserName = null;
+ try {
+ // try the proper JAXP way
+ parserName =
+ SAXParserFactory
+ .newInstance()
+ .newSAXParser()
+ .getXMLReader()
+ .getClass()
+ .getName();
+ } catch (Exception e) {
+ // fall back to Batik's hack
+ parserName = XMLResourceDescriptor.getXMLParserClassName();
+ }
+ logger.debug("parser name: " + parserName);
+ docFactory = new SAXSVGDocumentFactory(parserName);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest,
+ * javax.servlet.http.HttpServletResponse)
+ */
+ protected void doGet(
+ HttpServletRequest request,
+ HttpServletResponse response)
+ throws ServletException, IOException {
+ // create new request with defaults
+ DigilibRequest dlReq = new DigilibRequest();
+ // set with request parameters
+ dlReq.setWithRequest(request);
+ // add DigilibRequest to ServletRequest
+ request.setAttribute("digilib.servlet.request", dlReq);
+ // do the processing
+ processRequest(request, response);
+ }
+
+ /*
+ */
+ protected void doPost(
+ HttpServletRequest request,
+ HttpServletResponse response)
+ throws ServletException, IOException {
+ // create new request with defaults
+ DigilibRequest dlReq = new DigilibRequest();
+ // set with request parameters
+ dlReq.setWithRequest(request);
+ // add DigilibRequest to ServletRequest
+ request.setAttribute("digilib.servlet.request", dlReq);
+ // do the processing
+ processRequest(request, response);
+ }
+
+ protected void processRequest(
+ HttpServletRequest request,
+ HttpServletResponse response)
+ throws ServletException, IOException {
+
+ logger.debug("request: " + request.getQueryString());
+ // time for benchmarking
+ long startTime = System.currentTimeMillis();
+
+ /*
+ * request parameters
+ */
+ DigilibRequest dlRequest =
+ (DigilibRequest) request.getAttribute("digilib.servlet.request");
+
+ // destination image width
+ int paramDW = dlRequest.getAsInt("dw");
+ // destination image height
+ int paramDH = dlRequest.getAsInt("dh");
+ // relative area x_offset (0..1)
+ float paramWX = dlRequest.getAsFloat("wx");
+ // relative area y_offset
+ float paramWY = dlRequest.getAsFloat("wy");
+ // relative area width (0..1)
+ double paramWW = dlRequest.getAsFloat("ww");
+ // relative area height
+ double paramWH = dlRequest.getAsFloat("wh");
+
+ try {
+
+ /*
+ * find the file to load/send
+ */
+
+ // get PathInfo
+ String loadPathName = dlRequest.getFilePath();
+ // find the file(set)
+ SVGFile fileToLoad =
+ (SVGFile) dirCache.getFile(
+ loadPathName,
+ dlRequest.getAsInt("pn"),
+ FileOps.CLASS_SVG);
+ if (fileToLoad == null) {
+ throw new FileOpException(
+ "File "
+ + loadPathName
+ + "("
+ + dlRequest.getAsString("pn")
+ + ") not found.");
+ }
+
+ /*
+ * read the SVG document
+ */
+
+ // read the document
+ SVGDocument doc =
+ docFactory.createSVGDocument(
+ fileToLoad.getFile().toURI().toString());
+ // extract the SVG root
+ SVGSVGElement svgroot = doc.getRootElement();
+ // get document width and height
+ float imgWidth = svgroot.getWidth().getBaseVal().getValue();
+ float imgHeight = svgroot.getHeight().getBaseVal().getValue();
+
+ /*
+ * set up the transcoder
+ */
+
+ // create a PNG transcoder
+ MapTranscoder transcoder = new MapTranscoder();
+ // create the transcoder input
+ TranscoderInput input = new TranscoderInput(doc);
+ logger.info("Loading: " + fileToLoad.getFile());
+ // create the transcoder output
+ TranscoderOutput output =
+// new TranscoderOutput(new FileWriter("/tmp/maptest.out"));
+ new TranscoderOutput(new MapFilter());
+ // output is image/png
+ //response.setContentType("image/png");
+
+ // area of interest
+ Rectangle2D aoi =
+ new Rectangle2D.Double(
+ paramWX * imgWidth,
+ paramWY * imgHeight,
+ paramWW * imgWidth,
+ paramWH * imgHeight);
+ transcoder.addTranscodingHint(PNGTranscoder.KEY_AOI, aoi);
+
+ // destination image dimensions
+ if (paramDW > 0) {
+ transcoder.addTranscodingHint(
+ SVGAbstractTranscoder.KEY_WIDTH,
+ new Float(paramDW));
+ }
+ if (paramDH > 0) {
+ transcoder.addTranscodingHint(
+ SVGAbstractTranscoder.KEY_HEIGHT,
+ new Float(paramDH));
+ }
+
+ /*
+ * transcode
+ */
+
+ transcoder.transcode(input, output);
+
+ logger.info(
+ "Done in " + (System.currentTimeMillis() - startTime) + "ms");
+
+ /*
+ * error handling
+ */
+
+ } catch (FileOpException e) {
+ logger.error("ERROR: File IO Error: ", e);
+ try {
+ ServletOps.htmlMessage("ERROR: File IO Error: " + e, response);
+ } catch (Exception ex) {
+ } // so we don't get a loop
+ } catch (TranscoderException e) {
+ logger.error("ERROR: SVG encoder error: ", e);
+ try {
+ ServletOps.htmlMessage(
+ "ERROR: SVG encoder error: " + e,
+ response);
+ } catch (Exception ex) {
+ } // so we don't get a loop
+ }
+
+ }
+
+ protected class MapFilter extends XMLFilterImpl {
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.xml.sax.ContentHandler#characters(char[], int, int)
+ */
+ public void characters(char[] ch, int start, int length)
+ throws SAXException {
+ // TODO Auto-generated method stub
+ logger.debug(
+ "characters('"
+ + ch.toString()
+ + "',"
+ + start
+ + ","
+ + length
+ + ")");
+ super.characters(ch, start, length);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.xml.sax.ContentHandler#endDocument()
+ */
+ public void endDocument() throws SAXException {
+ // TODO Auto-generated method stub
+ logger.debug("endDocument");
+ super.endDocument();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.xml.sax.ContentHandler#endElement(java.lang.String,
+ * java.lang.String, java.lang.String)
+ */
+ public void endElement(String uri, String localName, String qName)
+ throws SAXException {
+ // TODO Auto-generated method stub
+ logger.debug(
+ "endElement(" + uri + "," + localName + "," + qName + ")");
+ super.endElement(uri, localName, qName);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.xml.sax.ContentHandler#startDocument()
+ */
+ public void startDocument() throws SAXException {
+ // TODO Auto-generated method stub
+ logger.debug("startDocument");
+ super.startDocument();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.xml.sax.ContentHandler#startElement(java.lang.String,
+ * java.lang.String, java.lang.String, org.xml.sax.Attributes)
+ */
+ public void startElement(
+ String uri,
+ String localName,
+ String qName,
+ Attributes atts)
+ throws SAXException {
+ // TODO Auto-generated method stub
+ logger.debug(
+ "startElement("
+ + uri
+ + ","
+ + localName
+ + ","
+ + qName
+ + ","
+ + atts.toString()
+ + ")");
+ super.startElement(uri, localName, qName, atts);
+ }
+
+ }
+
+ class MapTranscoder extends SVGAbstractTranscoder {
+
+ /**
+ *
+ */
+ public MapTranscoder() {
+ super();
+ }
+
+}
+
+}
diff -r 9f7b864f955f -r 5d0c0da080ec servlet/src/digilib/servlet/Raster.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/servlet/src/digilib/servlet/Raster.java Thu Oct 21 20:53:37 2004 +0200
@@ -0,0 +1,293 @@
+/*
+ * Raster -- Servlet for displaying rasterized SVG graphics
+ *
+ * Digital Image Library servlet components
+ *
+ * Copyright (C) 2003 Robert Casties (robcast@mail.berlios.de)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * Please read license.txt for the full details. A copy of the GPL may be found
+ * at http://www.gnu.org/copyleft/lgpl.html You should have received a copy of
+ * the GNU General Public License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 USA
+ *
+ * Created on 25.11.2003 by casties
+ */
+
+package digilib.servlet;
+
+import java.awt.geom.Rectangle2D;
+import java.io.IOException;
+
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.xml.parsers.SAXParserFactory;
+
+import org.apache.batik.dom.svg.SAXSVGDocumentFactory;
+import org.apache.batik.transcoder.TranscoderException;
+import org.apache.batik.transcoder.TranscoderInput;
+import org.apache.batik.transcoder.TranscoderOutput;
+import org.apache.batik.transcoder.image.PNGTranscoder;
+import org.apache.batik.util.XMLResourceDescriptor;
+import org.apache.log4j.Logger;
+import org.w3c.dom.svg.SVGDocument;
+import org.w3c.dom.svg.SVGSVGElement;
+
+import digilib.auth.AuthOps;
+import digilib.io.DocuDirCache;
+import digilib.io.FileOpException;
+import digilib.io.FileOps;
+import digilib.io.SVGFile;
+
+/**
+ * Servlet for displaying SVG graphics
+ *
+ * @author casties
+ *
+ */
+public class Raster extends HttpServlet {
+
+ private static final long serialVersionUID = -7756999389932675241L;
+
+ /** Servlet version */
+ public static String servletVersion = "0.1b1";
+ /** DigilibConfiguration instance */
+ DigilibConfiguration dlConfig = null;
+ /** general logger */
+ Logger logger = Logger.getLogger("digilib.raster");
+ /** AuthOps instance */
+ AuthOps authOp;
+ /** DocuDirCache instance */
+ DocuDirCache dirCache;
+ /** SVG document factory */
+ SAXSVGDocumentFactory docFactory;
+
+ /** use authentication */
+ boolean useAuthentication = false;
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see javax.servlet.Servlet#init(javax.servlet.ServletConfig)
+ */
+ public void init(ServletConfig config) throws ServletException {
+ super.init(config);
+
+ System.out.println(
+ "***** Digital Image Library SVG Render Servlet (version "
+ + servletVersion
+ + ") *****");
+
+ // get our ServletContext
+ ServletContext context = config.getServletContext();
+ // see if there is a Configuration instance
+ dlConfig =
+ (DigilibConfiguration) context.getAttribute(
+ "digilib.servlet.configuration");
+ if (dlConfig == null) {
+ // no config
+ throw new ServletException("ERROR: No Configuration!");
+ }
+ // say hello in the log file
+ logger.info(
+ "***** Digital Image Library SVG Render Servlet (version "
+ + servletVersion
+ + ") *****");
+
+ // set our AuthOps
+ useAuthentication = dlConfig.getAsBoolean("use-authorization");
+ authOp = (AuthOps) dlConfig.getValue("servlet.auth.op");
+ // DocuDirCache instance
+ dirCache = (DocuDirCache) dlConfig.getValue("servlet.dir.cache");
+ // parser name as a String (I hate you for not using JAXP, Batik!)
+ String parserName = null;
+ try {
+ // try the proper JAXP way
+ parserName = SAXParserFactory.newInstance().newSAXParser().getXMLReader().getClass().getName();
+ } catch (Exception e) {
+ // fall back to Batik's hack
+ parserName = XMLResourceDescriptor.getXMLParserClassName();
+ }
+ logger.debug("parser name: "+parserName);
+ docFactory = new SAXSVGDocumentFactory(parserName);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest,
+ * javax.servlet.http.HttpServletResponse)
+ */
+ protected void doGet(
+ HttpServletRequest request,
+ HttpServletResponse response)
+ throws ServletException, IOException {
+ // create new request with defaults
+ DigilibRequest dlReq = new DigilibRequest();
+ // set with request parameters
+ dlReq.setWithRequest(request);
+ // add DigilibRequest to ServletRequest
+ request.setAttribute("digilib.servlet.request", dlReq);
+ // do the processing
+ processRequest(request, response);
+ }
+
+ /*
+ */
+ protected void doPost(
+ HttpServletRequest request,
+ HttpServletResponse response)
+ throws ServletException, IOException {
+ // create new request with defaults
+ DigilibRequest dlReq = new DigilibRequest();
+ // set with request parameters
+ dlReq.setWithRequest(request);
+ // add DigilibRequest to ServletRequest
+ request.setAttribute("digilib.servlet.request", dlReq);
+ // do the processing
+ processRequest(request, response);
+ }
+
+ protected void processRequest(
+ HttpServletRequest request,
+ HttpServletResponse response)
+ throws ServletException, IOException {
+
+ logger.debug("request: "+request.getQueryString());
+ // time for benchmarking
+ long startTime = System.currentTimeMillis();
+
+ /*
+ * request parameters
+ */
+ DigilibRequest dlRequest =
+ (DigilibRequest) request.getAttribute("digilib.servlet.request");
+
+ // destination image width
+ int paramDW = dlRequest.getAsInt("dw");
+ // destination image height
+ int paramDH = dlRequest.getAsInt("dh");
+ // relative area x_offset (0..1)
+ float paramWX = dlRequest.getAsFloat("wx");
+ // relative area y_offset
+ float paramWY = dlRequest.getAsFloat("wy");
+ // relative area width (0..1)
+ double paramWW = dlRequest.getAsFloat("ww");
+ // relative area height
+ double paramWH = dlRequest.getAsFloat("wh");
+
+ try {
+
+ /*
+ * find the file to load/send
+ */
+
+ // get PathInfo
+ String loadPathName = dlRequest.getFilePath();
+ // find the file(set)
+ SVGFile fileToLoad =
+ (SVGFile) dirCache.getFile(
+ loadPathName,
+ dlRequest.getAsInt("pn"),
+ FileOps.CLASS_SVG);
+ if (fileToLoad == null) {
+ throw new FileOpException(
+ "File "
+ + loadPathName
+ + "("
+ + dlRequest.getAsString("pn")
+ + ") not found.");
+ }
+
+ /*
+ * read the SVG document
+ */
+
+ // read the document
+ SVGDocument doc =
+ docFactory.createSVGDocument(
+ fileToLoad.getFile().toURI().toString());
+ // extract the SVG root
+ SVGSVGElement svgroot = doc.getRootElement();
+ // get document width and height
+ float imgWidth = svgroot.getWidth().getBaseVal().getValue();
+ float imgHeight = svgroot.getHeight().getBaseVal().getValue();
+
+ /*
+ * set up the transcoder
+ */
+
+ // create a PNG transcoder
+ PNGTranscoder transcoder = new PNGTranscoder();
+ // create the transcoder input
+ //InputStream is = new FileInputStream(fileToLoad.getFile());
+ TranscoderInput input = new TranscoderInput(doc);
+ logger.info("Loading: " + fileToLoad.getFile());
+ // create the transcoder output
+ TranscoderOutput output =
+ new TranscoderOutput(response.getOutputStream());
+ // output is image/png
+ response.setContentType("image/png");
+
+ // area of interest
+ Rectangle2D aoi =
+ new Rectangle2D.Double(
+ paramWX * imgWidth,
+ paramWY * imgHeight,
+ paramWW * imgWidth,
+ paramWH * imgHeight);
+ transcoder.addTranscodingHint(PNGTranscoder.KEY_AOI, aoi);
+
+ // destination image dimensions
+ if (paramDW > 0) {
+ transcoder.addTranscodingHint(
+ PNGTranscoder.KEY_WIDTH,
+ new Float(paramDW));
+ }
+ if (paramDH > 0) {
+ transcoder.addTranscodingHint(
+ PNGTranscoder.KEY_HEIGHT,
+ new Float(paramDH));
+ }
+
+ /*
+ * transcode
+ */
+
+ transcoder.transcode(input, output);
+
+ logger.info(
+ "Done in " + (System.currentTimeMillis() - startTime) + "ms");
+
+ /*
+ * error handling
+ */
+
+ } catch (FileOpException e) {
+ logger.error("ERROR: File IO Error: ", e);
+ try {
+ ServletOps.htmlMessage("ERROR: File IO Error: " + e, response);
+ } catch (Exception ex) {
+ } // so we don't get a loop
+ } catch (TranscoderException e) {
+ logger.error("ERROR: SVG encoder error: ", e);
+ try {
+ ServletOps.htmlMessage(
+ "ERROR: SVG encoder error: " + e,
+ response);
+ } catch (Exception ex) {
+ } // so we don't get a loop
+ }
+
+ }
+
+}
diff -r 9f7b864f955f -r 5d0c0da080ec servlet/src/digilib/servlet/Scaler.java
--- a/servlet/src/digilib/servlet/Scaler.java Mon Oct 18 15:40:54 2004 +0200
+++ b/servlet/src/digilib/servlet/Scaler.java Thu Oct 21 20:53:37 2004 +0200
@@ -1,377 +1,684 @@
-/* Scaler -- Scaler servlet main class
-
- Digital Image Library servlet components
-
- Copyright (C) 2001, 2002 Robert Casties (robcast@mail.berlios.de)
-
- This program is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published by the
- Free Software Foundation; either version 2 of the License, or (at your
- option) any later version.
-
- Please read license.txt for the full details. A copy of the GPL
- may be found at http://www.gnu.org/copyleft/lgpl.html
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-
-*/
+/*
+ * Scaler -- Scaler servlet main class
+ *
+ * Digital Image Library servlet components
+ *
+ * Copyright (C) 2001, 2002, 2003 Robert Casties (robcast@mail.berlios.de)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * Please read license.txt for the full details. A copy of the GPL may be found
+ * at http://www.gnu.org/copyleft/lgpl.html
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
package digilib.servlet;
-import javax.servlet.*;
-import javax.servlet.http.*;
-import java.io.*;
-import java.util.*;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.NoninvertibleTransformException;
+import java.awt.geom.Rectangle2D;
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.log4j.Logger;
-import digilib.*;
-import digilib.io.*;
-import digilib.image.*;
-import digilib.auth.*;
+import digilib.auth.AuthOpException;
+import digilib.auth.AuthOps;
+import digilib.image.ImageOpException;
+import digilib.image.ImageOps;
+import digilib.image.ImageSize;
+import digilib.io.DocuDirCache;
+import digilib.io.FileOpException;
+import digilib.io.FileOps;
+import digilib.io.ImageFile;
+import digilib.io.ImageFileset;
+//import tilecachetool.*;
+/**
+ * @author casties
+ */
//public class Scaler extends HttpServlet implements SingleThreadModel {
public class Scaler extends HttpServlet {
- // Utils instance with debuglevel
- Utils util;
- // ServletOpss instance
- ServletOps servletOp;
- // FileOps instance
- FileOps fileOp;
- // AuthOps instance
- AuthOps authOp;
- // global DocuImage instance (don't reuse inside a request!)
- DocuImage globalImage;
+ private static final long serialVersionUID = -325080527268912852L;
+
+ /** digilib servlet version (for all components) */
+ public static final String dlVersion = "2.0a6";
+
+ /** logger for accounting requests */
+ private static Logger accountlog = Logger.getLogger("account.request");
+
+ /** gengeral logger for this class */
+ private static Logger logger = Logger.getLogger("digilib.servlet");
+
+ /** logger for authentication related */
+ private static Logger authlog = Logger.getLogger("digilib.auth");
+
+ /** general error code */
+ public static final int ERROR_UNKNOWN = 0;
+
+ /** error code for authentication error */
+ public static final int ERROR_AUTH = 1;
+
+ /** error code for file operation error */
+ public static final int ERROR_FILE = 2;
+
+ /** error code for image operation error */
+ public static final int ERROR_IMAGE = 3;
+
+ /** DocuDirCache instance */
+ DocuDirCache dirCache;
+
+ /** authentication error image file */
+ File denyImgFile;
+
+ /** image error image file */
+ File errorImgFile;
+
+ /** subsampling before scaling */
+ float minSubsample = 2f;
+
+ /** send files as is? */
+ boolean sendFileAllowed = true;
+
+ /** default scaling quality */
+ int defaultQuality = 1;
+
+ /** DigilibConfiguration instance */
+ DigilibConfiguration dlConfig;
+
+ /** fast worker queue */
+ DigilibManager fastQueue;
+
+ /** slow image worker queue */
+ DigilibManager slowQueue;
+
+ /** use authorization database */
+ boolean useAuthorization = true;
+
+ /** AuthOps instance */
+ AuthOps authOp;
+
+ // EXPRIMENTAL
+ /** try to enlarge cropping area for "oblique" angles */
+ boolean wholeRotArea = false;
+
+ /**
+ * Initialisation on first run.
+ *
+ * @see javax.servlet.Servlet#init(javax.servlet.ServletConfig)
+ */
+ public void init(ServletConfig config) throws ServletException {
+ super.init(config);
+
+ System.out
+ .println("***** Digital Image Library Image Scaler Servlet (version "
+ + dlVersion + ") *****");
+ // say hello in the log file
+ logger
+ .info("***** Digital Image Library Image Scaler Servlet (version "
+ + dlVersion + ") *****");
+
+ // get our ServletContext
+ ServletContext context = config.getServletContext();
+ // see if there is a Configuration instance
+ dlConfig = (DigilibConfiguration) context
+ .getAttribute("digilib.servlet.configuration");
+ if (dlConfig == null) {
+ // no Configuration
+ throw new ServletException("No Configuration!");
+ }
+ // set our AuthOps
+ useAuthorization = dlConfig.getAsBoolean("use-authorization");
+ authOp = (AuthOps) dlConfig.getValue("servlet.auth.op");
+ // work queues
+ fastQueue = (DigilibManager) dlConfig.getValue("servlet.fast.queue");
+ slowQueue = (DigilibManager) dlConfig.getValue("servlet.slow.queue");
+
+ // DocuDirCache instance
+ dirCache = (DocuDirCache) dlConfig.getValue("servlet.dir.cache");
+ denyImgFile = (File) dlConfig.getValue("denied-image");
+ errorImgFile = (File) dlConfig.getValue("error-image");
+ sendFileAllowed = dlConfig.getAsBoolean("sendfile-allowed");
+ minSubsample = dlConfig.getAsFloat("subsample-minimum");
+ defaultQuality = dlConfig.getAsInt("default-quality");
+ }
+
+ /** Process the HTTP Get request */
+ public void doGet(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, IOException {
+ accountlog.info("GET from " + request.getRemoteAddr());
+ // create new request with defaults
+ DigilibRequest dlReq = new DigilibRequest();
+ // set with request parameters
+ dlReq.setWithRequest(request);
+ // add DigilibRequest to ServletRequest
+ request.setAttribute("digilib.servlet.request", dlReq);
+ // do the processing
+ processRequest(request, response);
+ }
+
+ /** Process the HTTP Post request */
+ public void doPost(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, IOException {
+ accountlog.info("POST from " + request.getRemoteAddr());
+ // create new request with defaults
+ DigilibRequest dlReq = new DigilibRequest();
+ // set with request parameters
+ dlReq.setWithRequest(request);
+ // add DigilibRequest to ServletRequest
+ request.setAttribute("digilib.servlet.request", dlReq);
+ // do the processing
+ processRequest(request, response);
+ }
+
+ /** main request handler. */
+void processRequest(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException {
+
+ if (dlConfig == null) {
+ throw new ServletException("ERROR: No Configuration!");
+ }
+
+ accountlog.debug("request: " + request.getQueryString());
+ logger.debug("request: " + request.getQueryString());
+
+ // time for benchmarking
+ long startTime = System.currentTimeMillis();
+ // output mime/type
+ String mimeType = "image/png";
+
+ /* parameters for a session */
+
+ // scale the image file to fit window size i.e. respect dw,dh
+ boolean scaleToFit = true;
+ // scale the image by a fixed factor only
+ boolean absoluteScale = false;
+ // only crop the image to fit
+ boolean cropToFit = false;
+ // send the file as is
+ boolean sendFile = false;
+ // use low resolution images only
+ boolean loresOnly = false;
+ // use hires images only
+ boolean hiresOnly = false;
+ // interpolation to use for scaling
+ int scaleQual = defaultQuality;
+ // send html error message (or image file)
+ boolean errorMsgHtml = false;
+ // mirror the image
+ boolean doMirror = false;
+ // angle of mirror axis
+ float mirrorAngle = 0;
+ // original (hires) image resolution
+ float origResX = 0;
+ float origResY = 0;
+
+ /* request parameters */
+
+ DigilibRequest dlRequest = (DigilibRequest) request
+ .getAttribute("digilib.servlet.request");
+
+ // destination image width
+ int paramDW = dlRequest.getAsInt("dw");
+ // destination image height
+ int paramDH = dlRequest.getAsInt("dh");
+ // relative area x_offset (0..1)
+ float paramWX = dlRequest.getAsFloat("wx");
+ // relative area y_offset
+ float paramWY = dlRequest.getAsFloat("wy");
+ // relative area width (0..1)
+ float paramWW = dlRequest.getAsFloat("ww");
+ // relative area height
+ float paramWH = dlRequest.getAsFloat("wh");
+ // scale factor (additional to dw/width, dh/height)
+ float paramWS = dlRequest.getAsFloat("ws");
+ // rotation angle
+ float paramROT = dlRequest.getAsFloat("rot");
+ // contrast enhancement
+ float paramCONT = dlRequest.getAsFloat("cont");
+ // brightness enhancement
+ float paramBRGT = dlRequest.getAsFloat("brgt");
+ // color modification
+ float[] paramRGBM = null;
+ Parameter p = dlRequest.get("rgbm");
+ if (p.hasValue() && (!p.getAsString().equals("0/0/0"))) {
+ paramRGBM = p.parseAsFloatArray("/");
+ }
+ float[] paramRGBA = null;
+ p = dlRequest.get("rgba");
+ if (p.hasValue() && (!p.getAsString().equals("0/0/0"))) {
+ paramRGBA = p.parseAsFloatArray("/");
+ }
+ // destination resolution (DPI)
+ float paramDDPIX = dlRequest.getAsFloat("ddpix");
+ float paramDDPIY = dlRequest.getAsFloat("ddpiy");
+ if ((paramDDPIX == 0) || (paramDDPIY == 0)) {
+ // if X or Y resolution isn't set, use DDPI
+ paramDDPIX = dlRequest.getAsFloat("ddpi");
+ paramDDPIY = paramDDPIX;
+ }
+
+ /*
+ * operation mode: "fit": always fit to page, "clip": send original
+ * resolution cropped, "file": send whole file (if allowed)
+ */
+ if (dlRequest.hasOption("mo", "clip")) {
+ scaleToFit = false;
+ absoluteScale = false;
+ cropToFit = true;
+ sendFile = false;
+ hiresOnly = true;
+ } else if (dlRequest.hasOption("mo", "fit")) {
+ scaleToFit = true;
+ absoluteScale = false;
+ cropToFit = false;
+ sendFile = false;
+ hiresOnly = false;
+ } else if (dlRequest.hasOption("mo", "osize")) {
+ scaleToFit = false;
+ absoluteScale = true;
+ cropToFit = false;
+ sendFile = false;
+ hiresOnly = true;
+ }
+ // operation mode: "lores": try to use scaled image, "hires": use
+ // unscaled image
+ // "autores": try best fitting resolution
+ if (dlRequest.hasOption("mo", "lores")) {
+ loresOnly = true;
+ hiresOnly = false;
+ } else if (dlRequest.hasOption("mo", "hires")) {
+ loresOnly = false;
+ hiresOnly = true;
+ } else if (dlRequest.hasOption("mo", "autores")) {
+ loresOnly = false;
+ hiresOnly = false;
+ }
+ // operation mode: "errtxt": error message in html, "errimg": error
+ // image
+ if (dlRequest.hasOption("mo", "errtxt")) {
+ errorMsgHtml = true;
+ } else if (dlRequest.hasOption("mo", "errimg")) {
+ errorMsgHtml = false;
+ }
+ // operation mode: "q0" - "q2": interpolation quality
+ if (dlRequest.hasOption("mo", "q0")) {
+ scaleQual = 0;
+ } else if (dlRequest.hasOption("mo", "q1")) {
+ scaleQual = 1;
+ } else if (dlRequest.hasOption("mo", "q2")) {
+ scaleQual = 2;
+ }
+
+ // check with the maximum allowed size (if set)
+ int maxImgSize = dlConfig.getAsInt("max-image-size");
+ if (maxImgSize > 0) {
+ paramDW = (paramDW * paramWS > maxImgSize) ? (int) (maxImgSize / paramWS)
+ : paramDW;
+ paramDH = (paramDH * paramWS > maxImgSize) ? (int) (maxImgSize / paramWS)
+ : paramDH;
+ }
- // use authorization database
- boolean useAuthentication = true;
- // image file to send in case of error
- File errorImgFile = new File("/docuserver/images/icons/scalerror.gif");
- // image file to send if access is denied
- File denyImgFile = new File("/docuserver/images/icons/denied.gif");
- // base directories in order of preference (prescaled versions first)
- String[] baseDirs = {"/docuserver/scaled/small", "/docuserver/images", "/docuserver/scans/quellen"};
+ //"big" try for all file/image actions
+ try {
+
+ // ImageFileset of the image to load
+ ImageFileset fileset = null;
+
+ /* find the file to load/send */
+
+ // get PathInfo
+ String loadPathName = dlRequest.getFilePath();
+
+ /* check permissions */
+ if (useAuthorization) {
+ // get a list of required roles (empty if no restrictions)
+ List rolesRequired = authOp.rolesForPath(loadPathName, request);
+ if (rolesRequired != null) {
+ authlog.debug("Role required: " + rolesRequired);
+ authlog.debug("User: " + request.getRemoteUser());
+ // is the current request/user authorized?
+ if (!authOp.isRoleAuthorized(rolesRequired, request)) {
+ // send deny answer and abort
+ throw new AuthOpException();
+ }
+ }
+ }
+
+ // find the file(set)
+ ImageFile fileToLoad;
+ fileset = (ImageFileset) dirCache.getFile(loadPathName, dlRequest
+ .getAsInt("pn"), FileOps.CLASS_IMAGE);
+ if (fileset == null) {
+ throw new FileOpException("File " + loadPathName + "("
+ + dlRequest.getAsInt("pn") + ") not found.");
+ }
+
+ /* calculate expected source image size */
+ ImageSize expectedSourceSize = new ImageSize();
+ if (scaleToFit) {
+ float scale = (1 / Math.min(paramWW, paramWH)) * paramWS;
+ expectedSourceSize.setSize((int) (paramDW * scale),
+ (int) (paramDH * scale));
+ } else {
+ expectedSourceSize.setSize((int) (paramDW * paramWS),
+ (int) (paramDH * paramWS));
+ }
+
+ /* select a resolution */
+ if (hiresOnly) {
+ // get first element (= highest resolution)
+ fileToLoad = fileset.getBiggest();
+ } else if (loresOnly) {
+ // enforced lores uses next smaller resolution
+ fileToLoad = fileset.getNextSmaller(expectedSourceSize);
+ if (fileToLoad == null) {
+ // this is the smallest we have
+ fileToLoad = fileset.getSmallest();
+ }
+ } else {
+ // autores: use next higher resolution
+ fileToLoad = fileset.getNextBigger(expectedSourceSize);
+ if (fileToLoad == null) {
+ // this is the highest we have
+ fileToLoad = fileset.getBiggest();
+ }
+ }
+ logger.info("Loading: " + fileToLoad.getFile());
+
+ /*
+ * send the image if its mo=(raw)file
+ */
+ if (dlRequest.hasOption("mo", "file")
+ || dlRequest.hasOption("mo", "rawfile")) {
+ if (sendFileAllowed) {
+ String mt = null;
+ if (dlRequest.hasOption("mo", "rawfile")) {
+ mt = "application/octet-stream";
+ }
+ logger.debug("Sending RAW File as is.");
+ ServletOps.sendFile(fileToLoad.getFile(), mt, response,
+ fastQueue);
+ logger.info("Done in "
+ + (System.currentTimeMillis() - startTime) + "ms");
+ return;
+ }
+ }
+
+ /*
+ * prepare resolution for original size
+ */
+ if (absoluteScale) {
+ // get original resolution from metadata
+ fileset.checkMeta();
+ origResX = fileset.getResX();
+ origResY = fileset.getResY();
+ if ((origResX == 0) || (origResY == 0)) {
+ throw new ImageOpException("Missing image DPI information!");
+ }
+
+ if ((paramDDPIX == 0) || (paramDDPIY == 0)) {
+ throw new ImageOpException(
+ "Missing display DPI information!");
+ }
+ }
+
+ // check the source image
+ if (!fileToLoad.isChecked()) {
+ ImageOps.checkFile(fileToLoad);
+ }
+ // get the source image type
+ mimeType = fileToLoad.getMimetype();
+ // get the source image size
+ ImageSize imgSize = fileToLoad.getSize();
+
+ // decide if the image can be sent as is
+ boolean mimetypeSendable = mimeType.equals("image/jpeg")
+ || mimeType.equals("image/png")
+ || mimeType.equals("image/gif");
+ boolean imagoOptions = dlRequest.hasOption("mo", "hmir")
+ || dlRequest.hasOption("mo", "vmir") || (paramROT != 0)
+ || (paramRGBM != null) || (paramRGBA != null)
+ || (paramCONT != 0) || (paramBRGT != 0);
+ boolean imageSendable = mimetypeSendable && !imagoOptions;
+
+ /*
+ * if not autoRes and image smaller than requested size then send as
+ * is. if autoRes and image has requested size then send as is. if
+ * not autoScale and not scaleToFit nor cropToFit then send as is
+ * (mo=file)
+ */
+ if (imageSendable
+ && ((loresOnly && fileToLoad.getSize().isSmallerThan(
+ expectedSourceSize)) || (!(loresOnly || hiresOnly) && fileToLoad
+ .getSize().fitsIn(expectedSourceSize)))) {
+
+ logger.debug("Sending File as is.");
+
+ ServletOps.sendFile(fileToLoad.getFile(), null, response,
+ fastQueue);
+
+ logger.info("Done in "
+ + (System.currentTimeMillis() - startTime) + "ms");
+ return;
+ }
+
+ // set missing dw or dh from aspect ratio
+ float imgAspect = fileToLoad.getAspect();
+ if (paramDW == 0) {
+ paramDW = (int) Math.round(paramDH * imgAspect);
+ } else if (paramDH == 0) {
+ paramDH = (int) Math.round(paramDW / imgAspect);
+ }
+
+ /* crop and scale the image */
+
+ logger.debug("IMG: " + imgSize.getWidth() + "x"
+ + imgSize.getHeight());
+ logger.debug("time " + (System.currentTimeMillis() - startTime)
+ + "ms");
+
+ // coordinates and scaling
+ float areaXoff;
+ float areaYoff;
+ float areaWidth;
+ float areaHeight;
+ float scaleX;
+ float scaleY;
+ float scaleXY;
+
+ // coordinates using Java2D
+ // image size in pixels
+ Rectangle2D imgBounds = new Rectangle2D.Float(0, 0, imgSize
+ .getWidth(), imgSize.getHeight());
+ // user window area in [0,1] coordinates
+ Rectangle2D relUserArea = new Rectangle2D.Float(paramWX, paramWY,
+ paramWW, paramWH);
+ // transform from relative [0,1] to image coordinates.
+ AffineTransform imgTrafo = AffineTransform.getScaleInstance(imgSize
+ .getWidth(), imgSize.getHeight());
+ // transform user coordinate area to image coordinate area
+ Rectangle2D userImgArea = imgTrafo.createTransformedShape(
+ relUserArea).getBounds2D();
+
+ // calculate scaling factors based on inner user area
+ if (scaleToFit) {
+ areaWidth = (float) userImgArea.getWidth();
+ areaHeight = (float) userImgArea.getHeight();
+ scaleX = paramDW / areaWidth * paramWS;
+ scaleY = paramDH / areaHeight * paramWS;
+ scaleXY = (scaleX > scaleY) ? scaleY : scaleX;
+ } else if (absoluteScale) {
+ // absolute scale
+ scaleX = paramDDPIX / origResX;
+ scaleY = paramDDPIY / origResY;
+ // currently only same scale :-(
+ scaleXY = scaleX;
+ areaWidth = paramDW / scaleXY * paramWS;
+ areaHeight = paramDH / scaleXY * paramWS;
+ // reset user area size
+ userImgArea.setRect(userImgArea.getX(), userImgArea.getY(),
+ areaWidth, areaHeight);
+ } else {
+ // crop to fit
+ areaWidth = paramDW * paramWS;
+ areaHeight = paramDH * paramWS;
+ // reset user area size
+ userImgArea.setRect(userImgArea.getX(), userImgArea.getY(),
+ areaWidth, areaHeight);
+ scaleX = 1f;
+ scaleY = 1f;
+ scaleXY = 1f;
+ }
+
+ // enlarge image area for rotations to cover additional pixels
+ Rectangle2D outerUserImgArea = userImgArea;
+ Rectangle2D innerUserImgArea = userImgArea;
+ if (wholeRotArea) {
+ if (paramROT != 0) {
+ try {
+ // rotate user area coordinates around center of user
+ // area
+ AffineTransform rotTrafo = AffineTransform
+ .getRotateInstance(Math.toRadians(paramROT),
+ userImgArea.getCenterX(), userImgArea
+ .getCenterY());
+ // get bounds from rotated end position
+ innerUserImgArea = rotTrafo.createTransformedShape(
+ userImgArea).getBounds2D();
+ // get bounds from back-rotated bounds
+ outerUserImgArea = rotTrafo.createInverse()
+ .createTransformedShape(innerUserImgArea)
+ .getBounds2D();
+ } catch (NoninvertibleTransformException e1) {
+ // this shouldn't happen anyway
+ logger.error(e1);
+ }
+ }
+ }
+
+ logger.debug("Scale " + scaleXY + "(" + scaleX + "," + scaleY
+ + ") on " + outerUserImgArea);
+
+ // clip area at the image border
+ outerUserImgArea = outerUserImgArea.createIntersection(imgBounds);
+
+ // check image parameters sanity
+ if ((outerUserImgArea.getWidth() < 1) || (outerUserImgArea.getHeight() < 1)
+ || (scaleXY * outerUserImgArea.getWidth() < 2) || (scaleXY * outerUserImgArea.getHeight() < 2)) {
+ logger.error("ERROR: invalid scale parameter set!");
+ throw new ImageOpException("Invalid scale parameter set!");
+ }
+
+ /*
+ * submit the image worker job
+ */
+
+ DigilibWorker job = new DigilibImageWorker(dlConfig, response,
+ mimeType, scaleQual, dlRequest, paramROT, paramCONT,
+ paramBRGT, paramRGBM, paramRGBA, fileToLoad, scaleXY, outerUserImgArea,
+ innerUserImgArea, minSubsample, wholeRotArea);
+
+ try {
+ // we're cheating
+ job.run();
+ } catch (Exception e1) {
+ throw new ImageOpException(e1.toString());
+ }
+
+ /*
+ try {
+ slowQueue.execute(job);
+ logger.debug("servlet job submitted by "
+ + Thread.currentThread().getName() + " ("
+ + slowQueue.getQueueSize() + " in queue)");
+
+ synchronized (job) {
+ while (job.isBusy()) {
+ Thread.yield();
+ job.wait();
+ }
+ }
+ } catch (InterruptedException e1) {
+ throw new ImageOpException("INTERRUPTED: " + e1.getMessage());
+ }
+ */
- /*********************************************************
- * Initialize global variables
- *********************************************************/
- public void init(ServletConfig config) throws ServletException {
- super.init(config);
-
- // first we need an Utils to setup ServletOps UGLY!!
- util = new Utils(5);
- // servletOps takes a ServletConfig to get the config file name
- servletOp = new ServletOps(util, config);
- // then we can start reading parameters UGLY!!
-
- // Utils instance with debuglevel
- int debugLevel = servletOp.tryToGetInitParam("debug-level", 10);
- util = new Utils(debugLevel);
- // reset Util for ServletOps instance
- servletOp.setUtils(util);
- // image file to send in case of error
- String errorImgFileName = servletOp.tryToGetInitParam("error-image", "/docuserver/images/icons/scalerror.gif");
- errorImgFile = new File(errorImgFileName);
- // image file to send if access is denied
- String denyImgFileName = servletOp.tryToGetInitParam("denied-image", "/docuserver/images/icons/denied.gif");
- denyImgFile = new File(denyImgFileName);
- // base directories in order of preference (prescaled versions first)
- String baseDirList = servletOp.tryToGetInitParam("basedir-list", "/docuserver/scaled/small:/docuserver/images:/docuserver/scans/quellen");
- // split list into directories
- StringTokenizer dirs = new StringTokenizer(baseDirList, ":");
- int n = dirs.countTokens();
- // add directories into array
- baseDirs = new String[n];
- for (int i = 0; i < n; i++) {
- baseDirs[i] = dirs.nextToken();
- }
- // use authentication information
- String useAuth = servletOp.tryToGetInitParam("use-authorization", "true");
- if ((useAuth.indexOf("false") > 0)||(useAuth.indexOf("FALSE") > 0)) {
- useAuthentication = false;
- } else {
- useAuthentication = true;
- try {
- // DB version
- //authOp = new DBAuthOpsImpl(util);
- // XML version
- String cnfPath = servletOp.tryToGetInitParam("auth-file", "/docuserver/www/digitallibrary/WEB-INF/digilib-auth.xml");
- authOp = new XMLAuthOps(util, cnfPath);
- } catch (AuthOpException e) {
- throw new ServletException(e);
- }
- }
- // FileOps instance
- fileOp = new FileOps(util);
- // global DocuImage instance (don't reuse inside a request!)
- globalImage = new JAIDocuImage(util);
-// globalImage = new JIMIDocuImage(util);
- //globalImage = new ImageLoaderDocuImage(util);
-
- }
-
- /**Process the HTTP Get request*/
- public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
- util.dprintln(1, "The servlet has received a GET!");
- processRequest(request, response);
- }
-
- /**Process the HTTP Post request*/
- public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
- util.dprintln(1, "The servlet has received a POST!");
- processRequest(request, response);
- }
-
- /**Clean up resources*/
- public void destroy() {
- }
-
-/**********************************************************************
- * main request handler
- **********************************************************************/
+ logger.debug("servlet done in "
+ + (System.currentTimeMillis() - startTime));
- void processRequest(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
-
- // time for benchmarking
- long startTime = System.currentTimeMillis();
- // output mime/type
- String mimeType = "image/png";
-
- /**
- * parameters for a session
- */
-
- // scale the image file to fit window size
- boolean scaleToFit = true;
- // use heuristics (GIF?) to scale or not
- boolean forcedScale = false;
- // try prescaled images first
- boolean preScaledFirst = true;
- // interpolation to use for scaling
- int scaleQual = 0;
- // send html error message (or image file)
- boolean errorMsgHtml = false;
-
- /**
- * request parameter
- */
-
- // file/dir to load
- String param_fn = servletOp.tryToGetParam("fn", "", request);
- // page number
- int param_pn = servletOp.tryToGetParam("pn", 1, request);
- // destination image width
- int param_dw = servletOp.tryToGetParam("dw", 300, request);
- // destination image height
- int param_dh = servletOp.tryToGetParam("dh", 400, request);
- // relative area x_offset (0..1)
- float param_wx = servletOp.tryToGetParam("wx", 0f, request);
- // relative area y_offset
- float param_wy = servletOp.tryToGetParam("wy", 0f, request);
- // relative area width (0..1)
- float param_ww = servletOp.tryToGetParam("ww", 1f, request);
- // relative area height
- float param_wh = servletOp.tryToGetParam("wh", 1f, request);
- // scale factor (additional to dw/width, dh/height)
- float param_ws = servletOp.tryToGetParam("ws", 1f, request);
- // operation mode: flags separated by "+"
- String param_mo = servletOp.tryToGetParam("mo", "", request);
- // operation mode: "fit": always fit to page, "file": send as-is
- if (param_mo.indexOf("fit") >= 0) {
- scaleToFit = true;
- forcedScale = true;
- } else if (param_mo.indexOf("file") >= 0) {
- scaleToFit = false;
- forcedScale = true;
- }
- // operation mode: "errtxt": error message in html, "errimg": error image
- if (param_mo.indexOf("errtxt") >= 0) {
- errorMsgHtml = true;
- } else if (param_mo.indexOf("errimg") >= 0) {
- errorMsgHtml = false;
- }
- // operation mode: "q0" - "q2": interpolation quality
- if (param_mo.indexOf("q0") >= 0) {
- scaleQual = 0;
- } else if (param_mo.indexOf("q1") >= 0) {
- scaleQual = 1;
- } else if (param_mo.indexOf("q2") >= 0) {
- scaleQual = 2;
- }
- // operation mode: "lores": try to use scaled image, "hires": unscaled image
- if (param_mo.indexOf("lores") >= 0) {
- preScaledFirst = true;
- } else if (param_mo.indexOf("hires") >= 0) {
- preScaledFirst = false;
- }
-
- Utils.dprintln(1, "Parameter values: fn:"+param_fn+" pn:"+param_pn+" dw:"+param_dw+" dh:"+param_dh+" wx:"+param_wx+" wy:"+param_wy+" ww:"+param_ww+" wh:"+param_wh+" ws:"+param_ws+" mo:"+param_mo);
-
- //"big" try for all file/image actions
- try {
+ /* error handling */
- // DocuImage instance
- DocuImage docuImage = new JAIDocuImage(util);
-// DocuImage docuImage = new JIMIDocuImage(util);
- //DocuImage docuImage = new ImageLoaderDocuImage(util);
-
-
- /**
- * find the file to load/send
- */
-
- String loadPathName = "";
- // if there's PathInfo, append
- if (request.getPathInfo() != null) {
- loadPathName += request.getPathInfo();
- }
- // append fn parameter
- loadPathName += param_fn;
- // if it's zoomed, try hires version (to be optimized...)
- if ((param_ww < 1f) || (param_wh < 1f)) {
- preScaledFirst = false;
- }
-
- if (useAuthentication) {
- // check permissions
- List rolesRequired = authOp.rolesForPath(loadPathName, request);
- if (rolesRequired != null) {
- Utils.dprintln(1, "Role required: "+rolesRequired);
- Utils.dprintln(2, "User: "+request.getRemoteUser());
- if (! authOp.isRoleAuthorized(rolesRequired, request)) {
- Utils.dprintln(1, "ERROR: access denied!");
- if (errorMsgHtml) {
- servletOp.htmlMessage("ERROR: Unauthorized access!", response);
- } else {
- docuImage.sendFile(denyImgFile, response);
- }
- return;
- }
- }
- }
-
- // find the file
- File fileToLoad = fileOp.getFileVariant(baseDirs, loadPathName, param_pn, preScaledFirst);
-
- Utils.dprintln(1, "Loading: "+fileToLoad);
-
- // get the source image type (if it's known)
- mimeType = fileOp.mimeForFile(fileToLoad);
-
- // if not forced and source is GIF/PNG then send-as-is if not zoomed
- if((!forcedScale && (mimeType == "image/gif" || mimeType == "image/png")
- && (param_ww == 1f) && (param_wh == 1f)) || (forcedScale && !scaleToFit)) {
-
- Utils.dprintln(1, "Sending File as is.");
-
- docuImage.sendFile(fileToLoad, response);
-
- Utils.dprintln(1, "Done in "+(System.currentTimeMillis()-startTime)+"ms");
- return;
- }
-
- // load file
- docuImage.loadImage(fileToLoad);
-
- /**
- * crop and scale the image
- */
-
- // get size
- int imgWidth = docuImage.getWidth();
- int imgHeight = docuImage.getHeight();
-
- util.dprintln(2, "IMG: "+imgWidth+"x"+imgHeight);
- util.dprintln(2, "time "+(System.currentTimeMillis()-startTime)+"ms");
+ } // end of "big" try
+ catch (IOException e) {
+ logger.error("ERROR: File IO Error: " + e);
+ digilibError(errorMsgHtml, ERROR_FILE,
+ "ERROR: File IO Error: " + e, response);
+ } catch (AuthOpException e) {
+ logger.error("ERROR: Authorization error: " + e);
+ digilibError(errorMsgHtml, ERROR_AUTH,
+ "ERROR: Authorization error: " + e, response);
+ } catch (ImageOpException e) {
+ logger.error("ERROR: Image Error: " + e);
+ digilibError(errorMsgHtml, ERROR_IMAGE,
+ "ERROR: Image Operation Error: " + e, response);
+ } catch (RuntimeException e) {
+ // JAI likes to throw RuntimeExceptions ;-(
+ logger.error("ERROR: Other Image Error: " + e);
+ digilibError(errorMsgHtml, ERROR_IMAGE,
+ "ERROR: Other Image Operation Error: " + e, response);
+ }
+ }
+ /**
+ * Sends an error to the client as text or image.
+ *
+ * @param asHTML
+ * @param type
+ * @param msg
+ * @param response
+ */
+ public void digilibError(boolean asHTML, int type, String msg,
+ HttpServletResponse response) {
+ try {
+ File img = null;
+ if (type == ERROR_AUTH) {
+ if (msg == null) {
+ msg = "ERROR: Unauthorized access!";
+ }
+ img = denyImgFile;
+ } else {
+ if (msg == null) {
+ msg = "ERROR: Other image error!";
+ }
+ img = this.errorImgFile;
+ }
+ if (asHTML && (img != null)) {
+ ServletOps.htmlMessage(msg, response);
+ } else {
+ ServletOps.sendFile(img, null, response, fastQueue);
+ }
+ } catch (IOException e) {
+ logger.error("Error sending error!", e);
+ }
- // calculate absolute from relative coordinates
- float areaXoff = param_wx * imgWidth;
- float areaYoff = param_wy * imgHeight;
- float areaWidth = param_ww * imgWidth;
- float areaHeight = param_wh * imgHeight;
- // calculate scaling factors
- float scaleX = param_dw / areaWidth * param_ws;
- float scaleY = param_dh / areaHeight * param_ws;
- float scaleXY = (scaleX > scaleY) ? scaleY : scaleX;
-
- util.dprintln(1, "Scale "+scaleXY+"("+scaleX+","+scaleY+") on "+areaXoff+","+areaYoff+" "+areaWidth+"x"+areaHeight);
-
- // fit area to image
- areaWidth = (areaXoff + areaWidth > imgWidth) ? imgWidth - areaXoff : areaWidth;
- areaHeight = (areaYoff + areaHeight > imgHeight) ? imgHeight - areaYoff : areaHeight;
-
- util.dprintln(2, "cropped: "+areaXoff+","+areaYoff+" "+areaWidth+"x"+areaHeight);
-
- // check image parameters
- if ((areaWidth < 1)||(areaHeight < 1)
- ||(scaleXY * areaWidth < 2)||(scaleXY * areaHeight < 2)) {
- Utils.dprintln(1, "ERROR: invalid scale parameter set!");
- throw new ImageOpException("Invalid scale parameter set!");
- }
-
- // crop and scale image
- docuImage.cropAndScale((int)areaXoff, (int)areaYoff, (int)areaWidth, (int)areaHeight,
- scaleXY, scaleQual);
-
- util.dprintln(2, "time "+(System.currentTimeMillis()-startTime)+"ms");
-
- /**
- * write the resulting image
- */
-
- // setup output -- if source is JPG then dest will be JPG else it's PNG
- if (mimeType != "image/jpeg") {
- mimeType="image/png";
- }
-
- // write the image
- docuImage.writeImage(mimeType, response);
+ }
- util.dprintln(1, "Done in "+(System.currentTimeMillis()-startTime)+"ms");
-
- /**
- * error handling
- */
-
- }//"big" try
- catch (FileOpException e) {
- util.dprintln(1, "ERROR: File IO Error: "+e);
- try {
- if (errorMsgHtml) {
- servletOp.htmlMessage("ERROR: File IO Error: "+e, response);
- } else {
- globalImage.sendFile(errorImgFile, response);
- }
- } catch (FileOpException ex) {} // so we don't get a loop
- return;
- }
- catch (AuthOpException e) {
- Utils.dprintln(1, "ERROR: Authorization error: "+e);
- try {
- if (errorMsgHtml) {
- servletOp.htmlMessage("ERROR: Authorization error: "+e, response);
- } else {
- globalImage.sendFile(errorImgFile, response);
- }
- } catch (FileOpException ex) {} // so we don't get a loop
- return;
- }
- catch (ImageOpException e) {
- Utils.dprintln(1, "ERROR: Image Error: "+e);
- try {
- if (errorMsgHtml) {
- servletOp.htmlMessage("ERROR: Image Operation Error: "+e, response);
- } else {
- globalImage.sendFile(errorImgFile, response);
- }
- } catch (FileOpException ex) {} // so we don't get a loop
- return;
- }
-
- }
-
-}//Scaler class
+} //Scaler class
diff -r 9f7b864f955f -r 5d0c0da080ec servlet/src/digilib/servlet/ServletOps.java
--- a/servlet/src/digilib/servlet/ServletOps.java Mon Oct 18 15:40:54 2004 +0200
+++ b/servlet/src/digilib/servlet/ServletOps.java Thu Oct 21 20:53:37 2004 +0200
@@ -1,156 +1,217 @@
-/* ServletOps -- Servlet utility class
-
- Digital Image Library servlet components
-
- Copyright (C) 2001, 2002 Robert Casties (robcast@mail.berlios.de)
-
- This program is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published by the
- Free Software Foundation; either version 2 of the License, or (at your
- option) any later version.
-
- Please read license.txt for the full details. A copy of the GPL
- may be found at http://www.gnu.org/copyleft/lgpl.html
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-
-*/
+/*
+ * ServletOps -- Servlet utility class
+ *
+ * Digital Image Library servlet components
+ *
+ * Copyright (C) 2001, 2002 Robert Casties (robcast@mail.berlios.de)
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * Please read license.txt for the full details. A copy of the GPL may be found
+ * at http://www.gnu.org/copyleft/lgpl.html
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
package digilib.servlet;
-import javax.servlet.*;
-import javax.servlet.http.*;
-import java.io.*;
-import java.util.*;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.util.StringTokenizer;
-import digilib.*;
-import digilib.io.*;
+import javax.servlet.ServletConfig;
+import javax.servlet.http.HttpServletResponse;
+import org.apache.log4j.Logger;
+
+import EDU.oswego.cs.dl.util.concurrent.Executor;
+import digilib.io.FileOpException;
+import digilib.io.FileOps;
public class ServletOps {
- private Utils util = null;
- private Hashtable confTable = null;
-
- public ServletOps() {
- util = new Utils();
- }
+ private static Logger logger = Logger.getLogger("servlet.op");
- public ServletOps(Utils u) {
- util = u;
- }
+ /**
+ * convert a string with a list of pathnames into an array of strings using
+ * the system's path seperator string
+ */
+ public static String[] getPathArray(String paths) {
+ // split list into directories
+ StringTokenizer dirs = new StringTokenizer(paths,
+ java.io.File.pathSeparator);
+ int n = dirs.countTokens();
+ if (n < 1) {
+ return null;
+ }
+ // add directories into array
+ String[] pathArray = new String[n];
+ for (int i = 0; i < n; i++) {
+ pathArray[i] = dirs.nextToken();
+ }
+ return pathArray;
+ }
- public ServletOps(Utils u, ServletConfig sc) throws ServletException {
- util = u;
- setConfig(sc);
- }
-
- public void setUtils(Utils u) {
- util = u;
- }
+ /**
+ * get a real File for a config File.
+ *
+ * If the File is not absolute the path is appended to the WEB-INF directory
+ * of the web-app.
+ *
+ * @param file
+ * @param sc
+ * @return
+ */
+ public static File getConfigFile(File f, ServletConfig sc) {
+ // is the filename absolute?
+ if (!f.isAbsolute()) {
+ // relative path -> use getRealPath to resolve in WEB-INF
+ String fn = sc.getServletContext().getRealPath(
+ "WEB-INF/" + f.getPath());
+ f = new File(fn);
+ }
+ return f;
+ }
- /**
- * read parameter list from the XML file in init parameter "config-file"
- */
- public void setConfig(ServletConfig c) throws ServletException {
- // reset parameter table
- confTable = null;
- if (c == null) {
- return;
- }
- // get config file name
- String fn = c.getInitParameter("config-file");
- if (fn == null) {
- util.dprintln(4, "setConfig: no param config-file");
- return;
- }
- File f = new File(fn);
- // setup config file list reader
- XMLListLoader lilo = new XMLListLoader("digilib-config", "parameter", "name", "value");
- try {
- confTable = lilo.loadURL(f.toURL().toString());
- } catch (Exception e) {
- util.dprintln(4, "setConfig: unable to read file "+fn);
- throw new ServletException(e);
- }
- }
+ /**
+ * get a real file name for a config file pathname.
+ *
+ * If filename starts with "/" its treated as absolute else the path is
+ * appended to the WEB-INF directory of the web-app.
+ *
+ * @param filename
+ * @param sc
+ * @return
+ */
+ public static String getConfigFile(String filename, ServletConfig sc) {
+ File f = new File(filename);
+ // is the filename absolute?
+ if (!f.isAbsolute()) {
+ // relative path -> use getRealPath to resolve in WEB-INF
+ filename = sc.getServletContext()
+ .getRealPath("WEB-INF/" + filename);
+ }
+ return filename;
+ }
- /**
- * print a servlet response and exit
- */
- public static void htmlMessage(String s, HttpServletResponse response) throws IOException {
- response.setContentType("text/html; charset=iso-8859-1");
- PrintWriter out = response.getWriter();
- out.println("");
- out.println("
"+s+"
"); - out.println(""); - } + /** + * print a servlet response and exit + */ + public static void htmlMessage(String msg, HttpServletResponse response) + throws IOException { + htmlMessage("Scaler", msg, response); + } + + /** + * print a servlet response and exit + */ + public static void htmlMessage(String title, String msg, + HttpServletResponse response) throws IOException { + response.setContentType("text/html; charset=iso-8859-1"); + PrintWriter out = response.getWriter(); + out.println(""); + out.println("" + msg + "
"); + out.println(""); + } - /** - * get a parameter from request and return it if set, otherwise return default - */ - public int tryToGetParam(String s, int i, HttpServletRequest r) { - try { - i = Integer.parseInt(r.getParameter(s)); - } catch(Exception e) { - util.dprintln(4, "trytoGetParam(int) failed on param "+s); - //e.printStackTrace(); - } - return i; - } - public float tryToGetParam(String s, float f, HttpServletRequest r) { - try { - f = Float.parseFloat(r.getParameter(s)); - } catch(Exception e) { - util.dprintln(4, "trytoGetParam(float) failed on param "+s); - //e.printStackTrace(); - } - return f; - } - public String tryToGetParam(String s, String x, HttpServletRequest r) { - if (r.getParameter(s) != null) { - x = r.getParameter(s); - } else { - util.dprintln(4, "trytoGetParam(string) failed on param "+s); - } - return x; - } - + /** + * Transfers an image file as-is with the mime type mt. + * + * The local file is copied to theOutputStream
of the
+ * ServletResponse
. If mt is null then the mime-type is
+ * auto-detected with mimeForFile.
+ *
+ * @param mt
+ * mime-type of the file.
+ * @param f
+ * Image file to be sent.
+ * @param res
+ * ServletResponse where the image file will be sent.
+ * @throws FileOpException
+ * Exception is thrown for a IOException.
+ */
+ public static void sendFileImmediately(File f, String mt,
+ HttpServletResponse response) throws FileOpException {
+ logger.debug("sendRawFile(" + mt + ", " + f + ")");
+ if (mt == null) {
+ // auto-detect mime-type
+ mt = FileOps.mimeForFile(f);
+ if (mt == null) {
+ throw new FileOpException("Unknown file type.");
+ }
+ }
+ response.setContentType(mt);
+ // open file
+ try {
+ if (mt.equals("application/octet-stream")) {
+ response.addHeader("Content-Disposition",
+ "attachment; filename=\"" + f.getName() + "\"");
+ }
+ FileInputStream inFile = new FileInputStream(f);
+ OutputStream outStream = response.getOutputStream();
+ byte dataBuffer[] = new byte[4096];
+ int len;
+ while ((len = inFile.read(dataBuffer)) != -1) {
+ // copy out file
+ outStream.write(dataBuffer, 0, len);
+ }
+ inFile.close();
+ response.flushBuffer();
+ } catch (IOException e) {
+ throw new FileOpException("Unable to send file.");
+ }
+ }
- /**
- * get an init parameter from config and return it if set, otherwise return default
- */
- public int tryToGetInitParam(String s, int i) {
- //System.out.println("trytogetInitParam("+s+", "+i+")");
- try {
- //System.out.println("trytogetInitParam: "+(String)confTable.get(s));
- i = Integer.parseInt((String)confTable.get(s));
- } catch(Exception e) {
- util.dprintln(4, "trytogetInitParam(int) failed on param "+s);
- //e.printStackTrace();
- }
- return i;
- }
- public float tryToGetInitParam(String s, float f) {
- try {
- f = Float.parseFloat((String)confTable.get(s));
- } catch(Exception e) {
- util.dprintln(4, "trytoGetInitParam(float) failed on param "+s);
- //e.printStackTrace();
- }
- return f;
- }
- public String tryToGetInitParam(String s, String x) {
- if ((confTable != null)&&((String)confTable.get(s) != null)) {
- x = (String)confTable.get(s);
- } else {
- util.dprintln(4, "trytoGetInitParam(string) failed on param "+s);
- }
- return x;
- }
+ /**
+ * Transfers an image file as-is with the mime type mt using a work queue.
+ *
+ * The local file is copied to the OutputStream
of the
+ * ServletResponse
. If mt is null then the mime-type is
+ * auto-detected with mimeForFile.
+ *
+ * @param mt
+ * mime-type of the file.
+ * @param f
+ * Image file to be sent.
+ * @param res
+ * ServletResponse where the image file will be sent.
+ * @throws FileOpException
+ * Exception is thrown for a IOException.
+ */
+ public static void sendFile(File f, String mimetype,
+ HttpServletResponse response, Executor workQueue)
+ throws FileOpException {
+ // we're cheating
+ sendFileImmediately(f, mimetype, response);
+ /*
+ // create worker
+ DigilibSender job = new DigilibSender(f, null, response);
+ try {
+ logger.debug("queue size: "
+ + ((DigilibManager) workQueue).getQueueSize());
+ workQueue.execute(job);
+ logger.debug("job sent!");
+ synchronized (job) {
+ while (job.isBusy()) {
+ job.wait();
+ }
+ }
+ } catch (InterruptedException e) {
+ throw new FileOpException("INTERRUPTED: Unable to send file. " + e);
+ }
+ */
-}
+ }
+
+}
\ No newline at end of file
diff -r 9f7b864f955f -r 5d0c0da080ec servlet/src/digilib/servlet/Texter.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/servlet/src/digilib/servlet/Texter.java Thu Oct 21 20:53:37 2004 +0200
@@ -0,0 +1,189 @@
+/* Texter.java -- Servlet for displaying text
+ * Digital Image Library servlet components
+ * Copyright (C) 2003 Robert Casties (robcast@mail.berlios.de)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version. Please read license.txt for the full details. A copy of
+ * the GPL may be found at http://www.gnu.org/copyleft/lgpl.html
+ * You should have received a copy of the GNU General Public License along with this
+ * program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Created on 15.09.2003 by casties
+ */
+
+package digilib.servlet;
+
+import java.io.IOException;
+
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.log4j.Logger;
+
+import digilib.auth.AuthOps;
+import digilib.io.DocuDirCache;
+import digilib.io.FileOpException;
+import digilib.io.FileOps;
+import digilib.io.TextFile;
+
+/**
+ * Servlet for displaying text
+ *
+ *
+ * @author casties
+ *
+ */
+public class Texter extends HttpServlet {
+
+ private static final long serialVersionUID = -8539178734033662322L;
+
+ /** Servlet version */
+ public static String tlVersion = "0.1b1";
+
+ /** DigilibConfiguration instance */
+ DigilibConfiguration dlConfig = null;
+
+ /** general logger */
+ Logger logger = Logger.getLogger("digilib.texter");
+
+ /** FileOps instance */
+ FileOps fileOp;
+
+ /** AuthOps instance */
+ AuthOps authOp;
+
+ /** ServletOps instance */
+ ServletOps servletOp;
+
+ /** DocuDirCache instance */
+ DocuDirCache dirCache;
+
+ /** use authentication */
+ boolean useAuthentication = false;
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see javax.servlet.Servlet#init(javax.servlet.ServletConfig)
+ */
+ public void init(ServletConfig config) throws ServletException {
+ super.init(config);
+
+ System.out.println("***** Digital Image Library Text Servlet (version "
+ + tlVersion + ") *****");
+
+ // get our ServletContext
+ ServletContext context = config.getServletContext();
+ // see if there is a Configuration instance
+ dlConfig = (DigilibConfiguration) context
+ .getAttribute("digilib.servlet.configuration");
+ if (dlConfig == null) {
+ // no Configuration
+ throw new ServletException("No Configuration!");
+ }
+ // say hello in the log file
+ logger.info("***** Digital Image Library Text Servlet (version "
+ + tlVersion + ") *****");
+
+ // set our AuthOps
+ useAuthentication = dlConfig.getAsBoolean("use-authorization");
+ authOp = (AuthOps) dlConfig.getValue("servlet.auth.op");
+ // DocuDirCache instance
+ dirCache = (DocuDirCache) dlConfig.getValue("servlet.dir.cache");
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest,
+ * javax.servlet.http.HttpServletResponse)
+ */
+ protected void doGet(HttpServletRequest request,
+ HttpServletResponse response) throws ServletException, IOException {
+ // create new request with defaults
+ DigilibRequest dlReq = new DigilibRequest();
+ // set with request parameters
+ dlReq.setWithRequest(request);
+ // add DigilibRequest to ServletRequest
+ request.setAttribute("digilib.servlet.request", dlReq);
+ // do the processing
+ processRequest(request, response);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see javax.servlet.http.HttpServlet#doPost(javax.servlet.http.HttpServletRequest,
+ * javax.servlet.http.HttpServletResponse)
+ */
+ protected void doPost(HttpServletRequest request,
+ HttpServletResponse response) throws ServletException, IOException {
+ // create new request with defaults
+ DigilibRequest dlReq = new DigilibRequest();
+ // set with request parameters
+ dlReq.setWithRequest(request);
+ // add DigilibRequest to ServletRequest
+ request.setAttribute("digilib.servlet.request", dlReq);
+ // do the processing
+ processRequest(request, response);
+ }
+
+protected void processRequest(HttpServletRequest request,
+ HttpServletResponse response) throws ServletException, IOException {
+
+ /*
+ * request parameters
+ */
+ DigilibRequest dlRequest = (DigilibRequest) request.getAttribute("digilib.servlet.request");
+ try {
+
+ /*
+ * find the file to load/send
+ */
+ TextFile f = getTextFile(dlRequest, "/txt");
+ if (f != null) {
+ ServletOps.sendFileImmediately(f.getFile(), null, response);
+ } else {
+ f = getTextFile(dlRequest, "");
+ if (f != null) {
+ ServletOps.sendFileImmediately(f.getFile(), null, response);
+ } else {
+ ServletOps.htmlMessage("No Text-File!", response);
+ }
+ }
+
+ } catch (FileOpException e) {
+ logger.error("ERROR: File IO Error: ", e);
+ try {
+ ServletOps.htmlMessage("ERROR: File IO Error: " + e, response);
+ } catch (FileOpException ex) {
+ } // so we don't get a loop
+ }
+ }
+
+
+ /**
+ * Looks for a file in the given subDirectory.
+ *
+ * @param dlRequest
+ * The received request which has the file path.
+ * @param subDirectory
+ * The subDirectory of the file path where the file should
+ * be found.
+ * @return The wanted Textfile or null if there wasn't a file.
+ */
+
+ private TextFile getTextFile(DigilibRequest dlRequest, String subDirectory) {
+ String loadPathName = dlRequest.getFilePath() + subDirectory;
+ // find the file(set)
+ return (TextFile) dirCache.getFile(loadPathName, dlRequest
+ .getAsInt("pn"), FileOps.CLASS_TEXT);
+ }
+}
\ No newline at end of file