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 }