Revision: 380
Author: tfenne
Date: 2006-08-14 17:18:37 -0700 (Mon, 14 Aug 2006)
ViewCVS: http://svn.sourceforge.net/stripes/?rev=380&view=rev
Log Message:
-----------
Changes to implement the pluggability of the file upload code, and include an
apache commons implementation.
Modified Paths:
--------------
trunk/stripes/src/net/sourceforge/stripes/config/Configuration.java
trunk/stripes/src/net/sourceforge/stripes/config/DefaultConfiguration.java
trunk/stripes/src/net/sourceforge/stripes/config/RuntimeConfiguration.java
trunk/stripes/src/net/sourceforge/stripes/controller/FileUploadLimitExceededException.java
trunk/stripes/src/net/sourceforge/stripes/controller/StripesFilter.java
trunk/stripes/src/net/sourceforge/stripes/controller/StripesRequestWrapper.java
trunk/stripes/stripes.iml
Added Paths:
-----------
trunk/stripes/lib/test/commons-fileupload-1.1.1.jar
trunk/stripes/lib/test/commons-io-1.2.jar
trunk/stripes/src/net/sourceforge/stripes/controller/multipart/
trunk/stripes/src/net/sourceforge/stripes/controller/multipart/CommonsMultipartWrapper.java
trunk/stripes/src/net/sourceforge/stripes/controller/multipart/CosMultipartWrapper.java
trunk/stripes/src/net/sourceforge/stripes/controller/multipart/DefaultMultipartWrapperFactory.java
trunk/stripes/src/net/sourceforge/stripes/controller/multipart/MultipartWrapper.java
trunk/stripes/src/net/sourceforge/stripes/controller/multipart/MultipartWrapperFactory.java
Added: trunk/stripes/lib/test/commons-fileupload-1.1.1.jar
===================================================================
(Binary files differ)
Property changes on: trunk/stripes/lib/test/commons-fileupload-1.1.1.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/stripes/lib/test/commons-io-1.2.jar
===================================================================
(Binary files differ)
Property changes on: trunk/stripes/lib/test/commons-io-1.2.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Modified: trunk/stripes/src/net/sourceforge/stripes/config/Configuration.java
===================================================================
--- trunk/stripes/src/net/sourceforge/stripes/config/Configuration.java
2006-08-14 18:24:12 UTC (rev 379)
+++ trunk/stripes/src/net/sourceforge/stripes/config/Configuration.java
2006-08-15 00:18:37 UTC (rev 380)
@@ -25,6 +25,7 @@
import net.sourceforge.stripes.format.FormatterFactory;
import net.sourceforge.stripes.controller.Interceptor;
import net.sourceforge.stripes.controller.LifecycleStage;
+import net.sourceforge.stripes.controller.multipart.MultipartWrapperFactory;
import net.sourceforge.stripes.exception.ExceptionHandler;
import javax.servlet.ServletContext;
@@ -175,4 +176,13 @@
* @return ExceptionHandler an instance of ExceptionHandler
*/
ExceptionHandler getExceptionHandler();
+
+ /**
+ * Returns an instance of MultipartWrapperFactory that can be used by
Stripes to construct
+ * MultipartWrapper instances for dealing with multipart requests (those
containing file
+ * uploads).
+ *
+ * @return MultipartWrapperFactory an instance of the wrapper factory
+ */
+ MultipartWrapperFactory getMultipartWrapperFactory();
}
Modified:
trunk/stripes/src/net/sourceforge/stripes/config/DefaultConfiguration.java
===================================================================
--- trunk/stripes/src/net/sourceforge/stripes/config/DefaultConfiguration.java
2006-08-14 18:24:12 UTC (rev 379)
+++ trunk/stripes/src/net/sourceforge/stripes/config/DefaultConfiguration.java
2006-08-15 00:18:37 UTC (rev 380)
@@ -24,6 +24,8 @@
import net.sourceforge.stripes.controller.Intercepts;
import net.sourceforge.stripes.controller.LifecycleStage;
import net.sourceforge.stripes.controller.NameBasedActionResolver;
+import net.sourceforge.stripes.controller.multipart.MultipartWrapperFactory;
+import
net.sourceforge.stripes.controller.multipart.DefaultMultipartWrapperFactory;
import net.sourceforge.stripes.exception.DefaultExceptionHandler;
import net.sourceforge.stripes.exception.ExceptionHandler;
import net.sourceforge.stripes.exception.StripesRuntimeException;
@@ -80,6 +82,7 @@
private PopulationStrategy populationStrategy;
private Map<LifecycleStage,Collection<Interceptor>> interceptors;
private ExceptionHandler exceptionHandler;
+ private MultipartWrapperFactory multipartWrapperFactory;
/** Gratefully accepts the BootstrapPropertyResolver handed to the
Configuration. */
public void setBootstrapPropertyResolver(BootstrapPropertyResolver
resolver) {
@@ -152,6 +155,12 @@
this.exceptionHandler.init(this);
}
+ this.multipartWrapperFactory = initMultipartWrapperFactory();
+ if (this.multipartWrapperFactory == null) {
+ this.multipartWrapperFactory = new
DefaultMultipartWrapperFactory();
+ this.multipartWrapperFactory.init(this);
+ }
+
this.interceptors = initInterceptors();
if (this.interceptors == null) {
this.interceptors = new HashMap<LifecycleStage,
Collection<Interceptor>>();
@@ -296,6 +305,21 @@
protected ExceptionHandler initExceptionHandler() { return null; }
/**
+ * Returns an instance of MultipartWrapperFactory that can be used by
Stripes to construct
+ * MultipartWrapper instances for dealing with multipart requests (those
containing file
+ * uploads).
+ *
+ * @return MultipartWrapperFactory an instance of the wrapper factory
+ */
+ public MultipartWrapperFactory getMultipartWrapperFactory() {
+ return this.multipartWrapperFactory;
+ }
+
+
+ /** Allows subclasses to initialize a non-default MultipartWrapperFactory.
*/
+ protected MultipartWrapperFactory initMultipartWrapperFactory() { return
null; }
+
+ /**
* Returns a list of interceptors that should be executed around the
lifecycle stage
* indicated. By default returns a single element list containing the
* [EMAIL PROTECTED] BeforeAfterMethodInterceptor}.
Modified:
trunk/stripes/src/net/sourceforge/stripes/config/RuntimeConfiguration.java
===================================================================
--- trunk/stripes/src/net/sourceforge/stripes/config/RuntimeConfiguration.java
2006-08-14 18:24:12 UTC (rev 379)
+++ trunk/stripes/src/net/sourceforge/stripes/config/RuntimeConfiguration.java
2006-08-15 00:18:37 UTC (rev 380)
@@ -20,6 +20,7 @@
import net.sourceforge.stripes.controller.Interceptor;
import net.sourceforge.stripes.controller.Intercepts;
import net.sourceforge.stripes.controller.LifecycleStage;
+import net.sourceforge.stripes.controller.multipart.MultipartWrapperFactory;
import net.sourceforge.stripes.exception.StripesRuntimeException;
import net.sourceforge.stripes.exception.ExceptionHandler;
import net.sourceforge.stripes.format.FormatterFactory;
@@ -85,6 +86,9 @@
/** The Configuration Key for looking up the name of the ExceptionHandler
class */
public static final String EXCEPTION_HANDLER = "ExceptionHandler.Class";
+ /** The Configuration Key for looking up the name of the
MultipartWrapperFactory class */
+ public static final String MULTIPART_WRAPPER_FACTORY =
"MultipartWrapperFactory.Class";
+
/** The Configuration Key for looking up the comma separated list of
interceptor classes. */
public static final String INTERCEPTOR_LIST = "Interceptor.Classes";
@@ -139,6 +143,11 @@
return initializeComponent(ExceptionHandler.class, EXCEPTION_HANDLER);
}
+ /** Looks for a class name in config and uses that to create the
component. */
+ @Override protected MultipartWrapperFactory initMultipartWrapperFactory() {
+ return initializeComponent(MultipartWrapperFactory.class,
MULTIPART_WRAPPER_FACTORY);
+ }
+
/**
* Looks for a list of class names separated by commas under the
configuration key
* [EMAIL PROTECTED] #INTERCEPTOR_LIST}. White space surrounding the
class names is trimmed,
Modified:
trunk/stripes/src/net/sourceforge/stripes/controller/FileUploadLimitExceededException.java
===================================================================
---
trunk/stripes/src/net/sourceforge/stripes/controller/FileUploadLimitExceededException.java
2006-08-14 18:24:12 UTC (rev 379)
+++
trunk/stripes/src/net/sourceforge/stripes/controller/FileUploadLimitExceededException.java
2006-08-15 00:18:37 UTC (rev 380)
@@ -23,8 +23,8 @@
* @author Tim Fennell
*/
public class FileUploadLimitExceededException extends StripesServletException {
- private int maximum;
- private int posted;
+ private long maximum;
+ private long posted;
/**
* Constructs a new exception that contains the limt that was violated,
and the size
@@ -33,15 +33,15 @@
* @param max the current post size limit
* @param posted the size of the post
*/
- public FileUploadLimitExceededException(int max, int posted) {
+ public FileUploadLimitExceededException(long max, long posted) {
super("File post limit exceeded. Limit: " + max + " bytes. Posted: " +
posted + " bytes.");
this.maximum = max;
this.posted = posted;
}
/** Gets the limit in bytes for HTTP POSTs. */
- public int getMaximum() { return maximum; }
+ public long getMaximum() { return maximum; }
/** The size in bytes of the HTTP POST. */
- public int getPosted() { return posted; }
+ public long getPosted() { return posted; }
}
\ No newline at end of file
Modified:
trunk/stripes/src/net/sourceforge/stripes/controller/StripesFilter.java
===================================================================
--- trunk/stripes/src/net/sourceforge/stripes/controller/StripesFilter.java
2006-08-14 18:24:12 UTC (rev 379)
+++ trunk/stripes/src/net/sourceforge/stripes/controller/StripesFilter.java
2006-08-15 00:18:37 UTC (rev 380)
@@ -17,8 +17,8 @@
import net.sourceforge.stripes.config.BootstrapPropertyResolver;
import net.sourceforge.stripes.config.Configuration;
import net.sourceforge.stripes.config.RuntimeConfiguration;
-import net.sourceforge.stripes.exception.StripesServletException;
import net.sourceforge.stripes.exception.StripesRuntimeException;
+import net.sourceforge.stripes.exception.StripesServletException;
import net.sourceforge.stripes.util.Log;
import net.sourceforge.stripes.util.ReflectUtil;
@@ -30,14 +30,11 @@
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
-import java.io.File;
import java.io.IOException;
import java.util.Collection;
+import java.util.Iterator;
import java.util.Locale;
import java.util.Map;
-import java.util.Iterator;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
/**
* The Stripes filter is used to ensure that all requests coming to a Stripes
application
@@ -52,21 +49,12 @@
/** Key used to lookup the name of the Configuration class used to
configure Stripes. */
public static final String CONFIG_CLASS = "Configuration.Class";
- /** Key used to lookup the name of the maximum post size. */
- public static final String MAX_POST = "FileUpload.MaximumPostSize";
-
- /** Path to a temporary directory that will be used to process file
uploads. */
- protected String temporaryDirectoryPath;
-
/** Log used throughout the class. */
private static Log log = Log.getInstance(StripesFilter.class);
/** The configuration instance for Stripes. */
private Configuration configuration;
- /** Stores the maximum post size for a form upload request. */
- private int maxPostSize = 1024 * 1024 * 10;
-
/**
* A place to stash the Configuration object so that other classes in
Stripes can access it
* without resorting to ferrying it, or the request, to every class that
needs access to the
@@ -107,40 +95,6 @@
this.configuration.setBootstrapPropertyResolver(bootstrap);
this.configuration.init();
- // Figure out where the temp directory is, and store that info
- File tempDir = (File)
filterConfig.getServletContext().getAttribute("javax.servlet.context.tempdir");
- if (tempDir != null) {
- this.temporaryDirectoryPath = tempDir.getAbsolutePath();
- }
- else {
- this.temporaryDirectoryPath = System.getProperty("java.io.tmpdir");
- }
-
- // See if a maximum post size was configured
- String limit = bootstrap.getProperty(MAX_POST);
- if (limit != null) {
- Pattern pattern = Pattern.compile("([\\d,]+)([kKmMgG]?).*");
- Matcher matcher = pattern.matcher(limit);
- if (!matcher.matches()) {
- log.warn("Did not understand value of configuration parameter
", MAX_POST,
- " You supplied: ", limit, ". Valid values are any
string of numbers ",
- "optionally followed by (case insensitive)
[k|kb|m|mb|g|gb]. ",
- "Default value of ", this.maxPostSize, " bytes will
be used instead.");
- }
- else {
- String digits = matcher.group(1);
- String suffix = matcher.group(2).toLowerCase();
- int number = Integer.parseInt(digits);
-
- if ("k".equals(suffix)) { number = number * 1024; }
- else if ("m".equals(suffix)) { number = number * 1024 * 1024;
}
- else if ("g".equals(suffix)) { number = number * 1024 * 1024 *
1024; }
-
- this.maxPostSize = number;
- log.info("Configured file upload post size limit: ", number, "
bytes.");
- }
- }
-
Package pkg = getClass().getPackage();
log.info("Stripes Initialization Complete. Version: ",
pkg.getSpecificationVersion(),
", Build: ", pkg.getImplementationVersion());
@@ -246,11 +200,7 @@
*/
protected StripesRequestWrapper wrapRequest(HttpServletRequest
servletRequest)
throws StripesServletException {
- String tempDirPath = getTempDirectoryPath();
-
- StripesRequestWrapper request =
- new StripesRequestWrapper(servletRequest, tempDirPath,
this.maxPostSize);
- return request;
+ return new StripesRequestWrapper(servletRequest);
}
/**
@@ -292,12 +242,6 @@
}
}
- /** Returns the path to the temporary directory that is used to store file
uploads. */
- protected String getTempDirectoryPath() {
- return this.temporaryDirectoryPath;
- }
-
-
/** Does nothing. */
public void destroy() {
// Do nothing
Modified:
trunk/stripes/src/net/sourceforge/stripes/controller/StripesRequestWrapper.java
===================================================================
---
trunk/stripes/src/net/sourceforge/stripes/controller/StripesRequestWrapper.java
2006-08-14 18:24:12 UTC (rev 379)
+++
trunk/stripes/src/net/sourceforge/stripes/controller/StripesRequestWrapper.java
2006-08-15 00:18:37 UTC (rev 380)
@@ -14,23 +14,21 @@
*/
package net.sourceforge.stripes.controller;
-import com.oreilly.servlet.MultipartRequest;
import net.sourceforge.stripes.action.FileBean;
+import net.sourceforge.stripes.controller.multipart.MultipartWrapper;
import net.sourceforge.stripes.exception.StripesServletException;
+import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
-import javax.servlet.ServletRequest;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
-import java.util.Map;
-import java.util.Locale;
-import java.util.Collections;
import java.util.List;
-import java.util.ArrayList;
-import java.util.regex.Pattern;
-import java.util.regex.Matcher;
-import java.io.IOException;
+import java.util.Locale;
+import java.util.Map;
/**
* HttpServletRequestWrapper that is used to make the file upload
functionality transparent.
@@ -40,15 +38,9 @@
*
* @author Tim Fennell
*/
[EMAIL PROTECTED]("CLASS") // Request has some deprecated methods we don't
touch, so don't warn us!
public class StripesRequestWrapper extends HttpServletRequestWrapper {
-
- /** Pattern used to parse useful info out of the IOException cos throws. */
- private static Pattern exceptionPattern =
- Pattern.compile("Posted content length of (\\d*) exceeds limit of
(\\d*)");
-
/** The Multipart Request that parses out all the pieces. */
- private MultipartRequest multipart;
+ private MultipartWrapper multipart;
/** The Locale that is going to be used to process the request. */
private Locale locale;
@@ -91,55 +83,38 @@
* just wrapped and the behaviour is unchanged.
*
* @param request the HttpServletRequest to wrap
- * @param pathToTempDir the path to a temporary directory in which to
store files during upload
- * @param maxTotalPostSize a limit on how much can be uploaded in a single
request. Note that
* this is not a file size limit, but a post size limit.
* @throws FileUploadLimitExceededException if the total post size is
larger than the limit
* @throws StripesServletException if any other error occurs constructing
the wrapper
*/
- public StripesRequestWrapper(HttpServletRequest request,
- String pathToTempDir,
- int maxTotalPostSize) throws
StripesServletException {
+ public StripesRequestWrapper(HttpServletRequest request) throws
StripesServletException {
super(request);
String contentType = request.getContentType();
if (contentType != null &&
contentType.startsWith("multipart/form-data")) {
- constructMultipartRequest(request, pathToTempDir,
maxTotalPostSize);
+ constructMultipartWrapper(request);
}
}
/**
- * Responsible for constructing the MultipartRequest object and setting it
on to
+ * Responsible for constructing the MultipartWrapper object and setting it
on to
* the instnace variable 'multipart'.
*
* @param request the HttpServletRequest to wrap
- * @param pathToTempDir the path to a temporary directory in which to
store files during upload
- * @param maxTotalPostSize a limit on how much can be uploaded in a single
request. Note that
* this is not a file size limit, but a post size limit.
* @throws StripesServletException if any other error occurs constructing
the wrapper
*/
- protected void constructMultipartRequest(HttpServletRequest request,
- String pathToTempDir,
- int maxTotalPostSize) throws
StripesServletException {
+ protected void constructMultipartWrapper(HttpServletRequest request)
throws StripesServletException {
try {
- this.multipart = new MultipartRequest(request,
- pathToTempDir,
- maxTotalPostSize,
-
request.getCharacterEncoding());
+ this.multipart =
+
StripesFilter.getConfiguration().getMultipartWrapperFactory().wrap(request);
}
catch (IOException e) {
- Matcher matcher = exceptionPattern.matcher(e.getMessage());
-
- if (matcher.matches()) {
- throw new
FileUploadLimitExceededException(Integer.parseInt(matcher.group(2)),
-
Integer.parseInt(matcher.group(1)));
- }
- else {
- throw new StripesServletException("Could not construct request
wrapper.", e);
- }
+ throw new StripesServletException("Could not construct request
wrapper.", e);
}
}
+ /** Returns true if this request is wrapping a multipart request, false
otherwise. */
public boolean isMultipart() {
return this.multipart != null;
}
@@ -167,16 +142,7 @@
*/
public String[] getParameterValues(String name) {
if ( isMultipart() ) {
- String[] values = this.multipart.getParameterValues(name);
- if (values != null) {
- for (int i=0; i<values.length; ++i) {
- if (values[i] == null) {
- values[i] = "";
- }
- }
- }
-
- return values;
+ return this.multipart.getParameterValues(name);
}
else {
return super.getParameterValues(name);
@@ -252,7 +218,7 @@
* no file upload parameters are submitted returns an empty enumeration.
*/
public Enumeration<String> getFileParameterNames() {
- return this.multipart.getFileNames();
+ return this.multipart.getFileParameterNames();
}
/**
@@ -264,11 +230,8 @@
* @return a FileBean if a file was actually submitted by the user,
otherwise null
*/
public FileBean getFileParameterValue(String name) {
-
- if (this.multipart.getFile(name) != null) {
- return new FileBean(this.multipart.getFile(name),
- this.multipart.getContentType(name),
- this.multipart.getOriginalFileName(name));
+ if (this.multipart != null) {
+ return this.multipart.getFileParameterValue(name);
}
else {
return null;
Added:
trunk/stripes/src/net/sourceforge/stripes/controller/multipart/CommonsMultipartWrapper.java
===================================================================
---
trunk/stripes/src/net/sourceforge/stripes/controller/multipart/CommonsMultipartWrapper.java
(rev 0)
+++
trunk/stripes/src/net/sourceforge/stripes/controller/multipart/CommonsMultipartWrapper.java
2006-08-15 00:18:37 UTC (rev 380)
@@ -0,0 +1,196 @@
+/* Copyright 2005-2006 Tim Fennell
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package net.sourceforge.stripes.controller.multipart;
+
+import net.sourceforge.stripes.action.FileBean;
+import net.sourceforge.stripes.controller.FileUploadLimitExceededException;
+import org.apache.commons.fileupload.disk.DiskFileItemFactory;
+import org.apache.commons.fileupload.servlet.ServletFileUpload;
+import org.apache.commons.fileupload.FileItem;
+import org.apache.commons.fileupload.FileUploadException;
+import org.apache.commons.fileupload.FileUploadBase;
+
+import javax.servlet.http.HttpServletRequest;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.ArrayList;
+import java.util.Iterator;
+
+/**
+ * An implementation of MultipartWrapper that uses Jakarta Commons FileUpload
(from apache)
+ * to parse the request parts. This implementation requires that both
commons-fileupload and
+ * commons-io be present in the classpath. While this implementation does
introduce additional
+ * dependencies, it's licensing (ASL 2.0) is significantly less restrictive
than the licesing
+ * for COS - the other alternative provided by Stripes.
+ *
+ * @author Tim Fennell
+ * @since Stripes 1.4
+ */
+public class CommonsMultipartWrapper implements MultipartWrapper {
+ private Map<String,FileItem> files = new HashMap<String,FileItem>();
+ private Map<String,String[]> parameters = new HashMap<String, String[]>();
+
+ /**
+ * Pseudo-constructor that allows the class to perform any initialization
necessary.
+ *
+ * @param request an HttpServletRequest that has a content-type of
multipart.
+ * @param tempDir a File representing the temporary directory that can be
used to store
+ * file parts as they are uploaded if this is desirable
+ * @param maxPostSize the size in bytes beyond which the request should
not be read, and a
+ * FileUploadLimitExceeded exception should be thrown
+ * @throws IOException if a problem occurrs processing the request of
storing temporary
+ * files
+ * @throws FileUploadLimitExceededException if the POST content is longer
than the
+ * maxPostSize supplied.
+ */
+ public void build(HttpServletRequest request, File tempDir, long
maxPostSize)
+ throws IOException, FileUploadLimitExceededException {
+ try {
+ DiskFileItemFactory factory = new DiskFileItemFactory();
+ factory.setRepository(tempDir);
+ ServletFileUpload upload = new ServletFileUpload(factory);
+ upload.setSizeMax(maxPostSize);
+ List<FileItem> items = upload.parseRequest(request);
+ Map<String,List<String>> params = new HashMap<String,
List<String>>();
+
+ for (FileItem item : items) {
+ // If it's a form field, add the string value to the list
+ if (item.isFormField()) {
+ List<String> values = params.get(item.getFieldName());
+ if (values == null) {
+ values = new ArrayList<String>();
+ params.put(item.getFieldName(), values);
+ }
+ values.add(item.getString());
+ }
+ // Else store the file param
+ else {
+ files.put(item.getFieldName(), item);
+ }
+ }
+
+ // Now convert them down into the usual map of String->String[]
+ for (Map.Entry<String,List<String>> entry : params.entrySet()) {
+ List<String> values = entry.getValue();
+ this.parameters.put(entry.getKey(), values.toArray(new
String[values.size()]));
+ }
+ }
+ catch (FileUploadBase.SizeLimitExceededException slee) {
+ throw new FileUploadLimitExceededException(maxPostSize,
slee.getActualSize());
+ }
+ catch (FileUploadException fue) {
+ IOException ioe = new IOException("Could not parse and cache file
upload data.");
+ ioe.initCause(fue);
+ throw ioe;
+ }
+
+ }
+
+ /**
+ * Fetches the names of all non-file parameters in the request. Directly
analogous to the
+ * method of the same name in HttpServletRequest when the request is
non-multipart.
+ *
+ * @return an Enumeration of all non-file parameter names in the rqequest
+ */
+ public Enumeration<String> getParameterNames() {
+ return new IteratorEnumeration(this.parameters.keySet().iterator());
+ }
+
+ /**
+ * Fetches all values of a specifical parameter in the request. To
simulate the HTTP request
+ * style, the array should be null for non-present parameters, and values
in the array should
+ * never be null - the empty String should be used when there is value.
+ *
+ * @param name the name of the request parameter
+ * @return an array of non-null parameters or null
+ */
+ public String[] getParameterValues(String name) {
+ return this.parameters.get(name);
+ }
+
+ /**
+ * Fetches the names of all file parameters in the request. Note that
these are not the file
+ * names, but the names given to the form fields in which the files are
specified.
+ *
+ * @return the names of all file parameters in the request.
+ */
+ public Enumeration<String> getFileParameterNames() {
+ return new IteratorEnumeration(this.files.keySet().iterator());
+ }
+
+ /**
+ * Responsible for contructing a FileBean object for the named file
parameter. If there is no
+ * file parameter with the specified name this method should return null.
+ *
+ * @param name the name of the file parameter
+ * @return a FileBean object wrapping the uploaded file
+ */
+ public FileBean getFileParameterValue(String name) {
+ final FileItem item = this.files.get(name);
+ if (item == null) {
+ return null;
+ }
+ else {
+ // Use an anonymous inner subclass of FileBean that overrides all
the
+ // methods that rely on having a File present, to use the FileItem
+ // created by commons upload instead.
+ return new FileBean(null, item.getContentType(), item.getName()) {
+ @Override public long getSize() { return item.getSize(); }
+
+ @Override public InputStream getInputStream() throws
IOException {
+ return item.getInputStream();
+ }
+
+ @Override public void save(File toFile) throws IOException {
+ try {
+ item.write(toFile);
+ delete();
+ }
+ catch (Exception e) {
+ if (e instanceof IOException) throw (IOException) e;
+ else {
+ IOException ioe = new IOException("Problem saving
uploaded file.");
+ ioe.initCause(e);
+ throw ioe;
+ }
+ }
+ }
+
+ @Override
+ public void delete() throws IOException { item.delete(); }
+ };
+ }
+ }
+
+ /** Little helper class to create an enumeration as per the interface. */
+ private static class IteratorEnumeration implements Enumeration<String> {
+ Iterator<String> iterator;
+
+ /** Constructs an enumeration that consumes from the underlying
iterator. */
+ IteratorEnumeration(Iterator<String> iterator) { this.iterator =
iterator; }
+
+ /** Returns true if more elements can be consumed, false otherwise. */
+ public boolean hasMoreElements() { return this.iterator.hasNext(); }
+
+ /** Gets the next element out of the iterator. */
+ public String nextElement() { return this.iterator.next(); }
+ }
+}
+
Added:
trunk/stripes/src/net/sourceforge/stripes/controller/multipart/CosMultipartWrapper.java
===================================================================
---
trunk/stripes/src/net/sourceforge/stripes/controller/multipart/CosMultipartWrapper.java
(rev 0)
+++
trunk/stripes/src/net/sourceforge/stripes/controller/multipart/CosMultipartWrapper.java
2006-08-15 00:18:37 UTC (rev 380)
@@ -0,0 +1,140 @@
+/* Copyright 2005-2006 Tim Fennell
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package net.sourceforge.stripes.controller.multipart;
+
+import com.oreilly.servlet.MultipartRequest;
+import net.sourceforge.stripes.action.FileBean;
+import net.sourceforge.stripes.controller.FileUploadLimitExceededException;
+
+import javax.servlet.http.HttpServletRequest;
+import java.io.IOException;
+import java.io.File;
+import java.util.Enumeration;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Implementation of MultipartWrapper that uses Jason Hunter's COS
(com.oreilly.servlet)
+ * multipart parser implementation. This is the default implementation in
Stripes and is
+ * generally preferred as it is a) free for use and b) has no other
dependencies! However,
+ * commercial redistribution of the COS library requires licensing from Jason
Hunter, so
+ * this implemenation may not be applicable for commercial products that are
distributed/sold
+ * (though it is fine for commercial applications that are simply developed
and hosted by the
+ * company developing them).
+ *
+ * @author Tim Fennell
+ * @since Stripes 1.4
+ */
+public class CosMultipartWrapper implements MultipartWrapper {
+ /** Pattern used to parse useful info out of the IOException cos throws. */
+ private static Pattern EXCEPTION_PATTERN =
+ Pattern.compile("Posted content length of (\\d*) exceeds limit of
(\\d*)");
+
+ private MultipartRequest multipart;
+ /**
+ * Pseudo-constructor that allows the class to perform any initialization
necessary.
+ *
+ * @param request an HttpServletRequest that has a content-type of
multipart.
+ * @param tempDir a File representing the temporary directory that can be
used to store
+ * file parts as they are uploaded if this is desirable
+ * @param maxPostSize the size in bytes beyond which the request should
not be read, and a
+ * FileUploadLimitExceeded exception should be thrown
+ * @throws IOException if a problem occurrs processing the request of
storing temporary
+ * files
+ * @throws FileUploadLimitExceededException if the POST content is longer
than the
+ * maxPostSize supplied.
+ */
+ public void build(HttpServletRequest request, File tempDir, long
maxPostSize)
+ throws IOException, FileUploadLimitExceededException {
+
+ try {
+ this.multipart = new MultipartRequest(request,
+ tempDir.getAbsolutePath(),
+ (int) maxPostSize,
+
request.getCharacterEncoding());
+ }
+ catch (IOException ioe) {
+ Matcher matcher = EXCEPTION_PATTERN.matcher(ioe.getMessage());
+
+ if (matcher.matches()) {
+ throw new
FileUploadLimitExceededException(Long.parseLong(matcher.group(2)),
+
Long.parseLong(matcher.group(1)));
+ }
+ else {
+ throw ioe;
+ }
+ }
+ }
+
+ /**
+ * Fetches the names of all non-file parameters in the request. Directly
analogous to the method
+ * of the same name in HttpServletRequest when the request is
non-multipart.
+ *
+ * @return an Enumeration of all non-file parameter names in the rqequest
+ */
+ public Enumeration<String> getParameterNames() {
+ return this.multipart.getParameterNames();
+ }
+
+ /**
+ * Fetches all values of a specifical parameter in the request. To
simulate the HTTP request
+ * style, the array should be null for non-present parameters, and values
in the array should
+ * never be null - the empty String should be used when there is value.
+ *
+ * @param name the name of the request parameter
+ * @return an array of non-null parameters or null
+ */
+ public String[] getParameterValues(String name) {
+ String[] values = this.multipart.getParameterValues(name);
+ if (values != null) {
+ for (int i=0; i<values.length; ++i) {
+ if (values[i] == null) {
+ values[i] = "";
+ }
+ }
+ }
+
+ return values;
+ }
+
+ /**
+ * Fetches the names of all file parameters in the request. Note that
these are not the file
+ * names, but the names given to the form fields in which the files are
specified.
+ *
+ * @return the names of all file parameters in the request.
+ */
+ public Enumeration<String> getFileParameterNames() {
+ return this.multipart.getFileNames();
+ }
+
+ /**
+ * Responsible for contructing a FileBean object for the named file
parameter. If there is no
+ * file parameter with the specified name this method should return null.
+ *
+ * @param name the name of the file parameter
+ * @return a FileBean object wrapping the uploaded file
+ */
+ public FileBean getFileParameterValue(String name) {
+ File file = this.multipart.getFile(name);
+ if (file != null) {
+ return new FileBean(file,
+ this.multipart.getContentType(name),
+ this.multipart.getOriginalFileName(name));
+ }
+ else {
+ return null;
+ }
+ }
+}
Added:
trunk/stripes/src/net/sourceforge/stripes/controller/multipart/DefaultMultipartWrapperFactory.java
===================================================================
---
trunk/stripes/src/net/sourceforge/stripes/controller/multipart/DefaultMultipartWrapperFactory.java
(rev 0)
+++
trunk/stripes/src/net/sourceforge/stripes/controller/multipart/DefaultMultipartWrapperFactory.java
2006-08-15 00:18:37 UTC (rev 380)
@@ -0,0 +1,135 @@
+/* Copyright 2005-2006 Tim Fennell
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package net.sourceforge.stripes.controller.multipart;
+
+import net.sourceforge.stripes.controller.FileUploadLimitExceededException;
+import net.sourceforge.stripes.config.Configuration;
+import net.sourceforge.stripes.util.Log;
+import net.sourceforge.stripes.exception.StripesRuntimeException;
+
+import javax.servlet.http.HttpServletRequest;
+import java.io.IOException;
+import java.io.File;
+import java.util.regex.Pattern;
+import java.util.regex.Matcher;
+
+/**
+ * <p>Default implementation of a factory for MultipartWrappers. Looks up a
class name in
+ * Configuration under the key specified by [EMAIL PROTECTED]
#WRAPPER_CLASS_NAME}. If no class
+ * name is configured, defaults to the [EMAIL PROTECTED] CosMultipartWrapper}.
An additional configuration
+ * parameter is supported to specify the maximum post size allowable.</p>
+ *
+ * @author Tim Fennell
+ * @since Stripes 1.4
+ */
+public class DefaultMultipartWrapperFactory implements MultipartWrapperFactory
{
+ /** The configuration key used to lookup the implementation of
MultipartWrapper. */
+ public static final String WRAPPER_CLASS_NAME = "MultipartWrapper.Class";
+
+ /** The name of the MultipartWrapper class that will be used if no other
is specified. */
+ public static final String DEFAULT_IMPLEMENTATION =
+ "net.sourceforge.stripes.controller.multipart.CosMultipartWrapper";
+
+ /** Key used to lookup the name of the maximum post size. */
+ public static final String MAX_POST = "FileUpload.MaximumPostSize";
+
+ private static final Log log =
Log.getInstance(DefaultMultipartWrapperFactory.class);
+
+ // Instance level fields
+ private Class<? extends MultipartWrapper> multipartClass;
+ private long maxPostSizeInBytes = 1024 * 1024 * 10; // Defaults to 10MB
+ private File temporaryDirectory;
+
+ /**
+ * Invoked directly after instantiation to allow the configured component
to perform one time
+ * initialization. Components are expected to fail loudly if they are not
going to be in a
+ * valid state after initialization.
+ *
+ * @param config the Configuration object being used by Stripes
+ * @throws Exception should be thrown if the component cannot be
configured well enough to use.
+ */
+ public void init(Configuration config) throws Exception {
+ // Determine which class we're using
+ String type =
config.getBootstrapPropertyResolver().getProperty(WRAPPER_CLASS_NAME);
+ if (type == null) type = DEFAULT_IMPLEMENTATION;
+ try {
+ this.multipartClass = (Class<? extends MultipartWrapper>)
Class.forName(type);
+ }
+ catch (ClassNotFoundException cnfe) {
+ throw new StripesRuntimeException
+ ("Could not find configured MultipartWrapper type '" +
type + "'.", cnfe);
+ }
+
+ // Figure out where the temp directory is, and store that info
+ File tempDir = (File)
config.getServletContext().getAttribute("javax.servlet.context.tempdir");
+ if (tempDir != null) {
+ this.temporaryDirectory = tempDir;
+ }
+ else {
+ this.temporaryDirectory = new
File(System.getProperty("java.io.tmpdir")).getAbsoluteFile();
+ }
+
+ // See if a maximum post size was configured
+ String limit =
config.getBootstrapPropertyResolver().getProperty(MAX_POST);
+ if (limit != null) {
+ Pattern pattern = Pattern.compile("([\\d,]+)([kKmMgG]?).*");
+ Matcher matcher = pattern.matcher(limit);
+ if (!matcher.matches()) {
+ log.error("Did not understand value of configuration parameter
", MAX_POST,
+ " You supplied: ", limit, ". Valid values are any
string of numbers ",
+ "optionally followed by (case insensitive)
[k|kb|m|mb|g|gb]. ",
+ "Default value of ", this.maxPostSizeInBytes, " bytes
will be used instead.");
+ }
+ else {
+ String digits = matcher.group(1);
+ String suffix = matcher.group(2).toLowerCase();
+ int number = Integer.parseInt(digits);
+
+ if ("k".equals(suffix)) { number = number * 1024; }
+ else if ("m".equals(suffix)) { number = number * 1024 * 1024;
}
+ else if ("g".equals(suffix)) { number = number * 1024 * 1024 *
1024; }
+
+ this.maxPostSizeInBytes = number;
+ log.info("Configured file upload post size limit: ", number, "
bytes.");
+ }
+ }
+
+
+ }
+
+ /**
+ * Wraps the request in an appropriate implementation of MultipartWrapper
that is capable of
+ * providing access to request parameters and any file parts contained
within the request.
+ *
+ * @param request an active HttpServletRequest
+ * @return an implementation of the appropriate wrapper
+ * @throws IOException if encountered when consuming the contents of the
request
+ * @throws FileUploadLimitExceededException if the post size of the
request exceeds any
+ * configured limits
+ */
+ public MultipartWrapper wrap(HttpServletRequest request) throws
IOException, FileUploadLimitExceededException {
+ try {
+ MultipartWrapper wrapper = this.multipartClass.newInstance();
+ wrapper.build(request, this.temporaryDirectory,
this.maxPostSizeInBytes);
+ return wrapper;
+ }
+ catch (IOException ioe) { throw ioe; }
+ catch (FileUploadLimitExceededException fulee) { throw fulee; }
+ catch (Exception e) {
+ throw new StripesRuntimeException
+ ("Could not construct a MultipartWrapper for the " +
"current request.", e);
+ }
+ }
+}
Added:
trunk/stripes/src/net/sourceforge/stripes/controller/multipart/MultipartWrapper.java
===================================================================
---
trunk/stripes/src/net/sourceforge/stripes/controller/multipart/MultipartWrapper.java
(rev 0)
+++
trunk/stripes/src/net/sourceforge/stripes/controller/multipart/MultipartWrapper.java
2006-08-15 00:18:37 UTC (rev 380)
@@ -0,0 +1,83 @@
+/* Copyright 2005-2006 Tim Fennell
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package net.sourceforge.stripes.controller.multipart;
+
+import net.sourceforge.stripes.controller.FileUploadLimitExceededException;
+import net.sourceforge.stripes.action.FileBean;
+
+import javax.servlet.http.HttpServletRequest;
+import java.io.IOException;
+import java.io.File;
+import java.util.Enumeration;
+
+/**
+ * Interface which must be implemented by classes which provide the ability to
parse
+ * the POST content when it is of type multipart/form-data. Provides a single,
pluggable
+ * wrapper interface around third party libraries which provide this
capability.
+ *
+ * @author Tim Fennell
+ * @since Stripes 1.4
+ */
+public interface MultipartWrapper {
+ /**
+ * Pseudo-constructor that allows the class to perform any initialization
necessary.
+ *
+ * @param request an HttpServletRequest that has a content-type of
multipart.
+ * @param tempDir a File representing the temporary directory that can be
used to store
+ * file parts as they are uploaded if this is desirable
+ * @param maxPostSize the size in bytes beyond which the request should
not be read,
+ * and a FileUploadLimitExceeded exception should be thrown
+ * @throws IOException if a problem occurrs processing the request of
storing temporary files
+ * @throws FileUploadLimitExceededException if the POST content is longer
than the maxPostSize
+ * supplied.
+ */
+ void build(HttpServletRequest request, File tempDir, long maxPostSize)
+ throws IOException, FileUploadLimitExceededException;
+
+ /**
+ * Fetches the names of all non-file parameters in the request. Directly
analogous to the
+ * method of the same name in HttpServletRequest when the request is
non-multipart.
+ *
+ * @return an Enumeration of all non-file parameter names in the rqequest
+ */
+ Enumeration<String> getParameterNames();
+
+ /**
+ * Fetches all values of a specifical parameter in the request. To
simulate the HTTP
+ * request style, the array should be null for non-present parameters, and
values in the
+ * array should never be null - the empty String should be used when there
is value.
+ *
+ * @param name the name of the request parameter
+ * @return an array of non-null parameters or null
+ */
+ String[] getParameterValues(String name);
+
+ /**
+ * Fetches the names of all file parameters in the request. Note that
these are not the
+ * file names, but the names given to the form fields in which the files
are specified.
+ *
+ * @return the names of all file parameters in the request.
+ */
+ Enumeration<String> getFileParameterNames();
+
+ /**
+ * Responsible for contructing a FileBean object for the named file
parameter. If there is
+ * no file parameter with the specified name this method should return
null.
+ *
+ * @param name the name of the file parameter
+ * @return a FileBean object wrapping the uploaded file
+ */
+ FileBean getFileParameterValue(String name);
+}
Added:
trunk/stripes/src/net/sourceforge/stripes/controller/multipart/MultipartWrapperFactory.java
===================================================================
---
trunk/stripes/src/net/sourceforge/stripes/controller/multipart/MultipartWrapperFactory.java
(rev 0)
+++
trunk/stripes/src/net/sourceforge/stripes/controller/multipart/MultipartWrapperFactory.java
2006-08-15 00:18:37 UTC (rev 380)
@@ -0,0 +1,44 @@
+/* Copyright 2005-2006 Tim Fennell
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package net.sourceforge.stripes.controller.multipart;
+
+import net.sourceforge.stripes.config.ConfigurableComponent;
+import net.sourceforge.stripes.controller.FileUploadLimitExceededException;
+
+import javax.servlet.http.HttpServletRequest;
+import java.io.IOException;
+
+/**
+ * Factory for classes that implement [EMAIL PROTECTED] MultipartWrapper}. The
factory may chose to
+ * always supply the same kind of wrapper, or vary the implementation request
by request
+ * as it sees fit.
+ *
+ * @author Tim Fennell
+ * @since Stripes 1.4
+ */
+public interface MultipartWrapperFactory extends ConfigurableComponent {
+ /**
+ * Wraps the request in an appropriate implementation of MultipartWrapper
that is capable
+ * of providing access to request parameters and any file parts contained
within the
+ * request.
+ *
+ * @param request an active HttpServletRequest
+ * @return an implementation of the appropriate wrapper
+ * @throws IOException if encountered when consuming the contents of the
request
+ * @throws FileUploadLimitExceededException if the post size of the
request exceeds
+ * any configured limits
+ */
+ MultipartWrapper wrap(HttpServletRequest request) throws IOException,
FileUploadLimitExceededException;
+}
Modified: trunk/stripes/stripes.iml
===================================================================
--- trunk/stripes/stripes.iml 2006-08-14 18:24:12 UTC (rev 379)
+++ trunk/stripes/stripes.iml 2006-08-15 00:18:37 UTC (rev 380)
@@ -77,6 +77,15 @@
<SOURCES />
</library>
</orderEntry>
+ <orderEntry type="module-library" exported="">
+ <library>
+ <CLASSES>
+ <root
url="jar://$MODULE_DIR$/lib/test/commons-fileupload-1.1.1.jar!/" />
+ </CLASSES>
+ <JAVADOC />
+ <SOURCES />
+ </library>
+ </orderEntry>
<orderEntryProperties />
<javadoc-paths>
<root url="file://$MODULE_DIR$/docs" />
This was sent by the SourceForge.net collaborative development platform, the
world's largest Open Source development site.
-------------------------------------------------------------------------
Using Tomcat but need to do more? Need to support web services, security?
Get stuff done quickly with pre-integrated technology to make your job easier
Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642
_______________________________________________
Stripes-development mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/stripes-development