/********************************************************************************** * $URL: https://source.sakaiproject.org/svn/metaobj/trunk/metaobj-util/tool-lib/src/java/org/sakaiproject/metaobj/shared/control/servlet/FileDownloadServlet.java $ * $Id: FileDownloadServlet.java 105079 2012-02-24 23:08:11Z ottenhoff@longsight.com $ *********************************************************************************** * * Copyright (c) 2005, 2006, 2008 The Sakai Foundation * * Licensed under the Educational Community 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.opensource.org/licenses/ECL-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.sakaiproject.metaobj.shared.control.servlet; import java.io.BufferedInputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.Enumeration; import java.util.Hashtable; import java.util.StringTokenizer; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.sakaiproject.component.cover.ComponentManager; import org.sakaiproject.metaobj.shared.DownloadableManager; public class FileDownloadServlet extends HttpServlet { protected final Log logger = LogFactory.getLog(getClass()); public final static String REPOSITORY_PREFIX = "repository"; private static final String MANAGER_NAME = "manager"; /** * Called by the server (via the <code>service</code> method) to * allow a servlet to handle a GET request. * <p/> * <p>Overriding this method to support a GET request also * automatically supports an HTTP HEAD request. A HEAD * request is a GET request that returns no body in the * response, only the request header fields. * <p/> * <p>When overriding this method, read the request data, * write the response headers, get the response's writer or * output stream object, and finally, write the response data. * It's best to include content type and encoding. When using * a <code>PrintWriter</code> object to return the response, * set the content type before accessing the * <code>PrintWriter</code> object. * <p/> * <p>The servlet container must write the headers before * committing the response, because in HTTP the headers must be sent * before the response body. * <p/> * <p>Where possible, set the Content-Length header (with the * {@link javax.servlet.ServletResponse#setContentLength} method), * to allow the servlet container to use a persistent connection * to return its response to the client, improving performance. * The content length is automatically set if the entire response fits * inside the response buffer. * <p/> * <p>When using HTTP 1.1 chunked encoding (which means that the response * has a Transfer-Encoding header), do not set the Content-Length header. * <p/> * <p>The GET method should be safe, that is, without * any side effects for which users are held responsible. * For example, most form queries have no side effects. * If a client request is intended to change stored data, * the request should use some other HTTP method. * <p/> * <p>The GET method should also be idempotent, meaning * that it can be safely repeated. Sometimes making a * method safe also makes it idempotent. For example, * repeating queries is both safe and idempotent, but * buying a product online or modifying data is neither * safe nor idempotent. * <p/> * <p>If the request is incorrectly formatted, <code>doGet</code> * returns an HTTP "Bad Request" message. * * @param request an {@link javax.servlet.http.HttpServletRequest} object that * contains the request the client has made * of the servlet * @param response an {@link javax.servlet.http.HttpServletResponse} object that * contains the response the servlet sends * to the client * @throws java.io.IOException if an input or output error is * detected when the servlet handles * the GET request * @throws javax.servlet.ServletException if the request for the GET * could not be handled * @see javax.servlet.ServletResponse#setContentType */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { java.util.Enumeration tokenizer = new StringTokenizer(request.getRequestURI(), "/"); if (!tokenizer.hasMoreElements()) { throw new ServletException("Incorrect format url."); } String base = (String) tokenizer.nextElement(); // burn off the first element of the path while (!base.equalsIgnoreCase(REPOSITORY_PREFIX)) { if (!tokenizer.hasMoreElements()) { throw new ServletException("Incorrect format url."); } base = (String) tokenizer.nextElement(); } Hashtable params = HttpUtils.parseQueryString(getNextToken(tokenizer)); DownloadableManager manager = getDownloadableManager(((String[]) params.get(MANAGER_NAME))[0]); ByteArrayOutputStream bos = new ByteArrayOutputStream(); String filename = manager.packageForDownload(params, bos); response.setHeader("Content-Type", "application/octet-stream"); response.setHeader("Content-Disposition", "attachment" + ((filename != null && !filename.equals("")) ? ";filename=\"" + filename + "\"" : "")); response.setHeader("Content-Length", Integer.toString(bos.size())); copyStream(new ByteArrayInputStream(bos.toByteArray()), response.getOutputStream()); } private void copyStream(InputStream in, OutputStream out) throws IOException { byte data[] = new byte[1024*10]; BufferedInputStream origin = new BufferedInputStream(in, data.length); int count; while ((count = origin.read(data, 0, data.length)) != -1) { out.write(data, 0, count); } in.close(); out.flush(); } protected DownloadableManager getDownloadableManager(String name) { return (DownloadableManager) ComponentManager.get(name); } protected String getNextToken(Enumeration tokenizer) throws ServletException { if (!tokenizer.hasMoreElements()) { throw new ServletException("Incorrect format url."); } return (String) tokenizer.nextElement(); } }