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.plugin.io;
017    
018    import org.opengion.hayabusa.common.HybsSystem;
019    import org.opengion.hayabusa.common.HybsSystemException;
020    import org.opengion.hayabusa.db.DBTableModelUtil;
021    import org.opengion.hayabusa.io.AbstractTableReader;
022    import org.opengion.fukurou.util.StringUtil;
023    
024    import jxl.Workbook;
025    import jxl.WorkbookSettings;
026    import jxl.Sheet;
027    import jxl.Cell;
028    import jxl.read.biff.BiffException;
029    
030    import java.io.File;
031    import java.io.BufferedReader;
032    import java.io.IOException;
033    
034    /**
035     * JExcelによるEXCELバイナリファイルを読み取る実?ラスです?
036     *
037     * ファイル名?シート名を指定して、データを読み取ることが可能です?
038     * 第?ラ? # で始まる行?、コメント行なので、読み飛?します?
039     * カラ?の?行で、カラ??null の場合?、その列?読み飛?します?
040     *
041     * @og.rev 3.5.4.8 (2004/02/23) 新規作?
042     * @og.group ファイル入?
043     *
044     * @version  4.0
045     * @author   Kazuhiko Hasegawa
046     * @since    JDK5.0,
047     */
048    public class TableReader_JExcel extends AbstractTableReader {
049            //* こ?プログラ??VERSION??を設定します?       {@value} */
050            private static final String VERSION = "5.5.7.2 (2012/10/09)" ;
051    
052            private String  sheetName               = null;         // 3.5.4.2 (2003/12/15)
053            private String  sheetNos                = null;         // 5.5.7.2 (2012/10/09)
054            private String  filename                = null;         // 3.5.4.3 (2004/01/05)
055    
056            /**
057             * DBTableModel から ?式???タを作?して,BufferedReader より読み取ります?
058             * コメン?空行を除き???の行?、??名が?です?
059             * それ以降?、コメン?空行を除き???タとして読み込んで?ます?
060             * こ?メソ?は、EXCEL 読み込み時に使用します?
061             *
062             * @og.rev 4.0.0.0 (2006/09/31) 新規追?
063             * @og.rev 5.1.6.0 (2010/05/01) columns 処?追?
064             * @og.rev 5.1.6.0 (2010/05/01) skipRowCount , useNumber の追?
065             * @og.rev 5.2.1.0 (2010/10/01) setTableColumnValues メソ?を経由して、テーブルに??タをセ?する?
066             * @og.rev 5.5.7.2 (2012/10/09) sheetNos 追?よる?シート?マ?ジ読み取りサポ??
067             *
068             * @see #isExcel()
069             */
070            @Override
071            public void readDBTable() {
072                    Workbook wb = null;
073                    try {
074                            WorkbookSettings settings = new WorkbookSettings();
075                            // System.gc()「ガベ?ジコレクション」?実行をOFFに設?
076                            settings.setGCDisabled(true);
077                            wb = Workbook.getWorkbook(new File(filename),settings);
078    
079    //                      Sheet sheet ;
080                            Sheet[] sheets ;                                                                        // 5.5.7.2 (2012/10/09) 配?に変更
081    
082                            // 5.5.7.2 (2012/10/09) ?シート?マ?ジ読み取り?sheetNos の?が優先される?
083                            if( sheetNos != null && sheetNos.length() > 0 ) {
084                                    String[] sheetList = StringUtil.csv2ArrayExt( sheetNos , wb.getNumberOfSheets()-1 );    // ?シート番号は、シート数-1
085                                    sheets = new Sheet[sheetList.length];
086                                    for( int i=0; i<sheetList.length; i++ ) {
087                                            sheets[i] = wb.getSheet( Integer.parseInt( sheetList[i] ) );
088                                    }
089                            }
090                            else if( sheetName != null && sheetName.length() > 0 ) {
091                                    Sheet sheet = wb.getSheet( sheetName );
092                                    if( sheet == null ) {
093                                            String errMsg = "対応するシートが存在しません?Sheet=[" + sheetName + "]" ;
094                                            throw new HybsSystemException( errMsg );
095                                    }
096                                    sheets = new Sheet[] { sheet };
097                            }
098                            else {
099                                    Sheet sheet = wb.getSheet(0);
100                                    sheets = new Sheet[] { sheet };
101                            }
102    
103    //                      if( sheetName == null || sheetName.length() == 0 ) {
104    //                              sheet = wb.getSheet(0);
105    //                      }
106    //                      else {
107    //                              sheet = wb.getSheet( sheetName );
108    //                              if( sheet == null ) {
109    //                                      String errMsg = "対応するシートが存在しません?Sheet=[" + sheetName + "]" ;
110    //                                      throw new HybsSystemException( errMsg );
111    //                              }
112    //                      }
113    
114                            boolean nameNoSet = true;
115                            table = DBTableModelUtil.newDBTable();
116    
117                            int numberOfRows = 0;
118                            JxlHeaderData data = new JxlHeaderData();
119    
120                            // 5.1.6.0 (2010/05/01) columns 処?
121                            data.setUseNumber( isUseNumber() );
122                            if( data.setColumns( columns ) ) {
123                                    nameNoSet = false;
124                                    table.init( data.getColumnSize() );
125                                    setTableDBColumn( data.getNames() ) ;
126                            }
127    
128                            // 5.5.7.2 (2012/10/09) ?シート?マ?ジ読み取り?
129                            for( int i=0; i<sheets.length; i++ ) {                       // 5.5.7.2 (2012/10/09) シート?列を処?ます?
130                                    Sheet sheet = sheets[i] ;                                       // 5.5.7.2 (2012/10/09)
131                                    int rowCnt = sheet.getRows();
132                                    int skip = getSkipRowCount();           // 5.1.6.0 (2010/05/01)
133            //                      for( int nIndexRow = 0; nIndexRow < rowCnt; nIndexRow++) {
134                                    for( int nIndexRow = skip; nIndexRow < rowCnt; nIndexRow++) {
135                                            Cell[] cells = sheet.getRow( nIndexRow );
136                                            if( data.isSkip( cells ) ) { continue; }
137                                            if( nameNoSet ) {
138                                                    nameNoSet = false;
139                                                    table.init( data.getColumnSize() );
140                                                    setTableDBColumn( data.getNames() ) ;
141                                            }
142    
143                                            if( numberOfRows < getMaxRowCount() ) {
144                                                    setTableColumnValues( data.toArray( cells ) );          // 5.2.1.0 (2010/10/01)
145            //                                      table.addColumnValues( data.toArray( cells ) );
146                                                    numberOfRows ++ ;
147                                            }
148                                            else {
149                                                    table.setOverflow( true );
150                                            }
151                                    }
152    
153                                    // ?まで?NAME が見つから無かった??
154                                    if( nameNoSet ) {
155                                            String errMsg = "?まで?NAME が見つかりませんでした?
156                                                                            + HybsSystem.CR
157                                                                            + "ファイルが空か?もしく?損傷して?可能性があります?"
158                                                                            + HybsSystem.CR ;
159                                            throw new HybsSystemException( errMsg );
160                                    }
161                            }
162                    }
163                    catch (IOException ex) {
164                            String errMsg = "ファイル読込みエラー[" + filename + "]"  ;
165                            throw new HybsSystemException( errMsg,ex );
166                    }
167                    catch (BiffException ex) {
168                            String errMsg = "ファイル読込みエラー。データ形式が不正です[" + filename + "]"  ;
169                            throw new HybsSystemException( errMsg,ex );
170                    }
171                    finally {
172                            if( wb != null ) { wb.close(); }
173                    }
174            }
175    
176            /**
177             * DBTableModel から ?式???タを作?して,BufferedReader より読み取ります?
178             * コメン?空行を除き???の行?、??名が?です?
179             * それ以降?、コメン?空行を除き???タとして読み込んで?ます?
180             *
181             * @og.rev 3.5.4.3 (2004/01/05) 引数に、BufferedReader を受け取る要に変更します?
182             * @og.rev 4.0.0.0 (2006/09/31) UnsupportedOperationException を発行します?
183             *
184             * @param   reader ?式???タ(使用して?せん)
185             */
186            @Override
187            public void readDBTable( final BufferedReader reader ) {
188                    String errMsg = "こ?クラスでは実?れて?せん?;
189                    throw new UnsupportedOperationException( errMsg );
190            }
191    
192            /**
193             * DBTableModelの??タとしてEXCELファイルを読み込?き?シート名を設定します?
194             * これにより、?の形式?異なるデータを?次読み込?と??シートを?して
195             * 読み取ることが可能になります?
196             * sheetNos と sheetName が同時に?された場合?、sheetNos が優先されます?エラーにはならな??でご注意く???
197             * のでご注意く???
198             *
199             * @og.rev 3.5.4.2 (2003/12/15) 新規追?
200             *
201             * @param   sheetName シート名
202             */
203            @Override
204            public void setSheetName( final String sheetName ) {
205                    this.sheetName = sheetName;
206            }
207    
208            /**
209             * EXCELファイルを読み込?き?シート番号を指定しま?初期値:0)?
210             *
211             * EXCEL読み込み時に?シートをマ?ジして取り込みます?
212             * シート番号は? から始まる数字で表します?
213             * ヘッ??は、最初?シート?カラ?置に合わせます????ータイトルの自動認識?ありません。?
214             * よって、指定するシート?、すべて同?イアウトでな?取り込み時にカラ??ずれが発生します?
215             * 
216             * シート番号の??、カンマ区?で、??できます?また?N-M の様にハイフンで繋げることで?
217             * N 番から、M 番のシート?を??可能です?また?"*" による、?シート指定が可能です?
218             * これら??合わせも可能です???0,1,3,5-8,10-* ??
219             * ただし?"*" に関しては例外的に、?字だけで、すべてのシートを表すか、N-* を最後に?するかの
220             * どちらかです?途中には?*" は、現れません?
221             * シート番号は??1,1,2,2)??転(3,2,1) での?が可能です?これは、その??で、読み込まれます?
222             * sheetNos と sheetName が同時に?された場合?、sheetNos が優先されます?エラーにはならな??でご注意く???
223             * こ?メソ?は、isExcel() == true の場合?み利用されます?
224             * 
225             * 初期値は??第?ート?です?
226             *
227             * ※ こ?クラスでは実?れて?せん?
228             *
229             * @og.rev 5.5.7.2 (2012/10/09) 新規追?
230             *
231             * @param   sheetNos EXCELファイルのシート番号??から始まる?
232             * @see         #setSheetName( String ) 
233             */
234            @Override
235            public void setSheetNos( final String sheetNos ) {
236                    this.sheetNos = sheetNos;
237            }
238    
239            /**
240             * こ?クラスが?EXCEL対応機?を持って?かど?を返します?
241             *
242             * EXCEL対応機?とは、シート名のセ?、読み込み?ァイルの
243             * Fileオブジェクト取得などの、特殊機?です?
244             * 本来は、インターフェースを?けるべきと?ますが、taglib クラス等?
245             * 関係があり、問?わせによる条件?で対応します?
246             *
247             * @og.rev 3.5.4.3 (2004/01/05) 新規追?
248             *
249             * @return      EXCEL対応機?を持って?かど?(常にtrue)
250             */
251            @Override
252            public boolean isExcel() {
253                    return true;
254            }
255    
256            /**
257             * 読み取り?ァイル名をセ?します?(DIR + Filename)
258             * これは、EXCEL追??として実?れて?す?
259             *
260             * @og.rev 3.5.4.3 (2004/01/05) 新規作?
261             *
262             * @param   filename 読み取り?ァイル?
263             */
264            @Override
265            public void setFilename( final String filename ) {
266                    this.filename = filename;
267                    if( filename == null ) {
268                            String errMsg = "ファイル名が?されて?せん? ;
269                            throw new HybsSystemException( errMsg );
270                    }
271            }
272    }
273    
274    /**
275     * EXCEL ネイ?ブ???タを???ローカルクラスです?
276     * こ?クラスでは、コメント行?スキ??判定?ヘッ??部のカラ?取得?
277     * 行情報(HSSFRow)から、カラ??配?の取得などを行います?
278     *
279     * @og.rev 3.5.4.8 (2004/02/23) 新規追?
280     * @og.group ファイル入?
281     *
282     * @version  4.0
283     * @author   儲
284     * @since    JDK5.0,
285     */
286    class JxlHeaderData {
287            private String[] names ;
288            private int[]    index;
289            private int              columnSize = 0;
290            private boolean  nameNoSet = true;
291            private boolean  useNumber = true;
292    
293            /**
294             * 行番号??を使用するかど?[true/false]を指定しま?初期値:true)?
295             *
296             * 初期値は、true(使用する) です?
297             *
298             * @og.rev 5.1.6.0 (2010/05/01) 新規作?
299             *
300             * @param useNumber 行番号?? [true:使用して?/false:して?い]
301             */
302            void setUseNumber( final boolean useNumber ) {
303                    this.useNumber = useNumber ;
304            }
305    
306            /**
307             * カラ?を外部から?します?
308             * カラ?が?NULL でなければ?NAME より、こちらが優先されます?
309             * カラ?は??番に、指定する?があります?
310             *
311             * @og.rev 5.1.6.0 (2010/05/01) 新規作?
312             *
313             * @param       columns EXCELのカラ??(CSV形?
314             *
315             * @return true:処?施/false:無処?
316             */
317            boolean setColumns( final String columns ) {
318                    if( columns != null && columns.length() > 0 ) {
319                            names = StringUtil.csv2Array( columns );
320                            columnSize = names.length ;
321                            index = new int[columnSize];
322                            int adrs = (useNumber) ? 1:0 ;  // useNumber =true の場合??件目(No)は読み飛?す?
323                            for( int i=0; i<columnSize; i++ ) { index[i] = adrs++; }
324                            nameNoSet = false;
325    
326                            return true;
327                    }
328                    return false;
329            }
330    
331            /**
332             * EXCEL ネイ?ブ???タを???ローカルクラスです?
333             * こ?クラスでは、コメント行?スキ??判定?ヘッ??部のカラ?取得?
334             * 行情報(HSSFRow)から、カラ??配?の取得などを行います?
335             *
336             * @param cells Cell[] EXCELのセル配?(?
337             *
338             * @return true:コメント?false:通常?
339             */
340            boolean isSkip( final Cell[] cells ) {
341                    int size = cells.length ;
342                    if( size == 0 ) { return true; }
343    
344                    String strText =  cells[0].getContents();
345                    if( strText != null && strText.length() > 0 ) {
346                            if( nameNoSet ) {
347                                    if( strText.equalsIgnoreCase( "#Name" ) ) {
348                                            makeNames( cells );
349                                            nameNoSet = false;
350                                            return true;
351                                    }
352                                    else if( strText.charAt( 0 ) == '#' ) {
353                                            return true;
354                                    }
355                                    else {
356                                            String errMsg = "#NAME が見つかる前に??タが見つかりました?
357                                                                            + HybsSystem.CR
358                                                                            + "可能性として、ファイルが?ネイ?ブExcelでな?が?られます?"
359                                                                            + HybsSystem.CR ;
360                                            throw new HybsSystemException( errMsg );
361                                    }
362                            }
363                            else {
364                                    if( strText.charAt( 0 ) == '#' ) {
365                                            return true;
366                                    }
367                            }
368                    }
369    
370                    return nameNoSet ;
371            }
372    
373            /**
374             * EXCEL ネイ?ブ?行?セル配?からカラ???を取得します?
375             *
376             * @og.rev 5.1.6.0 (2010/05/01) useNumber(行番号??を?使用して?(true)/して??false)を指?
377             *
378             * @param cells Cell[] EXCELの行?セル配?
379             */
380            private void makeNames( final Cell[] cells ) {
381                    int maxCnt = cells.length;
382                    String[] names2 = new String[maxCnt];
383                    int[]    index2 = new int[maxCnt];
384    
385                    // 先?カラ???NAME 属?行である?
386    //              for( int nIndexCell = 1; nIndexCell < maxCnt; nIndexCell++) {
387                    // 先?カラ???NAME 属?行であるかど?を?useNumber で判定しておく?
388                    int nFirstCell = (useNumber) ? 1:0 ;
389                    for( int nIndexCell = nFirstCell; nIndexCell < maxCnt; nIndexCell++) {
390                            String strText = cells[nIndexCell].getContents();
391    
392                            if( strText != null && strText.length() > 0 ) {
393                                    names2[columnSize] = strText;
394                                    index2[columnSize] = nIndexCell;
395                                    columnSize++;
396                            }
397                    }
398    
399                    // #NAME を使用しな??合:no?存在しな?ース
400                    if( maxCnt == columnSize ) {
401                            names = names2;
402                            index = index2;
403                    }
404                    else {
405                            names = new String[columnSize];
406                            index = new int[columnSize];
407                            System.arraycopy(names2, 0, names, 0, columnSize);
408                            System.arraycopy(index2, 0, index, 0, columnSize);
409                    }
410            }
411    
412            /**
413             * カラ???を返します?
414             * ここでは、?部配?をそのまま返します?
415             *
416             * @return String[] カラ??配???
417             */
418            String[] getNames() {
419                    return names;
420            }
421    
422            /**
423             * カラ?イズを返します?
424             *
425             * @return      カラ?イズ
426             */
427            int getColumnSize() {
428                    return columnSize;
429            }
430    
431            /**
432             * カラ???を返します?
433             *
434             * @param cells Cell[] EXCELの行?セル配?
435             *
436             * @return String[] カラ??配???
437             */
438            String[] toArray( final Cell[] cells ) {
439                    if( nameNoSet ) {
440                            String errMsg = "#NAME が見つかる前に??タが見つかりました?;
441                            throw new HybsSystemException( errMsg );
442                    }
443    
444                    int cellSize = cells.length;
445                    String[] data = new String[columnSize];
446                    for( int i=0;i<columnSize; i++ ) {
447                            int indx = index[i];
448                            if( indx < cellSize ) {
449                                    data[i] = cells[indx].getContents();
450                            }
451                            else {
452                                    data[i] = null;
453                            }
454                    }
455    
456                    return data;
457            }
458    }