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.StringUtil; 019import org.opengion.fukurou.util.FileUtil; 020 021import java.util.regex.Pattern ; 022import java.util.regex.Matcher ; 023import java.util.Set ; 024import java.util.HashSet ; 025import java.io.File; 026 027/** 028 * FileFilter で使用する、紙芝居用HTMLファイル作成時に内部文字列を変換するクラスです。 029 * 030 * @og.group フィルター処理 031 * 032 * @version 4.0 033 * @author Kazuhiko Hasegawa 034 * @since JDK5.0, 035 */ 036public class FileResponseTransform { 037 038 // 5.6.4.2 (2013/05/17) JFreeChart の画像ファイル(ChartTempフォルダ) のコピー関係の固定値 039 private static final String CHART_KEY = "/ChartTemp/" ; 040 private static final int KEY_LEN = CHART_KEY.length(); 041 042 private static final Set<String> TARGET_CHANGE_SET = new HashSet<>(); 043 044 private static final ChangeData[] CHG_DATA = new ChangeData[] { // 6.4.1.1 (2016/01/16) data → CHG_DATA refactoring 045 new ChangeData( null , "\"/[^/]*/jsp/" ,"\"../" ) // 5.5.7.2 (2012/10/09) マッチ条件を広げる 046 ,new ChangeData( null , "'/[^/]*/jsp/" ,"'../" ) // 5.5.7.2 (2012/10/09) マッチ条件を広げる 047 ,new ChangeData( null , "\\(/[^/]*/jsp/" ,"(../" ) // 6.4.3.2 (2016/02/19) マッチ条件を広げる 048 ,new ChangeData( null , "=\"/[^/]*/[^/]*/ChartTemp/","=\"../ChartTemp/" ) // 5.5.2.5 (2012/05/21) JfreeChart関係の画像のアドレス変換 049 ,new ChangeData( null , "='/[^/]*/[^/]*/ChartTemp/" ,"='../ChartTemp/" ) // 5.5.2.5 (2012/05/21) JfreeChart関係の画像のアドレス変換 050 ,new ChangeData( null , "=\"/[^/]*/help/" ,"=\"../help/" ) // 5.5.2.5 (2012/05/21) help関係の画像のアドレス変換 051 ,new ChangeData( null , "='/[^/]*/help/" ,"='../help/" ) // 5.5.2.5 (2012/05/21) help関係の画像のアドレス変換 052 ,new ChangeData( null , "\\.jsp" ,".htm" ) 053 ,new ChangeData( "query.htm" , "action=\"result" ,"action=\"forward" ) // 6.2.5.0 (2015/06/05) GMIS V6 対応(3ペイン対応) 054 ,new ChangeData( "forward.htm" , "frame src=\"result" ,"frame src=\"forward" ) // 5.6.3.4 (2013/04/26) forward.htm にフレームを使うパターン(3ペイン) 055 ,new ChangeData( "reset.htm" , "frame src=\"result" ,"frame src=\"forward" ) // 5.6.4.2 (2013/05/17) reset.htm で、フレームを使うパターン(3ペイン) 056 ,new ChangeData( "index.htm" , "frame src=\"forward.htm" ,"frame src=\"../common/dummy.html" ) 057 ,new ChangeData( "index.htm" , "frame src=\"entry.htm" ,"frame src=\"../common/dummy.html" ) // 5.6.3.4 (2013/04/26) ENTRY系の特殊対応 058 ,new ChangeData( "indexRNW.htm" , "frame src=\"forward.htm" ,"frame src=\"renew.htm" ) 059 ,new ChangeData( "indexNW.htm" , "frame src=\"query.htm" ,"frame src=\"queryNW.htm" ) 060 ,new ChangeData( "indexNW.htm" , "frame src=\"entry.htm" ,"frame src=\"../common/dummy.html" ) // 5.6.3.4 (2013/04/26) ENTRY系の特殊対応 061 ,new ChangeData( "entry" , "<input[^>]*history.back[^>]*>" ,"" ) // 6.3.8.0 (2015/09/11) hiistory.back() のタグ削除 の対象を、entry を含むに変更 062 ,new ChangeData( null , "onSubmit=\"return oneClick\\(\\);\"","onSubmit=\"return false;\"" ) // 5.5.7.2 (2012/10/09) 変更は、すべて行う。 063 ,new ChangeData( null , "onSubmit=\"\"" ,"onSubmit=\"return false;\"" ) // 5.6.3.4 (2013/04/26) onSubmit 引数のないケースへの対応 064 ,new ChangeData( null , "src=\"\\.\\./common/option/ajaxSubmit\\.js\\?v=[^\"]+\"","" ) // 5.6.3.4 (2013/04/26) ajaxSubmit.js を削除 065 // 4.3.3.0 (2008/10/01) 戻るリンクの対応 066 ,new ChangeData( "queryNW.htm" ,"=\"http://.*jsp/+?" ,"=\"../" ) 067 ,new ChangeData( "queryNW.htm" ,"\"query.htm?" ,"\"querNWy.htm?" ) // 6.4.2.1 (2016/02/05) クリアボタンのとび先 068 ,new ChangeData( "query.htm" ,"renew\\('query.htm'" ,"renew\\('queryNW.htm'" ) // 5.6.4.2 (2013/05/17) renew('query.htm' 変換 069 // 漢字のボタンでは、後ろにショートカット文字が入る為、前方一致で挿入する。 070 // ,new ChangeData( "forward.htm","value=\"追加","onClick=\"location.href='insert.htm'\" value=\"追加" ) 071 // ,new ChangeData( "forward.htm","value=\"複写","onClick=\"location.href='copy.htm'\" value=\"複写" ) 072 // ,new ChangeData( "forward.htm","value=\"変更","onClick=\"location.href='modify.htm'\" value=\"変更" ) 073 // ,new ChangeData( "forward.htm","value=\"削除","onClick=\"location.href='delete.htm'\" value=\"削除" ) 074 // ,new ChangeData( "query.htm","index.htm\\?command=RENEW" ,"indexRNW.htm?command=RENEW" ) 075 // ,new ChangeData( null ,"index.htm\\?command=NEW" ,"indexNW.htm?command=NEW" ) 076 ,new IndexMatrixMenuData() // 4.3.3.0 (2008/10/01) マトリクスメニュー対応 077 ,new IndexChangeData() 078 ,new HrefChangeData() 079 ,new NoTranHrefChangeData() // 5.6.3.4 (2013/04/26) entry.htm に "noTransitionUrl" が存在するときの処理。 080 ,new FileDownloadChangeData() // 5.6.4.2 (2013/05/17) fileDownload.htm 対応 081 }; 082 083 /** 084 * デフォルトコンストラクター 085 * 086 * @og.rev 6.4.2.0 (2016/01/29) PMD refactoring. Each class should declare at least one constructor. 087 */ 088 public FileResponseTransform() { super(); } // これも、自動的に呼ばれるが、空のメソッドを作成すると警告されるので、明示的にしておきます。 089 090 /** 091 * 変換を行います。 092 * 実際には、各内部クラスのメソッドで処理を行います。 093 * 094 * @og.rev 5.6.4.2 (2013/05/17) JFreeChart の画像ファイル(ChartTempフォルダ) のコピー 095 * 096 * @param file 対象ファイル名 097 * @param inStr 対象データ 098 * 099 * @return 変換後データ 100 */ 101 public String replace( final String file,final String inStr ) { 102 String rtnStr = inStr; 103 104 // query 画面で、登録コマンドが発行された場合の特殊処理 105 if( file.indexOf( "query.htm" ) >= 0 && inStr.indexOf( "name=\"command\" value=\"登録" ) >= 0 ) { 106 rtnStr = inStr.replace( "forward.jsp","entry.htm" ); 107 } 108 109 // 5.6.4.2 (2013/05/17) JFreeChart の画像ファイル(ChartTempフォルダ) のコピー 110 if( inStr.indexOf( "/ChartTemp/" ) >= 0 ) { 111 chartTempFileCopy( file,inStr ); 112 } 113 114 for( int i=0; i<CHG_DATA.length; i++ ) { 115 rtnStr = CHG_DATA[i].replace( file,rtnStr ); 116 } 117 return rtnStr; 118 } 119 120 /** 121 * JFreeChart の画像ファイル(ChartTempフォルダ) のコピーを行います。 122 * これは、Tomcatを停止させずに、ChartTempフォルダ を人手てコピーする予定でしたが、 123 * 万一、停止させると、ファイルが自動削除されるため、自動コピー機能を入れておきます。 124 * 125 * ここの処理は、対象データ(inStr) の文字列変換ではなく、画像ファイルを見つけて、 126 * コピーするという処理を行います。非常に特殊な処理です。 127 * 128 * @og.rev 5.6.4.2 (2013/05/17) 新規追加 129 * 130 * @param file 対象ファイル名 131 * @param inStr 対象データ 132 */ 133 private void chartTempFileCopy( final String file,final String inStr ) { 134 // 以下、決め打ちします。本当は saveDir や、ChartTemp をパラメータから取得すべき 135 // 大前提として、fromDir = filetemp/ChartTemp/ 136 // toDir = filetemp/DIR/ChartTemp/ 137 138 final int adrs = file.indexOf( "filetemp/DIR" ); // jsp ファイルの出力先なので、DIR を含んでいます。 139 final File toDir = new File( file.substring( 0,adrs ) + "filetemp/DIR/ChartTemp/" ); 140 141 // コピー先ディレクトリが存在しなければ・・・ 142 // 6.0.0.1 (2014/04/25) These nested if statements could be combined 143 if( !toDir.exists() && !toDir.mkdirs() ) { 144 System.err.println( toDir + " の ディレクトリ作成に失敗しました。" ); 145 return ; 146 } 147 148 // 6.4.1.1 (2016/01/16) PMD refactoring. Avoid declaring a variable if it is unreferenced before a possible exit point. 149 final File fromDir = new File( file.substring( 0,adrs ) + "filetemp/ChartTemp/" ); 150 // 画像ファイル名を求めます。 151 int st = inStr.indexOf( CHART_KEY ) ; 152 while( st >= 0 ) { 153 final int ed = inStr.indexOf( ".png" ,st + KEY_LEN ) ; // 検索開始位置は、CHART_KEYの発見場所+文字数 154 final String fname = inStr.substring( st + KEY_LEN , ed + 4 ); // + 4 は、".png" の分 155 156 FileUtil.copy( new File( fromDir,fname ) , new File( toDir,fname ) ); 157 158 st = inStr.indexOf( CHART_KEY , ed + 4 ) ; 159 } 160 } 161 162 /** 163 * 個々の変換データを管理している、データクラス 164 * このクラスは、不変クラスのため、マルチスレッドでの同時使用に対して、安全です。 165 * 166 * ※ このクラスは継承されるため、final化しません。 167 */ 168 private static class ChangeData { 169 private final String filename ; 170 private final String org ; 171 private final String rep ; 172 173 /** 174 * デフォルトコンストラクター 175 * サブクラス作成用に用意された、コンストラクタ。このクラス自身には不要。 176 */ 177 public ChangeData() { 178 this( null,null,null ); 179 } 180 181 /** 182 * コンストラクター 183 * 初期設定を行います。 184 * 対象ファイル名は、処理を実行するかどうかの判定に使用します。 185 * 指定の文字列が含まれているかどうかで判定します。 186 * null の場合は、すべてのファイルを対象にします。 187 * 188 * @param filename 対象ファイル名 189 * @param org 変換元データ 190 * @param rep 変換後データ 191 */ 192 public ChangeData( final String filename,final String org,final String rep ) { 193 this.filename = filename; 194 this.org = org; 195 this.rep = rep; 196 } 197 198 /** 199 * 実際に変換を行うメソッド 200 * 内部的には、入力文字列.replaceAll( 変換元,変換後 ) メソッドを実行します。 201 * 202 * @param file 対象ファイル名 203 * @param inStr 対象データ 204 * @return 変換後データ 205 */ 206 public String replace( final String file,final String inStr ) { 207 208 String rtnStr = inStr; 209 if( filename == null || file.indexOf( filename ) >= 0 ) { 210 rtnStr = inStr.replaceAll( org,rep ); 211 } 212 return rtnStr; 213 } 214 215 /** 216 * このオブジェクトの文字列表現 217 * "ChangeData( " + filename + " , " + org + " , " + rep + " )" を返します。 218 * 219 * @return 文字列表現 220 * @og.rtnNotNull 221 */ 222 @Override 223 public String toString() { 224 return "ChangeData( " + filename + " , " + org + " , " + rep + " )" ; 225 } 226 } 227 228 /** 229 * マトリクスメニュー対応のデータ置き換えクラスです。 230 * jsp/ は、先に、../ に変換済みなので、その "../" からの検索条件で判断します。 231 * multiMenu と、matrixMenu は、標準は、menu フォルダですが、場合によっては、custom フォルダに存在する 232 * 場合があるため、menu/ は検索条件に含めません。 233 * ③と④は、変換処理は無いはずなので、ロジックは記述していません。 234 * 235 * matrixMenu対応 236 * URI分離 URI分離 request取出 237 * ① gamenId="jsp" + index.jsp + GAMENID=XXXX ⇒ saveDir + "jsp/indexXXXX.htm" Matrixメニューからの画面呼出し。 238 * ② gamenId="jsp" + result.jsp + GAMENID=XXXX ⇒ saveDir + "jsp/indexXXXX.htm" 画面QUERYのヘッダーメニュー 239 * ③ gamenId="menu" + multiMenu.jsp + group=YYYY ⇒ saveDir + "menu/menuYYYY.htm" 通常メニューのグループ選択 240 * ④ gamenId="menu" + matrixMenu.jsp + group=YYYY ⇒ saveDir + "menu/matrixMenuYYYY.htm" Matrixメニューのグループ選択 241 * 242 * このクラスは、不変クラスのため、マルチスレッドでの同時使用に対して、安全です。 243 * 244 * @og.rev 4.3.3.0 (2008/10/01) Matrixメニュー対応 245 * @og.rev 5.5.2.5 (2012/05/21) TopMenuTag の ONELEVEL メニューリンク対応 246 * @og.rev 5.6.4.2 (2013/05/17) 正規表現修正、判定条件変更 247 * @og.rev 6.3.8.4 (2015/10/09) セーブフォルダを、URIではなく、画面IDから取得する。 248 * @og.rev 6.4.3.2 (2016/02/19) matrixMenu の、../画面ID/index.htm の場合の対応 249 */ 250 private static final class IndexMatrixMenuData extends ChangeData { 251 /** 252 * 実際に変換を行うメソッド。 253 * 254 * @param file 対象ファイル名 255 * @param inStr 対象データ 256 * @return 変換後データ 257 */ 258 @Override 259 public String replace( final String file,final String inStr ) { 260 String rtnStr = inStr; 261 262 // 5.6.4.2 (2013/05/17) 正規表現修正、判定条件変更 263 // ① gamenId="jsp" + index.jsp + GAMENID=XXXX ⇒ saveDir + "jsp/indexXXXX.htm" Matrixメニューからの画面呼出し。 264 // ④ gamenId="menu" + matrixMenu.jsp + group=YYYY ⇒ saveDir + "menu/matrixMenuYYYY.htm" Matrixメニューのグループ選択 265 if( file.indexOf( "matrixMenu" ) >= 0 ) { 266 // 6.4.3.2 (2016/02/19) ../画面ID/index.htm の場合の対応 267 // 6.4.3.2 (2016/02/19) 従来の../index.htm では、/ がひとつなので、注意。先頭の ".. にしておかないと、前方のタグまで食ってしまう。 268 rtnStr = rtnStr.replaceAll( "\"../[^/]*[/]*index.htm\\?[^\"]*GAMENID=([^&\"]*)[^\"]*\"","\"../jsp/index$1.htm\"" ); // ① 269 rtnStr = rtnStr.replaceAll( "matrixMenu.htm\\?[^\"]*group=([^&\"]*)[^\"]*\"","matrixMenu$1.htm\"" ); // ④ 270 rtnStr = rtnStr.replaceAll( "=\"../../../mr/jsp/","=\"../" ); 271 } 272 // 6.3.8.4 (2015/10/09) セーブフォルダを、URIではなく、画面IDから取得する。 273 // ① のケースの、jsp/indexXXXX.htm ファイルの内容(frame)のフォルダ名を画面IDに変更 274 else if( file.indexOf( "jsp/index" ) >= 0 ) { 275 rtnStr = rtnStr.replaceAll( "frame src=\"../[^\"]*GAMENID=([^&\"]*)[^\"]*\"","frame src=\"../$1/index.htm\"" ); // ① 276 } 277 // ② gamenId="jsp" + result.jsp + GAMENID=XXXX ⇒ saveDir + "XXXX/index.htm" 画面QUERYのヘッダーメニュー 278 else if( file.indexOf( "query" ) >= 0 ) { 279 rtnStr = rtnStr.replaceAll( "../result.htm\\?[^\"]*GAMENID=([^&\"]*)[^\"]*\"","../jsp/index$1.htm\"" ); // ② 280 } 281 // ③ gamenId="menu" + multiMenu.jsp + group=YYYY ⇒ saveDir + "jsp/menuYYYY.htm" 通常メニューのグループ選択 282 else if( file.indexOf( "multiMenu" ) >= 0 || file.indexOf( "menu" ) >= 0 || file.indexOf( "normalMenu" ) >= 0 ) { 283 rtnStr = rtnStr.replaceAll( "multiMenu.htm\\?[^\"]*group=([^&\"]*)[^\"]*\"","menu$1.htm\"" ); // ③ 284 } 285 return rtnStr; 286 } 287 288 /** 289 * このオブジェクトの文字列表現 290 * "IndexMatrixMenuData()" を返します。 291 * 292 * @return 文字列表現 293 * @og.rtnNotNull 294 */ 295 @Override 296 public String toString() { 297 return "IndexMatrixMenuData()" ; 298 } 299 } 300 301 /** 302 * index.htm のコマンド単位のファイル名の置き換えクラスです。 303 * このクラスは、不変クラスのため、マルチスレッドでの同時使用に対して、安全です。 304 * 305 */ 306 private static final class IndexChangeData extends ChangeData { 307 // <a href="aaaa/index.htm?command=RENEW&GAMENID=bbbb 形式とマッチし、index.htm 部分を前方参照します。 308 private static final Pattern PTN1 = Pattern.compile( "index.htm\\?[^\"]*command=(NEW|RENEW)" ); 309 310 /** 311 * 実際に変換を行うメソッド。 312 * 313 * @param file 対象ファイル名 314 * @param inStr 対象データ 315 * @return 変換後データ 316 */ 317 @Override 318 public String replace( final String file,final String inStr ) { 319 String rtnStr = inStr; 320 // if( file.indexOf( "query" ) >= 0 ) { // query の場合 321 final Matcher mch = PTN1.matcher( rtnStr ); 322 int adrs = 0; 323 while( mch.find( adrs ) ) { 324 final int indx = mch.start() ; 325 final String cmd = mch.group(1); // command=(NEW|RENEW) 部分の()内文字列 326 // index.htm 文字列部に、NW または RNW を追加し、indexNW.html を作成する。 327 if( "NEW".equalsIgnoreCase( cmd ) ) { 328 rtnStr = rtnStr.substring(0,indx+5) + "NW" + rtnStr.substring(indx+5) ; 329 } 330 else if( "RENEW".equalsIgnoreCase( cmd ) ) { 331 rtnStr = rtnStr.substring(0,indx+5) + "RNW" + rtnStr.substring(indx+5) ; 332 } 333 adrs = mch.end() ; 334 mch.reset( rtnStr ); 335 } 336 // } 337 return rtnStr; 338 } 339 340 /** 341 * このオブジェクトの文字列表現 342 * "IndexChangeData()" を返します。 343 * 344 * @return 文字列表現 345 * @og.rtnNotNull 346 */ 347 @Override 348 public String toString() { 349 return "IndexChangeData()" ; 350 } 351 } 352 353 /** 354 * コマンド転送先を、onClick="location.href=XXX" で指定するように、変換します。 355 * <input type="hidden" name="hX_複写(C)" value="copy.htm" /> を見つけ、 356 * 前方参照で、複写(C) と、copy.htm を取り出します。 357 * その後、<input name="command" value="複写(C)" という文字列をキーに、 358 * <input name="command" onClick="location.href='copy.htm'" value="複写(C)" という 359 * 文字列に置き換えます。 360 * これにより、ボタンを押したときに、ボタンごとに異なる画面に遷移します。 361 * 前提条件として、下記の項目を満たしておく必要がある。 362 * ・form には、onSubmit="return false;" を記述し、フォームを無効化しておく。 363 * ・input タグの type="submit" を、type="button" にしておく。(ボタンイベント) 364 * ・query.htm 以外のファイルのみ適用。location.href では、フレームのtarget指定 365 * まで行っていない。 366 * ・上と同意で、query.htm の登録時処理は、別に行う。 367 * 368 * @og.rev 5.5.2.5 (2012/05/21) update.jsp に出力されるファイルを、コマンド名.htm に出力するように機能追加 369 * @og.rev 5.6.4.2 (2013/05/17) 3ペイン、エントリなど、特殊な画面にフラグを付けます。(TARGET_CHANGE_SET) 370 * @og.rev 6.2.5.0 (2015/06/05) GMIS V6 対応(location.href時に、type="submit" を type="button" に変更) 371 */ 372 private static final class HrefChangeData extends ChangeData { 373 private static final String PTN1 = "<input type=\"hidden\" name=\"hX_([^\"]*)\" value=\"([^\"]*.htm)" ; 374 private static final Pattern PTN_OBJ1 = Pattern.compile( PTN1 ); // 6.4.1.1 (2016/01/16) ptnObj1 → PTN_OBJ1 refactoring 375 376 // 5.5.7.2 (2012/10/09) 定数名の変更 377 private static final String ORG = "<input name=\"command\"" ; 378 private static final String SELF = "<input name=\"command\" onClick=\"location.href='" ; 379 private static final String PRNT = "<input name=\"command\" onClick=\"parent.location.href='" ; 380 private static final String TOP = "<input name=\"command\" onClick=\"top.location.href='" ; 381 382 // 5.5.7.2 (2012/10/09) formのtargetを取得。location.href に利用する。 383 private static final String PTN2 = "<form .*target=\"([^\"]*)\"" ; 384 private static final Pattern PTN_OBJ2 = Pattern.compile( PTN2 ); // 6.4.1.1 (2016/01/16) ptnObj2 → PTN_OBJ2 refactoring 385 386 // 6.2.5.0 (2015/06/05) GMIS V6 対応(location.href時に、type="submit" を type="button" に変更) 387 private static final String LOC_HREF = "location.href" ; 388 private static final String TP_SUBMIT = "type=\"submit\"" ; 389 private static final String TP_BUTTON = "type=\"button\"" ; 390 391 /** 392 * コマンド転送先を、onClick="location.href=XXX" で指定するように、変換します。 393 * <input type="hidden" name="hX_複写(C)" value="copy.htm" /> を見つけ、 394 * 前方参照で、複写(C) と、copy.htm を取り出します。 395 * その後、<input name="command" value="複写(C)" という文字列をキーに、 396 * <input name="command" onClick="location.href='copy.htm'" value="複写(C)" という 397 * 文字列に置き換えます。 398 * 399 * @og.rev 5.5.2.5 (2012/05/21) update.jsp に出力されるファイルを、コマンド名.htm に出力するように機能追加 400 * @og.rev 5.5.7.2 (2012/10/09) 定数名の変更。formのtargetを加味した、location.href を作成する。 401 * @og.rev 5.6.4.2 (2013/05/17) 3ペイン、エントリなど、特殊な画面にフラグを付けます。(TARGET_CHANGE_SET) 402 * @og.rev 6.2.5.0 (2015/06/05) query*** 以外 403 * @og.rev 6.3.8.0 (2015/09/11) idxEnd = -1 の場合、無限ループになる。(javadoc上では -1 のハズ) 404 * 405 * @param file 対象ファイル名 406 * @param inStr 対象データ 407 * @return 変換後データ 408 */ 409 @Override 410 public String replace( final String file,final String inStr ) { 411 String rtnStr = inStr; 412 // 6.2.5.0 (2015/06/05) query.htm , queryNW.htm , query1.htm 以外 413 if( file.indexOf( "query" ) < 0 ) { // 6.2.5.0 (2015/06/05) query*** 以外 414 // 5.5.7.2 (2012/10/09) formのtargetを加味した、location.href を作成する。 415 final Matcher mch2 = PTN_OBJ2.matcher( rtnStr ); 416 String ptnHref = SELF; // 標準は、location.href 417 if( mch2.find() ) { 418 // 5.6.4.2 (2013/05/17) 3ペイン、エントリなど、特殊な画面にフラグを付けます。(TARGET_CHANGE_SET) 419 final int indx = file.lastIndexOf( '/' ); 420 final String fileKey = file.substring( 0,indx ); 421 422 final String frmTgt = mch2.group(1); 423 if( "CONTENTS".equals( frmTgt ) ) { ptnHref = PRNT; } 424 else if( "_top".equals( frmTgt ) ) { ptnHref = TOP; } 425 // 6.4.1.1 (2016/01/16) PMD refactoring. Avoid if (x != y) ..; else ..; 426 else if( "RESULT".equals( frmTgt ) || frmTgt == null ) { 427 // 5.6.4.2 (2013/05/17) ある画面で、特殊なターゲット(INPUT,BUTTOMなど)を使用している場合のチェック 428 if( TARGET_CHANGE_SET.contains( fileKey ) ) { 429 ptnHref = PRNT ; 430 } 431 } 432 else { 433 ptnHref = "<input name=\"command\" onClick=\"parent." + frmTgt + ".location.href='" ; 434 // 5.6.4.2 (2013/05/17) ある画面で、特殊なターゲット(INPUT,BUTTOMなど)を使用している場合に記憶 435 TARGET_CHANGE_SET.add( fileKey ); // 別のファイルを処理するときに参照する。 436 } 437 } 438 439 final Matcher mch = PTN_OBJ1.matcher( rtnStr ); 440 int adrs = 0; 441 while( mch.find( adrs ) ) { 442 final String cmd = mch.group(1); 443 if( !cmd.endsWith( "CMD" ) ) { 444 final String val = mch.group(2); 445 final String str1 = ORG + " value=\"" + cmd ; 446 String str2 ; 447 448 if( val != null && val.startsWith( "../" ) ) { 449 str2 = PRNT + val + "'\" value=\"" + cmd ; 450 } 451 // 5.5.2.5 (2012/05/21) update.jsp に出力されるファイルを、コマンド名.htm に出力するように機能追加 452 else if( val != null && val.startsWith( "update" ) ) { 453 str2 = ptnHref + cmd + ".htm'\" value=\"" + cmd ; 454 } 455 else { 456 str2 = ptnHref + val + "'\" value=\"" + cmd ; 457 } 458 rtnStr = rtnStr.replace( str1,str2 ); 459 } 460 adrs = mch.end(); 461 mch.reset( rtnStr ); 462 } 463 464 // 6.2.5.0 (2015/06/05) GMIS V6 対応(location.href時に、type="submit" を type="button" に変更) 465 // 正規表現の置き換え箇所が、難しそうなので、もう一度初めから処理します。 466 // location.href① … type="submit"② … />③ の関係チェック 467 final StringBuilder buf = new StringBuilder( rtnStr ); 468 469 int idxHref = buf.indexOf( LOC_HREF ); // ① 470 while( idxHref >= 0 ) { 471 final int idxType = buf.indexOf( TP_SUBMIT , idxHref ); // ② 472 final int idxEnd = buf.indexOf( "/>" , idxHref ); // ③ 473 if( idxType >= 0 && idxEnd >= 0 && idxType < idxEnd ) { 474 buf.replace( idxType , idxType + TP_SUBMIT.length() , TP_BUTTON ); // 範囲置換 475 } 476 // 6.3.8.0 (2015/09/11) idxEnd = -1 の場合、無限ループになる。(javadoc上では -1 のハズ) 477 idxHref = buf.indexOf( LOC_HREF , Math.max( idxEnd , idxHref + LOC_HREF.length() ) ); 478 } 479 rtnStr = buf.toString(); 480 } 481 return rtnStr; 482 } 483 484 /** 485 * このオブジェクトの文字列表現 486 * "HrefChangeData()" を返します。 487 * 488 * @return 文字列表現 489 * @og.rtnNotNull 490 */ 491 @Override 492 public String toString() { 493 return "HrefChangeData()" ; 494 } 495 } 496 497 /** 498 * 雛形自動作成 で、useAjaxSubmit="true" の対策 499 * 500 * update.jsp で、useAjaxSubmit="true" の場合、entry.htm は、update.jsp の 501 * JavaScriptでforward されるため、雛形には、HTMLの結果は出力されません。 502 * (result.jsp に出力されます。) 503 * そこで、雛形作成時には、entry.htm にJavaScriptを入れて、forward させます。 504 * JavaScript の挿入位置は、 BODYの終了タグがあれば、その直前に、なければ、最後に追加します。 505 * 506 * ※ 6.2.5.0 (2015/06/05) 507 * 本当は、ForwardTag#doEndTag() の noTransitionUrl を出力している箇所に入れれば 508 * 一番きれいだが、各種各画面で使用しているタグなので、あまり変更したくないのと、 509 * style 属性で設定すると、画面が動作しなくなったため、何か問題が起こりそうなので、 510 * 紙芝居作成時のみ対応することとします。 511 * 非表示(display:none;)は、<div id="noTransitionUrl"> の直前にします。 512 * 513 * @og.rev 5.6.3.4 (2013/04/26) entry.htm に "noTransitionUrl" が存在するときの処理。 514 * @og.rev 6.2.5.0 (2015/06/05) GMIS V6 対応(noTransitionUrl,noTransitionTargetを非表示にする) 515 */ 516 private static final class NoTranHrefChangeData extends ChangeData { 517 // 6.2.5.0 (2015/06/05) GMIS V6 対応(noTransitionUrl,noTransitionTargetを非表示にする) 518 private static final String DIV_TAG = "<div id=\"noTransitionUrl\">" ; 519 private static final String DISPLAY_NONE = "<style type=\"text/css\">#noTransitionUrl,#noTransitionTarget{display:none;}</style>"; 520 521 private static final String BODY_END = "</body>" ; 522 private static final String APPEND_JS = "<script type=\"text/javascript\" src=\"../common/option/noTranHref.js\" ><!-- --></script>" ; 523 524 /** 525 * 実際に変換を行うメソッド。 526 * 527 * @param file 対象ファイル名 528 * @param inStr 対象データ 529 * @return 変換後データ 530 */ 531 @Override 532 public String replace( final String file,final String inStr ) { 533 String rtnStr = inStr; 534 // entry.jsp で、かつ noTransitionUrl 文字列を含む場合のみ 535 if( file.indexOf( "entry" ) >= 0 && inStr.indexOf( "noTransitionUrl" ) >= 0 ) { 536 // 6.2.5.0 (2015/06/05) GMIS V6 対応 537 final StringBuilder buf = new StringBuilder( rtnStr ); 538 final int divAd = buf.indexOf( DIV_TAG ); 539 if( divAd >= 0 ) { buf.insert( divAd,DISPLAY_NONE ); } 540 541 final int adrs = buf.indexOf( BODY_END ); 542 if( adrs >= 0 ) { buf.insert( adrs,APPEND_JS ); } // </body> タグが存在した場合は、その直前に挿入する。 543 else { buf.append( APPEND_JS ); } // 存在しない場合は、最後に挿入する。 544 545 rtnStr = buf.toString(); 546 } 547 return rtnStr; 548 } 549 550 /** 551 * このオブジェクトの文字列表現 552 * "NoTranHrefChangeData()" を返します。 553 * 554 * @return 文字列表現 555 * @og.rtnNotNull 556 */ 557 @Override 558 public String toString() { 559 return "NoTranHrefChangeData()" ; 560 } 561 } 562 563 /** 564 * 雛形自動作成 で、fileDownload の日本語名対応 565 * 566 * 標準的な、fileDownload 処理では、../common/fileDownload.jsp?・・・・GAMENID=XXXX&filename=YYYY" と 567 * なっており、filename 部分は、日本語にも対応できるように urlEncode されています。 568 * これを、元に戻さないとうまくダウンロードできませんでした。 569 * 570 * ※ 参考情報 571 * 1.urlEncode のままで、ファイル名を取得する場合は、下記の標準系で対応可能です。 572 * ,new ChangeData( null ,"../common/fileDownload.htm\\?[^\"]*filename=([^&\"]*)[^\"]*\"","$1\"" ) 573 * 2.ファイル名を、fileDownload.xls 固定にする場合は、下記の標準系で対応可能です。 574 * ,new ChangeData( null ,"../common/fileDownload.htm\\?[^\"]*\"","fileDownload.xls\"" ) 575 * 576 * @og.rev 5.6.4.2 (2013/05/17) 新規追加 577 */ 578 private static final class FileDownloadChangeData extends ChangeData { 579 private static final String PTN1 = "../common/fileDownload.htm\\?[^\"]*filename=([^&\"]*)[^\"]*\"" ; 580 private static final Pattern PTN_OBJ1 = Pattern.compile( PTN1 ); // 6.4.1.1 (2016/01/16) ptnObj1 → PTN_OBJ1 refactoring 581 582 /** 583 * 実際に変換を行うメソッド。 584 * 585 * @param file 対象ファイル名 586 * @param inStr 対象データ 587 * @return 変換後データ 588 */ 589 @Override 590 public String replace( final String file,final String inStr ) { 591 String rtnStr = inStr; 592 // entry.jsp で、かつ noTransitionUrl 文字列を含む場合のみ 593 if( rtnStr.indexOf( "../common/fileDownload.htm" ) >= 0 ) { 594 final Matcher mch = PTN_OBJ1.matcher( rtnStr ); 595 int adrs = 0; 596 while( mch.find( adrs ) ) { 597 String fname = mch.group(1); 598 fname = StringUtil.urlDecode( fname ); // デコードしています。 599 600 final int indx = mch.start() ; 601 adrs = mch.end(); 602 rtnStr = rtnStr.substring( 0,indx ) + fname + "\"" + rtnStr.substring( adrs ) ; 603 604 mch.reset( rtnStr ); 605 } 606 } 607 return rtnStr; 608 } 609 610 /** 611 * このオブジェクトの文字列表現 612 * "FileDownloadChangeData()" を返します。 613 * 614 * @return 文字列表現 615 * @og.rtnNotNull 616 */ 617 @Override 618 public String toString() { 619 return "FileDownloadChangeData()" ; 620 } 621 } 622}