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.taglib;
017
018import org.opengion.fukurou.system.OgRuntimeException;                                                  // 6.4.2.0 (2016/01/29)
019import org.opengion.fukurou.system.OgCharacterException;                                                // 6.5.0.1 (2016/10/21)
020import org.opengion.fukurou.system.ThrowUtil;                                                                   // 6.4.2.0 (2016/01/29)
021import org.opengion.fukurou.util.ErrorMessage;
022import org.opengion.fukurou.util.StringUtil;
023import org.opengion.fukurou.util.ToString;                                                                              // 6.1.1.0 (2015/01/17)
024import org.opengion.fukurou.util.FileInfo;                                                                              // 6.2.0.0 (2015/02/27)
025import org.opengion.fukurou.util.ArraySet;                                                                              // 6.4.3.4 (2016/03/11)
026import org.opengion.hayabusa.common.HybsSystem;
027import org.opengion.hayabusa.common.HybsSystemException;
028import org.opengion.hayabusa.common.HybsOverflowException;                                              // 6.2.2.0 (2015/03/27)
029import org.opengion.hayabusa.db.DBTableModelUtil;                                                               // 6.2.1.0 (2015/03/13)
030import org.opengion.hayabusa.db.DBTableModel;
031import org.opengion.hayabusa.db.DBColumn;
032import org.opengion.hayabusa.db.ColumnActionListener;                                                   // 6.2.2.0 (2015/03/27)
033import org.opengion.hayabusa.io.TableReader;
034import org.opengion.hayabusa.io.HybsFileOperationFactory;                                               // 8.0.0.1 (2021/10/08)
035
036import static org.opengion.fukurou.util.StringUtil.nval;
037import static org.opengion.fukurou.system.HybsConst.BR;                                                 // 6.1.0.0 (2014/12/26) refactoring
038
039import java.util.Locale;
040import java.util.List;                                                                                                                  // 6.2.5.0 (2015/06/05)
041import java.util.Set;                                                                                                                   // 6.4.3.4 (2016/03/11)
042import java.util.ArrayList;                                                                                                             // 6.2.5.0 (2015/06/05)
043import java.util.Map;                                                                                                                   // 6.4.6.0 (2016/05/27)
044import java.util.HashMap;                                                                                                               // 6.4.6.0 (2016/05/27)
045import java.io.File;
046
047/**
048 * 指定のファイルを DBTableModelオブジェクトに読み取るファイル入力タグです。
049 *
050 * データ(DBTableModel)と、コントローラ(ReadTableタグ)を与えて、外部からコントロールすることで、
051 * 各種形式で データ(DBTableModel)を表示させることが できます。
052 * ReadTableタグ に対して、コマンドを与えることにより、内部のコントローラの実装に対応した
053 * 形式でデータを作成します。
054 * すべての読取の初期クラス名を リソースファイルの TABLE_READER_DEFAULT_CLASS で指定可能です。
055 * その場合、AutoReader を指定すると、Excel と Text(テキスト) を以下の順番で試します。
056 * Excel,Calc,Text(UnicodeLittle),Text(Windows-31J),Text(UTF-8),Text(EUC-JP),POI
057 * UTF-8 のTEXTとWindows-31JのTEXTは、ヘッダー部での区別ができないため、正確なTextの自動読取できません。
058 *
059 * ※ 6.2.5.0 (2015/06/05) 仕様変更
060 *    ・AutoReader で、encode を指定すると、Text(encode) を先に試します。
061 *    ・Textで、encode を指定しない場合は、システム変数の FILE_ENCODE を使用します。
062 *
063 * 入力件数を"DB.COUNT" キーでリクエストにセットしています。
064 *
065 * ※ 7.3.1.3 (2021/03/09) DB.NAMES , DB.ORGNAMES
066 *    #NAME や columns で指定したカラムは、{@DB.NAMES} で取り出すことが可能です。
067 *    ファイルにかかれた、オリジナルの #NAME は、{@DB.ORGNAMES} で取り出すことが可能です。
068 *
069 * @og.formSample
070 * ●形式:
071 *     <og:readTable
072 *         command      = "NEW"
073 *         fileURL      = "{@USER.ID}"     読取元ディレクトリ名
074 *         filename     = "{@filename}"    読取元ファイル名
075 *         encode       = "UnicodeLittle"       読取元ファイルエンコード名
076 *         maxRowCount  = "10000"               読取最大件数(初期値:0:[無制限])
077 *     />
078 * ●body:なし
079 *
080 * ●Tag定義:
081 *   <og:readTable
082 *       readerClass        【TAG】実際に読み出すクラス名の略称(TableReader_**** の ****)をセットします
083 *                                  (初期値:TABLE_READER_DEFAULT_CLASS[={@og.value SystemData#TABLE_READER_DEFAULT_CLASS}])
084 *       command            【TAG】コマンド (NEW,RENEW)をセットします(初期値:NEW)
085 *       fileURL            【TAG】読取元ディレクトリ名を指定します(初期値:FILE_URL)
086 *       filename           【TAG】ファイルを読み出すときのファイル名をセットします (初期値:FILE_FILENAME[=file.xls])
087 *       encode             【TAG】ファイルを読み出すときのファイルエンコーディング名をセットします(初期値:FILE_ENCODE)
088 *       skipRowCount       【TAG】(通常は使いません)データの読み飛ばし件数を設定します
089 *       maxRowCount        【TAG】読取時の最大取込件数をセットします (初期値:0:[無制限])
090 *       errRowCount        【TAG】読取時の最大エラー件数をセットします (初期値:{@og.value #ERROR_ROW_COUNT})(0:[無制限])
091 *       separator          【TAG】可変長ファイルを読み出すときの項目区切り文字をセットします
092 *       columns            【TAG】読取元ファイルのカラム列を、外部(タグ)よりCSV形式で指定します
093 *       omitNames          【TAG】読取対象外のカラム列を、外部(タグ)よりCSV形式で指定します
094 *       modifyType         【TAG】ファイル取込時の モディファイタイプ(A(追加),C(更新),D(削除))を指定します
095 *       displayMsg         【TAG】query の結果を画面上に表示するメッセージIDを指定します(初期値:VIEW_DISPLAY_MSG[={@og.value SystemData#VIEW_DISPLAY_MSG}]))
096 *       overflowMsg        【TAG】読取データが最大検索数をオーバーした場合に表示するメッセージリソースIDを指定します (初期値:MSG0007[検索結果が、制限行数を超えましたので、残りはカットされました])
097 *       notfoundMsg        【TAG】検索結果がゼロ件の場合に表示するメッセージリソースIDを指定します(初期値:MSG0077[対象データはありませんでした])
098 *  ※   sheetName          【TAG】EXCELファイルを読み込むときのシート名を設定します(初期値:指定なし)
099 *  ※   sheetNos           【TAG】EXCELファイルを読み込むときのシート番号を複数設定できます(初期値:0)
100 *  ※   sheetConstKeys     【TAG】EXCELファイルを読み込むときの固定値となるカラム名(CSV形式)
101 *  ※   sheetConstAdrs     【TAG】EXCELファイルを読み込むときの固定値となるアドレス(行-列,行-列,・・・)
102 *       nullBreakClm       【TAG】カラム列に NULL が現れた時点で読取を中止します(複数Sheetの場合は、次のSheetを読みます)。
103 *       nullSkipClm        【TAG】カラム列に NULL が現れたレコードは読み飛ばします。
104 *       useNumber          【TAG】行番号情報を、使用している/していない[true/false]を指定します(初期値:true)
105 *       useRepeatClms      【TAG】読取処理で横持ちデータの繰り返しが存在する場合に、trueを指定します(初期値:false) 7.3.0.0 (2021/01/06)
106 *       useRenderer        【TAG】読取処理でKEY:VAL形式のコードリソースから、KEYを取り出す処理を行うかどうかを指定します(初期値:USE_TABLE_READER_RENDERER[=false])
107 *       adjustColumns      【TAG】読取元ファイルのデータ変換を行うカラム列をカンマ指定します("*" で全カラム)
108 *       checkColumns       【TAG】読取元ファイルの整合性チェックを行うカラム列をカンマ指定します("*" で全カラム)
109 *       useStrict          【TAG】整合性チェック時に、厳密にチェックするかどうか[true/false]を指定します(初期値:true) 7.3.2.0 (2021/03/19)
110 *       nullCheck          【TAG】NULL チェックすべきカラム列をCSV形式(CSV形式)で指定します
111 *       matchKeys          【TAG】レコードの読取条件指定時のカラム列をCSV形式で指定します 6.4.6.0 (2016/05/27)
112 *       matchVals          【TAG】レコードの読取条件指定時のカラム列に対応する正規表現データをCSV形式で指定します 6.4.6.0 (2016/05/27)
113 *       language           【TAG】タグ内部で使用する言語コード[ja/en/zh/…]を指定します
114 *       stopZero           【TAG】読込件数が0件のとき処理を続行するかどうか[true/false]を指定します(初期値:false[続行する])
115 *       mainTrans          【TAG】(通常は使いません)タグで処理される処理がメインとなるトランザクション処理かどうかを指定します(初期値:false)
116 *       tableId            【TAG】(通常は使いません)sessionから所得する DBTableModelオブジェクトの ID
117 *       scope              【TAG】キャッシュする場合のスコープ[request/page/session/application]を指定します(初期値:session)
118 *       useSLabel          【TAG】7.0.7.0 (2019/12/13) エラーメッセージにSLABELを利用するかどうか[true/false]を指定します(初期値:false)
119 *       useLocal           【TAG】システム定数でクラウド設定されていても、クラウド環境を使用しない場合、trueを指定します(初期値:false) 8.0.1.0 (2021/10/29)
120 *       caseKey            【TAG】このタグ自体を利用するかどうかの条件キーを指定します(初期値:null) 5.7.7.2 (2014/06/20)
121 *       caseVal            【TAG】このタグ自体を利用するかどうかの条件値を指定します(初期値:null) 5.7.7.2 (2014/06/20)
122 *       caseNN             【TAG】指定の値が、null/ゼロ文字列 でない場合(Not Null=NN)は、このタグは使用されます(初期値:判定しない) 5.7.7.2 (2014/06/20)
123 *       caseNull           【TAG】指定の値が、null/ゼロ文字列 の場合は、このタグは使用されます(初期値:判定しない) 5.7.7.2 (2014/06/20)
124 *       caseIf             【TAG】指定の値が、true/TRUE文字列の場合は、このタグは使用されます(初期値:判定しない)
125 *       debug              【TAG】デバッグ情報を出力するかどうか[true/false]を指定します(初期値:false)
126 *   />
127 *
128 * ●使用例
129 *
130 *     <og:readTable
131 *         command        = "NEW"
132 *         readerClass    = "Text"                テキストファイルの読取
133 *         modifyType     = "{@modifyType}"  読取時のモディファイタイプ(A,C等)
134 *         fileURL        = "{@USER.ID}"     読取元ディレクトリ名
135 *         filename       = "{@filename}"    読取元ファイル名
136 *         encode         = "Shift_JIS"           読取元ファイルエンコード名
137 *         maxRowCount    = "10000"               読取最大件数(0:[無制限])
138 *         columns        = "OYA,KO,HJO,SU,DYSTR,DYEND"   #NAME に対応するカラム列
139 *         useNumber      = "false"               行番号の存在しないデータを読取ます。
140 *         adjustColumns  = "OYA,KO,HJO,SU"       データ変換するカラム列("*" で全カラム)
141 *         checkColumns   = "OYA,KO,HJO,SU"       整合性チェックするカラム列("*" で全カラム)
142 *         nullCheck      = "OYA,KO,SU"           NULLチェックを実行します("*" で全カラム)
143 *         stopZero       = "true"                取得0件の場合に以降の処理を停止します
144 *         skipRowCount   = "4"                   データの読み飛ばし件数(読み込み開始は、この数字+1行目から)
145 *     />
146 *
147 * @og.group ファイル入力
148 *
149 * @version  4.0
150 * @author   Kazuhiko Hasegawa
151 * @since    JDK5.0,
152 */
153public class ReadTableTag extends CommonTagSupport {
154        /** このプログラムのVERSION文字列を設定します。 {@value} */
155        private static final String VERSION = "8.1.2.3 (2022/05/20)" ;
156        private static final long serialVersionUID = 812320220520L ;
157
158        private static final int ERROR_ROW_COUNT = 200 ;        // 4.0.0 (2007/05/25)
159
160        /** command 引数に渡す事の出来る コマンド  新規作成 {@value} */
161        public static final String CMD_NEW   = "NEW" ;
162        /** command 引数に渡す事の出来る コマンド  再検索 {@value} */
163        public static final String CMD_RENEW = "RENEW" ;
164
165        // 6.4.3.4 (2016/03/11) String配列 から、Setに置き換えます。
166        private static final Set<String> COMMAND_SET = new ArraySet<>( CMD_NEW , CMD_RENEW );
167
168        // 6.2.0.0 (2015/02/27) AutoReaderの対応方法変更。拡張子に応じて、チェック対象を変更する。null は全対象
169        // 6.2.2.0 (2015/03/27) マクロ付Excel(.xlsm)対応
170        // 6.2.5.0 (2015/06/05) 文字列配列から、内部クラスに変更
171        // 6.4.5.1 (2016/04/28) 順番の変更と、CSV対応
172
173        private static final List<AutoReaderParam> AUTO_READER_PARAM = new ArrayList<>() ;
174        static {
175                AUTO_READER_PARAM.add( new AutoReaderParam( "Excel"     ,       null                    ,       "xls,xlsx,xlsm" ) );
176                AUTO_READER_PARAM.add( new AutoReaderParam( "CSV"       ,       "Windows-31J"   ,       "csv"                   ) );                    // 6.4.5.1 (2016/04/28) 追加
177                AUTO_READER_PARAM.add( new AutoReaderParam( "CSV"       ,       "UTF-8"                 ,       "csv"                   ) );                    // 6.4.5.1 (2016/04/28) 追加
178                AUTO_READER_PARAM.add( new AutoReaderParam( "Text"      ,       "UnicodeLittle" ,       null                    ) );
179                AUTO_READER_PARAM.add( new AutoReaderParam( "Text"      ,       "Windows-31J"   ,       null                    ) );
180                AUTO_READER_PARAM.add( new AutoReaderParam( "Text"      ,       "UTF-8"                 ,       null                    ) );
181                AUTO_READER_PARAM.add( new AutoReaderParam( "Text"      ,       "EUC-JP"                ,       null                    ) );
182                AUTO_READER_PARAM.add( new AutoReaderParam( "POI"       ,       null                    ,       "ppt,pptx,doc,docx,xls,xlsx,xlsm" ) );          // 6.2.5.0 (2015/06/05) 追加
183                AUTO_READER_PARAM.add( new AutoReaderParam( "Calc"      ,       null                    ,       "ods"                   ) );                    // 6.4.5.1 (2016/04/28) 位置変更
184        }
185
186        /** 項目区切り文字 */
187        protected       String  separator               = TableReader.TAB_SEPARATOR;                    // 項目区切り文字 6.2.0.0 (2015/02/27) protected化
188        /** ファイルURL */
189        private         String  fileURL                 = HybsSystem.sys( "FILE_URL"            );
190        /** ファイル名 */
191        private         String  filename                = HybsSystem.sys( "FILE_FILENAME"       );
192        /** ファイルエンコーディング */
193        protected       String  encode                  ;                                                                               // 6.2.5.0 (2015/06/05)
194        /** 読取クラス名 */
195        protected       String  readerClass             ;                                                                               // 6.2.0.0 (2015/02/27) protected化
196        /** 最大行 */
197        protected       int             maxRowCount             ;                                                                               // 6.2.0.0 (2015/02/27) 初期値を無制限に変更
198        /** ディスプレイメッセージ */
199        protected       String  displayMsg              = HybsSystem.sys( "VIEW_DISPLAY_MSG" ); // 6.2.0.0 (2015/02/27) protected化
200        /** 読取データが最大検索数をオーバーした場合に表示するメッセージリソースIDを指定する */
201        private         String  overflowMsg             = "MSG0007";                                                    // 検索結果が、制限行数を超えましたので、残りはカットされました。
202        /** 検索結果がゼロ件の場合に表示するメッセージリソースIDを指定する */
203        private         String  notfoundMsg             = "MSG0077";                                                    // 対象データはありませんでした。
204        /** 実行件数 */
205        protected       int             executeCount    = -1;                                                                   // 検索/実行件数
206        /** ファイル取込時の モディファイタイプ */
207        private         String  modifyType              ;
208
209        private transient DBTableModel table    ;
210        /** コマンド */
211        private         String  command                 = CMD_NEW;
212        /** テーブルID */
213        private         String  tableId                 = HybsSystem.TBL_MDL_KEY;
214        /** シート名 */
215        protected       String  sheetName               ;                                                                               // 3.5.4.2 (2003/12/15)
216        /** シート番号 */
217        protected       String  sheetNos                ;                                                                               // 5.5.7.2 (2012/10/09) 複数シートを指定できるようにシート番号を指定できるようにする。
218        /** 固定値となるカラム名 */
219        protected       String  sheetConstKeys  ;                                                                               // 5.5.8.2 (2012/11/09) 固定値となるカラム名(CSV形式)
220        /** 固定値となるアドレス */
221        protected       String  sheetConstAdrs  ;                                                                               // 5.5.8.2 (2012/11/09) 固定値となるアドレス(行-列,行-列,・・・)
222        /** 取込み条件/Sheet BREAK条件 */
223        protected       String  nullBreakClm    ;                                                                               // 5.5.8.2 (2012/11/09) 取込み条件/Sheet BREAK条件
224        /** 行読み飛ばし */
225        protected       String  nullSkipClm             ;                                                                               // 6.2.3.0 (2015/05/01) 行読み飛ばし
226
227        /** 3.5.4.5 (2004/01/23) 外部よりカラム列(CSV形式)を指定できるようにする */
228        protected String columns                        ;                                                                               // 6.2.0.0 (2015/02/27) protected化
229        /** 6.1.0.0 (2014/12/26) 読取対象外のカラム列を、外部(タグ)より指定する */
230        protected       boolean useNumber               = true;                                                                 // 3.7.0.5 (2005/04/11)
231//      /** 7.3.0.0 (2021/01/06) useRepeatClms 属性を追加 */
232//      protected       boolean useRepeatClms   ;                                                                               // 7.3.0.0 (2021/01/06)
233        /** stopZero属性 */
234        protected       boolean stopZero                ;                                                                               // 4.3.7.0 (2009/06/01) stopZero属性追加
235
236        /** メイントランザクションかどうか */
237        private         boolean isMainTrans             = true;                                                                 // 5.1.6.0 (2010/05/01) DBLastSqlの処理の見直し
238        /** データの読み飛ばし設定 */
239        protected       int             skipRowCount    ;                                                                               // 5.1.6.0 (2010/05/01) データの読み飛ばし設定
240
241        /** 6.2.2.0 (2015/03/27) ColumnAction インナークラスでパラメータを整理する */
242        protected       transient       ColumnAction clmAct     = new ColumnAction();                   // 6.3.9.0 (2015/11/06) transient 追加
243
244        // 6.3.6.1 (2015/08/28) DirectTableInsertTag でSQLException発生時にセットする。(暫定対応)
245        // 8.1.1.0 (2022/02/04) sqlError フラグでの判定は、DirectTableInsertTag のみで行います。
246//      protected       boolean         sqlError        ;                                                                               // 6.3.6.1 (2015/08/28)
247
248        /** 7.0.7.0 (2019/12/13) エラーメッセージにSLABELを利用するかどうか[true/false]を指定します(初期値:false) */
249        protected       boolean         useSLabel       ;
250        /** クラウド設定を使用するかどうか */
251        private         boolean         useLocal        ;                                                                               // 8.0.1.0 (2021/10/29) クラウド設定を使用しない場合は、true
252
253        /**
254         * デフォルトコンストラクター
255         *
256         * @og.rev 6.4.2.0 (2016/01/29) PMD refactoring. Each class should declare at least one constructor.
257         */
258        public ReadTableTag() { super(); }              // これも、自動的に呼ばれるが、空のメソッドを作成すると警告されるので、明示的にしておきます。
259
260        /**
261         * Taglibの終了タグが見つかったときに処理する doEndTag() を オーバーライドします。
262         *
263         * @og.rev 3.0.1.4 (2003/03/17) displayMsg が 0Byteの場合は、件数も表示しないように変更。
264         * @og.rev 3.1.1.2 (2003/04/04) Tomcat4.1 対応。release2() を doEndTag()で呼ぶ。
265         * @og.rev 3.5.4.1 (2003/12/01) 引数の BufferedReader を、InputStream に変更。
266         * @og.rev 3.5.4.3 (2004/01/05) 引数の InputStream を、 BufferedReader に戻す。
267         * @og.rev 3.5.6.5 (2004/08/09) 暫定的に、DBTableModelを先行削除します。
268         * @og.rev 3.6.0.0 (2004/09/24) DBTableModel の先行削除は、scope="session" の場合のみ。
269         * @og.rev 3.6.0.2 (2004/10/04) 取込時チェック用に、checkColumns,adjustColumns 属性追加
270         * @og.rev 3.6.0.8 (2004/11/19) DBTableModel をセーブする時に、トランザクションチェックを行います。
271         * @og.rev 3.8.5.3 (2006/08/07) readerClassが "Excel"でエラーが発生したとき、もう一度Defaultで再読取を行います。
272         * @og.rev 4.0.0.0 (2007/10/12) checkTableColumn 前に、modifyType 設定を行います。
273         * @og.rev 4.0.0.0 (2007/10/18) メッセージリソース統合( getResource().getMessage ⇒ getResource().getLabel )
274         * @og.rev 4.3.1.1 (2008/10/08) columnsが指定されている場合は、AutoReader禁止
275         * @og.rev 4.3.7.0 (2009/06/01) stopZero機能,DB.COUNTリクエストキーへ読込件数セットを追加
276         * @og.rev 5.1.6.0 (2010/05/01) DBLastSqlの処理は、DBTableModelが新規作成された処理でのみ行う。
277         * @og.rev 5.1.8.0 (2010/07/01) AutoReaderのCalc対応
278         * @og.rev 5.1.9.0 (2010/08/01) AutoReaderでのExceptionの判定をThrowableに変更
279         * @og.rev 5.7.1.2 (2013/12/20) tempMsg.toString() ⇒ errMsg 変更
280         * @og.rev 5.7.7.2 (2014/06/20) caseKey,caseVal,caseNN,caseNull 属性を追加
281         * @og.rev 6.0.2.5 (2014/10/31) debug=true 時のエラー情報を増やします。
282         * @og.rev 6.2.0.0 (2015/02/27) TableReader クラスの呼び出し元メソッドの共通化(EXCEL,TEXT)
283         * @og.rev 6.2.0.0 (2015/02/27) EXCEL出力のparamLevel初期値変更 3:標準推奨 → 4:個人設定可
284         * @og.rev 6.2.2.0 (2015/03/27) ColumnAction インナークラスでパラメータを整理する。
285         * @og.rev 6.2.3.0 (2015/05/01) 複数処理を考慮して、例外処理は発行しない。
286         * @og.rev 6.2.3.0 (2015/05/01) columnsが指定されていても、AutoReader を使えるようにします。
287         * @og.rev 6.2.4.2 (2015/05/29) エラーを画面に出します。
288         * @og.rev 6.2.5.0 (2015/06/05) AutoReaderの仕様変更。
289         * @og.rev 6.3.6.1 (2015/08/28) DirectTableInsertTag でSQLException発生時のみ throwする。
290         * @og.rev 6.4.2.0 (2016/01/29) StringUtil#ogStackTrace(Throwable) を、ThrowUtil#ogStackTrace(String,Throwable) に置き換え。
291         * @og.rev 6.4.3.4 (2016/03/11) String配列 から、Setに置き換えます。
292         * @og.rev 6.4.5.1 (2016/04/28) CSV 指定時は、readerClass="Text" , separator="," に、再設定します。
293         * @og.rev 6.5.0.1 (2016/10/21) Throwable ではなく、OgCharacterException をキャッチして、処理を継続します。
294         * @og.rev 7.0.4.0 (2019/05/31) encode指定時の処理順序変更
295         * @og.rev 7.0.5.0 (2019/09/09) OgCharacterExceptionでは、取りこぼしがあるため、OgRuntimeException も継続処理するように変更。
296         * @og.rev 8.0.0.1 (2021/10/08) クラウド対応
297         * @og.rev 8.0.0.2 (2021/10/15) TableReader系は、クラウドから、ローカルファイルに移してから処理する。
298         * @og.rev 8.1.1.0 (2022/02/04) sqlError フラグでの判定は、DirectTableInsertTag のみで行います。
299         * @og.rev 8.1.2.3 (2022/05/20) readerClass が AutoReader の時、readerClass が Text になるバグ修正
300         *
301         * @return      後続処理の指示
302         */
303        @Override
304        public int doEndTag() {
305                debugPrint();           // 4.0.0 (2005/02/28)
306                // 5.7.7.2 (2014/06/20) caseKey,caseVal,caseNN,caseNull 属性を追加
307                if( !useTag() ) { return EVAL_PAGE ; }
308
309                int rtnCode = EVAL_PAGE;
310
311                if( check( command, COMMAND_SET ) ) {
312                        useMainTrans( isMainTrans );                    // 5.1.6.0 (2010/05/01) DBLastSqlの処理の見直し
313                        startQueryTransaction( tableId );               // 3.6.0.8 (2004/11/19)
314
315                        // 3.5.6.5 (2004/08/09) 削除するのは、セッションのオブジェクトでよい。
316                        // 3.6.0.0 (2004/09/24) 削除するのは、scope="session" の場合のみ。
317                        if( "session".equals( getScope() ) ) {
318                                removeSessionAttribute( tableId );
319                                removeSessionAttribute( HybsSystem.VIEWFORM_KEY );
320                        }
321
322                        // 6.2.5.0 (2015/06/05) AutoReaderの仕様変更。
323
324                        // 6.2.0.0 (2015/02/27) EXCEL出力のparamLevel初期値変更 3:標準推奨 → 4:個人設定可
325                        if( readerClass == null ) {
326                                readerClass = nval( sys( "TABLE_READER_DEFAULT_CLASS" ) , "AutoReader" );
327                        }
328
329                        // ファイル の読み込み:AutoReader 処理
330                        // 6.2.5.0 (2015/06/05) AutoReaderParam 内部クラスを使用します。
331                        final List<AutoReaderParam> readerParam = new ArrayList<>() ;
332
333                        if( "AutoReader".equalsIgnoreCase( readerClass ) ) {
334                                // 4.3.1.1 (2008/10/08)
335        //                      // 6.2.3.0 (2015/05/01) columnsが指定されていても、AutoReader を使えるようにします。
336        //                      if( columns != null && columns.length() > 0 ) {
337        //                              final String errMsg = "columnsが指定されている場合は、readerClass=\"AutoReader\"は使えません";
338        //                              throw new HybsSystemException( errMsg );        // 4.3.4.4 (2009/01/01)
339        //                      }
340                                // 6.2.5.0 (2015/06/05) AutoReaderParam 内部クラスを使用します。
341                                // 6.5.0.1 (2016/10/21) encode 指定時の優先は、拡張子が、txt か、csv のみとします。
342        //                      if( encode != null ) { readerParam.add( new AutoReaderParam( "Text" , encode , null ) ); }                              // encode 指定時は優先
343//                              if( encode != null ) { readerParam.add( new AutoReaderParam( "Text" , encode , "csv,txt,xls" ) ); }             // encode 指定時は優先
344//                              if( encode != null ) { readerParam.add( new AutoReaderParam( "Text" , encode , "txt,csv,xls" ) ); }             // encode 指定時は優先  7.0.4.0 (2019/05/31) 順序変更
345                                if( encode != null ) {
346                                        readerParam.add( new AutoReaderParam( "Text" , encode , "txt,csv,xls" ) );              // encode 指定時は優先  7.0.4.0 (2019/05/31) 順序変更
347                                        readerParam.add( new AutoReaderParam( "Text" , encode , null          ) );              // 7.1.0.0 (2020/01/20) 拡張子に関係ない分も追加
348                                }
349                                readerParam.addAll( AUTO_READER_PARAM );                // 標準のパラメータを追加します。
350                        }
351                        else {
352                                // 6.2.5.0 (2015/06/05) readerClass が "Text" で、encode が null の場合は、FILE_ENCODE を使用する。
353                                if( "Text".equalsIgnoreCase( readerClass ) && encode == null ) { encode = HybsSystem.sys( "FILE_ENCODE" ); }
354                                readerParam.add( new AutoReaderParam( readerClass , encode , null ) );  // 8.1.2.3 (2022/05/20) 復活
355//                              readerParam.add( new AutoReaderParam( "Text" , encode , null ) );               // 8.1.1.0 (2022/02/04) 勘違い?
356                        }
357
358                        final String directory = HybsSystem.url2dir( fileURL );
359                        final File file = new File( directory,filename );
360                        // 8.0.0.2 (2021/10/15) TableReader系は、クラウドから、ローカルファイルに移してから処理する。
361                        // ※ readなので、クラウドに戻す必要はない。
362                        HybsFileOperationFactory.cloud2local( useLocal,() -> file );
363
364//                      // 8.0.0.1 (2021/10/08) クラウド対応
365//                      final File file = HybsFileOperationFactory.create( directory, filename );
366
367                        final String sufix = FileInfo.getSUFIX( file ) ;                // 6.2.3.0 (2015/05/01) 拡張子に応じて、チェックを変更する。
368
369                        StringBuilder tempMsg = new StringBuilder( BUFFER_MIDDLE );
370                        // 6.2.5.0 (2015/06/05) AutoReaderParam 内部クラスを使用します。
371                        for( final AutoReaderParam arParam : readerParam ) {
372                                // 6.2.0.0 (2015/02/27) 拡張子に応じて、チェックを変更する。
373                                if( !arParam.useSufix( sufix ) ) { continue; }          // false:対象外の場合は、次のreaderClassを使う。
374
375                                readerClass = arParam.CLASS;
376                                encode      = arParam.ENCODE;
377
378                                // 6.4.5.1 (2016/04/28) CSV 指定時は、readerClass="Text" , separator="," に、再設定します。
379                                if( "CSV".equalsIgnoreCase( readerClass ) || "CSV".equalsIgnoreCase( sufix ) ) {
380                                        readerClass = "Text";
381                                        separator   = ",";
382                                }
383
384                                if( isDebug() ) {
385                                        final String errMsg = "File=[" + file + "] , class=[" + readerClass + "] , encode=[" + encode + "]" + BR ;
386                                        jspPrint( errMsg );
387                                        System.out.println( errMsg );
388                                }
389
390                                try {
391                                        clmAct.isDebug = isDebug();
392//                                      sqlError = false;       // 6.3.6.1 (2015/08/28) DirectTableInsertTag でSQLException発生時のみ処理する。
393                                        create( file );         // 6.2.0.0 (2015/02/27) TableReader クラスの呼び出し元メソッドの共通化(EXCEL,TEXT)
394
395                                        // 成功すれば、エラーメッセージをクリアして、その場で抜ける。
396                                        tempMsg = null;
397                                        break;
398                                }
399                                // 6.2.2.0 (2015/03/27) HybsOverflowException処理をタグ側で行う。
400                                catch( final HybsOverflowException ex ) {
401                                        // table.setOverflow( true ); は、処理済み。ループから抜けて処理を継続する。
402                                        tempMsg = null;
403                                        break;
404                                }
405                                // 6.3.6.1 (2015/08/28) DirectTableInsertTag でSQLException発生時のみ処理する。
406                                catch( final HybsSystemException ex ) {
407//                                      if( sqlError ) { throw ex; }    // SQLException発生時は処理中止
408                                        // 8.1.1.0 (2022/02/04) sqlError フラグでの判定は、DirectTableInsertTag のみで行います。
409                                        tempMsg.append( "File=["  ).append( file )
410                                                        .append( "] , Class=["   ).append( readerClass )
411                                                        .append( "] , Encode=["  ).append( encode )
412                                                        .append( "] Error!"      ).append( CR )
413                                                        .append( ex.getMessage() ).append( CR ) ;
414                                }
415                                // 3.8.5.3 (2006/08/07) readerClassが "Excel"でエラーが発生したとき、もう一度Defaultで再読取を行います。
416                                // 5.1.9.0 (2010/08/01) RuntimeException系のExceptionがキャッチできないため、Throwableで受ける
417                                // 6.5.0.1 (2016/10/21) Throwable ではなく、OgCharacterException をキャッチして、処理を継続します。
418                                catch( final OgCharacterException ex ) {
419                                        tempMsg.append( "File=["  ).append( file )
420                                                        .append( "] , Class=["   ).append( readerClass )
421                                                        .append( "] , Encode=["  ).append( encode )
422                                                        .append( "] Error!"      ).append( CR )
423                                                        .append( ex.getMessage() ).append( CR ) ;
424        //                              if( isDebug() ) {
425        //                                      jspPrint( "<pre>" + tempMsg.toString() + "</pre>" );                            // 6.2.4.2 (2015/05/29) 画面にも出力します。
426        //                                      tempMsg.append( ThrowUtil.ogStackTrace( ex ) ).append( CR ) ;           // 6.4.2.0 (2016/01/29)
427        //                              }
428                                }
429                                // 7.0.5.0 (2019/09/09) OgCharacterExceptionでは、取りこぼしがあるため、OgRuntimeException も継続処理するように変更。
430                                catch( final OgRuntimeException ex ) {
431                                        tempMsg.append( "File=["  ).append( file )
432                                                        .append( "] , Class=["   ).append( readerClass )
433                                                        .append( "] , Encode=["  ).append( encode )
434                                                        .append( "] Error!"      ).append( CR )
435                                                        .append( ex.getMessage() ).append( CR ) ;
436
437                                        // 拡張子が、xls 以外は、処理を停止します。
438        //                              if( !"xls".equalsIgnoreCase( sufix ) ) {
439                                        // 8.1.1.0 (2022/02/04) 拡張子は、xls,xlsx 以外とする。
440                                        if( !"xls".equalsIgnoreCase( sufix ) || !"xlsx".equalsIgnoreCase( sufix ) ) {
441                                                tempMsg.append( ThrowUtil.ogStackTrace( ex ) ).append( CR ) ;
442        //                                      break;          様子見。当面は、止めません。
443                                        }
444                                }
445                                // 6.5.0.1 (2016/10/21) Throwable をキャッチして、処理を中断します。
446                                catch( final Throwable th ) {
447                                        tempMsg.append( "File=["  ).append( file )
448                                                        .append( "] , Class=["   ).append( readerClass )
449                                                        .append( "] , Encode=["  ).append( encode )
450                                                        .append( "] Error!"      ).append( CR )
451                                                        .append( ThrowUtil.ogStackTrace( th ) ).append( CR ) ;          // 6.4.2.0 (2016/01/29)
452                                        break;
453                                }
454                        }
455
456                        // 6.2.3.0 (2015/05/01) 複数処理を考慮して、例外処理は発行しない。
457                        // 6.4.1.1 (2016/01/16) PMD refactoring. Avoid if (x != y) ..; else ..;
458                        if( tempMsg == null ) {
459                                // 6.2.2.0 (2015/03/27) #afterEnd() メソッド 新規作成。
460                                rtnCode = afterEnd();
461                        }
462                        else {                                                          // 最後までエラーがあれば、例外処理を発行します。
463                                final String errMsg = tempMsg.toString();
464                                System.err.print( errMsg );
465                                jspPrint( "<pre>" + errMsg + "</pre>" );                // 6.2.4.0 (2015/05/15) エラーを画面に出します。
466                                rtnCode = SKIP_PAGE;                                                    // 6.2.4.2 (2015/05/29) エラー時はSKIP
467                        }
468                }
469
470                return rtnCode ;
471        }
472
473        /**
474         * #doEndTag() の後続処理を記述します。
475         *
476         * これは、サブクラスで、DBTableModel以外の処理を行う場合に、
477         * 処理内容を分けるために用意します。
478         *
479         * @og.rev 6.2.2.0 (2015/03/27) #afterEnd() メソッド 新規作成。
480         * @og.rev 6.2.4.2 (2015/05/29) executeCount の設定がおかしい。ReadTableTagでは、設定されていなかった。
481         * @og.rev 6.2.5.0 (2015/06/05) エラー処理は、継承先でも行うので、メソッド化します。
482         * @og.rev 7.0.7.0 (2019/12/13) useSLabel 属性を追加。
483         *
484         * @return      後続処理の指示
485         */
486        protected int afterEnd() {
487                if( table != null ) {
488                        // 6.2.4.2 (2015/05/29) executeCount が設定されなくなった件
489                        executeCount = table.getRowCount();
490
491                        // 3.6.0.2 (2004/10/04)
492                        // 4.0.0.0 (2007/10/12) checkTableColumn 前に、modifyType 設定を行います。
493
494                        // 6.2.5.0 (2015/06/05) エラー処理は、継承先でも行うので、メソッド化します。
495                        final ErrorMessage errMsg = clmAct.getErrorMessage();
496                        if( !errMsg.isOK() ) {
497//                              jspPrint( TaglibUtil.makeHTMLErrorTable( errMsg,getResource() ) );
498                                jspPrint( TaglibUtil.makeHTMLErrorTable( errMsg,getResource(),useSLabel ) );            // 7.0.7.0 (2019/12/13)
499                                return SKIP_PAGE ;
500                        }
501                }
502
503                // 3.6.0.8 (2004/11/19) トランザクションチェックを行います。
504                if( ! commitTableObject( tableId, table ) ) {
505                        jspPrint( "ReadTableTag Query処理が割り込まれました。DBTableModel は登録しません。" );
506                        return SKIP_PAGE ;
507                }
508
509                final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE );
510
511                // 実行件数の表示 command="NEW" のときのみ、displayMsg を表示させます。
512                // 4.0.0 (2005/11/30) 出力順の変更。一番最初に出力します。
513                if( CMD_NEW.equals( command ) ) {
514                        if( executeCount > 0 && displayMsg != null && displayMsg.length() > 0 ) {
515                                buf.append( executeCount )
516                                        .append( getResource().getLabel( displayMsg ) )
517                                        .append( BR );
518                        }
519                        else if( executeCount == 0 && notfoundMsg != null && notfoundMsg.length() > 0 ) {
520                                buf.append( getResource().getLabel( notfoundMsg ) )
521                                        .append( BR );
522                        }
523                }
524
525                // 4.3.7.0 (2009/06/01) 読込件数を、"DB.COUNT" キーでリクエストにセットする。
526                setRequestAttribute( "DB.COUNT"   , String.valueOf( executeCount ) );
527
528                // 6.2.0.0 (2015/02/27) オーバーフロー時のメッセージを表示
529                if( table != null && table.isOverflow() && overflowMsg != null && overflowMsg.length() > 0  ) {
530                        buf.append( getResource().getLabel( overflowMsg ) )
531                                .append( BR );
532                }
533
534                jspPrint( buf.toString() );
535
536                // 4.3.7.0 (2009/06/01) stopZero機能を追加
537                return executeCount == 0 && stopZero ? SKIP_PAGE : EVAL_PAGE ;
538        }
539
540        /**
541         * タグリブオブジェクトをリリースします。
542         * キャッシュされて再利用されるので、フィールドの初期設定を行います。
543         *
544         * @og.rev 2.0.0.4 (2002/09/27) カスタムタグの release() メソッドを、追加
545         * @og.rev 3.1.1.2 (2003/04/04) Tomcat4.1 対応。release2() を doEndTag()で呼ぶ。
546         * @og.rev 3.1.3.0 (2003/04/10) FILE_ENCODE から、エンコード情報を取得する。
547         * @og.rev 3.1.4.0 (2003/04/18) command 属性に、初期値(NEW)を設定する。
548         * @og.rev 3.5.4.2 (2003/12/15) EXCELのシート名を指定できるように変更。
549         * @og.rev 3.5.4.5 (2004/01/23) 外部よりカラム列(CSV形式)を指定できるようにする。
550         * @og.rev 3.6.0.2 (2004/10/04) checkColumns,adjustColumns,allColumnCheck 属性追加
551         * @og.rev 3.7.0.5 (2005/04/11) useNumber 属性を追加します。
552         * @og.rev 3.8.0.2 (2005/06/30) nullCheck 属性追加
553         * @og.rev 3.8.5.3 (2006/08/07) readerClass 属性の初期値をシステムリソースより取得します。
554         * @og.rev 4.3.7.0 (2009/06/01) stopZero属性追加
555         * @og.rev 5.1.6.0 (2010/05/01) DBLastSqlの処理は、DBTableModelが新規作成された処理でのみ行う。
556         * @og.rev 5.1.6.0 (2010/05/01) データの読み飛ばし設定 skipRowCount 属性追加
557         * @og.rev 5.2.1.0 (2010/10/01) 読取処理でコードリソースのラベル変換を行うかどうか useRenderer 属性追加
558         * @og.rev 5.5.7.2 (2012/10/09) 複数シートを指定できるようにシート番号を指定できるように、sheetNos属性追加
559         * @og.rev 5.5.8.2 (2012/11/09) 固定値となるカラム名、アドレスの指定のための、sheetConstKeys、sheetConstAdrs属性追加
560         * @og.rev 5.5.8.2 (2012/11/09) カラム列に NULL が現れた時点で読取を中止する、nullBreakClm属性追加
561         * @og.rev 6.1.0.0 (2014/12/26) omitNames 属性を追加
562         * @og.rev 6.2.0.0 (2015/02/27) オーバーフロー時のメッセージを表示
563         * @og.rev 6.2.0.0 (2015/02/27) EXCEL出力のparamLevel初期値変更 3:標準推奨 → 4:個人設定可
564         * @og.rev 6.2.2.0 (2015/03/27) ColumnAction インナークラスでパラメータを整理する。
565         * @og.rev 6.2.3.0 (2015/05/01) 行読み飛ばし nullSkipClm追加
566         * @og.rev 6.2.5.0 (2015/06/05) ファイルエンコードの初期化を遅らせます。
567         * @og.rev 7.0.7.0 (2019/12/13) useSLabel 属性を追加。
568         * @og.rev 8.0.1.0 (2021/10/29) useLocal 属性を追加。
569         */
570        @Override
571        protected void release2() {
572                super.release2();
573                separator               = TableReader.TAB_SEPARATOR;                                                    // 項目区切り文字
574                fileURL                 = HybsSystem.sys( "FILE_URL" );                                                 // ファイルURL
575                filename                = HybsSystem.sys( "FILE_FILENAME" );                                    // ファイル名
576                encode                  = null;                                                                                                 // 6.2.5.0 (2015/06/05) ファイルエンコーディング
577                readerClass             = null;                                                                                                 // 6.2.0.0 (2015/02/27)
578                maxRowCount             = 0 ;                                                                                                   // 6.2.2.0 (2015/03/27)
579                displayMsg              = HybsSystem.sys( "VIEW_DISPLAY_MSG" );
580                overflowMsg             = "MSG0007";                                                                                    // 検索結果が、制限行数を超えましたので、残りはカットされました。
581                notfoundMsg             = "MSG0077";                                                                                    // 対象データはありませんでした。
582                executeCount    = -1;                                                                                                   // 検索/実行件数
583                modifyType              = null;
584                command                 = CMD_NEW;
585                table                   = null;
586                tableId                 = HybsSystem.TBL_MDL_KEY ;
587                sheetName               = null;                                                                                                 // 3.5.4.2 (2003/12/15)
588                sheetNos                = null;                                                                                                 // 5.5.7.2 (2012/10/09) 複数シートを指定できるようにシート番号を指定できるようにする。
589                sheetConstKeys  = null;                                                                                                 // 5.5.8.2 (2012/11/09) 固定値となるカラム名(CSV形式)
590                sheetConstAdrs  = null;                                                                                                 // 5.5.8.2 (2012/11/09) 固定値となるアドレス(行-列,行-列,・・・)
591                nullBreakClm    = null;                                                                                                 // 5.5.8.2 (2012/11/09) 取込み条件/Sheet BREAK条件
592                nullSkipClm             = null;                                                                                                 // 6.2.3.0 (2015/05/01) 行読み飛ばし
593                columns                 = null;                                                                                                 // 3.5.4.5 (2004/01/23)
594                useNumber               = true;                                                                                                 // 3.7.0.5 (2005/04/11)
595//              useRepeatClms   = false;                                                                                                // 7.3.0.0 (2021/01/06)
596                stopZero                = false;                                                                                                // 4.3.7.0 (2009/06/01) soptZero追加
597                isMainTrans             = true;                                                                                                 // 5.1.6.0 (2010/05/01) DBLastSqlの処理の見直し
598                skipRowCount    = 0;                                                                                                    // 5.1.6.0 (2010/05/01) データの読み飛ばし設定
599                clmAct                  = new ColumnAction();                                                                   // 6.2.2.0 (2015/03/27)
600                useSLabel               = false;                                                                                                // 7.0.7.0 (2019/12/13) エラーメッセージにSLABELを利用するかどうか[true/false]を指定します(初期値:false)
601                useLocal                = false;                                                                                                // 8.0.1.0 (2021/10/29) クラウド設定を使用しない場合は、true
602        }
603
604        /**
605         * TableReader の実オブジェクトを生成して、BufferedReader に書き込みます。
606         *
607         * @og.rev 3.5.4.1 (2003/12/01) 引数の BufferedReader を、InputStream に変更。
608         * @og.rev 3.5.4.2 (2003/12/15) TableReader のサブクラス名変更。
609         * @og.rev 3.5.4.2 (2003/12/15) EXCELのシート名を指定できるように変更。
610         * @og.rev 3.5.4.3 (2004/01/05) 引数の InputStream を、 BufferedReader に戻す。
611         * @og.rev 3.5.4.5 (2004/01/23) TableReader に、encode を渡すように変更。
612         * @og.rev 3.5.6.0 (2004/06/18) 各種プラグイン関連付け設定を、システムパラメータ に記述します。
613         * @og.rev 3.7.0.5 (2005/04/11) useNumber 属性を追加します。
614         * @og.rev 4.0.0.0 (2005/01/31) キーの指定を、TableReader. から、TableReader_ に変更します。
615         * @og.rev 4.0.0.0 (2005/01/31) lang ⇒ ResourceManager へ変更
616         * @og.rev 5.1.6.0 (2010/05/01) データの読み飛ばし設定 skipRowCount 属性追加
617         * @og.rev 5.2.1.0 (2010/10/01) 読取処理でコードリソースのラベル変換を行うかどうか設定 useRenderer 属性追加
618         * @og.rev 5.5.7.2 (2012/10/09) 複数シートを指定できるようにシート番号を指定できるように、sheetNos属性追加
619         * @og.rev 5.5.8.2 (2012/11/09) 固定値となるカラム名、アドレスの指定のための、sheetConstKeys、sheetConstAdrs属性追加
620         * @og.rev 5.5.8.2 (2012/11/09) カラム列に NULL が現れた時点で読取を中止する、nullBreakClm属性追加
621         * @og.rev 6.0.4.0 (2014/11/28) NullPointerException が発生するので、事前にチェックします。
622         * @og.rev 6.2.0.0 (2015/02/27) TableReader クラスの呼び出し元メソッドの共通化(EXCEL,TEXT)
623         * @og.rev 6.2.2.0 (2015/03/27) ColumnAction インナークラスでパラメータを整理する。
624         * @og.rev 6.2.2.0 (2015/03/27) ColumnActionListener 対応。
625         * @og.rev 6.2.3.0 (2015/05/01) 行読み飛ばし nullSkipClm追加
626         * @og.rev 6.4.1.2 (2016/01/22) setColumnActionListener は、内部処理が走るため、他の設定が終わってから呼び出す。
627         * @og.rev 6.4.3.3 (2016/03/04) HybsSystem.newInstance(String,String) への置き換え。
628         * @og.rev 7.3.0.0 (2021/01/06) ColumnActionListenerインターフェースを無名内部クラスから、内部クラスへ。
629         * @og.rev 7.3.0.0 (2021/01/06) 横持ちデータの繰り返し対応
630         *
631         * @param       file    出力するFileオブジェクト
632         */
633        protected void create( final File file )  {
634                table = DBTableModelUtil.newDBTable();                  // 6.2.1.0 (2015/03/13)
635
636                final ColumnActionListener listener = new NormalCAListener();
637
638                final TableReader reader = HybsSystem.newInstance( "TableReader_" , readerClass );      // 3.5.5.3 (2004/04/09)
639
640                reader.setSeparator( separator );
641                reader.setColumns( columns );                                   // 3.5.4.5 (2004/01/23) 、6.2.0.0 (2015/02/27) 削除
642                reader.setUseNumber( useNumber );                               // 3.7.0.5 (2005/04/11)
643                reader.setSkipRowCount( skipRowCount );                 // 5.1.6.0 (2010/05/01)
644                reader.setDebug( isDebug() );                                   // 5.5.7.2 (2012/10/09) デバッグ情報を出力するかどうかを指定
645                // 6.2.0.0 (2015/02/27) EXCELでない場合でも、メソッドは呼び出す。(空振りします)
646                reader.setSheetName( sheetName );                       // 3.5.4.2 (2003/12/15)
647                reader.setSheetNos( sheetNos );                         // 5.5.7.2 (2012/10/09) 複数シートを指定できるようにシート番号を指定できるようにする。
648                reader.setSheetConstData( sheetConstKeys,sheetConstAdrs ) ;             // 5.5.8.2 (2012/11/09) 固定値となるカラム名、アドレスの指定
649                reader.setNullBreakClm( nullBreakClm ) ;        // 5.5.8.2 (2012/11/09) 取込み条件/Sheet BREAK条件
650                reader.setNullSkipClm( nullSkipClm ) ;          // 6.2.3.0 (2015/05/01) 行読み飛ばし
651                // 6.4.1.2 (2016/01/22) setColumnActionListener は、内部処理が走るため、他の設定が終わってから呼び出す。
652                reader.setColumnActionListener( listener );             // 6.2.2.0 (2015/03/27)
653                reader.readDBTable( file,encode );                      // 6.2.0.0 (2015/02/27) 追加
654        }
655
656        /**
657         * ColumnActionListenerインターフェースの内部クラス
658         *
659         * @og.rev 6.2.2.0 (2015/03/27) ColumnActionListener 対応。
660         * @og.rev 7.3.0.0 (2021/01/06) ColumnActionListenerインターフェースを無名内部クラスから、内部クラスへ。
661         * @og.rev 7.3.1.1 (2021/02/25) カラム列を、"DB.NAMES" キーでリクエストにセットする。
662         *
663         * @param       names   カラム名配列
664         */
665        private final class NormalCAListener implements ColumnActionListener {
666//      final ColumnActionListener listener = new ColumnActionListener() {
667                private DBColumn[] dbClms ;                             // 6.3.9.1 (2015/11/27) 修飾子を、なし → private に変更。
668
669                /**
670                 * デフォルトコンストラクター
671                 *
672                 * @og.rev 7.3.0.0 (2021/01/06) PMD refactoring. Each class should declare at least one constructor.
673                 */
674                public NormalCAListener() { super(); }          // これも、自動的に呼ばれるが、空のメソッドを作成すると警告されるので、明示的にしておきます。
675
676                /**
677                 * カラム名の配列が設定された場合に、呼び出されます。
678                 *
679                 * @og.rev 6.2.2.0 (2015/03/27) ColumnActionListener 対応。
680                 * @og.rev 7.3.1.1 (2021/02/25) カラム列を、"DB.NAMES" キーでリクエストにセットする。
681                 *
682                 * @param       names   カラム名配列
683                 */
684                @Override       // ColumnActionListener
685                public void columnNames( final String[] names ) {
686                        final String[] nms = clmAct.makeNames( names );
687                        table.init( nms.length );
688                        dbClms = new DBColumn[nms.length];
689                        final StringBuilder nmsBuf = new StringBuilder( BUFFER_MIDDLE );                // 7.3.1.1 (2021/02/25)
690                        for( int no=0; no<nms.length; no++ ) {
691                                nmsBuf.append( ',' ).append( nms[no] );                                                         // 7.3.1.1 (2021/02/25)
692                                dbClms[no] = getDBColumn( nms[no] );
693                                table.setDBColumn( no,dbClms[no] );
694                        }
695
696                        if( nmsBuf.length() > 1 ) {             // 7.3.1.1 (2021/02/25) 最初のカンマを削除して、DB.NAMES で登録する。
697                                setRequestAttribute( "DB.NAMES" , nmsBuf.substring(1) );
698                        }
699                }
700
701                /**
702                 * #NAME のオリジナルカラム名配列がそろった段階で、イベントが発生します。
703                 *
704                 * @og.rev 7.3.1.3 (2021/03/09) #NAMEのオリジナルを取得できるようにします。
705                 *
706                 * @param       names   カラム名配列
707                 */
708                @Override       // ColumnActionListener
709                public void originalNames( final String[] names ) {
710                        if( names != null && names.length > 0 ) {
711                                final StringBuilder nmsBuf = new StringBuilder( BUFFER_MIDDLE );
712                                for( int no=0; no<names.length; no++ ) {
713                                        nmsBuf.append( ',' ).append( names[no] );
714                                }
715
716                                if( nmsBuf.length() > 1 ) {             // 7.3.1.1 (2021/02/25) 最初のカンマを削除して、DB.NAMES で登録する。
717                                        setRequestAttribute( "DB.ORGNAMES" , nmsBuf.substring(1) );
718                                }
719                        }
720                }
721
722                /**
723                 * 1行分のデータが設定された場合に、呼び出されます。
724                 *
725                 * @og.rev 6.2.2.0 (2015/03/27) ColumnActionListener 対応。
726                 * @og.rev 6.4.6.0 (2016/05/27) レコードの読取条件指定を追加。条件に一致しなければ、null が返されます。
727                 * @og.rev 7.3.0.0 (2021/01/06) 横持ちデータの繰り返し対応
728                 * @og.rev 8.4.0.0 (2022/12/23) 7.1.0.0 (2020/01/27) の対応は、ReadTableTag に移動。
729                 *
730                 * @param       vals    文字列値の1行分の配列
731                 * @param       rowNo   行番号(0~)
732                 */
733                @Override       // ColumnActionListener
734                public void values( final String[] vals, final int rowNo ) {
735                        if( maxRowCount > 0 && rowNo > maxRowCount ) {          // 読み取り件数オーバーフロー
736                                table.setOverflow( true );
737                                throw new HybsOverflowException();
738                        }
739
740                        // 7.3.0.0 (2021/01/06) 横持ちデータの繰り返し対応。
741//                      final String[] newVals = clmAct.clmAction( vals , dbClms , rowNo );
742//                      // 6.4.6.0 (2016/05/27) レコードの読取条件指定を追加。条件に一致しなければ、null が返されます。
743//                      if( newVals != null ) {
744//                              table.addColumnValues( newVals,modifyType,true );       // 値配列、変更タイプ、書込許可
745//                      }
746                        final List<String[]> valsList = clmAct.clmAction( vals , dbClms , rowNo );
747                        if( valsList != null ) {                                                                // 8.4.0.0 (2022/12/23) nullチェック漏れ
748                                for( final String[] newVals : valsList ) {
749                                        // 8.4.0.0 (2022/12/23) セパレータ分割時にデータ分割されない場合は、エンコードエラーの可能性が高い
750                                        // 7.1.0.0 (2020/01/27) で、fukurou.model.TableModelHelper#value の処理を移植
751                                        if( table.getColumnCount() > 1 && newVals.length == 1 ) {
752                                                final String errMsg = "カラム数とデータ数が合いません。エンコードエラーの可能性があります。";
753                                                throw new OgCharacterException( errMsg );
754                                        }
755                                        table.addColumnValues( newVals,modifyType,true );       // 値配列、変更タイプ、書込許可
756                                }
757                        }
758                }
759
760                /**
761                 * 新しくEXCELのシートを処理する際に、シート名をセットするときに呼び出されます。
762                 *
763                 * @og.rev 7.3.1.1 (2021/02/25) 現在実行中のシート名を、"DB.SHEET_NAME" キーでリクエストにセットする。
764                 *
765                 * @param       sheetName       現在実行中のシート名
766                 */
767                @Override       // ColumnActionListener
768                public void shtName( final String sheetName ) {
769                        setRequestAttribute( "DB.SHEET_NAME" , sheetName );
770                }
771        }
772
773        /**
774         * 【TAG】(通常は使いません)結果のDBTableModelを、sessionに登録するときのキーを指定します
775         *              (初期値:HybsSystem#TBL_MDL_KEY[={@og.value HybsSystem#TBL_MDL_KEY}])。
776         *
777         * @og.tag
778         * 検索結果より、DBTableModelオブジェクトを作成します。これを、下流のviewタグ等に
779         * 渡す場合に、通常は、session を利用します。その場合の登録キーです。
780         * query タグを同時に実行して、結果を求める場合、同一メモリに配置される為、
781         * この tableId 属性を利用して、メモリ空間を分けます。
782         *              (初期値:HybsSystem#TBL_MDL_KEY[={@og.value HybsSystem#TBL_MDL_KEY}])。
783         *
784         * @param       id      テーブルID (sessionに登録する時のID)
785         */
786        public void setTableId( final String id ) {
787                tableId = nval( getRequestParameter( id ), tableId );
788        }
789
790        /**
791         * 【TAG】可変長ファイルを作成するときの項目区切り文字をセットします。
792         *
793         * @og.tag 可変長ファイルを作成するときの項目区切り文字をセットします。
794         *
795         * @param       separator       項目区切り文字
796         */
797        public void setSeparator( final String separator ) {
798                this.separator = nval( getRequestParameter( separator ),this.separator );
799        }
800
801        /**
802         * 【TAG】読取元ディレクトリ名を指定します
803         *              (初期値:FILE_URL[={@og.value SystemData#FILE_URL}])。
804         *
805         * @og.tag
806         * この属性で指定されるディレクトリより、ファイルを読取ます。
807         * 指定方法は、通常の fileURL 属性と同様に、先頭が、'/' (UNIX) または、2文字目が、
808         * ":" (Windows)の場合は、指定のURLそのままのディレクトリに、そうでない場合は、
809         * fileURL = "{&#064;USER.ID}" と指定すると、FILE_URL 属性で指定のフォルダの下に、
810         * さらに、各個人ID別のフォルダを作成して、そこを操作します。
811         * (初期値:システム定数のFILE_URL[={@og.value SystemData#FILE_URL}])。
812         *
813         * @og.rev 4.0.0.0 (2005/01/31) StringUtil.urlAppend メソッドの利用
814         * @og.rev 4.0.0.0 (2007/11/20) 指定されたディレクトリ名の最後が"\"or"/"で終わっていない場合に、"/"を付加する。
815         * @og.rev 6.4.2.1 (2016/02/05) URLの最後に、"/" を追加する処理を廃止。
816         *
817         * @param       url     読取元ディレクトリ名
818         * @see         org.opengion.hayabusa.common.SystemData#FILE_URL
819         */
820        public void setFileURL( final String url ) {
821                final String furl = nval( getRequestParameter( url ),null );
822                if( furl != null ) {
823                        fileURL = StringUtil.urlAppend( fileURL,furl );
824                }
825        }
826
827        /**
828         * 【TAG】ファイルを作成するときのファイル名をセットします
829         *              (初期値:FILE_FILENAME[={@og.value SystemData#FILE_FILENAME}])。
830         *
831         * @og.tag ファイルを作成するときのファイル名をセットします。
832         * (初期値:システム定数のFILE_FILENAME[={@og.value SystemData#FILE_FILENAME}])。
833         *
834         * @param       filename        ファイル名
835         * @see         org.opengion.hayabusa.common.SystemData#USE_SQL_INJECTION_CHECK
836         */
837        public void setFilename( final String filename ) {
838                this.filename = nval( getRequestParameter( filename ),this.filename );
839        }
840
841        /**
842         * 【TAG】ファイルを作成するときのファイルエンコーディング名をセットします
843         *              (初期値:FILE_ENCODE[={@og.value SystemData#FILE_ENCODE}])。
844         *
845         * @og.tag
846         * readerClass="AutoReader" の場合、ここで設定した encode が優先されます。
847         * readerClass="Text" の場合、encode が指定されていない場合は、初期値 の FILE_ENCODE が使用されます
848         *
849         * Shift_JIS,MS932,Windows-31J,UTF-8,ISO-8859-1,UnicodeLittle
850         * (初期値:システム定数のFILE_ENCODE[={@og.value SystemData#FILE_ENCODE}])。
851         *
852         * @og.rev 2.2.0.0 (2002/12/17) 中国語(国際化)対応 エンコードの取得方法変更
853         * @og.rev 3.1.3.0 (2003/04/10) FILE_ENCODE から、エンコード情報を取得する。
854         *
855         * @param       enc     ファイルエンコーディング名
856         * @see         <a href="http://www.iana.org/assignments/character-sets" target="_blank" >IANA Charset Registry</a>
857         * @see         org.opengion.hayabusa.common.SystemData#FILE_ENCODE
858         */
859        public void setEncode( final String enc ) {
860                encode = nval( getRequestParameter( enc ),encode );
861        }
862
863        /**
864         * 【TAG】実際に読み出すクラス名の略称(TableReader_**** の ****)をセットします
865         *              (初期値:TABLE_READER_DEFAULT_CLASS[={@og.value SystemData#TABLE_READER_DEFAULT_CLASS}])。
866         *
867         * @og.tag
868         * 実際に読み出すクラス名(の略称)をセットします。
869         * これは、org.opengion.hayabusa.io 以下の TableReader_**** クラスの **** を
870         * 与えます。これらは、TableReader インターフェースを継承したサブクラスです。
871         * 属性クラス定義の {@link org.opengion.hayabusa.io.TableReader TableReader} を参照願います。
872         * {@og.doc03Link readerClass TableReader_**** クラス}
873         * @og.rev 3.1.3.0 (2003/04/10) FILE_ENCODE から、エンコード情報を取得する。
874         *
875         * "AutoReader" は特別な名前で、Excel と Text(テキスト) を以下の順番で試します。
876         * Excel,Calc,Text(UnicodeLittle),Text(Windows-31J),Text(Windows-31J),Text(UTF-8),Text(EUC-JP)
877         * Excel については、拡張子を自動判定して、(xlsx か xls) 適切な処理を行います。
878         * 従来からの 拡張子のみ、xls のテキストファイルは、#NAME を見つけることができないため、エラーになり、
879         * 次のText読み取りにゆだねられます。
880         * UTF-8 のTEXTとWindows-31JのTEXTは、ヘッダー部での区別ができないため、java.nio.file.Files と Pathを
881         * 使用した読み取り方式に変更しています。
882         * "AutoReader" に設定した場合は、上記の様に、encode を順番に確かめるため、encode属性の指定は無視されます。
883         *              (初期値:TABLE_READER_DEFAULT_CLASS[={@og.value SystemData#TABLE_READER_DEFAULT_CLASS}])。
884         *
885         * @og.rev 6.2.1.0 (2015/03/13) Default廃止に伴い、Defaultが指定された場合は、Textに置き換える。
886         *
887         * @param       readerCls       クラス名(の略称)
888         * @see         org.opengion.hayabusa.io.TableReader  TableReaderのサブクラス
889         */
890        public void setReaderClass( final String readerCls ) {
891                readerClass = nval( getRequestParameter( readerCls ),readerClass );
892
893                // 6.2.1.0 (2015/03/13) 互換性の為。
894                if( "Default".equals( readerClass ) ) { readerClass = "Text" ; }
895        }
896
897        /**
898         * 【TAG】読取時の最大取込件数をセットします(初期値:0:無制限)。
899         *
900         * @og.tag
901         * DBTableModelのデータとして登録する最大件数をこの値に設定します。
902         * サーバーのメモリ資源と応答時間の確保の為です。
903         * 0 をセットすると、無制限になります。
904         * (初期値:0:無制限)
905         *
906         * @og.rev 5.5.8.5 (2012/11/27) 0を無制限として処理します。
907         * @og.rev 6.2.2.0 (2015/03/27) 初期値を、無制限に変更
908         *
909         * @param       count   最大件数
910         */
911        public void setMaxRowCount( final String count ) {
912                maxRowCount = nval( getRequestParameter( count ),maxRowCount );
913        }
914
915        /**
916         * 【TAG】読取時の最大エラー件数をセットします (初期値:{@og.value #ERROR_ROW_COUNT})。
917         *
918         * @og.tag
919         * DBTableModelのデータチェックを行う場合、エラーの最大件数をこの値に設定します。
920         * エラー最大件数がこの値を超えると、処理を打ち切ります。
921         * 0 をセットすると、無制限になります。
922         * (初期値:{@og.value #ERROR_ROW_COUNT})。
923         *
924         * @og.rev 6.2.2.0 (2015/03/27) 読取時の最大エラー件数(errRowCount) を新規追加
925         *
926         * @param       count   最大件数
927         */
928        public void setErrRowCount( final String count ) {
929                clmAct.errRowCount = nval( getRequestParameter( count ),ERROR_ROW_COUNT );
930        }
931
932        /**
933         * 【TAG】コマンド (NEW,RENEW)をセットします(初期値:NEW)。
934         *
935         * @og.tag
936         * コマンドは、HTMLから(get/post)指定されますので、CMD_xxx で設定される
937         * フィールド定数値のいづれかを、指定できます。
938         * 何も設定されない、または、null の場合は、"NEW" が初期値にセットされます。
939         *
940         * @param       cmd     コマンド (public static final 宣言されている文字列)
941         * @see         <a href="../../../../constant-values.html#org.opengion.hayabusa.taglib.ReadTableTag.CMD_NEW">コマンド定数</a>
942         */
943        public void setCommand( final String cmd ) {
944                final String cmd2 = getRequestParameter( cmd );
945                if( cmd2 != null && cmd2.length() > 0 ) { command = cmd2.toUpperCase(Locale.JAPAN); }
946        }
947
948        /**
949         * 【TAG】query の結果を画面上に表示するメッセージIDを指定します
950         *              (初期値:VIEW_DISPLAY_MSG[={@og.value SystemData#VIEW_DISPLAY_MSG}])。
951         *
952         * @og.tag
953         * ここでは、検索結果の件数や登録された件数をまず出力し、
954         * その次に、ここで指定したメッセージをリソースから取得して
955         * 表示します。
956         * 件数を表示させる場合は、displayMsg = "MSG0033"[ 件検索しました] をセットしてください。
957         * 表示させたくない場合は、displayMsg = "" をセットしてください。
958         * (初期値:システム定数のVIEW_DISPLAY_MSG[={@og.value SystemData#VIEW_DISPLAY_MSG}])。
959         *
960         * @og.rev 6.2.0.0 (2015/02/27) リクエスト変数を使用できるように修正。
961         *
962         * @param       id      処理結果表示メッセージID
963         */
964        public void setDisplayMsg( final String id ) {
965                final String ids = getRequestParameter( id );
966                if( ids != null ) { displayMsg = ids; }
967        }
968
969        /**
970         * 【TAG】読取データが最大検索数をオーバーした場合に表示するメッセージリソースIDを指定します
971         *              (初期値:MSG0007[検索結果が、制限行数を超えましたので、残りはカットされました])。
972         *
973         * @og.tag
974         * 読取結果が、maxRowCount で設定された値より多い場合、何らかのデータは読取されず
975         * 切り捨てられたことになります。
976         * ここでは、displayMsg を表示した後、必要に応じて、このメッセージを表示します。
977         * 表示させたくない場合は、overflowMsg = "" をセットしてください。
978         * 初期値は、MSG0007[検索結果が、制限行数を超えましたので、残りはカットされました]です。
979         *
980         * @og.rev 6.2.0.0 (2015/02/27) オーバーフロー時のメッセージを表示
981         *
982         * @param       id      検索数オーバー時メッセージID
983         */
984        public void setOverflowMsg( final String id ) {
985                final String ids = getRequestParameter( id );
986                if( ids != null ) { overflowMsg = ids; }
987        }
988
989        /**
990         * 【TAG】検索結果がゼロ件の場合に表示するメッセージリソースIDを指定します(初期値:MSG0077[対象データはありませんでした])。
991         *
992         * @og.tag
993         * ここでは、検索結果がゼロ件の場合のみ、特別なメッセージを表示させます。
994         * 従来は、displayMsg と兼用で、『0 件検索しました』という表示でしたが、
995         * displayMsg の初期表示は、OFF になりましたので、ゼロ件の場合のみ別に表示させます。
996         * 表示させたくない場合は、notfoundMsg = "" をセットしてください。
997         * 初期値は、MSG0077[対象データはありませんでした]です。
998         *
999         * @param       id      ゼロ件時表示メッセージID
1000         */
1001        public void setNotfoundMsg( final String id ) {
1002                final String ids = getRequestParameter( id );
1003                if( ids != null ) { notfoundMsg = ids; }
1004        }
1005
1006        /**
1007         * 【TAG】ファイル取込時の 更新タイプ [A:追加/C:更新/D:削除]を指定します。
1008         *
1009         * @og.tag
1010         * ファイル読み込み時に、そのデータをA(追加)、C(更新)、D(削除)の
1011         * 更新タイプをつけた状態にします。
1012         * その状態で、そのまま、update する事が可能になります。
1013         *
1014         * @param       type    更新タイプ [A:追加/C:更新/D:削除]
1015         */
1016        public void setModifyType( final String type ) {
1017                modifyType = getRequestParameter( type );
1018        }
1019
1020        /**
1021         * 【TAG】EXCELファイルを読み込むときのシート名を設定します(初期値:指定なし)。
1022         *
1023         * @og.tag
1024         * EXCELファイルを読み込む時に、シート名を指定します。これにより、複数の形式の
1025         * 異なるデータを順次読み込むことや、シートを指定して読み取ることが可能になります。
1026         * sheetNos と sheetName が同時に指定された場合は、sheetNos が優先されます。エラーにはならないのでご注意ください。
1027         * 初期値は、指定なしです。
1028         *
1029         * @og.rev 3.5.4.2 (2003/12/15) 新規追加
1030         *
1031         * @param       sheet   EXCELファイルのシート名
1032         * @see         #setSheetNos( String )
1033         */
1034        public void setSheetName( final String sheet ) {
1035                sheetName = nval( getRequestParameter( sheet ),sheetName );
1036        }
1037
1038        /**
1039         * 【TAG】EXCELファイルを読み込むときのシート番号を指定します(初期値:0)。
1040         *
1041         * @og.tag
1042         * EXCEL読み込み時に複数シートをマージして取込ます。
1043         * シート番号は、0 から始まる数字で表します。
1044         * ヘッダーは、最初のシートのカラム位置に合わせます。(ヘッダータイトルの自動認識はありません。)
1045         * よって、指定するシートは、すべて同一レイアウトでないと取込時にカラムのずれが発生します。
1046         *
1047         * シート番号の指定は、CSV形式で、複数指定できます。また、N-M の様にハイフンで繋げることで、
1048         * N 番から、M 番のシート範囲を一括指定可能です。また、"*" による、全シート指定が可能です。
1049         * これらの組み合わせも可能です。( 0,1,3,5-8,10-* )
1050         * ただし、"*" に関しては例外的に、一文字だけで、すべてのシートを表すか、N-* を最後に指定するかの
1051         * どちらかです。途中には、"*" は、現れません。
1052         * シート番号は、重複(1,1,2,2)、逆転(3,2,1) での指定が可能です。これは、その指定順で、読み込まれます。
1053         * sheetNos と sheetName が同時に指定された場合は、sheetNos が優先されます。エラーにはならないのでご注意ください。
1054         *
1055         * 初期値は、0(第一シート) です。
1056         *
1057         * @og.rev 5.5.7.2 (2012/10/09) 新規追加
1058         *
1059         * @param       sheet   EXCELファイルのシート番号(0から始まる)
1060         * @see         #setSheetName( String )
1061         */
1062        public void setSheetNos( final String sheet ) {
1063                sheetNos = nval( getRequestParameter( sheet ),sheetNos );
1064                if( sheetNos != null && sheetNos.length() > 0 ) {
1065                        boolean errFlag = false;
1066                        for( int i=0; i<sheetNos.length(); i++ ) {
1067                                final char ch = sheetNos.charAt(i);
1068                                if( ch == '-' || ch == ',' ) { continue; }
1069                                if( ch == '*' && ( i==0 || i==sheetNos.length()-1 ) ) { continue; }
1070                                if( ch < '0' || ch > '9' ) { errFlag = true; break; }
1071                        }
1072                        if( errFlag ) {
1073                                final String errMsg = "sheetNos の指定を見直してください。sheetNos=[" + sheetNos + "]";
1074                                throw new HybsSystemException( errMsg );
1075                        }
1076                }
1077        }
1078
1079        /**
1080         * 【TAG】EXCELファイルを読み込むときのシート単位の固定値を設定するためのカラム名を指定します。
1081         *
1082         * @og.tag
1083         * カラム名は、CSV形式で指定します。
1084         * これにより、シートの一か所に書かれている情報を、DBTableModel のカラムに固定値として
1085         * 設定することができます。
1086         * 例として、DB定義書で、テーブル名をシートの全レコードに設定したい場合などに使います。
1087         * このメソッドは、isExcel() == true の場合のみ利用されます。
1088         *
1089         * @og.rev 5.5.8.2 (2012/11/09) 新規追加
1090         *
1091         * @param       constKeys       固定値となるカラム名 (CSV形式)
1092         * @see         #setSheetConstAdrs( String )
1093         */
1094        public void setSheetConstKeys( final String constKeys ) {
1095                sheetConstKeys = nval( getRequestParameter( constKeys ),null );
1096        }
1097
1098        /**
1099         * 【TAG】EXCELファイルを読み込むときのシート単位の固定値を設定するためのカラム名に対応するアドレスを指定します。
1100         *
1101         * @og.tag
1102         * アドレスは、EXCEL上の行-列をCSV形式で指定します。
1103         * 行列は、EXCELオブジェクトに準拠するため、0から始まる整数です。
1104         * 0-0 ⇒ A1 , 1-0 ⇒ A2 , 0-1 ⇒ B1 になります。
1105         * これにより、シートの一か所に書かれている情報を、DBTableModel のカラムに固定値として
1106         * 設定することができます。
1107         * 例として、DB定義書で、テーブル名をシートの全レコードに設定したい場合などに使います。
1108         * このメソッドは、isExcel() == true の場合のみ利用されます。
1109         *
1110         * 5.7.6.3 (2014/05/23) より、
1111         *   ①EXCEL表記に準拠した、A1,A2,B1 の記述も処理できるように対応します。
1112         *     なお、A1,A2,B1 の記述は、必ず、英字1文字+数字 にしてください。(A~Zまで)
1113         *   ②処理中のEXCELシート名をカラムに割り当てるために、"SHEET" という記号に対応します。
1114         * 例えば、sheetConstKeys="CLM,LANG,NAME" とし、sheetConstAdrs="0-0,A2,SHEET" とすると、
1115         * NAMEカラムには、シート名を読み込むことができます。
1116         * これは、内部処理の簡素化のためです。
1117         *
1118         * ちなみに、EXCELのセルに、シート名を表示させる場合の関数は、下記の様になります。
1119         * =RIGHT(CELL("filename",$A$1),LEN(CELL("filename",$A$1))-FIND("]",CELL("filename",$A$1)))
1120         *
1121         * @og.rev 5.5.8.2 (2012/11/09) 新規追加
1122         *
1123         * @param       constAdrs       固定値となるアドレス (行-列,行-列,・・・)
1124         * @see         #setSheetConstKeys( String )
1125         */
1126        public void setSheetConstAdrs( final String constAdrs ) {
1127                sheetConstAdrs = nval( getRequestParameter( constAdrs ),null );
1128        }
1129
1130        /**
1131         * 【TAG】ここに指定されたカラム列に NULL が現れた時点で読取を中止します。
1132         *
1133         * @og.tag
1134         * これは、指定のカラムは必須という事を条件に、そのレコードだけを読み取る処理を行います。
1135         * 複数Sheetの場合は、次のSheetを読みます。
1136         * 現時点では、Excel の場合のみ有効です。
1137         *
1138         * @og.rev 5.5.8.2 (2012/11/09) 新規追加
1139         *
1140         * @param       clm     カラム列
1141         */
1142        public void setNullBreakClm( final String clm ) {
1143                nullBreakClm = nval( getRequestParameter( clm ),null );
1144        }
1145
1146        /**
1147         * 【TAG】ここに指定されたカラム列に NULL が現れたレコードは読み飛ばします。
1148         *
1149         * @og.tag
1150         * 例えば、更新対象カラムで、null の場合は、何もしない、などのケースで使用できます。
1151         * 複数カラムの場合は、AND条件やOR条件などが、考えられるため、
1152         * カラムを一つにまとめて、指定してください。
1153         *
1154         * @og.rev 6.2.3.0 (2015/05/01) 行読み飛ばし nullSkipClm追加
1155         *
1156         * @param       clm     カラム列
1157         */
1158        public void setNullSkipClm( final String clm ) {
1159                nullSkipClm = nval( getRequestParameter( clm ),null );
1160        }
1161
1162        /**
1163         * 【TAG】読取元ファイルのカラム列を、外部(タグ)より指定します。
1164         *
1165         * @og.tag
1166         * 読取元ファイルのカラム列を、外部(タグ)より指定します。
1167         * ファイルに記述された #NAME より優先して使用されます。
1168         * これは、元ファイルのカラムを順番に指定のカラム名に割り当てる機能で
1169         * ファイルの特定のカラム列を抜き出して取り込む機能ではありません。
1170         *
1171         * ※ 7.2.6.0 (2020/06/30)
1172         *      readerClass="POI"の場合、TEXT(テキスト)、CMNT(コメント)の位置は変えられません。
1173         *      また、カラム数も、必ず、2以上必要です。
1174         *      それより多い場合は、null値のカラムが作成されます。
1175         *
1176         * @og.rev 3.5.4.5 (2004/01/23) 新規作成
1177         *
1178         * @param       clms    読取元ファイルのカラム列 (CSV形式)
1179         */
1180        public void setColumns( final String clms ) {
1181                columns = nval( getRequestParameter( clms ),columns );
1182        }
1183
1184        /**
1185         * 【TAG】読取対象外のカラム列を、外部(タグ)よりCSV形式で指定します。
1186         *
1187         * @og.tag
1188         * 指定するカラム名に対して、読取処理を行いません。
1189         * ここで指定するカラム名は、ファイルの #NAME または、columns で
1190         * 指定するカラム名に対して、含まれている必要はありません。
1191         * その場合は、ここでの指定は無視されます。
1192         *
1193         * @og.rev 6.1.0.0 (2014/12/26) omitNames 属性を追加
1194         * @og.rev 6.2.2.0 (2015/03/27) ColumnAction インナークラスでパラメータを整理する。
1195         *
1196         * @param       clms    読取対象外のカラム列 (CSV形式)
1197         */
1198        public void setOmitNames( final String clms ) {
1199                clmAct.omitNames = nval( getRequestParameter( clms ),null );
1200        }
1201
1202        /**
1203         * 読取対象外のカラム列を、追加指定します。
1204         *
1205         * 内部的な処理で、DirectTableInsertTag で、WRITABLE,ROWID などの
1206         * データベースに存在しないカラムを、omit するための機能です。
1207         * 属性定義してもよいのですが、統一的な処理方法が決まらないので、
1208         * 取りあえず、暫定的に、サブクラスからのみ、して可能にしておきます。
1209         * このメソッドは、setOmitNames( String ) が呼び出された後でしか
1210         * 有効に機能しません。
1211         *
1212         * @og.rev 6.2.4.0 (2015/05/15) 無条件でOMITする名称を指定します。
1213         *
1214         * @param       omit    読取対象外の追加カラム列 (CSV形式)
1215         */
1216        protected void addOmitNames( final String omit ) {
1217                if( clmAct.omitNames == null ) {
1218                        clmAct.omitNames = omit;
1219                }
1220                else {
1221                        clmAct.omitNames = "," + omit ;
1222                }
1223        }
1224
1225        /**
1226         * 【TAG】読取元ファイルの整合性チェックを行うカラム列をカンマ指定します。
1227         *
1228         * @og.tag
1229         * カラムオブジェクトのDBType属性に対応したチェックを行います。
1230         * 指定のカラム名をCSV形式(CSV)で複数指定できます。
1231         * 全てのカラムのチェックを行う場合は、"*" を指定して下さい。
1232         * 分解方法は、通常のパラメータ取得後に、CSV分解します。
1233         *
1234         * @og.rev 3.6.0.2 (2004/10/04) 新規追加 取込時チェック用
1235         * @og.rev 3.8.8.5 (2007/03/09) 通常のパラメータ取得後に、CSV分解に戻します。
1236         * @og.rev 6.2.2.0 (2015/03/27) ColumnAction インナークラスでパラメータを整理する。
1237         *
1238         * @param       clms    整合性チェックを行うカラム列 (CSV形式)
1239         */
1240        public void setCheckColumns( final String clms ) {
1241                clmAct.checkColumns = nval( getRequestParameter( clms ),null );
1242        }
1243
1244        /**
1245         * 【TAG】整合性チェック時に、厳密にチェックするかどうか[true/false]を指定します(初期値:true)。
1246         *
1247         * @og.tag
1248         * checkColumnsで、読取元ファイルの整合性チェックを行う際に、厳密なチェックを行うかどうかを指定します。
1249         * 従来は、厳密なチェックのみでしたが、動的に作成したカラムで、DB登録に無関係な場合は、
1250         * official(カラムリソースから作成されたかどうか)が」falseになり、必ずエラーになっていました。
1251         * isStrict=false を指定すると、甘い目でカラムチェックすると同時に、official チェックも行いません。
1252         * 初期値は、互換性を考慮して、true になります。
1253         *
1254         * @og.rev 7.3.2.0 (2021/03/19) isStrict:整合性チェック時に、厳密にチェックするかどうか[true/false]追加(初期値:true)
1255         *
1256         * @param       flag    厳密チェックか [true:厳密/false:甘い]
1257         */
1258        public void setUseStrict( final String flag ) {
1259                clmAct.isStrict = nval( getRequestParameter( flag ),clmAct.isStrict );
1260        }
1261
1262        /**
1263         * 【TAG】読取元ファイルのデータ変換を行うカラム列をカンマ指定します。
1264         *
1265         * @og.tag
1266         * カラムオブジェクトのDBType属性に対応したデータ変換を行います。
1267         * 指定のカラム名をCSV形式(CSV)で複数指定できます。
1268         * 全てのカラムをデータ変換する場合は、"*" を指定して下さい。
1269         * 分解方法は、通常のパラメータ取得後に、CSV分解します。
1270         *
1271         * @og.rev 3.6.0.2 (2004/10/04) 新規追加 取込時データ変換
1272         * @og.rev 3.8.8.5 (2007/03/09) 通常のパラメータ取得後に、CSV分解に戻します。
1273         * @og.rev 6.2.2.0 (2015/03/27) ColumnAction インナークラスでパラメータを整理する。
1274         *
1275         * @param       clms    データ変換を行うカラム列 (CSV形式)
1276         */
1277        public void setAdjustColumns( final String clms ) {
1278                clmAct.adjustColumns = nval( getRequestParameter( clms ),null );
1279        }
1280
1281        /**
1282         * 【TAG】NULL チェックすべきカラム列をCSV形式(CSV形式)で指定します。
1283         *
1284         * @og.tag nullCheck="AAA,BBB,CCC,DDD"
1285         * 分解方法は、通常のパラメータ取得後に、CSV分解します。
1286         *
1287         * @og.rev 3.8.0.2 (2005/06/30) 新規追加
1288         * @og.rev 3.8.8.5 (2007/03/09) 通常のパラメータ取得後に、CSV分解に戻します。
1289         * @og.rev 6.2.2.0 (2015/03/27) ColumnAction インナークラスでパラメータを整理する。
1290         *
1291         * @param       clms    カラム列(CSV形式)
1292         */
1293        public void setNullCheck( final String clms ) {
1294                clmAct.nullCheck = nval( getRequestParameter( clms ),null );
1295        }
1296
1297        /**
1298         * 【TAG】行番号情報を、使用している/していない[true/false]を指定します(初期値:true)。
1299         *
1300         * @og.tag
1301         * 通常のフォーマットでは、各行の先頭に行番号が出力されています。
1302         * 読取時に、#NAME 属性を使用する場合は、この行番号を無視しています。
1303         * #NAME 属性を使用せず、columns 属性でカラム名を指定する場合(他システムの
1304         * 出力ファイルを読み取るケース等)では、行番号も存在しないケースがあり、
1305         * その様な場合に、useNumber="false" を指定すれば、データの最初から読取始めます。
1306         * この場合、出力データのカラムの並び順が変更された場合、columns 属性も
1307         * 指定しなおす必要がありますので、できるだけ、#NAME 属性を使用するように
1308         * してください。
1309         * なお、EXCEL 入力には、この設定は適用されません。(暫定対応)
1310         * 初期値は、true(使用する) です。
1311         *
1312         * @og.rev 3.7.0.5 (2005/04/11) 新規追加
1313         *
1314         * @param       useNo   行番号情報 [true:使用する/false:使用しない]
1315         */
1316        public void setUseNumber( final String useNo ) {
1317                useNumber = nval( getRequestParameter( useNo ),useNumber );
1318        }
1319
1320        /**
1321         * 【TAG】読取処理で横持ちデータの繰り返しが存在する場合に、trueを指定します(初期値:false)。
1322         *
1323         * @og.tag
1324         * データを取り込む際、1行に繰り返しカラムが存在する場合に、true に設定します。
1325         * 例えば、注文番号,品番,納期1,数量1,納期2,数量2…納期31,数量31,備考 のようなデータ形式です。
1326         * これを、
1327         * 注文番号,品番,備考,納期1,数量1
1328         * 注文番号,品番,備考,納期2,数量2
1329         * ・・・
1330         * 注文番号,品番,備考,納期31,数量31
1331         * のように、縦型のデータに変更します。
1332         *
1333         * 繰り返しカラムの廃位を [] で囲います。先の例でいうと、
1334         * 注文番号,品番,[納期1,数量1],[納期2,数量2]…[納期31,数量31],備考 になります。
1335         *
1336         * 従来の取込と同じく、カラムが空欄(,,,,などと指定)の場合は、読み飛ばします。
1337         * なお、[] で囲われていないカラムは、固定カラムで、繰り返しカラムより前に来ます。
1338         * 先の例でいうと、備考は、品番の次に来ます。
1339         * 繰り返しカラムの指定は、1度だけできます。複数の繰り返しカラムには対応していません。
1340         * 初期値は、false(使用しない) です。
1341         *
1342         * @og.rev 7.3.0.0 (2021/01/06) 横持ちデータの繰り返し対応。
1343         *
1344         * @param       useRepeat       横持ちデータの繰り返し [true:使用する/false:使用しない]
1345         */
1346        public void setUseRepeatClms( final String useRepeat ) {
1347//              useRepeatClms = nval( getRequestParameter( useRepeat ),useRepeatClms );
1348                clmAct.useRepeatClms( nval( getRequestParameter( useRepeat ),false ) );
1349        }
1350
1351        /**
1352         * 【TAG】読込件数が0件のとき処理を続行するかどうか[true/false]を指定します(初期値:false[続行する])。
1353         *
1354         * @og.tag
1355         * 初期値は、false(続行する)です。
1356         *
1357         * @og.rev 4.3.7.0 (2009/06/01) 新規追加
1358         *
1359         * @param       flag    0件時停止可否 [true:処理を中止する/false:続行する]
1360         */
1361        public void setStopZero( final String flag ) {
1362                stopZero = nval( getRequestParameter( flag ), stopZero );
1363        }
1364
1365        /**
1366         * 【TAG】(通常は使いません)タグで処理される処理がメインとなるトランザクション処理かどうかを指定します(初期値:true)。
1367         *
1368         * @og.tag
1369         * この値は、ファイルダウンロード処理に影響します。この値がtrueに指定された時にcommitされたDBTableModelが
1370         * ファイルダウンロードの対象の表になります。
1371         *
1372         * このパラメーターは、通常、各タグにより実装され、ユーザーが指定する必要はありません。
1373         * 但し、1つのJSP内でDBTableModelが複数生成される場合に、前に処理したDBTableModelについてファイルダウンロードをさせたい
1374         * 場合は、後ろでDBTableModelを生成するタグで、明示的にこの値をfalseに指定することで、ファイルダウンロード処理の対象から
1375         * 除外することができます。
1376         *
1377         * @og.rev 5.1.6.0 (2010/05/01) 新規作成
1378         *
1379         * @param       flag    メイントランザクションかどうか [true:メイン/false:その他]
1380         */
1381        public void setMainTrans( final String flag ) {
1382                isMainTrans = nval( getRequestParameter( flag ),isMainTrans );
1383        }
1384
1385        /**
1386         * 【TAG】(通常は使いません)データの読み飛ばし件数を設定します。
1387         *
1388         * @og.tag
1389         * TAB区切りテキストやEXCEL等のデータの読み始めの初期値を指定します。
1390         * ファイルの先頭行が、0行としてカウントしますので、設定値は、読み飛ばす
1391         * 件数になります。(1と指定すると、1件読み飛ばし、2行目から読み込みます。)
1392         * 読み飛ばしは、コメント行などは、無視しますので、実際の行数分読み飛ばします。
1393         * #NAME属性や、columns 属性は、有効です。
1394         *
1395         * @og.rev 5.1.6.0 (2010/05/01) 新規作成
1396         *
1397         * @param       count   読み始めの初期値
1398         */
1399        public void setSkipRowCount( final String count ) {
1400                skipRowCount = nval( getRequestParameter( count ),skipRowCount );
1401        }
1402
1403        /**
1404         * 【TAG】読取処理でKEY:VAL形式のコードリソースから、KEYを取り出す処理を行うかどうかを指定します
1405         *              (初期値:USE_TABLE_READER_RENDERER[={@og.value SystemData#USE_TABLE_READER_RENDERER}])。
1406         *
1407         * @og.tag
1408         * TableWriter_Renderer 系のクラスで出力した場合は、コードリソースがラベルで出力されます。
1409         * そのファイルを読み取ると、当然、エラーになります。
1410         * ここでは、コードリソースのカラムに対して、ラベルからコードを求める逆変換を行うことで、
1411         * Renderer 系で出力したファイルを取り込むことができるようにします。
1412         *
1413         * ここでは、TableWriter 系と同様に、TableReader_Renderer 系のクラスを作るのではなく、
1414         * 属性値のフラグで、制御します。
1415         * 将来的には、TableWriter 系も廃止して、同様のフラグで制御するように変更する予定です。
1416         * (初期値:システム定数のUSE_TABLE_READER_RENDERER[={@og.value SystemData#USE_TABLE_READER_RENDERER}])。
1417         *
1418         * @og.rev 5.2.1.0 (2010/10/01) 新規作成
1419         * @og.rev 6.2.2.0 (2015/03/27) ColumnAction インナークラスでパラメータを整理する。
1420         *
1421         * @param       flag    ラベル逆変換を行うかどうか [true:行う/false:行わない]
1422         * @see         org.opengion.hayabusa.common.SystemData#USE_TABLE_READER_RENDERER
1423         */
1424        public void setUseRenderer( final String flag ) {
1425                clmAct.useRenderer = nval( getRequestParameter( flag ),HybsSystem.sysBool( "USE_TABLE_READER_RENDERER" ) );
1426        }
1427
1428        /**
1429         * 【TAG】matchKeysをCSV形式で指定します。
1430         *
1431         * @og.tag
1432         * ファイルから特定の行のみを読み取るためのmatchKeysを指定します。
1433         * matchKeysで指定したカラムに対して、matchValsの正規表現でチェックします。
1434         * 何も指定しない場合は、読取対象になります。
1435         * matchVals と個数を合わせてください。
1436         *
1437         * @og.rev 6.4.6.0 (2016/05/27) 新規追加
1438         *
1439         * @param       keys    カラム列(CSV形式文字)
1440         * @see         #setMatchVals( String )
1441         */
1442        public void setMatchKeys( final String keys ) {
1443                clmAct.matchKeys = getCSVParameter( keys );
1444        }
1445
1446        /**
1447         * 【TAG】matchValsをCSV形式で指定します。
1448         *
1449         * @og.tag
1450         * ファイルから特定の行のみを読み取るためのmatchValsを指定します。
1451         * matchKeysで指定したカラムに対して、matchValsの正規表現でチェックします。
1452         * この機能はTableReader_Defaultのみ有効です。
1453         * 何も指定しない場合は、読取対象になります。
1454         * matchKeys と個数を合わせてください。
1455         *
1456         * @og.rev 6.4.6.0 (2016/05/27) 新規追加
1457         *
1458         * @param       vals    カラム列に対する正規表現(CSV形式文字)
1459         * @see         #setMatchKeys( String )
1460         */
1461        public void setMatchVals( final String vals ) {
1462                clmAct.matchVals = getCSVParameter( vals );
1463        }
1464
1465        /**
1466         * 【TAG】エラーメッセージにSLABELを利用するかどうか[true/false]を指定します(初期値:false)。
1467         *
1468         * @og.tag
1469         * 通常のエラーメッセージは、ラベル(長)が使われますが、これをラベル(短)を使いたい場合に、true にセットします。
1470         * ここでのラベル(短)は、タグ修飾なしの、ラベル(短)です。
1471         * 標準はfalse:利用しない=ラベル(長)です。
1472         * true/false以外を指定した場合はfalse扱いとします。
1473         *
1474         * ラベルリソースの概要説明があれば表示しますが、useSLabel="true" 時は、概要説明を表示しません。
1475         *
1476         * @og.rev 7.0.7.0 (2019/12/13) 新規追加
1477         *
1478         * @param       prm     SLABEL利用 [true:利用する/false:利用しない]
1479         */
1480        public void setUseSLabel( final String prm ) {
1481                useSLabel = nval( getRequestParameter( prm ),useSLabel );
1482        }
1483
1484        /**
1485         * 【TAG】システム定数でクラウド設定されていても、クラウド環境を使用しない場合、trueを指定します(初期値:false)。
1486         *
1487         * @og.tag
1488         * クラウド設定は、システム定数の『CLOUD_TARGET』と『CLOUD_BUCKET』の設定で自動的に使用しますが、
1489         * どうしてもローカルでのみ使いたい場合は、この属性を true に設定します。
1490         * 標準はfalse:設定どおりとなります。
1491         * true/false以外を指定した場合はfalse扱いとします。
1492         *
1493         * @og.rev 8.0.1.0 (2021/10/29) useLocal 属性を追加。
1494         *
1495         * @param       flag    ローカル環境のみ [true:ローカルのみ/false:設定どおり]
1496         */
1497        public void setUseLocal( final String flag ) {
1498                useLocal = nval( getRequestParameter( flag ),useLocal );
1499        }
1500
1501        /**
1502         * カラム処理を行う、内部クラス
1503         *
1504         * カラム個別に行う処理をまとめたクラスです。
1505         * omitNames     : 読取対象外のカラム列を、外部(タグ)よりCSV形式で指定します
1506         * adjustColumns : 読取元ファイルのデータ変換を行うカラム列をカンマ指定します
1507         * checkColumns  : 読取元ファイルの整合性チェックを行うカラム列をカンマ指定します
1508         * nullCheck     : NULL チェックすべきカラム列をCSV形式(CSV形式)で指定します
1509         *
1510         * 名前配列設定で対象のカラムをピックアップし、値設定処理で、個々に処理します。
1511         *
1512         * @og.rev 6.2.2.0 (2015/03/27) ColumnAction 新規作成
1513         */
1514        protected static final class ColumnAction {
1515                private String  omitNames               ;                                       // 読取対象外のカラム列を、外部(タグ)よりCSV形式で指定します
1516                private String  adjustColumns   ;                                       // 読取元ファイルのデータ変換を行うカラム列をカンマ指定します
1517                private String  checkColumns    ;                                       // 読取元ファイルの整合性チェックを行うカラム列をカンマ指定します
1518                private boolean isStrict                ;                                       // 7.3.2.0 (2021/03/19) 厳密にチェックするかどうか[true/false]を指定します(初期値:true)
1519                private String  nullCheck               ;                                       // NULL チェックすべきカラム列をCSV形式(CSV形式)で指定します
1520                private int             errRowCount             = ERROR_ROW_COUNT;      // NULL チェックすべきカラム列をCSV形式(CSV形式)で指定します
1521                private boolean useRenderer             ;                                       // 読取処理でKEY:VAL形式のコードリソースから、KEYを取り出す処理を行うかどうかを指定
1522                private boolean isDebug                 ;                                       // debug フラグ
1523                private ErrorMessage errMsgObj  ;                                       // 6.2.5.0 (2015/06/05) 初期化します。
1524
1525                private int[]           clmNos          ;                                       // 新名前配列に対応した、値配列のアドレス
1526                private int[]           actFlg          ;                                       // カラム処理の実行有無のフラグ管理
1527                private String[]        mtVals          ;                                       // 6.4.6.0 (2016/05/27) 新名前配列に対応した、判定処理用のデータ(正規表現)
1528
1529                private String[]        matchKeys       ;                                       // 6.4.6.0 (2016/05/27) レコードの読取条件指定時のカラム列を配列で指定します
1530                private String[]        matchVals       ;                                       // 6.4.6.0 (2016/05/27) レコードの読取条件指定時のカラム列に対応する正規表現データを配列で指定します
1531
1532                private boolean useRepeat ;                                                     // 7.3.0.0 (2021/01/06) 横持ちデータの繰り返し [true:使用する/false:使用しない]
1533                private RepeatDataChenge repDataCng ;                           // 7.3.0.0 (2021/01/06) 横持ちデータの繰り返し対応。
1534
1535                private static final int OMIT    = -1;                          // OMIT だけ別。clmNosで、OMITフラグは除外する。
1536                private static final int ADJUST  = 1;                           // adjustColumns 処理フラグ
1537                private static final int CHECK   = 2;                           // checkColumns 処理フラグ
1538                private static final int NULL_CH = 4;                           // nullCheck  処理フラグ
1539                private static final int MAT_KYS = 8;                           // 6.4.6.0 (2016/05/27) matchKeys  処理フラグ
1540
1541                /**
1542                 * 名前配列が設定された場合に、対象カラムのピックアップを行います。
1543                 * このクラスでは、名前の再設定で、初期化されます。
1544                 *
1545                 * @og.rev 6.2.2.0 (2015/03/27) ColumnAction 新規作成
1546                 * @og.rev 6.2.5.0 (2015/06/05) ErrorMessage を、初期化します。
1547                 * @og.rev 6.4.6.0 (2016/05/27) レコードの読取条件指定を追加
1548                 * @og.rev 7.3.0.0 (2021/01/06) 横持ちデータの繰り返し対応。
1549                 *
1550                 * @param       orgNms  オリジナル名前配列
1551                 * @return      OMIT等考慮した、新名前配列
1552                 */
1553                public String[] makeNames( final String[] orgNms ) {
1554                        if( useRepeat ) { repDataCng = new RepeatDataChenge(); }        // 7.3.0.0 (2021/01/06) 初期化します。(Autoreaderチェックで、複数回呼ばれると重複するため)
1555                        errMsgObj = new ErrorMessage( "Check Columns Error!" );         // 6.2.5.0 (2015/06/05) 初期化します。
1556
1557                        // omit だけ、他のフラグセットと異なり、処理された数は、除外されるので逆になります。
1558                        final int[] temp = new int[orgNms.length];
1559                        final int size = orgNms.length - actionFlagSet( omitNames, orgNms, OMIT, temp );
1560
1561                        if( size == 0 ) {       // 有りえないが、omitNames="*" を誤って指定した場合にはありうる。
1562                                final String errMsg = "カラムがありません。omitNames=[" + omitNames + "]";
1563                                throw new HybsSystemException( errMsg );
1564                        }
1565
1566                        final String[] names = new String[size];
1567                        clmNos = new int[size];
1568                        int no = 0;
1569                        for( int i=0; i<temp.length; i++ ) {
1570                                if( temp[i] != OMIT ) {                         // 除外しない場合
1571                                        names[no] = orgNms[i];                  // 名前配列に、オリジナルの名前をセット
1572                                        clmNos[no]= i;                                  // カラムアドレスをセット(TableModelのカラム番号になる)
1573                                        no++ ;
1574                                }
1575                        }
1576
1577                        actFlg = new int[size];                                 // 新名前配列に対応した、処理フラグを作成(フラグを加算)
1578                        actionFlagSet( adjustColumns, names, ADJUST,  actFlg );         // それぞれのフラグが加算される。
1579                        actionFlagSet( checkColumns,  names, CHECK,   actFlg );
1580                        actionFlagSet( nullCheck,     names, NULL_CH, actFlg );
1581
1582                        // 6.4.6.0 (2016/05/27) レコードの読取条件指定を追加。ほとんど使わない機能。
1583                        if( matchKeys != null && matchKeys.length > 0 ) {
1584                                final Map<String,String> keyMap = makeMatchMap( matchKeys , matchVals );
1585                                mtVals = new String[size];
1586                                for( int i=0; i<size; i++ ) {
1587                                        mtVals[i] = keyMap.get( names[i] );
1588                                        if( mtVals[i] != null ) { actFlg[i] += MAT_KYS; }               // 一致するカラムにフラグを加算する。
1589                                }
1590                        }
1591
1592                        // 7.3.0.0 (2021/01/06) 横持ちデータの繰り返し対応
1593//                      return names;
1594                        return useRepeat ? repDataCng.newNames( names ) : names ;
1595                }
1596
1597                /**
1598                 * 値配列に対して、変換処理、チェック処理を行った結果を返します。
1599                 *
1600                 * @og.rev 6.2.2.0 (2015/03/27) ColumnAction 新規作成
1601                 * @og.rev 6.3.9.0 (2015/11/06) コンストラクタで初期化されていないフィールドを null チェックなしで利用している(findbugs)
1602                 * @og.rev 6.4.1.2 (2016/01/22) HybsOverflowException をthrow するとき、最大件数を引数に渡す。
1603                 * @og.rev 6.4.6.0 (2016/05/27) レコードの読取条件指定を追加
1604                 * @og.rev 7.2.9.4 (2020/11/20) spotbugs:null になっている可能性があるメソッドの戻り値を利用している
1605                 * @og.rev 7.3.0.0 (2021/01/06) 横持ちデータの繰り返し対応。
1606                 * @og.rev 7.3.2.0 (2021/03/19) isStrict:整合性チェック時に、厳密にチェックするかどうか[true/false]追加(初期値:true)
1607                 *
1608                 * @param       vals    値配列
1609                 * @param       dbClms  カラムオブジェクト配列
1610                 * @param       row             行番号(エラーメッセージの表示用)
1611                 * @return      変換、チェック処理結果の値配列。このレコードを使用しない場合は、null を返します。
1612                 */
1613//              public String[] clmAction( final String[] vals , final DBColumn[] dbClms , final int row ) {
1614                public List<String[]> clmAction( final String[] vals , final DBColumn[] dbClms , final int row ) {
1615                        // 6.3.9.0 (2015/11/06) コンストラクタで初期化されていないフィールドを null チェックなしで利用している(findbugs)
1616                        // 7.3.0.0 (2021/01/06) SpotBugs コンストラクタで初期化されていないフィールドを null チェックなしで null 値を利用している
1617//                      if( clmNos == null || actFlg == null ) {
1618                        if( clmNos == null || actFlg == null || errMsgObj == null ) {
1619                                final String errMsg = "#makeNames(String[])を先に実行しておいてください。" ;
1620                                throw new OgRuntimeException( errMsg );
1621                        }
1622
1623                        final String[] rtnVals = new String[clmNos.length] ;
1624                        boolean isError = false;
1625
1626                        for( int no=0; no<clmNos.length; no++ ) {
1627                                String val = vals[clmNos[no]];
1628                                if( useRenderer ) {                                                                                             // useRenderer(KEY:VAL) 処理
1629                                        val = dbClms[no].getReaderValue( val );
1630                                }
1631                                if( (actFlg[no] & ADJUST) == ADJUST ) {                                                 // adjustColumns 処理
1632                                        val = dbClms[no].valueSet( val );
1633                                }
1634                                if( (actFlg[no] & CHECK)  == CHECK  ) {                                                 // checkColumns 処理
1635//                                      final ErrorMessage msg = dbClms[no].valueCheck( val );
1636                                        final ErrorMessage msg = dbClms[no].valueCheck( val,isStrict ); // 7.3.2.0 (2021/03/19)
1637                                        if( msg.getKekka() > ErrorMessage.OK ) {
1638                                                isError = true;
1639                                                errMsgObj.append( row+1,msg );
1640                                        }
1641                                }
1642                                if( (actFlg[no] & NULL_CH) == NULL_CH ) {                                               // nullCheck 処理
1643                                        if( val == null || val.isEmpty() ) {
1644                                                isError = true;
1645                                                // ERR0012 : 指定のデータがセットされていません。(NULLエラー)。key={0}
1646                                                errMsgObj.addMessage( row+1,ErrorMessage.NG,"ERR0012",dbClms[no].getLabel() );
1647                                        }
1648                                }
1649                                // 6.4.6.0 (2016/05/27) レコードの読取条件指定を追加
1650                                // 6.9.8.0 (2018/05/28) FindBugs:コンストラクタで初期化されていないフィールドを null チェックなしで null 値を利用している
1651                                // このフラグが立っているということは、mtVals も、その値も、null ではない。
1652//                              if( (actFlg[no] & MAT_KYS) == MAT_KYS && !val.matches( mtVals[no] ) ) { return null; }  // マッチしない場合は、null を返します。
1653                                if( (actFlg[no] & MAT_KYS) == MAT_KYS && mtVals != null && !val.matches( mtVals[no] ) ) { return null; }        // マッチしない場合は、null を返します。
1654
1655                                rtnVals[no] = val;
1656                        }
1657
1658                        // 5.5.7.2 (2012/10/09) エラー時のデバッグ出力
1659                        if( isDebug && isError ) {
1660                                errMsgObj.addMessage( row+1,ErrorMessage.NG,"Debug",vals );
1661                        }
1662
1663                        // isDebug == true 時には、件数は倍になるが、仕方がない。
1664                        if( errMsgObj.size() > errRowCount ) { throw new HybsOverflowException( errRowCount ); }                // 6.4.1.1 (2016/01/16)
1665
1666                        // adjustColumns 処理結果を反映させます。
1667                        // 7.3.0.0 (2021/01/06) 横持ちデータの繰り返し対応
1668//                      return rtnVals;
1669                        if( useRepeat && repDataCng != null ) {
1670                                return repDataCng.newValuesList( rtnVals ) ;
1671                        }
1672                        else {
1673                                final List<String[]> rtnList = new ArrayList<>();
1674                                rtnList.add( rtnVals );
1675                                return rtnList;
1676                        }
1677                }
1678
1679                /**
1680                 * ErrorMessageオブジェクトを返します。
1681                 *
1682                 * @og.rev 6.2.5.0 (2015/06/05) 新規作成
1683                 *
1684                 * @return      ErrorMessageオブジェクト
1685                 */
1686                public ErrorMessage getErrorMessage() {
1687                        return errMsgObj ;
1688                }
1689
1690                /**
1691                 * 読取処理で横持ちデータの繰り返しが存在する場合に、trueを指定します(初期値:false)。
1692                 *
1693                 * @og.rev 7.3.0.0 (2021/01/06) 横持ちデータの繰り返し対応。
1694                 *
1695                 * @param       useRepeat       横持ちデータの繰り返し [true:使用する/false:使用しない]
1696                 */
1697                public void useRepeatClms( final boolean useRepeat ) {
1698                        this.useRepeat = useRepeat ;
1699                }
1700
1701                /**
1702                 * 処理実行可否を判断し、フラグをセットします。
1703                 *
1704                 * フラグのセットは、"|"(論理和)するのが良いのですが、OMITもここで判定している関係で、
1705                 * 単なる加算にしています。
1706                 * (マイナスをフラグにしているので、マイナスの論理和が良く判らないためです(^^))
1707                 *
1708                 * @og.rev 6.2.2.0 (2015/03/27) ColumnAction 新規作成
1709                 *
1710                 * @param       clms    指定のカラム名 (CSV形式)
1711                 * @param       names   名前配列
1712                 * @param       flag    設定するフラグ(既存の配列に加算)
1713                 * @param       actFlg  オリジナル名前配列
1714                 * @return      処理を行った件数
1715                 */
1716                private int actionFlagSet( final String clms , final String[] names , final int flag , final int[] actFlg ) {
1717                        int cnt = 0;
1718                        if( clms != null ) {
1719                                final String clmStr = ',' + clms.replaceAll( " ","" ) + ',' ;           // 前後に カンマ(',') を追加、中間スペース削除
1720                                for( int i=0; i<names.length; i++ ) {
1721                                        // "*" はループの外で判定して、2回それぞれでループを回す方が早い・・・かな?
1722                                        if( "*".equals( clms ) || clmStr.indexOf( ',' + names[i] + ',' ) >= 0 ) {
1723                                                cnt++ ;
1724                                                actFlg[i] += flag;                      // 一致するカラムにフラグを加算する。
1725                                        }
1726                                }
1727                        }
1728                        return cnt ;
1729                }
1730
1731                /**
1732                 * コードの読取条件指定のキーと値を関連付けるMapを作成します。
1733                 *
1734                 * ほとんど使用しない処理なので、できるだけ本体処理の影響が無いように、
1735                 * メソッドを分けています。
1736                 * このメソッドは、keys の、nullチェックを行ったうえで呼び出しています。
1737                 * key,vals の個数が異なる場合は、エラーにしています。
1738                 *
1739                 * @og.rev 6.4.6.0 (2016/05/27) 新規作成
1740                 *
1741                 * @param       keys    指定のカラム名配列(呼び出し前に、nullでないことを確認済み)
1742                 * @param       vals    指定の値配列
1743                 * @return      カラム名と値のMap
1744                 * @og.rtnNotNull
1745                 */
1746                private Map<String,String> makeMatchMap( final String[] keys , final String[] vals ) {
1747
1748                        // 6.4.6.0 (2016/05/27) レコードの読取条件指定を追加。個数判定
1749                        if( vals != null && keys.length != vals.length ) {
1750                                final String errMsg = "keys属性とvals属性の個数が合いません。"                                                  + CR
1751                                                                        + " keys=[" + keys.length + "]:KEYS=" + StringUtil.array2csv( keys ) + CR
1752                                                                        + " vals=[" + vals.length + "]:VLAS=" + StringUtil.array2csv( vals ) + CR ;
1753                                throw new HybsSystemException( errMsg );
1754                        }
1755
1756                        final Map<String,String> keyMap = new HashMap<>();              // 6.4.9.1 (2016/08/05)
1757                        for( int i=0; i<keys.length; i++ ) {
1758                                keyMap.put( keys[i] , vals[i] );
1759                        }
1760
1761                        return keyMap;
1762                }
1763        }
1764
1765        /**
1766         * 繰り返しカラム処理を行う内部クラス
1767         *
1768         * 繰り返しカラムの廃位を [] で囲います。
1769         * 注文番号,品番,[納期1,数量1],[納期2,数量2]…[納期31,数量31],備考 と指定した場合、
1770         *
1771         * 注文番号,品番,備考,納期1,数量1
1772         * 注文番号,品番,備考,納期2,数量2
1773         * ・・・
1774         * 注文番号,品番,備考,納期31,数量31
1775         * のように、縦型のデータに変更します。
1776         *
1777         * @og.rev 7.3.0.0 (2021/01/06) useRepeatClms 属性を追加。
1778         */
1779        protected static final class RepeatDataChenge {
1780                private final List<Integer>               ad1 = new ArrayList<>();              // 固定カラムのアドレス
1781                private final List<List<Integer>> ad2 = new ArrayList<>();              // 繰り返しカラムのアドレス
1782                // 8.0.0.0 (2021/07/31) Avoid using redundant field initializer for ***
1783//              private int   cnst = 0;                                                                                 // 固定カラムの個数
1784//              private int   rpet = 0;                                                                                 // 繰り返しカラムの個数([~]の間のカラムの数)
1785                private int   cnst ;                                                                                    // 固定カラムの個数
1786                private int   rpet ;                                                                                    // 繰り返しカラムの個数([~]の間のカラムの数)
1787
1788                /**
1789                 * カラム名の配列を、繰り返しのアドレス設定と、繰り返し変換後のカラム配列を生成します。
1790                 *
1791                 * @param       nms     カラム名配列
1792                 * @return      変換後のカラム名配列
1793                 */
1794                public String[] newNames( final String[] nms ) {
1795                        final List<String> nms1 = new ArrayList<>();                                            // 固定カラムの名称
1796                        final List<String> nms2 = new ArrayList<>();                                            // 繰り返しカラムの名称
1797
1798                        List<Integer> lad = null ;                                                                                      // 繰り返しカラムの中間アドレスのリスト
1799
1800                        boolean repCheck = true;                                                                                        // 繰り返しカラム名の取得は最初だけ
1801                        boolean inFlag   = false;                                                                                       // "[" でIN(true) "]" でOUT(false) の判定
1802                        for( int i=0; i<nms.length; i++ ) {
1803                                if( nms[i].startsWith( "[" ) ) {                                                                // 繰り返しカラム IN
1804                                        if( repCheck ) { nms2.add( nms[i].substring(1) ); }                     // 最初だけカラム名取得("["を削る)
1805                                        lad = new ArrayList<>();
1806                                        lad.add(i);
1807                                        inFlag = true;
1808                                }
1809                                else if( nms[i].endsWith( "]" ) ) {                                                             // 繰り返しカラム OUT
1810                                        if( repCheck ) { nms2.add( nms[i].substring(0,nms[i].length()-1) ); repCheck = false; }         // カラム名取得終了
1811                                        lad.add(i);
1812                                        ad2.add( lad );                                                                                         // 繰り返しカラムの塊([~]の間)をまとめてセット
1813                                        inFlag = false;
1814                                }
1815                                else if( inFlag ) {                                                                                             // 繰り返しカラムの範囲内
1816                                        if( repCheck ) { nms2.add( nms[i] ); }                                          // 最初だけカラム名取得
1817                                        lad.add(i);
1818                                }
1819                                else {                                                                                                                  // 固定カラム
1820                                        nms1.add( nms[i] );
1821                                        ad1.add(i);
1822                                }
1823                        }
1824
1825                        cnst = nms1.size();                                                                                                     // 固定カラムの個数
1826                        rpet = nms2.size();                                                                                                     // 繰り返しカラムの個数([~]の間のカラムの数)
1827
1828                        final List<String> names = new ArrayList<>( nms1 );                                     // 最終形のカラム一覧
1829                        names.addAll( nms2 );
1830
1831                        return names.toArray( new String[names.size()] ) ;
1832                }
1833
1834                /**
1835                 * 1行分のデータが設定された場合に、呼び出されます。
1836                 *
1837                 * 繰り返しデータに拡張したリストの中に、繰り返し変換後のデータ配列をセットして返します。
1838                 *
1839                 * @param       vals    文字列値の1行分の配列
1840                 * @return      変換後のデータ配列のリスト
1841                 */
1842                public List<String[]> newValuesList( final String[] vals ) {
1843                        final List<String[]> valList = new ArrayList<>();
1844
1845                        // 6.4.6.0 (2016/05/27) レコードの読取条件指定を追加。条件に一致しなければ、null が返されます。
1846                        if( vals != null ) {
1847                                final String[] cnstVals = new String[cnst];                                             // 固定カラムの取得
1848                                for( int i=0;i<cnst; i++ ) {
1849                                        cnstVals[i] = vals[ad1.get(i)];                                                         // 固定カラムのアドレスから取得する。
1850                                }
1851
1852                                for( int j=0; j<ad2.size(); j++ ) {                                                             // 繰り返しカラム群の個数だけループする。
1853                                        final String[] allVals = new String[cnst + rpet];                       // DBTableModelにセットするデータ(繰り返し毎に新規作成)
1854                                        System.arraycopy(cnstVals,0,allVals,0,cnst);                            // 固定カラムのデータをコピーする。
1855
1856                                        int k = cnst;
1857                                        final List<Integer> lad = ad2.get(j) ;                                          // 繰り返しカラムのアドレス
1858                                        boolean isNN = false;                                                                           // 繰り返しカラムのすべてのデータが null(空文字列)の場合は、登録しない。
1859                                        for( int i=0; i<rpet; i++ ) {
1860                                                final String val = vals[lad.get(i)];
1861                                                if( !isNN && val != null && !val.trim().isEmpty() ) { isNN = true; }
1862                                                allVals[k++] = val;
1863                                        }
1864                                        if( isNN ) {
1865                                                valList.add( allVals );                                                                 // 値配列
1866                                        }
1867                                }
1868                        }
1869                        return valList;
1870                }
1871        }
1872
1873        /**
1874         * AutoReader用の 簡易パラメータ管理用の内部クラスです。
1875         *
1876         * 3つのパラメータ(クラス、エンコード、サフィックス)を管理します。
1877         *
1878         * CLASS        TableReader_**** クラス の ****部分を指定します。(Excel,Calc,Text,PIO など)
1879         * ENCODE       クラスが、Text の場合のエンコード(UnicodeLittle,Windows-31J,UTF-8,EUC-JP など)
1880         * SUFIX        処理対象の拡張子(xls,xlsx,xlsm,ods など)
1881         *
1882         * @og.rev 6.2.5.0 (2015/06/05) 新規追加。AutoReader用の 簡易パラメータ管理用の内部クラス
1883         */
1884        private static final class AutoReaderParam {
1885                public final String CLASS       ;
1886                public final String ENCODE      ;
1887                public final String SUFIX       ;
1888
1889                /**
1890                 * AutoReader用の 簡易パラメータ管理用の内部クラスのコンストラクターです。
1891                 *
1892                 * 3つのパラメータ(クラス、エンコード、サフィックス)を管理します。
1893                 *
1894                 * @og.rev 6.2.5.0 (2015/06/05) 新規追加。AutoReader用の 簡易パラメータ管理用の内部クラス
1895                 *
1896                 * @param       cls     TableReader_**** クラス の ****部分を指定します。(Excel,Calc,Text,PIO など)
1897                 * @param       enc     クラスが、Text の場合のエンコード(UnicodeLittle,Windows-31J,UTF-8,EUC-JP など)
1898                 * @param       sfx     処理対象の拡張子(xls,xlsx,xlsm,ods など) nullの場合は、すべてを対象とする。
1899                 */
1900                public AutoReaderParam( final String cls , final String enc , final String sfx ) {
1901                        CLASS   = cls ;
1902                        ENCODE  = enc ;
1903                        SUFIX   = sfx == null ? null : ',' + sfx + ',' ;                // 判定用なので、
1904                }
1905
1906                /**
1907                 * 引数のサフィックスが、対象かどうか、判定します。
1908                 * 対象の場合はtrue、対象でない場合はfalse を返します。
1909                 *
1910                 * @og.rev 6.2.5.0 (2015/06/05) 新規追加。AutoReader用の 簡易パラメータ管理用の内部クラス
1911                 *
1912                 * @param       sufix   比較対象の拡張子(小文字のみ判定可能)
1913                 * @return      対象かどうか[true:対象/false:対象外]
1914                 */
1915                public boolean useSufix( final String sufix ) {
1916                        return SUFIX == null || SUFIX.contains( ',' + sufix + ',' ) ;
1917                }
1918
1919                /**
1920                 * オブジェクトの文字列表現を返します。
1921                 * 対象の場合はtrue、対象でない場合はfalse を返します。
1922                 *
1923                 * @og.rev 6.2.5.0 (2015/06/05) 新規追加。AutoReader用の 簡易パラメータ管理用の内部クラス
1924                 *
1925                 * @return      このオブジェクトの文字列表現
1926                 */
1927                @Override
1928                public String toString() {
1929                        return "class=[" + CLASS + "] , encode=[" + ENCODE + "] , sufix=[" + SUFIX + "]" ;
1930                }
1931        }
1932
1933        /**
1934         * このオブジェクトの文字列表現を返します。
1935         * 基本的にデバッグ目的に使用します。
1936         *
1937         * @return      このクラスの文字列表現
1938         * @og.rtnNotNull
1939         */
1940        @Override
1941        public String toString() {
1942                return ToString.title( this.getClass().getName() )
1943                                .println( "VERSION"                     ,VERSION        )
1944                                .println( "separator"           ,separator              )
1945                                .println( "fileURL"             ,fileURL                )
1946                                .println( "filename"            ,filename               )
1947                                .println( "encode"                      ,encode                 )
1948                                .println( "readerClass"         ,readerClass    )
1949                                .println( "maxRowCount"         ,maxRowCount    )
1950                                .println( "displayMsg"          ,displayMsg             )
1951                                .println( "executeCount"        ,executeCount   )
1952                                .println( "modifyType"          ,modifyType             )
1953                                .println( "command"                     ,command                )
1954                                .println( "tableId"                     ,tableId                )
1955                                .println( "sheetName"           ,sheetName              )
1956                                .println( "sheetNos"            ,sheetNos               )               // 5.5.7.2 (2012/10/09)
1957                                .println( "columns"                     ,columns                )
1958                                .println( "useNumber"           ,useNumber              )
1959                                .println( "Other..."    ,getAttributes().getAttribute() )
1960                                .fixForm().toString() ;
1961        }
1962}