/*==========================================================================*\
| $Id: DeliverFile.java,v 1.1 2010/05/11 14:51:55 aallowat Exp $
|*-------------------------------------------------------------------------*|
| Copyright (C) 2006-2008 Virginia Tech
|
| This file is part of Web-CAT.
|
| Web-CAT is free software; you can redistribute it and/or modify
| it under the terms of the GNU Affero General Public License as published
| by the Free Software Foundation; either version 3 of the License, or
| (at your option) any later version.
|
| Web-CAT is distributed in the hope that it will be useful,
| but WITHOUT ANY WARRANTY; without even the implied warranty of
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
| GNU General Public License for more details.
|
| You should have received a copy of the GNU Affero General Public License
| along with Web-CAT; if not, see <http://www.gnu.org/licenses/>.
\*==========================================================================*/
package org.webcat.core;
import com.webobjects.appserver.*;
import com.webobjects.foundation.*;
import java.io.*;
import org.webcat.core.DeliverFile;
import org.webcat.core.Session;
import org.apache.log4j.Logger;
// -------------------------------------------------------------------------
/**
* A page for deliverying a file to the user. The file can either
* be presented in a new browser window, or the user can be prompted
* to save it on his or her machine. See the setFileData() method
* for information about delivering content that is not located in
* a physical file (such as content stored in the database). See
* setStartDownload() for information on controlling whether the
* content will be displayed or downloaded.
*
* @author Stephen Edwards
* @version $Id: DeliverFile.java,v 1.1 2010/05/11 14:51:55 aallowat Exp $
*/
public class DeliverFile
extends WOComponent
{
//~ Constructors ..........................................................
// ----------------------------------------------------------
/**
* This is the default constructor
*
* @param context The page's context
*/
public DeliverFile( WOContext context )
{
super( context );
}
//~ Methods ...............................................................
// ----------------------------------------------------------
/**
* Set the file to be delivered by this page. If the file data
* has not been set, then this value will be used to locate the
* file on disk and load its contents for delivery. For downloaded
* files, this value also determines the file name used in the
* "Save As..." dialog if setDeliveredName is never called. Only the
* last name in the pathname sequence is visible to the user.
*
* @param name the file name to use
*/
public void setFileName( File name )
{
fileName = name;
}
// ----------------------------------------------------------
/**
* Set the filename that will be presented to the user in the browser
* file download dialog. This method can be used to deliver the file
* to the user with a different name than it has internally on the
* server.
*
* If this is null (the default value) then the file will be
* presented with the last segment of the actual filename as passed
* into setFileName.
*
* @param name the file name to be presented to the user
*/
public void setDeliveredName( String name )
{
deliveredName = name;
}
// ----------------------------------------------------------
/**
* Set the file content to deliver. If this method is not called
* (i.e., the internal file data member is left null), then the
* file content will be read directly from the file system using
* the associated file name. Alternatively, if the file content
* data is set to a non-null NSData value, then that data will be
* used rather than reading from the file system. This allows
* dynamically generated content or content stored in the database
* to be delivered to the user just like a plain file.
*
* @param data the file data to deliver
*/
public void setFileData( NSData data )
{
fileData = data;
}
// ----------------------------------------------------------
/**
* Set the MIME type for the associated file content. Any
* MIME content type is acceptable. The two simplified type names
* "text" and "html" are also supported. They are automatically
* converted to the MIME content types "text/plain" and "text/html",
* respectively.
*
* @param type the content type to use
*/
public void setContentType( String type )
{
if ( type == null )
{
log.debug( "setContentType called with null parameter" );
contentType = null;
}
else if ( type == "text" )
{
contentType = "text/plain";
}
else if ( type == "html" )
{
contentType = "text/html";
}
else
{
contentType = type;
}
log.debug( "setContentType("
+ ( ( type == null ) ? "<null>" : type )
+ ") = "
+ ( ( contentType == null ) ? "<null>" : contentType )
);
}
// ----------------------------------------------------------
/**
* Determine whether the delivery action is a file download, instead
* of viewing the file in a browser window. If the parameter is set
* to true, then the browser will prompt the user to save the file
* to disk. If the parameter is false, then the browser will simply
* display the file content in a new window.
*
* @param download true to force a file download action
*/
public void setStartDownload( boolean download )
{
startDownload = download;
}
// ----------------------------------------------------------
/**
* Adds to the response of the page
*
* @param response The response being built
* @param context The context of the request
*/
public void appendToResponse( WOResponse response, WOContext context )
{
if ( fileName == null )
{
if ( fileData == null )
{
log.error( "no file name or file data specified" );
}
fileName = new File( "file.dat" );
}
if ( fileData == null )
{
log.debug( "no file data provided, attempting to read from "
+ fileName );
try
{
FileInputStream stream = new FileInputStream( fileName );
fileData = new NSData( stream, (int)fileName.length() );
stream.close();
}
catch ( Exception e )
{
log.error( "cannot read data from file", e );
}
}
if ( contentType == null )
{
log.debug( "no content type provided, using default" );
contentType = defaultContentType;
}
response.setContent( fileData );
response.setHeader( contentType, "content-type" );
// TA: Allow the download to be presented to the user with a different
// filename than the one it has on the server
String attachmentName;
if (deliveredName != null)
{
attachmentName = deliveredName;
}
else
{
attachmentName = fileName.getName();
}
response.setHeader( (startDownload ? "attachment;" : "")
+ "filename=\"" + attachmentName +"\"",
"content-disposition" );
// TODO: test out caching downloads on IE
// Work around bug in IE that prevents downloads over SSL when
// file isn't supposed to be cached. Here, we'll explicitly set
// headers to allow caching for file downloads, if the browser being
// used is IE.
Session mySession = (Session)session();
if ( mySession.browser().isIE() )
{
// Cache for 5 minutes (300 seconds)
response.setHeader( "max-age=300", "cache-control" );
}
if ( log.isDebugEnabled() )
{
log.debug( "response:\n" + response );
log.debug( "headers = "+ response.headers() );
log.debug( "time = " + new NSTimestamp() );
}
}
//~ Instance/static variables .............................................
/**
* The file data to deliver. If it is not provided using
* setFileData(), then the contents will be read directly from
* the given file on disk.
*/
protected NSData fileData;
/** The name (and location) of the file to deliver. */
protected File fileName;
/** If not null, use this name instead of fileName as the destination name
* shown to the user in the browser download dialog */
protected String deliveredName;
/** True if the file should be delivered via a download action; false
* if the file should simply be displayed in a browser window. */
protected boolean startDownload = false;
/** The MIME type of the file's content. */
protected String contentType;
private static final String defaultContentType = "text/plain";
// "application/octet-stream";
static Logger log = Logger.getLogger( DeliverFile.class );
}