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