    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 */
    016package org.opengion.hayabusa.filter;
    017
    018import org.opengion.fukurou.util.Closer;
    019
    020import java.io.ByteArrayOutputStream;
    021import java.io.IOException;
    022
    023import java.util.zip.GZIPOutputStream;
    024import javax.servlet.ServletOutputStream;
    025import 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 */
    036public 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 の汎用規約では、1 バイトが
    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}