903
|
1 package digilib.servlet;
|
|
2
|
|
3 import java.io.File;
|
|
4 import java.io.FileNotFoundException;
|
|
5 import java.io.IOException;
|
|
6 import java.util.concurrent.Future;
|
|
7
|
|
8 import javax.servlet.RequestDispatcher;
|
|
9 import javax.servlet.ServletConfig;
|
|
10 import javax.servlet.ServletContext;
|
|
11 import javax.servlet.ServletException;
|
|
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.image.DocuImage;
|
|
19 import digilib.pdf.PDFFileWorker;
|
|
20 import digilib.util.DigilibJobCenter;
|
|
21
|
|
22 /**
|
|
23 * A class for handling user requests for pdf documents made from digilib images.
|
|
24 *
|
|
25 * If a document does not already exist, it will be enqueued for generation; if it does exist, it is sent
|
|
26 * to the user.
|
|
27 *
|
|
28 * @author cmielack
|
|
29 *
|
|
30 */
|
|
31
|
|
32 @SuppressWarnings("serial")
|
|
33 public class PDFCache extends HttpServlet {
|
|
34
|
|
35 public static String version = "0.3a";
|
|
36
|
|
37 /** logger for accounting requests */
|
|
38 protected static Logger accountlog = Logger.getLogger("account.pdf.request");
|
|
39
|
|
40 /** gengeral logger for this class */
|
|
41 protected static Logger logger = Logger.getLogger("digilib.pdfcache");
|
|
42
|
|
43 /** logger for authentication related */
|
|
44 protected static Logger authlog = Logger.getLogger("digilib.pdf.auth");
|
|
45
|
|
46 private DigilibConfiguration dlConfig = null;
|
|
47
|
|
48 public static String instanceKey = "digilib.servlet.PDFCache";
|
|
49
|
|
50 private DigilibJobCenter<File> pdfJobCenter = null;
|
|
51
|
|
52 private DigilibJobCenter<DocuImage> pdfImageJobCenter = null;
|
|
53
|
|
54 private File cache_directory = new File("cache");
|
|
55
|
|
56 private File temp_directory = new File("pdf_temp");
|
|
57
|
|
58 private static String JSP_WIP = "/pdf/wip.jsp";
|
|
59
|
|
60 private static String JSP_ERROR = "/pdf/error.jsp";
|
|
61
|
|
62 /** document status.
|
|
63 * DONE: document exists in cache
|
|
64 * WIP: document is "work in progress"
|
|
65 * NONEXISTENT: document does not exist in cache and is not in progress
|
|
66 * ERROR: an error occurred while processing the request
|
|
67 */
|
|
68 public static enum PDFStatus {DONE, WIP, NONEXISTENT, ERROR};
|
|
69
|
|
70
|
|
71 public void init(ServletConfig config) throws ServletException {
|
|
72 super.init(config);
|
|
73
|
|
74 System.out.println("***** Digital Image Library Image PDF-Cache Servlet (version "
|
|
75 + version + ") *****");
|
|
76 // say hello in the log file
|
|
77 logger.info("***** Digital Image Library Image PDF-Cache Servlet (version "
|
|
78 + version + ") *****");
|
|
79
|
|
80 ServletContext context = getServletContext();
|
|
81 dlConfig = (DigilibConfiguration) context.getAttribute("digilib.servlet.configuration");
|
|
82 if (dlConfig == null) {
|
|
83 // no Configuration
|
|
84 throw new ServletException("No Configuration!");
|
|
85 }
|
|
86
|
|
87 String temp_fn = dlConfig.getAsString("pdf-temp-dir");
|
|
88 temp_directory = new File(temp_fn);
|
|
89 if (!temp_directory.exists()) {
|
|
90 // try to create
|
|
91 temp_directory.mkdirs();
|
|
92 } else {
|
|
93 // rid the temporary directory of possible incomplete document files
|
|
94 emptyDirectory(temp_directory);
|
|
95 }
|
|
96 if (!temp_directory.isDirectory()) {
|
|
97 throw new ServletException("Configuration error: problem with pdf-temp-dir="+temp_fn);
|
|
98 }
|
|
99
|
|
100 String cache_fn = dlConfig.getAsString("pdf-cache-dir");
|
|
101 cache_directory = new File(cache_fn);
|
|
102 if (!cache_directory.exists()) {
|
|
103 // try to create
|
|
104 cache_directory.mkdirs();
|
|
105 }
|
|
106 if (!cache_directory.isDirectory()) {
|
|
107 throw new ServletException("Configuration error: problem with pdf-cache-dir="+cache_fn);
|
|
108 }
|
|
109
|
|
110 pdfJobCenter = (DigilibJobCenter<File>) dlConfig.getValue("servlet.worker.pdfexecutor");
|
|
111 pdfImageJobCenter = (DigilibJobCenter<DocuImage>) dlConfig.getValue("servlet.worker.pdfimageexecutor");
|
|
112
|
|
113 // register this instance globally
|
|
114 context.setAttribute(instanceKey, this);
|
|
115
|
|
116 }
|
|
117
|
|
118 /* (non-Javadoc)
|
|
119 * @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
|
|
120 */
|
|
121 public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException {
|
|
122 accountlog.info("GET from " + request.getRemoteAddr());
|
|
123 this.processRequest(request, response);
|
|
124 }
|
|
125
|
|
126
|
|
127 /* (non-Javadoc)
|
|
128 * @see javax.servlet.http.HttpServlet#doPost(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
|
|
129 */
|
|
130 public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException {
|
|
131 accountlog.info("POST from " + request.getRemoteAddr());
|
|
132 this.processRequest(request, response);
|
|
133 }
|
|
134
|
|
135 /**
|
|
136 * clean up any broken and unfinished files from the temporary directory.
|
|
137 */
|
|
138 public void emptyDirectory(File dir){
|
|
139 File[] temp_files = dir.listFiles();
|
|
140 for (File f: temp_files){
|
|
141 f.delete();
|
|
142 }
|
|
143 }
|
|
144
|
|
145
|
|
146 public void processRequest(HttpServletRequest request,
|
|
147 HttpServletResponse response) throws ServletException {
|
|
148
|
|
149 if (dlConfig == null) {
|
|
150 logger.error("ERROR: No Configuration!");
|
|
151 throw new ServletException("NO VALID digilib CONFIGURATION!");
|
|
152 }
|
|
153
|
|
154 String docid = "";
|
|
155 try {
|
|
156 // evaluate request ( make a PDFJobDeclaration , get the DocumentId)
|
|
157 PDFRequest pdfji = new PDFRequest(request, dlConfig);
|
|
158
|
|
159 docid = pdfji.getDocumentId();
|
|
160
|
|
161 // if some invalid data has been entered ...
|
|
162 if(!pdfji.checkValidity()) {
|
|
163 notifyUser(PDFStatus.ERROR, docid, request, response);
|
|
164 return;
|
|
165 }
|
|
166
|
|
167 PDFStatus status = getStatus(docid);
|
|
168
|
|
169 if (status == PDFStatus.NONEXISTENT) {
|
|
170 // not there -- start creation
|
|
171 try {
|
|
172 createNewPdfDocument(pdfji, docid);
|
|
173 notifyUser(status, docid, request, response);
|
|
174 return;
|
|
175 } catch (FileNotFoundException e) {
|
|
176 // error in pdf creation
|
|
177 logger.error(e.getMessage());
|
|
178 notifyUser(PDFStatus.ERROR, docid, request, response);
|
|
179 return;
|
|
180 }
|
|
181 } else if (status == PDFStatus.DONE) {
|
|
182 // pdf created -- send it
|
|
183 try {
|
|
184 ServletOps.sendFile(getCacheFile(docid), "application/pdf", getDownloadFilename(pdfji), response, logger);
|
|
185 return;
|
|
186 } catch (Exception e) {
|
|
187 // sending didn't work
|
|
188 logger.error(e.getMessage());
|
|
189 return;
|
|
190 }
|
|
191 } else {
|
|
192 // should be work in progress
|
|
193 notifyUser(status, docid, request, response);
|
|
194 return;
|
|
195 }
|
|
196 } catch (Exception e) {
|
|
197 // error in pdf creation
|
|
198 logger.error(e.getMessage());
|
|
199 notifyUser(PDFStatus.ERROR, docid, request, response);
|
|
200 return;
|
|
201 }
|
|
202 }
|
|
203
|
|
204 /**
|
|
205 * depending on the documents status, redirect the user to the appropriate
|
|
206 * waiting or download page.
|
|
207 *
|
|
208 * @param status
|
|
209 * @param documentid
|
|
210 * @param request
|
|
211 * @param response
|
|
212 */
|
|
213 public void notifyUser(PDFStatus status, String documentid,
|
|
214 HttpServletRequest request, HttpServletResponse response) {
|
|
215
|
|
216 String jsp = null;
|
|
217
|
|
218 if (status == PDFStatus.NONEXISTENT) {
|
|
219 // tell the user that the document has to be created before he/she
|
|
220 // can download it
|
|
221 logger.debug("PDFCache: " + documentid + " has STATUS_NONEXISTENT.");
|
|
222 jsp = JSP_WIP;
|
|
223 } else if (status == PDFStatus.WIP) {
|
|
224 logger.debug("PDFCache: " + documentid + " has STATUS_WIP.");
|
|
225 jsp = JSP_WIP;
|
|
226
|
|
227 // TODO: estimate remaining work time
|
|
228 // TODO: tell the user he/she has to wait
|
|
229 } else if (status == PDFStatus.DONE) {
|
|
230 logger.debug("PDFCache: " + documentid + " has STATUS_DONE.");
|
|
231 } else {
|
|
232 logger.debug("PDFCache: " + documentid + " has STATUS_ERROR.");
|
|
233 jsp = JSP_ERROR;
|
|
234 }
|
|
235
|
|
236 try {
|
|
237 // forward to the relevant jsp
|
|
238 ServletContext context = getServletContext();
|
|
239 RequestDispatcher dispatch = context.getRequestDispatcher(jsp);
|
|
240 dispatch.forward(request, response);
|
|
241 } catch (ServletException e) {
|
|
242 logger.debug(e.getMessage());
|
|
243 e.printStackTrace();
|
|
244 } catch (IOException e) {
|
|
245 logger.debug(e.getMessage());
|
|
246 e.printStackTrace();
|
|
247 }
|
|
248
|
|
249 }
|
|
250
|
|
251
|
|
252 /** check the status of the document corresponding to the documentid */
|
|
253 public PDFStatus getStatus(String documentid){
|
|
254 // looks into the cache and temp directory in order to find out the status of the document
|
|
255 File cached = getCacheFile(documentid);
|
|
256 File wip = getTempFile(documentid);
|
|
257 if(cached.exists()){
|
|
258 return PDFStatus.DONE;
|
|
259 } else if (wip.exists()){
|
|
260 return PDFStatus.WIP;
|
|
261 } else {
|
|
262 return PDFStatus.NONEXISTENT;
|
|
263 }
|
|
264 }
|
|
265
|
|
266 /**
|
|
267 * create new thread for pdf generation.
|
|
268 *
|
|
269 * @param pdfji
|
|
270 * @param filename
|
|
271 * @return
|
|
272 * @throws FileNotFoundException
|
|
273 */
|
|
274 public Future<File> createNewPdfDocument(PDFRequest pdfji, String filename) throws FileNotFoundException{
|
|
275 // start new worker
|
|
276 File tempf = this.getTempFile(filename);
|
|
277 File finalf = this.getCacheFile(filename);
|
|
278 PDFFileWorker job = new PDFFileWorker(dlConfig, tempf, finalf, pdfji, pdfImageJobCenter);
|
|
279 // start job
|
|
280 Future<File> jobTicket = pdfJobCenter.submit(job);
|
|
281 return jobTicket;
|
|
282 }
|
|
283
|
|
284
|
|
285 /**
|
|
286 * generate the filename the user is going to receive the pdf as
|
|
287 *
|
|
288 * @param pdfji
|
|
289 * @return
|
|
290 */
|
|
291 public String getDownloadFilename(PDFRequest pdfji){
|
|
292 // filename example: digilib_example_pgs1-3.pdf
|
|
293 String filename;
|
|
294 filename = "digilib_";
|
|
295 filename += pdfji.getAsString("fn");
|
|
296 filename += "_pgs" + pdfji.getAsString("pgs");
|
|
297 filename += ".pdf";
|
|
298
|
|
299 return filename;
|
|
300 }
|
|
301
|
|
302 public File getCacheDirectory(){
|
|
303 return cache_directory;
|
|
304 }
|
|
305
|
|
306 public File getTempDirectory(){
|
|
307 return temp_directory;
|
|
308 }
|
|
309
|
|
310 /**
|
|
311 * returns a File object based on filename in the temp directory.
|
|
312 * @param filename
|
|
313 * @return
|
|
314 */
|
|
315 public File getTempFile(String filename) {
|
|
316 return new File(temp_directory, filename);
|
|
317 }
|
|
318
|
|
319 /**
|
|
320 * returns a File object based on filename in the cache directory.
|
|
321 * @param filename
|
|
322 * @return
|
|
323 */
|
|
324 public File getCacheFile(String filename) {
|
|
325 return new File(cache_directory, filename);
|
|
326 }
|
|
327 }
|