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