Source code: org/mentawai/core/StreamConsequence.java
1 /*
2 * Mentawai Web Framework http://mentawai.lohis.com.br/
3 * Copyright (C) 2005 Sergio Oliveira Jr. (sergio.oliveira.jr@gmail.com)
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19 package org.mentawai.core;
20
21 import java.io.IOException;
22 import java.io.InputStream;
23 import java.io.OutputStream;
24 import java.io.PrintWriter;
25
26 import javax.servlet.http.HttpServletRequest;
27 import javax.servlet.http.HttpServletResponse;
28
29 import org.mentawai.core.Action;
30 import org.mentawai.core.Consequence;
31 import org.mentawai.core.ConsequenceException;
32 import org.mentawai.core.Output;
33
34 /**
35 *
36 * A web-based consequence that gets a ready-to-use input stream
37 * from the output of the action, get the contents from that input
38 * stream and flush them to the servlet output stream.
39 * Very useful for loading images from a database, downloads and
40 * other resources that the programmer may want to protect from
41 * direct access from the client.
42 * This class is <i>thread-safe</i>.
43 *
44 * @author Rubem Azenha
45 */
46 public class StreamConsequence implements Consequence {
47
48 /** The default key ("<i>stream</i>") to look for in the action output. */
49 public static final String STREAM_KEY = "stream";
50
51 /** The default key ("<i>contentDisposition</i>") to look for in the action output. */
52 public static final String CONTENT_DISPOSITION_KEY = "contentDisposition";
53
54 /** The default key ("<i>contentLength</i>") to look for in the action output. */
55 public static final String CONTENT_LENGTH_KEY = "contentLength";
56
57 // The content-type of the message
58 private String contentType;
59
60 // The key with which to get the stream from the output...
61 private String stream_key = STREAM_KEY;
62
63 // The key with which to get the content disposition from the output...
64 private String content_disposition_key = CONTENT_DISPOSITION_KEY;
65
66 // The key with which to get the content length from the output...
67 private String content_length_key = CONTENT_LENGTH_KEY;
68
69
70 /**
71 * Creates a new instance of the StreamConsequence class,
72 * with the given content-type
73 *
74 * @param contentType The content type to set in the servlet response.
75 */
76 public StreamConsequence(String contentType) {
77 this.contentType = contentType;
78 }
79
80 /**
81 * Creates a new instance of the StreamConsequence class,
82 * with the given content-type and key.
83 *
84 * @param contentType The content type to set in the servlet response.
85 * @param stream_key The key with which to get the stream from the output.
86 */
87 public StreamConsequence(String contentType, String stream_key) {
88 this(contentType);
89 this.stream_key = stream_key;
90 }
91
92 /**
93 * Creates a new instance of the StreamConsequence class,
94 * with the given content-type and key.
95 *
96 * @param contentType The content type to set in the servlet response.
97 * @param stream_key The key with which to get the stream from the output.
98 * @param content_disposition_key The key with which to get the content disposition from the output.
99 */
100 public StreamConsequence(String contentType, String stream_key, String content_disposition_key) {
101 this(contentType, stream_key);
102 this.content_disposition_key = content_disposition_key;
103 }
104
105 /**
106 * Creates a new instance of the StreamConsequence class,
107 * with the given content-type and key.
108 *
109 * @param contentType The content type to set in the servlet response.
110 * @param stream_key The key with which to get the stream from the output.
111 * @param content_disposition_key The key with which to get the content disposition from the output.
112 * @param content_length_key The key with which to get the content length from the output.
113 */
114 public StreamConsequence(String contentType, String stream_key, String content_disposition_key, String content_length_key) {
115 this(contentType, stream_key, content_disposition_key);
116 this.content_length_key = content_length_key;
117 }
118
119 /**
120 * Executes the action, reading from the input stream the data that
121 * has to be flushed into the servlet output stream.
122 */
123 public void execute(Action a, HttpServletRequest req, HttpServletResponse res) throws ConsequenceException {
124 Output output = a.getOutput();
125 defineHeader(res, output);
126 OutputStream outputStream = null;
127 try {
128 outputStream = res.getOutputStream();
129 } catch (IOException e) {
130 throw new ConsequenceException(e);
131 }
132
133 Object obj = output.getValue(stream_key);
134 try {
135 if (obj instanceof InputStream) {
136 InputStream in = (InputStream) obj;
137 int i;
138 while((i = in.read()) != -1) {
139 outputStream.write(i);
140 }
141 outputStream.flush();
142 } else if (obj instanceof byte[]) {
143 byte [] b = (byte []) obj;
144 outputStream.write(b);
145 outputStream.flush();
146 } else {
147 throw new ConsequenceException("Cannot find stream: " + stream_key);
148 }
149 } catch(Exception e) {
150 throw new ConsequenceException(e);
151 }
152 }
153
154 protected void defineHeader(HttpServletResponse res, Output output) {
155 res.setContentType(contentType);
156
157 Object contentLength = output.getValue(content_length_key);
158 if (contentLength != null && contentLength instanceof Integer) {
159 res.setContentLength(((Integer) contentLength).intValue());
160 }
161
162 Object contentDisposition = output.getValue(content_disposition_key);
163 if (contentDisposition == null) {
164 res.setHeader("Content-Disposition", "inline");
165 } else {
166 res.setHeader("Content-Disposition", contentDisposition.toString());
167 }
168 }
169 }