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オブジェクトに、1行分のデータを追加します。
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 1行分のデータ配列
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オブジェクトに準拠するため、0から始まる整数です。
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         * ファイルの先頭行が、0行としてカウントしますので、設定値は、読み飛ばす
299         * 件数になります。(1と指定すると、1件読み飛ばし、2行目から読み込みます。)
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         * ファイルの先頭行が、0行としてカウントしますので、設定値は、読み飛ばす
316         * 件数になります。(1と指定すると、1件読み飛ばし、2行目から読み込みます。)
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}