Mercurial > hg > digilib
changeset 1613:1d21cb0d697c iiif-presentation-2
first version of Manifester servlet for creating simple IIIF presentation API manifests (does not really work yet).
author | Robert Casties <casties@mpiwg-berlin.mpg.de> |
---|---|
date | Wed, 24 May 2017 21:02:19 +0200 |
parents | 4018355cb442 |
children | e3c6e4c0d93d |
files | .hgignore common/src/main/java/digilib/conf/DigilibConfiguration.java common/src/main/java/digilib/io/DocuDirectory.java iiif-presentation/pom.xml iiif-presentation/src/main/java/digilib/conf/ManifestServletConfiguration.java iiif-presentation/src/main/java/digilib/servlet/Manifester.java pom.xml servlet3/src/main/java/digilib/servlet/Scaler.java webapp/pom.xml webapp/src/main/webapp/WEB-INF/web-3.0.xml |
diffstat | 10 files changed, 554 insertions(+), 6 deletions(-) [+] |
line wrap: on
line diff
--- a/.hgignore Wed May 24 15:58:54 2017 +0200 +++ b/.hgignore Wed May 24 21:02:19 2017 +0200 @@ -129,4 +129,6 @@ syntax: regexp ^webapp/src/main/webapp/jquery/jquery\.digilib-basic\.js$ syntax: regexp -^webapp/src/main/webapp/jquery/jquery\.digilib-basic\.min\.css$ \ No newline at end of file +^webapp/src/main/webapp/jquery/jquery\.digilib-basic\.min\.css$ +syntax: regexp +^iiif-presentation/target$ \ No newline at end of file
--- a/common/src/main/java/digilib/conf/DigilibConfiguration.java Wed May 24 15:58:54 2017 +0200 +++ b/common/src/main/java/digilib/conf/DigilibConfiguration.java Wed May 24 21:02:19 2017 +0200 @@ -57,7 +57,7 @@ /** digilib version */ public static String getClassVersion() { - return "2.5.2a"; + return "2.5.3a"; } /* non-static getVersion for Java inheritance */
--- a/common/src/main/java/digilib/io/DocuDirectory.java Wed May 24 15:58:54 2017 +0200 +++ b/common/src/main/java/digilib/io/DocuDirectory.java Wed May 24 21:02:19 2017 +0200 @@ -30,6 +30,7 @@ import java.io.File; import java.util.ArrayList; import java.util.Collections; +import java.util.Iterator; import java.util.List; import digilib.conf.DigilibConfiguration; @@ -47,7 +48,7 @@ * * @author casties */ -public abstract class DocuDirectory extends Directory { +public abstract class DocuDirectory extends Directory implements Iterable<DocuDirent> { /** type of files in this DocuDirectory */ protected FileClass fileClass = FileClass.IMAGE; @@ -347,6 +348,15 @@ public DirMeta getMeta() { return meta; } + + /** + * Returns an Iterator over all DocuDirents in this DocuDirectory in default order. + * + * @return + */ + public Iterator<DocuDirent> iterator() { + return files.iterator(); + } private boolean isBasenameInList(List<DocuDirent> fileList, int idx, String fn) { String dfn = FileOps.basename((fileList.get(idx)).getName());
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/iiif-presentation/pom.xml Wed May 24 21:02:19 2017 +0200 @@ -0,0 +1,41 @@ +<?xml version="1.0"?> +<project + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" + xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>digilib</groupId> + <artifactId>digilib</artifactId> + <version>2.5-SNAPSHOT</version> + </parent> + <artifactId>digilib-iiif-presentation</artifactId> + <name>digilib-iiif-presentation</name> + <description>The Digital Image Library - IIIF presentation API manifest serving servlet</description> + <url>http://digilib.sourceforge.net</url> + <properties> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + </properties> + <dependencies> + <dependency> + <groupId>digilib</groupId> + <artifactId>digilib-servlet</artifactId> + </dependency> + <dependency> + <groupId>org.mortbay.jetty</groupId> + <artifactId>servlet-api</artifactId> + <version>3.0.20100224</version> + <type>jar</type> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>javax.json</groupId> + <artifactId>javax.json-api</artifactId> + <version>1.1</version> + </dependency> + <dependency> + <groupId>org.glassfish</groupId> + <artifactId>javax.json</artifactId> + <version>1.1</version> + </dependency> + </dependencies> +</project>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/iiif-presentation/src/main/java/digilib/conf/ManifestServletConfiguration.java Wed May 24 21:02:19 2017 +0200 @@ -0,0 +1,85 @@ +package digilib.conf; + +import javax.servlet.ServletContext; +import javax.servlet.annotation.WebListener; + +/** + * 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. + * + * @author casties + */ +@WebListener +public class ManifestServletConfiguration extends DigilibServletConfiguration { + + public static final String MANIFEST_SERVLET_CONFIG_KEY = "digilib.manifest.servlet.configuration"; + + public static String getClassVersion() { + return DigilibConfiguration.getClassVersion() + " manif"; + } + + /** non-static getVersion for Java inheritance */ + @Override + public String getVersion() { + return getClassVersion(); + } + + /** + * Constructs DigilibServletConfiguration and defines all parameters and + * their default values. + */ + public ManifestServletConfiguration() { + super(); + // more parameters... + } + + /* + * (non-Javadoc) + * + * @see digilib.conf.DigilibServletConfiguration#configure(javax.servlet. + * ServletContext) + */ + @Override + public void configure(ServletContext context) { + super.configure(context); + + // set version + setValue("servlet.version", getVersion()); + + } + + /** + * Sets the current DigilibConfiguration in the context. + * @param context + */ + @Override + public void setContextConfig(ServletContext context) { + context.setAttribute(ManifestServletConfiguration.MANIFEST_SERVLET_CONFIG_KEY, this); + } + + /** + * Returns the current TextServletConfiguration from the context. + * + * @param context + * @return + */ + public static DigilibServletConfiguration getCurrentConfig(ServletContext context) { + DigilibServletConfiguration config = (DigilibServletConfiguration) context + .getAttribute(ManifestServletConfiguration.MANIFEST_SERVLET_CONFIG_KEY); + return config; + } + + /** + * Returns the current DigilibConfiguration from the context. + * (non-static method, for Java inheritance) + * + * @param context + * @return + */ + @Override + protected DigilibServletConfiguration getContextConfig(ServletContext context) { + return getCurrentConfig(context); + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/iiif-presentation/src/main/java/digilib/servlet/Manifester.java Wed May 24 21:02:19 2017 +0200 @@ -0,0 +1,369 @@ +package digilib.servlet; + +/* + * #%L + * + * Texter.java -- Servlet for displaying text + * + * Digital Image Library servlet components + * %% + * Copyright (C) 2003 - 2017 MPIWG Berlin + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + * Author: Robert Casties (robcast@sourceforge.net) + * Created on 24.5.2017 + */ + +import java.io.IOException; + +import javax.json.Json; +import javax.json.stream.JsonGenerator; +import javax.servlet.ServletConfig; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.log4j.Logger; + +import digilib.auth.AuthzOps; +import digilib.conf.DigilibServletConfiguration; +import digilib.conf.DigilibServletRequest; +import digilib.conf.ManifestServletConfiguration; +import digilib.io.DocuDirCache; +import digilib.io.DocuDirectory; +import digilib.io.DocuDirent; +import digilib.io.FileOps; +import digilib.io.ImageFileSet; +import digilib.io.ImageInput; +import digilib.util.ImageSize; + +/** + * Servlet for displaying text + * + * + * @author casties + * + */ +public class Manifester extends HttpServlet { + + private static final long serialVersionUID = 6678666342141409868L; + + /** Servlet version */ + public static String tlVersion = ManifestServletConfiguration.getClassVersion(); + + /** DigilibConfiguration instance */ + DigilibServletConfiguration dlConfig = null; + + /** general logger */ + Logger logger = Logger.getLogger("digilib.texter"); + + /** logger for accounting requests */ + protected static Logger accountlog = Logger.getLogger("account.texter.request"); + + /** FileOps instance */ + FileOps fileOp; + + /** AuthOps instance */ + AuthzOps authzOp; + + /** ServletOps instance */ + ServletOps servletOp; + + /** DocuDirCache instance */ + DocuDirCache dirCache; + + /** use authentication */ + boolean useAuthorization = 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 IIF Manifest Servlet (version " + tlVersion + ") *****"); + + // get our ServletContext + ServletContext context = config.getServletContext(); + // see if there is a Configuration instance + dlConfig = ManifestServletConfiguration.getCurrentConfig(context); + if (dlConfig == null) { + // no Configuration + throw new ServletException("No Configuration!"); + } + // say hello in the log file + logger.info("***** Digital Image Library IIIF Manifest Servlet (version " + tlVersion + ") *****"); + + // set our AuthOps + useAuthorization = dlConfig.getAsBoolean("use-authorization"); + authzOp = (AuthzOps) dlConfig.getValue(DigilibServletConfiguration.AUTHZ_OP_KEY); + // DocuDirCache instance + dirCache = (DocuDirCache) dlConfig.getValue(DigilibServletConfiguration.DIR_CACHE_KEY); + } + + /* + * (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 { + accountlog.info("GET from " + request.getRemoteAddr()); + // 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 { + accountlog.info("POST from " + request.getRemoteAddr()); + // do the processing + processRequest(request, response); + } + + protected void processRequest(HttpServletRequest request, HttpServletResponse response) { + + /* + * request parameters + */ + // create new request with defaults + DigilibServletRequest dlRequest = new DigilibServletRequest(request, dlConfig); + try { + // get directory path + String dlFn = dlRequest.getFilePath(); + // get information about the directory + DocuDirectory dlDir = dirCache.getDirectory(dlFn); + if (dlDir == null) { + logger.error("Directory for manifest not found: " + dlFn); + response.sendError(HttpServletResponse.SC_NOT_FOUND); + return; + } + /* + * set CORS header ACAO "*" for info response as per IIIF spec + */ + if (dlConfig.getAsBoolean("iiif-info-cors")) { + String origin = request.getHeader("Origin"); + if (origin != null) { + response.setHeader("Access-Control-Allow-Origin", "*"); + } + } + + // use JSON-LD content type only when asked + String accept = request.getHeader("Accept"); + if (accept != null && accept.contains("application/ld+json")) { + response.setContentType("application/ld+json"); + } else { + response.setContentType("application/json"); + } + + /* + * get manifest URL + */ + String url = request.getRequestURL().toString(); + if (url.endsWith("/")) { + url = url.substring(0, url.lastIndexOf("/")); + } + + /* + * create json representation + */ + ServletOutputStream out = response.getOutputStream(); + JsonGenerator manifest = Json.createGenerator(out).writeStartObject(); + /* + * manifest metadata + */ + writeManifestMeta(dlFn, url, manifest); + /* + * sequences + */ + manifest.writeStartArray("sequences"); + /* + * first sequence + */ + writeSequence(dlDir, url, manifest); + + manifest.writeEnd(); // sequences + + manifest.writeEnd(); // manifest + manifest.close(); + + } catch (IOException e) { + logger.error("ERROR sending manifest: ", e); + } + } + + /** + * @param dlDir + * @param url + * @param manifest + */ + protected void writeSequence(DocuDirectory dlDir, String url, JsonGenerator manifest) { + manifest.writeStartObject() + .write("@id", url + "/sequence/default") + .write("@type", "sc:Sequence") + .write("label", "Scan image order"); + /* + * canvases + */ + writeCanvases(dlDir, url, manifest); + + manifest.writeEnd(); // sequence + } + + /** + * @param dlDir + * @param url + * @param manifest + */ + protected void writeCanvases(DocuDirectory dlDir, String url, JsonGenerator manifest) { + /* + * list of canvases + */ + manifest.writeStartArray("canvases"); + + int idx = 0; + for (DocuDirent imgFile : dlDir) { + idx += 1; + ImageFileSet imgFs = (ImageFileSet) imgFile; + ImageInput img = imgFs.getBiggest(); + ImageSize imgSize = img.getSize(); + /* + * canvas + */ + writeCanvas(url, manifest, idx, imgFile, imgSize); + } + + manifest.writeEnd(); // canvases + } + + /** + * @param url + * @param manifest + * @param idx + * @param imgFile + * @param imgSize + */ + protected void writeCanvas(String url, JsonGenerator manifest, int idx, DocuDirent imgFile, ImageSize imgSize) { + manifest.writeStartObject() + .write("@type", "sc:Canvas") + .write("@id", url + "/canvas/p" + idx) + .write("label", "image " + imgFile.getName()) + .write("height", imgSize.getHeight()) + .write("width", imgSize.getWidth()); + /* + * images + */ + writeImages(url, manifest, idx, imgFile, imgSize); + + manifest.writeEnd(); // canvas + } + + /** + * @param url + * @param manifest + * @param idx + * @param imgFile + * @param imgSize + */ + protected void writeImages(String url, JsonGenerator manifest, int idx, DocuDirent imgFile, ImageSize imgSize) { + /* + * list of images (just one) + */ + manifest.writeStartArray("images"); + /* + * image + */ + writeImage(url, manifest, idx, imgFile, imgSize); + + manifest.writeEnd(); // images + } + + /** + * @param url + * @param manifest + * @param idx + * @param imgFile + * @param imgSize + */ + protected void writeImage(String url, JsonGenerator manifest, int idx, DocuDirent imgFile, ImageSize imgSize) { + manifest.writeStartObject() + .write("@type", "oa:Annotation") + .write("@id", url + "/annotation/p" + idx + "-image") + .write("motivation", "sc:painting"); + /* + * resource + */ + writeResource(url, manifest, imgFile, imgSize); + + manifest.write("on", url + "/canvas/p" + idx) + .writeEnd(); // image + } + + /** + * @param url + * @param manifest + * @param imgFile + * @param imgSize + */ + protected void writeResource(String url, JsonGenerator manifest, DocuDirent imgFile, ImageSize imgSize) { + manifest.writeStartObject("resource") + .write("@id", url + "/" + imgFile.getName()) + .write("@type", "dctypes:Image"); + /* + * service + */ + writeService(manifest); + + manifest.write("height", imgSize.getHeight()) + .write("width", imgSize.getWidth()) + .writeEnd(); // resource + } + + /** + * @param manifest + */ + protected void writeService(JsonGenerator manifest) { + manifest.writeStartObject("service") + .write("@context", "http://iiif.io/api/image/2/context.json") + .write("@id", "digilib-iiif???") + .write("profile", "http://iiif.io/api/image/2/profiles/level2.json") + .writeEnd(); // service + } + + /** + * @param dlFn + * @param url + * @param manifest + */ + protected void writeManifestMeta(String dlFn, String url, JsonGenerator manifest) { + manifest.write("@context", "http://iiif.io/api/presentation/2/context.json") + .write("@type", "sc:Manifest") + .write("@id", url + "/manifest") + .write("label", "(Scanned work " + dlFn + ")"); + } + +} \ No newline at end of file
--- a/pom.xml Wed May 24 15:58:54 2017 +0200 +++ b/pom.xml Wed May 24 21:02:19 2017 +0200 @@ -1,6 +1,5 @@ <?xml version="1.0" encoding="UTF-8"?> -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <properties> @@ -158,6 +157,12 @@ </modules> </profile> <profile> + <id>iiif-presentation</id> + <modules> + <module>iiif-presentation</module> + </modules> + </profile> + <profile> <id>pdf</id> <modules> <module>pdf</module> @@ -230,6 +235,11 @@ </dependency> <dependency> <groupId>digilib</groupId> + <artifactId>digilib-iiif-presentation</artifactId> + <version>2.5-SNAPSHOT</version> + </dependency> + <dependency> + <groupId>digilib</groupId> <artifactId>digilib-servlet</artifactId> <version>2.5-SNAPSHOT</version> </dependency>
--- a/servlet3/src/main/java/digilib/servlet/Scaler.java Wed May 24 15:58:54 2017 +0200 +++ b/servlet3/src/main/java/digilib/servlet/Scaler.java Wed May 24 21:02:19 2017 +0200 @@ -142,7 +142,7 @@ authzOp = (AuthzOps) dlConfig.getValue(DigilibServletConfiguration.AUTHZ_OP_KEY); // DocuDirCache instance - dirCache = (DocuDirCache) dlConfig.getValue("servlet.dir.cache"); + dirCache = (DocuDirCache) dlConfig.getValue(DigilibServletConfiguration.DIR_CACHE_KEY); // Executor imageJobCenter = (DigilibJobCenter<DocuImage>) dlConfig.getValue("servlet.worker.imageexecutor");
--- a/webapp/pom.xml Wed May 24 15:58:54 2017 +0200 +++ b/webapp/pom.xml Wed May 24 21:02:19 2017 +0200 @@ -276,6 +276,17 @@ </dependency> </dependencies> </profile> + <profile> + <id>iiif-presentation</id> + <dependencies> + <dependency> + <groupId>digilib</groupId> + <artifactId>digilib-iiif-presentation</artifactId> + <type>jar</type> + <scope>compile</scope> + </dependency> + </dependencies> + </profile> <profile> <id>codec-jai</id> <dependencies>
--- a/webapp/src/main/webapp/WEB-INF/web-3.0.xml Wed May 24 15:58:54 2017 +0200 +++ b/webapp/src/main/webapp/WEB-INF/web-3.0.xml Wed May 24 21:02:19 2017 +0200 @@ -50,4 +50,24 @@ /Scaler/* </url-pattern> </servlet-mapping> + + <!-- The Manifest servlet --> + <servlet> + <servlet-name>Manifester</servlet-name> + <servlet-class>digilib.servlet.Manifester</servlet-class> + </servlet> + <!-- The Intialisation Listener --> + <listener> + <listener-class> + digilib.conf.ManifestServletConfiguration + </listener-class> + </listener> + <!-- The mapping for the Manifest servlet --> + <servlet-mapping> + <servlet-name>Manifester</servlet-name> + <url-pattern>/servlet/Manifester/*</url-pattern> + </servlet-mapping> + + + </web-app>