1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package compressionFilters;
17
18 import java.io.IOException;
19 import java.io.OutputStream;
20 import java.util.zip.GZIPOutputStream;
21 import javax.servlet.ServletOutputStream;
22 import javax.servlet.http.HttpServletResponse;
23
24
25 /**
26 * Implementation of <b>ServletOutputStream</b> that works with
27 * the CompressionServletResponseWrapper implementation.
28 *
29 * @author Amy Roh
30 * @author Dmitri Valdin
31 * @version $Revision: 267129 $, $Date: 2004-03-18 08:40:35 -0800 (Thu, 18 Mar 2004) $
32 */
33
34 public class CompressionResponseStream
35 extends ServletOutputStream {
36
37
38
39
40
41 /**
42 * Construct a servlet output stream associated with the specified Response.
43 *
44 * @param response The associated response
45 */
46 public CompressionResponseStream(HttpServletResponse response) throws IOException{
47
48 super();
49 closed = false;
50 this.response = response;
51 this.output = response.getOutputStream();
52
53 }
54
55
56
57
58
59 /**
60 * The threshold number which decides to compress or not.
61 * Users can configure in web.xml to set it to fit their needs.
62 */
63 protected int compressionThreshold = 0;
64
65 /**
66 * Debug level
67 */
68 private int debug = 0;
69
70 /**
71 * The buffer through which all of our output bytes are passed.
72 */
73 protected byte[] buffer = null;
74
75 /**
76 * The number of data bytes currently in the buffer.
77 */
78 protected int bufferCount = 0;
79
80 /**
81 * The underlying gzip output stream to which we should write data.
82 */
83 protected GZIPOutputStream gzipstream = null;
84
85 /**
86 * Has this stream been closed?
87 */
88 protected boolean closed = false;
89
90 /**
91 * The content length past which we will not write, or -1 if there is
92 * no defined content length.
93 */
94 protected int length = -1;
95
96 /**
97 * The response with which this servlet output stream is associated.
98 */
99 protected HttpServletResponse response = null;
100
101 /**
102 * The underlying servket output stream to which we should write data.
103 */
104 protected ServletOutputStream output = null;
105
106
107
108
109 /**
110 * Set debug level
111 */
112 public void setDebugLevel(int debug) {
113 this.debug = debug;
114 }
115
116
117 /**
118 * Set the compressionThreshold number and create buffer for this size
119 */
120 protected void setBuffer(int threshold) {
121 compressionThreshold = threshold;
122 buffer = new byte[compressionThreshold];
123 if (debug > 1) {
124 System.out.println("buffer is set to "+compressionThreshold);
125 }
126 }
127
128 /**
129 * Close this output stream, causing any buffered data to be flushed and
130 * any further output data to throw an IOException.
131 */
132 public void close() throws IOException {
133
134 if (debug > 1) {
135 System.out.println("close() @ CompressionResponseStream");
136 }
137 if (closed)
138 throw new IOException("This output stream has already been closed");
139
140 if (gzipstream != null) {
141 flushToGZip();
142 gzipstream.close();
143 gzipstream = null;
144 } else {
145 if (bufferCount > 0) {
146 if (debug > 2) {
147 System.out.print("output.write(");
148 System.out.write(buffer, 0, bufferCount);
149 System.out.println(")");
150 }
151 output.write(buffer, 0, bufferCount);
152 bufferCount = 0;
153 }
154 }
155
156 output.close();
157 closed = true;
158
159 }
160
161
162 /**
163 * Flush any buffered data for this output stream, which also causes the
164 * response to be committed.
165 */
166 public void flush() throws IOException {
167
168 if (debug > 1) {
169 System.out.println("flush() @ CompressionResponseStream");
170 }
171 if (closed) {
172 throw new IOException("Cannot flush a closed output stream");
173 }
174
175 if (gzipstream != null) {
176 gzipstream.flush();
177 }
178
179 }
180
181 public void flushToGZip() throws IOException {
182
183 if (debug > 1) {
184 System.out.println("flushToGZip() @ CompressionResponseStream");
185 }
186 if (bufferCount > 0) {
187 if (debug > 1) {
188 System.out.println("flushing out to GZipStream, bufferCount = " + bufferCount);
189 }
190 writeToGZip(buffer, 0, bufferCount);
191 bufferCount = 0;
192 }
193
194 }
195
196 /**
197 * Write the specified byte to our output stream.
198 *
199 * @param b The byte to be written
200 *
201 * @exception IOException if an input/output error occurs
202 */
203 public void write(int b) throws IOException {
204
205 if (debug > 1) {
206 System.out.println("write "+b+" in CompressionResponseStream ");
207 }
208 if (closed)
209 throw new IOException("Cannot write to a closed output stream");
210
211 if (bufferCount >= buffer.length) {
212 flushToGZip();
213 }
214
215 buffer[bufferCount++] = (byte) b;
216
217 }
218
219
220 /**
221 * Write <code>b.length</code> bytes from the specified byte array
222 * to our output stream.
223 *
224 * @param b The byte array to be written
225 *
226 * @exception IOException if an input/output error occurs
227 */
228 public void write(byte b[]) throws IOException {
229
230 write(b, 0, b.length);
231
232 }
233
234
235 /**
236 * Write <code>len</code> bytes from the specified byte array, starting
237 * at the specified offset, to our output stream.
238 *
239 * @param b The byte array containing the bytes to be written
240 * @param off Zero-relative starting offset of the bytes to be written
241 * @param len The number of bytes to be written
242 *
243 * @exception IOException if an input/output error occurs
244 */
245 public void write(byte b[], int off, int len) throws IOException {
246
247 if (debug > 1) {
248 System.out.println("write, bufferCount = " + bufferCount + " len = " + len + " off = " + off);
249 }
250 if (debug > 2) {
251 System.out.print("write(");
252 System.out.write(b, off, len);
253 System.out.println(")");
254 }
255
256 if (closed)
257 throw new IOException("Cannot write to a closed output stream");
258
259 if (len == 0)
260 return;
261
262
263 if (len <= (buffer.length - bufferCount)) {
264 System.arraycopy(b, off, buffer, bufferCount, len);
265 bufferCount += len;
266 return;
267 }
268
269
270 flushToGZip();
271
272
273 if (len <= (buffer.length - bufferCount)) {
274 System.arraycopy(b, off, buffer, bufferCount, len);
275 bufferCount += len;
276 return;
277 }
278
279
280 writeToGZip(b, off, len);
281 }
282
283 public void writeToGZip(byte b[], int off, int len) throws IOException {
284
285 if (debug > 1) {
286 System.out.println("writeToGZip, len = " + len);
287 }
288 if (debug > 2) {
289 System.out.print("writeToGZip(");
290 System.out.write(b, off, len);
291 System.out.println(")");
292 }
293 if (gzipstream == null) {
294 if (debug > 1) {
295 System.out.println("new GZIPOutputStream");
296 }
297 response.addHeader("Content-Encoding", "gzip");
298 gzipstream = new GZIPOutputStream(output);
299 }
300 gzipstream.write(b, off, len);
301
302 }
303
304
305
306
307
308 /**
309 * Has this response stream been closed?
310 */
311 public boolean closed() {
312
313 return (this.closed);
314
315 }
316
317 }