In this recipe you will see how to implement a JSF application for downloading files. To accomplish this task we will use a dedicated component developed under the Mojarra Scales project. Since, we haven't used it before in this book let's say that this project "is a JSF component library that started out in the JSF RI Sandbox. Currently, Scales offers a number of components which, primarily, wrap some of the excellent Yahoo! User Interface (YUI) JavaScript widgets. Scales goes beyond those widgets, though, and offers a number of other useful components such as a multi-file upload component and a dynamic content 'download' component."
We developed this recipe with NetBeans 6.8, JSF 1.2, and GlassFish v3. The JSF 1.2 classes were obtained from the NetBeans JSF 1.2 bundled library. In addition, we have used Mojarra Scales 1.3.2, which provides support for JSF 1.2. You can download this distribution from http://kenai.com/projects/scales. The Mojarra Scales libraries (including necessary dependencies) are in the book code bundle, under the /JSF_libs/Mojarra Scales JSF 1.2 folder
.
As we said earlier, we will download files using a dedicated component of Mojarra Scales. This component is mapped by the download
tag, which supports a set of attributes that provide us with fine control over download configuration. The following table is an overview of these attributes (you can check a detailed list of attributes in the official documentation (http://kenai.com/projects/scales)—the following table is a snapshot of the original javadoc):
Name |
Required |
Description |
---|---|---|
|
No |
The component unique identifier. |
|
No |
A |
|
Yes |
The current value of this component. |
|
No |
The method for displaying the object: |
|
No |
The mime type of the object. |
|
No |
The filename of the object; used only for |
|
No |
The width of the object to be displayed; used only for |
|
No |
The height of the object to be displayed; used only for |
|
No |
A Boolean value indicating whether or not to use an |
|
No |
If set, this property will cause an EL variable by the name of |
|
No |
A flag indicating whether or not this component should be rendered (during |
|
No |
A flag indicating that this element must never receive focus or be included in a subsequent submit. A value of |
Now, based on the attribute's description, we have configured two download tags, one for downloading a JPG image and one for downloading a PDF document:
… <!-- For an image use: --> <h:outputText value="Download RafaNadal.jpg image:" /><br /> <sc:download method="download" mimeType="image/jpg" fileName="RafaNadal.jpg" data="#{downloadBean.image}"> <h:graphicImage alt="Download" url="/download.jpg" /> </sc:download> <!-- For a pdf document use: --> <br /> <h:outputText value="Download RafaNadal.pdf document:" /><br /> <sc:download method="download" mimeType="application/pdf" fileName="RafaNadal.pdf" data="#{downloadBean.pdf}"> <h:graphicImage alt="Download" url="/download.jpg" /> </sc:download> …
Now, let's focus on the data
attribute. This attribute is an EL expression that resolves to the content of the file to be downloaded. This data can be returned as a byte[], InputStream
, or a ByteArrayOutputStream
. Based on this information and on TestBean
provided in the Mojarra Scales examples, we can easily develop our DownloadBean
as follows:
package downloadbeanpkg; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import javax.faces.context.FacesContext; public class DownloadBean { public byte[] getPdf() { ByteArrayOutputStream baos = new ByteArrayOutputStream(); InputStream is = null; try { //is = Thread.currentThread().getContextClassLoader(). //getResourceAsStream("/RafaNadal.pdf"); FacesContext.getCurrentInstance().getExternalContext(). getResourceAsStream("/RafaNadal.pdf"); int count = 0; byte[] buffer = new byte[4096]; while ((count = is.read(buffer)) != -1) { if (count > 0) { baos.write(buffer, 0, count); } } } catch (IOException e) { System.err.println(e.getMessage()); } finally { if (is != null) { try { is.close(); } catch (Exception e) { // just make sure it's closed } } } return baos.toByteArray(); } public byte[] getImage() { ByteArrayOutputStream baos = new ByteArrayOutputStream(); InputStream is = null; try { //is = Thread.currentThread().getContextClassLoader(). //getResourceAsStream("/RafaNadal.png"); FacesContext.getCurrentInstance().getExternalContext(). getResourceAsStream("/RafaNadal.jpg"); int count = 0; byte[] buffer = new byte[4096]; while ((count = is.read(buffer)) != -1) { if (count > 0) { baos.write(buffer, 0, count); } } } catch (IOException e) { System.err.println(e.getMessage()); } finally { if (is != null) { try { is.close(); } catch (Exception e) { // just make sure it's closed } } } return baos.toByteArray(); }
This component is really rather simple. The download
tag encapsulates the download parameters, while a simple bean provides the requested file through a ByteArrayOutputStream
object. The filename is indicated in the fileName
attribute, while the corresponding bean name and method are indicated in the data
attribute.