    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.io;
    017
    018import org.opengion.fukurou.system.OgRuntimeException ;         // 6.4.2.0 (2016/01/29)
    019
    020import org.opengion.hayabusa.db.ColumnActionListener;           // 6.2.2.0 (2015/03/27)
    021
    022/**
    023 * 指定の区切り記号(初期値:タブ区切り)ファイルの読み取りクラスです。
    024 *
    025 * 名前，データの入力部のみオーバーライドすれば，各種入力フォーマットに合わせた
    026 * サブクラスを実現する事が可能です。
    027 *
    028 * @og.group ファイル入力
    029 *
    030 * @version  4.0
    031 * @author   Kazuhiko Hasegawa
    032 * @since    JDK5.0,
    033 */
    034public abstract class AbstractTableReader implements TableReader {
    035        /** このプログラムのVERSION文字列を設定します。   {@value} */
    036        private static final String VERSION = "6.4.2.0 (2016/01/29)" ;
    037
    038        /** システムの改行コードを設定します。*/
    039
    040        protected String        separator       = TAB_SEPARATOR;        // 6.2.0.0 (2015/02/27) 項目区切り文字。protected化
    041
    042        private   ColumnActionListener  listener        ;               // 6.2.2.0 (2015/03/27)
    043
    044        // 3.5.4.5 (2004/01/23) カラム名の外部指定を出来る様にする。
    045        protected String        columns         ;                       // 外部指定のカラム名 ( 4.3.4.7 (2009/01/22) protectedに変更 )
    046        // 6.1.0.0 (2014/12/26) 読み取り対象外のカラム列を、外部(タグ)より指定する。
    047
    048        private boolean   useNumber             = true;         // 3.7.0.5 (2005/04/11)
    049
    050        private int               skipRowCount  ;                       // 5.1.6.0 (2010/05/01) データの読み飛ばし設定
    051
    052        // 5.2.1.0 (2010/10/01) コードリソース毎のラベル逆引きマップ
    053
    054        // 6.2.0.0 (2015/02/27) TableReader クラスの呼び出し元メソッドの共通化(EXCEL,TEXT)
    055        protected String  sheetName             ;               // 3.5.4.2 (2003/12/15)
    056        protected String  sheetNos              ;               // 5.5.7.2 (2012/10/09)
    057
    058        protected String  constKeys             ;               // 5.5.8.2 (2012/11/09) 固定値となるカラム名(CSV形式)
    059        protected String  constAdrs             ;               // 5.5.8.2 (2012/11/09) 固定値となるアドレス(行-列,行-列,・・・)
    060        protected String  nullBreakClm  ;               // 5.5.8.2 (2012/11/09) 取込み条件/Sheet BREAK条件
    061        protected String  nullSkipClm   ;               // 6.2.3.0 (2015/05/01) 行読み飛ばし
    062
    063        private boolean   useDebug              ;               // 5.5.7.2 (2012/10/09) デバッグ情報の出力するかどうか
    064
    065        /**
    066         * デフォルトコンストラクター
    067         *
    068         * @og.rev 6.4.2.0 (2016/01/29) PMD refactoring. Each class should declare at least one constructor.
    069         */
    070        protected AbstractTableReader() { super(); }            // これも、自動的に呼ばれるが、空のメソッドを作成すると警告されるので、明示的にしておきます。
    071
    072        /**
    073         * DBColumn オブジェクトをDBTable に設定します。
    074         *
    075         * ここでは、omitNames 属性を加味した、カラム名を作成します。
    076         * その際、ゼロ文字列のカラム名は、omit します。
    077         * 戻り値は、新しいカラム数(omitNames を加味、ゼロ文字列のカラムも除去)です。
    078         *
    079         * ※ 6.1.0.0 (2014/12/26) で、omitNames 属性を追加します。
    080         *    これに伴い、従来は、EXCELのみ、#NAME で、ゼロ文字列のカラム名や
    081         *    columns 指定で、a,b,,,,,,x のようなカラム名指定で、カラム飛ばしを
    082         *    実装していましたが、その他の Reader でも、対応します。
    083         *    これは、互換性に影響しますので、ご注意ください。
    084         *    (読み込んでも、カラム名が無いので、使えなかったと思いますけど…)
    085         *
    086         * @og.rev 3.5.4.2 (2003/12/15) private を protected に変更。
    087         * @og.rev 3.5.4.5 (2004/01/23) DBColumn 配列に値をセットします。
    088         * @og.rev 5.2.1.0 (2010/10/01) useRenderer対応(コードリソース毎のラベル逆引き)
    089         * @og.rev 6.1.0.0 (2014/12/26) omitNames 属性を追加
    090         * @og.rev 6.2.1.0 (2015/03/13) ロングラベルから、コード値を見つける機能を、廃止します。
    091         * @og.rev 6.2.2.0 (2015/03/27) ColumnActionListener 対応。
    092         * @og.rev 6.3.9.0 (2015/11/06) コンストラクタで初期化されていないフィールドを null チェックなしで利用している(findbugs)
    093         *
    094         * @param names カラム名配列
    095         * @return 新しいカラム数(omitNames を加味、ゼロ文字列のカラムも除去)
    096         */
    097        protected int setTableDBColumn( final String[] names ) {
    098                // 6.3.9.0 (2015/11/06) コンストラクタで初期化されていないフィールドを null チェックなしで利用している(findbugs)
    099                if( listener == null ) {
    100                        final String errMsg = "#setColumnActionListener(ColumnActionListener)を先に実行しておいてください。" ;
    101                        throw new OgRuntimeException( errMsg );
    102                }
    103
    104                listener.columnNames( names );                  // 6.2.2.0 (2015/03/27)
    105
    106                return names == null ? 0 : names.length;
    107        }
    108
    109        /**
    110         * DBTableModelオブジェクトに、１行分のデータを追加します。
    111         * これ自体は、メソッドの共通化による 拡張をしやすくするために用意しました。
    112         *
    113         * @og.rev 5.2.1.0 (2010/10/01) 新規作成
    114         * @og.rev 6.2.0.0 (2015/02/27) コードリソースの逆引き処理の前に、Key:Val 分解を実行する。
    115         * @og.rev 6.2.1.0 (2015/03/13) ロングラベルから、コード値を見つける機能を、廃止します。
    116         * @og.rev 6.2.2.0 (2015/03/27) ColumnActionListener 対応。
    117         * @og.rev 6.3.9.0 (2015/11/06) コンストラクタで初期化されていないフィールドを null チェックなしで利用している(findbugs)
    118         *
    119         * @param values １行分のデータ配列
    120         * @param rowNo  行番号
    121         */
    122        protected void setTableColumnValues( final String[] values, final int rowNo ) {
    123                // 6.3.9.0 (2015/11/06) コンストラクタで初期化されていないフィールドを null チェックなしで利用している(findbugs)
    124                if( listener == null ) {
    125                        final String errMsg = "#setColumnActionListener(ColumnActionListener)を先に実行しておいてください。" ;
    126                        throw new OgRuntimeException( errMsg );
    127                }
    128
    129                listener.values( values,rowNo );                                        // 6.2.2.0 (2015/03/27)
    130        }
    131
    132        /**
    133         * データを読み込む場合の,区切り文字をセットします。
    134         *
    135         * なお，このメソッドは,サブクラスによっては,使用しない場合があります。
    136         * もし，使用しないサブクラスを作成する場合は, UnsupportedOperationException
    137         * を throw するように,サブクラスで実装して下さい。
    138         *
    139         * @og.rev 3.1.1.0 (2003/03/28) 同期メソッド(synchronized付き)を非同期に変更する。
    140         *
    141         * @param   sep 区切り文字
    142         */
    143        public void setSeparator( final String sep ) {
    144                if( sep != null ) { this.separator = sep; }
    145        }
    146
    147        /**
    148         * DBTableModelのデータとしてEXCELファイルを読み込むときのシート名を設定します。
    149         * これにより、複数の形式の異なるデータを順次読み込むことや、シートを指定して
    150         * 読み取ることが可能になります。
    151         * sheetNos と sheetName が同時に指定された場合は、sheetNos が優先されます。エラーにはならないのでご注意ください。
    152         * のでご注意ください。
    153         * このメソッドは、isExcel() == true の場合のみ利用されます。
    154         *
    155         * ※ このクラスでは実装されていません。
    156         *
    157         * @og.rev 3.5.4.2 (2003/12/15) 新規追加
    158         * @og.rev 6.2.0.0 (2015/02/27) TableReader クラスの呼び出し元メソッドの共通化(EXCEL,TEXT)
    159         *
    160         * @param   sheetName シート名
    161         */
    162        public void setSheetName( final String sheetName ) {
    163                this.sheetName = sheetName;
    164        }
    165
    166        /**
    167         * EXCELファイルを読み込むときのシート番号を指定します(初期値:0)。
    168         *
    169         * EXCEL読み込み時に複数シートをマージして取り込みます。
    170         * シート番号は、0 から始まる数字で表します。
    171         * ヘッダーは、最初のシートのカラム位置に合わせます。（ヘッダータイトルの自動認識はありません。）
    172         * よって、指定するシートは、すべて同一レイアウトでないと取り込み時にカラムのずれが発生します。
    173         *
    174         * シート番号の指定は、CSV形式で、複数指定できます。また、N-M の様にハイフンで繋げることで、
    175         * N 番から、M 番のシート範囲を一括指定可能です。また、"*" による、全シート指定が可能です。
    176         * これらの組み合わせも可能です。（ 0,1,3,5-8,10-* ）
    177         * ただし、"*" に関しては例外的に、一文字だけで、すべてのシートを表すか、N-* を最後に指定するかの
    178         * どちらかです。途中には、"*" は、現れません。
    179         * シート番号は、重複(1,1,2,2)、逆転(3,2,1) での指定が可能です。これは、その指定順で、読み込まれます。
    180         * sheetNos と sheetName が同時に指定された場合は、sheetNos が優先されます。エラーにはならないのでご注意ください。
    181         * このメソッドは、isExcel() == true の場合のみ利用されます。
    182         *
    183         * 初期値は、0（第一シート） です。
    184         *
    185         * ※ このクラスでは実装されていません。
    186         *
    187         * @og.rev 5.5.7.2 (2012/10/09) 新規追加
    188         * @og.rev 6.2.0.0 (2015/02/27) TableReader クラスの呼び出し元メソッドの共通化(EXCEL,TEXT)
    189         *
    190         * @param   sheetNos EXCELファイルのシート番号（0から始まる）
    191         * @see         #setSheetName( String )
    192         */
    193        public void setSheetNos( final String sheetNos ) {
    194                this.sheetNos = sheetNos;
    195        }
    196
    197        /**
    198         * 固定値となるカラム名(CSV形式)と、constAdrs 固定値となるアドレス(行-列,行-列,・・・)を設定します。
    199         *
    200         * アドレスは、EXCEL上の行-列をCSV形式で指定します。
    201         * 行列は、EXCELオブジェクトに準拠するため、０から始まる整数です。
    202         * 0-0 ⇒ A1 , 1-0 ⇒ A2 , 0-1 ⇒ B1 になります。
    203         * これにより、シートの一か所に書かれている情報を、DBTableModel のカラムに固定値として
    204         * 設定することができます。
    205         * 例として、DB定義書で、テーブル名をシートの全レコードに設定したい場合などに使います。
    206         * このメソッドは、isExcel() == true の場合のみ利用されます。
    207         *
    208         * 5.7.6.3 (2014/05/23) より、
    209         *   ①EXCEL表記に準拠した、A1,A2,B1 の記述も処理できるように対応します。
    210         *     なお、A1,A2,B1 の記述は、必ず、英字1文字＋数字 にしてください。(A～Zまで)
    211         *   ②処理中のEXCELシート名をカラムに割り当てるために、"SHEET" という記号に対応します。
    212         * 例えば、sheetConstKeys="CLM,LANG,NAME" とし、sheetConstAdrs="0-0,A2,SHEET" とすると、
    213         * NAMEカラムには、シート名を読み込むことができます。
    214         * これは、内部処理の簡素化のためです。
    215         *
    216         * 例として、DB定義書で、テーブル名をシートの全レコードに設定したい場合などに使います。
    217         * このメソッドは、isExcel() == true の場合のみ利用されます。
    218         *
    219         * @og.rev 5.5.8.2 (2012/11/09) 新規追加
    220         *
    221         * @param   constKeys 固定値となるカラム名(CSV形式)
    222         * @param   constAdrs 固定値となるアドレス(行-列,行-列,・・・)
    223         */
    224        public void setSheetConstData( final String constKeys,final String constAdrs ) {
    225                this.constKeys = constKeys;
    226                this.constAdrs = constAdrs;
    227        }
    228
    229        /**
    230         * ここに指定されたカラム列に NULL が現れた時点で読み取りを中止します。
    231         *
    232         * これは、指定のカラムは必須という事を条件に、そのレコードだけを読み取る処理を行います。
    233         * 複数Sheetの場合は、次のSheetを読みます。
    234         * 現時点では、Excel の場合のみ有効です。
    235         *
    236         * @og.rev 5.5.8.2 (2012/11/09) 新規追加
    237         * @og.rev 6.2.0.0 (2015/02/27) TableReader クラスの呼び出し元メソッドの共通化(EXCEL,TEXT)
    238         *
    239         * @param   clm カラム列
    240         */
    241        public void setNullBreakClm( final String clm ) {
    242                nullBreakClm = clm;
    243        }
    244
    245        /**
    246         * ここに指定されたカラム列に NULL が現れたレコードは読み飛ばします。
    247         *
    248         * 例えば、更新対象カラムで、null の場合は、何もしない、などのケースで使用できます。
    249         * 複数カラムの場合は、AND条件やOR条件などが、考えられるため、
    250         * カラムを一つにまとめて、指定してください。
    251         *
    252         * @og.rev 6.2.3.0 (2015/05/01) 行読み飛ばし nullSkipClm追加
    253         *
    254         * @param   clm カラム列
    255         */
    256        public void setNullSkipClm( final String clm ) {
    257                nullSkipClm = clm;
    258        }
    259
    260        /**
    261         * 読み取り元ファイルのカラム列を、外部(タグ)より指定します。
    262         * ファイルに記述された #NAME より優先して使用されます。
    263         *
    264         * @og.rev 3.5.4.5 (2004/01/23) 新規作成
    265         *
    266         * @param   clms 読み取り元ファイルのカラム列(CSV形式)
    267         */
    268        public void setColumns( final String clms ) {
    269                columns = clms ;
    270        }
    271
    272        /**
    273         * 行番号情報を指定[true:使用している/false:していない]します(初期値:true)。
    274         *
    275         * 通常のフォーマットでは、各行の先頭に行番号が出力されています。
    276         * 読み取り時に、#NAME 属性を使用する場合は、この行番号を無視しています。
    277         * #NAME 属性を使用せず、columns 属性でカラム名を指定する場合(他システムの
    278         * 出力ファイルを読み取るケース等)では、行番号も存在しないケースがあり、
    279         * その様な場合に、useNumber="false" を指定すれば、データの最初から読み取り始めます。
    280         * この場合、出力データのカラムの並び順が変更された場合、columns 属性も
    281         * 指定しなおす必要がありますので、できるだけ、#NAME 属性を使用するように
    282         * してください。
    283         * なお、EXCEL 入力には、この設定は適用されません。(暫定対応)
    284         * 初期値は、true(使用する) です。
    285         *
    286         * @og.rev 3.7.0.5 (2005/04/11) 新規追加
    287         *
    288         * @param       useNumber       行番号情報  [true:使用する/false:使用しない]
    289         */
    290        public void setUseNumber( final boolean useNumber ) {
    291                this.useNumber = useNumber ;
    292        }
    293
    294        /**
    295         * データの読み始めの初期値を取得します。
    296         *
    297         * TAB区切りテキストやEXCEL等のデータの読み始めの初期値を指定します。
    298         * ファイルの先頭行が、０行としてカウントしますので、設定値は、読み飛ばす
    299         * 件数になります。(１と指定すると、１件読み飛ばし、２行目から読み込みます。)
    300         * 読み飛ばしは、コメント行などは、無視しますので、実際の行数分読み飛ばします。
    301         * ＃NAME属性や、columns 属性は、有効です。
    302         *
    303         * @og.rev 5.1.6.0 (2010/05/01) 新規作成
    304         *
    305         * @return      読み始めの初期値
    306         */
    307        public int getSkipRowCount() {
    308                return skipRowCount ;
    309        }
    310
    311        /**
    312         * データの読み飛ばし件数を設定します。
    313         *
    314         * TAB区切りテキストやEXCEL等のデータの読み始めの初期値を指定します。
    315         * ファイルの先頭行が、０行としてカウントしますので、設定値は、読み飛ばす
    316         * 件数になります。(１と指定すると、１件読み飛ばし、２行目から読み込みます。)
    317         * 読み飛ばしは、コメント行などは、無視しますので、実際の行数分読み飛ばします。
    318         * ＃NAME属性や、columns 属性は、有効です。
    319         *
    320         * @og.rev 5.1.6.0 (2010/05/01) 新規作成
    321         *
    322         * @param       count 読み始めの初期値
    323         */
    324        public void setSkipRowCount( final int count ) {
    325                skipRowCount = count;
    326        }
    327
    328        /**
    329         * 行番号情報を、使用している(true)/していない(false)を返します。
    330         *
    331         * 通常のフォーマットでは、各行の先頭に行番号が出力されています。
    332         * 読み取り時に、#NAME 属性を使用する場合は、この行番号を無視しています。
    333         * #NAME 属性を使用せず、columns 属性でカラム名を指定する場合(他システムの
    334         * 出力ファイルを読み取るケース等)では、行番号も存在しないケースがあり、
    335         * その様な場合に、useNumber="false" を指定すれば、データの最初から読み取り始めます。
    336         * この場合、出力データのカラムの並び順が変更された場合、columns 属性も
    337         * 指定しなおす必要がありますので、できるだけ、#NAME 属性を使用するように
    338         * してください。
    339         * なお、EXCEL 入力には、この設定は適用されません。(暫定対応)
    340         * 初期値は、true(使用する) です。
    341         *
    342         * @og.rev 3.7.0.5 (2005/04/11) 新規追加
    343         * @og.rev 4.0.0.0 (2007/07/20) メソッド名変更(getUseNumber() ⇒  isUseNumber())
    344         *
    345         * @return      行番号情報を、使用している(true)/していない(false)を指定
    346         */
    347        protected boolean isUseNumber() {
    348                return useNumber ;
    349        }
    350
    351        /**
    352         * ColumnActionListenerオブジェクトを設定します。
    353         *
    354         * ColumnActionListenerオブジェクトは、カラム名配列設定時と、それに対応する値配列設定時に
    355         * 呼ばれるイベントリスナーです。
    356         * 具体的なテーブル処理は、このイベントを使用して書き込みを行います。
    357         *
    358         * @og.rev 6.2.2.0 (2015/03/27) 新規作成
    359         *
    360         * @param       listener        ColumnActionListenerオブジェクト
    361         */
    362        public void setColumnActionListener( final ColumnActionListener listener ) {
    363                this.listener = listener;
    364        }
    365
    366        /**
    367         * デバッグ情報を出力するかどうか[true:する/false:しない]を指定します。
    368         *
    369         * EXCELなどを読み取る場合、シートマージで読み取ると、エラー時の行番号が、連番になるため、
    370         * どのシートなのか、判らなくなります。
    371         * そこで、どうしてもわからなくなった場合に備えて、デバッグ情報を出力できるようにします。
    372         * 通常は使用しませんので、設定を無視します。
    373         * 初期値は、false:デバッグ情報を出力しない です。
    374         *
    375         * @og.rev 5.5.7.2 (2012/10/09) 新規作成
    376         *
    377         * @param       useDebug        デバッグ出力するか [true:する/false:しない]
    378         */
    379        public void setDebug( final boolean useDebug ) {
    380                this.useDebug = useDebug;
    381        }
    382
    383        /**
    384         * デバッグ情報を出力するかどうか[true:する/false:しない]を取得します。
    385         *
    386         * EXCELなどを読み取る場合、シートマージで読み取ると、エラー時の行番号が、連番になるため、
    387         * どのシートなのか、判らなくなります。
    388         * そこで、どうしてもわからなくなった場合に備えて、デバッグ情報を出力できるようにします。
    389         *
    390         * @og.rev 5.5.7.2 (2012/10/09) 新規作成
    391         *
    392         * @return      デバッグ出力 [true:する/false:しない]
    393         */
    394        protected boolean isDebug() {
    395                return useDebug ;
    396        }
    397}