001    /* DERIVED FROM APACHE CODE, modifications (c) Damon Hart-Davis 2001-2006, under same terms:
002     *
003     * CompressionServletResponseWrapper.java
004     * $Header: /rw/CVS-repository.s0.l/general/PG2Ksrc/javasrc/webSvr/org/hd/d/pg2k/webSvr/util/CompressionServletResponseWrapper.java,v 1.3 2004/11/06 16:27:58 dhd Exp $
005     * $Revision: 1.3 $
006     * $Date: 2004/11/06 16:27:58 $
007     *
008     * ====================================================================
009     *
010     * The Apache Software License, Version 1.1
011     *
012     * Copyright (c) 1999 The Apache Software Foundation.  All rights
013     * reserved.
014     *
015     * Redistribution and use in source and binary forms, with or without
016     * modification, are permitted provided that the following conditions
017     * are met:
018     *
019     * 1. Redistributions of source code must retain the above copyright
020     *    notice, this list of conditions and the following disclaimer.
021     *
022     * 2. Redistributions in binary form must reproduce the above copyright
023     *    notice, this list of conditions and the following disclaimer in
024     *    the documentation and/or other materials provided with the
025     *    distribution.
026     *
027     * 3. The end-user documentation included with the redistribution, if
028     *    any, must include the following acknowlegement:
029     *       "This product includes software developed by the
030     *        Apache Software Foundation (http://www.apache.org/)."
031     *    Alternately, this acknowlegement may appear in the software itself,
032     *    if and wherever such third-party acknowlegements normally appear.
033     *
034     * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
035     *    Foundation" must not be used to endorse or promote products derived
036     *    from this software without prior written permission. For written
037     *    permission, please contact apache@apache.org.
038     *
039     * 5. Products derived from this software may not be called "Apache"
040     *    nor may "Apache" appear in their names without prior written
041     *    permission of the Apache Group.
042     *
043     * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
044     * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
045     * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
046     * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
047     * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
048     * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
049     * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
050     * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
051     * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
052     * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
053     * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
054     * SUCH DAMAGE.
055     * ====================================================================
056     *
057     * This software consists of voluntary contributions made by many
058     * individuals on behalf of the Apache Software Foundation.  For more
059     * information on the Apache Software Foundation, please see
060     * <http://www.apache.org/>.
061     *
062     * [Additional notices, if required by prior licensing conditions]
063     *
064     */
065    
066    package org.hd.d.pg2k.webSvr.util;
067    
068    import java.io.IOException;
069    import java.io.PrintWriter;
070    
071    import javax.servlet.ServletOutputStream;
072    import javax.servlet.http.HttpServletResponse;
073    import javax.servlet.http.HttpServletResponseWrapper;
074    
075    import ORG.hd.d.IsDebug;
076    
077    /**
078     * Implementation of <b>HttpServletResponseWrapper</b> that works with
079     * the CompressionServletResponseStream implementation.
080     *
081     * @author Amy Roh
082     * @version $Revision: 1.3 $, $Date: 2004/11/06 16:27:58 $
083     */
084    
085    public class CompressionServletResponseWrapper extends HttpServletResponseWrapper {
086    
087        // ----------------------------------------------------- Constructor
088    
089        /**
090         * Calls the parent constructor which creates a ServletResponse adaptor
091         * wrapping the given response object.
092         */
093    
094        public CompressionServletResponseWrapper(final HttpServletResponse response) {
095          super(response);
096          origResponse = response;
097          //System.out.println("CompressionServletResponseWrapper constructor gets called");
098        }
099    
100    
101        // ----------------------------------------------------- Instance Variables
102    
103        /**
104         * Original response
105         */
106    
107        protected HttpServletResponse origResponse = null;
108    
109        /**
110         * Descriptive information about this Response implementation.
111         */
112    
113        protected static final String info = "CompressionServletResponseWrapper";
114    
115        /**
116         * The ServletOutputStream that has been returned by
117         * <code>getOutputStream()</code>, if any.
118         */
119    
120        protected ServletOutputStream stream = null;
121    
122    
123        /**
124         * The PrintWriter that has been returned by
125         * <code>getWriter()</code>, if any.
126         */
127    
128        protected PrintWriter writer = null;
129    
130        /**
131         * The threshold number to compress
132         */
133        protected int threshold = 0;
134    
135    
136        // --------------------------------------------------------- Public Methods
137    
138    
139        /**
140         * Set threshold number
141         */
142        public void setCompressionThreshold(final int threshold) {
143            //System.out.println("setCompressionThreshold @ CompressionServletResponseWrapper");
144            this.threshold = threshold;
145        }
146    
147        /**
148         * Create and return a ServletOutputStream to write the content
149         * associated with this Response.
150         *
151         * @exception IOException if an input/output error occurs
152         */
153        public ServletOutputStream createOutputStream() throws IOException {
154    
155            //System.out.println("createOutputStream gets called");
156            return(new CompressionResponseStream(this, origResponse));
157    
158        }
159    
160    
161        /**
162         * Finish a response.
163         */
164        public void finishResponse() {
165            try {
166                if (writer != null) {
167                    writer.close();
168                } else {
169                    if (stream != null)
170                        {
171                            stream.close();
172                            }
173                }
174            } catch (final IOException e) {
175            }
176        }
177    
178    
179        // ------------------------------------------------ ServletResponse Methods
180    
181    
182        /**
183         * Flush the buffer and commit this response.
184         *
185         * @exception IOException if an input/output error occurs
186         */
187        @Override
188        public void flushBuffer() throws IOException {
189    
190            //  System.out.println("flush buffer @ CompressionServletResponseWrapper");
191            stream.flush();
192    
193        }
194    
195        /**
196         * Return the servlet output stream associated with this Response.
197         *
198         * @exception IllegalStateException if <code>getWriter</code> has
199         *  already been called for this response
200         * @exception IOException if an input/output error occurs
201         */
202        @Override
203        public ServletOutputStream getOutputStream() throws IOException {
204    
205            if (writer != null) {
206                throw new IllegalStateException("getWriter() has already been called for this response");
207                }
208    
209            if (stream == null)
210                {
211                    stream = createOutputStream();
212                    }
213            //System.out.println("stream is set to "+stream+" in getOutputStream");
214            ((CompressionResponseStream) stream).setBuffer(threshold);
215                return (stream);
216    
217        }
218    
219        /**
220         * Return the writer associated with this Response.
221         *
222         * @exception IllegalStateException if <code>getOutputStream</code> has
223         *  already been called for this response
224         * @exception IOException if an input/output error occurs
225         */
226        @Override
227        public PrintWriter getWriter() throws IOException {
228    
229            if (writer != null) {
230                return (writer);
231                }
232    
233            if (stream != null) {
234                throw new IllegalStateException("getOutputStream() has already been called for this response");
235                }
236    
237            stream = createOutputStream();
238            //System.out.println("strean is set to "+stream+" in getWriter");
239            ((CompressionResponseStream) stream).setBuffer(threshold);
240            writer = new PrintWriter(stream);
241            return (writer);
242    
243        }
244    
245        /**The value set for the Content-Length header, or zero if not (yet) set. */
246        private int contentLength;
247    
248        /**Get the value set for the Content-Length header, or zero if not (yet) set.
249         * This is only made package-visible.
250         */
251        int getContentLength()
252            { return(contentLength); }
253    
254        /**Prevent the content length being set directly.
255         * We do this because if we do apply compression
256         * then the value in this header will be wrong (too large).
257         * <p>
258         * But if we don't apply compression
259         * then we may wish to re-apply this value.
260         */
261        @Override public void setContentLength(final int length)
262            { contentLength = length; }
263    
264        /**The value set for the Content-MD5 header, or null if not (yet) set. */
265        private String contentMD5;
266    
267        /**Get the value set for the Content-MD5 header, or null if not (yet) set.
268         * This is only made package-visible.
269         */
270        String getContentMD5()
271            { return(contentMD5); }
272    
273    
274        /**Intercept any headers that interact with compression and Content-Encoding.
275         * We do this because if we do apply compression/encoding
276         * then the user-supplied value in some of these headers would be wrong.
277         * <p>
278         * But if we don't apply compression
279         * then we may wish to re-apply some of these values.
280         */
281        @Override public void setHeader(final String name, final String value)
282            {
283            if("Content-MD5".equalsIgnoreCase(name))
284                {
285    if(IsDebug.isDebug) { System.out.println("Intercepted set of Content-MD5 header"); }
286                contentMD5 = value;
287                return;
288                }
289    
290            // By default pass all sets/changes on.
291            super.setHeader(name, value);
292            }
293    
294    }