podd.util.FormHandler.java Source code

Java tutorial

Introduction

Here is the source code for podd.util.FormHandler.java

Source

/*
 * 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("\"", "&quot;");
            value = value.replaceAll("<http://", "&lt;http&#58;//");
            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>>();
    }
}