package er.extensions.components; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.InputStream; import org.apache.commons.lang3.builder.ToStringBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.webobjects.appserver.WOComponent; import com.webobjects.appserver.WOContext; import com.webobjects.appserver.WOMessage; import com.webobjects.appserver.WOResponse; import er.extensions.foundation.ERXFileContext; /** * A component that is used to generate a download response. Simply create the * component, use appropriate setters for the type of content to be downloaded * and return the component from a component action * * @binding contentDisposition A string to set the content-disposition header. Defaults to * <code>"attachment;filename=\"" + downloadFilename() + "\""</code> * @binding contentType A string to represents the MIME type (text/plain, application/pdf, * etc.) of the file * @binding downloadFilename A string that represents the name of the file. Defaults to * "downloadedfile" * @binding fileContext An ERXFileContext object that contains a reference to the file, * the file name and the MIME type. If you set this binding, you don't need to set the * contentType, fileToDownload and downloadFilename bindings. * @binding fileToDownload A java.io.File object that will be returned in the response * * @author kieran 1/27/2006 * * */ public class ERXDownloadResponse extends WOComponent { /** * Do I need to update serialVersionUID? * See section 5.6 <cite>Type Changes Affecting Serialization</cite> on page 51 of the * <a href="http://java.sun.com/j2se/1.4/pdf/serial-spec.pdf">Java Object Serialization Spec</a> */ private static final long serialVersionUID = 1L; private static final Logger log = LoggerFactory.getLogger(ERXDownloadResponse.class); private String _downloadFilename; private long _streamingContentSize = 0L; public ERXDownloadResponse(WOContext context) { super(context); } /** * Convenience method to set file, download filename and content type. * * @param fileContext */ public void setFileContext(ERXFileContext fileContext) { _fileToDownload = fileContext.file(); _downloadFilename = fileContext.clientFileName(); _contentType = fileContext.mimeType(); } /** * @return the filename for the file after it is downloaded. Defaults to an * arbitrary name. */ private String downloadFilename() { if (_downloadFilename == null) { if (fileToDownload() != null) { _downloadFilename = fileToDownload().getName(); } else { _downloadFilename = "downloadedfile"; } } return _downloadFilename; } public void setDownloadFilename(String newDownloadFilename) { _downloadFilename = newDownloadFilename; } private File _fileToDownload; /** @return the file to be downloaded (streaming) */ private File fileToDownload() { return _fileToDownload; } /** * @param aFile the file to be downloaded. */ public void setFileToDownload(File aFile) { _fileToDownload = aFile; } private InputStream _inputStreamToDownload; /** * @return an InputStream pointing to the data to download. */ private InputStream inputStreamToDownload() { return _inputStreamToDownload; } /** * WO 5.3.3 setter where contentSize is int * * @param inStream * @param contentSize */ public void setInputStreamToDownload(InputStream inStream, long contentSize) { _inputStreamToDownload = inStream; _streamingContentSize = contentSize; } @Override public void appendToResponse(WOResponse aResponse, WOContext aContext) { super.appendToResponse(aResponse, aContext); // Set default encoding // CHECKME: Is this line needed? - probably not. aResponse.setContentEncoding(WOMessage.defaultEncoding()); // We want to return an InputStream always InputStream is = null; if (fileToDownload() != null) { try { is = new FileInputStream(fileToDownload()); } catch (FileNotFoundException e) { throw new RuntimeException(e); } _streamingContentSize = fileToDownload().length(); } if (is == null && inputStreamToDownload() != null) { is = inputStreamToDownload(); } if (is == null) { throw new IllegalStateException( "At least one of 'fileContext', 'fileToDownload' or 'inputStreamToDownload' must be set!"); } // Note, when set to zero, the buffer is assigned a default value, // currently 4096. aResponse.setContentStream(is, 0, _streamingContentSize); // Set content headers aResponse.setHeader(contentType(), "content-type"); aResponse.setHeader(contentDisposition(), "content-disposition"); log.debug("DownloadResponse = {}", this); } private String _contentDisposition; /** * @return content-disposition header. Defaults to * <code>"attachment;filename=\"" + downloadFilename() + "\""</code> */ private String contentDisposition() { if (_contentDisposition == null) { _contentDisposition = "attachment;filename=\"" + downloadFilename() + "\""; } return _contentDisposition; } public void setContentDisposition(String contentDisposition) { _contentDisposition = contentDisposition; } private String _contentType; /** * @return content-type header. Defaults to * <code>"application/octet-stream"</code> */ private String contentType() { if (_contentType == null) { _contentType = "application/octet-stream"; } return _contentType; } public void setContentType(String contentType) { _contentType = contentType; } @Override public String toString() { ToStringBuilder b = new ToStringBuilder(this); b.append("File To Download", _fileToDownload); b.append("Stream to Download", _inputStreamToDownload); b.append("Download Filename", _downloadFilename); b.append("Content Type", _contentType); b.append("Content Disposition", _contentDisposition); b.append("Content Size", _streamingContentSize); return b.toString(); } }