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.HybsSystemException;
019import org.opengion.fukurou.util.StringUtil;
020import org.opengion.fukurou.util.HybsDateUtil ;
021import org.opengion.fukurou.util.Closer ;
022
023import org.apache.poi.poifs.filesystem.POIFSFileSystem;
024import org.apache.poi.hssf.record.RecordFormatException;
025
026import org.apache.poi.hssf.usermodel.HSSFWorkbook;
027import org.apache.poi.hssf.usermodel.HSSFSheet;
028import org.apache.poi.hssf.usermodel.HSSFRow;
029import org.apache.poi.hssf.usermodel.HSSFCell;
030import org.apache.poi.hssf.usermodel.HSSFDateUtil;
031import org.apache.poi.hssf.usermodel.HSSFRichTextString;
032
033import java.io.File;
034import java.io.InputStream;
035import java.io.FileInputStream;
036import java.io.IOException;
037
038// import java.text.DateFormat;
039// import java.text.SimpleDateFormat;
040// import java.util.Locale ;
041import java.text.NumberFormat ;
042import java.text.DecimalFormat ;
043import java.util.Iterator ;
044
045/**
046 * 【EXCEL取込】雛形EXCELシートの解析処理を行う為の、HSSFListener 拡張クラスです。
047 * このオブジェクトは、HSSFRequest クラスの addListenerForAllRecords メソッドに渡す
048 * HSSFListener インターフェースを実装しています。また、雛形EXCEL を処理後、ExcelLayout
049 * 管理クラスを取得することが出来ます。
050 *
051 *   ※ 最新のPOIでは、org.apache.poi.ss.usermodel を使う事で、2003形式、2007形式に対応させます。
052 *      report パッケージは保守対象外なので、あえて修正しません。
053 *
054 * @og.rev 3.8.0.0 (2005/06/07) 新規追加
055 * @og.group 帳票システム
056 *
057 * @version  4.0
058 * @author   Kazuhiko Hasegawa
059 * @since    JDK5.0,
060 */
061public class ExcelDataPickup {
062
063        private final ExcelLayout       layout  ;
064//      private final File                      filename;
065
066        private final InputStream       in;
067        private final HSSFWorkbook      wb;
068//      private DateFormat   dateFormat = null;                 // 5.5.7.2 (2012/10/09) HybsDateUtil を利用するように修正
069        private NumberFormat numFormat  = null;
070
071        private final boolean    debug;
072
073        /**
074         * 雛形EXCELを処理済みのExcelLayoutオブジェクトと、
075         * データEXCELファイル名よりオブジェクトを構築します。
076         *
077         * 内部で、HSSFWorkbook を構築します。
078         *
079         * @param       layout  雛形EXCELを処理済みのExcelLayoutオブジェクト
080         * @param       filename        データEXCELファイル名
081         * @param debug デバッグフラグ
082         */
083//      public ExcelDataPickup( final ExcelLayout layout,final File fname, final boolean debug ) {
084        public ExcelDataPickup( final ExcelLayout layout,final File filename, final boolean debug ) {
085                this.layout     = layout;
086//              filename        = fname;
087                this.debug      = debug;
088
089                try {
090                        in = new FileInputStream( filename );
091
092                        POIFSFileSystem fs = new POIFSFileSystem( in );
093                        wb = new HSSFWorkbook( fs );
094                }
095                catch (IOException ex) {
096                        String errMsg = "ファイル読込みエラー[" + filename.getName() + "]"  ;
097                        throw new HybsSystemException( errMsg,ex );
098                }
099                catch (RecordFormatException ex) {
100                        String errMsg = "無効の形式/データが使用されています。[" + filename.getName() + "]"
101                                        + "現バージョンのPOIでは読み取ることが出来ません。"
102                                        + "例えば、自動フィルタの設定されたシートが含まれる場合などです。" ;
103                        throw new HybsSystemException( errMsg,ex );
104                }
105        }
106
107        /**
108         * データEXCELファイル名のシート数を返します。
109         *
110         * 内部で、HSSFWorkbook を構築します。
111         *
112         * @return      シート数
113         */
114        public int getSheetSize() {
115                return wb.getNumberOfSheets();
116        }
117
118        /**
119         * データEXCELファイル名のデータをピックアップします。
120         *
121         * この処理を行うと、ExcelLayout オブジェクトにデータEXCEL解析結果を
122         * 保存しますので、処理側でその結果を取り出して使用します。
123         *
124         * @og.rev 3.8.1.1 (2005/11/21) デバッグ用コメント修正
125         *
126         * @param       modelSheetNo    雛形シート番号
127         * @param       sheetNo データシート番号
128         * @param       loopClm 繰返必須カラム(なければ通常の1対1処理)
129         */
130        public void execute( final int modelSheetNo, final int sheetNo, final String loopClm ) {
131
132                HSSFSheet sheet = wb.getSheetAt( sheetNo );
133                layout.dataClear();
134
135                if( debug ) { System.out.println( sheetNo + ":" + wb.getSheetName( sheetNo ) ); }
136
137                Iterator<ExcelLayoutData> ite = layout.getLayoutDataIterator( modelSheetNo,loopClm ) ;
138                while( ite.hasNext() ) {
139//                      ExcelLayoutData data = (ExcelLayoutData)ite.next();
140                        ExcelLayoutData data = ite.next();
141                        String clm  = data.getClm();
142                        int    edbn = data.getEdbn();
143                        int    row  = data.getRowNo();
144                        short  col  = data.getColNo();
145
146        //              if( clm.indexOf( debugClm ) >= 0 ) { debug = true; }
147        //              else { debug = false; }
148
149                        String val = getValue( sheet,row,col );
150                        layout.addData( clm,edbn,val );
151                        if( debug ) { System.out.println( data.toString() + "=[" + val + "]" ); }
152                }
153        }
154
155        /**
156         * シートオブジェクト(HSSFSheet)から行列番号を指定して値を取り出します。
157         * 行オブジェクト(HSSFRow)や列オブジェクト(HSSFCell)が存在しない場合は、nullを返します。
158         * それ以外は、各セルタイプに応じて、処理を行います。
159         * 関数タイプ(HSSFCell.CELL_TYPE_FORMULA)の場合は、まず、文字列として取り出し、ゼロ文字列の
160         * 場合は、数字タイプとして取り出します。
161         *
162         * @og.rev 3.8.0.9 (2005/10/17) 結果を rtrim(右スペース削除)します。
163         * @og.rev 3.8.1.1 (2005/11/21) デバッグ用コメント修正
164         * @og.rev 3.9.0.5 (2008/11/27) POI3.2対応 引数の型変更(short⇒int)
165         *
166         * @param       sheet   EXCELのシートオブジェクト
167         * @param       row             行番号
168         * @param       col             列番号
169         *
170         * @return      セルの値
171         */
172//      private String getValue( final HSSFSheet sheet,final int row, final short col ) {
173        private String getValue( final HSSFSheet sheet,final int row, final int col ) {
174
175                HSSFRow  oRow  = sheet.getRow(row);
176                if( oRow == null ) { return null; }
177                HSSFCell oCell = oRow.getCell(col);
178                if( oCell == null ) { return null; }
179
180                String strText = "";
181                HSSFRichTextString richText ;
182                int nCellType = oCell.getCellType();
183                switch( nCellType ) {
184                        case HSSFCell.CELL_TYPE_NUMERIC:
185                                        strText = getNumericTypeString( oCell );
186                                        break;
187                        case HSSFCell.CELL_TYPE_STRING:
188        // POI3.0               strText = oCell.getStringCellValue();
189                                        richText = oCell.getRichStringCellValue();
190                                        strText =  richText.getString();
191                                        if( debug ) { System.out.print( "String :" ); }
192                                        break;
193                        case HSSFCell.CELL_TYPE_FORMULA:
194        //                              strText = oCell.getCellFormula();
195        // POI3.0               strText = oCell.getStringCellValue();
196                                        richText = oCell.getRichStringCellValue();
197                                        strText =  richText.getString();
198                                        if( strText == null || strText.length() == 0 ) {
199                                                strText = getNumericTypeString( oCell );
200                                        }
201                                        else {
202                                                if( debug ) { System.out.print( "Formula:" ); }
203                                        }
204                                        break;
205                        case HSSFCell.CELL_TYPE_BOOLEAN:
206                                        strText = String.valueOf(oCell.getBooleanCellValue());
207                                        if( debug ) { System.out.print( "Boolean:" ); }
208                                        break;
209                        case HSSFCell.CELL_TYPE_BLANK :
210                                        if( debug ) { System.out.print( "Blank  :" ); }
211                                        break;
212                        case HSSFCell.CELL_TYPE_ERROR :
213                                        if( debug ) { System.out.print( "Error  :" ); }
214                                        break;
215                        default :
216                                        if( debug ) { System.out.print( "Other " + nCellType + ":" ); }
217                                break;
218                }
219
220                return StringUtil.rTrim( strText );             // 3.8.0.9 (2005/10/17)
221        }
222
223        /**
224         * セル値が数字の場合に、数字か日付かを判断して、対応する文字列を返します。
225         *
226         * @og.rev 3.8.1.1 (2005/11/21) デバッグ用コメント修正
227         * @og.rev 5.5.7.2 (2012/10/09) HybsDateUtil を利用するように修正します。
228         *   ※ 最新のPOIでは、org.apache.poi.ss.usermodel を使う事で、2003形式、2007形式に対応させます。
229         *      report パッケージは保守対象外なので、あえて修正しません。
230         *
231         * @param oCell Cellオブジェクト
232         *
233         * @return      数字の場合は、文字列に変換した結果を、日付の場合は、"yyyyMMddHHmmss" 形式で返します。
234         */
235        private String getNumericTypeString( final HSSFCell oCell ) {
236                final String strText ;
237
238                double dval = oCell.getNumericCellValue() ;
239                if( HSSFDateUtil.isCellDateFormatted( oCell ) ) {
240                        strText = HybsDateUtil.getDate( HSSFDateUtil.getJavaDate( dval ).getTime() , "yyyyMMddHHmmss" );
241
242//                      if( dateFormat == null ) {
243//                              dateFormat = new SimpleDateFormat( "yyyyMMddHHmmss",Locale.JAPAN );
244//                      }
245//                      strText = dateFormat.format( HSSFDateUtil.getJavaDate( dval ) );
246                        if( debug ) { System.out.print( "Date   :" ); }
247                }
248                else {
249                        // 3.8.0.9 (2005/10/17) 数字について、NumberFormat を行います。
250                        if( numFormat == null ) {
251                                numFormat = NumberFormat.getInstance();
252                                if( numFormat instanceof DecimalFormat ) {
253                                        ((DecimalFormat)numFormat).applyPattern( "#.####" );
254                                }
255                        }
256                        strText = numFormat.format( dval );
257                        if( debug ) { System.out.print( "Numeric:" ); }
258                }
259                return strText ;
260        }
261
262        /**
263         * EXCEL をオープンした InputStream を閉じます。
264         */
265        public void close() {
266                Closer.ioClose( in );           // 4.0.0 (2006/01/31) close 処理時の IOException を無視
267        }
268}