Newsletter sign-up
View all newsletters

Enterprise Java Newsletter
Stay up to date on the latest tutorials and Java community news posted on JavaWorld

Sponsored Links

Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs

Filter code with Servlet 2.3 model

Discover freely available servlet filters you can use today

  • Print
  • Feedback

Page 5 of 5

The doFilter() method examines the request content type, and should it be a multipart/form-data request, wraps the request with a MultipartWrapper. The wrapper code looks like this:

package com.oreilly.servlet;
import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class MultipartWrapper extends HttpServletRequestWrapper {
  MultipartRequest mreq = null;
  public MultipartWrapper(HttpServletRequest req, String dir)
                                     throws IOException {
    super(req);
    mreq = new MultipartRequest(req, dir);
  }
  // Methods to replace HSR methods
  public Enumeration getParameterNames() {
    return mreq.getParameterNames();
  }
  public String getParameter(String name) {
    return mreq.getParameter(name);
  }
  public String[] getParameterValues(String name) {
    return mreq.getParameterValues(name);
  }
  public Map getParameterMap() {
    Map map = new HashMap();
    Enumeration enum = getParameterNames();
    while (enum.hasMoreElements()) {
      String name = (String) enum.nextElement();
      map.put(name, mreq.getParameterValues(name));
    }
    return map;
  }
  // Methods only in MultipartRequest
  public Enumeration getFileNames() {
    return mreq.getFileNames();
  }
  public String getFilesystemName(String name) {
    return mreq.getFilesystemName(name);
  }
  public String getContentType(String name) {
    return mreq.getContentType(name);
  }
  public File getFile(String name) {
    return mreq.getFile(name);
  }
}


The wrapper constructs a com.oreilly.servlet.MultipartRequestobject to handle the upload parsing and overrides the getParameter() family of methods to use the MultipartRequest rather than the raw request to read parameter values. The wrapper also defines various getFile() methods so that a servlet receiving this wrapped request can call additional methods to handle the uploaded files.

The web.xml deployment descriptor adds the filter like this:

<
filter>
    <filter-name>multipartFilter</filter-name>
    <filter-class>com.oreilly.servlet.MultipartFilter</filter-class>
    <!--
    <init-param>
      <param-name>uploadDir</param-name>
      <param-value>/tmp</param-value>
    </init-param>
    -->
</filter>
<filter-mapping>
    <filter-name>multipartFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
<servlet>
    <servlet-name>
        uploadTest
    </servlet-name>
    <servlet-class>
        UploadTest
    </servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>
        uploadTest
    </servlet-name>
    <url-pattern>
        /uploadTest
    </url-pattern>
</servlet-mapping>


The UploadTest servlet looks like this:

import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
import com.oreilly.servlet.*;
public class UploadTest extends HttpServlet {
  public void doPost(HttpServletRequest req, HttpServletResponse res)
                                throws ServletException, IOException {
    res.setContentType("text/html");
    PrintWriter out = res.getWriter();
    out.println("<HTML>");
    out.println("<HEAD><TITLE>UploadTest</TITLE></HEAD>");
    out.println("<BODY>");
    out.println("<H1>UploadTest</H1>");
    // Parameters can now be read the same way for both
    // application/x-www-form-urlencoded and multipart/form-data requests!
    out.println("<H3>Request Parameters:</H3><PRE>");
    Enumeration enum = req.getParameterNames();
    while (enum.hasMoreElements()) {
      String name = (String) enum.nextElement();
      String values[] = req.getParameterValues(name);
      if (values != null) {
        for (int i = 0; i < values.length; i++) {
          out.println(name + " (" + i + "): " + values[i]);
        }
      }
    }
    out.println("</PRE>");
    // Files can be read if the request class is MultipartWrapper
    // Init params to MultipartWrapper control the upload handling
    if (req instanceof MultipartWrapper) {
      try {
        // Cast the request to a MultipartWrapper
        MultipartWrapper multi = (MultipartWrapper) req;
        // Show which files we received
        out.println("<H3>Files:</H3>");
        out.println("<PRE>");
        Enumeration files = multi.getFileNames();
        while (files.hasMoreElements()) {
          String name = (String)files.nextElement();
          String filename = multi.getFilesystemName(name);
          String type = multi.getContentType(name);
          File f = multi.getFile(name);
          out.println("name: " + name);
          out.println("filename: " + filename);
          out.println("type: " + type);
          if (f != null) {
            out.println("length: " + f.length());
          }
          out.println();
        }
        out.println("</PRE>");
      }
      catch (Exception e) {
        out.println("<PRE>");
        e.printStackTrace(out);
        out.println("</PRE>");
      }
    }
    out.println("</BODY></HTML>");
  }
}


The first half of the servlet shows how the filter exposes parameter data without any change to the receiving servlet. The second half shows how a servlet can downcase the request to a MultipartWrapperin order to expose the additional file-access methods.

An example HTML form to drive this servlet is shown here:

<
FORM ACTION="uploadTest" ENCTYPE="multipart/form-data" METHOD=POST>
What is your name? <INPUT TYPE=TEXT NAME=submitter> <BR>
What is your age? <INPUT TYPE=TEXT NAME=age> <BR>
Which file do you want to upload? <INPUT TYPE=FILE NAME=file1> <BR>
Any other file to upload? <INPUT TYPE=FILE NAME=file2> <BR>
<INPUT TYPE=SUBMIT>
</FORM>


Here's some possible output:

UploadTest
Request Parameters:
submitter (0): Jason
age (0): 28
Files:
name: file1
filename: 4008b21.tif
type: application/octet-stream
length: 39396
name: file2
filename: null
type: null


Some of you may wonder what assurance we have that the MultipartWrapperset by the filter will be directly exposed to the follow-on servlet. In the specification Public Draft #2 and in Tomcat 4.0 beta 5, there is no guarantee. In fact, if you try to access the servlet as /servlet/UploadTest, you'll notice the filtering doesn't work quite right, because the invoker handling /servlet wraps the MultipartWrapperwith its own Tomcat-specific wrapper. This allows the parameters to be parsed correctly, but the file access methods won't be directly exposed. In discussing this issue with the Servlet API expert group, we've decided that the servlet container shouldn't do further wrapping beyond the filter's wrapper. The servlet specification will be updated to make that clear. Later betas of Tomcat 4.0 will comply with the clarified rules. A short-term workaround is to use the getRequest()method in the request wrapper to "walk up" the request to find the shadowed multipart wrapper.

Download the WAR file for this filter at http://www.javaworld.com/jw-06-2001/Filters/mulitpart.war.

Filter power

Servlet filters provide a powerful ability to control request processing and response generation, providing new functionality to servlets without large amounts of servlet coding. I hope these filters have shown you some of what is possible to do with filters, and taught you some tricks about how to make the most effective use of the new filter mechanism.

My thanks to the authors of these filters and to the people who suggested useful filters to write about: Amy Roh, Criag McClanahan, Serge Knystautas, and the folks at OpenSymphony.

About the author

Jason Hunteris a senior technologist with CollabNet, a company that provides tools and services for collaborative software development based on open source concepts. He is author of Java Servlet Programming, 2nd Edition (O'Reilly, April 2001), publisher of Servlets.com, and contributor to Apache Tomcat (starting on the project when it was still Sun internal). He is also a member of the expert groups responsible for Servlet/JSP and JAXP API development, and holds a seat on the JCP Executive Committee overseeing the Java platform, as a representative of the Apache Software Foundation. Most recently he cocreated the open source JDOM library to enable optimized Java and XML integration.

Read more about Enterprise Java in JavaWorld's Enterprise Java section.

  • Print
  • Feedback

Resources