001: /**********************************************************************************
002: * $URL: https://source.sakaiproject.org/svn/metaobj/tags/sakai_2-4-1/metaobj-util/tool-lib/src/java/org/sakaiproject/metaobj/shared/control/servlet/FileDownloadServlet.java $
003: * $Id: FileDownloadServlet.java 14230 2006-09-05 18:02:51Z chmaurer@iupui.edu $
004: ***********************************************************************************
005: *
006: * Copyright (c) 2005, 2006 The Sakai Foundation.
007: *
008: * Licensed under the Educational Community License, Version 1.0 (the "License");
009: * you may not use this file except in compliance with the License.
010: * You may obtain a copy of the License at
011: *
012: * http://www.opensource.org/licenses/ecl1.php
013: *
014: * Unless required by applicable law or agreed to in writing, software
015: * distributed under the License is distributed on an "AS IS" BASIS,
016: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017: * See the License for the specific language governing permissions and
018: * limitations under the License.
019: *
020: **********************************************************************************/package org.sakaiproject.metaobj.shared.control.servlet;
021:
022: import java.io.BufferedInputStream;
023: import java.io.ByteArrayInputStream;
024: import java.io.ByteArrayOutputStream;
025: import java.io.IOException;
026: import java.io.InputStream;
027: import java.io.OutputStream;
028: import java.util.Enumeration;
029: import java.util.Hashtable;
030: import java.util.StringTokenizer;
031:
032: import javax.servlet.ServletException;
033: import javax.servlet.http.HttpServlet;
034: import javax.servlet.http.HttpServletRequest;
035: import javax.servlet.http.HttpServletResponse;
036: import javax.servlet.http.HttpUtils;
037:
038: import org.apache.commons.logging.Log;
039: import org.apache.commons.logging.LogFactory;
040: import org.sakaiproject.component.cover.ComponentManager;
041: import org.sakaiproject.metaobj.shared.DownloadableManager;
042:
043: public class FileDownloadServlet extends HttpServlet {
044: protected final Log logger = LogFactory.getLog(getClass());
045:
046: public final static String REPOSITORY_PREFIX = "repository";
047: private static final String MANAGER_NAME = "manager";
048:
049: /**
050: * Called by the server (via the <code>service</code> method) to
051: * allow a servlet to handle a GET request.
052: * <p/>
053: * <p>Overriding this method to support a GET request also
054: * automatically supports an HTTP HEAD request. A HEAD
055: * request is a GET request that returns no body in the
056: * response, only the request header fields.
057: * <p/>
058: * <p>When overriding this method, read the request data,
059: * write the response headers, get the response's writer or
060: * output stream object, and finally, write the response data.
061: * It's best to include content type and encoding. When using
062: * a <code>PrintWriter</code> object to return the response,
063: * set the content type before accessing the
064: * <code>PrintWriter</code> object.
065: * <p/>
066: * <p>The servlet container must write the headers before
067: * committing the response, because in HTTP the headers must be sent
068: * before the response body.
069: * <p/>
070: * <p>Where possible, set the Content-Length header (with the
071: * {@link javax.servlet.ServletResponse#setContentLength} method),
072: * to allow the servlet container to use a persistent connection
073: * to return its response to the client, improving performance.
074: * The content length is automatically set if the entire response fits
075: * inside the response buffer.
076: * <p/>
077: * <p>When using HTTP 1.1 chunked encoding (which means that the response
078: * has a Transfer-Encoding header), do not set the Content-Length header.
079: * <p/>
080: * <p>The GET method should be safe, that is, without
081: * any side effects for which users are held responsible.
082: * For example, most form queries have no side effects.
083: * If a client request is intended to change stored data,
084: * the request should use some other HTTP method.
085: * <p/>
086: * <p>The GET method should also be idempotent, meaning
087: * that it can be safely repeated. Sometimes making a
088: * method safe also makes it idempotent. For example,
089: * repeating queries is both safe and idempotent, but
090: * buying a product online or modifying data is neither
091: * safe nor idempotent.
092: * <p/>
093: * <p>If the request is incorrectly formatted, <code>doGet</code>
094: * returns an HTTP "Bad Request" message.
095: *
096: * @param request an {@link javax.servlet.http.HttpServletRequest} object that
097: * contains the request the client has made
098: * of the servlet
099: * @param response an {@link javax.servlet.http.HttpServletResponse} object that
100: * contains the response the servlet sends
101: * to the client
102: * @throws java.io.IOException if an input or output error is
103: * detected when the servlet handles
104: * the GET request
105: * @throws javax.servlet.ServletException if the request for the GET
106: * could not be handled
107: * @see javax.servlet.ServletResponse#setContentType
108: */
109: protected void doGet(HttpServletRequest request,
110: HttpServletResponse response) throws ServletException,
111: IOException {
112: java.util.Enumeration tokenizer = new StringTokenizer(request
113: .getRequestURI(), "/");
114:
115: if (!tokenizer.hasMoreElements()) {
116: throw new ServletException("Incorrect format url.");
117: }
118: String base = (String) tokenizer.nextElement(); // burn off the first element of the path
119:
120: while (!base.equalsIgnoreCase(REPOSITORY_PREFIX)) {
121: if (!tokenizer.hasMoreElements()) {
122: throw new ServletException("Incorrect format url.");
123: }
124: base = (String) tokenizer.nextElement();
125: }
126:
127: Hashtable params = HttpUtils
128: .parseQueryString(getNextToken(tokenizer));
129:
130: DownloadableManager manager = getDownloadableManager(((String[]) params
131: .get(MANAGER_NAME))[0]);
132: ByteArrayOutputStream bos = new ByteArrayOutputStream();
133: String filename = manager.packageForDownload(params, bos);
134:
135: response.setHeader("Content-Type", "application/octet-stream");
136: response
137: .setHeader(
138: "Content-Disposition",
139: "attachment"
140: + ((filename != null && filename != "") ? ";filename=\""
141: + filename + "\""
142: : ""));
143: response.setHeader("Content-Length", Integer.toString(bos
144: .size()));
145:
146: copyStream(new ByteArrayInputStream(bos.toByteArray()),
147: response.getOutputStream());
148:
149: }
150:
151: private void copyStream(InputStream in, OutputStream out)
152: throws IOException {
153: byte data[] = new byte[1024 * 10];
154:
155: BufferedInputStream origin = new BufferedInputStream(in,
156: data.length);
157:
158: int count;
159: while ((count = origin.read(data, 0, data.length)) != -1) {
160: out.write(data, 0, count);
161: }
162: in.close();
163: out.flush();
164: }
165:
166: protected DownloadableManager getDownloadableManager(String name) {
167: return (DownloadableManager) ComponentManager.get(name);
168: }
169:
170: protected String getNextToken(Enumeration tokenizer)
171: throws ServletException {
172: if (!tokenizer.hasMoreElements()) {
173: throw new ServletException("Incorrect format url.");
174: }
175: return (String) tokenizer.nextElement();
176: }
177:
178: }
|