Java tutorial
/* * Copyright (c) 2009 - 2010. School of Information Technology and Electrical * Engineering, The University of Queensland. This software is being developed * for the "Phenomics Ontoogy Driven Data Management Project (PODD)" project. * PODD is a National e-Research Architecture Taskforce (NeAT) project * co-funded by ANDS and ARCS. * * PODD is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * PODD 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 Public License for more details. * * You should have received a copy of the GNU General Public License * along with PODD. If not, see <http://www.gnu.org/licenses/>. */ package podd.util; import org.apache.commons.fileupload.FileItem; import org.apache.commons.fileupload.FileUploadException; import org.apache.commons.fileupload.disk.DiskFileItemFactory; import org.apache.commons.fileupload.servlet.FileCleanerCleanup; import org.apache.commons.io.FileCleaningTracker; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.owasp.validator.html.AntiSamy; import org.owasp.validator.html.CleanResults; import org.owasp.validator.html.Policy; import org.owasp.validator.html.PolicyException; import org.owasp.validator.html.ScanException; import org.restlet.data.Form; import org.restlet.ext.fileupload.RestletFileUpload; import org.restlet.representation.Representation; import org.springframework.core.io.Resource; import org.springframework.web.context.ServletContextAware; import javax.servlet.ServletContext; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; /** * Reads in multipart/form-data and stores the values. * * @author Faith Davies * @version $Id$ */ public class FormHandler implements ServletContextAware { private static final Logger LOGGER = LoggerFactory.getLogger(FormHandler.class); DiskFileItemFactory fileItemFactory; private Map<String, List<String>> formValues; private Map<String, List<String>> inputErrors; private Integer fileIndex; private Map<String, Integer> fileNameToIndexMap; private Map<Integer, FileItem> fileItemMap; private Map<Integer, String> fileDescriptionMap; private List<FileItem> currentFileItems; private AntiSamy antiSamy = new AntiSamy(); private Policy antiSamyPolicy; public FormHandler() { fileItemFactory = new DiskFileItemFactory(); formValues = new HashMap<String, List<String>>(); fileIndex = 0; fileNameToIndexMap = new HashMap<String, Integer>(); fileItemMap = new HashMap<Integer, FileItem>(); fileDescriptionMap = new HashMap<Integer, String>(); currentFileItems = new ArrayList<FileItem>(); } public void setPolicyResource(Resource policyResource) { try { antiSamyPolicy = Policy.getInstance(policyResource.getFile()); } catch (PolicyException e) { LOGGER.error("Error getting Policy instance for " + policyResource.toString() + ". ", e); } catch (IOException e) { LOGGER.error("Error loading Policy file for " + policyResource.toString() + ". ", e); } } @Override public void setServletContext(ServletContext servletContext) { FileCleaningTracker fileCleaningTracker = FileCleanerCleanup.getFileCleaningTracker(servletContext); fileItemFactory.setFileCleaningTracker(fileCleaningTracker); } /** * Adds the field with the given value. * If the value is clean, then return true * @param name * @param value * @return */ private boolean addFieldValue(String name, String value) { if (value == null) return true; // null values are always clean // handle form fields; add the entered value to the list and values List<String> list = formValues.get(name); if (null == list) { list = new ArrayList<String>(); } try { value = value.trim().replaceAll("\"", """); value = value.replaceAll("<http://", "<http://"); final CleanResults cleanResults = antiSamy.scan(value, antiSamyPolicy); if (null != cleanResults) { if (cleanResults.getErrorMessages().isEmpty()) { list.add(cleanResults.getCleanHTML()); } else { list.add(value); inputErrors.put(name, cleanResults.getErrorMessages()); return false; } } } catch (ScanException e) { LOGGER.error("Error parsing user input. ", e); } catch (PolicyException e) { LOGGER.error("Error parsing Policy " + antiSamyPolicy.toString() + ". ", e); } formValues.put(name, list); return true; } private boolean saveMultipart(Representation entity) { RestletFileUpload upload = new RestletFileUpload(fileItemFactory); // re-initalises formValues, but remembers all files which have already been added to the map boolean valid = true; formValues = new HashMap<String, List<String>>(); inputErrors = new HashMap<String, List<String>>(); try { for (FileItem item : upload.parseRepresentation(entity)) { String name = item.getFieldName(); if (item.isFormField()) { try { if (!addFieldValue(name, item.getString("UTF-8"))) valid = false; } catch (UnsupportedEncodingException e) { if (!addFieldValue(name, item.getString())) valid = false; } } else { // the user can only add one file at a time // store the fileItem in a tempory variable and add to the map when requested currentFileItems.add(item); } } } catch (FileUploadException e) { valid = false; LOGGER.error("Error parsing form. ", e); } return valid; } public boolean saveForm(Form form) { boolean valid = true; formValues = new HashMap<String, List<String>>(); inputErrors = new HashMap<String, List<String>>(); for (String name : form.getNames()) { String[] values = form.getValuesArray(name); if (values != null) { for (String value : values) { if (!addFieldValue(name, value)) valid = false; } } } return valid; } /** * Save values from the form. * The currently selected file is not added to the map of files until it is request by calling addFile() * @param entity * @return */ public boolean saveFieldValues(Representation entity) { return saveMultipart(entity); } /** * Adds the currently selected file to the Map of files. * @return true if there is currenlty a file selected to add to the Map */ public boolean addFile(boolean descriptionRequired) { for (FileItem fileItem : currentFileItems) { final String description = getFirstFieldValue("file_description"); if (null == fileItem || fileItem.getName().equals("")) { addErrorMessage("file", "Please selected a file to upload."); return false; } if (descriptionRequired && description.equals("")) { addErrorMessage("file_description", "Description is a required field when uploading files."); return false; } String filename = fileItem.getName(); try { filename = URLEncoder.encode(fileItem.getName(), "UTF-8"); filename = filename.replace("+", "%20"); } catch (UnsupportedEncodingException e) { } fileNameToIndexMap.put(filename, fileIndex++); fileItemMap.put(fileIndex, fileItem); fileDescriptionMap.put(fileIndex, description); } removeFieldValues("file_description"); currentFileItems.clear(); return true; } private void addErrorMessage(String key, String message) { List<String> list = inputErrors.get(key); if (null == list) { list = new ArrayList<String>(); } list.add(message); inputErrors.put(key, list); } public void removeFile() { final String filename = getFirstFieldValue("fileToRemove"); final Integer index = fileNameToIndexMap.get(filename); fileNameToIndexMap.remove(filename); fileItemMap.remove(index); fileDescriptionMap.remove(index); } public boolean fieldExists(String fieldName) { return formValues.containsKey(fieldName); } public String getFirstFieldValue(String fieldName) { String value = ""; List<String> list = formValues.get(fieldName); if (null != list && list.size() > 0) { value = list.get(0); } return value; } public List<String> getFieldValues(String fieldName) { List<String> list = formValues.get(fieldName); if (null != list && list.size() > 0) { return list; } return Collections.emptyList(); } public Map<String, List<String>> getInputErrors() { return inputErrors; } public void setFirstFieldValue(String fieldName, String value) { List<String> list = formValues.get(value); if (null == list) { list = new ArrayList<String>(); } list.add(0, value); formValues.put(fieldName, list); } public void removeFieldValues(String fieldName) { formValues.remove(fieldName); } public List<String> getFileNames() { return new ArrayList<String>(fileNameToIndexMap.keySet()); } public Map<Integer, FileItem> getFileItemMap() { return fileItemMap; } public Map<Integer, String> getFileDescriptionMap() { return fileDescriptionMap; } public Iterator<FileItem> getFileIterator() { return fileItemMap.values().iterator(); } public String getFileDescription(String fileName) { return fileDescriptionMap.get(fileNameToIndexMap.get(fileName)); } public void resetFileFields() { fileNameToIndexMap = new HashMap<String, Integer>(); fileItemMap = new HashMap<Integer, FileItem>(); fileDescriptionMap = new HashMap<Integer, String>(); } public void resetAllFields() { resetFileFields(); formValues = new HashMap<String, List<String>>(); inputErrors = new HashMap<String, List<String>>(); } }