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.fukurou.db.DBUtil; 022 023import org.opengion.fukurou.util.ErrorMessage; 024import org.opengion.fukurou.util.StringUtil ; 025import static org.opengion.fukurou.util.StringUtil.nval ; 026import org.opengion.fukurou.model.Formatter; 027 028import java.util.Locale ; 029import java.util.List ; 030import java.util.ArrayList ; 031 032import java.io.ObjectOutputStream; 033import java.io.ObjectInputStream; 034import java.io.IOException; 035 036/** 037 * 【廃止】登録すべきデータのマスタ存在チェックを行うためのタグです(通常はentry.jspでupdateタグの直前で使用します)。 038 * 039 * この要素の内容に、SQL文を記述します。 040 * names に対応するカラム名を、カンマ区切りで複数与えます。その値を、DBTableModel 041 * より、取得し、先のSQL文の ? に値を設定します。 042 * または、引数部に、[カラム名]を用いたHybs拡張SQL文を指定することも可能です。 043 * 044 * 値の取得は、先に選択された行のみについて、実行されます。 045 * exist 属性に指定された 、「true:存在する」、「false:存在しない」、「one:ひとつ以下」、 046 * の値は、チェック方法を設定しています。 047 * いずれの場合も、成立時は、正常とみなします。 048 * (「true:存在する」 には、データが存在した場合に、OKで、なければエラーです。) 049 * 050 * @og.formSample 051 * ●形式: 052 * ・<og:tableExist 053 * command = "{@command}" 054 * names = "[…]" 055 * from = "…" 必須 056 * where = "…" 必須 057 * exist = "[auto|true|false|one|notuse]" 必須 058 * errRemove = "[true|false]" 059 * /> 060 * 061 * ●body:なし 062 * 063 * ●Tag定義: 064 * <og:tableExist 065 * command 【廃止】コマンド(ENTRY)をセットします 066 * scope 【TAG】キャッシュする場合のスコープ[request/page/session/applicaton]を指定します(初期値:session) 067 * names 【廃止】引数にセットすべき データの名称(カラム名)をCSV形式で複数指定します 068 * from ○【廃止】チェックするデータベース名(from 句)を指定します(必須)。 069 * where ○【廃止】チェックする検索条件(where句)を指定します(必須)。 070 * exist 【廃止】データベースのチェック方法(auto/true/false/one/notuse)を指定します(初期値:「auto:自動」) 071 * tableId 【廃止】(通常は使いません)結果をDBTableModelに書き込んで、sessionに登録するときのキーを指定します 072 * dbid 【廃止】(通常は使いません)Queryオブジェクトを作成する時のDB接続IDを指定します 073 * errRemove 【廃止】エラー時の選択行を取り除いて継続処理を行うかどうか[true/false]を指定します(初期値:false) 074 * debug 【TAG】デバッグ情報を出力するかどうか[true/false]を指定します(初期値:false) 075 * /> 076 * 077 * ●使用例 078 * ・<og:tableExist 079 * command = "{@command}" 080 * names = "USERID,SYSTEM_ID" 081 * from = "GE10" 082 * where = "USERID=? AND SYSTEM_ID=?" 083 * exist = "true" /> 084 * 085 * ・where 条件の ? 文字に、names で指定したカラム名の値が、DBTableModelより 086 * 取得されます。 087 * 値の取得は、先に選択された行のみについて、実行されます。 088 * ・exist 属性の値に応じて、チェック方法が異なります。 089 * auto , true , false , one , notuse が指定できます。 090 * ・テーブルは、1つのみ指定できます。複数指定や、UNIONで結合する場合は、 091 * ビュー等を作成して対応してください。 092 * 093 * ・<og:tableExist 094 * command = "{@command}" 095 * from = "GE10" 096 * where = "USERID=[USERID] AND SYSTEM_ID=[SYSTEM_ID]" /> 097 * 098 * ・where 条件の [カラム名] 文字に、DBTableModelより値がセットされます。 099 * ・exist は、初期値(auto)になります。内部のA,C,Dに応じて自動判別します。 100 * 101 * @og.rev 3.5.0.0 (2003/09/17) 新規作成 102 * @og.group (廃止)DB登録 103 * 104 * @version 4.0 105 * @author Kazuhiko Hasegawa 106 * @since JDK5.0, 107 * @deprecated 代わりに dataCheckタグを使用してください 108 */ 109@Deprecated public class TableExistTag extends CommonTagSupport { 110 //* このプログラムのVERSION文字列を設定します。 {@value} */ 111 private static final String VERSION = "4.0.0.0 (2007/11/28)" ; 112 113 private static final long serialVersionUID = 400020071128L ; 114 115 /** command 引数に渡す事の出来る コマンド エントリー {@value} */ 116 public static final String CMD_ENTRY = "ENTRY" ; 117 118 /** command 引数に渡す事の出来る コマンド リスト */ 119 private static final String COMMAND_LIST = CMD_ENTRY; 120 121 // 3.5.6.0 (2004/06/18) すべてを protected から private に変更します。 122 private transient DBTableModel table = null; 123 private transient ErrorMessage errMessage = null; 124 private String tableId = HybsSystem.TBL_MDL_KEY; 125 // 4.0.0.0 (2007/10/10) dbid の初期値を、"DEFAULT" から null に変更 126 private String dbid = null; 127 private String command = CMD_ENTRY; 128 private String sql = null; 129 private String names = null; 130 private String from = null; 131 private String where = null; 132 private String exist = "auto"; 133 private boolean errRemove = false; 134 135 /** 136 * Taglibの開始タグが見つかったときに処理する doStartTag() を オーバーライドします。 137 * 138 * @og.rev 3.7.1.0 (2005/04/15) notuse 値を追加 139 * 140 * @return 後続処理の指示(SKIP_BODY) 141 */ 142 @Override 143 public int doStartTag() { 144 if( !"notuse".equalsIgnoreCase( exist ) ) { 145 table = (DBTableModel)getObject( tableId ); 146 if( table != null && table.getRowCount() > 0 && check( command, COMMAND_LIST ) ) { 147 sql = makeSQLString(); 148 execute( sql ); 149 } 150 } 151 152 return SKIP_BODY ; // Body を評価しない 153 } 154 155 /** 156 * Taglibの終了タグが見つかったときに処理する doEndTag() を オーバーライドします。 157 * 158 * @og.rev 3.5.4.2 (2003/12/15) HTMLTableViewForm クラス名変更(⇒ ViewForm_HTMLTable) 159 * @og.rev 3.5.4.4 (2004/01/16) エラー結果を表示するテーブル形式のフォーム修正 160 * @og.rev 3.5.5.2 (2004/04/02) TaglibUtil.makeHTMLErrorTable メソッドを利用 161 * 162 * @return 後続処理の指示 163 */ 164 @Override 165 public int doEndTag() { 166 debugPrint(); // 4.0.0 (2005/02/28) 167 168 int rtnCode = EVAL_PAGE; 169 170 // 6.0.0.1 (2014/04/18) These nested if statements could be combined 171 if( CMD_ENTRY.equals( command ) && errMessage != null && ! errMessage.isOK() && !errRemove ) { 172 rtnCode = SKIP_PAGE ; 173 jspPrint( TaglibUtil.makeHTMLErrorTable( errMessage,getResource() ) ); 174 } 175 176 return rtnCode ; 177 } 178 179 /** 180 * タグリブオブジェクトをリリースします。 181 * キャッシュされて再利用されるので、フィールドの初期設定を行います。 182 * 183 * @og.rev 4.0.0.0 (2007/10/10) dbid の初期値を、"DEFAULT" から null に変更 184 */ 185 @Override 186 protected void release2() { 187 super.release2(); 188 tableId = HybsSystem.TBL_MDL_KEY; 189 dbid = null; 190 command = CMD_ENTRY; 191 table = null; 192 sql = null; 193 names = null; 194 errMessage = null; 195 exist = "auto"; 196 errRemove = false; 197 } 198 199 /** 200 * SQL文を構築します。 201 * 202 * @return 構築された、SQL文 203 */ 204 private String makeSQLString() { 205 StringBuilder rtn = new StringBuilder( HybsSystem.BUFFER_MIDDLE ); 206 rtn.append( "select count(*) from " ); 207 rtn.append( from ); 208 rtn.append( " where " ); 209 rtn.append( where ); 210 211 return rtn.toString(); 212 } 213 214 /** 215 * Query を実行します。 216 * 217 * @param sql 検索文字列 218 * 219 * @og.rev 3.8.6.0 (2006/09/29) exist 属性の one を 「one:ひとつのみ」から「one:ひとつ以下」に変更 220 * @og.rev 3.8.7.0 (2006/12/15) アクセスログ取得の為,ApplicationInfoオブジェクトを設定 221 * @og.rev 4.0.0.0 (2005/01/31) getParameterRows() を使用するように変更 222 * @og.rev 4.0.0.0 (2007/11/28) 論理処理の不具合修正(カッコの付ける位置間違い) 223 */ 224 private void execute( final String sql ) { 225 errMessage = new ErrorMessage( "Database Exist Data Error!" ); 226 227 final String query ; 228 final int[] clmNo ; 229 230 int[] rowNo = getParameterRows(); // 4.0.0 (2005/01/31) 231 if( rowNo.length == 0 ) { return; } 232 233 // names なしの場合は、Query より取得する。 4.0.0 (2005/01/31) 234 if( names == null ) { 235 Formatter format = new Formatter( table ); 236 format.setFormat( sql ); 237 query = format.getQueryFormatString(); 238 clmNo = format.getClmNos(); 239 names = StringUtil.array2csv( table.getNames() ); 240 } 241 else { 242 clmNo = getTableColumnNo( StringUtil.csv2Array( names ) ); 243 query = sql; 244 } 245 246 int row; 247 boolean okFlag ; 248 List<Integer> list = new ArrayList<Integer>(); 249 String[] values ; 250 for( int j=0; j<rowNo.length; j++ ) { 251 okFlag = true; 252 row = rowNo[j]; 253 values = getTableModelData( clmNo,row ); 254 int cnt = DBUtil.dbExist( query,values,getApplicationInfo(),dbid ); 255 256 String modifyType = table.getModifyType( row ); 257 if( ( "true".equalsIgnoreCase( exist ) || 258 ( "auto".equalsIgnoreCase( exist ) && ( 259 DBTableModel.UPDATE_TYPE.equals( modifyType ) || 260 DBTableModel.DELETE_TYPE.equals( modifyType ) ) ) ) && cnt <= 0 ) { 261 // ERR0025=データ未登録エラー。キー={0}、値={1} のデータは、存在していません。 262 String vals = StringUtil.array2csv( values ); 263 errMessage.addMessage( row,ErrorMessage.NG,"ERR0025",names,vals ); 264 okFlag = false; 265 } 266 // 4.0.0.0 (2007/11/28) 論理処理の不具合修正(カッコの付ける位置間違い) 267 else if( ( "false".equalsIgnoreCase( exist ) || 268 ( "auto".equalsIgnoreCase( exist ) && 269 DBTableModel.INSERT_TYPE.equals( modifyType ) ) ) && cnt > 0 ) { 270 // ERR0026=データ登録済みエラー。キー={0}、値={1} のデータは、すでに存在しています。 271 String vals = StringUtil.array2csv( values ); 272 errMessage.addMessage( row,ErrorMessage.NG,"ERR0026",names,vals ); 273 okFlag = false; 274 } 275 else if( "one".equalsIgnoreCase( exist ) && cnt > 1 ) { 276 // ERR0027=データ2重登録エラー。キー={0}、値={1} のデータは、重複して存在しています。 277 String vals = StringUtil.array2csv( values ); 278 errMessage.addMessage( row,ErrorMessage.NG,"ERR0027",names,vals ); 279 okFlag = false; 280 } 281 if( errRemove && okFlag ) { list.add( row ); } 282 } 283 if( errRemove ) { 284 Integer[] in = list.toArray( new Integer[list.size()] ); 285 int[] newRowNo = new int[in.length]; 286 for( int i=0; i<in.length; i++ ) { 287 newRowNo[i] = in[i].intValue(); 288 } 289 setParameterRows( newRowNo ); 290 } 291 } 292 293 /** 294 * 【廃止】(通常は使いません)結果をDBTableModelに書き込んで、sessionに登録するときのキーを指定します。 295 * 296 * @og.tag 297 * (初期値:HybsSystem#TBL_MDL_KEY[={@og.value org.opengion.hayabusa.common.HybsSystem#TBL_MDL_KEY}])。 298 * 299 * @param id sessionに登録する時の ID 300 * @deprecated クラスが廃止されました。 301 */ 302 @Deprecated public void setTableId( final String id ) { 303 tableId = nval( getRequestParameter( id ),tableId ); // 3.8.0.9 (2005/10/17) 304 } 305 306 /** 307 * 【廃止】(通常は使いません)Queryオブジェクトを作成する時のDB接続IDを指定します。 308 * 309 * @og.tag Queryオブジェクトを作成する時のDB接続IDを指定します。 310 * 311 * @param id データベース接続ID 312 * @deprecated クラスが廃止されました。 313 */ 314 @Deprecated public void setDbid( final String id ) { 315 dbid = nval( getRequestParameter( id ),dbid ); 316 } 317 318 /** 319 * 【廃止】コマンド(ENTRY)をセットします。 320 * 321 * @og.tag 322 * コマンドは,HTMLから(get/post)指定されますので,CMD_xxx で設定される 323 * フィールド定数値のいづれかを、指定できます。 324 * 325 * @param cmd コマンド(public static final 宣言されている文字列) 326 * @see <a href="../../../../constant-values.html#org.opengion.hayabusa.taglib.TableExistTag.CMD_NEW">コマンド定数</a> 327 * @deprecated クラスが廃止されました。 328 */ 329 @Deprecated public void setCommand( final String cmd ) { 330 String cmd2 = getRequestParameter( cmd ); 331 if( cmd2 != null && cmd2.length() > 0 ) { command = cmd2.toUpperCase(Locale.JAPAN); } 332 } 333 334 /** 335 * 【廃止】引数にセットすべき データの名称(カラム名)をCSV形式で複数指定します。 336 * 337 * @og.tag 338 * 複数ある場合は、カンマ区切り文字で渡します。 339 * 引数をnames ではなく、[カラム名]形式で直接指定するほうが、SQL文が判りやすくなります。 340 * 341 * @param nm 引数の名称(複数ある場合は、カンマ区切り文字) 342 * @deprecated クラスが廃止されました。 343 */ 344 @Deprecated public void setNames( final String nm ) { 345 names = nval( getRequestParameter( nm ),names ); 346 } 347 348 /** 349 * 【廃止】チェックするデータベース名(from 句)を指定します。 350 * 351 * @og.tag 352 * from 句 に指定するデータベース名です。 353 * 354 * @param fm データベースID 355 * @deprecated クラスが廃止されました。 356 */ 357 @Deprecated public void setFrom( final String fm ) { 358 from = nval( getRequestParameter( fm ),from ); 359 } 360 361 /** 362 * 【廃止】チェックする検索条件(where句)を指定します。 363 * 364 * @og.tag 365 * where 区 に指定する検索条件です。? の部分に、names 属性で指定した 366 * カラムのデータが、DBTableModelより取り出されて適用されます。 367 * または、[カラム名]形式で、直接指定することもできます。その場合は、 368 * name 属性は指定する必要がありません。 369 * [カラム名]の前後に、(')シングルコーテーションは、不要です。 370 * 371 * @param wr 検索条件(where句) 372 * @deprecated クラスが廃止されました。 373 */ 374 @Deprecated public void setWhere( final String wr ) { 375 where = nval( getRequestParameter( wr ),where ); 376 } 377 378 /** 379 * 【廃止】データベースのチェック方法(auto/true/false/one/notuse)を指定します(初期値:「auto:自動」)。 380 * 381 * @og.tag 382 * exist 属性に指定された 、「true:存在する」、「false:存在しない」、「one:ひとつ以下」、 383 * の値は、いずれの場合も、成立時は、正常とみなします。 384 * 「auto:自動」は、DBTableModeleのmodifyType(A,C,D)に応じて、チェックします。 385 * A,C,D は、entryタグにコマンドを渡してデータを作成したときに、内部で作成されます。 386 * notuse は、チェックを行いません。これは、このタグを共有使用する場合に、外部で 387 * チェックを行うかどうかを指定できるようにするために使用します。 388 * (「true:存在する」 には、データが存在した場合に、OKで、なければエラーです。) 389 * 初期値は、「auto:自動」です。 390 * 391 * @param ext チェック方法(「auto:自動」、「true:存在する」、「false:存在しない」、「one:ひとつ以下」、「notuse:チェックしない」) 392 * @deprecated クラスが廃止されました。 393 */ 394 @Deprecated public void setExist( final String ext ) { 395 exist = nval( getRequestParameter( ext ),exist ); 396 if( !"auto".equalsIgnoreCase( exist ) && 397 !"true".equalsIgnoreCase( exist ) && 398 !"false".equalsIgnoreCase( exist ) && 399 !"one".equalsIgnoreCase( exist ) && 400 !"notuse".equalsIgnoreCase( exist ) ) { 401 String errMsg = "exist 属性は、(auto,true,false,one,notuse)を指定してください。 [" + exist + "]" + HybsSystem.CR ; 402 throw new HybsSystemException( errMsg ); 403 } 404 } 405 406 /** 407 * 【廃止】エラー時の選択行を取り除いて継続処理を行うかどうか[true/false]を指定します(初期値:false)。 408 * 409 * @og.tag 410 * exist 属性に指定された 、「true:存在する」、「false:存在しない」、「one:ひとつ以下」、 411 * に対して、エラーが発生した選択行番号を、取り除いて以下の処理を継続するかどうかを 412 * 指定します。 413 * true に設定した場合は、エラーデータを削除し、継続処理を行うことができます。 414 * flase の場合は、エラーデータを表示して、継続処理を停止します。 415 * 初期値は、「false:エラー時停止」です。 416 * 417 * @param flag エラー時の継続処理 [true:エラー行番号を取り除き継続処理/false:エラー時停止] 418 * @deprecated クラスが廃止されました。 419 */ 420 @Deprecated public void setErrRemove( final String flag ) { 421 errRemove = nval( getRequestParameter( flag ),errRemove ); 422 } 423 424 /** 425 * カラム名配列(String[])より、対応するカラムNo配列(int[])を作成します。 426 * 427 * @param nameArray カラム名配列 428 * 429 * @return カラムNo配列 430 */ 431 private int[] getTableColumnNo( final String[] nameArray ) { 432 int[] clmNo = new int[ nameArray.length ]; 433 for( int i=0; i<clmNo.length; i++ ) { 434 clmNo[i] = table.getColumnNo( nameArray[i] ); 435 } 436 return clmNo; 437 } 438 439 /** 440 * 指定の行番号の、カラムNo配列(int[])に対応した値の配列を返します。 441 * 442 * 表示データの HybsSystem.ROW_SEL_KEY を元に、選ばれた 行を 443 * 処理の対象とします。 444 * 445 * @param clmNo カラムNo配列 446 * @param row 行番号 447 * 448 * @return 行番号とカラムNo配列に対応した、値の配列 449 */ 450 private String[] getTableModelData( final int[] clmNo,final int row ) { 451 String[] values = new String[ clmNo.length ]; 452 for( int i=0; i<values.length; i++ ) { 453 values[i] = table.getValue( row,clmNo[i] ) ; 454 } 455 return values; 456 } 457 458 /** 459 * シリアライズ用のカスタムシリアライズ書き込みメソッド 460 * 461 * @og.rev 4.0.0.0 (2006/09/31) 新規追加 462 * @serialData 一部のオブジェクトは、シリアライズされません。 463 * 464 * @param strm ObjectOutputStreamオブジェクト 465 * @throws IOException 入出力エラーが発生した場合 466 */ 467 private void writeObject( final ObjectOutputStream strm ) throws IOException { 468 strm.defaultWriteObject(); 469 } 470 471 /** 472 * シリアライズ用のカスタムシリアライズ読み込みメソッド 473 * 474 * ここでは、transient 宣言された内部変数の内、初期化が必要なフィールドのみ設定します。 475 * 476 * @og.rev 4.0.0.0 (2006/09/31) 新規追加 477 * @serialData 一部のオブジェクトは、シリアライズされません。 478 * 479 * @param strm ObjectInputStreamオブジェクト 480 * @see #release2() 481 * @throws IOException シリアライズに関する入出力エラーが発生した場合 482 * @throws ClassNotFoundException クラスを見つけることができなかった場合 483 */ 484 private void readObject( final ObjectInputStream strm ) throws IOException , ClassNotFoundException { 485 strm.defaultReadObject(); 486 } 487 488 /** 489 * このオブジェクトの文字列表現を返します。 490 * 基本的にデバッグ目的に使用します。 491 * 492 * @return このクラスの文字列表現 493 */ 494 @Override 495 public String toString() { 496 return org.opengion.fukurou.util.ToString.title( this.getClass().getName() ) 497 .println( "VERSION" ,VERSION ) 498 .println( "tableId" ,tableId ) 499 .println( "dbid" ,dbid ) 500 .println( "command" ,command ) 501 .println( "sql" ,sql ) 502 .println( "names" ,names ) 503 .println( "from" ,from ) 504 .println( "where" ,where ) 505 .println( "exist" ,exist ) 506 .println( "CMD_ENTRY" ,CMD_ENTRY ) 507 .println( "Other..." ,getAttributes().getAttribute() ) 508 .fixForm().toString() ; 509 } 510}