source: other-projects/the-macronizer/trunk/src/java/web/servlets/FileUpload.java@ 35721

Last change on this file since 35721 was 35721, checked in by cstephen, 2 years ago

Implement json response for file macronisation

File size: 13.7 KB
Line 
1package web.servlets;
2
3import java.io.File;
4import java.io.IOException;
5import java.util.ArrayList;
6import java.util.List;
7
8import javax.servlet.RequestDispatcher;
9import javax.servlet.ServletConfig;
10import javax.servlet.ServletException;
11import javax.servlet.http.HttpServlet;
12import javax.servlet.http.HttpServletRequest;
13import javax.servlet.http.HttpServletResponse;
14
15import com.google.gson.Gson;
16import com.google.gson.stream.JsonWriter;
17
18import monogram.plugin.PluginConfiguration;
19import monogram.plugin.PluginManager;
20
21import org.apache.commons.fileupload.FileItem;
22import org.apache.commons.fileupload.FileUploadException;
23import org.apache.commons.fileupload.disk.DiskFileItemFactory;
24import org.apache.commons.fileupload.servlet.ServletFileUpload;
25import org.apache.log4j.*;
26
27import util.FileUtil;
28
29/**
30 * Represents a servlet for macronising the contents of a file.
31 * @author University of Waikato - Te Whare Wānanga o Waikato
32 * @version 2.0
33 * @since 2014-11-20
34 */
35public class FileUpload extends HttpServlet {
36
37 // Create an instance of the logger object defined for the DirectInput servlet in log4j.properties.
38 private static final Logger logger = Logger.getLogger(web.servlets.DirectInput.class.getName());
39
40 private final Gson gsonInstance = new Gson();
41
42 private File tmpdir;
43 private PluginManager pluginManager;
44
45 @Override
46 public void init(ServletConfig config)
47 throws ServletException
48 {
49 super.init(config);
50
51 tmpdir = new File((String) config.getServletContext().getAttribute("tmpdir"));
52 pluginManager = new PluginManager(tmpdir);
53 }
54
55 /**
56 * Handles the HTTP <code>GET</code> method.
57 * @param request The servlet request.
58 * @param response The servlet response.
59 * @throws IllegalStateException if a reponse has already been committed.
60 * @throws IOException if an I/O error occurs.
61 */
62 @Override
63 protected void doGet(HttpServletRequest request, HttpServletResponse response)
64 throws IllegalStateException, IOException
65 {
66 response.sendError(405); // 405 Method Not Allowed
67 }
68
69 /**
70 * Handles the HTTP <code>POST</code> method.
71 * @param request servlet request
72 * @param response servlet response
73 * @throws ServletException if a servlet-specific error occurs
74 * @throws IOException if an I/O error occurs
75 */
76 @Override
77 protected void doPost(HttpServletRequest request, HttpServletResponse response)
78 throws IllegalStateException, IOException, ServletException
79 {
80 List<FileItem> formItems = null;
81 Properties properties = null;
82 File restoredFile = null;
83 PluginConfiguration configuration = null;
84
85 try
86 {
87 formItems = parseFormItems(request);
88 properties = getRequestProperties(formItems);
89 }
90 catch (Exception ex)
91 {
92 throw new ServletException("Expected a multipart/form-data request.", ex);
93 }
94
95 try
96 {
97 Boolean foundFile = getRequestFile(formItems, properties);
98 if (!foundFile)
99 {
100 setError(properties, "FILE_NOT_FOUND_ERROR", request, response, true);
101 return;
102 }
103 }
104 catch (Exception ex)
105 {
106 ex.printStackTrace();
107 logger.error("Failed to get uploaded file", ex);
108 setError(properties, "UNEXPECTED_ERROR", request, response, false);
109 }
110
111 try
112 {
113 configuration = configure(properties);
114
115 if (configuration.getFile().length() == 0)
116 {
117 configuration.getFile().delete();
118 setError(properties, "FILE_NOT_FOUND_ERROR", request, response, false);
119 return;
120 }
121
122 restoredFile = pluginManager.run(configuration);
123
124 if (properties.getOutputType() == OutputType.Json)
125 {
126 response.setContentType("application/json; charset=UTF-8");
127 JsonWriter writer = gsonInstance.newJsonWriter(response.getWriter());
128 writer.beginObject();
129
130 writer.name("fileName");
131 writer.value(properties.getFileName());
132
133 writer.name("filePath");
134 writer.value(restoredFile.getPath());
135
136 writer.name("fileType");
137 writer.value(configuration.getFileType());
138
139 writer.endObject();
140 writer.flush();
141 }
142 else
143 {
144 request.setAttribute("file", restoredFile);
145 request.setAttribute("fileType", configuration.getFileType());
146 request.setAttribute("charsetEncoding", "utf-8");
147 request.setAttribute("filename", properties.getFileName());
148 request.setAttribute("preserveMacrons", properties.getPreserveExistingMacrons());
149 request.setAttribute("options", properties.getShowAdvancedOptions());
150
151 forward(properties.getJspForwardPath() + "/main.jsp", request, response);
152 }
153 }
154 catch (UnsupportedOperationException uoex)
155 {
156 FileUtil.deleteFile(restoredFile);
157 logger.error("Failed to restore macrons on a file", uoex);
158 setError(properties, "FILE_TYPE_NOT_SUPPORTED_ERROR", request, response, false);
159 }
160 catch (Exception ex)
161 {
162 FileUtil.deleteFile(restoredFile);
163 ex.printStackTrace();
164 logger.error("Failed to restore macrons on a file", ex);
165 setError(properties, "UNEXPECTED_ERROR", request, response, false);
166 }
167 finally
168 {
169 if (configuration != null)
170 {
171 FileUtil.deleteFile(configuration.getFile());
172 // We don't clean up the file held by the properties object,
173 // as the configuration holds a reference to said file
174 }
175 }
176 }
177
178 private void setError(
179 Properties properties,
180 String errorCode,
181 HttpServletRequest request,
182 HttpServletResponse response,
183 Boolean isClientError)
184 throws IOException, ServletException
185 {
186 switch (properties.getOutputType()) {
187 case Json:
188 // 500 Internal Server Error
189 response.sendError(isClientError ? 400 : 500, errorCode);
190 break;
191 default:
192 request.setAttribute("errorMessage", errorCode);
193 forward(properties.getJspForwardPath()+ "/error.jsp", request, response);
194 break;
195 }
196 }
197
198 /**
199 * Forwards a request from a servlet to another resource on the server.
200 * @param path The path to forward to.
201 * @param request The servlet request.
202 * @param response The servlet response.
203 * @throws ServletException
204 * @throws IOException
205 */
206 private void forward(String path, HttpServletRequest request, HttpServletResponse response)
207 throws ServletException, IOException
208 {
209 final RequestDispatcher dispatcher = getServletContext().getRequestDispatcher(path);
210 dispatcher.forward(request, response);
211 }
212
213 /**
214 * Parses multipart items from a request.
215 * @param request The request
216 * @return The parsed multipart items.
217 * @throws FileUploadException
218 */
219 private List<FileItem> parseFormItems(HttpServletRequest request)
220 throws FileUploadException
221 {
222 DiskFileItemFactory factory = new DiskFileItemFactory();
223 factory.setSizeThreshold(10 * 1024 * 1024);
224 ServletFileUpload upload = new ServletFileUpload(factory);
225
226 List<FileItem> items = new ArrayList<>();
227 for (Object element : upload.parseRequest(request)) {
228 items.add(FileItem.class.cast(element));
229 }
230
231 return items;
232 }
233
234 /**
235 * Gets the properties of the request by checking the submitted form items.
236 * @param formItems The multipart form items.
237 * @return The properties.
238 */
239 private Properties getRequestProperties(List<FileItem> formItems)
240 {
241 Properties properties = new Properties();
242
243 for (FileItem item : formItems)
244 {
245 if (!item.isFormField())
246 {
247 continue;
248 }
249
250 String fieldName = item.getFieldName();
251 String fieldValue = item.getString();
252
253 switch (fieldName)
254 {
255 case "charsetEncoding":
256 properties.setCharsetEncoding(fieldValue);
257 break;
258 case "fileType":
259 properties.setFileType(fieldValue);
260 break;
261 case "preserveExistingMacrons":
262 properties.setPreserveExistingMacrons(fieldValue);
263 break;
264 case "lang":
265 properties.setLanguage(fieldValue);
266 break;
267 case "options":
268 properties.setShowAdvancedOptions(fieldValue);
269 break;
270 case "o":
271 properties.setOutputType(fieldValue);
272 break;
273 }
274 }
275
276 return properties;
277 }
278
279 /**
280 * Gets the first file contained in the submitted form items.
281 * @param formItems The multipart form items.
282 * @return The file, or <code>null</code> if the request contained no files.
283 * @throws Exception
284 * @throws IOException
285 */
286 private Boolean getRequestFile(List<FileItem> formItems, Properties properties)
287 throws Exception, IOException
288 {
289 for (FileItem item : formItems)
290 {
291 if (item.isFormField())
292 {
293 continue;
294 }
295
296 String fileType = FileUtil.guessFileType(new File(item.getName()));
297 File file = File.createTempFile(FileUtil.TMP_FILE_PREFIX, fileType, tmpdir);
298 item.write(file);
299
300 properties.setFile(file);
301 properties.setFilename(item.getName());
302
303 return true;
304 }
305
306 return false;
307 }
308
309 /* Useful for debugging file operations */
310 // private String readStringFromFile(File file)
311 // throws FileNotFoundException, IOException
312 // {
313 // BufferedReader reader = new BufferedReader(new FileReader(file));
314 // String line = null;
315 // StringBuilder sb = new StringBuilder();
316
317 // try
318 // {
319 // while ((line=reader.readLine()) != null)
320 // {
321 // sb.append(line);
322 // }
323 // }
324 // finally
325 // {
326 // reader.close();
327 // }
328
329 // return sb.toString();
330 // }
331
332 private PluginConfiguration configure(Properties properties)
333 {
334 final File file = properties.getFile();
335
336 String fileType = properties.getFileType();
337 if (fileType == null || fileType.equals("(detect automatically)"))
338 {
339 fileType = FileUtil.guessFileType(file);
340 }
341
342 String charsetEncoding = properties.getCharsetEncoding();
343 if (charsetEncoding == null || charsetEncoding.equals("(detect automatically)"))
344 {
345 charsetEncoding = "utf8";
346 }
347
348 final PluginConfiguration configuration = new PluginConfiguration();
349 configuration.setFile(file);
350 configuration.setFileType(fileType);
351 configuration.setCharsetEncoding(charsetEncoding);
352 configuration.setPreserveExistingMacrons(properties.getPreserveExistingMacrons());
353
354 return configuration;
355 }
356
357 private class Properties
358 {
359 private File file;
360 private String filename;
361 private String fileType;
362 private String charsetEncoding;
363 private Boolean preserveExistingMacrons;
364 private String language;
365 private Boolean showAdvancedOptions;
366 private OutputType outputType;
367
368 public Properties() {
369 this.outputType = OutputType.JspRedirect;
370 }
371
372 public File getFile() {
373 return file;
374 }
375
376 public String getFileName() {
377 return filename;
378 }
379
380 public String getFileType() {
381 return fileType;
382 }
383
384 public String getCharsetEncoding() {
385 return charsetEncoding;
386 }
387
388 public Boolean getPreserveExistingMacrons() {
389 return preserveExistingMacrons;
390 }
391
392 public String getLanguage() {
393 return language;
394 }
395
396 public Boolean getShowAdvancedOptions() {
397 return showAdvancedOptions;
398 }
399
400 public OutputType getOutputType() {
401 return outputType;
402 }
403
404 public String getJspForwardPath() {
405 return getLanguage() != null
406 ? "/jsp/" + getLanguage()
407 : "/jsp/mi";
408 }
409
410 public void setFile(File file) {
411 this.file = file;
412 }
413
414 public void setFilename(String filename) {
415 this.filename = filename;
416 }
417
418 public void setFileType(String fileType) {
419 this.fileType = fileType;
420 }
421
422 public void setCharsetEncoding(String charsetEncoding) {
423 this.charsetEncoding = charsetEncoding;
424 }
425
426 public void setPreserveExistingMacrons(String preserveExistingMacrons) {
427 this.preserveExistingMacrons = Boolean.parseBoolean(preserveExistingMacrons);
428 }
429
430 public void setLanguage(String language) {
431 this.language = language;
432 }
433
434 public void setShowAdvancedOptions(String options) {
435 this.showAdvancedOptions = Boolean.parseBoolean(options);
436 }
437
438 public void setOutputType(String outputType) {
439 this.outputType = OutputType.parse(outputType);
440 }
441 }
442}
Note: See TracBrowser for help on using the repository browser.