All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.glassfish.admingui.common.servlet.DownloadServlet Maven / Gradle / Ivy

There is a newer version: 4.1.2.181
Show newest version
/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 2009-2012 Oracle and/or its affiliates. All rights reserved.
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License.  You can
 * obtain a copy of the License at
 * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
 * or packager/legal/LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 *
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at packager/legal/LICENSE.txt.
 *
 * GPL Classpath Exception:
 * Oracle designates this particular file as subject to the "Classpath"
 * exception as provided by Oracle in the GPL Version 2 section of the License
 * file that accompanied this code.
 *
 * Modifications:
 * If applicable, add the following below the License Header, with the fields
 * enclosed by brackets [] replaced by your own identifying information:
 * "Portions Copyright [year] [name of copyright owner]"
 *
 * Contributor(s):
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 */
package org.glassfish.admingui.common.servlet;

import java.io.IOException;
import java.io.BufferedInputStream;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.StringTokenizer;

import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;



/**
 *  

This Servlet provides the ability to download information from the * Server to the client. It provides the ability to set the content type * of the downloaded file, if not specified, it will attempt to guess * based on the extension (if possible). It requires the * {@link DownloadServlet#ContentSource} of the data to download to be * specified by passing in a ServletRequest parameter named * {@link DownloadServlet#CONTENT_SOURCE_ID}. The * {@link DownloadServlet.ContentSource} provides a plugable means * of obtaining data from an arbitrary source (i.e. the filesystem, * generated on the fly, from some network location, etc.). The available * {@link DownloadServlet.ContentSource} implemenatations must be * specified via a Servlet init parameter named * {@link DownloadServlet#CONTENT_SOURCES}.

*/ public class DownloadServlet extends HttpServlet { /** *

Default Constructor.

*/ public DownloadServlet() { super(); } /** *

Servlet initialization method.

*/ public void init(ServletConfig config) throws ServletException { super.init(config); // Register ContentSources String sources = config.getInitParameter(CONTENT_SOURCES); if ((sources == null) || (sources.trim().length() == 0)) { throw new ServletException("No ContentSources specified! Ensure " + "at least 1 DownloadServlet.ContentSource is provided as" + " a Servlet init parameter (key: " + CONTENT_SOURCES + ")."); } StringTokenizer tokens = new StringTokenizer(sources, " \t\n\r\f,;:"); while (tokens.hasMoreTokens()) { registerContentSource(tokens.nextToken()); } } /** *

This method registers the given class name as a * {@link DownloadServlet#ContentSource}. This method will attempt * to resolve and instantiate the class using the current * classloader.

*/ public void registerContentSource(String className) { // Sanity Check if ((className == null) || className.trim().equals("")) { return; } Class cls = null; try { cls = Class.forName(className); } catch (Exception ex) { throw new RuntimeException(ex); } registerContentSource(cls); } /** *

This method registers the given class name as a * {@link DownloadServlet#ContentSource}. This method will attempt * to instantiate the class via the default constructor.

*/ public void registerContentSource(Class cls) { // Create a new instance DownloadServlet.ContentSource source = null; try { source = (DownloadServlet.ContentSource) cls.newInstance(); } catch (Exception ex) { throw new RuntimeException(ex); } // Add the new instance to the registered ContentSources _contentSources.put(source.getId(), source); } /** *

This method looks up a DownloadServlet.ContentSource given its id. * The {@link DownloadServlet#ContentSource} must be previously * registered.

*/ public DownloadServlet.ContentSource getContentSource(String id) { return _contentSources.get(id); } /** *

This method delegates to the {@link #doPost()} method.

*/ public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } /** *

This method is the main method for this class when used in an * HttpServlet environment. It drives the process, which * includes creating a {@link DownloadServet#Context}, choosing the * appropriate {@link DownloadServlet#ContentSource}, and copying the * output of the {@link DownloadServlet#ContentSource} to the * ServletResponse's OutputStream.

*/ public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // Get the Download Context DownloadServlet.Context context = getDownloadContext(request, response); // Get the ContentSource ContentSource source = getContentSource(request); // Write Content writeContent(source, context); // Clean Up source.cleanUp(context); } /** *

This method instantiates a {@link DownloadServlet.Context} and * initializes it with the Servlet, ServletConfig, ServletRequest, * and ServletResponse.

*/ protected DownloadServlet.Context getDownloadContext(HttpServletRequest request, HttpServletResponse response) { DownloadServlet.Context ctx = (DownloadServlet.Context) request.getAttribute(DOWNLOAD_CONTEXT); if (ctx == null) { ctx = new DownloadServlet.Context(); ctx.setServlet(this); ctx.setServletConfig(getServletConfig()); ctx.setServletRequest(request); request.setAttribute(DOWNLOAD_CONTEXT, ctx); } // This is done differently b/c the response may initially be null, // subsequent calls may provide this information ctx.setServletResponse(response); return ctx; } /** *

This method locates the appropriate * {@link DownloadServlet#ContentSource} for this request. It uses * the given ServletRequest to look for a * ServletRequest Parameter named {@link #CONTENT_SOURCE_ID}. * This value is used as the key when looking up registered * {@link DownloadServlet#ContentSource} implementations. */ protected DownloadServlet.ContentSource getContentSource(ServletRequest request) { // Get the ContentSource id String id = request.getParameter(CONTENT_SOURCE_ID); if (id == null) { id = getServletConfig().getInitParameter(CONTENT_SOURCE_ID); if(id == null) { throw new RuntimeException("You must provide the '" + CONTENT_SOURCE_ID + "' request parameter!"); } } // Get the ContentSource DownloadServlet.ContentSource src = getContentSource(id); if (src == null) { throw new RuntimeException("The ContentSource with id '" + id + "' is not registered!"); } // Return the ContentSource return src; } /** *

This method is responsible for setting the response header * information.

*/ protected void writeHeader(DownloadServlet.ContentSource source, DownloadServlet.Context context) { ServletResponse resp = context.getServletResponse(); if (!(resp instanceof HttpServletResponse)) { // This implementation is only valid for HttpServletResponse return; } // Set the "Last-Modified" Header // First check context long longTime = source.getLastModified(context); if (longTime != -1) { ((HttpServletResponse) resp). setDateHeader("Last-Modified", longTime); } // First check CONTENT_TYPE String contentType = (String) context.getAttribute(CONTENT_TYPE); if (contentType == null) { // Not found yet, check EXTENSION String ext = (String) context.getAttribute(EXTENSION); if (ext != null) { contentType = mimeTypes.get(ext); } if (contentType == null) { // Default Content-type is: application/octet-stream contentType = DEFAULT_CONTENT_TYPE; } } ((HttpServletResponse) resp).setHeader("Content-type", contentType); // Write additional headers Object o = context.getAttribute(HEADERS); if (o instanceof Map) { @SuppressWarnings("unchecked") Map headers = (Map) o; for (Map.Entry h: headers.entrySet()) { ((HttpServletResponse) resp).setHeader(h.getKey(), h.getValue()); } } // TODO: log warning } /** *

This method is responsible for copying the data from the given * InputStream to the ServletResponse's * OutputStream. The InputStream should be * the from the {@link DownloadServlet#ContentSource}.

*/ protected void writeContent(DownloadServlet.ContentSource source, DownloadServlet.Context context) { // Get the InputStream InputStream in = source.getInputStream(context); // Get the OutputStream ServletResponse resp = context.getServletResponse(); if(in == null) { //nothing to write String jspPage = (String)context.getAttribute("JSP_PAGE_SERVED"); if(jspPage != null && (jspPage.equals("false"))) { try { //Mainly to take care of javahelp2, bcz javahelp2 code needs an Exception to be thrown for FileNotFound. //We may have to localize this message. ((HttpServletResponse)resp).sendError(404, "File Not Found"); } catch (IOException ex) { //squelch it, just return. } } return; } InputStream stream = null; try { javax.servlet.ServletOutputStream out = resp.getOutputStream(); // Get the InputStream stream = new BufferedInputStream(in); // Write the header writeHeader(source, context); // Copy the data to the ServletOutputStream byte [] buf = new byte[512]; // Set our buffer at 512 bytes int read = stream.read(buf, 0, 512); while (read != -1) { // Write data from the OutputStream to the InputStream out.write(buf, 0, read); // Read more... read = stream.read(buf, 0, 512); } } catch (IOException ex) { throw new RuntimeException(ex); } finally { if (stream != null) { try { // Close the Stream stream.close(); } catch (IOException ex) { //ignore } } } } ////////////////////////////////////////////////////////////////////////// // Inner Classes ////////////////////////////////////////////////////////////////////////// /** *

Implement this interface to provide an Object that is capable of * providing data to DownloadServlet. * ContentSource implementations must be thread safe. * The DownloadServlet will reuse the same instance when * 2 requests are made to the same ContentSource type. Instance * variables, therefore, should not be used; you may use the context * to store local information.

*/ public static interface ContentSource { /** *

This method should return a unique string used to identify this * ContentSource. This string must be specified in * order to select the appropriate ContentSource when * using the DownloadServlet.

*/ public String getId(); /** *

This method is responsible for generating the content and * returning an InputStream to that content. It is also * responsible for setting any attribute values in the * {@link DownloadServlet#Context}, such as {@link EXTENSION} or * {@link CONTENT_TYPE}.

*/ public InputStream getInputStream(DownloadServlet.Context ctx); /** *

This method may be used to clean up any temporary resources. * It will be invoked after the InputStream has * been completely read.

*/ public void cleanUp(DownloadServlet.Context ctx); /** *

This method is responsible for returning the last modified date * of the content, or -1 if not applicable. This information will * be used for caching.

*/ public long getLastModified(DownloadServlet.Context context); } /** *

This class provides information about the request that may be * necessary for the DownloadServlet.ContentSource to * provide content. The DownloadServlet is responsible * for supplying this object to the * DownloadServlet.ContentSource.

*/ public static class Context { /** *

The default constructor.

*/ public Context() { } /** *

This method may be used to manage arbitrary information between * the DownloadServlet and the * DownloadServlet.ContentSource. This method * retrieves an attribute.

*/ public Object getAttribute(String name) { if (name == null) { return null; } // First check the local attribute Map Object value = _att.get(name); if (value == null) { // Not found, check the Request attributes... value = getServletRequest().getParameter(name); } // Return the value (if any) return value; } /** *

This method may be used to manage arbitrary information between * the DownloadServlet and the * DownloadServlet.ContentSource. This method sets * an attribute.

*/ public void setAttribute(String name, Object value) { if (name != null) { _att.put(name, value); } } /** *

This method may be used to manage arbitrary information between * the DownloadServlet and the * DownloadServlet.ContentSource. This method * removes an attribute.

*/ public void removeAttribute(String name) { _att.remove(name); } /** *

This returns the Servlet associated with the * request. This may be cast to the specific Servlet * instance, such as HttpServlet.

*/ public Servlet getServlet() { return _servlet; } /** *

This sets the Servlet associated with the * request.

*/ protected void setServlet(Servlet servlet) { _servlet = servlet; } /** *

This returns the ServletConfig.

*/ public ServletConfig getServletConfig() { return _servletConfig; } /** *

This sets the ServletConfig.

*/ protected void setServletConfig(ServletConfig config) { _servletConfig = config; } /** *

This returns the ServletRequest associated with * the request. This may be cast to the specific type, such as * HttpServletRequest.

*/ public ServletRequest getServletRequest() { return _request; } /** *

This sets the ServletRequest associated with the * request.

*/ protected void setServletRequest(ServletRequest request) { _request = request; } /** *

This returns the ServletResponse associated with * the request. This may be cast to the specific type, such as * HttpServletResponse.

*/ public ServletResponse getServletResponse() { return _response; } /** *

This sets the ServletResponse associated with the * request.

*/ protected void setServletResponse(ServletResponse response) { _response = response; } private Servlet _servlet = null; private ServletConfig _servletConfig = null; private ServletRequest _request = null; private ServletResponse _response = null; private Map _att = new HashMap(); } /** *

This method gets called before the doGet/doPost method. The * requires us to create the {@link DownloadServlet#Context} here. * However, we do not have the HttpServletResponse yet, * so it will be null.

*/ protected long getLastModified(HttpServletRequest request) { // Get the DownloadServlet Context DownloadServlet.Context context = getDownloadContext(request, null); // Get the ContentSource ContentSource source = getContentSource(request); // Calculate the last modified date return source.getLastModified(context); } /** * HashMap to hold mimetypes by extension. */ private static Map mimeTypes = new HashMap(120); static { mimeTypes.put("aif", "audio/x-aiff"); mimeTypes.put("aifc", "audio/x-aiff"); mimeTypes.put("aiff", "audio/x-aiff"); mimeTypes.put("asc", "text/plain"); mimeTypes.put("asf", "application/x-ms-asf"); mimeTypes.put("asx", "application/x-ms-asf"); mimeTypes.put("au", "audio/basic"); mimeTypes.put("avi", "video/x-msvideo"); mimeTypes.put("bin", "application/octet-stream"); mimeTypes.put("bmp", "image/bmp"); mimeTypes.put("bwf", "audio/wav"); mimeTypes.put("bz2", "application/x-bzip2"); mimeTypes.put("c", "text/plain"); mimeTypes.put("cc", "text/plain"); mimeTypes.put("cdda", "audio/x-aiff"); mimeTypes.put("class", "application/octet-stream"); mimeTypes.put("com", "application/octet-stream"); mimeTypes.put("cpp", "text/plain"); mimeTypes.put("cpr", "image/cpr"); mimeTypes.put("css", "text/css"); mimeTypes.put("doc", "application/msword"); mimeTypes.put("dot", "application/msword"); mimeTypes.put("dtd", "text/xml"); mimeTypes.put("ear", "application/zip"); mimeTypes.put("exe", "application/octet-stream"); mimeTypes.put("flc", "video/flc"); mimeTypes.put("fm", "application/x-maker"); mimeTypes.put("frame", "application/x-maker"); mimeTypes.put("frm", "application/x-maker"); mimeTypes.put("h", "text/plain"); mimeTypes.put("hh", "text/plain"); mimeTypes.put("hpp", "text/plain"); mimeTypes.put("hqx", "application/mac-binhex40"); mimeTypes.put("htm", "text/html"); mimeTypes.put("html", "text/html"); mimeTypes.put("gif", "image/gif"); mimeTypes.put("gz", "application/x-gunzip"); mimeTypes.put("ico", "image/x-icon"); mimeTypes.put("iso", "application/octet-stream"); mimeTypes.put("jar", "application/zip"); mimeTypes.put("java", "text/plain"); mimeTypes.put("jnlp", "application/x-java-jnlp-file"); mimeTypes.put("jpeg", "image/jpeg"); mimeTypes.put("jpe", "image/jpeg"); mimeTypes.put("jpg", "image/jpeg"); mimeTypes.put("js", "text/x-javascript"); mimeTypes.put("m3u", "audio/x-mpegurl"); mimeTypes.put("maker", "application/x-maker"); mimeTypes.put("mid", "audio/midi"); mimeTypes.put("midi", "audio/midi"); mimeTypes.put("mim", "application/mime"); mimeTypes.put("mime", "application/mime"); mimeTypes.put("mov", "video/quicktime"); mimeTypes.put("mp2", "audio/mpeg"); mimeTypes.put("mp3", "audio/mpeg"); mimeTypes.put("mp4", "video/mpeg4"); mimeTypes.put("mpa", "video/mpeg"); mimeTypes.put("mpe", "video/mpeg"); mimeTypes.put("mpeg", "video/mpeg"); mimeTypes.put("mpg", "video/mpeg"); mimeTypes.put("mpga", "audio/mpeg"); mimeTypes.put("mpm", "video/mpeg"); mimeTypes.put("mpv", "video/mpeg"); mimeTypes.put("pdf", "application/pdf"); mimeTypes.put("pic", "image/x-pict"); mimeTypes.put("pict", "image/x-pict"); mimeTypes.put("pct", "image/x-pict"); mimeTypes.put("pl", "application/x-perl"); mimeTypes.put("png", "image/png"); mimeTypes.put("pnm", "image/x-portable-anymap"); mimeTypes.put("pbm", "image/x-portable-bitmap"); mimeTypes.put("ppm", "image/x-portable-pixmap"); mimeTypes.put("ps", "application/postscript"); mimeTypes.put("ppt", "application/vnd.ms-powerpoint"); mimeTypes.put("qt", "video/quicktime"); mimeTypes.put("ra", "application/vnd.rn-realaudio"); mimeTypes.put("rar", "application/zip"); mimeTypes.put("rf", "application/vnd.rn-realflash"); mimeTypes.put("ra", "audio/vnd.rn-realaudio"); mimeTypes.put("ram", "audio/x-pn-realaudio"); mimeTypes.put("rm", "application/vnd.rn-realmedia"); mimeTypes.put("rmm", "audio/x-pn-realaudio"); mimeTypes.put("rsml", "application/vnd.rn-rsml"); mimeTypes.put("rtf", "text/rtf"); mimeTypes.put("rv", "video/vnd.rn-realvideo"); mimeTypes.put("spl", "application/futuresplash"); mimeTypes.put("snd", "audio/basic"); mimeTypes.put("ssm", "application/smil"); mimeTypes.put("swf", "application/x-shockwave-flash"); mimeTypes.put("tar", "application/x-tar"); mimeTypes.put("tgz", "application/x-gtar"); mimeTypes.put("tif", "image/tiff"); mimeTypes.put("tiff", "image/tiff"); mimeTypes.put("txt", "text/plain"); mimeTypes.put("ulw", "audio/basic"); mimeTypes.put("war", "application/zip"); mimeTypes.put("wav", "audio/x-wav"); mimeTypes.put("wax", "application/x-ms-wax"); mimeTypes.put("wm", "application/x-ms-wm"); mimeTypes.put("wma", "application/x-ms-wma"); mimeTypes.put("wml", "text/wml"); mimeTypes.put("wmw", "application/x-ms-wmw"); mimeTypes.put("wrd", "application/msword"); mimeTypes.put("wvx", "application/x-ms-wvx"); mimeTypes.put("xbm", "image/x-xbitmap"); mimeTypes.put("xpm", "image/image/x-xpixmap"); mimeTypes.put("xml", "text/xml"); mimeTypes.put("xsl", "text/xml"); mimeTypes.put("xls", "application/vnd.ms-excel"); mimeTypes.put("zip", "application/zip"); mimeTypes.put("z", "application/x-compress"); mimeTypes.put("Z", "application/x-compress"); } private static Map _contentSources = new HashMap(); /** *

This String ("downloadContext") is the name if the * ServletRequest Attribute used to store the * {@link DownloadServlet#Context} object for this request.

*/ public static final String DOWNLOAD_CONTEXT = "downloadContext"; /** *

This String ("ContentSources") is the name if the Servlet Init * Parameter that should be used to register all available * {@link DownloadServlet#ContentSource} implementations.

*/ public static final String CONTENT_SOURCES = "ContentSources"; /** *

This is the ServletRequest Parameter that should be provided * to identify the DownloadServlet.ContentSource * implementation that should be used. This value must match the * value returned by the DownloadServlet.ContentSource * implementation's getId() method.

*/ public static final String CONTENT_SOURCE_ID = "contentSourceId"; /** *

The Content-type ("ContentType"). This is the * {@link DownloadServlet#Context} attribute used to specify an * explicit "Content-type". It may be set by the * {@link DownloadServlet#ContentSource}, or may be passed in via a * request parameter. If not specified, the {@link #EXTENSION} will * be used. If that fails, the {@link #DEFAULT_CONTENT_TYPE} will * apply.

*/ public static final String CONTENT_TYPE = "ContentType"; /** *

The Default Content-type ("application/octet-stream").

*/ public static final String DEFAULT_CONTENT_TYPE = "application/octet-stream"; /** *

This is the {@link DownloadServlet#Context} attribute name used to * specify the filename extension of the content. It is the * responsibility of the {@link DownloadServlet#ContentSource} to set * this value. The value should represent the filename extension of * the content if it were saved to a filesystem.

*/ public static final String EXTENSION = "extension"; /** *

This is the {@link DownloadServlet#Context} attribute name used to * specify optional additional headers. It must be set to * Map object when needed.

*/ public static final String HEADERS = "Headers"; }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy