    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.report;
    017
    018import org.opengion.hayabusa.common.HybsSystem;
    019import org.opengion.hayabusa.common.HybsSystemException;
    020import org.opengion.fukurou.util.Closer ;
    021
    022import org.apache.poi.poifs.filesystem.POIFSFileSystem;
    023import org.apache.poi.hssf.usermodel.HSSFWorkbook;
    024import org.apache.poi.hssf.usermodel.HSSFSheet;
    025import org.apache.poi.hssf.usermodel.HSSFRow;
    026import org.apache.poi.hssf.usermodel.HSSFCell;
    027import org.apache.poi.hssf.usermodel.HSSFRichTextString;
    028
    029import java.io.FileInputStream;
    030import java.io.FileOutputStream;
    031import java.io.IOException;
    032
    033import java.util.regex.Pattern;
    034import java.util.regex.Matcher;
    035
    036/**
    037 * DBTableReport インターフェース を実装したネイティブEXCEL形式で出力するクラスです。
    038 * AbstractDBTableReport を継承していますので，writeReport() のみオーバーライドして，
    039 * 固定長文字ファイルの出力機能を実現しています。
    040 *
    041 * @og.group 帳票システム
    042 *
    043 * @version  4.0
    044 * @author   Kazuhiko Hasegawa
    045 * @since    JDK5.0,
    046 */
    047public class DBTableReport_Excel extends AbstractDBTableReport {
    048
    049        private static final String EXCEL_FILE_EXT        = ".xls";
    050        private static final Pattern PATTERN_KEY =
    051                          Pattern.compile("\\{@((\\w+?)(?:_(\\d+?))?)\\}", Pattern.MULTILINE);
    052
    053        // POIの解析した式の中に変な属性が付けられて、これを取り除く(patternExcludeInFormula)
    054        private static final Pattern PATTERN_EXIN =
    055                          Pattern.compile("ATTR\\(semiVolatile\\)", Pattern.MULTILINE);
    056
    057        private HSSFWorkbook wb = null;
    058
    059        /**
    060         * DBTableModel から データを作成して,PrintWriter に書き出します。
    061         *
    062         */
    063        @Override
    064        public void writeReport() {
    065                setHeaderFooter();
    066                initReader();
    067                initWriter();
    068                changeSheet();
    069                close();
    070        }
    071
    072        /**
    073         * POIFSFileSystem を、初期化します。
    074         * これは、雛型ファイルの終端まで読取り、処理した場合、もう一度
    075         * 初めから読み込みなおす処理を行います。
    076         * 基本的に、書き込みも初期化する必要があります。
    077         *
    078         * メモリ上に読み込んで、繰り返し利用するかどうかは、実装依存です。
    079         *
    080         */
    081        @Override
    082        protected void initReader() {
    083                if( null != wb ) { wb = null; }
    084
    085                FileInputStream  istream = null;
    086                try {
    087                        istream = new FileInputStream(templateFile);
    088                        POIFSFileSystem fs = new POIFSFileSystem(istream);
    089                        wb = new HSSFWorkbook(fs);
    090                }
    091                catch( IOException ex ) {
    092                        String errMsg = "ファイル名がオープン出来ませんでした。"
    093                                                + HybsSystem.CR
    094                                                + "  File:" + templateFile;
    095                        throw new HybsSystemException( errMsg,ex );             // 3.5.5.4 (2004/04/15) 引数の並び順変更
    096                }
    097                finally {
    098                        Closer.ioClose( istream );      // 4.0.0 (2006/01/31) close 処理時の IOException を無視
    099                }
    100        }
    101
    102        /**
    103         * FileOutputStream を、初期化します。
    104         * これは、雛型ファイルを終端まで読取り、処理した場合、出力ファイル名を
    105         * 変えて、別ファイルとして出力する為のものです。
    106         * 基本的に、読取も初期化する必要があります。
    107         *
    108         * 現在の所、POIはメモリ上にExcelファイルを作成する為、作成したファイルの書く込むを
    109         * ファイル閉じる時点に伸ばされます。
    110         *
    111         */
    112        @Override
    113        protected void initWriter() {
    114                // ここでは処理を行いません。
    115        }
    116
    117        /**
    118         * リーダー、ライターの終了処理を行います。
    119         * このメソッドが呼ばれたタイミングで、実際にファイル出力を行います。
    120         *
    121         */
    122        protected void close() {
    123
    124                String filename = htmlDir + HybsSystem.FS + htmlFileKey + EXCEL_FILE_EXT ;
    125
    126                FileOutputStream fileOut = null;
    127                try {
    128                        // Write the output to a file
    129                        fileOut = new FileOutputStream(filename);
    130                        wb.write(fileOut);
    131                }
    132                catch( IOException ex ) {
    133                        wb = null;
    134                        String errMsg = "ファイル名がオープン出来ませんでした。"
    135                                                + HybsSystem.CR
    136                                                + "  File:" + filename;
    137                        throw new HybsSystemException( errMsg,ex );             // 3.5.5.4 (2004/04/15) 引数の並び順変更
    138                }
    139                finally {
    140                        Closer.ioClose( fileOut );      // 4.0.0 (2006/01/31) close 処理時の IOException を無視
    141                }
    142        }
    143
    144        /**
    145         * Excelの雛型をコピーして、そのシートに帳票データを埋め込みます。
    146         * いろいろな属性がある所に、適切に対応していく予定。
    147         * 各サブクラスで実装してください。
    148         *
    149         * @og.rev 4.3.4.0 (2008/12/01) POI3.2対応
    150         *
    151         */
    152        protected void changeSheet() {
    153                HSSFSheet patternSheet = wb.getSheetAt(0);
    154                while(!rowOver) {
    155                        HSSFSheet sheet2 = wb.cloneSheet(0);
    156        //              HSSFRow oRow2;
    157                        int nFirstRow = sheet2.getFirstRowNum();
    158                        int nLastRow  = sheet2.getLastRowNum();
    159        //              int nTotalRows = patternSheet.getPhysicalNumberOfRows();
    160                        for( int nIndexRow = nFirstRow; nIndexRow <= nLastRow; nIndexRow++) {
    161                                HSSFRow oRow = patternSheet.getRow(nIndexRow);
    162                                if( null != oRow ) {
    163        //                              int nTotalCells = oRow.getPhysicalNumberOfCells();
    164                                        // 4.3.4.0 (2008/12/01) POI3.2対応。shortをintにする。
    165                                        // short nFirstCell = oRow.getFirstCellNum();
    166                                        // short nLastCell  = oRow.getLastCellNum();
    167                                        int nFirstCell = oRow.getFirstCellNum();
    168                                        int nLastCell  = oRow.getLastCellNum();
    169                                        for( int nIndexCell = nFirstCell; nIndexCell <= nLastCell; nIndexCell++) {
    170                                                HSSFCell oCell = oRow.getCell(nIndexCell);
    171                                                if( null != oCell ) { changeCell(oCell);}
    172                                        }
    173                                }
    174                        }
    175                }
    176        }
    177
    178        /**
    179         * セル情報を変更します。
    180         *
    181         * @og.rev 4.3.4.0 (2008/12/01) POI3.2対応
    182         *
    183         * @param oCell HSSFCellオブジェクト
    184         */
    185        protected void changeCell(final HSSFCell oCell) {
    186                String strText;
    187                HSSFRichTextString richText;
    188                int nCellType = oCell.getCellType();
    189                switch(nCellType) {
    190                        case HSSFCell.CELL_TYPE_FORMULA:
    191                                strText = changeData(changeFormulaAttr(oCell.getCellFormula()));
    192                                if( null != strText ) {
    193        //                              oCell.setCellType(HSSFCell.CELL_TYPE_FORMULA);
    194        //                              oCell.setEncoding(HSSFCell.ENCODING_UTF_16);
    195                                        oCell.setCellFormula(strText);
    196                                }
    197                                break;
    198                        case HSSFCell.CELL_TYPE_STRING:
    199        // POI3.0       strText =  changeData(oCell.getStringCellValue());
    200                                richText = oCell.getRichStringCellValue();
    201                                strText =  changeData(richText.getString());
    202                                if( null != strText ) {
    203        //                              oCell.setCellType(HSSFCell.CELL_TYPE_STRING);
    204        // POI3.0               oCell.setEncoding(HSSFCell.ENCODING_UTF_16);
    205        // POI3.2               oCell.setCellValue( strText );  // POI3.0 Deprecation
    206                                        oCell.setCellValue( new HSSFRichTextString(strText) );
    207                                }
    208                                break;
    209        //              case HSSFCell.CELL_TYPE_NUMERIC:
    210        //                      break;
    211        //              case HSSFCell.CELL_TYPE_BOOLEAN:
    212        //                      break;
    213        //              case HSSFCell.CELL_TYPE_ERROR:
    214        //                      break;
    215                        default :
    216                                break;
    217                }
    218        }
    219
    220        /**
    221         * POIで解釈したExcel式の中の変な属性を加工して、出力します。
    222         * いろいろな属性がある所に、適切に対応していく予定。
    223         * 各サブクラスで実装してください。
    224         *
    225         * @param       inLine  入力文字列
    226         *
    227         * @return      出力文字列
    228         */
    229        protected String changeFormulaAttr( final String inLine ) {
    230                // rowOver で、かつ ページブレークかページエンドカットの場合、処理終了。
    231                Matcher  matcher = PATTERN_EXIN.matcher(inLine);
    232                return matcher.find() ? matcher.replaceAll("") : inLine;
    233        }
    234
    235        /**
    236         * 入力文字列 を加工して、出力します。
    237         * データをテーブルモデルより読み取り、値をセットします。
    238         * 各サブクラスで実装してください。
    239         *
    240         * @param       inLine  入力文字列
    241         *
    242         * @return      出力文字列. 文字列の変換は要らない場合、nullを返します
    243         */
    244        @Override
    245        protected String changeData( final String inLine ) {
    246                boolean bFind = false;
    247
    248                // rowOver で、かつ ページブレークかページエンドカットの場合、処理終了。
    249                Matcher  matcher = PATTERN_KEY.matcher(inLine);
    250                StringBuffer sb = new StringBuffer();   // Matcher.appendTail( StringBuffer ) の為
    251
    252                while (matcher.find()) {
    253                        matcher.appendReplacement(sb, getValue(matcher.group( 1 )));
    254                        bFind = true;
    255                }
    256
    257                if( bFind ) {
    258                        matcher.appendTail(sb);
    259                        return sb.toString();
    260                }
    261                else {
    262                        return null;
    263                }
    264        }
    265
    266        /**
    267         * 入力文字列 を読み取って、出力します。
    268         * tr タグを目印に、１行(trタグ間)ずつ取り出します。
    269         * 読み取りを終了する場合は、null を返します。
    270         * 各サブクラスで実装してください。
    271         * ※ このクラスでは実装されていません。
    272         *
    273         * @return      出力文字列
    274         */
    275        @Override
    276        protected String readLine() {
    277                throw new UnsupportedOperationException();
    278        }
    279
    280        /**
    281         * 入力文字列 を読み取って、出力します。
    282         * 各サブクラスで実装してください。
    283         * ※ このクラスでは実装されていません。
    284         *
    285         * @param line 入力文字列
    286         */
    287        @Override
    288        protected void println( final String line ) {
    289                throw new UnsupportedOperationException();
    290        }
    291}