FileDownloadServlet.java
// license-header java merge-point
// Generated by andromda-jsf cartridge (utils\download\FileDownloadServlet.java.vsl) DO NOT EDIT!
package org.andromda.presentation.jsf;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Properties;
import javax.faces.context.FacesContext;
import javax.faces.el.MethodBinding;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang.ObjectUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* This servlet is used to download files. It can be used by
* including it an output link, like the following:
*
* <h:outputLink value="/my-jsf-app-context/fileDownload?action=myControllerBean.myControllerOperation&prompt=true&fileName=exportResultFileName&outputName=exportResult">
* <h:outputText value="#{messages['export']}"/>
* </h:outputLink>
*
* The following parameters may be specified:
* <ul>
* <li>fileName:</li> the name of the property on the the action form that has the name of your download file.
* <li>outputName:</li> the name of the property on the action form that has the output to download.
* <li>contentType:</li> any explicit content type to be used for the download (if not specified, it will be guessed
* from the extension of the specified file).
* <li>action:</li> the optional action to execute before downloading is attempted.
* </ul>
*/
public class FileDownloadServlet
extends HttpServlet
{
private static final Log logger = LogFactory.getLog(FileDownloadServlet.class);
private static final long serialVersionUID = 1L;
/**
* The name of an action on a controller to execute before attempt to render the download.
*/
private static final String ACTION = "action";
/**
* Whether or not to prompt with a "save as" dialog, or just render the download in the browser.
*/
private static final String PROMPT = "prompt";
/**
* The name of the property on the action form that has the name of the file to use when downloading.
*/
private static final String FILE_NAME = "fileName";
/**
* The name of the property on the action form that will contain the output.
*/
private static final String OUTPUT = "outputName";
/**
* The contentType parameter specifies what content type to render the download as
*/
private static final String CONTENT_TYPE = "contentType";
private static final int BUFFER_SIZE = 4096;
/**
* @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
*/
@Override
public void doGet(final HttpServletRequest request, final HttpServletResponse response)
throws ServletException,
IOException
{
try
{
final String action = request.getParameter(ACTION);
final FacesContext context = FacesContextUtils.getFacesContext(request, response);
if (action != null && action.trim().length() > 0)
{
final MethodBinding methodBinding = context.getApplication().createMethodBinding("#{" + action + "}", null);
methodBinding.invoke(context, null);
}
final Object form = context.getApplication().getVariableResolver().resolveVariable(context, "form");
final Boolean prompt = Boolean.valueOf(request.getParameter(PROMPT));
final String fileNameProperty = request.getParameter(FILE_NAME);
final String outputProperty = request.getParameter(OUTPUT);
if (form != null && outputProperty != null && fileNameProperty.trim().length() > 0)
{
final OutputStream stream = response.getOutputStream();
// - reset the response to clear out any any headers (i.e. so
// the user doesn't get "unable to open..." when using IE.)
response.reset();
Object output = PropertyUtils.getProperty(form, outputProperty);
final String fileName = ObjectUtils.toString(PropertyUtils.getProperty(form, fileNameProperty));
final String contentType = this.getContentType(context, request.getParameter(CONTENT_TYPE), fileName);
if (prompt.booleanValue() && fileName != null && fileName.trim().length() > 0)
{
response.addHeader(
"Content-disposition",
"attachment; filename=\"" + fileName + '"');
}
// - for IE we need to set the content type, content length and buffer size and
// then the flush the response right away because it seems as if there is any lag time
// IE just displays a blank page. With mozilla based clients reports display correctly regardless.
if (contentType != null && contentType.length() > 0)
{
response.setContentType(contentType);
}
if (output instanceof String)
{
output = ((String)output).getBytes();
}
if (output instanceof byte[])
{
byte[] file = (byte[])output;
response.setBufferSize(file.length);
response.setContentLength(file.length);
response.flushBuffer();
stream.write(file);
}
else if (output instanceof InputStream)
{
final InputStream report = (InputStream)output;
final byte[] buffer = new byte[BUFFER_SIZE];
response.setBufferSize(BUFFER_SIZE);
response.flushBuffer();
for (int ctr = 0; (ctr = report.read(buffer)) > 0;)
{
stream.write(buffer, 0, ctr);
}
}
stream.flush();
}
if (form != null)
{
// - remove the output now that we're done with it (in case its large)
PropertyUtils.setProperty(form, outputProperty, null);
}
}
catch (Throwable throwable)
{
throw new ServletException(throwable);
}
}
/**
* @see javax.servlet.http.HttpServlet#doPost(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
*/
@Override
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException,
IOException
{
doGet(request, response);
}
/**
* The name of the attribute that stores the content type.
*/
public static final String CONTENT_TYPE_ATTRIBUTE = "contentType";
/**
* Gets the explicity content type to render the file in.
*
* @return Returns the contentType.
*/
private String getContentType(final FacesContext context, final String contentType, final String fileName)
{
String foundContentType = contentType;
// - if the content type is still null, lets guess
if (contentType == null || contentType.length() == 0)
{
if (fileName != null && fileName.trim().length() > 0)
{
int lastDotIndex = fileName.lastIndexOf('.');
if (lastDotIndex != -1)
{
final String extension = fileName.substring(
lastDotIndex,
fileName.length());
foundContentType = CONTENT_TYPES.getProperty(extension);
}
}
}
return foundContentType;
}
/**
* Stores the default content types.
*/
static final Properties CONTENT_TYPES = new Properties();
/**
* Load up the default content types
*/
static
{
final String fileName = "contenttypes.properties";
final InputStream stream = FileDownloadServlet.class.getResourceAsStream(fileName);
if (stream == null)
{
logger.error("Could not load file from '" + fileName + "'");
}
else
{
try
{
CONTENT_TYPES.load(stream);
}
catch (final Throwable throwable)
{
logger.error(throwable.getMessage(),throwable);
}
}
try
{
if (stream != null)
{
stream.close();
}
}
catch (final Throwable throwable)
{
// - ignore
}
}
}