diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/filestorage/uploadrequest/FileUploadServletRequest.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/filestorage/uploadrequest/FileUploadServletRequest.java new file mode 100644 index 000000000..8dff4522b --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/filestorage/uploadrequest/FileUploadServletRequest.java @@ -0,0 +1,332 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.filestorage.uploadrequest; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.security.Principal; +import java.util.Enumeration; +import java.util.List; +import java.util.Locale; +import java.util.Map; + +import javax.servlet.RequestDispatcher; +import javax.servlet.ServletInputStream; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpSession; + +import org.apache.commons.fileupload.FileItem; +import org.apache.commons.fileupload.servlet.ServletFileUpload; + +/** + *

+ * Wraps an HTTP request and parses it for file uploads, without losing the + * request parameters. + *

+ *

+ * Most methods are declared here, and simply delegate to the wrapped request. + * Methods that have to do with parameters or files are handled differently for + * simple requests and multipart request, and are implemented in the + * sub-classes. + *

+ */ +public abstract class FileUploadServletRequest implements HttpServletRequest { + // ---------------------------------------------------------------------- + // The factory method + // ---------------------------------------------------------------------- + + /** + * Wrap this {@link HttpServletRequest} in an appropriate wrapper class. + */ + public static FileUploadServletRequest parseRequest( + HttpServletRequest request) throws IOException { + boolean isMultipart = ServletFileUpload.isMultipartContent(request); + if (isMultipart) { + return new MultipartHttpServletRequest(request); + } else { + return new SimpleHttpServletRequestWrapper(request); + } + } + + // ---------------------------------------------------------------------- + // The constructor and the delegate. + // ---------------------------------------------------------------------- + + private final HttpServletRequest delegate; + + public FileUploadServletRequest(HttpServletRequest delegate) { + this.delegate = delegate; + } + + protected HttpServletRequest getDelegate() { + return this.delegate; + } + + // ---------------------------------------------------------------------- + // New functionality to be implemented by the subclasses. + // ---------------------------------------------------------------------- + + public abstract boolean isMultipart(); + + public abstract Map> getFiles(); + + // ---------------------------------------------------------------------- + // Delegated methods. + // ---------------------------------------------------------------------- + + @Override + public String getAuthType() { + return delegate.getAuthType(); + } + + @Override + public String getContextPath() { + return delegate.getContextPath(); + } + + @Override + public Cookie[] getCookies() { + return delegate.getCookies(); + } + + @Override + public long getDateHeader(String name) { + return delegate.getDateHeader(name); + } + + @Override + public String getHeader(String name) { + return delegate.getHeader(name); + } + + @Override + public Enumeration getHeaderNames() { + return delegate.getHeaderNames(); + } + + @Override + public Enumeration getHeaders(String name) { + return delegate.getHeaders(name); + } + + @Override + public int getIntHeader(String name) { + return delegate.getIntHeader(name); + } + + @Override + public String getMethod() { + return delegate.getMethod(); + } + + @Override + public String getPathInfo() { + return delegate.getPathInfo(); + } + + @Override + public String getPathTranslated() { + return delegate.getPathTranslated(); + } + + @Override + public String getQueryString() { + return delegate.getQueryString(); + } + + @Override + public String getRemoteUser() { + return delegate.getRemoteUser(); + } + + @Override + public String getRequestURI() { + return delegate.getRequestURI(); + } + + @Override + public StringBuffer getRequestURL() { + return delegate.getRequestURL(); + } + + @Override + public String getRequestedSessionId() { + return delegate.getRequestedSessionId(); + } + + @Override + public String getServletPath() { + return delegate.getServletPath(); + } + + @Override + public HttpSession getSession() { + return delegate.getSession(); + } + + @Override + public HttpSession getSession(boolean create) { + return delegate.getSession(create); + } + + @Override + public Principal getUserPrincipal() { + return delegate.getUserPrincipal(); + } + + @Override + public boolean isRequestedSessionIdFromCookie() { + return delegate.isRequestedSessionIdFromCookie(); + } + + @Override + public boolean isRequestedSessionIdFromURL() { + return delegate.isRequestedSessionIdFromURL(); + } + + @SuppressWarnings("deprecation") + @Override + public boolean isRequestedSessionIdFromUrl() { + return delegate.isRequestedSessionIdFromUrl(); + } + + @Override + public boolean isRequestedSessionIdValid() { + return delegate.isRequestedSessionIdValid(); + } + + @Override + public boolean isUserInRole(String role) { + return delegate.isUserInRole(role); + } + + @Override + public Object getAttribute(String name) { + return delegate.getAttribute(name); + } + + @Override + public Enumeration getAttributeNames() { + return delegate.getAttributeNames(); + } + + @Override + public String getCharacterEncoding() { + return delegate.getCharacterEncoding(); + } + + @Override + public int getContentLength() { + return delegate.getContentLength(); + } + + @Override + public String getContentType() { + return delegate.getContentType(); + } + + @Override + public ServletInputStream getInputStream() throws IOException { + return delegate.getInputStream(); + } + + @Override + public String getLocalAddr() { + return delegate.getLocalAddr(); + } + + @Override + public String getLocalName() { + return delegate.getLocalName(); + } + + @Override + public int getLocalPort() { + return delegate.getLocalPort(); + } + + @Override + public Locale getLocale() { + return delegate.getLocale(); + } + + @Override + public Enumeration getLocales() { + return delegate.getLocales(); + } + + @Override + public String getProtocol() { + return delegate.getProtocol(); + } + + @Override + public BufferedReader getReader() throws IOException { + return delegate.getReader(); + } + + @SuppressWarnings("deprecation") + @Override + public String getRealPath(String path) { + return delegate.getRealPath(path); + } + + @Override + public String getRemoteAddr() { + return delegate.getRemoteAddr(); + } + + @Override + public String getRemoteHost() { + return delegate.getRemoteHost(); + } + + @Override + public int getRemotePort() { + return delegate.getRemotePort(); + } + + @Override + public RequestDispatcher getRequestDispatcher(String path) { + return delegate.getRequestDispatcher(path); + } + + @Override + public String getScheme() { + return delegate.getScheme(); + } + + @Override + public String getServerName() { + return delegate.getServerName(); + } + + @Override + public int getServerPort() { + return delegate.getServerPort(); + } + + @Override + public boolean isSecure() { + return delegate.isSecure(); + } + + @Override + public void removeAttribute(String name) { + delegate.removeAttribute(name); + } + + @Override + public void setAttribute(String name, Object o) { + delegate.setAttribute(name, o); + } + + @Override + public void setCharacterEncoding(String env) + throws UnsupportedEncodingException { + delegate.setCharacterEncoding(env); + } + +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/filestorage/uploadrequest/MultipartHttpServletRequest.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/filestorage/uploadrequest/MultipartHttpServletRequest.java new file mode 100644 index 000000000..4f174fc1f --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/filestorage/uploadrequest/MultipartHttpServletRequest.java @@ -0,0 +1,157 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.filestorage.uploadrequest; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import javax.servlet.http.HttpServletRequest; + +import org.apache.commons.fileupload.FileItem; +import org.apache.commons.fileupload.FileItemFactory; +import org.apache.commons.fileupload.FileUploadException; +import org.apache.commons.fileupload.disk.DiskFileItemFactory; +import org.apache.commons.fileupload.servlet.ServletFileUpload; +import org.apache.log4j.Logger; + +/** + * A wrapper for a servlet request that holds multipart content. Parsing the + * request will consume the parameters, so we need to hold them here to answer + * any parameter-related requests. File-related information will also be held + * here, to answer file-related requests. + */ +class MultipartHttpServletRequest extends FileUploadServletRequest { + private static final Logger LOG = Logger + .getLogger(MultipartHttpServletRequest.class); + + private static final String[] EMPTY_ARRAY = new String[0]; + + private final Map> parameters; + private final Map> files; + + /** + * Parse the multipart request. Store the info about the request parameters + * and the uploaded files. + */ + public MultipartHttpServletRequest(HttpServletRequest request) + throws IOException { + super(request); + + Map> parameters = new HashMap>(); + Map> files = new HashMap>(); + + try { + FileItemFactory factory = new DiskFileItemFactory(); + ServletFileUpload upload = new ServletFileUpload(factory); + List items = parseRequestIntoFileItems(request, upload); + for (FileItem item : items) { + // Process a regular form field + if (item.isFormField()) { + addToParameters(parameters, item.getFieldName(), item + .getString()); + LOG.debug("Form field (parameter) " + item.getFieldName() + + "=" + item.getString()); + } else { + addToFileItems(files, item); + LOG.debug("File " + item.getFieldName() + ": " + + item.getName()); + } + } + } catch (FileUploadException e) { + String message = "Failed to parse a multipart-content request."; + LOG.error(message, e); + throw new IOException(message, e); + } + + this.parameters = Collections.unmodifiableMap(parameters); + LOG.debug("Parameters are: " + this.parameters); + this.files = Collections.unmodifiableMap(files); + LOG.debug("Files are: " + this.files); + } + + /** Either create a new List for the value, or add to an existing List. */ + private void addToParameters(Map> map, String name, + String value) { + if (!map.containsKey(name)) { + map.put(name, new ArrayList()); + } + map.get(name).add(value); + } + + /** Either create a new List for the file, or add to an existing List. */ + private void addToFileItems(Map> map, + FileItem file) { + String name = file.getFieldName(); + if (!map.containsKey(name)) { + map.put(name, new ArrayList()); + } + map.get(name).add(file); + } + + /** Minimize the code that uses the unchecked cast. */ + @SuppressWarnings("unchecked") + private List parseRequestIntoFileItems(HttpServletRequest req, + ServletFileUpload upload) throws FileUploadException { + return upload.parseRequest(req); + } + + // ---------------------------------------------------------------------- + // This is a multipart request, so make the file info available. + // ---------------------------------------------------------------------- + + @Override + public boolean isMultipart() { + return true; + } + + @Override + public Map> getFiles() { + return files; + } + + // ---------------------------------------------------------------------- + // Parameter-related methods won't find anything on the delegate request, + // since parsing consumed the parameters. So we need to look to the parsed + // info for the answers. + // ---------------------------------------------------------------------- + + @Override + public String getParameter(String name) { + if (parameters.containsKey(name)) { + return parameters.get(name).get(0); + } else { + return null; + } + } + + @Override + public Enumeration getParameterNames() { + return Collections.enumeration(parameters.keySet()); + } + + @Override + public String[] getParameterValues(String name) { + if (parameters.containsKey(name)) { + return parameters.get(name).toArray(EMPTY_ARRAY); + } else { + return null; + } + } + + @Override + public Map getParameterMap() { + Map result = new HashMap(); + for (Entry> entry : parameters.entrySet()) { + result.put(entry.getKey(), entry.getValue().toArray(EMPTY_ARRAY)); + } + LOG.debug("resulting parameter map: " + result); + return result; + } + +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/filestorage/uploadrequest/SimpleHttpServletRequestWrapper.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/filestorage/uploadrequest/SimpleHttpServletRequestWrapper.java new file mode 100644 index 000000000..91e98f16b --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/filestorage/uploadrequest/SimpleHttpServletRequestWrapper.java @@ -0,0 +1,64 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.filestorage.uploadrequest; + +import java.util.Collections; +import java.util.Enumeration; +import java.util.List; +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; + +import org.apache.commons.fileupload.FileItem; + +/** + * A wrapper for a servlet request that does not hold multipart content. Pass + * all parameter-related requests to the delegate, and give simple answers to + * all file-related requests. + */ +class SimpleHttpServletRequestWrapper extends FileUploadServletRequest { + + SimpleHttpServletRequestWrapper(HttpServletRequest request) { + super(request); + } + + // ---------------------------------------------------------------------- + // Not a multipart request, so there are no files. + // ---------------------------------------------------------------------- + + @Override + public boolean isMultipart() { + return false; + } + + @Override + public Map> getFiles() { + return Collections.emptyMap(); + } + + // ---------------------------------------------------------------------- + // Since this is not a multipart request, the parameter methods can be + // delegated. + // ---------------------------------------------------------------------- + + @Override + public String getParameter(String name) { + return getDelegate().getParameter(name); + } + + @Override + public Map getParameterMap() { + return getDelegate().getParameterMap(); + } + + @Override + public Enumeration getParameterNames() { + return getDelegate().getParameterNames(); + } + + @Override + public String[] getParameterValues(String name) { + return getDelegate().getParameterValues(name); + } + +}