Foundation
Project Documentation

Overview

The JavaServer Faces (JSF) specification provides no direct support for file uploads. (And, unfortunately, nothing else in the J2EE technology stack does either.) MyFaces Trinidad provides integrated support for processing file uploads in a manner natural to JSF applications, by providing a component that delivers standard ValueChangeEvents as files are uploaded, and managing processing of the uploaded content transparently.

Setup

File upload processing requires the installation of the MyFaces Trinidad Filter. This filter is required for all MyFaces Trinidad applications. One of its features is handling file uploads. To install the filter, first add the following entry to your WEB-INF/web.xml file:

  <filter>
    <filter-name>trinidad</filter-name>
    <filter-class>org.apache.myfaces.trinidad.webapp.TrinidadFilter</filter-class>
  </filter>

Second, map that filter to process all FacesServlet requests. For example, if you've named the FacesServlet "faces":

  <servlet>
    <servlet-name>faces</servlet-name>
    <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
  </servlet>

...then use the following filter-mapping:

  <filter-mapping>
    <filter-name>trinidad</filter-name>
    <servlet-name>faces</servlet-name>
  </filter-mapping>

inputFile

To support uploading a file on your page, use the <tr:inputFile> component. Like all other input components, <tr:inputFile> sends ValueChangeEvents. And like all MyFaces Trinidad input components, it has built-in support for accessibility, labels, and messages.

       <tr:inputFile label="Upload:"
                     valueChangeListener="#{backingBean.fileUploaded}"/>
                          

<tr:inputFile> can be placed in either an <h:form> tag or an <tr:form> tag, but in either case you have to set it to support file upload. For the JSF Basic HTML form, that involves setting the "enctype" to the correct magic value; for the MyFaces Trinidad form, just set "usesUpload" to true:

     <tr:form usesUpload="true">
       <tr:inputFile label="Upload:"
                     valueChangeListener="#{backingBean.fileUploaded}"/>
     </tr:form>
     <!-- or -->
     <h:form enctype="multipart/form-data">
       <tr:inputFile label="Upload:"
                     valueChangeListener="#{backingBean.fileUploaded}"/>
     </h:form>

The "value" of an inputFile component is an instance of the org.apache.myfaces.trinidad.model.UploadedFile interface. This API lets you get at the actual byte stream of the file, as well as the file's name, its MIME type, and its size. The UploadedFile might be stored as a file in the filesystem, but might also be stored in memory; this API hides that difference. The filter ensures that the UploadedFile content is cleaned up after the request is complete. Because of this, you cannot usefully cache UploadedFile objects across requests. If you need to keep the file, you must copy it into persistent storage before the request finishes.

Example

For an example of processing a file upload, instead of actually storing it anywhere, we'll just add a message telling the user that the file was successfully uploaded. The page content is simple:

     <tr:form usesUpload="true">
       <tr:inputFile label="Upload:"
                     valueChangeListener="#{backingBean.fileUploaded}"/>
       <tr:commandButton text="Begin"/>
     </tr:form>

Now, in our backing bean, we'll handle the ValueChangeEvent:

import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.faces.event.ValueChangeEvent;
import org.apache.myfaces.trinidad.model.UploadedFile;

public class ABackingBean
{
  ...
  public void fileUploaded(ValueChangeEvent event)
  {
    UploadedFile file = (UploadedFile) event.getNewValue();
    if (file != null)
    {
      FacesContext context = FacesContext.getCurrentInstance();
      FacesMessage message = new FacesMessage(
         "Successfully uploaded file " + file.getFilename() +
         " (" + file.getLength() + " bytes)");
      context.addMessage(event.getComponent().getClientId(context), message);
      // Here's where we could call file.getInputStream()
    }
  }
}

Here, we've chosen to use ValueChangeEvents. You could also bind the value of the inputFile directly to a managed bean:

     <tr:form usesUpload="true">
       <tr:inputFile label="Upload:" value="#{managedBean.file}"/>
       <tr:commandButton text="Begin" action="#{managedBean.doUpload}"/>
     </tr:form>
import org.apache.myfaces.trinidad.model.UploadedFile;

public class AManagedBean
{
  public UploadedFile getFile()
  {
    return _file;
  }

  public void setFile(UploadedFile file)
  {
    _file = file;
  }

  public String doUpload()
  {
    UploadedFile file = getFile();
    // ... and process it in some way
  }


  private UploadedFile _file;
}

Configuration

Because MyFaces Trinidad will temporarily store incoming files (either on disk or in memory), by default it limits the size of acceptable incoming requests to avoid denial-of-service attacks that might attempt to fill a hard drive or flood memory with uploaded files. By default, only the first 100 kilobytes in any one request will be stored in memory. Once that has been filled, disk space will be used. Again, by default, that is limited to 2,000 kilobytes of disk storage for any one request for all files combined. Once these limits are exceeded, the filter will throw an EOFException. Files are, by default, stored in the temporary directory used by java.io.File.createTempFile(), which is usually defined by the system property java.io.tmpdir. Obviously, this will be insufficient for some applications, so you can configure these values using three servlet context initialization parameters:

  <context-param>
    <!-- Maximum memory per request (in bytes) -->
    <param-name>org.apache.myfaces.trinidad.UPLOAD_MAX_MEMORY</param-name>
    <!-- Use 500K -->
    <param-value>512000</param-value>
  </context-param>
  <context-param>
    <!-- Maximum disk space per request (in bytes) -->
    <param-name>org.apache.myfaces.trinidad.UPLOAD_MAX_DISK_SPACE</param-name>
    <!-- Use 5,000K -->
    <param-value>5120000</param-value>
  </context-param>
  <context-param>
    <!-- directory to store temporary files -->
    <param-name>org.apache.myfaces.trinidad.UPLOAD_TEMP_DIR</param-name>
    <!-- Use a TrinidadUploads subdirectory of /tmp -->
    <param-value>/tmp/TrinidadUploads/</param-value>
  </context-param>

  <!-- This filter is always required;  one of its functions is 
          file upload. -->
  <filter>
    <filter-name>trinidad</filter-name>
    <filter-class>org.apache.myfaces.trinidad.webapp.TrinidadFilter</filter-class>
  </filter>

Developers can also customize file upload more comprehensively in trinidad-config.xml with the following elements:

<uploaded-file-processor>
The org.apache.myfaces.trinidad.webapp.UploadedFileProcessor can be replaced by specifying a new class with the <uploaded-file-processor> element.
<uploaded-file-max-memory>
The servlet context param org.apache.myfaces.trinidad.UPLOAD_MAX_MEMORY can be overridden by <uploaded-file-max-memory> if this param needs to be bound to an EL expression.
<uploaded-file-max-disk-space>
The servlet context param org.apache.myfaces.trinidad.UPLOAD_MAX_DISK_SPACE can be overridden by <uploaded-file-max-disk-space> if this param needs to be bound to an EL expression.
<uploaded-file-temp-dir>
The servlet context param org.apache.myfaces.trinidad.UPLOAD_TEMP_DIR can be overridden by <uploaded-file-temp-dir> if this param needs to be bound to an EL expression.

Please see the Configuration chapter for more information on these trinidad-config.xml elements. NOTE: Replacing the UploadedFileProcessor makes the init-params listed above irrelevant; they are only processed by the default UploadedFileProcessor, unless they are specifically taken into consideration by the class that replaces the deault file processor class.