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 isClosed = false; 057 this.response = response; 058 this.output = response.getOutputStream(); 059 baos = new ByteArrayOutputStream(); 060 gzipstream = new GZIPOutputStream(baos); 061 } 062 063 /** 064 * このストリームを閉じ、このストリームに関連するすべてのシステムリソースを解放します。 065 * 066 * close の汎用規約では、close は出力ストリームを閉じます。閉じられたストリームは 067 * 出力処理を実行できません。また、それを開き直すことはできません。 068 * 069 * @og.rev 5.1.7.0 (2010/06/01) isClosed == true の場合に Exception でなく、return にする。 070 * 071 * @throws IOException 入出力エラーが発生したとき 072 */ 073 @Override 074 public void close() throws IOException { 075 if(isClosed) { 076 return ; 077 } 078 try { 079 gzipstream.finish(); 080 081 byte[] bytes = baos.toByteArray(); 082 083 response.setContentLength( bytes.length ); 084 response.addHeader("Content-Encoding", "gzip"); 085 output.write(bytes); 086 output.flush(); 087 } 088 finally { 089 isClosed = true; 090 Closer.ioClose( output ); 091 } 092 } 093 094 /** 095 * この出力ストリームをフラッシュし、バッファに入っている出力バイトをすべて強制的書き込みますに。 096 * 097 * flush の汎用規約では、それまでに書き込まれたバイトが出力ストリームの 098 * 実装によってバッファに入れられている場合に flush を呼び出すと、それらのバイトは 099 * ただちにその目的の転送先に書き込まれます。 100 * 101 * @og.rev 5.1.7.0 (2010/06/01) isClosed == true の場合に Exception でなく、return にする。 102 * 103 * @throws IOException 入出力エラーが発生したとき 104 */ 105 @Override 106 public void flush() throws IOException { 107 if(isClosed) { 108 return ; 109 } 110 gzipstream.flush(); 111 } 112 113 /** 114 * この出力ストリームに指定されたバイトを書き込みます。 115 * 116 * write の汎用規約では、1 バイトが 117 * 出力ストリームに書き込まれます。書き込まれるバイトは、引数 b の下位 8 ビットです。 118 * b の上位 24 ビットは無視されます。 119 * 120 * @og.rev 5.1.7.0 (2010/06/01) isClosed == true の場合に Exception でなく、return にする。 121 * 122 * @param bt byteデータ 123 * @throws IOException 入出力エラーが発生したとき 124 */ 125 @Override 126 public void write(final int bt) throws IOException { 127 if(isClosed) { 128 return ; 129 } 130 gzipstream.write((byte)bt); 131 } 132 133 /** 134 * 指定されたバイト配列からこの出力ストリームに b.length バイトを書き込みます。 135 * 136 * write(b) の汎用規約では、write(b) の効果は write(b, 0, b.length) を呼び出す 137 * 場合とまったく同じです。 138 * 139 * @param bt バイト配列 140 * @throws IOException 入出力エラーが発生したとき 141 */ 142 @Override 143 public void write(final byte[] bt) throws IOException { 144 write(bt, 0, bt.length); 145 } 146 147 /** 148 * オフセット off から始まる指定のバイト配列からこの出力ストリームに len バイトを書き込みます。 149 * 150 * write(b, off, len) の汎用規約では、配列 b 内の一定のバイトが出力ストリームに順番に 151 * 書き込まれます。この処理で最初に書き込まれるバイトは要素 b[off]、最後に書き込まれる 152 * バイトは要素 b[off+len-1] です。 153 * 154 * @og.rev 5.1.7.0 (2010/06/01) isClosed == true の場合に Exception でなく、return にする。 155 * 156 * @param bt バイト配列 157 * @param off オフセット数 158 * @param len 書き込みバイト数 159 * @throws IOException 入出力エラーが発生したとき 160 */ 161 @Override 162 public void write(final byte bt[], final int off, final int len) throws IOException { 163 if(isClosed) { 164 return ; 165 } 166 gzipstream.write(bt, off, len); 167 } 168 169 /** 170 * すでにストリームが閉じられているかどうかを返します。 171 * 172 * @return すでにストリームが閉じられているかどうか 173 */ 174 public boolean closed() { 175 return isClosed; 176 } 177 178 /** 179 * Checks if a non-blocking write will succeed. If this returns 180 * <code>false</code>, it will cause a callback to 181 * WriteListener#onWritePossible() when the buffer has emptied. If 182 * this method returns <code>false</code> no further data must be written 183 * until the contain calls WriteListener#onWritePossible(). 184 * 185 * @og.rev 5.6.8.2 (2013/09/20) 新規追加(Tomcat8 / Servlet 3.1 で追加された abstract メソッド) 186 * 187 * @return true:書き込み可能/false:不可 (true if data can be written, else false) 188 * 189 * @since Servlet 3.1 190 */ 191 @Override 192 public boolean isReady() { return false; } 193 194 /** 195 * Sets the WriteListener for this ServletOutputStream and 196 * thereby switches to non-blocking IO. It is only valid to switch to 197 * non-blocking IO within async processing or HTTP upgrade processing. 198 * 199 * @og.rev 5.6.8.2 (2013/09/20) 新規追加(Tomcat8 / Servlet 3.1 で追加された abstract メソッド) 200 * 201 * @param listener The non-blocking IO write listener 202 * 203 * @throws IllegalStateException If this method is called if neither 204 * async nor HTTP upgrade is in progress or 205 * if the WriteListener has already 206 * been set 207 * @throws NullPointerException If listener is null 208 * 209 * @since Servlet 3.1 210 */ 211 @Override 212 public void setWriteListener( final javax.servlet.WriteListener listener ) { 213 // 何も実装しない。 214 } 215}