View Javadoc

1   package com.panogenesis.webapp.filter;
2   
3   import java.io.ByteArrayOutputStream;
4   import java.io.IOException;
5   import java.io.OutputStream;
6   import java.util.zip.GZIPOutputStream;
7   
8   import javax.servlet.ServletOutputStream;
9   import javax.servlet.http.HttpServletResponse;
10  
11  
12  /***
13   * Wraps Response Stream for GZipFilter
14   *
15   * @author  Matt Raible
16   * @version $Revision: 1.1 $ $Date: 2004/11/28 03:49:32 $
17   */
18  public class GZIPResponseStream extends ServletOutputStream {
19      // abstraction of the output stream used for compression
20      protected OutputStream bufferedOutput = null;
21  
22      // state keeping variable for if close() has been called
23      protected boolean closed = false;
24  
25      // reference to original response
26      protected HttpServletResponse response = null;
27  
28      // reference to the output stream to the client's browser
29      protected ServletOutputStream output = null;
30  
31      // default size of the in-memory buffer
32      private int bufferSize = 50000;
33  
34      public GZIPResponseStream(HttpServletResponse response)
35      throws IOException {
36          super();
37          closed = false;
38          this.response = response;
39          this.output = response.getOutputStream();
40          bufferedOutput = new ByteArrayOutputStream();
41      }
42  
43      public void close() throws IOException {
44          // verify the stream is yet to be closed
45          if (closed) {
46              throw new IOException("This output stream has already been closed");
47          }
48  
49          // if we buffered everything in memory, gzip it
50          if (bufferedOutput instanceof ByteArrayOutputStream) {
51              // get the content
52              ByteArrayOutputStream baos = (ByteArrayOutputStream) bufferedOutput;
53  
54              // prepare a gzip stream
55              ByteArrayOutputStream compressedContent =
56                  new ByteArrayOutputStream();
57              GZIPOutputStream gzipstream =
58                  new GZIPOutputStream(compressedContent);
59              byte[] bytes = baos.toByteArray();
60              gzipstream.write(bytes);
61              gzipstream.finish();
62  
63              // get the compressed content
64              byte[] compressedBytes = compressedContent.toByteArray();
65  
66              // set appropriate HTTP headers
67              response.setContentLength(compressedBytes.length);
68              response.addHeader("Content-Encoding", "gzip");
69              output.write(compressedBytes);
70              output.flush();
71              output.close();
72              closed = true;
73          }
74          // if things were not buffered in memory, finish the GZIP stream and response
75          else if (bufferedOutput instanceof GZIPOutputStream) {
76              // cast to appropriate type
77              GZIPOutputStream gzipstream = (GZIPOutputStream) bufferedOutput;
78  
79              // finish the compression
80              gzipstream.finish();
81  
82              // finish the response
83              output.flush();
84              output.close();
85              closed = true;
86          }
87      }
88  
89      public void flush() throws IOException {
90          if (closed) {
91              throw new IOException("Cannot flush a closed output stream");
92          }
93  
94          bufferedOutput.flush();
95      }
96  
97      public void write(int b) throws IOException {
98          if (closed) {
99              throw new IOException("Cannot write to a closed output stream");
100         }
101 
102         // make sure we aren't over the buffer's limit
103         checkBufferSize(1);
104 
105         // write the byte to the temporary output
106         bufferedOutput.write((byte) b);
107     }
108 
109     private void checkBufferSize(int length) throws IOException {
110         // check if we are buffering too large of a file
111         if (bufferedOutput instanceof ByteArrayOutputStream) {
112             ByteArrayOutputStream baos = (ByteArrayOutputStream) bufferedOutput;
113 
114             if ((baos.size() + length) > bufferSize) {
115                 // files too large to keep in memory are sent to the client without Content-Length specified
116                 response.addHeader("Content-Encoding", "gzip");
117 
118                 // get existing bytes
119                 byte[] bytes = baos.toByteArray();
120 
121                 // make new gzip stream using the response output stream
122                 GZIPOutputStream gzipstream = new GZIPOutputStream(output);
123                 gzipstream.write(bytes);
124 
125                 // we are no longer buffering, send content via gzipstream
126                 bufferedOutput = gzipstream;
127             }
128         }
129     }
130 
131     public void write(byte[] b) throws IOException {
132         write(b, 0, b.length);
133     }
134 
135     public void write(byte[] b, int off, int len) throws IOException {
136 
137         if (closed) {
138             throw new IOException("Cannot write to a closed output stream");
139         }
140 
141         // make sure we aren't over the buffer's limit
142         checkBufferSize(len);
143 
144         // write the content to the buffer
145         bufferedOutput.write(b, off, len);
146     }
147 
148     public boolean closed() {
149         return (this.closed);
150     }
151 
152     public void reset() {
153         //noop
154     }
155 }