Author: martinc Date: Fri Oct 29 19:50:56 2004 New Revision: 56011 Added: struts/trunk/src/share/org/apache/struts/actions/DownloadAction.java Log: New abstract action that provides the nuts and bolts for downloading files from a Struts application.
Added: struts/trunk/src/share/org/apache/struts/actions/DownloadAction.java ============================================================================== --- (empty file) +++ struts/trunk/src/share/org/apache/struts/actions/DownloadAction.java Fri Oct 29 19:50:56 2004 @@ -0,0 +1,273 @@ +/* + * $Id$ + * + * Copyright 2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.struts.actions; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import javax.servlet.ServletContext; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.struts.action.Action; +import org.apache.struts.action.ActionForm; +import org.apache.struts.action.ActionForward; +import org.apache.struts.action.ActionMapping; + + +/** + * This is an abstract base class that minimizes the amount of special coding + * that needs to be written to download a file. All that is required to use + * this class is to extend it and implement the <code>getStreamInfo()</code> + * method so that it returns the relevant information for the file (or other + * stream) to be downloaded. Optionally, the <code>getBufferSize()</code> + * method may be overridden to customize the size of the buffer used to + * transfer the file. + * + * @since Struts 1.2.6 + */ +public abstract class DownloadAction extends Action { + + /** + * If the <code>getBufferSize()</code> method is not overridden, this is + * the buffer size that will be used to transfer the data to the servlet + * output stream. + */ + protected static final int DEFAULT_BUFFER_SIZE = 1024 * 4; + + /** + * Returns the information on the file, or other stream, to be downloaded + * by this action. This method must be implemented by an extending class. + * + * @param mapping The ActionMapping used to select this instance. + * @param form The optional ActionForm bean for this request (if any). + * @param request The HTTP request we are processing. + * @param response The HTTP response we are creating. + * + * @return The information for the file to be downloaded. + * + * @throws Exception if an exception occurs. + */ + protected abstract StreamInfo getStreamInfo(ActionMapping mapping, + ActionForm form, HttpServletRequest request, + HttpServletResponse response) + throws Exception; + + /** + * Returns the size of the buffer to be used in transferring the data to + * the servlet output stream. This method may be overridden by an extending + * class in order to customize the buffer size. + * + * @return The size of the transfer buffer, in bytes. + */ + protected int getBufferSize() { + return DEFAULT_BUFFER_SIZE; + } + + /** + * Process the specified HTTP request, and create the corresponding HTTP + * response (or forward to another web component that will create it). + * Return an <code>ActionForward</code> instance describing where and how + * control should be forwarded, or <code>null</code> if the response has + * already been completed. + * + * @param mapping The ActionMapping used to select this instance. + * @param form The optional ActionForm bean for this request (if any). + * @param request The HTTP request we are processing. + * @param response The HTTP response we are creating. + * + * @throws Exception if an exception occurs. + */ + public ActionForward execute(ActionMapping mapping, ActionForm form, + HttpServletRequest request, HttpServletResponse response) + throws Exception { + + StreamInfo info = getStreamInfo(mapping, form, request, response); + String contentType = info.getContentType(); + InputStream stream = info.getInputStream(); + + try { + response.setContentType(contentType); + copy(stream, response.getOutputStream()); + } finally { + if (stream != null) { + stream.close(); + } + } + + // Tell Struts that we are done with the response. + return null; + } + + /** + * Copy bytes from an <code>InputStream</code> to an + * <code>OutputStream</code>. + * + * @param input The <code>InputStream</code> to read from. + * @param output The <code>OutputStream</code> to write to. + * + * @return the number of bytes copied + * + * @throws IOException In case of an I/O problem + */ + public static int copy(InputStream input, OutputStream output) + throws IOException { + byte[] buffer = new byte[DEFAULT_BUFFER_SIZE]; + int count = 0; + int n = 0; + while (-1 != (n = input.read(buffer))) { + output.write(buffer, 0, n); + count += n; + } + return count; + } + + /** + * The information on a file, or other stream, to be downloaded by the + * <code>DownloadAction</code>. + */ + public static interface StreamInfo { + + /** + * Returns the content type of the stream to be downloaded. + * + * @return The content type of the stream. + */ + public abstract String getContentType(); + + /** + * Returns an input stream on the content to be downloaded. This stream + * will be closed by the <code>DownloadAction</code>. + * + * @return The input stream for the content to be downloaded. + */ + public abstract InputStream getInputStream() throws IOException; + } + + /** + * A concrete implementation of the <code>StreamInfo</code> interface which + * simplifies the downloading of a file from the disk. + */ + public static class FileStreamInfo implements StreamInfo { + + /** + * The content type for this stream. + */ + private String contentType; + + /** + * The file to be downloaded. + */ + private File file; + + /** + * Constructs an instance of this class, based on the supplied + * parameters. + * + * @param contentType The content type of the file. + * @param file The file to be downloaded. + */ + public FileStreamInfo(String contentType, File file) { + this.contentType = contentType; + this.file = file; + } + + /** + * Returns the content type of the stream to be downloaded. + * + * @return The content type of the stream. + */ + public String getContentType() { + return this.contentType; + } + + /** + * Returns an input stream on the file to be downloaded. This stream + * will be closed by the <code>DownloadAction</code>. + * + * @return The input stream for the file to be downloaded. + */ + public InputStream getInputStream() throws IOException { + FileInputStream fis = new FileInputStream(file); + BufferedInputStream bis = new BufferedInputStream(fis); + return bis; + } + } + + /** + * A concrete implementation of the <code>StreamInfo</code> interface which + * simplifies the downloading of a web application resource. + */ + public static class ResourceStreamInfo implements StreamInfo { + + /** + * The content type for this stream. + */ + private String contentType; + + /** + * The servlet context for the resource to be downloaded. + */ + private ServletContext context; + + /** + * The path to the resource to be downloaded. + */ + private String path; + + /** + * Constructs an instance of this class, based on the supplied + * parameters. + * + * @param contentType The content type of the file. + * @param context The servlet context for the resource. + * @param path The path to the resource to be downloaded. + */ + public ResourceStreamInfo(String contentType, ServletContext context, + String path) { + this.contentType = contentType; + this.context = context; + this.path = path; + } + + /** + * Returns the content type of the stream to be downloaded. + * + * @return The content type of the stream. + */ + public String getContentType() { + return this.contentType; + } + + /** + * Returns an input stream on the resource to be downloaded. This stream + * will be closed by the <code>DownloadAction</code>. + * + * @return The input stream for the resource to be downloaded. + */ + public InputStream getInputStream() throws IOException { + return context.getResourceAsStream(path); + } + } +} --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]