// $HeadURL$
// $Id$
//
// Copyright © 2006, 2010, 2011, 2012 by the President and Fellows of Harvard College.
//
// Screensaver is an open-source project developed by the ICCB-L and NSRB labs
// at Harvard Medical School. This software is distributed under the terms of
// the GNU General Public License.
package edu.harvard.med.screensaver.ui.arch.util;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import javax.activation.MimetypesFileTypeMap;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.model.SelectItem;
import javax.servlet.http.HttpServletResponse;
import com.google.common.base.Function;
import com.google.common.base.Functions;
import org.apache.commons.io.IOUtils;
import org.apache.log4j.Logger;
public class JSFUtils
{
private static Logger log = Logger.getLogger(JSFUtils.class);
/**
* Performs the necessary steps to return a server-side file to an HTTP
* client. Must be called within a JSF-enabled servlet environment.
*
* @param facesContext the JSF FacesContext
* @param file the File to send to the HTTP client
* @param mimeType the MIME type of the file being sent
* @throws IOException
*/
public static void handleUserFileDownloadRequest(
FacesContext facesContext,
File file,
String mimeType)
throws IOException
{
InputStream in = new FileInputStream(file);
handleUserDownloadRequest(facesContext,
in,
file.getName(),
mimeType);
}
public static void handleUserFileDownloadRequest(FacesContext facesContext,
File file,
String suggestedFileName,
String mimeType)
throws IOException
{
InputStream in = new FileInputStream(file);
handleUserDownloadRequest(facesContext,
in,
suggestedFileName,
mimeType);
}
/**
* Performs the necessary steps to return server-side data, provided as an
* InputStream, to an HTTP client. Must be called within a JSF-enabled servlet
* environment.
*
* @param facesContext the JSF FacesContext
* @param dataInputStream an InputStream containing the data to send to the HTTP client
* @param contentLocation set the "content-location" HTTP header to this value, allowing the downloaded file to be named
* @param mimeType the MIME type of the file being sent
* @throws IOException
*/
public static void handleUserDownloadRequest(
FacesContext facesContext,
InputStream dataInputStream,
String contentLocation,
String mimeType)
throws IOException
{
HttpServletResponse response = (HttpServletResponse) facesContext.getExternalContext().getResponse();
if (mimeType == null && contentLocation != null) {
mimeType = MimetypesFileTypeMap.getDefaultFileTypeMap().getContentType(contentLocation);
}
if (mimeType != null) {
response.setContentType(mimeType);
}
// NOTE: the second line does the trick with the filename. leaving first line in for posterity
response.setHeader("Content-Location", contentLocation);
response.setHeader("Content-disposition", "attachment; filename=\"" + contentLocation + "\"");
OutputStream out = response.getOutputStream();
IOUtils.copy(dataInputStream, out);
out.close();
// skip Render-Response JSF lifecycle phase, since we're generating a
// non-Faces response
facesContext.responseComplete();
}
/**
* Creates a UISelectItems object that can be assigned to the "value"
* attribute of a UISelectItems JSF component.
*/
public static List<SelectItem> createUISelectItems(Collection items)
{
return createUISelectItems(items, false, null, Functions.toStringFunction());
}
/**
* Creates a UISelectItems object that can be assigned to the "value"
* attribute of a UISelectItems JSF component. Adds an additional
* "empty selection" item, whose value is an empty string and label is as
* specified (empty string if null).
*/
public static List<SelectItem> createUISelectItemsWithEmptySelection(Collection<?> items,
String emptySelectionLabel)
{
return createUISelectItems(items, true, emptySelectionLabel, Functions.toStringFunction());
}
public static <E> List<SelectItem> createUISelectItemsWithEmptySelection(Collection<? extends E> items,
String emptySelectionLabel,
Function<E,String> toDisplayString)
{
return createUISelectItems(items, true, emptySelectionLabel, toDisplayString);
}
private static <E> List<SelectItem> createUISelectItems(Collection<? extends E> items,
boolean addEmptyItem,
String emptyItemLabel,
Function<E,String> toDisplayString)
{
List<SelectItem> result = new ArrayList<SelectItem>();
if (addEmptyItem) {
result.add(new SelectItem("", emptyItemLabel == null ? "" : emptyItemLabel));
}
for (E item : items) {
result.add(new SelectItem(item, toDisplayString.apply(item)));
}
return result;
}
/**
* Output the names of all registered JSF components to the logger, as debug output.
*
* @motivation allows developer to determine the valid set of JSF component
* names that can be passed to Application.createComponent();
* @param component
* @param level
*/
private void logComponentNames()
{
log.debug("JSF registered component names:");
Iterator iter = FacesContext.getCurrentInstance().getApplication().getComponentTypes();
while (iter.hasNext()) {
log.debug("component name: " + iter.next().toString());
}
}
/**
* Output the hierarchical structure of a JSF component with nested children.
*/
private void logComponentStructure(UIComponent component, int level)
{
char[] indent = new char[level];
Arrays.fill(indent, ' ');
log.debug(new String(indent) + component.getClass() + ": " + component.getId());
for (Iterator iter = component.getChildren().iterator(); iter.hasNext();) {
UIComponent child = (UIComponent) iter.next();
logComponentStructure(child, level + 1);
}
}
}