File Source: CompressionFilter.java
/*
P/P * Method: org.apache.roller.weblogger.ui.core.filters.CompressionFilter$ByteArrayResponseWrapper__static_init
*/
1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. The ASF licenses this file to You
4 * under the Apache License, Version 2.0 (the "License"); you may not
5 * use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License. For additional information regarding
15 * copyright in this work, please see the NOTICE file in the top level
16 * directory of this distribution.
17 */
18
19 package org.apache.roller.weblogger.ui.core.filters;
20
21 import java.io.ByteArrayOutputStream;
22 import java.io.IOException;
23 import java.io.OutputStream;
24 import java.io.OutputStreamWriter;
25 import java.io.PrintWriter;
26 import java.util.zip.GZIPOutputStream;
27 import javax.servlet.Filter;
28 import javax.servlet.FilterChain;
29 import javax.servlet.FilterConfig;
30 import javax.servlet.ServletException;
31 import javax.servlet.ServletOutputStream;
32 import javax.servlet.ServletRequest;
33 import javax.servlet.ServletResponse;
34 import javax.servlet.http.HttpServletRequest;
35 import javax.servlet.http.HttpServletResponse;
36 import javax.servlet.http.HttpServletResponseWrapper;
37 import org.apache.commons.logging.Log;
38 import org.apache.commons.logging.LogFactory;
39 import org.apache.roller.weblogger.config.WebloggerConfig;
40
41
42 /**
43 * Filter that compresses output with gzip (assuming that browser supports gzip).
44 * <P>
45 * Taken from More Servlets and JavaServer Pages from Prentice Hall and
46 * Sun Microsystems Press, http://www.moreservlets.com/.
47 * © 2002 Marty Hall; may be freely used or adapted.
48 */
/*
P/P * Method: void org.apache.roller.weblogger.ui.core.filters.CompressionFilter()
*
* Postconditions:
* this.enabled == 1
*/
49 public class CompressionFilter implements Filter {
50
/*
P/P * Method: org.apache.roller.weblogger.ui.core.filters.CompressionFilter__static_init
*
* Postconditions:
* init'ed(log)
*/
51 private static Log log = LogFactory.getLog(CompressionFilter.class);
52
53 private boolean enabled = true;
54
55
56 /**
57 * If browser does not support gzip, invoke resource normally. If browser
58 * does support gzip, set the Content-Encoding response header and invoke
59 * resource with a wrapped response that collects all the output. Extract
60 * the output and write it into a gzipped byte array. Finally, write that
61 * array to the client's output stream.
62 */
63 public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
64 throws ServletException, IOException {
65
/*
P/P * Method: void doFilter(ServletRequest, ServletResponse, FilterChain)
*
* Preconditions:
* chain != null
* init'ed(this.enabled)
* (soft) log != null
* (soft) request != null
* (soft) response != null
*
* Presumptions:
* javax.servlet.ServletResponse:getOutputStream(...)@150 != null
*
* Test Vectors:
* this.enabled: {0}, {1}
*/
66 HttpServletRequest req = (HttpServletRequest) request;
67 HttpServletResponse res = (HttpServletResponse) response;
68
69 if (!this.enabled || !isGzipSupported(req)) {
70 // Invoke resource normally.
71 chain.doFilter(req, res);
72 } else {
73 // Tell browser we are sending it gzipped data.
74 res.setHeader("Content-Encoding", "gzip");
75
76 // Invoke resource, accumulating output in the wrapper.
77 ByteArrayResponseWrapper responseWrapper =
78 new ByteArrayResponseWrapper(response);
79
80 chain.doFilter(req, responseWrapper);
81
82 ByteArrayOutputStream outputStream = responseWrapper.getByteArrayOutputStream();
83
84 // Get character array representing output.
85 log.debug("Pre-zip size:" + outputStream.size());
86
87 // Make a writer that compresses data and puts
88 // it into a byte array.
89 ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
90 GZIPOutputStream zipOut = new GZIPOutputStream(byteStream);
91
92 // Compress original output and put it into byte array.
93 zipOut.write(responseWrapper.getByteArrayOutputStream().toByteArray());
94
95 // Gzip streams must be explicitly closed.
96 zipOut.close();
97
98 log.debug("Gzip size:" + byteStream.size());
99
100 // Update the Content-Length header.
101 res.setContentLength(byteStream.size());
102
103 ByteArrayOutputStreamWrapper newOut =
104 (ByteArrayOutputStreamWrapper) responseWrapper.getOutputStream();
105 newOut.clear();
106 newOut.setFinallized();
107
108 /* now force close of OutputStream */
109 newOut.write(byteStream.toByteArray());
110 newOut.close();
111 }
112
113 }
114
115
116 public void init(FilterConfig config) throws ServletException {
117
118 // is compression enabled?
/*
P/P * Method: void init(FilterConfig)
*
* Preconditions:
* log != null
*
* Postconditions:
* init'ed(this.enabled)
*
* Test Vectors:
* org.apache.roller.weblogger.config.WebloggerConfig:getBooleanProperty(...)@119: {0}, {1}
*/
119 if(WebloggerConfig.getBooleanProperty("compression.gzipResponse.enabled")) {
120 this.enabled = true;
121 log.info("Compressed Output ENABLED");
122 } else {
123 this.enabled = false;
124 log.info("Compressed Output DISABLED");
125 }
126 }
127
128
/*
P/P * Method: void destroy()
*/
129 public void destroy() {}
130
131
132 private boolean isGzipSupported(HttpServletRequest req) {
/*
P/P * Method: bool isGzipSupported(HttpServletRequest)
*
* Preconditions:
* req != null
*
* Postconditions:
* init'ed(return_value)
*/
133 String browserEncodings = req.getHeader("Accept-Encoding");
134 return ((browserEncodings != null)
135 && (browserEncodings.indexOf("gzip") != -1));
136 }
137
138
139 /**
140 * Implementation of HttpServletResponseWrapper that supports caching.
141 */
142 private class ByteArrayResponseWrapper extends HttpServletResponseWrapper {
143
144 private PrintWriter tpWriter;
145 private ByteArrayOutputStreamWrapper tpStream;
146
147
/*
P/P * Method: void org.apache.roller.weblogger.ui.core.filters.CompressionFilter$ByteArrayResponseWrapper(CompressionFilter, ServletResponse)
*
* Preconditions:
* inResp != null
*
* Postconditions:
* this.tpStream == &new CompressionFilter$ByteArrayOutputStreamWrapper(CompressionFilter$ByteArrayResponseWrapper#1)
* this.tpWriter == &new PrintWriter(CompressionFilter$ByteArrayResponseWrapper#2)
* new ByteArrayOutputStream(CompressionFilter$ByteArrayOutputStreamWrapper#1) num objects == 1
* new CompressionFilter$ByteArrayOutputStreamWrapper(CompressionFilter$ByteArrayResponseWrapper#1) num objects == 1
* this.tpStream.flushOnFinalizeOnly == 1
* new PrintWriter(CompressionFilter$ByteArrayResponseWrapper#2) num objects == 1
* this.tpStream.baStream == &new ByteArrayOutputStream(CompressionFilter$ByteArrayOutputStreamWrapper#1)
* init'ed(this.tpStream.finallized)
* init'ed(this.tpStream.intStream)
*/
148 public ByteArrayResponseWrapper(ServletResponse inResp) throws IOException {
149 super((HttpServletResponse) inResp);
150 tpStream = new ByteArrayOutputStreamWrapper(inResp.getOutputStream());
151 tpWriter = new PrintWriter(new OutputStreamWriter(tpStream,"UTF-8"));
152 }
153
154
155 public ServletOutputStream getOutputStream() throws IOException {
/*
P/P * Method: ServletOutputStream getOutputStream()
*
* Preconditions:
* init'ed(this.tpStream)
*
* Postconditions:
* return_value == this.tpStream
* init'ed(return_value)
*/
156 return tpStream;
157 }
158
159 public PrintWriter getWriter() throws IOException {
/*
P/P * Method: PrintWriter getWriter()
*
* Preconditions:
* init'ed(this.tpWriter)
*
* Postconditions:
* return_value == this.tpWriter
* init'ed(return_value)
*/
160 return tpWriter;
161 }
162
163 /**
164 * Get a String representation of the entire buffer.
165 */
166 public String toString() {
/*
P/P * Method: String toString()
*
* Preconditions:
* this.tpStream != null
* this.tpStream.baStream != null
*
* Postconditions:
* java.io.ByteArrayOutputStream:toString(...)._tainted == this.tpStream.baStream._tainted
* init'ed(java.io.ByteArrayOutputStream:toString(...)._tainted)
* return_value == &java.io.ByteArrayOutputStream:toString(...)
*/
167 return tpStream.getByteArrayStream().toString();
168 }
169
170 public ByteArrayOutputStream getByteArrayOutputStream() throws IOException {
/*
P/P * Method: ByteArrayOutputStream getByteArrayOutputStream()
*
* Preconditions:
* this.tpStream != null
* init'ed(this.tpStream.baStream)
*
* Postconditions:
* return_value == this.tpStream.baStream
* init'ed(return_value)
*/
171 return tpStream.getByteArrayStream();
172 }
173
174 }
175
176
177 /**
178 * Implementation of ServletOutputStream that allows the filter to hold the
179 * Response content for insertion into the cache.
180 */
181 private class ByteArrayOutputStreamWrapper extends ServletOutputStream {
182
183 protected OutputStream intStream;
184 protected ByteArrayOutputStream baStream;
185 protected boolean finallized = false;
186 protected boolean flushOnFinalizeOnly = true;
187
188
/*
P/P * Method: void org.apache.roller.weblogger.ui.core.filters.CompressionFilter$ByteArrayOutputStreamWrapper(CompressionFilter, OutputStream)
*
* Postconditions:
* this.baStream == &new ByteArrayOutputStream(CompressionFilter$ByteArrayOutputStreamWrapper#1)
* this.finallized == 0
* this.flushOnFinalizeOnly == 1
* new ByteArrayOutputStream(CompressionFilter$ByteArrayOutputStreamWrapper#1) num objects == 1
* this.intStream == outStream
* init'ed(this.intStream)
*/
189 public ByteArrayOutputStreamWrapper(OutputStream outStream) {
190 intStream = outStream;
191 baStream = new ByteArrayOutputStream();
192 }
193
/*
P/P * Method: void org.apache.roller.weblogger.ui.core.filters.CompressionFilter$ByteArrayOutputStreamWrapper(CompressionFilter)
*
* Presumptions:
* init'ed(java.lang.System.out)
*
* Postconditions:
* this.baStream == &new ByteArrayOutputStream(CompressionFilter$ByteArrayOutputStreamWrapper#1)
* this.finallized == 0
* this.flushOnFinalizeOnly == 1
* new ByteArrayOutputStream(CompressionFilter$ByteArrayOutputStreamWrapper#1) num objects == 1
* this.intStream == java.lang.System.out
* (soft) init'ed(this.intStream)
*/
194 public ByteArrayOutputStreamWrapper() {
195 intStream = System.out;
196 baStream = new ByteArrayOutputStream();
197 }
198
199
200 public ByteArrayOutputStream getByteArrayStream() {
/*
P/P * Method: ByteArrayOutputStream getByteArrayStream()
*
* Preconditions:
* init'ed(this.baStream)
*
* Postconditions:
* return_value == this.baStream
* init'ed(return_value)
*/
201 return baStream;
202 }
203
204 public void setFinallized() {
/*
P/P * Method: void setFinallized()
*
* Postconditions:
* this.finallized == 1
*/
205 finallized = true;
206 }
207
208 public boolean isFinallized() {
/*
P/P * Method: bool isFinallized()
*
* Preconditions:
* init'ed(this.finallized)
*
* Postconditions:
* return_value == this.finallized
* init'ed(return_value)
*/
209 return finallized;
210 }
211
212
213 public void write(int i) throws java.io.IOException {
/*
P/P * Method: void write(int)
*
* Preconditions:
* this.baStream != null
*/
214 baStream.write(i);
215 }
216
217 public void close() throws java.io.IOException {
/*
P/P * Method: void close()
*
* Preconditions:
* init'ed(this.finallized)
* (soft) this.baStream != null
* (soft) this.intStream != null
*
* Test Vectors:
* this.finallized: {0}, {1}
*/
218 if (finallized) {
219 processStream();
220 intStream.close();
221 }
222 }
223
224 public void flush() throws java.io.IOException {
/*
P/P * Method: void flush()
*
* Preconditions:
* this.baStream != null
* (soft) init'ed(this.finallized)
* (soft) init'ed(this.flushOnFinalizeOnly)
* (soft) this.intStream != null
*
* Postconditions:
* this.baStream == One-of{old this.baStream, &new ByteArrayOutputStream(flush#1)}
* this.baStream != null
* new ByteArrayOutputStream(flush#1) num objects <= 1
*
* Test Vectors:
* this.finallized: {0}, {1}
* java.io.ByteArrayOutputStream:size(...)@225: {0}, {-231..-1, 1..232-1}
*/
225 if (baStream.size() != 0) {
226 if (!flushOnFinalizeOnly || finallized) {
227 processStream();
228 baStream = new ByteArrayOutputStream();
229 }
230 }
231 }
232
233 protected void processStream() throws java.io.IOException {
/*
P/P * Method: void processStream()
*
* Preconditions:
* this.baStream != null
* this.intStream != null
*/
234 intStream.write(baStream.toByteArray());
235 intStream.flush();
236 }
237
238 public void clear() {
/*
P/P * Method: void clear()
*
* Postconditions:
* this.baStream == &new ByteArrayOutputStream(clear#1)
* new ByteArrayOutputStream(clear#1) num objects == 1
*/
239 baStream = new ByteArrayOutputStream();
240 }
241
242 }
243
244 }
SofCheck Inspector Build Version : 2.18479
| CompressionFilter.java |
2009-Jan-02 14:24:56 |
| CompressionFilter.class |
2009-Sep-04 03:12:44 |
| CompressionFilter$ByteArrayOutputStreamWrapper.class |
2009-Sep-04 03:12:44 |
| CompressionFilter$ByteArrayResponseWrapper.class |
2009-Sep-04 03:12:44 |