    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.FileUtil;
    019import org.opengion.fukurou.util.Closer;
    020
    021import java.io.PrintWriter;
    022import java.io.BufferedOutputStream;
    023import java.io.FileOutputStream;
    024import java.io.IOException;
    025import java.io.File;
    026import java.io.ByteArrayOutputStream;
    027import javax.servlet.ServletOutputStream;
    028import javax.servlet.ServletResponse;
    029
    030/**
    031 * FileFilter で使用する、File圧縮するServletOutputStreamクラスです。
    032 *
    033 * @og.group フィルター処理
    034 *
    035 * @version  4.0
    036 * @author   Kazuhiko Hasegawa
    037 * @since    JDK5.0,
    038 */
    039public class FileResponseStream extends ServletOutputStream {
    040        /** 内部出力ストリーム */
    041        protected ByteArrayOutputStream filestream = null;
    042        /** クローズ判定 */
    043        protected boolean isClosed = false;
    044        /** レスポンスオブジェクト */
    045//      protected ServletResponse response = null;              // 5.5.2.6 (2012/05/25)
    046        /** サーブレット出力ストリーム */
    047        protected ServletOutputStream output = null;
    048
    049        private final String filename ;
    050
    051        /**
    052         * コンストラクター
    053         *
    054         * @param       response        レスポンス
    055         * @param       filename        ファイル名
    056         * @throws IOException 入出力エラーが発生したとき
    057         */
    058        public FileResponseStream( final ServletResponse response,final String filename ) throws IOException {
    059                // 4.3.4.4 (2009/01/01)
    060//              super();
    061                this.filename = filename;
    062                isClosed = false;
    063//              this.response = response;               // 5.5.2.6 (2012/05/25)
    064                this.output = response.getOutputStream();
    065                filestream = new ByteArrayOutputStream();
    066        }
    067
    068        /**
    069         * このストリームを閉じ、このストリームに関連するすべてのシステムリソースを解放します。
    070         *
    071         * close の汎用規約では、close は出力ストリームを閉じます。閉じられたストリームは
    072         * 出力処理を実行できません。また、それを開き直すことはできません。
    073         *
    074         * @og.rev 5.6.4.2 (2013/05/17) fileDownload のエンコードは、UTF-8 ではなく、UnicodeLittle でセーブする。
    075         *
    076         * @throws IOException 入出力エラーが発生したとき
    077         */
    078        @Override
    079        public void close() throws IOException {
    080                if(isClosed) {
    081//                      System.out.println( "already been closed !" );
    082//                      throw new IOException("This output stream has already been closed");
    083                        return ;
    084                }
    085                try {
    086                        filestream.flush();
    087
    088                        // 5.6.4.2 (2013/05/17) ファイル名が fileDownload で始まる場合は、Streamのままセーブする。
    089                        if( filename.indexOf( "fileDownload:" ) >= 0 ) {
    090                                BufferedOutputStream toStream = new BufferedOutputStream( new FileOutputStream( filename.replace( "fileDownload:","" ) ) );
    091                                filestream.writeTo( toStream );
    092                                Closer.ioClose( toStream );
    093                        }
    094                        else {
    095                                String msg = filestream.toString( "UTF-8" );
    096                                FileResponseTransform trans = new FileResponseTransform();
    097                                msg = trans.replace( filename,msg );
    098
    099                                PrintWriter writer = FileUtil.getPrintWriter( new File( filename ), "UTF-8" );
    100                                writer.print( msg );
    101                                Closer.ioClose( writer );
    102                        }
    103                        System.out.println( filename + " Saved" );
    104
    105                        output.flush();
    106                }
    107                catch( Throwable th ) {
    108                        System.out.println( filename + " Error! " + th );
    109                }
    110                finally {
    111                        isClosed = true;
    112                        Closer.ioClose( filestream );
    113                        Closer.ioClose( output );
    114                }
    115        }
    116
    117        /**
    118         * この出力ストリームをフラッシュし、バッファに入っている出力バイトをすべて強制的書き込みますに。
    119         *
    120         * flush の汎用規約では、それまでに書き込まれたバイトが出力ストリームの
    121         * 実装によってバッファに入れられている場合に flush を呼び出すと、それらのバイトは
    122         * ただちにその目的の転送先に書き込まれます。
    123         *
    124         * @og.rev 5.1.7.0 (2010/06/01) isClosed == true の場合に Exception でなく、return にする。
    125         * @throws IOException 入出力エラーが発生したとき
    126         */
    127        @Override
    128        public void flush() throws IOException {
    129                if(isClosed) {
    130//                      throw new IOException("Cannot flush a closed output stream");
    131                        return ;
    132                }
    133                filestream.flush();
    134                output.flush();
    135        }
    136
    137        /**
    138         * この出力ストリームに指定されたバイトを書き込みます。
    139         *
    140         * write の汎用規約では、1 バイトが
    141         * 出力ストリームに書き込まれます。書き込まれるバイトは、引数 b の下位 8 ビットです。
    142         * b の上位 24 ビットは無視されます。
    143         *
    144         * @og.rev 5.1.7.0 (2010/06/01) isClosed == true の場合に Exception でなく、return にする。
    145         *
    146         * @param       bt      byteデータ
    147         * @throws IOException 入出力エラーが発生したとき
    148         */
    149        @Override
    150        public void write(final int bt) throws IOException {
    151                if(isClosed) {
    152//                      throw new IOException("Cannot write to a closed output stream");
    153                        return ;
    154                }
    155                filestream.write((byte)bt);
    156                output.write((byte)bt);
    157        }
    158
    159        /**
    160         * 指定されたバイト配列からこの出力ストリームに b.length バイトを書き込みます。
    161         *
    162         * write(b) の汎用規約では、write(b) の効果は write(b, 0, b.length) を呼び出す
    163         * 場合とまったく同じです。
    164         *
    165         * @param       bt      バイト配列
    166         * @throws IOException 入出力エラーが発生したとき
    167         */
    168        @Override
    169        public void write(final byte[] bt) throws IOException {
    170                write(bt, 0, bt.length);
    171        }
    172
    173        /**
    174         * オフセット off から始まる指定のバイト配列からこの出力ストリームに len バイトを書き込みます。
    175         *
    176         * write(b, off, len) の汎用規約では、配列 b 内の一定のバイトが出力ストリームに順番に
    177         * 書き込まれます。この処理で最初に書き込まれるバイトは要素 b[off]、最後に書き込まれる
    178         * バイトは要素 b[off+len-1] です。
    179         *
    180         * @og.rev 5.1.7.0 (2010/06/01) isClosed == true の場合に Exception でなく、return にする。
    181         *
    182         * @param       bt      バイト配列
    183         * @param       off     オフセット数
    184         * @param       len     書き込みバイト数
    185         * @throws IOException 入出力エラーが発生したとき
    186         */
    187        @Override
    188        public void write(final byte bt[], final int off, final int len) throws IOException {
    189                if(isClosed) {
    190//                      throw new IOException("Cannot write to a closed output stream");
    191                        return ;
    192                }
    193                output.write(bt, off, len);
    194                filestream.write(bt, off, len);
    195        }
    196
    197        /**
    198         * すでにストリームが閉じられているかどうかを返します。
    199         *
    200         * @return      すでにストリームが閉じられているかどうか
    201         */
    202        public boolean closed() {
    203                return isClosed;
    204        }
    205
    206        /**
    207         * Checks if a non-blocking write will succeed. If this returns
    208         * <code>false</code>, it will cause a callback to
    209         * WriteListener#onWritePossible() when the buffer has emptied. If
    210         * this method returns <code>false</code> no further data must be written
    211         * until the contain calls WriteListener#onWritePossible().
    212         *
    213         * @og.rev 5.6.8.2 (2013/09/20) 新規追加(Tomcat8 / Servlet 3.1 で追加された abstract メソッド)
    214         *
    215         * @return true:書き込み可能/false:不可 (true if data can be written, else false)
    216         *
    217         * @since Servlet 3.1
    218         */
    219        //@Override
    220        public boolean isReady() { return false; }
    221
    222        /**
    223         * Sets the WriteListener for this ServletOutputStream and
    224         * thereby switches to non-blocking IO. It is only valid to switch to
    225         * non-blocking IO within async processing or HTTP upgrade processing.
    226         *
    227         * @og.rev 5.6.8.2 (2013/09/20) 新規追加(Tomcat8 / Servlet 3.1 で追加された abstract メソッド)
    228         *
    229         * @param listener      The non-blocking IO write listener
    230         *
    231         * @throws IllegalStateException        If this method is called if neither
    232         *                                                                      async nor HTTP upgrade is in progress or
    233         *                                                                      if the WriteListener has already
    234         *                                                                      been set
    235         * @throws NullPointerException         If listener is null
    236         *
    237         * @since Servlet 3.1
    238         */
    239        //@Override
    240        //      public void setWriteListener( final javax.servlet.WriteListener listener ) {
    241        //              // 何も実装しない。
    242        //      }
    243}