Mercurial > hg > digilib
view servlet3/src/main/java/digilib/servlet/Scaler.java @ 1690:a0a8dbecb94c
Change web.xml setup to use WebServlet annotations.
Solves problem of having the correct web.xml when combining Servlets
via Maven profiles.
Works only with Servlet 3. For Servlet 2 you still need to patch
your own set of Servlets into web-2.4.xml.
You can still override Servlet mappings in web.xml if you want
(watch out for servlet-name).
author | Robert Casties <casties@mpiwg-berlin.mpg.de> |
---|---|
date | Mon, 26 Mar 2018 20:46:01 +0200 |
parents | 1c87dbe782ab |
children |
line wrap: on
line source
package digilib.servlet; /* * #%L * Scaler.java * * Scaler servlet that uses asynchronous servlet API V3.0. * * %% * Copyright (C) 2001 - 2013 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@berlios.de) */ import java.io.File; import java.io.IOException; import javax.servlet.AsyncContext; import javax.servlet.ServletConfig; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.log4j.Logger; import digilib.auth.AuthOpException; import digilib.auth.AuthzOps; import digilib.conf.DigilibOption; import digilib.conf.DigilibServlet3Configuration; import digilib.conf.DigilibServletConfiguration; import digilib.conf.DigilibServletRequest; import digilib.image.DocuImage; import digilib.image.ImageJobDescription; import digilib.image.ImageOpException; import digilib.io.DocuDirCache; import digilib.io.DocuDirectory; import digilib.io.ImageInput; import digilib.util.DigilibJobCenter; @WebServlet(name = "Scaler", urlPatterns = { "/Scaler/*", "/servlet/Scaler/*" }, asyncSupported = true) public class Scaler extends HttpServlet { private static final long serialVersionUID = 5289386646192471549L; /** digilib servlet version (for all components) */ public static final String version = DigilibServlet3Configuration.getClassVersion(); /** servlet error codes */ public static enum Error { UNKNOWN, AUTH, FILE, IMAGE }; /** type of error message */ public static enum ErrMsg { IMAGE, TEXT, CODE }; /** default error message type */ public static ErrMsg defaultErrMsgType = ErrMsg.IMAGE; /** logger for accounting requests */ protected static Logger accountlog = Logger.getLogger("account.request"); /** gengeral logger for this class */ protected static Logger logger = Logger.getLogger("digilib.scaler"); /** logger for authentication related */ protected static Logger authlog = Logger.getLogger("digilib.auth"); /** DocuDirCache instance */ protected DocuDirCache dirCache; /** Image executor */ protected DigilibJobCenter<DocuImage> imageJobCenter; /** authentication error image file */ public static File denyImgFile; /** image error image file */ public static File errorImgFile; /** not found error image file */ public static File notfoundImgFile; /** send files as is? */ protected boolean sendFileAllowed = true; /** DigilibConfiguration instance */ protected DigilibServletConfiguration dlConfig; /** use authorization database */ protected boolean useAuthorization = false; /** AuthzOps instance */ protected AuthzOps authzOp; /** * Initialisation on first run. * * @throws ServletException * * @see javax.servlet.Servlet#init(javax.servlet.ServletConfig) */ @SuppressWarnings("unchecked") public void init(ServletConfig config) throws ServletException { super.init(config); System.out.println("***** Digital Image Library Image Scaler Servlet (version " + version + ") *****"); // say hello in the log file logger.info("***** Digital Image Library Image Scaler Servlet (version " + version + ") *****"); // get our ServletContext ServletContext context = config.getServletContext(); // see if there is a Configuration instance dlConfig = DigilibServlet3Configuration.getCurrentConfig(context); if (dlConfig == null) { // no Configuration throw new ServletException("No Configuration!"); } // log DocuImage version logger.info("Scaler uses " + dlConfig.getValue("servlet.docuimage.version")); // 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); // Executor imageJobCenter = (DigilibJobCenter<DocuImage>) dlConfig.getValue("servlet.worker.imageexecutor"); // configure ServletOps ServletOps.setDlConfig(dlConfig); denyImgFile = ServletOps.getFile(dlConfig.getAsFile("denied-image"), context); errorImgFile = ServletOps.getFile(dlConfig.getAsFile("error-image"), context); notfoundImgFile = ServletOps.getFile(dlConfig.getAsFile("notfound-image"), context); sendFileAllowed = dlConfig.getAsBoolean("sendfile-allowed"); try { defaultErrMsgType = ErrMsg.valueOf(dlConfig.getAsString("default-errmsg-type")); } catch (Exception e) { // nothing to do } } /** * Returns modification time relevant to the request for caching. * * @see javax.servlet.http.HttpServlet#getLastModified(javax.servlet.http.HttpServletRequest) */ public long getLastModified(HttpServletRequest request) { accountlog.debug("GetLastModified from " + request.getRemoteAddr() + " for " + request.getQueryString()); long mtime = -1; try { // create new digilib request DigilibServletRequest dlReq = new DigilibServletRequest(request, dlConfig); DocuDirectory dd = dirCache.getDirectory(dlReq.getFilePath()); if (dd != null) { mtime = dd.getDirMTime() / 1000 * 1000; } } catch (Exception e) { logger.error("error in getLastModified: " + e.getMessage()); } logger.debug(" returns " + mtime); return mtime; } /* * (non-Javadoc) * * @see * javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest * , javax.servlet.http.HttpServletResponse) */ public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException { accountlog.info("GET from " + request.getRemoteAddr()); this.processRequest(request, response); } /* * (non-Javadoc) * * @see * javax.servlet.http.HttpServlet#doPost(javax.servlet.http.HttpServletRequest * , javax.servlet.http.HttpServletResponse) */ public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException { accountlog.info("POST from " + request.getRemoteAddr()); this.processRequest(request, response); } protected void doHead(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { logger.debug("HEAD from " + req.getRemoteAddr()); super.doHead(req, resp); } protected void doOptions(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { logger.debug("OPTIONS from " + req.getRemoteAddr()); super.doOptions(req, resp); } /** * Service this request using the response. * * @param request * @param response * @throws ServletException */ public void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException { if (dlConfig == null) { logger.error("ERROR: No Configuration!"); throw new ServletException("NO VALID digilib CONFIGURATION!"); } accountlog.debug("request: " + request.getQueryString()); logger.debug("request: " + request.getQueryString()); //logger.debug("headers: " + ServletOps.headersToString(request)); //logger.debug("processRequest response committed=" + response.isCommitted()); if (response.isCommitted()) { logger.error("Crap: response committed before we got a chance!"); } final long startTime = System.currentTimeMillis(); // parse request DigilibServletRequest dlRequest = new DigilibServletRequest(request, dlConfig); // type of error reporting ErrMsg errMsgType = defaultErrMsgType; if (dlRequest.hasOption(DigilibOption.errimg)) { errMsgType = ErrMsg.IMAGE; } else if (dlRequest.hasOption(DigilibOption.errtxt)) { errMsgType = ErrMsg.TEXT; } else if (dlRequest.hasOption(DigilibOption.errcode)) { errMsgType = ErrMsg.CODE; } try { // extract the job information final ImageJobDescription jobTicket = ImageJobDescription.getInstance(dlRequest, dlConfig); // handle the IIIF info-request if (dlRequest.hasOption(DigilibOption.info)) { ServletOps.sendIiifInfo(dlRequest, response, logger); return; } if (dlRequest.hasOption(DigilibOption.redirect_info)) { StringBuffer url = request.getRequestURL(); if (url.toString().endsWith("/")) { url.append("info.json"); } else { url.append("/info.json"); } // TODO: the redirect should have code 303 response.sendRedirect(url.toString()); return; } // error out if request was bad if (dlRequest.errorMessage != null) { digilibError(errMsgType, Error.UNKNOWN, dlRequest.errorMessage, response); return; } /* * check permissions */ if (useAuthorization) { // is the current request/user authorized? if (!authzOp.isAuthorized(dlRequest)) { // send deny answer and abort throw new AuthOpException("Access denied!"); } } /* * get the input file */ ImageInput fileToLoad = jobTicket.getInput(); /* * if requested, send image as a file */ if (sendFileAllowed && jobTicket.getSendAsFile()) { String mt = null; if (jobTicket.hasOption(DigilibOption.rawfile)) { // mo=rawfile sends as octet-stream mt = "application/octet-stream"; } logger.debug("Sending RAW File as is."); ServletOps.sendFile(fileToLoad.getFile(), mt, null, response, logger); logger.info("Done in " + (System.currentTimeMillis() - startTime) + "ms"); return; } /* * send the image if it's possible without having to transform it */ if (!jobTicket.isTransformRequired()) { logger.debug("Sending File as is."); ServletOps.sendFile(fileToLoad.getFile(), null, null, response, logger); logger.info("Done in " + (System.currentTimeMillis() - startTime) + "ms"); return; } /* * check load of workers */ if (imageJobCenter.isBusy()) { logger.error("Servlet overloaded!"); response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE); return; } /* * dispatch worker job to be done asynchronously */ AsyncContext asyncCtx = request.startAsync(); // create job AsyncServletWorker job = new AsyncServletWorker(dlConfig, jobTicket, asyncCtx, errMsgType, startTime); // AsyncServletWorker is its own AsyncListener asyncCtx.addListener(job); // submit job imageJobCenter.submit(job); // we're done for now } catch (ImageOpException e) { logger.error(e.getClass() + ": " + e.getMessage()); digilibError(errMsgType, Error.IMAGE, null, response); } catch (IOException e) { logger.error(e.getClass() + ": " + e.getMessage()); digilibError(errMsgType, Error.FILE, null, response); } catch (AuthOpException e) { logger.error(e.getClass() + ": " + e.getMessage()); digilibError(errMsgType, Error.AUTH, null, response); } catch (Exception e) { logger.error("Other Exception: ", e); // TODO: should we rethrow or swallow? // throw new ServletException(e); } } /** * Sends an error to the client as text or image. * * @param type * @param error * @param msg * @param response */ public static void digilibError(ErrMsg type, Error error, String msg, HttpServletResponse response) { try { File img = null; int status = 0; if (error == Error.AUTH) { if (msg == null) { msg = "ERROR: Unauthorized access!"; } img = denyImgFile; status = HttpServletResponse.SC_FORBIDDEN; } else if (error == Error.FILE) { if (msg == null) { msg = "ERROR: Image file not found or image not readable!"; } img = notfoundImgFile; status = HttpServletResponse.SC_NOT_FOUND; } else { if (msg == null) { msg = "ERROR: Other image error!"; } img = errorImgFile; status = HttpServletResponse.SC_BAD_REQUEST; } if (response.isCommitted()) { // response already committed logger.warn("Response committed for error " + msg); } if (type == ErrMsg.TEXT) { ServletOps.htmlMessage(msg, response); } else if (type == ErrMsg.CODE) { response.sendError(status, msg); } else if (img != null) { // default: image ServletOps.sendFile(img, null, null, response, logger); } } catch (Exception e) { logger.error("Error sending error!", e); } } public static String getVersion() { return version; } }