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>
<uploaded-file-max-memory>
<uploaded-file-max-disk-space>
<uploaded-file-temp-dir>
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.