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.taglib; 017 018import org.opengion.hayabusa.common.HybsSystem; 019import org.opengion.hayabusa.common.HybsSystemException; 020import org.opengion.hayabusa.db.DBTableModel; 021import org.opengion.hayabusa.db.TableFilter; 022import org.opengion.fukurou.db.Transaction; 023import org.opengion.fukurou.db.TransactionReal; 024import org.opengion.fukurou.util.ErrorMessage; 025import org.opengion.fukurou.util.StringUtil; 026import static org.opengion.fukurou.util.StringUtil.nval ; 027 028import java.io.ObjectOutputStream; 029import java.io.ObjectInputStream; 030import java.io.IOException; 031import java.util.Map; 032 033/** 034 * TableFilter のサブクラスをCALLしてDBTableModelにアクセスするタグです。 035 * 036 * DBTableModel を TableFilter のサブクラス(classIdで指定)に渡して処理を実行します。 037 * クラスを作成する場合は、org.opengion.hayabusa.db.TableFilter インターフェースを継承した 038 * クラスにする必要があります。また、classId 属性には、システムリソース で 039 * 設定した TableFilter.XXXX の XXXX を指定します。 040 * 041 * BODY部分は、SQLを記述する為だけに使っていましたが、CSS定義形式の書式で、keys,vals を記述 042 * できるようにします。 043 * これは、下記のようなパラメータを、keys="KEY,KEY2,KEY3" vals='AAAA,"BB,CC,DD",EE' のような記述形式と 044 * { 045 * KEY1 : AAAA ; 046 * KEY2 : BB,CC,DD ; 047 * KEY3 : EE ; 048 * ・・・・・・ 049 * } 050 * のような、CSS形式に類似の形式でも記述できるようにしました。 051 * keys,vals と CSS定義形式パラメータを同時に指定した場合は、両方とも有効です。 052 * ただし、キーが重複した場合は、不定と考えてください。 053 * 現時点では、CSS定義形式パラメータが優先されますが、これは、単に内部パラメータMapへの 054 * 登録順が、CSS定義形式パラメータが後の為、上書きされるためです。 055 * 056 * ※ このタグは、Transaction タグの対象です。 057 * 058 * @og.formSample 059 * ●形式:<og:tableFilter classId="…" /> 060 * ●body:あり(EVAL_BODY_BUFFERED:BODYを評価し、{@XXXX} を解析します) 061 * 062 * ●Tag定義: 063 * <og:tableFilter 064 * classId ○【TAG】データベース処理を実行するクラスパスを指定します(必須)。 065 * tableId 【TAG】(通常は使いません)DBTableModel sessionに登録されているキーを指定します 066 * modifyType 【TAG】データ処理の方法(A:追加 C:更新 D:削除)を指定します 067 * keys 【TAG】リンク先に渡すキーを指定します 068 * vals 【TAG】keys属性に対応する値をCSV形式で複数指定します 069 * selectedAll 【TAG】データを全件選択済みとして処理するかどうか[true/false]を指定します(初期値:false) 070 * stopZero 【TAG】検索結果が0件のとき処理を続行するかどうか[true/false]を指定します(初期値:false[続行する]) 071 * scope 【TAG】キャッシュする場合のスコープ[request/page/session/applicaton]を指定します(初期値:session) 072 * dbid 【TAG】(通常は使いません)Queryオブジェクトを作成する時のDB接続IDを指定します 073 * caseKey 【TAG】このタグ自体を利用するかどうかの条件キーを指定します(初期値:null) 5.7.7.2 (2014/06/20) 074 * caseVal 【TAG】このタグ自体を利用するかどうかの条件値を指定します(初期値:null) 5.7.7.2 (2014/06/20) 075 * caseNN 【TAG】指定の値が、null/ゼロ文字列 でない場合(Not Null=NN)は、このタグは使用されます(初期値:true) 5.7.7.2 (2014/06/20) 076 * caseNull 【TAG】指定の値が、null/ゼロ文字列 の場合は、このタグは使用されます(初期値:true) 5.7.7.2 (2014/06/20) 077 * debug 【TAG】デバッグ情報を出力するかどうか[true/false]を指定します(初期値:false) 078 * > ... Body ... 079 * </og:tableFilter> 080 * 081 * ●使用例 082 * ・引数/プロシジャーを直接書く場合 083 * 【entry.jsp】 084 * <og:tableFilter 085 * classId = "WL_LOGICSET" :TableFilter のサブクラス(実行クラス) 086 * tableId = "WL0000" :登録元のDBTableModelのsession/request変数内の取得キー 087 * keys = "AA,BB,CC" :実行クラスへの引数のキー 088 * vals = "{@AA},{@BB},{@CC}" :実行クラスへの引数の値 089 * selectedAll = "false/true" :処理対象の行を全行選択するかどうか(初期値:false) 090 * modifyType = "A/C/D" :処理の方法(A:追加 C:更新 D:削除)を指定します。初期値は自動です。 091 * /> 092 * 093 * ・BODY部分に、CSS形式のパラメータ(keys,vals)を記述する例 094 * 095 * <og:tableFilter 096 * classId = "WL_LOGICSET" :TableFilter のサブクラス(実行クラス) 097 * tableId = "WL0000" :登録元のDBTableModelのsession/request変数内の取得キー 098 * selectedAll = "false/true" :処理対象の行を全行選択するかどうか(初期値:false) 099 * modifyType = "A/C/D" :処理の方法(A:追加 C:更新 D:削除)を指定します。初期値は自動です。 100 * > 101 * { 102 * AA : {@AA} 103 * BB : {@BB} 104 * CC : {@CC} 105 * } 106 * </og:tableFilter> 107 * 108 * @og.group その他 109 * @og.rev 3.8.5.0 (2006/03/20) 新規作成 110 * 111 * @version 0.9.0 2000/10/17 112 * @author Kazuhiko Hasegawa 113 * @since JDK1.1, 114 */ 115public class TableFilterTag extends CommonTagSupport { 116 //* このプログラムのVERSION文字列を設定します。 {@value} */ 117 private static final String VERSION = "5.7.7.2 (2014/06/20)" ; 118 119 private static final long serialVersionUID = 577220140620L ; 120 121 private static final String errMsgId = HybsSystem.ERR_MSG_KEY; 122 private transient DBTableModel table = null; 123 124 private String tableId = HybsSystem.TBL_MDL_KEY; 125 private String classId = null; 126 private String modifyType = null; 127 private String[] keys = null; 128 private String[] vals = null; 129 130 private String dbid = null ; // 4.2.4.0 (2008/06/23) 131 private String sql = null ; // 5.6.5.2 (2013/06/21) bodyからSQL文のみを切り出す。 132 private Map<String,String> paramMap = null; // 5.6.5.2 (2013/06/21) bodyからparamMapを取りだし。 133 134 private boolean selectedAll = false; 135 private boolean stopZero = false; // 5.7.6.2 (2014/05/16) stopZero属性追加 136 137 /** 138 * Taglibの開始タグが見つかったときに処理する doStartTag() を オーバーライドします。 139 * 140 * @og.rev 5.7.7.2 (2014/06/20) caseKey,caseVal,caseNN,caseNull 属性を追加 141 * 142 * @return 後続処理の指示( EVAL_BODY_BUFFERED ) 143 */ 144 @Override 145 public int doStartTag() { 146 // 5.7.7.2 (2014/06/20) caseKey,caseVal,caseNN,caseNull 属性を追加 147 if( !useTag() ) { return SKIP_BODY ; } 148 149 table = (DBTableModel)getObject( tableId ); 150 151 if( keys != null && vals != null && keys.length != vals.length ) { 152 String errMsg = "keys と vals の設定値の数が異なります。: " + HybsSystem.CR 153 + "keys.length=[" + keys.length + "] , " 154 + "keys.length=[" + StringUtil.array2line( keys,"," ) + "]" 155 + HybsSystem.CR 156 + "vals.length=[" + vals.length + "] , " 157 + "vals.length=[" + StringUtil.array2line( vals,"," ) + "]"; 158 throw new HybsSystemException( errMsg ); 159 } 160 161 startQueryTransaction( tableId ); 162 return EVAL_BODY_BUFFERED ; // Body を評価する 163 } 164 165 /** 166 * Taglibのタグ本体を処理する doAfterBody() を オーバーライドします。 167 * 168 * @og.rev 5.6.5.2 (2013/06/21) bodyローカル化、sql、paramMap 追加 169 * 170 * @return 後続処理の指示(SKIP_BODY) 171 */ 172 @Override 173 public int doAfterBody() { 174 String body = nval( getBodyString(),null ); 175 176 // paramMapの取り出し 177 paramMap = StringUtil.cssParse( body ); 178 179 // SQL文の切り出し classId="DBSELECT" の場合のみの処理 180 if( "DBSELECT".equalsIgnoreCase( classId ) && body != null ) { 181 int ad1 = body.indexOf( '{' ); 182 int ad2 = body.indexOf( '}' ); 183 184 if( ad1 >= 0 && ad2 >= 0 ) { 185 sql = body.substring( 0,ad1 ).trim() + body.substring( ad2+1 ).trim(); 186 } 187 else { 188 sql = body.trim(); 189 } 190 } 191 192 return SKIP_BODY ; 193 } 194 195 /** 196 * Taglibの終了タグが見つかったときに処理する doEndTag() を オーバーライドします。 197 * 198 * @og.rev 3.8.7.0 (2006/12/15) アクセスログ取得の為,ApplicationInfoオブジェクトを設定 199 * @og.rev 4.2.3.0 (2008/06/23) DBIDとボディー部分の記述を下位クラスに渡す用に修正 200 * @og.rev 4.3.7.4 (2009/07/01) Resouceオブジェクトを下位クラスに渡す用に修正 201 * @og.rev 5.1.9.0 (2010/08/01) Transaction 対応 202 * @og.rev 5.2.1.0 (2010/10/01) debugPrint() メソッドの処理条件見直し 203 * @og.rev 5.3.7.0 (2011/07/01) TransactionReal の引数変更 、Transaction対応で、close処理を入れる。 204 * @og.rev 5.6.5.2 (2013/06/21) bodyローカル化、sql、paramMap 追加 205 * @og.rev 5.7.6.2 (2014/05/16) table件数が変わる場合、"DB.COUNT" キーでリクエストに再セットする。 206 * @og.rev 5.7.7.2 (2014/06/20) caseKey,caseVal,caseNN,caseNull 属性を追加 207 * 208 * @return 後続処理の指示 209 */ 210 @Override 211 public int doEndTag() { 212 // デバッグ時には、オブジェクト内部情報を表示する。 213 debugPrint(); // 5.2.1.0 (2010/10/01) debugPrint() メソッド自体に、isDebug() が組み込まれている。 214 215 // 5.7.7.2 (2014/06/20) caseKey,caseVal,caseNN,caseNull 属性を追加 216 if( !useTag() ) { return EVAL_PAGE ; } 217 218 int rtnCode = EVAL_PAGE; // try 〜 finally の関係で、変数化しておく 219 220 int[] rowNo = getParameterRows(); 221 222 // 5.1.9.0 (2010/08/01) Transaction 対応 223 Transaction tran = null; 224 final TableFilter filter ; 225 // 5.3.7.0 (2011/07/01) Transaction対応で、close処理を入れる。 226 try { 227 TransactionTag tranTag = (TransactionTag)findAncestorWithClass( this,TransactionTag.class ); 228 if( tranTag == null ) { 229 tran = new TransactionReal( getApplicationInfo() ); // 5.3.7.0 (2011/07/01) 引数変更 230 } 231 else { 232 tran = tranTag.getTransaction(); 233 } 234 235 // 5.7.6.2 (2014/05/16) table件数が変わる場合、"DB.COUNT" キーでリクエストに再セットする。 236 int rowCnt1 = table == null ? -1 : table.getRowCount(); 237 238 String cls = HybsSystem.sys( "TableFilter_" + classId ); 239 filter = (TableFilter)HybsSystem.newInstance( cls ); 240 241 filter.setDBTableModel( table ); 242 filter.setParameterRows( rowNo ); 243 filter.setModifyType( modifyType ); 244 filter.setKeysVals( keys,vals ); 245 // filter.setApplicationInfo( getApplicationInfo() ); // 3.8.7.0 (2006/12/15) 246 filter.setTransaction( tran ); // 5.1.9.0 (2010/08/01) Transaction 対応 247 filter.setDebug( isDebug() ); 248 filter.setDbid( dbid ); // 4.2.4.0 (2008/06/23) 249 filter.setSql( sql ); // 5.6.5.2 (2013/06/21) sql 追加 250 filter.setParamMap( paramMap ); // 5.6.5.2 (2013/06/21) paramMap 追加 251 filter.setResource( getResource() ); // 4.3.7.4 (2009/07/01) 252 253 table = filter.execute(); 254 255 // 5.7.6.2 (2014/05/16) table件数が変わる場合、"DB.COUNT" キーでリクエストに再セットする。 256 int rowCnt2 = table == null ? -1 : table.getRowCount(); 257 if( rowCnt1 != rowCnt2 ) { 258 setRequestAttribute( "DB.COUNT" , String.valueOf( rowCnt2 ) ); 259 } 260 261 int errCode = filter.getErrorCode(); 262 ErrorMessage errMessage = filter.getErrorMessage(); 263 264 if( errCode >= ErrorMessage.NG ) { // 異常 265 rtnCode = SKIP_PAGE; 266 } 267 268 // 5.7.6.2 (2014/05/16) 件数0件(または、table==null)かつ stopZero = true 269 if( rowCnt2 <= 0 && stopZero ) { return SKIP_PAGE; } 270 271 String err = TaglibUtil.makeHTMLErrorTable( errMessage,getResource() ); 272 if( err != null && err.length() > 0 ) { 273 jspPrint( err ); 274 setSessionAttribute( errMsgId,errMessage ); 275 } 276 else { 277 removeSessionAttribute( errMsgId ); 278 } 279 } 280 finally { 281 if( tran != null ) { tran.close(); } 282 } 283 284 if( table != null && ! commitTableObject( tableId, table ) ) { 285 rtnCode = SKIP_PAGE ; 286 } 287 288 return rtnCode ; 289 } 290 291 /** 292 * タグリブオブジェクトをリリースします。 293 * キャッシュされて再利用されるので、フィールドの初期設定を行います。 294 * 295 * @og.rev 5.6.5.2 (2013/06/21) body廃止、sql、paramMap 追加 296 * @og.rev 5.7.6.2 (2014/05/16) stopZero属性追加 297 */ 298 @Override 299 protected void release2() { 300 super.release2(); 301 table = null; 302 tableId = HybsSystem.TBL_MDL_KEY; 303 classId = null; 304 modifyType = null; 305 keys = null; 306 vals = null; 307 selectedAll = false; 308 stopZero = false; // 5.7.6.2 (2014/05/16) stopZero属性追加 309 dbid = null; // 4.2.4.0 (2008/06/23) 310 sql = null; // 5.6.5.2 (2013/06/21) bodyからSQL文のみを切り出す。 311 paramMap = null; // 5.6.5.2 (2013/06/21) bodyからparamMapを取りだす。 312 } 313 314 /** 315 * 表示データの HybsSystem.ROW_SEL_KEY を元に、選ばれた 行を処理の対象とします。 316 * 317 * @return 選択行の配列 318 */ 319 @Override 320 protected int[] getParameterRows() { 321 final int[] rowNo ; 322 if( selectedAll ) { 323 int rowCnt = table.getRowCount(); 324 rowNo = new int[ rowCnt ]; 325 for( int i=0; i<rowCnt; i++ ) { 326 rowNo[i] = i; 327 } 328 } else { 329 rowNo = super.getParameterRows(); // 4.0.0 (2005/01/31) 330 } 331 return rowNo; 332 } 333 334 /** 335 * 【TAG】データベース処理を実行するクラスパスを指定します。 336 * 337 * @og.tag 338 * ここで指定するクラスIDは、システムリソース にて TableFilter の 339 * サブクラス(インターフェース継承)として指定する必要があります。 340 * 341 * クラス自身は、org.opengion.hayabusa.db.TableFilter インターフェースを継承している必要があります。 342 * {@og.doc03Link tableFilter TableFilter_**** クラス} 343 * 344 * @param id TableFilter インターフェースを継承している実クラスの ID 345 * @see org.opengion.hayabusa.db.TableFilter TableFilter インターフェース 346 */ 347 public void setClassId( final String id ) { 348 classId = nval( getRequestParameter( id ),classId ); 349 } 350 351 /** 352 * 【TAG】(通常は使いません)結果のDBTableModelを、sessionに登録するときのキーを指定します 353 * (初期値:HybsSystem#TBL_MDL_KEY[={@og.value org.opengion.hayabusa.common.HybsSystem#TBL_MDL_KEY}])。 354 * 355 * @og.tag 356 * 検索結果より、DBTableModelオブジェクトを作成します。これを、下流のviewタグ等に 357 * 渡す場合に、通常は、session を利用します。その場合の登録キーです。 358 * query タグを同時に実行して、結果を求める場合、同一メモリに配置される為、 359 * この tableId 属性を利用して、メモリ空間を分けます。 360 * (初期値:HybsSystem#TBL_MDL_KEY[={@og.value org.opengion.hayabusa.common.HybsSystem#TBL_MDL_KEY}])。 361 * 362 * @param id sessionに登録する時の ID 363 */ 364 public void setTableId( final String id ) { 365 tableId = nval( getRequestParameter( id ),tableId ); 366 } 367 368 /** 369 * 【TAG】データを全件選択済みとして処理するかどうか[true/false]を指定します(初期値:false)。 370 * 371 * @og.tag 372 * 全てのデータを選択済みデータとして扱って処理します。 373 * 全件処理する場合に、指定します。(true/false) 374 * デフォルト false です。 375 * 376 * @param all データを全件選択済み [true:全件選択済み/false:通常] 377 */ 378 public void setSelectedAll( final String all ) { 379 selectedAll = nval( getRequestParameter( all ),selectedAll ); 380 } 381 382 /** 383 * 【TAG】検索結果が0件のとき処理を続行するかどうか[true/false]を指定します(初期値:false[続行する])。 384 * 385 * @og.tag 386 * 初期値は、false(続行する)です。 387 * 388 * @og.rev 5.7.6.2 (2014/05/16) 新規追加 389 * 390 * @param cmd 検索結果が0件のとき、[true:処理を中止する/false:続行する] 391 */ 392 public void setStopZero( final String cmd ) { 393 stopZero = nval( getRequestParameter( cmd ),stopZero ); 394 } 395 396 /** 397 * 【TAG】データ処理の方法(A:追加 C:更新 D:削除)を指定します。 398 * 399 * @og.tag 400 * 通常は、DBTableModel に自動設定されている modifyType を元に、データ処理方法を 401 * 選別します。(A:追加 C:更新 D:削除) 402 * この場合、行単位で modifyType の値を取得して判別する必要がありますが、一般には 403 * 処理対象は、全件おなじ modifyType である可能性が高いです。 404 * また、selectedAll などで強制的に全件処理対象とする場合は、modifyType に値が 405 * 設定さていません。その様な場合に外部より modifyType を指定します。 406 * 初期値は、自動判定 です。 407 * 408 * @param type データ処理の方法(A:追加 C:更新 D:削除) 409 */ 410 public void setModifyType( final String type ) { 411 modifyType = nval( getRequestParameter( type ),modifyType ); 412 413 if( modifyType != null && !"A".equals( modifyType ) && !"C".equals( modifyType ) && !"D".equals( modifyType ) ) { 414 String errMsg = "modifyType は A:追加 C:更新 D:削除 のどれかを指定してください。: " + HybsSystem.CR 415 + "modifyType=[" + modifyType + "]"; 416 throw new HybsSystemException( errMsg ); 417 } 418 } 419 420 /** 421 * 【TAG】リンク先に渡すキーを指定します。 422 * 423 * @og.tag 424 * 戻る時に、検索時のキャッシュに指定した引数以外に指定したり、別の値に置き換えたり 425 * する場合のキーを設定できます。カンマ区切りで複数指定できます。 426 * vals 属性には、キーに対応する値を、設定してください。 427 * 分解方法は、CSV変数を先に分解してから、getRequestParameter で値を取得します。 428 * こうしないとデータ自身にカンマを持っている場合に分解をミスる為です。 429 * 430 * @param key リンク先に渡すキー 431 */ 432 public void setKeys( final String key ) { 433 keys = getCSVParameter( key ); 434 } 435 436 /** 437 * 【TAG】names属性に対応する値をCSV形式で複数指定します。 438 * 439 * @og.tag 440 * キーに設定した値を、カンマ区切り文字で複数して出来ます。 441 * 指定順序は、キーと同じにしておいて下さい。 442 * 分解方法は、CSV変数を先に分解してから、getRequestParameter で値を取得します。 443 * こうしないとデータ自身にカンマを持っている場合に分解をミスる為です。 444 * 445 * @param val names属性に対応する値 446 */ 447 public void setVals( final String val ) { 448 vals = getCSVParameter( val ); 449 } 450 451 /** 452 * 【TAG】(通常は使いません)Queryオブジェクトを作成する時のDB接続IDを指定します。 453 * 454 * @og.tag 455 * Queryオブジェクトを作成する時のDB接続IDを指定します。 456 * これは、システムリソースで、DEFAULT_DB_URL 等で指定している データベース接続先 457 * 情報に、XX_DB_URL を定義することで、 dbid="XX" とすると、この 接続先を使用して 458 * データベースにアクセスできます。 459 * 460 * @param id データベース接続ID 461 */ 462 public void setDbid( final String id ) { 463 dbid = nval( getRequestParameter( id ),dbid ); 464 } 465 466 /** 467 * シリアライズ用のカスタムシリアライズ書き込みメソッド 468 * 469 * @og.rev 4.0.0.0 (2006/09/31) 新規追加 470 * @serialData 一部のオブジェクトは、シリアライズされません。 471 * 472 * @param strm ObjectOutputStreamオブジェクト 473 * @throws IOException 入出力エラーが発生した場合 474 */ 475 private void writeObject( final ObjectOutputStream strm ) throws IOException { 476 strm.defaultWriteObject(); 477 } 478 479 /** 480 * シリアライズ用のカスタムシリアライズ読み込みメソッド 481 * 482 * ここでは、transient 宣言された内部変数の内、初期化が必要なフィールドのみ設定します。 483 * 484 * @og.rev 4.0.0.0 (2006/09/31) 新規追加 485 * @serialData 一部のオブジェクトは、シリアライズされません。 486 * 487 * @param strm ObjectInputStreamオブジェクト 488 * @see #release2() 489 * @throws IOException シリアライズに関する入出力エラーが発生した場合 490 * @throws ClassNotFoundException クラスを見つけることができなかった場合 491 */ 492 private void readObject( final ObjectInputStream strm ) throws IOException , ClassNotFoundException { 493 strm.defaultReadObject(); 494 } 495 496 /** 497 * このオブジェクトの文字列表現を返します。 498 * 基本的にデバッグ目的に使用します。 499 * 500 * @return このクラスの文字列表現 501 */ 502 @Override 503 public String toString() { 504 return org.opengion.fukurou.util.ToString.title( this.getClass().getName() ) 505 .println( "VERSION" ,VERSION ) 506 .println( "tableId" ,tableId ) 507 .println( "classId" ,classId ) 508 .println( "modifyType" ,modifyType ) 509 .println( "selectedAll" ,selectedAll ) 510 .println( "keys" ,keys ) 511 .println( "vals" ,vals ) 512 .println( "dbid" ,dbid ) // 4.2.4.0 (2008/06/23) 513 .println( "sql" ,sql ) // 5.6.5.2 (2013/06/21) 514 .fixForm().toString() ; 515 } 516}