Overview
The JavaServer Faces (JSF) 1.1 specification provides no direct support for
file uploads. (And, unfortunately, nothing else in the J2EE
technology stack does either.) ADF Faces 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 ADF Faces Filter.
This filter is required for all ADF Faces 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>adfFaces</filter-name>
<filter-class>oracle.adf.view.faces.webapp.AdfFacesFilter</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>adfFaces</filter-name>
<servlet-name>faces</servlet-name>
</filter-mapping>
inputFile
To support uploading a file on your page, use the
<
af:inputFile
>
component
. Like all other input components,
<
af:inputFile
>
sends
ValueChangeEvents
. And like all ADF Faces input components,
it has built-in support for accessibility, labels, and messages.
<af:inputFile label="Upload:"
valueChangeListener="#{backingBean.fileUploaded}"/>
<
af:inputFile
>
can be placed in either an
<
h:form
>
tag or an
<
af: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 ADF Faces
form, just set "usesUpload" to true:
<af:form usesUpload="true">
<af:inputFile label="Upload:"
valueChangeListener="#{backingBean.fileUploaded}"/>
</af:form>
<!-- or -->
<h:form enctype="multipart/form-data">
<af:inputFile label="Upload:"
valueChangeListener="#{backingBean.fileUploaded}"/>
</h:form>
The
"value"
of an inputFile component is an instance of
the
oracle.adf.view.faces.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 h
ides 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:
<af:form usesUpload="true">
<af:inputFile label="Upload:"
valueChangeListener="#{backingBean.fileUploaded}"/>
<af:commandButton text="Begin"/>
</af: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 oracle.adf.view.faces.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:
<af:form usesUpload="true">
<af:inputFile label="Upload:" value="#{managedBean.file}"/>
<af:commandButton text="Begin" action="#{managedBean.doUpload}"/>
</af:form>
import oracle.adf.view.faces.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 ADF Faces 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>oracle.adf.view.faces.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>oracle.adf.view.faces.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>oracle.adf.view.faces.UPLOAD_TEMP_DIR</param-name>
<!-- Use an ADFUploads subdirectory of /tmp -->
<param-value>/tmp/ADFUploads/</param-value>
</context-param>
<!-- This filter is always required by ADF; one of its functions is
file upload. -->
<filter>
<filter-name>adfFaces</filter-name>
<filter-class>oracle.adf.view.faces.webapp.AdfFacesFilter</filter-class>
</filter>
Developers can also customize file upload more comprehensively
by replacing the entire
oracle.adf.view.faces.webapp.UploadedFileProcessor
with the
<
uploaded-file-processor
>
element
in
adf-faces-config.xml
. Please see the
Configuration
chapter for
more information on that element. Replacing the
UploadedFileProcessor
makes the init-params listed
above irrelevant; they are only processed by the default
UploadedFileProcessor
.