package com.skynav.ttv.servlet; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.PrintWriter; import java.io.StringWriter; import java.net.MalformedURLException; import java.net.URISyntaxException; import java.net.URI; import java.net.URL; import java.util.List; import java.util.Map; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory; import javax.xml.transform.TransformerFactoryConfigurationError; import javax.xml.transform.stream.StreamSource; import javax.xml.transform.stream.StreamResult; import org.apache.commons.fileupload.FileItemIterator; import org.apache.commons.fileupload.FileItemStream; import org.apache.commons.fileupload.FileUploadException; import org.apache.commons.fileupload.servlet.ServletFileUpload; import org.apache.commons.fileupload.util.Streams; import com.skynav.ttv.app.TimedTextVerifier; import com.skynav.ttv.app.TimedTextVerifier.Results; public class CheckerServlet extends HttpServlet { private static final long serialVersionUID = 1L; private static final String UPLOAD_DIRECTORY_NAME = "uploads"; private static final String UPLOAD_FILE_PREFIX = "ttv"; private static final String UPLOAD_FILE_SUFFIX = ".dat"; private static final int UPLOAD_BUFFER_SIZE = 1<<16; private static final String REPORT_DIRECTORY_NAME = "reports"; private static final String REPORT_FILE_PREFIX = "rpt"; private static final String REPORT_FILE_SUFFIX = ".xml"; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doCheck(new RequestState(request, response)); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doCheck(new RequestState(request, response)); } private void doCheck(RequestState state) throws ServletException, IOException { try { if (!ServletFileUpload.isMultipartContent(state.request)) processQueryRequest(state); else processNonQueryRequest(state); processCheck(state); processResponse(state); } finally { state.reset(); } } private void processQueryRequest(RequestState state) throws ServletException, IOException { assert !ServletFileUpload.isMultipartContent(state.request); Map<String,String[]> parameters = state.request.getParameterMap(); for (String name : parameters.keySet()) { for (String value : parameters.get(name)) { state.addField(name, value); } } String[] uris = (String[]) parameters.get("uri"); if ((uris != null) && (uris.length > 0)) { URL url = null; try { url = new URI(uris[0]).toURL(); } catch (URISyntaxException e) { state.setPreverifyException(e); } catch (MalformedURLException e) { state.setPreverifyException(e); } catch (IllegalArgumentException e) { state.setPreverifyException(e); } if (url != null) processFileItem(state, new UrlItemStream(url)); } } private void processNonQueryRequest(RequestState state) throws ServletException, IOException { assert ServletFileUpload.isMultipartContent(state.request); ServletFileUpload upload = new ServletFileUpload(); try { for (FileItemIterator iter = upload.getItemIterator(state.request); iter.hasNext(); ) { FileItemStream item = iter.next(); if (item.isFormField()) { String name = item.getFieldName(); if (!name.equals("fragment")) { InputStream is = null; try { is = item.openStream(); state.addField(name, Streams.asString(is)); } finally { StreamUtil.closeSafely(is); } } else { String fragment = Streams.asString(item.openStream()); processFileItem(state, new FragmentItemStream(fragment)); state.fragment = fragment; } } else { processFileItem(state, item); } } } catch (FileUploadException e) { state.setPreverifyException(e); } } private void processFileItem(RequestState state, FileItemStream item) throws ServletException, IOException { File uploadDir = ensureUploadDirectory(); if (uploadDir != null) { File uploadFile = null; try { String prefix = UPLOAD_FILE_PREFIX; String suffix = UPLOAD_FILE_SUFFIX; uploadFile = File.createTempFile(prefix, suffix, uploadDir); InputStream is = null; InputStream bis = null; OutputStream bos = null; try { is = item.openStream(); bis = new BufferedInputStream(is, UPLOAD_BUFFER_SIZE); bos = new BufferedOutputStream(new FileOutputStream(uploadFile), UPLOAD_BUFFER_SIZE); byte[] buffer = new byte[UPLOAD_BUFFER_SIZE]; int fileLength = 0; for (int nb = 0; (nb = bis.read(buffer)) >= 0;) { if (nb > 0) { bos.write(buffer, 0, nb); fileLength += nb; } } state.uploadFile = uploadFile; state.uploadFileLength = fileLength; state.uploadFileNameOriginal = item.getName(); if (state.uploadFileNameOriginal == null) state.uploadFileNameOriginal = "unspecified"; } finally { StreamUtil.closeSafely(bos); StreamUtil.closeSafely(bis); StreamUtil.closeSafely(is); } } catch (IOException e) { state.setPreverifyException(e); } } } private File ensureUploadDirectory() { File tempDir = (File) getServletContext().getAttribute("javax.servlet.context.tempdir"); File uploadDir = new File(tempDir, UPLOAD_DIRECTORY_NAME); if (!uploadDir.exists()) { synchronized (this) { if (!uploadDir.exists()) { if (!uploadDir.mkdir()) uploadDir = tempDir; } } } return uploadDir; } private String createReporterFile(RequestState state) throws IOException { String reportFilePath = null; File reportDir = ensureReportDirectory(); if (reportDir != null) { File reportFile = null; String prefix = REPORT_FILE_PREFIX; String suffix = REPORT_FILE_SUFFIX; reportFile = File.createTempFile(prefix, suffix, reportDir); if (reportFile != null) { reportFilePath = reportFile.getAbsolutePath(); state.reportFile = reportFile; } } return reportFilePath; } private File ensureReportDirectory() { File tempDir = (File) getServletContext().getAttribute("javax.servlet.context.tempdir"); File reportDir = new File(tempDir, REPORT_DIRECTORY_NAME); if (!reportDir.exists()) { synchronized (this) { if (!reportDir.exists()) { if (!reportDir.mkdir()) reportDir = tempDir; } } } return reportDir; } private void processCheck(RequestState state) throws IOException { File upload = state.uploadFile; if ((upload != null) && upload.exists()) { TimedTextVerifier ttv = new TimedTextVerifier(); List<String> args = new java.util.ArrayList<String>(); if (state.getBooleanField("quiet")) args.add("-q"); if (state.getBooleanField("verbose")) args.add("-v"); if (state.getBooleanField("treatWarningAsError")) args.add("--treat-warning-as-error"); if (state.hasField("encoding")) { String encoding = state.getFirstFieldValue("encoding"); if (!encoding.equals("(detect automatically)")) { args.add("--force-encoding"); args.add(encoding); } } if (state.hasField("model")) { String model = state.getFirstFieldValue("model"); if (!model.equals("(detect automatically)")) { args.add("--force-model"); args.add(model); } else { args.add("--model"); args.add("auto"); } } args.add("--servlet"); args.add("--reporter"); args.add("xml"); args.add("--reporter-file"); args.add(createReporterFile(state)); args.add("--reporter-include-source"); String urlString = upload.toURI().toString(); args.add(urlString); System.out.println(args); ttv.run(args.toArray(new String[args.size()])); state.results = ttv.getResults(urlString); } else { state.results = new Results(); if (state.preverifyException != null) { state.request.setAttribute("PreverifyExceptionMessage", state.preverifyException.getMessage()); } } } private void processResponse(RequestState state) throws ServletException, IOException { HttpServletRequest request = state.request; HttpServletResponse response = state.response; if (state.results != null) { processReportWarnings(state); processReportErrors(state); request.setAttribute("Results", state.results); if (state.fragment != null) request.setAttribute("Fragment", state.fragment); else request.setAttribute("UploadFileNameOriginal", state.uploadFileNameOriginal); } request.getRequestDispatcher("/results.jsp").forward(request, response); } private void processReportErrors(RequestState state) throws ServletException, IOException { if (state.results != null) { HttpServletRequest request = state.request; try { String errors; if (state.results.errors > 0) { TransformerFactory tf = TransformerFactory.newInstance(); Transformer t = tf.newTransformer(new StreamSource(getServletContext().getRealPath("/templates/errors.xsl"))); StringWriter sw = new StringWriter(); t.transform(new StreamSource(state.reportFile.getAbsolutePath()), new StreamResult(sw)); errors = sw.toString(); } else errors = null; request.setAttribute("Errors", errors); } catch (Throwable e) { state.setPreverifyException(e); } } } private void processReportWarnings(RequestState state) throws ServletException, IOException { if (state.results != null) { HttpServletRequest request = state.request; try { String warnings; if (state.results.warnings > 0) { TransformerFactory tf = TransformerFactory.newInstance(); Transformer t = tf.newTransformer(new StreamSource(getServletContext().getRealPath("/templates/warnings.xsl"))); StringWriter sw = new StringWriter(); t.transform(new StreamSource(state.reportFile.getAbsolutePath()), new StreamResult(sw)); warnings = sw.toString(); } else warnings = null; request.setAttribute("Warnings", warnings); } catch (Throwable e) { state.setPreverifyException(e); } } } class RequestState { // request, response, and result output state HttpServletRequest request; HttpServletResponse response; // pre-verification state Throwable preverifyException; // fields state Map<String,List<String>> fields = new java.util.TreeMap<String,List<String>>(); // upload state File uploadFile; int uploadFileLength; String uploadFileNameOriginal; String fragment; // report state File reportFile; // ttv state Results results; RequestState(HttpServletRequest request, HttpServletResponse response) { this.request = request; this.response = response; } void reset() { if (reportFile != null) { FileUtil.deleteSafely(reportFile); reportFile = null; } if (uploadFile != null) { FileUtil.deleteSafely(uploadFile); uploadFile = null; } } boolean hasField(String name) { return fields.containsKey(name); } void addField(String name, String value) { if (!fields.containsKey(name)) fields.put(name, new java.util.ArrayList<String>()); fields.get(name).add(value); } List<String> getFieldValues(String name) { if (!fields.containsKey(name)) return new java.util.ArrayList<String>(); else return fields.get(name); } String getFirstFieldValue(String name) { if (!fields.containsKey(name)) return null; else return getFieldValues(name).get(0); } boolean getBooleanField(String name) { String value = getFirstFieldValue(name); if (value == null) return false; else return value.equals("1"); } void setPreverifyException(Throwable e) { if (preverifyException == null) preverifyException = e; } } static class StreamUtil { static void closeSafely(InputStream stream) { if (stream != null) { try { stream.close(); } catch (IOException e) { } } } static void closeSafely(OutputStream stream) { if (stream != null) { try { stream.close(); } catch (IOException e) { } } } } static class FileUtil { static void deleteSafely(File file) { if (file != null) { if (!file.delete()) file.deleteOnExit(); } } } }