Mercurial > hg > digilib
changeset 1196:2c448b6b21da
starting IIIF image api parser.
author | robcast |
---|---|
date | Wed, 17 Jul 2013 10:45:41 +0200 |
parents | 2cba651b91ce |
children | e7608a7205e1 |
files | common/src/main/java/digilib/conf/DigilibRequest.java servlet/src/main/java/digilib/conf/DigilibServletRequest.java |
diffstat | 2 files changed, 358 insertions(+), 297 deletions(-) [+] |
line wrap: on
line diff
--- a/common/src/main/java/digilib/conf/DigilibRequest.java Tue Jul 16 13:39:22 2013 +0200 +++ b/common/src/main/java/digilib/conf/DigilibRequest.java Wed Jul 17 10:45:41 2013 +0200 @@ -33,6 +33,8 @@ import java.net.URLDecoder; import java.util.StringTokenizer; +import org.apache.log4j.Logger; + import digilib.image.ImageJobDescription; import digilib.io.FileOps; import digilib.util.OptionsSet; @@ -42,7 +44,7 @@ /** * Class holding the parameters of a digilib user request. The parameters are * mostly named like the servlet parameters: <br> - * request_path: url of the page/document. <br> + * request.path: url of the page/document. <br> * fn: url of the page/document. <br> * pn: page number. <br> * dw: width of result window in pixels. <br> @@ -52,10 +54,7 @@ * ww: width of image area(float from 0 to 1). <br> * wh: height of image area(float from 0 to 1). <br> * ws: scale factor. <br> - * mo: special options like 'fit' for gifs. <br> - * mk: list of marks. <br> - * pt: total number of pages (generated by sevlet). <br> - * baseURL: base URL (from http:// to below /servlet). <br> + * mo: special options like 'fit'. <br> * ...et alii * * @author casties @@ -63,19 +62,24 @@ */ public class DigilibRequest extends ParameterMap { - /** ImageJobDescription for this request */ - protected ImageJobDescription ticket; - - /** DigilibConfiguration for this request */ - protected DigilibConfiguration config; + private static Logger logger = Logger.getLogger("digilib.request"); + + // TODO: make prefix configurable + public static final String iiifPrefix = "iiif"; + + /** ImageJobDescription for this request */ + protected ImageJobDescription ticket; - public DigilibRequest() { - super(30); - } + /** DigilibConfiguration for this request */ + protected DigilibConfiguration config; - /** - * Create DigilibRequest with DigilibConfiguration. - * + public DigilibRequest() { + super(30); + } + + /** + * Create DigilibRequest with DigilibConfiguration. + * * @param config */ public DigilibRequest(DigilibConfiguration config) { @@ -83,90 +87,85 @@ this.config = config; } - /** set up parameters. - * - */ - protected void initParams() { - /* - * Definition of parameters and default values. Parameter of type 's' - * are for the servlet. - */ + /** + * set up parameters. + * + */ + protected void initParams() { + /* + * Definition of parameters and default values. Parameter of type 's' + * are for the servlet. + */ - // url of the page/document (second part) - newParameter("fn", "", null, 's'); - // page number - newParameter("pn", new Integer(1), null, 's'); - // width of client in pixels - newParameter("dw", new Integer(0), null, 's'); - // height of client in pixels - newParameter("dh", new Integer(0), null, 's'); - // left edge of image (float from 0 to 1) - newParameter("wx", new Float(0), null, 's'); - // top edge in image (float from 0 to 1) - newParameter("wy", new Float(0), null, 's'); - // width of image (float from 0 to 1) - newParameter("ww", new Float(1), null, 's'); - // height of image (float from 0 to 1) - newParameter("wh", new Float(1), null, 's'); - // scale factor - newParameter("ws", new Float(1), null, 's'); - // special options like 'fit' for gifs - newParameter("mo", this.options, null, 's'); - // rotation angle (degree) - newParameter("rot", new Float(0), null, 's'); - // contrast enhancement factor - newParameter("cont", new Float(0), null, 's'); - // brightness enhancement factor - newParameter("brgt", new Float(0), null, 's'); - // color multiplicative factors - newParameter("rgbm", "0/0/0", null, 's'); - // color additive factors - newParameter("rgba", "0/0/0", null, 's'); - // display dpi resolution (total) - newParameter("ddpi", new Float(0), null, 's'); - // display dpi X resolution - newParameter("ddpix", new Float(0), null, 's'); - // display dpi Y resolution - newParameter("ddpiy", new Float(0), null, 's'); - // scale factor for mo=ascale - newParameter("scale", new Float(1), null, 's'); - // color conversion operation - newParameter("colop", "", null, 's'); + // url of the page/document (second part) + newParameter("fn", "", null, 's'); + // page number + newParameter("pn", new Integer(1), null, 's'); + // width of client in pixels + newParameter("dw", new Integer(0), null, 's'); + // height of client in pixels + newParameter("dh", new Integer(0), null, 's'); + // left edge of image (float from 0 to 1) + newParameter("wx", new Float(0), null, 's'); + // top edge in image (float from 0 to 1) + newParameter("wy", new Float(0), null, 's'); + // width of image (float from 0 to 1) + newParameter("ww", new Float(1), null, 's'); + // height of image (float from 0 to 1) + newParameter("wh", new Float(1), null, 's'); + // scale factor + newParameter("ws", new Float(1), null, 's'); + // special options like 'fit' for gifs + newParameter("mo", this.options, null, 's'); + // rotation angle (degree) + newParameter("rot", new Float(0), null, 's'); + // contrast enhancement factor + newParameter("cont", new Float(0), null, 's'); + // brightness enhancement factor + newParameter("brgt", new Float(0), null, 's'); + // color multiplicative factors + newParameter("rgbm", "0/0/0", null, 's'); + // color additive factors + newParameter("rgba", "0/0/0", null, 's'); + // display dpi resolution (total) + newParameter("ddpi", new Float(0), null, 's'); + // display dpi X resolution + newParameter("ddpix", new Float(0), null, 's'); + // display dpi Y resolution + newParameter("ddpiy", new Float(0), null, 's'); + // scale factor for mo=ascale + newParameter("scale", new Float(1), null, 's'); + // color conversion operation + newParameter("colop", "", null, 's'); - /* - * Parameters of type 'i' are not exchanged between client and server, - * but are for the servlets or JSPs internal use. - */ + /* + * Parameters of type 'i' are not exchanged between client and server, + * but are for the servlets or JSPs internal use. + */ - // url of the page/document (first part, may be empty) - newParameter("request.path", "", null, 'i'); - // base URL (from http:// to below /servlet) - newParameter("base.url", null, null, 'i'); - /* - * Parameters of type 'c' are for the clients use - */ + // url of the page/document (first part, may be empty) + newParameter("request.path", "", null, 'i'); + // base URL (from http:// to below /servlet) + newParameter("base.url", null, null, 'i'); + /* + * Parameters of type 'c' are for the clients use + */ - // "real" filename - newParameter("img.fn", "", null, 'c'); - // image dpi x - newParameter("img.dpix", new Integer(0), null, 'c'); - // image dpi y - newParameter("img.dpiy", new Integer(0), null, 'c'); - // hires image size x - newParameter("img.pix_x", new Integer(0), null, 'c'); - // hires image size y - newParameter("img.pix_y", new Integer(0), null, 'c'); - // total number of pages - newParameter("pt", new Integer(0), null, 'c'); - // display level of digilib (0 = just image, 1 = one HTML page - // 2 = in frameset, 3 = XUL-'frameset' - // 4 = XUL-Sidebar ) - newParameter("lv", new Integer(2), null, 'c'); - // marks - newParameter("mk", "", null, 'c'); - } + // "real" filename + newParameter("img.fn", "", null, 'c'); + // image dpi x + newParameter("img.dpix", new Integer(0), null, 'c'); + // image dpi y + newParameter("img.dpiy", new Integer(0), null, 'c'); + // hires image size x + newParameter("img.pix_x", new Integer(0), null, 'c'); + // hires image size y + newParameter("img.pix_y", new Integer(0), null, 'c'); + } - /* (non-Javadoc) + /* + * (non-Javadoc) + * * @see digilib.servlet.ParameterMap#initOptions() */ @Override @@ -174,127 +173,238 @@ options = (OptionsSet) getValue("mo"); } - /** - * Return the request parameters as a String in the parameter form - * 'fn=/icons&pn=1'. Empty (undefined) fields are not included. - * - * @return String of request parameters in parameter form. - */ - public String getAsString() { - return getAsString(0); - } + /** + * Return the request parameters as a String in the parameter form + * 'fn=/icons&pn=1'. Empty (undefined) fields are not included. + * + * @return String of request parameters in parameter form. + */ + public String getAsString() { + return getAsString(0); + } - /** - * Return the request parameters of a given type type as a String in the - * parameter form 'fn=/icons&pn=1'. Empty (undefined) fields are not - * included. - * - * @return String of request parameters in parameter form. - */ - public String getAsString(int type) { - StringBuffer s = new StringBuffer(50); - // go through all values - for (Parameter p: params.values()) { - if ((type > 0) && (p.getType() != type)) { - // skip the wrong types - continue; - } - String name = p.getName(); - /* - * handling special cases - */ - // request_path adds to fn - if (name.equals("fn")) { - s.append("&fn=" + getAsString("request.path") - + getAsString("fn")); - continue; - } - /* - * the rest is sent with its name - */ - // parameters that are not set or internal are not sent - if ((!p.hasValue()) || (p.getType() == 'i')) { - continue; - } - s.append("&" + name + "=" + p.getAsString()); - } - // kill first "&" - s.deleteCharAt(0); - return s.toString(); - } + /** + * Return the request parameters of a given type type as a String in the + * parameter form 'fn=/icons&pn=1'. Empty (undefined) fields are not + * included. + * + * @return String of request parameters in parameter form. + */ + public String getAsString(int type) { + StringBuffer s = new StringBuffer(50); + // go through all values + for (Parameter p : params.values()) { + if ((type > 0) && (p.getType() != type)) { + // skip the wrong types + continue; + } + String name = p.getName(); + /* + * handling special cases + */ + // request_path adds to fn + if (name.equals("fn")) { + s.append("&fn=" + getAsString("request.path") + getAsString("fn")); + continue; + } + /* + * the rest is sent with its name + */ + // parameters that are not set or internal are not sent + if ((!p.hasValue()) || (p.getType() == 'i')) { + continue; + } + s.append("&" + name + "=" + p.getAsString()); + } + // kill first "&" + s.deleteCharAt(0); + return s.toString(); + } + + /** + * Set request parameters from query string. Uses the separator string qs to + * get 'fn=foo' style parameters. + * + * @param qs + * query string + * @param sep + * parameter-separator string + */ + public void setWithParamString(String qs, String sep) { + // go through all request parameters + String[] qa = qs.split(sep); + for (int i = 0; i < qa.length; i++) { + // split names and values on "=" + String[] nv = qa[i].split("="); + try { + String name = URLDecoder.decode(nv[0], "UTF-8"); + String val = URLDecoder.decode(nv[1], "UTF-8"); + // is this a known parameter? + if (params.containsKey(name)) { + Parameter p = (Parameter) this.get(name); + // internal parameters are not set + if (p.getType() == 'i') { + continue; + } + p.setValueFromString(val); + continue; + } + // unknown parameters are just added with type 'r' + newParameter(name, null, val, 'r'); + } catch (UnsupportedEncodingException e) { + // this shouldn't happen anyway + e.printStackTrace(); + } + } + } - /** - * Set request parameters from query string. Uses the separator string qs to - * get 'fn=foo' style parameters. - * - * @param qs - * query string - * @param sep - * parameter-separator string - */ - public void setWithParamString(String qs, String sep) { - // go through all request parameters - String[] qa = qs.split(sep); - for (int i = 0; i < qa.length; i++) { - // split names and values on "=" - String[] nv = qa[i].split("="); - try { - String name = URLDecoder.decode(nv[0], "UTF-8"); - String val = URLDecoder.decode(nv[1], "UTF-8"); - // is this a known parameter? - if (params.containsKey(name)) { - Parameter p = (Parameter) this.get(name); - // internal parameters are not set - if (p.getType() == 'i') { - continue; - } - p.setValueFromString(val); - continue; - } - // unknown parameters are just added with type 'r' - newParameter(name, null, val, 'r'); - } catch (UnsupportedEncodingException e) { - // this shouldn't happen anyway - e.printStackTrace(); - } - } - } + /** + * Populate a request from a string with an IIIF Image API path. + * + * @param path + * String with IIIF Image API path. + * + * @see <a href="http://www-sul.stanford.edu/iiif/image-api/1.1/">IIIF Image + * API</a> + */ + public void setWithIiifPath(String path) { + if (path == null) { + return; + } + // enable the passing of delimiter to get empty parameters + StringTokenizer query = new StringTokenizer(path, "/", true); + String token; + // first parameter prefix + if (query.hasMoreTokens()) { + token = query.nextToken(); + if (!token.equals(iiifPrefix)) { + logger.error("IIIF path doesn't start with prefix!"); + // what now? + } + // skip / + if (query.hasMoreTokens()) { + query.nextToken(); + } + } + // second parameter FN (encoded) + if (query.hasMoreTokens()) { + token = query.nextToken(); + if (!token.equals("/")) { + try { + setValueFromString("fn", URLDecoder.decode(token, "UTF-8")); + } catch (UnsupportedEncodingException e) { + logger.error("Error decoding identifier in IIIF path!"); + } + // skip / + if (query.hasMoreTokens()) { + query.nextToken(); + } + } + } + // third parameter region + if (query.hasMoreTokens()) { + token = query.nextToken(); + if (!token.equals("/")) { + if (token.equals("full")) { + // full region -- default + } else if (token.startsWith("pct:")){ + // region in % of original image + String[] params = token.substring(4).split(","); + try { + float x = Float.parseFloat(params[0]); + setValue("wx", x / 100f); + float y = Float.parseFloat(params[1]); + setValue("wy", y / 100f); + float w = Float.parseFloat(params[2]); + setValue("ww", w / 100f); + float h = Float.parseFloat(params[3]); + setValue("wh", h / 100f); + } catch (Exception e) { + logger.error("Error parsing range parameter in IIIF path!"); + } + } else { + // region in pixel of original image :-( + logger.error("pixel region not yet implemented"); + } + // skip / + if (query.hasMoreTokens()) { + query.nextToken(); + } + } + } + // fourth parameter size + if (query.hasMoreTokens()) { + token = query.nextToken(); + if (!token.equals("/")) { + // TODO + setValueFromString("mo", token); + // skip / + if (query.hasMoreTokens()) { + query.nextToken(); + } + } + } + // fifth parameter rotation + if (query.hasMoreTokens()) { + token = query.nextToken(); + if (!token.equals("/")) { + setValueFromString("rot", token); + // skip / + if (query.hasMoreTokens()) { + query.nextToken(); + } + } + } + // sixth parameter quality.format + if (query.hasMoreTokens()) { + token = query.nextToken(); + if (!token.equals("/")) { + // TODO + setValueFromString("wx", token); + // skip / + if (query.hasMoreTokens()) { + query.nextToken(); + } + } + } + } - /** - * Test if option string <code>opt</code> is set. Checks if the substring - * <code>opt</code> is contained in the options string <code>param</code>. - * Deprecated! use hasOption(String opt) for "mo"-options. - * - * @param opt - * Option string to be tested. - * @return boolean - */ - public boolean hasOption(String param, String opt) { - String s = getAsString(param); - if (s != null) { - StringTokenizer i = new StringTokenizer(s, ","); - while (i.hasMoreTokens()) { - if (i.nextToken().equals(opt)) { - return true; - } - } - } - return false; - } + /** + * Test if option string <code>opt</code> is set. Checks if the substring + * <code>opt</code> is contained in the options string <code>param</code>. + * + * @param opt + * Option string to be tested. + * @return boolean + * + * @deprecated use hasOption(String opt) for "mo"-options. + */ + public boolean hasOption(String param, String opt) { + String s = getAsString(param); + if (s != null) { + StringTokenizer i = new StringTokenizer(s, ","); + while (i.hasMoreTokens()) { + if (i.nextToken().equals(opt)) { + return true; + } + } + } + return false; + } - /** - * The image file path to be accessed. - * - * The mage file path is assembled from the servlets RequestPath and - * Parameter fn and normalized. - * - * @return String the effective filepath. - */ - public String getFilePath() { - String s = getAsString("request.path"); - s += getAsString("fn"); - return FileOps.normalName(s); - } + /** + * The image file path to be accessed. + * + * The image file path is assembled from the servlets RequestPath and + * Parameter fn and normalized. + * + * @return String the effective filepath. + */ + public String getFilePath() { + String s = getAsString("request.path"); + s += getAsString("fn"); + return FileOps.normalName(s); + } /** * @return the ticket @@ -304,7 +414,8 @@ } /** - * @param ticket the ticket to set + * @param ticket + * the ticket to set */ public void setJobDescription(ImageJobDescription ticket) { this.ticket = ticket; @@ -318,7 +429,8 @@ } /** - * @param config the config to set + * @param config + * the config to set */ public void setDigilibConfig(DigilibConfiguration config) { this.config = config;
--- a/servlet/src/main/java/digilib/conf/DigilibServletRequest.java Tue Jul 16 13:39:22 2013 +0200 +++ b/servlet/src/main/java/digilib/conf/DigilibServletRequest.java Wed Jul 17 10:45:41 2013 +0200 @@ -27,8 +27,6 @@ * Christian Luginbuehl */ -import java.io.UnsupportedEncodingException; -import java.net.URLDecoder; import java.util.Enumeration; import java.util.StringTokenizer; @@ -171,10 +169,13 @@ newParameter("img.pix_x", new Integer(0), null, 'c'); // hires image size y newParameter("img.pix_y", new Integer(0), null, 'c'); - // total number of pages - newParameter("pt", new Integer(0), null, 'c'); - // marks - newParameter("mk", "", null, 'c'); + /* + * TODO: check if we can remove these + * // total number of pages + * newParameter("pt", new Integer(0), null, 'c'); + * // marks + * newParameter("mk", "", null, 'c'); + */ } /* @@ -195,25 +196,32 @@ */ public void setWithRequest(HttpServletRequest request) { servletRequest = request; - // decide if it's old-style or new-style - String qs = ((HttpServletRequest) request).getQueryString(); - if (qs != null) { - if (qs.indexOf("&") > -1) { - // & separator - setWithParamString(qs, "&"); - } else if (qs.indexOf(";") > -1) { - // ; separator - setWithParamString(qs, ";"); - } else if (qs.indexOf('=') > -1) { - // standard '&' parameters - setWithParamRequest(request); - } else { - setWithOldString(qs); + setValue("servlet.request", request); + // request path (after servlet, before "?") + String path = ((HttpServletRequest) request).getPathInfo(); + // decide if its IIIF API + if (path != null && path.startsWith(iiifPrefix, 1)) { + setWithIiifPath(path.substring(1)); + } else { + // decide if it's old-style or new-style digilib + String qs = ((HttpServletRequest) request).getQueryString(); + if (qs != null) { + if (qs.indexOf("&") > -1) { + // & separator + setWithParamString(qs, "&"); + } else if (qs.indexOf(";") > -1) { + // ; separator + setWithParamString(qs, ";"); + } else if (qs.indexOf('=') > -1) { + // standard '&' parameters + setWithParamRequest(request); + } else { + setWithOldString(qs); + } } + // add path from request + setValue("request.path", path); } - setValue("servlet.request", request); - // add path from request - setValue("request.path", ((HttpServletRequest) request).getPathInfo()); // set the baseURL setBaseURL((HttpServletRequest) request); } @@ -423,65 +431,6 @@ setValue("request.path", ((HttpServletRequest) request).getPathInfo()); } - /** - * Set request parameters from query string. Uses the separator string qs to - * get 'fn=foo' style parameters. - * - * @param qs - * query string - * @param sep - * parameter-separator string - */ - public void setWithParamString(String qs, String sep) { - // go through all request parameters - String[] qa = qs.split(sep); - for (int i = 0; i < qa.length; i++) { - // split names and values on "=" - String[] nv = qa[i].split("="); - try { - String name = URLDecoder.decode(nv[0], "UTF-8"); - String val = URLDecoder.decode(nv[1], "UTF-8"); - // is this a known parameter? - if (params.containsKey(name)) { - Parameter p = (Parameter) this.get(name); - // internal parameters are not set - if (p.getType() == 'i') { - continue; - } - p.setValueFromString(val); - continue; - } - // unknown parameters are just added with type 'r' - newParameter(name, null, val, 'r'); - } catch (UnsupportedEncodingException e) { - // this shouldn't happen anyway - e.printStackTrace(); - } - } - } - - /** - * Test if option string <code>opt</code> is set. Checks if the substring - * <code>opt</code> is contained in the options string <code>param</code>. - * Deprecated! use hasOption(String opt) for "mo"-options. - * - * @param opt - * Option string to be tested. - * @return boolean - */ - public boolean hasOption(String param, String opt) { - String s = getAsString(param); - if (s != null) { - StringTokenizer i = new StringTokenizer(s, ","); - while (i.hasMoreTokens()) { - if (i.nextToken().equals(opt)) { - return true; - } - } - } - return false; - } - /* Property getter and setter */ /** @@ -495,7 +444,7 @@ String baseURL = null; // calculate base URL string from request until webapp String s = request.getRequestURL().toString(); - // get name of webapp + // get name of webapp String wn = request.getContextPath(); int eop = s.lastIndexOf(wn); if (eop > 0) {