comparison servlet3/src/main/java/digilib/servlet/Scaler.java @ 903:7779b37d1d05

refactored into maven modules per servlet type. can build servlet-api 2.3 and 3.0 via profile now!
author robcast
date Tue, 26 Apr 2011 20:24:31 +0200
parents servlet/src/main/java/digilib/servlet/Scaler.java@ba1eb2d821a2
children 91e5f20a7c56
comparison
equal deleted inserted replaced
902:89ba3ffcf552 903:7779b37d1d05
1 package digilib.servlet;
2
3 import java.io.File;
4 import java.io.IOException;
5 import java.util.List;
6
7 import javax.servlet.AsyncContext;
8 import javax.servlet.ServletConfig;
9 import javax.servlet.ServletContext;
10 import javax.servlet.ServletException;
11 import javax.servlet.annotation.WebServlet;
12 import javax.servlet.http.HttpServlet;
13 import javax.servlet.http.HttpServletRequest;
14 import javax.servlet.http.HttpServletResponse;
15
16 import org.apache.log4j.Logger;
17
18 import digilib.auth.AuthOpException;
19 import digilib.auth.AuthOps;
20 import digilib.image.DocuImage;
21 import digilib.image.ImageJobDescription;
22 import digilib.image.ImageOpException;
23 import digilib.io.DocuDirCache;
24 import digilib.io.DocuDirectory;
25 import digilib.io.ImageInput;
26 import digilib.util.DigilibJobCenter;
27
28 @WebServlet(name="Scaler", urlPatterns={"/Scaler", "/servlet/Scaler/*"}, asyncSupported=true)
29 public class Scaler extends HttpServlet {
30
31 private static final long serialVersionUID = 5289386646192471549L;
32
33 /** digilib servlet version (for all components) */
34 public static final String version = "2.0b1";
35
36 /** servlet error codes */
37 public static enum Error {UNKNOWN, AUTH, FILE, IMAGE};
38
39 /** type of error message */
40 public static enum ErrMsg {IMAGE, TEXT, CODE};
41
42 /** default error message type */
43 public static ErrMsg defaultErrMsgType = ErrMsg.IMAGE;
44
45 /** logger for accounting requests */
46 protected static Logger accountlog = Logger.getLogger("account.request");
47
48 /** gengeral logger for this class */
49 protected static Logger logger = Logger.getLogger("digilib.scaler");
50
51 /** logger for authentication related */
52 protected static Logger authlog = Logger.getLogger("digilib.auth");
53
54 /** DocuDirCache instance */
55 protected DocuDirCache dirCache;
56
57 /** Image executor */
58 protected DigilibJobCenter<DocuImage> imageJobCenter;
59
60 /** authentication error image file */
61 public static File denyImgFile;
62
63 /** image error image file */
64 public static File errorImgFile;
65
66 /** not found error image file */
67 public static File notfoundImgFile;
68
69 /** send files as is? */
70 protected boolean sendFileAllowed = true;
71
72 /** DigilibConfiguration instance */
73 protected DigilibConfiguration dlConfig;
74
75 /** use authorization database */
76 protected boolean useAuthorization = true;
77
78 /** AuthOps instance */
79 protected AuthOps authOp;
80
81 /**
82 * Initialisation on first run.
83 *
84 * @throws ServletException
85 *
86 * @see javax.servlet.Servlet#init(javax.servlet.ServletConfig)
87 */
88 public void init(ServletConfig config) throws ServletException {
89 super.init(config);
90
91 System.out
92 .println("***** Digital Image Library Image Scaler Servlet (version "
93 + version + ") *****");
94 // say hello in the log file
95 logger.info("***** Digital Image Library Image Scaler Servlet (version "
96 + version + ") *****");
97
98 // get our ServletContext
99 ServletContext context = config.getServletContext();
100 // see if there is a Configuration instance
101 dlConfig = (DigilibConfiguration) context.getAttribute("digilib.servlet.configuration");
102 if (dlConfig == null) {
103 // no Configuration
104 throw new ServletException("No Configuration!");
105 }
106 // set our AuthOps
107 useAuthorization = dlConfig.getAsBoolean("use-authorization");
108 authOp = (AuthOps) dlConfig.getValue("servlet.auth.op");
109
110 // DocuDirCache instance
111 dirCache = (DocuDirCache) dlConfig.getValue("servlet.dir.cache");
112
113 // Executor
114 imageJobCenter = (DigilibJobCenter<DocuImage>) dlConfig
115 .getValue("servlet.worker.imageexecutor");
116
117 denyImgFile = ServletOps.getFile(
118 (File) dlConfig.getValue("denied-image"), context);
119 errorImgFile = ServletOps.getFile(
120 (File) dlConfig.getValue("error-image"), context);
121 notfoundImgFile = ServletOps.getFile(
122 (File) dlConfig.getValue("notfound-image"), context);
123 sendFileAllowed = dlConfig.getAsBoolean("sendfile-allowed");
124 try {
125 defaultErrMsgType = ErrMsg.valueOf(dlConfig.getAsString("default-errmsg-type"));
126 } catch (Exception e) {
127 // nothing to do
128 }
129 }
130
131 /**
132 * Returns modification time relevant to the request for caching.
133 *
134 * @see javax.servlet.http.HttpServlet#getLastModified(javax.servlet.http.HttpServletRequest)
135 */
136 public long getLastModified(HttpServletRequest request) {
137 accountlog.debug("GetLastModified from " + request.getRemoteAddr()
138 + " for " + request.getQueryString());
139 long mtime = -1;
140 try {
141 // create new digilib request
142 DigilibServletRequest dlReq = new DigilibServletRequest(request);
143 DocuDirectory dd = dirCache.getDirectory(dlReq.getFilePath());
144 if (dd != null) {
145 mtime = dd.getDirMTime() / 1000 * 1000;
146 }
147 } catch (Exception e) {
148 logger.error("error in getLastModified: " + e.getMessage());
149 }
150 logger.debug(" returns " + mtime);
151 return mtime;
152 }
153
154 /* (non-Javadoc)
155 * @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
156 */
157 public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException {
158 accountlog.info("GET from " + request.getRemoteAddr());
159 this.processRequest(request, response);
160 }
161
162
163 /* (non-Javadoc)
164 * @see javax.servlet.http.HttpServlet#doPost(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
165 */
166 public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException {
167 accountlog.info("POST from " + request.getRemoteAddr());
168 this.processRequest(request, response);
169 }
170
171
172 protected void doHead(HttpServletRequest req, HttpServletResponse resp)
173 throws ServletException, IOException {
174 logger.debug("HEAD from "+req.getRemoteAddr());
175 super.doHead(req, resp);
176 }
177
178 protected void doOptions(HttpServletRequest req, HttpServletResponse resp)
179 throws ServletException, IOException {
180 logger.debug("OPTIONS from "+req.getRemoteAddr());
181 super.doOptions(req, resp);
182 }
183
184 /** Service this request using the response.
185 * @param request
186 * @param response
187 * @throws ServletException
188 */
189 public void processRequest(HttpServletRequest request,
190 HttpServletResponse response) throws ServletException {
191
192 if (dlConfig == null) {
193 logger.error("ERROR: No Configuration!");
194 throw new ServletException("NO VALID digilib CONFIGURATION!");
195 }
196
197 accountlog.debug("request: " + request.getQueryString());
198 logger.debug("request: " + request.getQueryString());
199 logger.debug("headers: " + ServletOps.headersToString(request));
200 //logger.debug("response:"+ response + " committed=" + response.isCommitted());
201 final long startTime = System.currentTimeMillis();
202
203 // parse request
204 DigilibServletRequest dlRequest = new DigilibServletRequest(request);
205 // extract the job information
206 final ImageJobDescription jobTicket = ImageJobDescription.getInstance(dlRequest, dlConfig);
207
208 // type of error reporting
209 ErrMsg errMsgType = defaultErrMsgType;
210 if (dlRequest.hasOption("errimg")) {
211 errMsgType = ErrMsg.IMAGE;
212 } else if (dlRequest.hasOption("errtxt")) {
213 errMsgType = ErrMsg.TEXT;
214 } else if (dlRequest.hasOption("errcode")) {
215 errMsgType = ErrMsg.CODE;
216 }
217
218 try {
219 /*
220 * check if we can fast-track without scaling
221 */
222 ImageInput fileToLoad = (ImageInput) jobTicket.getInput();
223
224 // check permissions
225 if (useAuthorization) {
226 // get a list of required roles (empty if no restrictions)
227 List<String> rolesRequired = authOp.rolesForPath(
228 jobTicket.getFilePath(), request);
229 if (rolesRequired != null) {
230 authlog.debug("Role required: " + rolesRequired);
231 authlog.debug("User: " + request.getRemoteUser());
232 // is the current request/user authorized?
233 if (!authOp.isRoleAuthorized(rolesRequired, request)) {
234 // send deny answer and abort
235 throw new AuthOpException();
236 }
237 }
238 }
239
240 // if requested, send image as a file
241 if (sendFileAllowed && jobTicket.getSendAsFile()) {
242 String mt = null;
243 if (jobTicket.hasOption("rawfile")) {
244 mt = "application/octet-stream";
245 }
246 logger.debug("Sending RAW File as is.");
247 ServletOps.sendFile(fileToLoad.getFile(), mt, null, response, logger);
248 logger.info("Done in " + (System.currentTimeMillis() - startTime) + "ms");
249 return;
250 }
251
252 // if possible, send the image without actually having to transform it
253 if (! jobTicket.isTransformRequired()) {
254 logger.debug("Sending File as is.");
255 ServletOps.sendFile(fileToLoad.getFile(), null, null, response, logger);
256 logger.info("Done in " + (System.currentTimeMillis() - startTime) + "ms");
257 return;
258 }
259
260 // check load of workers
261 if (imageJobCenter.isBusy()) {
262 logger.error("Servlet overloaded!");
263 response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
264 return;
265 }
266
267 // worker job is done asynchronously
268 AsyncContext asyncCtx = request.startAsync(request, response);
269 // create job
270 AsyncServletWorker job = new AsyncServletWorker(dlConfig, jobTicket, asyncCtx, errMsgType, startTime);
271 // submit job
272 imageJobCenter.submit(job);
273 // we're done for now
274
275 } catch (ImageOpException e) {
276 logger.error(e.getClass() + ": " + e.getMessage());
277 digilibError(errMsgType, Error.IMAGE, null, response);
278 } catch (IOException e) {
279 logger.error(e.getClass() + ": " + e.getMessage());
280 digilibError(errMsgType, Error.FILE, null, response);
281 } catch (AuthOpException e) {
282 logger.error(e.getClass() + ": " + e.getMessage());
283 digilibError(errMsgType, Error.AUTH, null, response);
284 } catch (Exception e) {
285 logger.error("Other Exception: ", e);
286 // TODO: should we rethrow or swallow?
287 //throw new ServletException(e);
288 }
289 }
290
291 /**
292 * Sends an error to the client as text or image.
293 *
294 * @param type
295 * @param error
296 * @param msg
297 * @param response
298 */
299 public static void digilibError(ErrMsg type, Error error, String msg,
300 HttpServletResponse response) {
301 try {
302 File img = null;
303 int status = 0;
304 if (error == Error.AUTH) {
305 if (msg == null) {
306 msg = "ERROR: Unauthorized access!";
307 }
308 img = denyImgFile;
309 status = HttpServletResponse.SC_FORBIDDEN;
310 } else if (error == Error.FILE) {
311 if (msg == null) {
312 msg = "ERROR: Image file not found!";
313 }
314 img = notfoundImgFile;
315 status = HttpServletResponse.SC_NOT_FOUND;
316 } else {
317 if (msg == null) {
318 msg = "ERROR: Other image error!";
319 }
320 img = errorImgFile;
321 status = HttpServletResponse.SC_BAD_REQUEST;
322 }
323 if (response.isCommitted()) {
324 // response already committed
325 logger.warn("Response committed for error "+msg);
326 }
327 if (type == ErrMsg.TEXT) {
328 ServletOps.htmlMessage(msg, response);
329 } else if (type == ErrMsg.CODE) {
330 response.sendError(status, msg);
331 } else if (img != null) {
332 // default: image
333 ServletOps.sendFile(img, null, null, response, logger);
334 }
335 } catch (Exception e) {
336 logger.error("Error sending error!", e);
337 }
338
339 }
340
341 public static String getVersion() {
342 return version;
343 }
344
345 }