You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

DownloadStream.java 9.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. /*
  2. @ITMillApache2LicenseForJavaFiles@
  3. */
  4. package com.vaadin.terminal;
  5. import java.io.IOException;
  6. import java.io.InputStream;
  7. import java.io.OutputStream;
  8. import java.io.Serializable;
  9. import java.util.HashMap;
  10. import java.util.Iterator;
  11. import java.util.Map;
  12. import javax.servlet.http.HttpServletResponse;
  13. import com.vaadin.terminal.gwt.server.Constants;
  14. /**
  15. * Downloadable stream.
  16. *
  17. * @author IT Mill Ltd.
  18. * @version
  19. * @VERSION@
  20. * @since 3.0
  21. */
  22. @SuppressWarnings("serial")
  23. public class DownloadStream implements Serializable {
  24. /**
  25. * Maximum cache time.
  26. */
  27. public static final long MAX_CACHETIME = Long.MAX_VALUE;
  28. /**
  29. * Default cache time.
  30. */
  31. public static final long DEFAULT_CACHETIME = 1000 * 60 * 60 * 24;
  32. private InputStream stream;
  33. private String contentType;
  34. private String fileName;
  35. private Map<String, String> params;
  36. private long cacheTime = DEFAULT_CACHETIME;
  37. private int bufferSize = 0;
  38. /**
  39. * Creates a new instance of DownloadStream.
  40. */
  41. public DownloadStream(InputStream stream, String contentType,
  42. String fileName) {
  43. setStream(stream);
  44. setContentType(contentType);
  45. setFileName(fileName);
  46. }
  47. /**
  48. * Gets downloadable stream.
  49. *
  50. * @return output stream.
  51. */
  52. public InputStream getStream() {
  53. return stream;
  54. }
  55. /**
  56. * Sets the stream.
  57. *
  58. * @param stream
  59. * The stream to set
  60. */
  61. public void setStream(InputStream stream) {
  62. this.stream = stream;
  63. }
  64. /**
  65. * Gets stream content type.
  66. *
  67. * @return type of the stream content.
  68. */
  69. public String getContentType() {
  70. return contentType;
  71. }
  72. /**
  73. * Sets stream content type.
  74. *
  75. * @param contentType
  76. * the contentType to set
  77. */
  78. public void setContentType(String contentType) {
  79. this.contentType = contentType;
  80. }
  81. /**
  82. * Returns the file name.
  83. *
  84. * @return the name of the file.
  85. */
  86. public String getFileName() {
  87. return fileName;
  88. }
  89. /**
  90. * Sets the file name.
  91. *
  92. * @param fileName
  93. * the file name to set.
  94. */
  95. public void setFileName(String fileName) {
  96. this.fileName = fileName;
  97. }
  98. /**
  99. * Sets a paramater for download stream. Parameters are optional information
  100. * about the downloadable stream and their meaning depends on the used
  101. * adapter. For example in WebAdapter they are interpreted as HTTP response
  102. * headers.
  103. *
  104. * If the parameters by this name exists, the old value is replaced.
  105. *
  106. * @param name
  107. * the Name of the parameter to set.
  108. * @param value
  109. * the Value of the parameter to set.
  110. */
  111. public void setParameter(String name, String value) {
  112. if (params == null) {
  113. params = new HashMap<String, String>();
  114. }
  115. params.put(name, value);
  116. }
  117. /**
  118. * Gets a paramater for download stream. Parameters are optional information
  119. * about the downloadable stream and their meaning depends on the used
  120. * adapter. For example in WebAdapter they are interpreted as HTTP response
  121. * headers.
  122. *
  123. * @param name
  124. * the Name of the parameter to set.
  125. * @return Value of the parameter or null if the parameter does not exist.
  126. */
  127. public String getParameter(String name) {
  128. if (params != null) {
  129. return params.get(name);
  130. }
  131. return null;
  132. }
  133. /**
  134. * Gets the names of the parameters.
  135. *
  136. * @return Iterator of names or null if no parameters are set.
  137. */
  138. public Iterator<String> getParameterNames() {
  139. if (params != null) {
  140. return params.keySet().iterator();
  141. }
  142. return null;
  143. }
  144. /**
  145. * Gets length of cache expiration time. This gives the adapter the
  146. * possibility cache streams sent to the client. The caching may be made in
  147. * adapter or at the client if the client supports caching. Default is
  148. * <code>DEFAULT_CACHETIME</code>.
  149. *
  150. * @return Cache time in milliseconds
  151. */
  152. public long getCacheTime() {
  153. return cacheTime;
  154. }
  155. /**
  156. * Sets length of cache expiration time. This gives the adapter the
  157. * possibility cache streams sent to the client. The caching may be made in
  158. * adapter or at the client if the client supports caching. Zero or negavive
  159. * value disbales the caching of this stream.
  160. *
  161. * @param cacheTime
  162. * the cache time in milliseconds.
  163. */
  164. public void setCacheTime(long cacheTime) {
  165. this.cacheTime = cacheTime;
  166. }
  167. /**
  168. * Gets the size of the download buffer.
  169. *
  170. * @return int The size of the buffer in bytes.
  171. */
  172. public int getBufferSize() {
  173. return bufferSize;
  174. }
  175. /**
  176. * Sets the size of the download buffer.
  177. *
  178. * @param bufferSize
  179. * the size of the buffer in bytes.
  180. *
  181. * @since 7.0
  182. */
  183. public void setBufferSize(int bufferSize) {
  184. this.bufferSize = bufferSize;
  185. }
  186. /**
  187. * Writes this download stream to a wrapped response. This takes care of
  188. * setting response headers according to what is defined in this download
  189. * stream ({@link #getContentType()}, {@link #getCacheTime()},
  190. * {@link #getFileName()}) and transferring the data from the stream (
  191. * {@link #getStream()}) to the response. Defined parameters (
  192. * {@link #getParameterNames()}) are also included as headers in the
  193. * response. If there's is a parameter named <code>Location</code>, a
  194. * redirect (302 Moved temporarily) is sent instead of the contents of this
  195. * stream.
  196. *
  197. * @param response
  198. * the wrapped response to write this download stream to
  199. * @throws IOException
  200. * passed through from the wrapped response
  201. *
  202. * @since 7.0
  203. */
  204. public void writeTo(WrappedResponse response) throws IOException {
  205. if (getParameter("Location") != null) {
  206. response.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY);
  207. response.setHeader("Location", getParameter("Location"));
  208. return;
  209. }
  210. // Download from given stream
  211. final InputStream data = getStream();
  212. if (data != null) {
  213. OutputStream out = null;
  214. try {
  215. // Sets content type
  216. response.setContentType(getContentType());
  217. // Sets cache headers
  218. response.setCacheTime(getCacheTime());
  219. // Copy download stream parameters directly
  220. // to HTTP headers.
  221. final Iterator<String> i = getParameterNames();
  222. if (i != null) {
  223. while (i.hasNext()) {
  224. final String param = i.next();
  225. response.setHeader(param, getParameter(param));
  226. }
  227. }
  228. // suggest local filename from DownloadStream if
  229. // Content-Disposition
  230. // not explicitly set
  231. String contentDispositionValue = getParameter("Content-Disposition");
  232. if (contentDispositionValue == null) {
  233. contentDispositionValue = "filename=\"" + getFileName()
  234. + "\"";
  235. response.setHeader("Content-Disposition",
  236. contentDispositionValue);
  237. }
  238. int bufferSize = getBufferSize();
  239. if (bufferSize <= 0 || bufferSize > Constants.MAX_BUFFER_SIZE) {
  240. bufferSize = Constants.DEFAULT_BUFFER_SIZE;
  241. }
  242. final byte[] buffer = new byte[bufferSize];
  243. int bytesRead = 0;
  244. out = response.getOutputStream();
  245. long totalWritten = 0;
  246. while ((bytesRead = data.read(buffer)) > 0) {
  247. out.write(buffer, 0, bytesRead);
  248. totalWritten += bytesRead;
  249. if (totalWritten >= buffer.length) {
  250. // Avoid chunked encoding for small resources
  251. out.flush();
  252. }
  253. }
  254. } finally {
  255. tryToCloseStream(out);
  256. tryToCloseStream(data);
  257. }
  258. }
  259. }
  260. /**
  261. * Helper method that tries to close an output stream and ignores any
  262. * exceptions.
  263. *
  264. * @param out
  265. * the output stream to close, <code>null</code> is also
  266. * supported
  267. */
  268. static void tryToCloseStream(OutputStream out) {
  269. try {
  270. // try to close output stream (e.g. file handle)
  271. if (out != null) {
  272. out.close();
  273. }
  274. } catch (IOException e1) {
  275. // NOP
  276. }
  277. }
  278. /**
  279. * Helper method that tries to close an input stream and ignores any
  280. * exceptions.
  281. *
  282. * @param in
  283. * the input stream to close, <code>null</code> is also supported
  284. */
  285. static void tryToCloseStream(InputStream in) {
  286. try {
  287. // try to close output stream (e.g. file handle)
  288. if (in != null) {
  289. in.close();
  290. }
  291. } catch (IOException e1) {
  292. // NOP
  293. }
  294. }
  295. }