001    /*
002     * Copyright (c) 2009 The openGion Project.
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     *     http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
013     * either express or implied. See the License for the specific language
014     * governing permissions and limitations under the License.
015     */
016    package org.opengion.hayabusa.filter;
017    
018    import org.opengion.fukurou.util.Closer;
019    
020    import java.io.ByteArrayOutputStream;
021    import java.io.IOException;
022    
023    import java.util.zip.GZIPOutputStream;
024    import javax.servlet.ServletOutputStream;
025    import javax.servlet.http.HttpServletResponse;
026    
027    /**
028     * GZIPFilter で使用する、GZIP圧縮するServletOutputStreamクラスですã?
029     *
030     * @og.group フィルター処ç�?
031     *
032     * @version  4.0
033     * @author   Kazuhiko Hasegawa
034     * @since    JDK5.0,
035     */
036    public class GZIPResponseStream extends ServletOutputStream {
037            /** å†?ƒ¨出力ストリーãƒ?*/
038            protected ByteArrayOutputStream baos = null;
039            /** GZIP出力ストリーãƒ?*/
040            protected GZIPOutputStream gzipstream = null;
041            /** クローズ判å®?*/
042            protected boolean isClosed = false;
043            /** レスポンスオブジェクãƒ?*/
044            protected HttpServletResponse response = null;
045            /** サーブレãƒ?ƒˆ出力ストリーãƒ?*/
046            protected ServletOutputStream output = null;
047    
048            /**
049             * コンストラクター
050             *
051             * @param response HttpServletResponseオブジェクãƒ?
052             * @throws IOException 入出力エラーが発生したとã�?
053             */
054            public GZIPResponseStream(final HttpServletResponse response) throws IOException {
055                    // 4.3.4.4 (2009/01/01)
056    //              super();
057                    isClosed = false;
058                    this.response = response;
059                    this.output = response.getOutputStream();
060                    baos = new ByteArrayOutputStream();
061                    gzipstream = new GZIPOutputStream(baos);
062            }
063    
064            /**
065             * こã?ストリーãƒ?‚’閉じ、このストリーãƒ?�«関連するすべてのシスãƒ?ƒ リソースを解放しますã?
066             *
067             * close の汎用規ç´?�§は、close は出力ストリーãƒ?‚’閉じますã?閉じられたストリーãƒ??
068             * 出力å?ç�?‚’実行できません。またã?それを開き直すことはできませんã€?
069             *
070             * @og.rev 5.1.7.0 (2010/06/01) isClosed == true の場合に Exception でなくã?return にするã€?
071             *
072             * @throws IOException 入出力エラーが発生したとã�?
073             */
074            @Override
075            public void close() throws IOException {
076                    if(isClosed) {
077    //                      throw new IOException("This output stream has already been closed");
078                            return ;
079                    }
080                    try {
081                            gzipstream.finish();
082    
083                            byte[] bytes = baos.toByteArray();
084    
085    //                      response.addHeader("Content-Length", Integer.toString(bytes.length));
086                            response.setContentLength( bytes.length );
087    // System.out.println( bytes.length );
088                            response.addHeader("Content-Encoding", "gzip");
089                            output.write(bytes);
090                            output.flush();
091                    }
092                    finally {
093                            isClosed = true;
094                            Closer.ioClose( output );
095                    }
096            }
097    
098            /**
099             * こã?出力ストリーãƒ?‚’フラãƒ?‚·ュしã?バッファに入ってã�?‚‹出力バイトをすべて強制çš?›¸き込みますにã€?
100             *
101             * flush の汎用規ç´?�§は、それまでに書き込まれたバイトが出力ストリーãƒ??
102             * 実è£?�«よってバッファに入れられてã�?‚‹場合に flush を呼び出すと、それらのバイトã?
103             * ただちにそã?目çš??転送å?に書き込まれますã?
104             *
105             * @og.rev 5.1.7.0 (2010/06/01) isClosed == true の場合に Exception でなくã?return にするã€?
106             *
107             * @throws IOException 入出力エラーが発生したとã�?
108             */
109            @Override
110            public void flush() throws IOException {
111                    if(isClosed) {
112    //                      throw new IOException("Cannot flush a closed output stream");
113                            return ;
114                    }
115                    gzipstream.flush();
116            }
117    
118            /**
119             * こã?出力ストリーãƒ?�«æŒ?®šされたバイトを書き込みますã?
120             *
121             * write の汎用規ç´?�§はã€? バイトが
122             * 出力ストリーãƒ?�«書き込まれますã?書き込まれるバイトã?、引数 b の下ä½?8 ビットですã?
123             * b の上ä½?24 ビットã?無視されますã?
124             *
125             * @og.rev 5.1.7.0 (2010/06/01) isClosed == true の場合に Exception でなくã?return にするã€?
126             *
127             * @param       bt      byteãƒ??タ
128             * @throws IOException 入出力エラーが発生したとã�?
129             */
130            @Override
131            public void write(final int bt) throws IOException {
132                    if(isClosed) {
133    //                      throw new IOException("Cannot write to a closed output stream");
134                            return ;
135                    }
136                    gzipstream.write((byte)bt);
137            }
138    
139            /**
140             * æŒ?®šされたバイトé?列からこの出力ストリーãƒ?�« b.length バイトを書き込みますã?
141             *
142             * write(b) の汎用規ç´?�§は、write(b) の効果ã? write(b, 0, b.length) を呼び出ã�?
143             * 場合とまったく同じですã?
144             *
145             * @param       bt      バイトé?åˆ?
146             * @throws IOException 入出力エラーが発生したとã�?
147             */
148            @Override
149            public void write(final byte[] bt) throws IOException {
150                    write(bt, 0, bt.length);
151            }
152    
153            /**
154             * オフセãƒ?ƒˆ off から始まる指定ã?バイトé?列からこの出力ストリーãƒ?�« len バイトを書き込みますã?
155             *
156             * write(b, off, len) の汎用規ç´?�§はã€??åˆ?b å†??ä¸?®šã?バイトが出力ストリーãƒ?�«é ?•ªに
157             * 書き込まれますã?こã?処ç�?�§æœ??に書き込まれるバイトã?要ç´?b[off]、最後に書き込まれる
158             * バイトã?要ç´?b[off+len-1] ですã?
159             *
160             * @og.rev 5.1.7.0 (2010/06/01) isClosed == true の場合に Exception でなくã?return にするã€?
161             *
162             * @param       bt      バイトé?åˆ?
163             * @param       off     オフセãƒ?ƒˆ数
164             * @param       len     書き込みバイト数
165             * @throws IOException 入出力エラーが発生したとã�?
166             */
167            @Override
168            public void write(final byte bt[], final int off, final int len) throws IOException {
169    //              System.out.println("writing...");
170                    if(isClosed) {
171    //                      throw new IOException("Cannot write to a closed output stream");
172                            return ;
173                    }
174                    gzipstream.write(bt, off, len);
175            }
176    
177            /**
178             * すでにストリーãƒ?�Œ閉じられてã�?‚‹かどã�?�‹を返しますã?
179             *
180             * @return      すでにストリーãƒ?�Œ閉じられてã�?‚‹かどã�?�‹
181             */
182            public boolean closed() {
183                    return isClosed;
184            }
185    
186            /**
187             * Checks if a non-blocking write will succeed. If this returns
188             * <code>false</code>, it will cause a callback to
189             * WriteListener#onWritePossible() when the buffer has emptied. If
190             * this method returns <code>false</code> no further data must be written
191             * until the contain calls WriteListener#onWritePossible().
192             *
193             * @og.rev 5.6.8.2 (2013/09/20) 新規追åŠ?Tomcat8 / Servlet 3.1 で追åŠ?�•れた abstract メソãƒ?ƒ‰)
194             *
195             * @return true:書き込み可能/false:不可 (true if data can be written, else false)
196             *
197             * @since Servlet 3.1
198             */
199            //@Override
200            public boolean isReady() { return false; }
201    
202            /**
203             * Sets the WriteListener for this ServletOutputStream and
204             * thereby switches to non-blocking IO. It is only valid to switch to
205             * non-blocking IO within async processing or HTTP upgrade processing.
206             *
207             * @og.rev 5.6.8.2 (2013/09/20) 新規追åŠ?Tomcat8 / Servlet 3.1 で追åŠ?�•れた abstract メソãƒ?ƒ‰)
208             *
209             * @param listener      The non-blocking IO write listener
210             *
211             * @throws IllegalStateException        If this method is called if neither
212             *                                                                      async nor HTTP upgrade is in progress or
213             *                                                                      if the WriteListener has already
214             *                                                                      been set
215             * @throws NullPointerException         If listener is null
216             *
217             * @since Servlet 3.1
218             */
219            //@Override
220            //      public void setWriteListener( final javax.servlet.WriteListener listener ) {
221            //              // 何も実è£?�—なã�??
222            //      }
223    }