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.hayabusa.common.HybsSystem; 019 020import java.util.Locale; 021 022import java.io.File; 023import java.io.IOException; 024import java.io.UnsupportedEncodingException; 025import javax.servlet.ServletRequest; 026import javax.servlet.ServletResponse; 027import javax.servlet.ServletContext; 028import javax.servlet.Filter; 029import javax.servlet.FilterChain; 030import javax.servlet.FilterConfig; 031import javax.servlet.ServletException; 032import javax.servlet.http.HttpServletRequest; 033import javax.servlet.http.HttpServletResponse; 034 035/** 036 * Filter インターフェースを継承した HTMLデモ画面を作成するフィルタクラスです。 037 * web.xml で filter 設定することにより、使用できます。 038 * このフィルターでは、通常の画面アクセスを行うと、指定のフォルダに対して 039 * JSPをHTMLに変換した形で、ファイルをセーブしていきます。このHTMLは、 040 * デモサンプル画面として、使用できます。 041 * 出来る限り、デモ画面として使えるように、画面間リンクや、ボタン制御を 042 * JavaScript を挿入する事で実現しています。 043 * 044 * フィルターに対してweb.xml でパラメータを設定します。 045 * ・saveDir :ファイルをセーブするディレクトリ 046 * 047 * パラメータがない場合は、G:/webapps/作番/filetemp/DIR/ 以下に自動設定されます。 048 * また、ディレクトリが、相対パスの場合は、G:/webapps/作番/ 以下に、絶対パスの 049 * 場合は、そのパスの下に作成されます。 * 050 * 051 * 【WEB-INF/web.xml】 052 * <filter> 053 * <filter-name>FileFilter</filter-name> 054 * <filter-class>org.opengion.hayabusa.filter.FileFilter</filter-class> 055 * <init-param> 056 * <param-name>saveDir</param-name> 057 * <param-value>filetemp/DIR/</param-value> 058 * </init-param> 059 * </filter> 060 * 061 * <filter-mapping> 062 * <filter-name>FileFilter</filter-name> 063 * <url-pattern>/jsp/*</url-pattern> 064 * </filter-mapping> 065 * 066 * @og.group フィルター処理 067 * 068 * @version 4.0 069 * @author Kazuhiko Hasegawa 070 * @since JDK5.0, 071 */ 072public class FileFilter implements Filter { 073 private String saveDir = null; // "G:/webapps/gf/filetemp/DIR/" など 074 075 /** 076 * Filter インターフェースの doFilter メソッド 077 * 078 * Filter クラスの doFilter メソッドはコンテナにより呼び出され、 最後のチェーンにおける 079 * リソースへのクライアントリクエストのために、 毎回リクエスト・レスポンスのペアが、 080 * チェーンを通して渡されます。 このメソッドに渡される FilterChain を利用して、Filter が 081 * リクエストやレスポンスをチェーン内の次のエンティティ(Filter)にリクエストとレスポンスを 082 * 渡す事ができます。 083 * このメソッドの典型的な実装は以下のようなパターンとなるでしょう。 084 * 1. リクエストの検査 085 * 2. オプションとして、入力フィルタリング用にコンテンツもしくはヘッダをフィルタリング 086 * するためにカスタム実装によるリクエストオブジェクトのラップ 087 * 3. オプションとして、出力フィルタリング用にコンテンツもしくはヘッダをフィルタリング 088 * するためにカスタム実装によるレスポンスオブジェクトラップ 089 * 4. 以下の a)、b) のどちらか 090 * a) FileterChain オブジェクト(chain.doFilter()) を利用してチェーンの次のエンティティを呼び出す 091 * b) リクエスト処理を止めるために、リクエスト・レスポンスのペアをフィルタチェーンの次の 092 * エンティティに渡さない 093 * 5. フィルタチェーンの次のエンティティの呼び出した後、直接レスポンスのヘッダをセット 094 * 095 * @param req ServletRequestオブジェクト 096 * @param res ServletResponseオブジェクト 097 * @param chain FilterChainオブジェクト 098 * @throws IOException 入出力エラーが発生したとき 099 * @throws ServletException サーブレット関係のエラーが発生した場合、throw されます。 100 */ 101 public void doFilter( final ServletRequest req, 102 final ServletResponse res, 103 final FilterChain chain ) 104 throws IOException, ServletException { 105 if(req instanceof HttpServletRequest && res instanceof HttpServletResponse) { 106 HttpServletRequest request = (HttpServletRequest) req; 107 HttpServletResponse response = (HttpServletResponse) res; 108 109 try { 110 request.setCharacterEncoding( "UTF-8" ); 111 } 112 catch ( UnsupportedEncodingException ex ) { 113 throw new RuntimeException( ex ); 114 } 115 116 String filename = makeFileName( request ); 117 if( filename != null ) { 118 FileResponseWrapper wrappedResponse = new FileResponseWrapper(response,filename); 119 chain.doFilter(req, wrappedResponse); 120 wrappedResponse.finishResponse(); 121 } 122 else { 123 chain.doFilter(req, res); 124 } 125 } 126 } 127 128 /** 129 * フィルターの初期処理メソッドです。 130 * 131 * フィルターに対してweb.xml で初期パラメータを設定します。 132 * ・startTime:停止開始時刻 133 * ・stopTime :停止終了時刻 134 * ・filename :停止時メッセージ表示ファイル名 135 * 136 * @og.rev 5.7.3.2 (2014/02/28) Tomcat8 対応。getRealPath( "/" ) の互換性のための修正。 137 * 138 * @param filterConfig FilterConfigオブジェクト 139 */ 140 public void init(final FilterConfig filterConfig) { 141 ServletContext context = filterConfig.getServletContext(); 142// String realPath = context.getRealPath( "/" ); 143 String realPath = context.getRealPath( "" ) + File.separator; // 5.7.3.2 (2014/02/28) Tomcat8 対応 144 145 String dir = filterConfig.getInitParameter("saveDir"); 146 if( dir != null && dir.length() > 1 ) { 147 dir = dir.replace( '\\','/' ); 148 if( dir.charAt(0) == '/' || dir.charAt(1) == ':' ) { 149 saveDir = dir; 150 } 151 else { 152 saveDir = realPath + dir ; 153 } 154 155 if( dir.charAt(dir.length()-1) != '/' ) { 156 saveDir = saveDir + "/" ; 157 } 158 } 159 else { 160 saveDir = realPath + "filetemp/DIR/" ; 161 } 162 } 163 164 /** 165 * Filter インターフェースの destroy メソッド (何もしません)。 166 * 167 * サービス状態を終えた事を Filter に伝えるために Web コンテナが呼び出します。 168 * Filter の doFilter メソッドが終了したか、タイムアウトに達した全てのスレッドにおいて、 169 * このメソッドを一度だけ呼び出されます。 Web コンテナがこのメソッドを呼び出した後は、 170 * Filter のこのインスタンスにおいて二度と doFilter メソッドを呼び出す事はありません。 171 * 172 * このメソッドは、フィルタに保持されている(例えば、メモリ、ファイルハンドル、スレッド) 173 * 様々なリソースを開放する機会を与え、 あらゆる永続性の状態が、メモリ上における Filter 174 * の現在の状態と同期しているように注意してください。 175 */ 176 public void destroy() { 177 // noop 178 } 179 180 /** 181 * セーブするファイル名を、リクエスト情報より取得します。 182 * 183 * リクエストされたファイル(.jsp)を、HTMLファイル(.htm)にするだけでなく、 184 * 呼び出されたときの command を元に、ファイル名を作成します。 185 * command="NEW" + forward.jsp ⇒ "forward.htm" 186 * command="RENEW" + forward.jsp ⇒ "renew.htm" 187 * command="日本語名+ forward.jsp ⇒ "コマンド名.htm" 188 * command="日本語名+ update.jsp ⇒ "コマンド名.htm" 189 * command="NEW" + index.jsp ⇒ "indexNW.htm" 190 * command="RENEW" + index.jsp ⇒ "indexRNW.htm" 191 * command="NEW" + query.jsp ⇒ "queryNW.htm" 192 * command="NEW" + resultXX.jsp ⇒ "forwardXX.htm" 5.6.3.4 (2013/04/26) result.jsp にフレームを使うパターン(3ペイン) 193 * matrixMenu対応 194 * URI分離 URI分離 request取出 195 * @ gamenId="jsp" + index.jsp + GAMENID=XXXX ⇒ saveDir + "jsp/indexXXXX.htm" Matrixメニューからの画面呼出し。 196 * A gamenId="jsp" + result.jsp + GAMENID=XXXX ⇒ saveDir + "XXXX/index.htm" 画面QUERYのヘッダーメニュー 197 * B gamenId="jsp" + index.jsp + group=YYYY ⇒ saveDir + "jsp/indexYYYY.htm" (存在しないはず) 198 * C gamenId="menu" + multiMenu.jsp + GAMENID=XXXX ⇒ saveDir + "jsp/menuXXXX.htm" (存在しないはず) 199 * D gamenId="menu" + multiMenu.jsp + group=YYYY ⇒ saveDir + "jsp/menuYYYY.htm" 通常メニューのグループ選択 200 * E gamenId="menu" + matrixMenu.jsp + group=YYYY ⇒ saveDir + "menu/matrixMenuYYYY.htm" Matrixメニューのグループ選択 201 * その他 xxxx.jsp ⇒ "xxxx.htm" 202 * 203 * このメソッドは、フィルタに保持されている(例えば、メモリ、ファイルハンドル、スレッド) 204 * 様々なリソースを開放する機会を与え、 あらゆる永続性の状態が、メモリ上における Filter 205 * の現在の状態と同期しているように注意してください。 206 * 207 * @og.rev 4.0.0.0 (2007/11/28) メソッドの戻り値をチェックします。 208 * @og.rev 4.3.3.0 (2008/10/01) Matrixメニュー対応 209 * @og.rev 5.5.2.5 (2012/05/21) update.jsp に出力されるファイルを、コマンド名.htm に出力するように機能追加 210 * @og.rev 5.6.3.4 (2013/04/26) 5.6.3.4 (2013/04/26) command="NEW" + resultXX.jsp ⇒ "forwardXX.htm"。 result.jsp にフレームを使うパターン(3ペイン) 211 * @og.rev 5.6.4.2 (2013/05/17) Matrixメニュー buttonRequest 廃止対応 212 * 213 * @param request ServletRequestオブジェクト 214 * 215 * @return セーブするファイル名 216 */ 217 private String makeFileName( final ServletRequest request ) { 218 HttpServletRequest myReq = (HttpServletRequest) request; 219 String requestURI = myReq.getRequestURI(); 220 221 int index2 = requestURI.lastIndexOf( '/' ); 222 String jspID = requestURI.substring( index2+1 ); 223 int index1 = requestURI.lastIndexOf( '/',index2-1 ); 224 String gamenId = requestURI.substring( index1+1,index2 ); 225 226 String file = null; 227 228 if( jspID != null && jspID.endsWith( ".jsp" ) ) { 229 String cmd = request.getParameter( "command" ); 230 if( cmd != null && jspID.equals( "forward.jsp" ) ) { 231 if( "NEW".equals( cmd ) ) { file = "forward.htm"; } 232 else if( "RENEW".equals( cmd ) || "REVIEW".equals( cmd ) ) { file = "renew.htm"; } 233 else { 234 String xferVal = request.getParameter( HybsSystem.NO_XFER_KEY + cmd ); 235 // 5.5.2.5 (2012/05/21) update.jsp に出力されるファイルを、コマンド名.htm に出力するように機能追加 236 if( "update.jsp".equals( xferVal ) ) { 237 file = cmd + ".htm" ; 238 } 239 else if( xferVal != null && xferVal.endsWith( "jsp" ) ) { 240 file = xferVal.toLowerCase(Locale.JAPAN).replace( "jsp","htm" ); 241 } 242 else { 243 String xferCmd = request.getParameter( HybsSystem.NO_XFER_KEY + cmd + "CMD" ); 244 if( xferCmd != null ) { 245 file = xferCmd.toLowerCase(Locale.JAPAN) + ".htm"; 246 } 247 else { 248 file = cmd.toLowerCase(Locale.JAPAN) + ".htm"; 249 } 250 } 251 } 252 } 253 else if( "index.jsp".equals( jspID ) && ( "RENEW".equals( cmd ) || "REVIEW".equals( cmd ) ) ) { 254 file = "indexRNW.htm"; 255 } 256 else if( "index.jsp".equals( jspID ) && "NEW".equals( cmd ) ) { 257 file = "indexNW.htm"; 258 } 259 else if( "query.jsp".equals( jspID ) && "NEW".equals( cmd ) ) { 260 file = "queryNW.htm"; 261 } 262 // 5.6.3.4 (2013/04/26) command="NEW" + resultXX.jsp ⇒ "forwardXX.htm"。 result.jsp にフレームを使うパターン(3ペイン) 263// else if( jspID.startsWith( "result" ) && jspID.endsWith( ".jsp" ) && "NEW".equals( cmd ) ) { 264 else if( jspID.startsWith( "result" ) && "NEW".equals( cmd ) ) { 265 file = "forward" + jspID.substring( 6,jspID.length()-4 ) + ".htm" ; 266 } 267 // 5.6.4.2 (2013/05/17) fileDownload.jsp の対応 268 else if( "fileDownload.jsp".equals( jspID ) ) { 269 gamenId = request.getParameter( "GAMENID" ); // gamenId(元はフォルダを抽出)をリクエスト変数から取得する。 270 file = request.getParameter( "filename" ); // 日本語ファイル名で抽出する場合。 271 file = "fileDownload:" + file ; // ただし、セーブ時は、UnicodeLittle なので、"fileDownload:" でマーカーする。 272 } 273 else { 274 file = jspID.substring( 0,jspID.length()-4 ) + ".htm" ; 275 } 276 277 // 5.6.4.2 (2013/05/17) Matrixメニュー 対応 278 // URI分離 URI分離 request取出 279 // @ gamenId="jsp" + index.jsp + GAMENID=XXXX ⇒ saveDir + "jsp/indexXXXX.htm" Matrixメニューからの画面呼出し。 280 // A gamenId="jsp" + result.jsp + GAMENID=XXXX ⇒ saveDir + "jsp/indexXXXX.htm" 画面QUERYのヘッダーメニュー 281 // B gamenId="menu" + multiMenu.jsp + group=YYYY ⇒ saveDir + "menu/menuYYYY.htm" 通常メニューのグループ選択 282 // C gamenId="menu" + matrixMenu.jsp + group=YYYY ⇒ saveDir + "menu/matrixMenuYYYY.htm" Matrixメニューのグループ選択 283 String guiKey = request.getParameter( "GAMENID" ); 284 String group = request.getParameter( "group" ); 285 286 if( "jsp".equals( gamenId ) && guiKey != null ) { 287 if( "index.jsp".equals( jspID ) || "result.jsp".equals( jspID ) ) { 288 file = "jsp/index" + guiKey + ".htm"; // @,A 289 } 290 } 291 else if( group != null ) { 292 if( "multiMenu.jsp".equals( jspID ) ) { 293 file = gamenId + "/menu" + group + ".htm"; // B 294 } 295 else if( "matrixMenu.jsp".equals( jspID ) ) { 296 file = gamenId + "/matrixMenu" + group + ".htm"; // C 297 } 298 gamenId = "jsp" ; // トリッキー 299 } 300 301 // 5.6.4.2 (2013/05/17) Matrixメニュー buttonRequest 廃止 302// // 4.3.3.0 (2008/10/01) Matrixメニュー対応 303// // GAMENID=XXXX&buttonRequest=true + index.jsp ⇒ "jsp/indexXXXX.htm" 304// // GAMENID=XXXX&buttonRequest=true + multiMenu.jsp ⇒ "jsp/menuXXXX.htm" 305// // group=YYYY&buttonRequest=true + matrixMenu.jsp ⇒ "menu/matrixMenuYYYY.htm" 306// String guiKey = request.getParameter( "GAMENID" ); 307// String btnReq = request.getParameter( "buttonRequest" ); 308// if( "true".equals( btnReq ) ) { 309// if( guiKey != null ) { 310// if( "index.jsp".equals( jspID ) ) { 311// file = "jsp/index" + guiKey + ".htm"; 312// } 313// else if( "multiMenu.jsp".equals( jspID ) ) { 314// file = "jsp/menu" + guiKey + ".htm"; 315// gamenId = "jsp" ; // トリッキー 316// } 317// } 318// else { 319// 320// String group = request.getParameter( "group" ); 321// if( group != null ) { 322// if( "matrixMenu.jsp".equals( jspID ) ) { 323// file = "menu/matrixMenu" + group + ".htm"; 324// gamenId = "jsp" ; // トリッキー 325// } 326// } 327// } 328// } 329 330// int index1 = requestURI.lastIndexOf( '/',index2-1 ); 331// String gamenId = requestURI.substring( index1+1,index2 ); 332 333 if( "jsp".equals( gamenId ) ) { file = saveDir + file; } 334 else { file = saveDir + gamenId + "/" + file; } 335 336// File fl = new File( saveDir + gamenId ); 337// if( !fl.exists() && !fl.mkdirs() ) { 338 File fl = new File( file ).getParentFile(); 339 if( fl != null && !fl.exists() && !fl.mkdirs() ) { 340 String errMsg = "所定のフォルダが作成できませんでした。[" + fl + "]" ; 341 throw new RuntimeException( errMsg ); 342 } 343 } 344 345 return file; 346 } 347}