    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.fukurou.util.Closer ;
    019import org.opengion.fukurou.util.LogWriter;
    020
    021import org.apache.poi.poifs.filesystem.POIFSFileSystem;
    022import org.apache.poi.hssf.eventusermodel.HSSFRequest ;
    023import org.apache.poi.hssf.eventusermodel.HSSFEventFactory;
    024import org.apache.poi.hssf.eventusermodel.HSSFListener ;
    025import org.apache.poi.hssf.record.SSTRecord ;
    026import org.apache.poi.hssf.record.Record ;
    027import org.apache.poi.hssf.record.BOFRecord  ;
    028import org.apache.poi.hssf.record.BoundSheetRecord;
    029import org.apache.poi.hssf.record.LabelSSTRecord;
    030import org.apache.poi.hssf.record.common.UnicodeString;                 // X.X.X.X (2012/XX/XX) POI3.0の場合
    031
    032import java.io.File;
    033import java.io.InputStream;
    034import java.io.FileInputStream;
    035import java.io.IOException;
    036
    037/**
    038 * 【EXCEL取込】雛形EXCELシートの解析処理を行う為の、HSSFListener 拡張クラスです。
    039 * このオブジェクトは、HSSFRequest クラスの addListenerForAllRecords メソッドに渡す
    040 * HSSFListener インターフェースを実装しています。また、雛形EXCEL を処理後、ExcelLayout
    041 * 管理クラスを取得することが出来ます。
    042 *
    043 * @og.rev 3.8.0.0 (2005/06/07) 新規追加
    044 * @og.group 帳票システム
    045 *
    046 * @version  4.0
    047 * @author   Kazuhiko Hasegawa
    048 * @since    JDK5.0,
    049 */
    050public class HybsHSSFListener implements HSSFListener {
    051        private SSTRecord sstrec;
    052        private int       sheetNo = -1;
    053        private int       sheetSize = 0;
    054        private boolean   trace  = false;
    055
    056        private ExcelLayout laynot = null;
    057
    058        /**
    059         * 雛形EXCELの {&#064;カラム} 解析情報を設定します。
    060         *
    061         * 雛形EXCELは、HSSFListener を使用して、イベント駆動で取得します。その場合、
    062         * {&#064;カラム}を含むセルを見つける都度、このメソッドを呼び出して、{&#064;カラム}の
    063         * 位置(行列番号)を設定します。
    064         * データEXCELからデータを読み出す場合は、ここで登録したカラムの行列より、読み込みます。
    065         * 具体的には、HSSFListener#processRecord( Record )で、SSTRecord.sid の 情報をキープしておき、
    066         * LabelSSTRecord.sid 毎に、{&#064;カラム}を含むかチェックし、含む場合に、このメソッドに
    067         * 解析情報を設定します。
    068         *
    069         * @og.rev 4.3.4.0 (2008/12/01) POI3.2対応 引数の型変更(SSTRecord の toString() 化)
    070         *
    071         * @param record Recordオブジェクト
    072         */
    073        public void processRecord( final Record record ) {
    074                switch ( record.getSid() ) {
    075                        // Workbook での シート毎に呼ばれます。先行するため、この回数をシート数として数えます。
    076                        case BoundSheetRecord.sid:
    077                                // 4.0.0.0 (2007/11/29) 入れ子if の統合
    078                                if( trace && record instanceof BoundSheetRecord ) {
    079                                        BoundSheetRecord bsr = (BoundSheetRecord) record;
    080                                        System.out.println("Sheet named: " + bsr.getSheetname() );
    081                                }
    082                                sheetSize ++ ;
    083                                break;
    084                        // TYPE_WORKSHEET の場合、シート開始毎に呼ばれます。
    085                        case BOFRecord.sid:
    086                                if( record instanceof BOFRecord ) {
    087                                        BOFRecord bof = (BOFRecord) record;
    088                                        if(bof.getType() == BOFRecord.TYPE_WORKBOOK) {
    089                                                if( trace ) { System.out.println("Encountered workbook"); }
    090                                        }
    091                                        else if(bof.getType() == BOFRecord.TYPE_WORKSHEET) {
    092                                                // シート開始毎に呼ばれるため、現在のシート番号を得るのに使用します。
    093                                                sheetNo++ ;
    094                                                if( trace ) { System.out.println("Encountered sheet [" + sheetNo + "]" ); }
    095                                        }
    096                                }
    097                                break;
    098                        // すべてのレコードにアクセスするために、一度だけ呼ばれます。ここで初期化しておきます。
    099                        case SSTRecord.sid:
    100                                if( record instanceof SSTRecord ) {
    101                                        sstrec = (SSTRecord) record;
    102                                        laynot = new ExcelLayout( sheetSize );
    103                                        if( trace ) { System.out.println( "SSTRecord:[" + sstrec.getNumUniqueStrings() + "]" ); }
    104                        //              for( int k=0; k<sstrec.getNumUniqueStrings(); k++ )     {
    105                        //                      String val = sstrec.getString(k);
    106                        //                      System.out.println("SSTRecord id=[" + k + "]=[" + val + "]" );
    107                        //              }
    108                                }
    109                                break;
    110                        // 文字型のレコードです。
    111                        case LabelSSTRecord.sid:
    112                                if( record instanceof LabelSSTRecord ) {
    113                                        LabelSSTRecord lrec = (LabelSSTRecord) record;
    114
    115                                        int   row  = lrec.getRow();
    116                                        short col  = lrec.getColumn();
    117                        //              String val = sstrec.getString( lrec.getSSTIndex() ) ;                   // POI3.0の場合
    118                                        UnicodeString ustr = sstrec.getString( lrec.getSSTIndex() ) ;
    119                                        String val = ustr.getString();
    120
    121                                        // カラムに、{@を含む場合は、laynot に雛形情報を追加します。
    122                                        // 整合性チェックは、ExcelLayoutData クラスで行います。
    123                                        if( val != null && val.indexOf( "{@" ) >= 0 ) {
    124                                                if( trace ) { System.out.println("String cell id,sheet,row,col=[" + lrec.getSSTIndex() + "," + sheetNo + "," + row + "," + col + "] => " + val ); }
    125                                                laynot.addModel( sheetNo,val,row,col );
    126                                        }
    127                                }
    128                                break;
    129                        default :
    130                                LogWriter.log( "想定外のイベントを受け取りました。=[" + record.getSid() + "]" );
    131                                break;
    132                }
    133        }
    134
    135        /**
    136         * 雛形EXCELシートの {&#064;カラム} 解析データ管理クラスを返します。
    137         *
    138         * 雛形EXCELを解析し終わった後で、解析データ管理クラスを取り出します。
    139         * 雛形EXCELと、データEXCELが１対１ではないため、リアルタイム処理が出来ません。
    140         * 一旦、すべての雛形EXCELを解析し終わった後で、データEXCEL処理を行う必要があります。
    141         *
    142         * @return      雛形EXCELシート
    143         */
    144        public ExcelLayout getLayout() { return laynot; }
    145
    146        /**
    147         * 雛形EXCEL のシート数を返します。
    148         *
    149         * @return      雛形シート数
    150         */
    151        public int getSheetSize() { return sheetSize; }
    152
    153        /**
    154         * 処理経過情報を表示するかどうか[true/false]を指定します(初期値:false)
    155         *
    156         * イベント毎の状況を、標準出力に出力するかどうかのフラグです。
    157         * 初期値は、false です。
    158         *
    159         * @param       flag    処理経過情報を表示するかどうか[true/false]
    160         */
    161        public void setTrace( final boolean flag ) { trace = flag; }
    162
    163        /**
    164         * EXCELレイアウト情報を取得します。
    165         *
    166         * POIのイベント処理(HSSFListener)で、各イベントごとに処理を行います。
    167         * イベントは、BOFRecord、BoundSheetRecord、SSTRecord、LabelSSTRecord について
    168         * 発生するように設定しています。
    169         *
    170         * @param       file    処理するEXCELファイル
    171         * @param       trace   標準出力にトレース情報を出力するかどうかを指定します。
    172         *
    173         * @return      EXCELレイアウト情報
    174         * @throws IOException 入出力エラーが発生した場合
    175         */
    176        public static ExcelLayout makeExcelLayout( final File file ,final boolean trace ) throws IOException {
    177
    178                FileInputStream fin = null;
    179                InputStream din = null;
    180                final HybsHSSFListener event ;
    181                try {
    182                        fin = new FileInputStream( file );
    183                        POIFSFileSystem poifs = new POIFSFileSystem( fin );
    184                        din = poifs.createDocumentInputStream( "Workbook" );
    185                        HSSFRequest req = new HSSFRequest();
    186
    187                        event = new HybsHSSFListener();
    188                        event.setTrace( trace );                // 標準出力にトレース情報を出力します。
    189
    190                //      req.addListenerForAllRecords( event );  // 全イベントを処理
    191                        req.addListener( event,BOFRecord.sid );
    192                        req.addListener( event,BoundSheetRecord.sid );
    193                        req.addListener( event,SSTRecord.sid );
    194                        req.addListener( event,LabelSSTRecord.sid );
    195
    196                        HSSFEventFactory factory = new HSSFEventFactory();
    197                        factory.processEvents( req,din );
    198                }
    199                finally {
    200                        Closer.ioClose( fin );          // 4.0.0 (2006/01/31) close 処理時の IOException を無視
    201                        Closer.ioClose( din );          // 4.0.0 (2006/01/31) close 処理時の IOException を無視
    202        //              fin.close();
    203        //              din.close();
    204                }
    205
    206                return event.getLayout();
    207        }
    208}