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 */ 016 package org.opengion.hayabusa.report; 017 018 import org.opengion.hayabusa.common.HybsSystem; 019 import org.opengion.hayabusa.common.HybsSystemException; 020 import org.opengion.fukurou.util.LogWriter; 021 import org.opengion.hayabusa.db.DBTableModel; 022 import org.opengion.hayabusa.db.DBColumn; 023 import org.opengion.hayabusa.resource.ResourceManager; 024 import org.opengion.fukurou.util.StringUtil; 025 import org.opengion.fukurou.util.FileUtil; 026 import org.opengion.fukurou.util.Closer ; 027 028 import java.io.File; 029 import java.io.BufferedReader; 030 import java.io.PrintWriter; 031 032 /** 033 * DBTableReport インターフェース の?ォルト実?ラスです? 034 * writeReport() を?オーバ?ライドすれ??各種出力フォーマットに合わせた 035 * サブクラスを実現する事が可能です? 036 * 037 * @og.group 帳票シス? 038 * 039 * @version 4.0 040 * @author Kazuhiko Hasegawa 041 * @since JDK5.0, 042 */ 043 public abstract class AbstractDBTableReport implements DBTableReport { 044 private static final String ENCODE = HybsSystem.REPORT_ENCODE ; 045 046 protected String[] headerKeys = null; // 固定部の key 部??する?カンマで??できる? 047 protected String[] headerVals = null; // 固定部の key に対応する?を指定する? 048 protected String[] footerKeys = null; // 繰り返し部の終?に表示する key 部??する?カンマで??できる? 049 protected String[] footerVals = null; // 繰り返し部の終?に表示する key に対する値を指定する? 050 protected boolean pageEndCut = false; // ボディー部(繰り返し部)がなくなったときに、それ以降?ペ?ジを?力するか?する? 051 protected int maxRowCount = 0; // 自動計算方式を採用 052 protected int pageRowCount = 0; // 過去のペ?ジの?件数?3.7.0.1 (2005/01/31) 053 protected int lineCopyCnt = 0; // LINE_COPY した際??行番号?4.0.0 (2007/06/08) 054 protected ResourceManager resource = null; // 4.0.0 (2005/01/31) 055 protected PrintWriter writer = null; 056 protected BufferedReader reader = null; 057 protected File templateFile = null; // 3.8.0.0 (2005/06/07) 058 protected File firstTemplateFile = null; // 3.8.0.0 (2005/06/07) 059 protected String htmlDir = null; 060 protected String htmlFileKey = null; 061 protected String ykno = null; // 3.8.5.1 (2006/04/28) 追? 062 protected DBTableModel table = null; 063 064 protected int pageCount = 0; 065 protected int maxPageCount = 1000; 066 protected boolean rowOver = false; // ??タ件数??カラ?要求されると、true にセ?される? 067 protected boolean dataOver = false; // 3.8.1.2 (2005/12/19) ??タがなくなると、true にセ?される? 068 069 // 3.6.0.0 (2004/09/24) フォーマットエラーの判?formatErr)を?子クラスから移動します? 070 private boolean formatErr = false; // フォーマットエラーの判? 071 072 // 3.6.1.0 (2005/01/05) 帳票??追? 073 protected String listId = null; 074 075 // 3.7.0.1 (2005/01/31) ペ?ジブレイク時?処? 076 private static final String PAGEBREAK = "PAGEBREAK"; 077 private int pbClmNo = -1; // PAGEBREAK カラ??番号 078 private boolean pageBreak = false; // PAGEBREAK = "1" が見つかった時、true 079 private int tableSize = 0; 080 081 /** 082 * DBTableModel から ??タを作?して,PrintWriter に書き?します? 083 * 084 */ 085 public void writeReport() { 086 setHeaderFooter(); 087 initReader(); 088 initWriter(); 089 String str ; 090 while( (str = readLine()) != null ) { 091 println( changeData( str ) ); 092 } 093 close(); 094 } 095 096 /** 097 * 入力文字? を読み取って、?力します? 098 * tr タグを目印に??trタグ?ずつ取り出します? 099 * 読み取りを終?る?合?、null を返します? 100 * ?ブクラスで実?てください? 101 * 102 * @return 出力文字? 103 */ 104 abstract protected String readLine() ; 105 106 /** 107 * 入力文字? を加工して、?力します? 108 * {@XXXX} をテーブルモ?より読み取り、?をセ?します? 109 * ?ブクラスで実?てください? 110 * 111 * @param inLine 入力文字? 112 * 113 * @return 出力文字? 114 */ 115 abstract protected String changeData( final String inLine ) ; 116 117 /** 118 * 入力文字? を読み取って、?力します? 119 * ?ブクラスで実?てください? 120 * 121 * @param line 出力文字? 122 */ 123 abstract protected void println( final String line ) ; 124 125 /** 126 * リソースマネージャーをセ?します? 127 * これは、??ロケール)に応じ?DBColumn をあらかじめ設定しておく為に 128 * ?です? 129 * リソースマネージャーが設定されて???また?、所定?キーの DBColumn ? 130 * リソースに存在しな??合?、?部で DBColumn オブジェクトを作?します? 131 * 132 * @og.rev 4.0.0.0 (2005/01/31) lang ?ResourceManager へ変更 133 * 134 * @param resource リソースマネージャー 135 */ 136 public void setResourceManager( final ResourceManager resource ) { 137 this.resource = resource; 138 } 139 140 /** 141 * 帳票?? をセ?します? 142 * こ?帳票??を利用して、画像ファイル等?セーブディレクトリを求めます? 143 * 144 * @og.rev 3.6.1.0 (2005/01/05) 新規作? 145 * 146 * @param listId 帳票?? 147 */ 148 public void setListId( final String listId ) { 149 this.listId = listId ; 150 } 151 152 /** 153 * DBTableModel をセ?します? 154 * 155 * @og.rev 3.7.0.1 (2005/01/31) ペ?ジブレイク時?処? 156 * 157 * @param table DBTableModelオブジェク? 158 */ 159 public void setDBTableModel( final DBTableModel table ) { 160 this.table = table; 161 // 3.7.0.1 (2005/01/31) ペ?ジブレイク時?処? 162 tableSize = table.getRowCount(); 163 pbClmNo = table.getColumnNo( PAGEBREAK,false ); // 存在しな??合??1 164 165 // try { 166 // pbClmNo = table.getColumnNo( PAGEBREAK ); 167 // } 168 // catch( HybsSystemException e ) { 169 // pbClmNo = -1; 170 // } 171 } 172 173 /** 174 * 雛型ファイル名をセ?します? 175 * 176 * @og.rev 3.6.0.0 (2004/09/17) メソ?名?変更。setInputFile ?setTemplateFile 177 * @og.rev 3.8.0.0 (2005/06/07) 引数?String ?File に変更 178 * 179 * @param inFile 雛型ファイル? 180 */ 181 public void setTemplateFile( final File inFile ) { 182 templateFile = inFile; 183 } 184 185 /** 186 * ??のペ?ジのみに使用する雛型ファイル名をセ?します? 187 * 188 * @og.rev 3.6.0.0 (2004/09/17) 新規追? 189 * @og.rev 3.8.0.0 (2005/06/07) 引数?String ?File に変更 190 * 191 * @param inFile ??のペ?ジの雛型ファイル? 192 */ 193 public void setFirstTemplateFile( final File inFile ) { 194 firstTemplateFile = inFile; 195 } 196 197 /** 198 * 変換後ファイルを?力するディレクトリ名をセ?します? 199 * ?レクトリが存在しな??合?、新規に作?します? 200 * 201 * @og.rev 3.7.1.1 (2005/05/23) フォル?な??合?、?階層??フォル?自動で作?します? 202 * 203 * @param outDir 出力ディレクトリ 204 */ 205 public void setOutputDir( final String outDir ) { 206 htmlDir = outDir; 207 208 File dir = new File(htmlDir); 209 if( ! dir.exists() && ! dir.mkdirs() ) { 210 String errMsg = "?レクトリの作?に失敗しました?" + htmlDir + "]"; 211 throw new HybsSystemException( errMsg ); 212 } 213 } 214 215 /** 216 * 変換後ファイルキーをセ?します? 217 * キーとは、拡張子?無?態までのファイル名です? 218 * 変換後ファイルは、?発生します? 219 * 実際に出力されるファイル名?、outFile + "_連番.html" となります? 220 * 221 * @param outFile 出力ファイル名?共通部 222 */ 223 public void setOutputFileKey( final String outFile ) { 224 htmlFileKey = outFile; 225 } 226 227 /** 228 * 帳票起動された要求番号をセ?します? 229 * 230 * @og.rev 3.8.5.1 (2006/04/28) 新規追? 231 * 232 * @param ykno 要求番号 233 */ 234 public void setYkno( final String ykno ) { 235 this.ykno = ykno; 236 } 237 238 /** 239 * 固定部の key 部??します? 240 * カンマで??できます? 241 * 242 * @og.rev 3.5.6.0 (2004/06/18) 配?の設定?、arraycopy して取り込みます? 243 * 244 * @param hKeys 固定部のキー 245 */ 246 public void setHeaderKeys( final String[] hKeys ) { 247 if( hKeys != null ) { 248 int size = hKeys.length ; 249 headerKeys = new String[size]; 250 System.arraycopy( hKeys,0,headerKeys,0,size ); 251 } 252 else { 253 headerKeys = null; 254 } 255 } 256 257 /** 258 * 固定部のkey に対応する?を指定します? 259 * カンマで??で、リクエスト情報でも設定できます? 260 * 261 * @og.rev 3.5.6.0 (2004/06/18) 配?の設定?、arraycopy して取り込みます? 262 * 263 * @param hVals 固定部の値 264 */ 265 public void setHeaderVals( final String[] hVals ) { 266 if( hVals != null ) { 267 int size = hVals.length ; 268 headerVals = new String[size]; 269 System.arraycopy( hVals,0,headerVals,0,size ); 270 } 271 else { 272 headerVals = null; 273 } 274 } 275 276 /** 277 * 雛型帳票に対する、実際の行番号を求めます? 278 * これは?型??回読みをサポ?トする為、実際の雛型のrow番号と 279 * DBTableModel から取得すべ?row番号が?異なる為です? 280 * オーバ?フロー時?、Exception を避ける為?1 を返します? 281 * 282 * @og.rev 3.5.6.0 (2004/06/18) noDataflag の追?? 283 * @og.rev 3.5.6.3 (2004/07/12) noDataflag の?? 284 * @og.rev 3.6.0.4 (2004/10/14) FIRST 雛型時?対応追?? 285 * @og.rev 3.7.0.1 (2005/01/31) ペ?ジブレイク処?対応? 286 * @og.rev 3.8.1.2 (2005/12/19) PAGE_END_CUT用にdataOverフラグを追? 287 * 288 * @param row 固定部の値(オーバ?フロー時??1 ) 289 * 290 * @return 実際の行番号 291 */ 292 protected int getRealRow( final int row ) { 293 294 // 3.7.0.1 (2005/01/31) ペ?ジブレイク処?対応? 295 int realRow = pageRowCount + row + lineCopyCnt ; 296 if( maxRowCount <= realRow ) { maxRowCount = realRow + 1; } 297 298 if( realRow >= (tableSize-1) ) { // 行番号が最大値と同じ(??タは存在) 299 rowOver = true; 300 if( realRow >= tableSize ) { // さらに、データは存在しな?? 301 realRow = -1; // 3.5.6.3 (2004/07/12) オーバ?フロー 302 dataOver = true; // 3.8.1.2 (2005/12/19) 303 } 304 } 305 306 return realRow ; 307 } 308 309 /** 310 * ??キーにつ?、その値を取得します? 311 * 値の取得方法として? 312 * ??{@xxx_no} 形式?場合?、DBTableModel から? 313 * ??{@XXXX} 形式で、かつ、rowOver ?false の場合?、??ーから? 314 * ??{@XXXX} 形式で、かつ、rowOver ?true の場合?、フ?ーから? 315 * 取得します? 316 * rowOver は、{@xxx_no} 形式?番号?no)が?DBTableModel の??タ件数より? 317 * 大きい場合に、セ?されます? 318 * 319 * @og.rev 3.5.6.0 (2004/06/18) noDataflag の追?? 320 * @og.rev 3.5.6.3 (2004/07/12) noDataflag の?? 321 * @og.rev 3.6.0.0 (2004/09/24) フォーマットエラーの判?formatErr)を?子クラスから移動します? 322 * @og.rev 3.7.0.1 (2005/01/31) ペ?ジブレイク時?処??? 323 * @og.rev 3.7.0.2 (2005/02/18) HTML のエスケープ文字対? 324 * @og.rev 3.7.1.1 (2005/05/09) セル??改?<br> は、エスケープしな?? 325 * @og.rev 3.8.0.0 (2005/06/07) Shift-JIS で中国語を扱??(Unicodeエスケープ文字?、エスケープしな? 326 * @og.rev 3.8.5.1 (2006/04/28) YKNO を特別扱?る? 327 * 328 * @param key ??キー 329 * 330 * @return ??キーの値 331 */ 332 protected String getValue( final String key ) { 333 if( pageBreak ) { return ""; } // 3.7.0.1 (2005/01/31) ペ?ジブレイク時?処? 334 335 int sp = key.lastIndexOf( '_' ); 336 if( sp >= 0 ) { 337 try { 338 int row = Integer.parseInt( key.substring( sp+1 ) ); 339 int realRow = getRealRow( row ); 340 341 if( realRow >= 0 ) { // 3.5.6.3 (2004/07/12) 342 formatErr = false; // 3.6.0.0 (2004/09/24) 343 int col = table.getColumnNo( key.substring( 0,sp ),false ); 344 if( col < 0 ) { 345 // ?定対策:I 変数で、行番号を?力する? 346 if( "I".equals( key.substring( 0,sp ) ) ) { 347 return String.valueOf( realRow+1 ); // 行番号は物?+? 348 } 349 else { 350 String errMsg = "カラ?が存在しません:[" + key + "]" ; 351 System.out.println( errMsg ); 352 LogWriter.log( errMsg ); 353 return "" ; 354 } 355 } 356 357 String val = table.getValue( realRow,col ); 358 359 // 3.7.0.1 (2005/01/31) ペ?ジブレイク時?処?? 360 if( pbClmNo == col ) { 361 if( ! rowOver ) { 362 String val2 = table.getValue( realRow+1,pbClmNo ); // 先読み 363 if( val != null && ! val.equals( val2 ) ) { 364 pageBreak = true; 365 } 366 } 367 return ""; // ペ?ジブレイクカラ??、すべて""に変換する? 368 } 369 // 3.7.1.1 (2005/05/09) セル??改?<br> は、エスケープしな?? 370 val = StringUtil.htmlFilter( val ); 371 val = StringUtil.replace( val,"<br>","<br>" ); 372 // 3.8.0.0 (2005/06/07) Shift-JIS で中国語を扱??(Unicodeエスケープ文字?、エスケープしな? 373 val = StringUtil.replace( val,"&#","&#" ); // 中国語変換対?&# は変換しな? 374 return table.getDBColumn( col ).getRendererValue( val ); 375 } 376 } 377 catch ( NumberFormatException ex ) { // 4.0.0 (2005/01/31) 378 String errMsg = "警告:??ーに'_'カラ?が使用 " 379 + "key=[" + key + "] " 380 + ex.getMessage() ; 381 LogWriter.log( errMsg ); 382 // フォーマットエラーは、何もしな?? 383 // 通常のカラ?にアン??バ?が使用されて?可能性があるため? 384 } 385 catch ( RuntimeException ex ) { 386 String errMsg = "カラ?ータ取得??、エラーが発生しました? " 387 + "key=[" + key + "] " 388 + ex.getMessage() ; 389 LogWriter.log( errMsg ); 390 // フォーマットエラーは、何もしな?? 391 } 392 } 393 394 // 3.8.5.1 (2006/04/28) YKNO を特別扱?る? 395 if( "YKNO".equals( key ) ) { return ykno; } 396 397 String rtnVal ; 398 if( rowOver ) { rtnVal = getFooterValue( key ); } 399 else { rtnVal = getHeaderValue( key ); } 400 401 if( rtnVal == null ) { rtnVal = ""; } 402 return rtnVal ; 403 } 404 405 /** 406 * 固定部のkey に対応する?を取得します? 407 * 408 * @param key String 409 * 410 * @return 固定部の値 411 */ 412 private String getHeaderValue( final String key ) { 413 if( headerKeys == null || 414 headerVals == null || 415 key == null ) { return null; } 416 417 for( int i=0; i<headerKeys.length; i++ ) { 418 if( key.equals( headerKeys[i] ) ) { return headerVals[i]; } 419 } 420 return null; 421 } 422 423 /** 424 * 繰り返し部の終?に表示する key 部??します? 425 * カンマで??できます? 426 * 427 * @og.rev 3.5.6.0 (2004/06/18) 配?の設定?、arraycopy して取り込みます? 428 * 429 * @param fKeys 繰り返し部の終?に表示する key 430 */ 431 public void setFooterKeys( final String[] fKeys ) { 432 if( fKeys != null ) { 433 int size = fKeys.length ; 434 footerKeys = new String[size]; 435 System.arraycopy( fKeys,0,footerKeys,0,size ); 436 } 437 else { 438 footerKeys = null; 439 } 440 } 441 442 /** 443 * 繰り返し部の終?に表示する key 部?取得します? 444 * 445 * @param key String 446 * 447 * @return 繰り返し部の終?に表示する key 448 */ 449 private String getFooterValue( final String key ) { 450 if( footerKeys == null || 451 footerVals == null || 452 key == null ) { return null; } 453 454 for( int i=0; i<footerKeys.length; i++ ) { 455 if( key.equals( footerKeys[i] ) ) { return footerVals[i]; } 456 } 457 return null; 458 } 459 460 /** 461 * 固定部のkey に対応する?を指定します? 462 * カンマで??で、リクエスト情報でも設定できます? 463 * 464 * @og.rev 3.5.6.0 (2004/06/18) 配?の設定?、arraycopy して取り込みます? 465 * 466 * @param fVals 繰り返し部の終?に表示する値 467 */ 468 public void setFooterVals( final String[] fVals ) { 469 if( fVals != null ) { 470 int size = fVals.length ; 471 footerVals = new String[size]; 472 System.arraycopy( fVals,0,footerVals,0,size ); 473 } 474 else { 475 footerVals = null; 476 } 477 } 478 479 /** 480 * ボディー部(繰り返し部)がなくなったときに、それ以降を表示するかど?を指定します? 481 * true では、それ以降を出力しません? 482 * ?ォル?"true" (なくなった時点で、?力しな??)です? 483 * 484 * @param pageEndCut 繰り返し部の終?に継続??るかど? (true:処?な?false:処?? 485 */ 486 public void setPageEndCut( final boolean pageEndCut ) { 487 this.pageEndCut = pageEndCut ; 488 } 489 490 /** 491 * BufferedReader を?初期化します? 492 * これは?型ファイルの終端まで読取り、??た?合?もう? 493 * 初めから読み込みなおす処?行います? 494 * 基本?、書き込みも?期化する?があります? 495 * 496 * メモリ上に読み込んで、繰り返し利用するかど?は、実?存です? 497 * 498 * @og.rev 3.1.3.0 (2003/04/10) "DEFAULT" エンコー?ング名?サポ?トを?? 499 * @og.rev 3.5.5.9 (2004/06/07) FileUtil.getBufferedReader を使用 500 * @og.rev 3.6.0.0 (2004/09/17) ??のペ?ジのみに使用する雛型ファイル名を追?ます? 501 * @og.rev 3.6.0.0 (2004/09/24) フォーマットエラーの判?formatErr)を?子クラスから移動します? 502 * 503 */ 504 protected void initReader() { 505 Closer.ioClose( reader ); // 4.0.0 (2006/01/31) close 処?の IOException を無? 506 507 if( reader == null && firstTemplateFile != null ) { 508 reader = FileUtil.getBufferedReader(firstTemplateFile,ENCODE); 509 } 510 else { 511 if( formatErr ) { 512 String errMsg = "Error in HTML File. " + HybsSystem.CR 513 + "Excel containing two or more sheets is not supporting." 514 + HybsSystem.CR 515 + "or HTML template File is not in '{@xxxx_0}' key word." ; 516 throw new HybsSystemException( errMsg ); 517 } 518 reader = FileUtil.getBufferedReader(templateFile,ENCODE); 519 formatErr = true; // 初期化します?クリアしなければエラー 520 } 521 } 522 523 /** 524 * PrintWriter を?初期化します? 525 * これは?型ファイルを終端まで読取り、??た?合?出力ファイル名を 526 * 変えて、別ファイルとして出力する為のも?です? 527 * 基本?、読取も初期化する?があります? 528 * 529 * メモリ上に読み込んで、繰り返し利用するかど?は、実?存です? 530 * 531 * @og.rev 3.0.0.1 (2003/02/14) ペ?ジの?ペ?ジ数の制限を追??暴走停止用 532 * @og.rev 3.1.3.0 (2003/04/10) "DEFAULT" エンコー?ング名?サポ?トを?? 533 * @og.rev 3.5.5.9 (2004/06/07) FileUtil.getPrintWriter メソ?を使用 534 * @og.rev 3.7.0.1 (2005/01/31) ペ?ジブレイク処?対応? 535 * @og.rev 3.8.0.0 (2005/06/07) FileUtil#getPrintWriter を利用? 536 * @og.rev 3.8.5.3 (2006/06/30) EXCEL?シート数のエラーメ?ージを変更? 537 * 538 */ 539 protected void initWriter() { 540 if( writer != null ) { 541 writer.flush(); 542 writer.close(); 543 writer = null; 544 pageCount++ ; 545 if( pageCount >= maxPageCount ) { 546 String errMsg = "EXCELのペ?ジ(シー?が最大ペ?ジ数(1000)をオーバ?しました? 547 + HybsSystem.CR 548 + "こ?数は、DB_MAX_ROW_COUNT ではなく?LISTID_999.htmlのオーバ?を意味します?" 549 + HybsSystem.CR; 550 throw new HybsSystemException( errMsg ); 551 } 552 } 553 554 int pgCnt = pageCount + 1000; // 桁合わせの為、下3桁を利用します? 555 556 String subName = String.valueOf( pgCnt ).substring( 1 ); 557 String filename = htmlFileKey + "_" + subName + ".html" ; 558 559 // 3.8.0.0 (2005/06/07) FileUtil#getPrintWriter を利用? 560 writer = FileUtil.getPrintWriter( new File( htmlDir,filename ),ENCODE ); 561 562 // 3.7.0.1 (2005/01/31) ペ?ジブレイク時?処? 563 pageRowCount = maxRowCount ; // そ?ペ?ジの頭の??タ行数をセ? 564 pageBreak = false; // pageBreak フラグを?に戻す? 565 } 566 567 /** 568 * ヘッ??フッターのレン?ー??タを設定します? 569 * カンマで??で、リクエスト情報でも設定できます? 570 * 571 */ 572 protected void setHeaderFooter() { 573 574 DBColumn clm ; 575 if( headerKeys != null ) { 576 for( int i=0; i<headerKeys.length; i++ ) { 577 clm = resource.getDBColumn( headerKeys[i] ); 578 if( clm != null ) { 579 headerVals[i] = clm.getRendererValue( headerVals[i] ); 580 } 581 } 582 } 583 584 if( footerKeys != null ) { 585 for( int i=0; i<footerKeys.length; i++ ) { 586 clm = resource.getDBColumn( footerKeys[i] ); 587 if( clm != null ) { 588 footerVals[i] = clm.getRendererValue( footerVals[i] ); 589 } 590 } 591 } 592 } 593 594 /** 595 * リー??、ライターの終???行います? 596 * 597 */ 598 private void close() { 599 if( writer != null ) { 600 writer.flush(); 601 writer.close(); 602 writer = null; 603 } 604 Closer.ioClose( reader ); // 4.0.0 (2006/01/31) close 処?の IOException を無? 605 reader = null; 606 } 607 }