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             * ??{&#064;xxx_no} 形式?場合?、DBTableModel から?
313             * ??{&#064;XXXX} 形式で、かつ、rowOver ?false の場合?、??ーから?
314             * ??{&#064;XXXX} 形式で、かつ、rowOver ?true の場合?、フ?ーから?
315             * 取得します?
316             * rowOver は、{&#064;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,"&lt;br&gt;","<br>" );
372                                            // 3.8.0.0 (2005/06/07) Shift-JIS で中国語を扱??(Unicodeエスケープ文字?、エスケープしな?
373                                            val = StringUtil.replace( val,"&amp;#","&#" );  // 中国語変換対?&amp;# は変換しな?
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    }