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 static org.opengion.fukurou.util.StringUtil.*;
019
020import java.io.BufferedReader;
021import java.io.File;
022import java.io.IOException;
023import java.io.InputStream;
024import java.io.InputStreamReader;
025import java.io.ObjectInputStream;
026import java.io.ObjectOutputStream;
027import java.io.UnsupportedEncodingException;
028import java.nio.file.Files;
029import java.util.Locale ;
030
031import javax.servlet.http.HttpServletRequest;
032import javax.servlet.http.HttpSession;
033
034import org.opengion.fukurou.util.Closer ;
035import org.opengion.fukurou.util.ErrorMessage;
036import org.opengion.fukurou.util.FileUtil;
037import org.opengion.fukurou.util.StringUtil ;
038import org.opengion.hayabusa.common.HybsSystem;
039import org.opengion.hayabusa.common.HybsSystemException;
040import org.opengion.hayabusa.db.DBColumn;
041import org.opengion.hayabusa.db.DBTableModel;
042import org.opengion.hayabusa.io.StorageAPI;
043import org.opengion.hayabusa.io.StorageAPIFactory;
044import org.opengion.hayabusa.io.TableReader;
045
046/**
047 * 指定のファイルを DBTableModelオブジェクトに読み取るファイル入力タグです。
048 *
049 * データ(DBTableModel)と、コントローラ(ReadTableタグ)を与えて、外部からコントロールすることで、
050 * 各種形式で データ(DBTableModel)を表示させることが できます。
051 * ReadTableタグ に対して、コマンドを与えることにより、内部のコントローラの実装に対応した
052 * 形式でデータを作成します。
053 * すべての読取の初期クラス名を リソースファイルの TABLE_READER_DEFAULT_CLASS で指定可能です。
054 * その場合、AutoReader を指定すると、Excel と Default(テキスト) を順番に試します。
055 *
056 * 入力件数を"DB.COUNT" キーでリクエストにセットしています。
057 *
058 * @og.formSample
059 * ●形式:
060 *     <og:readTable
061 *         command      = "NEW"
062 *         fileURL      = "{@USER.ID}"     読み取り元ディレクトリ名
063 *         filename     = "{@filename}"    読み取り元ファイル名
064 *         encode       = "UnicodeLittle"       読み取り元ファイルエンコード名
065 *         maxRowCount  = "10000"               読取最大件数(0:[無制限])
066 *     />
067 * ●body:なし
068 *
069 * ●Tag定義:
070 *   <og:readTable
071 *       readerClass        【TAG】実際に読み出すクラス名の略称(TableReader_**** の ****)をセットします({@og.doc03Link readerClass 初期値:Default})
072 *       fileURL            【TAG】読み取り元ディレクトリ名を指定します(初期値:FILE_URL)
073 *       filename           【TAG】ファイルを作成するときのファイル名をセットします (初期値:FILE_FILENAME[=file.xls])
074 *       encode             【TAG】ファイルを作成するときのファイルエンコーディング名をセットします(初期値:FILE_ENCODE)
075 *       maxRowCount        【TAG】読取時の最大取り込み件数をセットします (初期値:DB_MAX_ROW_COUNT[=1000])(0:[無制限])
076 *       separator          【TAG】可変長ファイルを作成するときの項目区切り文字をセットします
077 *       tableId            【TAG】(通常使いません)sessionから所得する DBTableModelオブジェクトの ID
078 *       command            【TAG】コマンド(NEW,RENEW)をセットします(初期値:NEW)
079 *       modifyType         【TAG】ファイル取り込み時の モディファイタイプ(A(追加),C(更新),D(削除))を指定します
080 *       displayMsg         【TAG】query の結果を画面上に表示するメッセージIDを指定します(初期値:MSG0033[ 件検索しました])
081 *       notfoundMsg        【TAG】検索結果がゼロ件の場合に表示するメッセージリソースIDを指定します(初期値:MSG0077[対象データはありませんでした])
082 *       sheetName          【TAG】EXCELファイルを読み込むときのシート名を設定します(初期値:指定なし)
083 *       sheetNos           【TAG】EXCELファイルを読み込むときのシート番号を複数設定できます(初期値:0)
084 *       sheetConstKeys     【TAG】EXCELファイルを読み込むときの固定値となるカラム名(CSV形式)
085 *       sheetConstAdrs     【TAG】EXCELファイルを読み込むときの固定値となるアドレス(行-列,行-列,・・・)
086 *       nullBreakClm       【TAG】カラム列に NULL が現れた時点で読み取りを中止します(複数Sheetの場合は、次のSheetを読みます)。
087 *       columns            【TAG】読み取り元ファイルのカラム列を、外部(タグ)より指定します
088 *       useNumber          【TAG】行番号情報を、使用している/していない[true/false]を指定します(初期値:true)
089 *       adjustColumns      【TAG】読み取り元ファイルのデータ変換を行うカラム列をカンマ指定します
090 *       checkColumns       【TAG】読み取り元ファイルの整合性チェックを行うカラム列をカンマ指定します
091 *       nullCheck          【TAG】NULL チェックすべきカラム列をカンマ区切り(CVS形式)で指定します
092 *       language           【TAG】タグ内部で使用する言語コード[ja/en/zh/…]を指定します
093 *       stopZero           【TAG】読込件数が0件のとき処理を続行するかどうか[true/false]を指定します(初期値:false[続行する])
094 *       scope              【TAG】キャッシュする場合のスコープ[request/page/session/applicaton]を指定します(初期値:session)
095 *       mainTrans          【TAG】(通常使いません)タグで処理される処理がメインとなるトランザクション処理かどうかを指定します(初期値:false)
096 *       skipRowCount       【TAG】(通常は使いません)データの読み飛ばし件数を設定します
097 *       useRenderer        【TAG】読取処理でラベルをコードリソースに逆変換を行うかどうかを指定します (初期値:USE_TABLE_READER_RENDERER[=false])
098 *       caseKey            【TAG】このタグ自体を利用するかどうかの条件キーを指定します(初期値:null) 5.7.7.2 (2014/06/20)
099 *       caseVal            【TAG】このタグ自体を利用するかどうかの条件値を指定します(初期値:null) 5.7.7.2 (2014/06/20)
100 *       caseNN             【TAG】指定の値が、null/ゼロ文字列 でない場合(Not Null=NN)は、このタグは使用されます(初期値:true) 5.7.7.2 (2014/06/20)
101 *       caseNull           【TAG】指定の値が、null/ゼロ文字列 の場合は、このタグは使用されます(初期値:true) 5.7.7.2 (2014/06/20)
102 *       debug              【TAG】デバッグ情報を出力するかどうか[true/false]を指定します(初期値:false)
103 *   />
104 *
105 * ●使用例
106 *
107 *     <og:readTable
108 *         command        = "NEW"
109 *         readerClass    = "Fixed"               固定長データの読み取り
110 *         modifyType     = "{@modifyType}"  読取時のモディファイタイプ(A,C等)
111 *         fileURL        = "{@USER.ID}"     読み取り元ディレクトリ名
112 *         filename       = "{@filename}"    読み取り元ファイル名
113 *         encode         = "Shift_JIS"           読み取り元ファイルエンコード名
114 *         maxRowCount    = "10000"               読取最大件数(0:[無制限])
115 *         columns        = "OYA,KO,HJO,SU,DYSTR,DYEND"   #NAME に対応するカラム列
116 *         useNumber      = "false"               行番号の存在しないデータを読み取ります。
117 *         adjustColumns  = "OYA,KO,HJO,SU"       データ変換するカラム列("*" で全カラム)
118 *         checkColumns   = "OYA,KO,HJO,SU"       整合性チェックするカラム列("*" で全カラム)
119 *         nullCheck      = "OYA,KO,SU"           NULLチェックを実行します("*" で全カラム)
120 *         stopZero       = "true"                取得0件の場合に以降の処理を停止します
121 *         skipRowCount   = "4"                   データの読み飛ばし件数(読み込み開始は、この数字+1行目から)
122 *     />
123 *
124 * @og.group ファイル入力
125 *
126 * @version  4.0
127 * @author   Kazuhiko Hasegawa
128 * @since    JDK5.0,
129 */
130public class ReadTableTag extends CommonTagSupport {
131        //* このプログラムのVERSION文字列を設定します。   {@value} */
132        private static final String VERSION = "5.7.7.2 (2014/06/20)" ;
133
134        private static final long serialVersionUID = 577220140620L ;
135
136        private static final int ERROR_ROW_COUNT = 200 ;        // 4.0.0 (2007/05/25)
137
138        /** command 引数に渡す事の出来る コマンド  新規作成 {@value} */
139        public static final String CMD_NEW   = "NEW" ;
140        /** command 引数に渡す事の出来る コマンド  再検索 {@value} */
141        public static final String CMD_RENEW = "RENEW" ;
142
143        private static final String[] COMMAND_LIST = new String[] { CMD_NEW , CMD_RENEW };
144
145        // 5.9.25.2 (2017/10/27)
146        private final String CLOUD_STORAGE = HybsSystem.sys( "CLOUD_STORAGE");
147        private final String CLOUD_CONTAINER = HybsSystem.sys("CLOUD_STORAGE_CONTAINER");
148
149
150        private String  separator               = TableReader.TAB_SEPARATOR;     // 項目区切り文字
151        private String  fileURL                 = HybsSystem.sys( "FILE_URL" );
152        private String  filename                = HybsSystem.sys( "FILE_FILENAME"               );       // ファイル名
153        private String  encode                  = HybsSystem.sys( "FILE_ENCODE"                 );       // ファイルエンコーディング  "JISAutoDetect" ,"JIS", "EUC_JP", "MS932", "SJIS" , "Windows-31J" , "Shift_JIS"
154        private String  readerClass     = HybsSystem.sys( "TABLE_READER_DEFAULT_CLASS" );               // 3.8.5.3 (2006/08/07)
155        private int             maxRowCount             = -1;
156        private String  displayMsg              = HybsSystem.sys( "VIEW_DISPLAY_MSG" );
157        private String  notfoundMsg             = "MSG0077";    // 対象データはありませんでした。
158        private int     executeCount    = -1;                   // 検索/実行件数
159        private String  modifyType              = null;
160        private String adjustColumns    = null;         // 3.6.0.2 (2004/10/04) 取り込み時チェック
161        private String checkColumns             = null;         // 3.6.0.2 (2004/10/04) 取り込み時チェック
162        private String nullCheck                = null;         // 3.8.0.2 (2005/06/30) nullチェック確認
163
164        private transient DBTableModel table      = null;
165        private String          command         = CMD_NEW;
166        private String          tableId         = HybsSystem.TBL_MDL_KEY ;
167        private String          sheetName       = null ;                // 3.5.4.2 (2003/12/15)
168        private String          sheetNos        = null ;                // 5.5.7.2 (2012/10/09) 複数シートを指定できるようにシート番号を指定できるようにする。
169        private String          sheetConstKeys  = null ;        // 5.5.8.2 (2012/11/09) 固定値となるカラム名(CSV形式)
170        private String          sheetConstAdrs  = null ;        // 5.5.8.2 (2012/11/09) 固定値となるアドレス(行-列,行-列,・・・)
171        private String          nullBreakClm    = null;         // 5.5.8.2 (2012/11/09) 取込み条件/Sheet BREAK条件
172
173        // 3.5.4.5 (2004/01/23) 外部よりカラム列(カンマ区切り)を指定できるようにする。
174        private String          columns         = null;
175        private boolean         useNumber       = true;                 // 3.7.0.5 (2005/04/11)
176
177        private boolean         stopZero        = false;                // 4.3.7.0 (2009/06/01) stopZero属性追加
178
179        // 5.1.8.0 (2010/07/01) AutoReaderのCalc対応
180        private static final String[] AUTO_READER_CLASS  = new String[] { "Excel","Calc","Default"      ,"Default"     };
181        private static final String[] AUTO_READER_ENCODE = new String[] { null   ,null  ,"UnicodeLittle","Windows-31J" };
182
183        private boolean isMainTrans             = true;                 // 5.1.6.0 (2010/05/01) DBLastSqlの処理の見直し
184        private int             skipRowCount    = 0;                    // 5.1.6.0 (2010/05/01) データの読み飛ばし設定
185
186        // 5.9.8.1 (2016/05/13) 追加
187        private String[]        matchKeys       = null;
188        private String[]        matchVals       = null;
189
190        // 5.2.1.0 (2010/10/01) 読取処理でコードリソースのラベル変換を行うかどうか
191        private boolean useRenderer             = HybsSystem.sysBool( "USE_TABLE_READER_RENDERER" );    // 5.2.1.0 (2010/10/01)
192
193        /**
194         * Taglibの終了タグが見つかったときに処理する doEndTag() を オーバーライドします。
195         *
196         * @og.rev 3.0.1.4 (2003/03/17) displayMsg が 0Byteの場合は、件数も表示しないように変更。
197         * @og.rev 3.1.1.2 (2003/04/04) Tomcat4.1 対応。release2() を doEndTag()で呼ぶ。
198         * @og.rev 3.5.4.1 (2003/12/01) 引数の BufferedReader を、InputStream に変更。
199         * @og.rev 3.5.4.3 (2004/01/05) 引数の InputStream を、 BufferedReader に戻す。
200         * @og.rev 3.5.6.5 (2004/08/09) 暫定的に、DBTableModelを先行削除します。
201         * @og.rev 3.6.0.0 (2004/09/24) DBTableModel の先行削除は、scope="session" の場合のみ。
202         * @og.rev 3.6.0.2 (2004/10/04) 取り込み時チェック用に、checkColumns,adjustColumns 属性追加
203         * @og.rev 3.6.0.8 (2004/11/19) DBTableModel をセーブする時に、トランザクションチェックを行います。
204         * @og.rev 3.8.5.3 (2006/08/07) readerClassが "Excel"でエラーが発生したとき、もう一度Defaultで再読取を行います。
205         * @og.rev 4.0.0.0 (2007/10/12) checkTableColumn 前に、modifyType 設定を行います。
206         * @og.rev 4.0.0.0 (2007/10/18) メッセージリソース統合( getResource().getMessage ⇒ getResource().getLabel )
207         * @og.rev 4.3.1.1 (2008/10/08) columnsが指定されている場合は、AutoReader禁止
208         * @og.rev 4.3.7.0 (2009/06/01) stopZero機能,DB.COUNTリクエストキーへ読込件数セットを追加
209         * @og.rev 5.1.6.0 (2010/05/01) DBLastSqlの処理は、DBTableModelが新規作成された処理でのみ行う。
210         * @og.rev 5.1.8.0 (2010/07/01) AutoReaderのCalc対応
211         * @og.rev 5.1.9.0 (2010/08/01) AutoReaderでのExceptionの判定をThrowableに変更
212         * @og.rev 5.7.1.2 (2013/12/20) tempMsg.toString() ⇒ errMsg 変更
213         * @og.rev 5.7.7.2 (2014/06/20) caseKey,caseVal,caseNN,caseNull 属性を追加
214         *
215         * @return      後続処理の指示
216         */
217        @Override
218        public int doEndTag() {
219                debugPrint();           // 4.0.0 (2005/02/28)
220                // 5.7.7.2 (2014/06/20) caseKey,caseVal,caseNN,caseNull 属性を追加
221                if( !useTag() ) { return EVAL_PAGE ; }
222
223                if( check( command, COMMAND_LIST ) ) {
224                        useMainTrans( isMainTrans );                    // 5.1.6.0 (2010/05/01) DBLastSqlの処理の見直し
225                        startQueryTransaction( tableId );               // 3.6.0.8 (2004/11/19)
226
227                        // 3.5.6.5 (2004/08/09) 削除するのは、セッションのオブジェクトでよい。
228                        // 3.6.0.0 (2004/09/24) 削除するのは、scope="session" の場合のみ。
229                        if( "session".equals( getScope() ) ) {
230                                removeSessionAttribute( tableId );
231                                removeSessionAttribute( HybsSystem.VIEWFORM_KEY );
232                        }
233
234                        if( maxRowCount < 0 ) {
235                                maxRowCount     = sysInt( "DB_MAX_ROW_COUNT" );
236                        }
237
238                        // ファイル の読み込み:AutoReader 処理
239                        BufferedReader pw = null;
240                        final String[] READER_CLASS  ;
241                        final String[] READER_ENCODE ;
242                        if( "AutoReader".equalsIgnoreCase( readerClass ) ) {
243                                // 4.3.1.1 (2008/10/08)
244                                if( columns != null && columns.length() > 0 ) {
245                                        String errMsg = "columnsが指定されている場合は、readerClass=\"AutoReader\"は使えません";
246                                        throw new HybsSystemException( errMsg ); // 4.3.4.4 (2009/01/01)
247                                }
248                                READER_CLASS  = AUTO_READER_CLASS ;
249                                READER_ENCODE = AUTO_READER_ENCODE;
250                        }
251                        else {
252                                READER_CLASS  = new String[] { readerClass };
253                                READER_ENCODE = new String[] { encode };
254                        }
255
256                        StringBuilder tempMsg = new StringBuilder();
257                        for( int i=0; i<READER_CLASS.length; i++ ) {
258                                readerClass = READER_CLASS[i];
259                                encode      = READER_ENCODE[i];
260
261                                try {
262                                        // 5.1.8.0 (2010/07/01) AutoReaderのCalc対応
263                                        if( "Excel".equalsIgnoreCase( readerClass ) || "Calc".equalsIgnoreCase( readerClass ) ) {
264                                                create( null );
265                                        }
266                                        else {
267                                                pw = getBufferedReader();
268                                                create( pw );
269                                        }
270                                        // 成功すれば、エラーメッセージをクリアして、その場で抜ける。
271                                        tempMsg = null;
272                                        break;
273                                }
274                                // 3.8.5.3 (2006/08/07) readerClassが "Excel"でエラーが発生したとき、もう一度Defaultで再読取を行います。
275                                // 5.1.9.0 (2010/08/01) RuntimeException系のExceptionがキャッチできないため、Throwableで受ける
276                                catch( Throwable th ) {
277                                        tempMsg.append( "readerClass=["  ).append( readerClass )
278                                                        .append( "],encode=["    ).append( encode )
279                                                        .append( "] Error!"      ).append( HybsSystem.CR )
280                                                        .append( th.getMessage() ).append( HybsSystem.CR ) ;
281                                }
282                                finally {
283                                        Closer.ioClose( pw );           // 4.0.0 (2006/01/31) close 処理時の IOException を無視
284                                }
285                        }
286
287                        if( tempMsg != null ) { // 最後までエラーがあれば、例外処理を発行します。
288                                String errMsg = tempMsg.toString();
289                                System.err.print( errMsg );
290                                throw new HybsSystemException( errMsg );                // 5.7.1.2 (2013/12/20) msg ⇒ errMsg 変更
291                        }
292
293                        if( table != null ) {
294                                // 3.6.0.2 (2004/10/04)
295                                // 4.0.0.0 (2007/10/12) checkTableColumn 前に、modifyType 設定を行います。
296                                executeCount = table.getRowCount();
297                                if( modifyType != null ) {
298                                        for( int row=0; row<executeCount; row++ ) {
299                                                table.setModifyType( row,modifyType );
300                                        }
301                                }
302
303                                ErrorMessage errMsg = checkTableColumn( table );
304                                if( errMsg != null && ! errMsg.isOK()) {
305                                        jspPrint( TaglibUtil.makeHTMLErrorTable( errMsg,getResource() ) );
306                                        return SKIP_PAGE ;
307                                }
308
309                        }
310                        // 3.6.0.8 (2004/11/19) トランザクションチェックを行います。
311                        if( ! commitTableObject( tableId, table ) ) {
312                                jspPrint( "ReadTableTag Query処理が割り込まれました。DBTableModel は登録しません。" );
313                                return SKIP_PAGE ;
314                        }
315
316                        StringBuilder buf = new StringBuilder( HybsSystem.BUFFER_SMALL );
317
318                        // 実行件数の表示 command="NEW" のときのみ、displayMsg を表示させます。
319                        // 4.0.0 (2005/11/30) 出力順の変更。一番最初に出力します。
320                        if( CMD_NEW.equals( command ) ) {
321                                if( executeCount > 0 && displayMsg != null && displayMsg.length() > 0 ) {
322                                        buf.append( executeCount );
323                                        buf.append( getResource().getLabel( displayMsg ) );
324                                        buf.append( HybsSystem.BR );
325                                }
326                                else if( executeCount == 0 && notfoundMsg != null && notfoundMsg.length() > 0 ) {
327                                        buf.append( getResource().getLabel( notfoundMsg ) );
328                                        buf.append( HybsSystem.BR );
329                                }
330                        }
331
332                        // 4.3.7.0 (2009/06/01) 読込件数を、"DB.COUNT" キーでリクエストにセットする。
333                        setRequestAttribute( "DB.COUNT"   , String.valueOf( executeCount ) );
334
335                        jspPrint( buf.toString() );
336                }
337
338                // 4.3.7.0 (2009/06/01) stopZero機能を追加
339                final int rtnCode ;
340                if( executeCount == 0 && stopZero )     {
341                        rtnCode = SKIP_PAGE;
342                }
343                else {
344                        rtnCode = EVAL_PAGE;
345                }
346
347                return rtnCode ;
348        }
349
350        /**
351         * タグリブオブジェクトをリリースします。
352         * キャッシュされて再利用されるので、フィールドの初期設定を行います。
353         *
354         * @og.rev 2.0.0.4 (2002/09/27) カスタムタグの release() メソッドを、追加
355         * @og.rev 3.1.1.2 (2003/04/04) Tomcat4.1 対応。release2() を doEndTag()で呼ぶ。
356         * @og.rev 3.1.3.0 (2003/04/10) FILE_ENCODE から、エンコード情報を取得する。
357         * @og.rev 3.1.4.0 (2003/04/18) command 属性に、初期値(NEW)を設定する。
358         * @og.rev 3.5.4.2 (2003/12/15) EXCELのシート名を指定できるように変更。
359         * @og.rev 3.5.4.5 (2004/01/23) 外部よりカラム列(カンマ区切り)を指定できるようにする。
360         * @og.rev 3.6.0.2 (2004/10/04) checkColumns,adjustColumns,allColumnCheck 属性追加
361         * @og.rev 3.7.0.5 (2005/04/11) useNumber 属性を追加します。
362         * @og.rev 3.8.0.2 (2005/06/30) nullCheck 属性追加
363         * @og.rev 3.8.5.3 (2006/08/07) readerClass 属性の初期値をシステムリソースより取得します。
364         * @og.rev 4.3.7.0 (2009/06/01) stopZero属性追加
365         * @og.rev 5.1.6.0 (2010/05/01) DBLastSqlの処理は、DBTableModelが新規作成された処理でのみ行う。
366         * @og.rev 5.1.6.0 (2010/05/01) データの読み飛ばし設定 skipRowCount 属性追加
367         * @og.rev 5.2.1.0 (2010/10/01) 読取処理でコードリソースのラベル変換を行うかどうか useRenderer 属性追加
368         * @og.rev 5.5.7.2 (2012/10/09) 複数シートを指定できるようにシート番号を指定できるように、sheetNos属性追加
369         * @og.rev 5.5.8.2 (2012/11/09) 固定値となるカラム名、アドレスの指定のための、sheetConstKeys、sheetConstAdrs属性追加
370         * @og.rev 5.5.8.2 (2012/11/09) カラム列に NULL が現れた時点で読み取りを中止する、nullBreakClm属性追加
371         * @og.rev 5.9.8.1 (2016/05/13) 読込条件の追加
372         */
373        @Override
374        protected void release2() {
375                super.release2();
376                separator               = TableReader.TAB_SEPARATOR;   // 項目区切り文字
377                fileURL                 = HybsSystem.sys( "FILE_URL" );
378                filename                = HybsSystem.sys( "FILE_FILENAME" );   // ファイル名
379                encode                  = HybsSystem.sys( "FILE_ENCODE"   );   // ファイルエンコーディング  "JISAutoDetect" ,"JIS", "EUC_JP", "MS932", "SJIS" , "Windows-31J" , "Shift_JIS"
380                readerClass             = HybsSystem.sys( "TABLE_READER_DEFAULT_CLASS" );               // 3.8.5.3 (2006/08/07)
381                maxRowCount             = -1;
382                displayMsg              = HybsSystem.sys( "VIEW_DISPLAY_MSG" );
383                notfoundMsg             = "MSG0077";    // 対象データはありませんでした。
384                executeCount    = -1;                   // 検索/実行件数
385                modifyType              = null;
386                command                 = CMD_NEW;
387                table                   = null;
388                tableId                 = HybsSystem.TBL_MDL_KEY ;
389                sheetName               = null;         // 3.5.4.2 (2003/12/15)
390                sheetNos                = null ;        // 5.5.7.2 (2012/10/09) 複数シートを指定できるようにシート番号を指定できるようにする。
391                sheetConstKeys  = null ;        // 5.5.8.2 (2012/11/09) 固定値となるカラム名(CSV形式)
392                sheetConstAdrs  = null ;        // 5.5.8.2 (2012/11/09) 固定値となるアドレス(行-列,行-列,・・・)
393                nullBreakClm    = null;         // 5.5.8.2 (2012/11/09) 取込み条件/Sheet BREAK条件
394                columns                 = null;         // 3.5.4.5 (2004/01/23)
395                useNumber               = true;         // 3.7.0.5 (2005/04/11)
396                adjustColumns   = null;         // 3.6.0.2 (2004/10/04) 取り込み時チェック
397                checkColumns    = null;         // 3.6.0.2 (2004/10/04) 取り込み時チェック
398                nullCheck               = null;         // 3.8.0.2 (2005/06/30)
399                stopZero                = false;        // 4.3.7.0 (2009/06/01) soptZero追加
400                isMainTrans             = true;         // 5.1.6.0 (2010/05/01) DBLastSqlの処理の見直し
401                skipRowCount    = 0;            // 5.1.6.0 (2010/05/01) データの読み飛ばし設定
402                matchKeys               = null;         // 5.9.8.1 (2016/05/13) 読込条件設定
403                matchVals               = null;         // 5.9.8.1 (2016/05/13) 読込条件設定
404                useRenderer             = HybsSystem.sysBool( "USE_TABLE_READER_RENDERER" );    // 5.2.1.0 (2010/10/01)
405        }
406
407        /**
408         * TableReader の実オブジェクトを生成して,BufferedReader に書き込みます。
409         *
410         * @og.rev 3.5.4.1 (2003/12/01) 引数の BufferedReader を、InputStream に変更。
411         * @og.rev 3.5.4.2 (2003/12/15) TableReader のサブクラス名変更。
412         * @og.rev 3.5.4.2 (2003/12/15) EXCELのシート名を指定できるように変更。
413         * @og.rev 3.5.4.3 (2004/01/05) 引数の InputStream を、 BufferedReader に戻す。
414         * @og.rev 3.5.4.5 (2004/01/23) TableReader に、encode を渡すように変更。
415         * @og.rev 3.5.6.0 (2004/06/18) 各種プラグイン関連付け設定を、システムパラメータ に記述します。
416         * @og.rev 3.7.0.5 (2005/04/11) useNumber 属性を追加します。
417         * @og.rev 4.0.0.0 (2005/01/31) キーの指定を、TableReader. から、TableReader_ に変更します。
418         * @og.rev 4.0.0.0 (2005/01/31) lang ⇒ ResourceManager へ変更
419         * @og.rev 5.1.6.0 (2010/05/01) データの読み飛ばし設定 skipRowCount 属性追加
420         * @og.rev 5.2.1.0 (2010/10/01) 読取処理でコードリソースのラベル変換を行うかどうか設定 useRenderer 属性追加
421         * @og.rev 5.5.7.2 (2012/10/09) 複数シートを指定できるようにシート番号を指定できるように、sheetNos属性追加
422         * @og.rev 5.5.8.2 (2012/11/09) 固定値となるカラム名、アドレスの指定のための、sheetConstKeys、sheetConstAdrs属性追加
423         * @og.rev 5.5.8.2 (2012/11/09) カラム列に NULL が現れた時点で読み取りを中止する、nullBreakClm属性追加
424         * @og.rev 5.9.8.1 (2016/05/13) match対応
425         * @og.rev 5.9.25.2 (2017/10/27) クラウドストレージ対応
426         *
427         * @param       out     出力するBufferedReaderオブジェクト
428         */
429        protected void create( final BufferedReader out )  {
430                String className = HybsSystem.sys( "TableReader_" + readerClass ) ;             // 4.0.0 (2005/01/31)
431                TableReader reader = (TableReader)HybsSystem.newInstance( className );  // 3.5.5.3 (2004/04/09)
432                reader.setResourceManager( getResource() );     // 4.0.0 (2005/01/31)
433                reader.setSeparator( separator );
434                reader.setEncode( encode );                                             // 3.5.4.5 (2004/01/23)
435                reader.setColumns( columns );                                   // 3.5.4.5 (2004/01/23)
436                reader.setUseNumber( useNumber );                               // 3.7.0.5 (2005/04/11)
437                reader.setMaxRowCount( maxRowCount );
438                reader.setSkipRowCount( skipRowCount );                 // 5.1.6.0 (2010/05/01)
439                reader.setUseRenderer( useRenderer );                   // 5.2.1.0 (2010/10/01)
440                reader.setMatchKeys( matchKeys );                               // 5.9.8.1 (2016/05/13)
441                reader.setMatchVals( matchVals );                               // 5.9.8.1 (2016/05/13)
442                reader.setDebug( isDebug() );                                   // 5.5.7.2 (2012/10/09) デバッグ情報を出力するかどうかを指定
443                if( reader.isExcel() ) {                                                // 3.5.4.3 (2004/01/05)
444                        // 5.9.25.2 (2017/10/27)
445                        String filePath = "";
446                        try{
447                                if(CLOUD_STORAGE != null && CLOUD_STORAGE.length() > 0){
448                                        // クラウド上のファイルをサーバにダウンロードする。
449                                        filePath = downloadStorageFile(CLOUD_STORAGE, CLOUD_CONTAINER);
450                                }
451
452                                reader.setFilename( HybsSystem.url2dir( StringUtil.urlAppend( fileURL,filename )));
453                                reader.setSheetName( sheetName );                       // 3.5.4.2 (2003/12/15)
454                                reader.setSheetNos( sheetNos );                         // 5.5.7.2 (2012/10/09) 複数シートを指定できるようにシート番号を指定できるようにする。
455                                reader.setSheetConstData( sheetConstKeys,sheetConstAdrs ) ;             // 5.5.8.2 (2012/11/09) 固定値となるカラム名、アドレスの指定
456                                reader.setNullBreakClm( nullBreakClm ) ;        // 5.5.8.2 (2012/11/09) 取込み条件/Sheet BREAK条件
457                                reader.readDBTable();
458
459                        // 5.9.25.2 (2017/10/27)
460                        }finally{
461                                if(CLOUD_STORAGE != null && CLOUD_STORAGE.length() > 0){
462                                        // サーバにダウンロードしたファイルを削除
463                                        File file = new File(filePath);
464                                        if(file.exists()){
465                                                file.delete();
466                                        }
467                                }
468                        }
469                }
470                else {
471                        reader.readDBTable( out );
472                }
473                table = reader.getDBTableModel();
474        }
475
476        /**
477         * クラウドストレージのExcelファイルをサーバにダウンロード。
478         * (POIで処理する必要があるため)
479         *
480         * @og.rev 5.9.25.2 (2017/10/27) 新規作成
481         *
482         * @param storage クラウドのストレージ
483         * @param container クラウドのコンテナ名
484         * @return filePath サーバのファイルパス
485         */
486        private String downloadStorageFile(String storage, String container){
487                String filePath = HybsSystem.url2dir( StringUtil.urlAppend( fileURL,filename ));
488                HttpServletRequest request = (HttpServletRequest)getRequest();
489                HttpSession hsession = request.getSession(true);
490                StorageAPI storageApi = StorageAPIFactory.newStorageAPI(storage, container, hsession);
491                // ストレージからダウンロード
492                InputStream is = storageApi.get(fileURL + filename, hsession);
493
494                try{
495                        // コピー先ファイルパス
496                        File file = new File(filePath);
497
498                        // 既にファイルが存在する場合は、削除
499                        if(file.exists()){
500                                file.delete();
501                        }
502
503                        // ストレージからサーバにファイルコピー
504                        Files.copy(is, file.toPath());
505
506                }catch(IOException e){
507                        String errMsg = "download error:" + e;
508                        throw new HybsSystemException(errMsg);
509                }
510
511                return filePath;
512        }
513
514        /**
515         * BufferedReader を取得します。
516         *
517         * ここでは、一般的なファイル出力を考慮した BufferedReader を作成します。
518         *
519         * @og.rev 2.2.0.0 (2002/12/17) 中国語(国際化)対応 エンコードの取得方法変更
520         * @og.rev 3.1.3.0 (2003/04/10) FILE_ENCODE から、エンコード情報を取得する。
521         * @og.rev 3.5.4.1 (2003/12/01) 引数の BufferedReader を、InputStream に変更。
522         * @og.rev 3.5.4.3 (2004/01/05) 引数の InputStream を、 BufferedReader に戻す。
523         * @og.rev 3.5.5.9 (2004/06/07) FileUtil.getBufferedReader を使用
524         * @og.rev 5.9.25.2 (2017/10/27) クラウドストレージ対応
525         *
526         * @return      ファイル読取BufferedReaderオブジェクト
527         */
528        private BufferedReader getBufferedReader() {
529                if( filename == null ) {
530                        String errMsg = "ファイル名がセットされていません。";
531                        throw new HybsSystemException( errMsg );
532                }
533
534                // 2017/10/20 DELETE 後の判定処理内に移動
535                // 通常の処理
536//              String directory = HybsSystem.url2dir( fileURL );
537//              File file = new File( StringUtil.urlAppend( directory,filename ) );
538//
539//              BufferedReader out = FileUtil.getBufferedReader( file,encode );
540
541                // 5.9.25.2 (2017/10/27) クラウド対応
542
543                BufferedReader out = null;
544                if(CLOUD_STORAGE != null && CLOUD_STORAGE.length() > 0){
545                        // クラウドの場合の処理
546                        HttpServletRequest request = (HttpServletRequest)getRequest();
547                        HttpSession hsession = request.getSession(true);
548                        StorageAPI storageAPI = StorageAPIFactory.newStorageAPI(CLOUD_STORAGE, CLOUD_CONTAINER, hsession);
549                        // クラウドのオブジェクトを読み込み
550                        InputStream is = storageAPI.get(fileURL + filename, hsession);
551                        try{
552                                out = new BufferedReader(new InputStreamReader(is, encode));
553                        }catch(UnsupportedEncodingException e){
554                                String errMsg = "サポートされていない文字コードです。encode:" + encode;
555                                throw new HybsSystemException(errMsg);
556                        }
557                }else{
558                        // 通常の処理
559                        String directory = HybsSystem.url2dir( fileURL );
560                        File file = new File( StringUtil.urlAppend( directory,filename ) );
561
562                        out = FileUtil.getBufferedReader( file,encode );
563                }
564
565                return out ;
566        }
567
568        /**
569         * カラム文字列(CSV形式)から、カラム番号配列を作成します。
570         * 簡易メソッドです。
571         * 引数が、"*" の場合は、全カラムを指定したことになります。
572         * null の場合は、サイズが 0 の配列を返します。
573         *
574         * @og.rev 4.0.0.0 (2007/05/25) 新規作成
575         *
576         * @param       clms    カラム文字列(CSV形式)
577         * @param       table   DBTableModelオブジェクト
578         *
579         * @return      カラム番号配列(無い場合は、長さ0の配列)
580         */
581        private int[] makeClmNos( final String clms,final DBTableModel table ) {
582                final int[] clmNo;
583
584                if( clms == null ) {
585                        clmNo = new int[0];
586                }
587                else if( "*".equals( clms ) ) {
588                        int size = table.getColumnCount();
589                        clmNo = new int[size];
590                        for( int i=0; i<size; i++ ) {
591                                clmNo[i] = i;
592                        }
593                }
594                else {
595                        String[] clmStr = StringUtil.csv2Array( clms );
596                        int size = clmStr.length;
597                        clmNo = new int[size];
598                        for( int i=0; i<size; i++ ) {
599                                clmNo[i] = table.getColumnNo( clmStr[i] );
600                        }
601                }
602
603                return clmNo;
604        }
605
606        /**
607         * checkColumns に指定されたカラムをチェックします。
608         * カラムオブジェクトのDBType属性に対応したチェックを行います。
609         * チェック結果で、エラーが発生した場合は、ErrorMessage オブジェクトを
610         * 返します。
611         * DBColumn#valueCheck( String ) の結果のErrorMessageをすべて append
612         * していきます。
613         * useAdjust==true で、かつ、エラーがない場合は、adjustColumns 処理結果を
614         * DBTableModel に反映させます。
615         * debug=true で、エラー時の詳細なデータを出力します。
616         *
617         * @og.rev 3.6.0.2 (2004/10/04) 新規作成
618         * @og.rev 3.8.0.2 (2005/06/30) nullチェック確認
619         * @og.rev 4.0.0.0 (2007/05/25) 処理順序書き換え
620         *
621         * @param       table   DBTableModelオブジェクト
622         *
623         * @return      カラムキー + 値 のエラーメッセージオブジェクト
624         */
625        private ErrorMessage checkTableColumn( final DBTableModel table ) {
626                ErrorMessage errMsg = new ErrorMessage( "Check Columns Error!" );
627
628                int rowCnt = table.getRowCount();
629                int[] adjClmNo = makeClmNos( adjustColumns,table );
630                int[] chkClmNo = makeClmNos( checkColumns,table );
631                int[] nllclmNo = makeClmNos( nullCheck,table );
632
633                boolean useAdjust = adjClmNo.length > 0 ;
634
635                for( int row=0; row<rowCnt; row++ ) {
636                        String[]   vals   = table.getValues( row );
637                        DBColumn[] dbClms = table.getDBColumns();
638                        boolean isError = false;                                                // 5.5.7.2 (2012/10/09) エラー時のフラグ。ループでクリアする。
639
640                        // adjustColumns 処理
641                        for( int i=0; i<adjClmNo.length; i++ ) {
642                                int no = adjClmNo[i];
643                                vals[no] = dbClms[no].valueSet( vals[no] );
644                        }
645
646                        // checkColumns 処理
647                        for( int i=0; i<chkClmNo.length; i++ ) {
648                                int no = chkClmNo[i];
649                                ErrorMessage msg = dbClms[no].valueCheck( vals[no] );
650                                if( msg.getKekka() > ErrorMessage.OK ) {
651                                        isError = true;
652                                        errMsg.append( row+1,dbClms[no].valueCheck( vals[no] ) );
653                                }
654                        }
655
656                        // nullCheck 処理
657                        for( int i=0; i<nllclmNo.length; i++ ) {
658                                int no = nllclmNo[i];
659                                if( vals[no] == null || vals[no].length() == 0 ) {
660                                        isError = true;
661                                        String label = dbClms[no].getLabel();
662                                        // ERR0012 : 指定のデータがセットされていません。(NULLエラー)。key={0}
663                                        errMsg.addMessage( row+1,ErrorMessage.NG,"ERR0012",label );
664                                }
665                        }
666
667                        // 5.5.7.2 (2012/10/09) エラー時のデバッグ出力
668                        if( isDebug() && isError ) {
669                                errMsg.addMessage( row+1,ErrorMessage.OK,"Debug Info",java.util.Arrays.toString(table.getValues(row) ) );
670                        }
671
672                        // adjustColumns 処理結果を反映させます。
673                        if( useAdjust && !isError ) { table.setValues( vals,row ); }
674                        if( errMsg.size() > ERROR_ROW_COUNT ) { break; }
675                }
676
677                return errMsg;
678        }
679
680        /**
681         * 【TAG】(通常は使いません)結果のDBTableModelを、sessionに登録するときのキーを指定します
682         *              (初期値:HybsSystem#TBL_MDL_KEY[={@og.value org.opengion.hayabusa.common.HybsSystem#TBL_MDL_KEY}])。
683         *
684         * @og.tag
685         * 検索結果より、DBTableModelオブジェクトを作成します。これを、下流のviewタグ等に
686         * 渡す場合に、通常は、session を利用します。その場合の登録キーです。
687         * query タグを同時に実行して、結果を求める場合、同一メモリに配置される為、
688         * この tableId 属性を利用して、メモリ空間を分けます。
689         *              (初期値:HybsSystem#TBL_MDL_KEY[={@og.value org.opengion.hayabusa.common.HybsSystem#TBL_MDL_KEY}])。
690         *
691         * @param       id sessionに登録する時の ID
692         */
693        public void setTableId( final String id ) {
694                tableId = nval( getRequestParameter( id ), tableId );
695        }
696
697        /**
698         * 【TAG】可変長ファイルを作成するときの項目区切り文字をセットします。
699         *
700         * @og.tag 可変長ファイルを作成するときの項目区切り文字をセットします。
701         *
702         * @param   separator 項目区切り文字
703         */
704        public void setSeparator( final String separator ) {
705                this.separator = nval( getRequestParameter( separator ),this.separator );
706        }
707
708        /**
709         * 【TAG】読み取り元ディレクトリ名を指定します
710         *              (初期値:FILE_URL[={@og.value org.opengion.hayabusa.common.SystemData#FILE_URL}])。
711         *
712         * @og.tag
713         * この属性で指定されるディレクトリより、ファイルを読み取ります。
714         * 指定方法は、通常の fileURL 属性と同様に、先頭が、'/' (UNIX) または、2文字目が、
715         * ":" (Windows)の場合は、指定のURLそのままのディレクトリに、そうでない場合は、
716         * fileURL = "{&#064;USER.ID}" と指定すると、FILE_URL 属性で指定のフォルダの下に、
717         * さらに、各個人ID別のフォルダを作成して、そこを操作します。
718         * (初期値:システム定数のFILE_URL[={@og.value org.opengion.hayabusa.common.SystemData#FILE_URL}])。
719         *
720         * @og.rev 4.0.0.0 (2005/01/31) StringUtil.urlAppend メソッドの利用
721         * @og.rev 4.0.0.0 (2007/11/20) 指定されたディレクトリ名の最後が"\"or"/"で終わっていない場合に、"/"を付加する。
722         *
723         * @param       url 読み取り元ディレクトリ名
724         * @see         org.opengion.hayabusa.common.SystemData#FILE_URL
725         */
726        public void setFileURL( final String url ) {
727                String furl = nval( getRequestParameter( url ),null );
728                if( furl != null ) {
729                        char ch = furl.charAt( furl.length()-1 );
730                        if( ch != '/' && ch != '\\' ) { furl = furl + "/"; }
731                        fileURL = StringUtil.urlAppend( fileURL,furl );
732                }
733        }
734
735        /**
736         * 【TAG】ファイルを作成するときのファイル名をセットします
737         *              (初期値:FILE_FILENAME[={@og.value org.opengion.hayabusa.common.SystemData#FILE_FILENAME}])。
738         *
739         * @og.tag ファイルを作成するときのファイル名をセットします。
740         * (初期値:システム定数のFILE_FILENAME[={@og.value org.opengion.hayabusa.common.SystemData#FILE_FILENAME}])。
741         *
742         * @param   filename ファイル名
743         * @see         org.opengion.hayabusa.common.SystemData#USE_SQL_INJECTION_CHECK
744         */
745        public void setFilename( final String filename ) {
746                this.filename = nval( getRequestParameter( filename ),this.filename );
747        }
748
749        /**
750         * 【TAG】ファイルを作成するときのファイルエンコーディング名をセットします
751         *              (初期値:FILE_ENCODE[={@og.value org.opengion.hayabusa.common.SystemData#FILE_ENCODE}])。
752         *
753         * @og.tag
754         * Shift_JIS,MS932,Windows-31J,UTF-8,ISO-8859-1,UnicodeLittle
755         * (初期値:システム定数のFILE_ENCODE[={@og.value org.opengion.hayabusa.common.SystemData#FILE_ENCODE}])。
756         *
757         * @og.rev 2.2.0.0 (2002/12/17) 中国語(国際化)対応 エンコードの取得方法変更
758         * @og.rev 3.1.3.0 (2003/04/10) FILE_ENCODE から、エンコード情報を取得する。
759         *
760         * @param   enc ファイルエンコーディング名
761         * @see     <a href="http://www.iana.org/assignments/character-sets">IANA Charset Registry</a>
762         * @see         org.opengion.hayabusa.common.SystemData#FILE_ENCODE
763         */
764        public void setEncode( final String enc ) {
765                encode = nval( getRequestParameter( enc ),encode );
766        }
767
768        /**
769         * 【TAG】実際に読み出すクラス名の略称(TableReader_**** の ****)をセットします({@og.doc03Link readerClass 初期値:Default})。
770         *
771         * @og.tag
772         * 実際に読み出すクラス名(の略称)をセットします。
773         * これは、org.opengion.hayabusa.io 以下の TableReader_**** クラスの **** を
774         * 与えます。これらは、TableReader インターフェースを継承したサブクラスです。
775         * 属性クラス定義の {@link org.opengion.hayabusa.io.TableReader TableReader} を参照願います。
776         * {@og.doc03Link readerClass TableReader_**** クラス}
777         *
778         * @param   readerClass クラス名(の略称)
779         * @see         org.opengion.hayabusa.io.TableReader  TableReaderのサブクラス
780         */
781        public void setReaderClass( final String readerClass ) {
782                this.readerClass = nval( getRequestParameter( readerClass ),this.readerClass );
783        }
784
785        /**
786         * 【TAG】読取時の最大取り込み件数をセットします
787         *              (初期値:DB_MAX_ROW_COUNT[={@og.value org.opengion.hayabusa.common.SystemData#DB_MAX_ROW_COUNT}])。
788         *
789         * @og.tag
790         * DBTableModelのデータとして登録する最大件数をこの値に設定します。
791         * サーバーのメモリ資源と応答時間の確保の為です。
792         * 0 をセットすると、無制限(Integer.MAX_VALUE)になります。
793         * (初期値:ユーザー定数のDB_MAX_ROW_COUNT[={@og.value org.opengion.hayabusa.common.SystemData#DB_MAX_ROW_COUNT}])。
794         *
795         * @og.rev 5.5.8.5 (2012/11/27) 0を無制限として処理します。
796         *
797         * @param   count 読取時の最大取り込み件数
798         * @see         org.opengion.hayabusa.common.SystemData#DB_MAX_ROW_COUNT
799         */
800        public void setMaxRowCount( final String count ) {
801                maxRowCount = nval( getRequestParameter( count ),maxRowCount );
802                if( maxRowCount == 0 ) { maxRowCount = Integer.MAX_VALUE ; }            // 5.5.8.5 (2012/11/27)
803        }
804
805        /**
806         * 【TAG】コマンド(NEW,RENEW)をセットします(初期値:NEW)。
807         *
808         * @og.tag
809         * コマンドは,HTMLから(get/post)指定されますので,CMD_xxx で設定される
810         * フィールド定数値のいづれかを、指定できます。
811         * 何も設定されない、または、null の場合は、"NEW" が初期値にセットされます。
812         *
813         * @param       cmd コマンド(public static final 宣言されている文字列)
814         * @see         <a href="../../../../constant-values.html#org.opengion.hayabusa.taglib.ReadTableTag.CMD_NEW">コマンド定数</a>
815         */
816        public void setCommand( final String cmd ) {
817                String cmd2 = getRequestParameter( cmd );
818                if( cmd2 != null && cmd2.length() > 0 ) { command = cmd2.toUpperCase(Locale.JAPAN); }
819        }
820
821        /**
822         * 【TAG】query の結果を画面上に表示するメッセージIDを指定します(初期値:MSG0033[ 件検索しました])。
823         *
824         * @og.tag
825         * ここでは、検索結果の件数や登録された件数をまず出力し、
826         * その次に、ここで指定したメッセージをリソースから取得して
827         * 表示します。
828         * 表示させたくない場合は, displayMsg = "" をセットしてください。
829         * 初期値は、検索件数を表示します。
830         *
831         * @param   id ディスプレイに表示させるメッセージ ID
832         */
833        public void setDisplayMsg( final String id ) {
834                if( id != null ) { displayMsg = id; }
835        }
836
837        /**
838         * 【TAG】検索結果がゼロ件の場合に表示するメッセージリソースIDを指定します(初期値:MSG0077[対象データはありませんでした])。
839         *
840         * @og.tag
841         * ここでは、検索結果がゼロ件の場合のみ、特別なメッセージを表示させます。
842         * 従来は、displayMsg と兼用で、『0 件検索しました』という表示でしたが、
843         * displayMsg の初期表示は、OFF になりましたので、ゼロ件の場合のみ別に表示させます。
844         * 表示させたくない場合は, notfoundMsg = "" をセットしてください。
845         * 初期値は、MSG0077[対象データはありませんでした]です。
846         *
847         * @param       id ディスプレイに表示させるメッセージ ID
848         */
849        public void setNotfoundMsg( final String id ) {
850                String ids = getRequestParameter( id );
851                if( ids != null ) { notfoundMsg = ids; }
852        }
853
854        /**
855         * 【TAG】ファイル取り込み時の モディファイタイプ(A(追加),C(更新),D(削除))を指定します。
856         *
857         * @og.tag
858         * ファイル読み込み時に、そのデータをA(追加)、C(更新)、D(削除)の
859         * モディファイタイプをつけた状態にします。
860         * その状態で、そのまま、update する事が可能になります。
861         *
862         * @param   type ファイル取り込み時の モディファイタイプ(A,C,D属性)
863         */
864        public void setModifyType( final String type ) {
865                modifyType = getRequestParameter( type );
866        }
867
868        /**
869         * 【TAG】EXCELファイルを読み込むときのシート名を設定します(初期値:指定なし)。
870         *
871         * @og.tag
872         * EXCELファイルを読み込む時に、シート名を指定します。これにより、複数の形式の
873         * 異なるデータを順次読み込むことや、シートを指定して読み取ることが可能になります。
874         * sheetNos と sheetName が同時に指定された場合は、sheetNos が優先されます。エラーにはならないのでご注意ください。
875         * 初期値は、指定なしです。
876         *
877         * @og.rev 3.5.4.2 (2003/12/15) 新規追加
878         *
879         * @param   sheet EXCELファイルのシート名
880         * @see         #setSheetNos( String )
881         */
882        public void setSheetName( final String sheet ) {
883                sheetName = nval( getRequestParameter( sheet ),sheetName );
884        }
885
886        /**
887         * 【TAG】EXCELファイルを読み込むときのシート番号を指定します(初期値:0)。
888         *
889         * @og.tag
890         * EXCEL読み込み時に複数シートをマージして取り込みます。
891         * シート番号は、0 から始まる数字で表します。
892         * ヘッダーは、最初のシートのカラム位置に合わせます。(ヘッダータイトルの自動認識はありません。)
893         * よって、指定するシートは、すべて同一レイアウトでないと取り込み時にカラムのずれが発生します。
894         *
895         * シート番号の指定は、カンマ区切りで、複数指定できます。また、N-M の様にハイフンで繋げることで、
896         * N 番から、M 番のシート範囲を一括指定可能です。また、"*" による、全シート指定が可能です。
897         * これらの組み合わせも可能です。( 0,1,3,5-8,10-* )
898         * ただし、"*" に関しては例外的に、一文字だけで、すべてのシートを表すか、N-* を最後に指定するかの
899         * どちらかです。途中には、"*" は、現れません。
900         * シート番号は、重複(1,1,2,2)、逆転(3,2,1) での指定が可能です。これは、その指定順で、読み込まれます。
901         * sheetNos と sheetName が同時に指定された場合は、sheetNos が優先されます。エラーにはならないのでご注意ください。
902         *
903         * 初期値は、0(第一シート) です。
904         *
905         * @og.rev 5.5.7.2 (2012/10/09) 新規追加
906         *
907         * @param   sheet EXCELファイルのシート番号(0から始まる)
908         * @see         #setSheetName( String )
909         */
910        public void setSheetNos( final String sheet ) {
911                sheetNos = nval( getRequestParameter( sheet ),sheetNos );
912                if( sheetNos != null && sheetNos.length() > 0 ) {
913                        boolean errFlag = false;
914                        for( int i=0; i<sheetNos.length(); i++ ) {
915                                char ch = sheetNos.charAt(i);
916                                if( ch == '-' || ch == ',' ) { continue; }
917                                if( ch == '*' && ( i==0 || i==sheetNos.length()-1 ) ) { continue; }
918                                if( ch < '0' || ch > '9' ) { errFlag = true; break; }
919                        }
920                        if( errFlag ) {
921                                String errMsg = "sheetNos の指定を見直してください。sheetNos=[" + sheetNos + "]";
922                                throw new HybsSystemException( errMsg );
923                        }
924                }
925        }
926
927        /**
928         * 【TAG】EXCELファイルを読み込むときのシート単位の固定値を設定するためのカラム名を指定します。
929         *
930         * @og.tag
931         * カラム名は、カンマ区切りで指定します。
932         * これにより、シートの一か所に書かれている情報を、DBTableModel のカラムに固定値として
933         * 設定することができます。
934         * 例として、DB定義書で、テーブル名をシートの全レコードに設定したい場合などに使います。
935         * このメソッドは、isExcel() == true の場合のみ利用されます。
936         *
937         * @og.rev 5.5.8.2 (2012/11/09) 新規追加
938         *
939         * @param   constKeys 固定値となるカラム名(CSV形式)
940         * @see         #setSheetConstAdrs( String )
941         */
942        public void setSheetConstKeys( final String constKeys ) {
943                sheetConstKeys = nval( getRequestParameter( constKeys ),null );
944        }
945
946        /**
947         * 【TAG】EXCELファイルを読み込むときのシート単位の固定値を設定するためのカラム名に対応するアドレスを指定します。
948         *
949         * @og.tag
950         * アドレスは、EXCEL上の行-列をカンマ区切りで指定します。
951         * 行列は、EXCELオブジェクトに準拠するため、0から始まる整数です。
952         * 0-0 ⇒ A1 , 1-0 ⇒ A2 , 0-1 ⇒ B1 になります。
953         * これにより、シートの一か所に書かれている情報を、DBTableModel のカラムに固定値として
954         * 設定することができます。
955         * 例として、DB定義書で、テーブル名をシートの全レコードに設定したい場合などに使います。
956         * このメソッドは、isExcel() == true の場合のみ利用されます。
957         *
958         * 5.7.6.3 (2014/05/23) より、
959         *   @EXCEL表記に準拠した、A1,A2,B1 の記述も処理できるように対応します。
960         *     なお、A1,A2,B1 の記述は、必ず、英字1文字+数字 にしてください。(A〜Zまで)
961         *   A処理中のEXCELシート名をカラムに割り当てるために、"SHEET" という記号に対応します。
962         * 例えば、sheetConstKeys="CLM,LANG,NAME" とし、sheetConstAdrs="0-0,A2,SHEET" とすると、
963         * NAMEカラムには、シート名を読み込むことができます。
964         * これは、内部処理の簡素化のためです。
965         *
966         * ちなみに、EXCELのセルに、シート名を表示させる場合の関数は、下記の様になります。
967         * =RIGHT(CELL("filename",$A$1),LEN(CELL("filename",$A$1))-FIND("]",CELL("filename",$A$1)))
968         *
969         * @og.rev 5.5.8.2 (2012/11/09) 新規追加
970         *
971         * @param   constAdrs 固定値となるアドレス(行-列,行-列,・・・)
972         * @see         #setSheetConstKeys( String )
973         */
974        public void setSheetConstAdrs( final String constAdrs ) {
975                sheetConstAdrs = nval( getRequestParameter( constAdrs ),null );
976        }
977
978        /**
979         * 【TAG】ここに指定されたカラム列に NULL が現れた時点で読み取りを中止します。
980         *
981         * @og.tag
982         * これは、指定のカラムは必須という事を条件に、そのレコードだけを読み取る処理を行います。
983         * 複数Sheetの場合は、次のSheetを読みます。
984         * 現時点では、Excel の場合のみ有効です。
985         *
986         * @og.rev 5.5.8.2 (2012/11/09) 新規追加
987         *
988         * @param   clm カラム列
989         */
990        public void setNullBreakClm( final String clm ) {
991                nullBreakClm = nval( getRequestParameter( clm ),null );
992        }
993
994        /**
995         * 【TAG】読み取り元ファイルのカラム列を、外部(タグ)より指定します。
996         *
997         * @og.tag
998         * 読み取り元ファイルのカラム列を、外部(タグ)より指定します。
999         * ファイルに記述された #NAME より優先して使用されます。
1000         * これは、元ファイルのカラムを順番に指定のカラム名に割り当てる機能で
1001         * ファイルの特定のカラム列を抜き出して取り込む機能ではありません。
1002         *
1003         * @og.rev 3.5.4.5 (2004/01/23) 新規作成
1004         *
1005         * @param   clms 読み取り元ファイルのカラム列(カンマ区切り文字)
1006         */
1007        public void setColumns( final String clms ) {
1008                columns = nval( getRequestParameter( clms ),columns );
1009        }
1010
1011        /**
1012         * 【TAG】読み取り元ファイルの整合性チェックを行うカラム列をカンマ指定します。
1013         *
1014         * @og.tag
1015         * カラムオブジェクトのDBType属性に対応したチェックを行います。
1016         * 指定のカラム名をカンマ区切り(CSV)で複数指定できます。
1017         * 全てのカラムのチェックを行う場合は、allColumnCheck = "true" を
1018         * 指定して下さい。
1019         * 分解方法は、通常のパラメータ取得後に、CSV分解します。
1020         *
1021         * @og.rev 3.6.0.2 (2004/10/04) 新規追加 取り込み時チェック用
1022         * @og.rev 3.8.8.5 (2007/03/09) 通常のパラメータ取得後に、CSV分解に戻します。
1023         *
1024         * @param   clms 整合性チェックを行うカラム列(カンマ区切り文字)
1025         */
1026        public void setCheckColumns( final String clms ) {
1027                checkColumns = nval( getRequestParameter( clms ),checkColumns );
1028        }
1029
1030        /**
1031         * 【TAG】読み取り元ファイルのデータ変換を行うカラム列をカンマ指定します。
1032         *
1033         * @og.tag
1034         * カラムオブジェクトのDBType属性に対応したデータ変換を行います。
1035         * 指定のカラム名をカンマ区切り(CSV)で複数指定できます。
1036         * 分解方法は、通常のパラメータ取得後に、CSV分解します。
1037         *
1038         * @og.rev 3.6.0.2 (2004/10/04) 新規追加 取り込み時データ変換
1039         * @og.rev 3.8.8.5 (2007/03/09) 通常のパラメータ取得後に、CSV分解に戻します。
1040         *
1041         * @param   clms データ変換を行うカラム列(カンマ区切り文字)
1042         */
1043        public void setAdjustColumns( final String clms ) {
1044                adjustColumns = nval( getRequestParameter( clms ),adjustColumns );
1045        }
1046
1047        /**
1048         * 【TAG】NULL チェックすべきカラム列をカンマ区切り(CVS形式)で指定します。
1049         *
1050         * @og.tag nullCheck="AAA,BBB,CCC,DDD"
1051         * 分解方法は、通常のパラメータ取得後に、CSV分解します。
1052         *
1053         * @og.rev 3.8.0.2 (2005/06/30) 新規追加
1054         * @og.rev 3.8.8.5 (2007/03/09) 通常のパラメータ取得後に、CSV分解に戻します。
1055         *
1056         * @param   clms カラム列(CVS形式)
1057         */
1058        public void setNullCheck( final String clms ) {
1059                nullCheck = nval( getRequestParameter( clms ),nullCheck );
1060        }
1061
1062        /**
1063         * 【TAG】行番号情報を、使用している/していない[true/false]を指定します(初期値:true)。
1064         *
1065         * @og.tag
1066         * 通常のフォーマットでは、各行の先頭に行番号が出力されています。
1067         * 読み取り時に、#NAME 属性を使用する場合は、この行番号を無視しています。
1068         * #NAME 属性を使用せず、columns 属性でカラム名を指定する場合(他システムの
1069         * 出力ファイルを読み取るケース等)では、行番号も存在しないケースがあり、
1070         * その様な場合に、useNumber="false" を指定すれば、データの最初から読み取り始めます。
1071         * この場合、出力データのカラムの並び順が変更された場合、columns 属性も
1072         * 指定しなおす必要がありますので、できるだけ、#NAME 属性を使用するように
1073         * してください。
1074         * なお、EXCEL 入力には、この設定は適用されません。(暫定対応)
1075         * 初期値は、true(使用する) です。
1076         *
1077         * @og.rev 3.7.0.5 (2005/04/11) 新規追加
1078         *
1079         * @param   useNo 行番号情報 [true:使用する/false:使用しない]
1080         */
1081        public void setUseNumber( final String useNo ) {
1082                useNumber = nval( getRequestParameter( useNo ),useNumber );
1083        }
1084
1085        /**
1086         * 【TAG】読込件数が0件のとき処理を続行するかどうか[true/false]を指定します(初期値:false[続行する])。
1087         *
1088         * @og.tag
1089         * 初期値は、false(続行する)です。
1090         *
1091         * @og.rev 4.3.7.0 (2009/06/01) 新規追加
1092         *
1093         * @param  cmd 読込件数が0件のとき、処理を [true:中止する/false:続行する]
1094         */
1095        public void setStopZero( final String cmd ) {
1096                stopZero = nval( getRequestParameter( cmd ), stopZero );
1097        }
1098
1099        /**
1100         * 【TAG】(通常使いません)タグで処理される処理がメインとなるトランザクション処理かどうかを指定します(初期値:false)。
1101         *
1102         * @og.tag
1103         * この値は、ファイルダウンロード処理に影響します。この値がtrueに指定された時にcommitされたDBTableModelが
1104         * ファイルダウンロードの対象の表になります。
1105         *
1106         * このパラメーターは、通常、各タグにより実装され、ユーザーが指定する必要はありません。
1107         * 但し、1つのJSP内でDBTableModelが複数生成される場合に、前に処理したDBTableModelについてファイルダウンロードをさせたい
1108         * 場合は、後ろでDBTableModelを生成するタグで、明示的にこの値をfalseに指定することで、ファイルダウンロード処理の対象から
1109         * 除外することができます。
1110         *
1111         * @og.rev 5.1.6.0 (2010/05/01) 新規作成
1112         *
1113         * @param  flag メイントランザクションかどうか
1114         */
1115        public void setMainTrans( final String flag ) {
1116                isMainTrans = nval( getRequestParameter( flag ),isMainTrans );
1117        }
1118
1119        /**
1120         * 【TAG】(通常は使いません)データの読み飛ばし件数を設定します。
1121         *
1122         * @og.tag
1123         * TAB区切りテキストやEXCEL等のデータの読み始めの初期値を指定します。
1124         * ファイルの先頭行が、0行としてカウントしますので、設定値は、読み飛ばす
1125         * 件数になります。(1と指定すると、1件読み飛ばし、2行目から読み込みます。)
1126         * 読み飛ばしは、コメント行などは、無視しますので、実際の行数分読み飛ばします。
1127         * #NAME属性や、columns 属性は、有効です。
1128         *
1129         * @og.rev 5.1.6.0 (2010/05/01) 新規作成
1130         *
1131         * @param       count 読み始めの初期値
1132         */
1133        public void setSkipRowCount( final String count ) {
1134                skipRowCount = nval( getRequestParameter( count ),skipRowCount );
1135        }
1136
1137        /**
1138         * 【TAG】読取処理でラベルをコードリソースに逆変換を行うかどうかを指定します
1139         *              (初期値:USE_TABLE_READER_RENDERER[={@og.value org.opengion.hayabusa.common.SystemData#USE_TABLE_READER_RENDERER}])。
1140         *
1141         * @og.tag
1142         * TableWriter_Renderer 系のクラスで出力した場合は、コードリソースがラベルで出力されます。
1143         * そのファイルを読み取ると、当然、エラーになります。
1144         * ここでは、コードリソースのカラムに対して、ラベルからコードを求める逆変換を行うことで、
1145         * Renderer 系で出力したファイルを取り込むことができるようにします。
1146         *
1147         * ここでは、TableWriter 系と同様に、TableReader_Renderer 系のクラスを作るのではなく、
1148         * 属性値のフラグで、制御します。
1149         * 将来的には、TableWriter 系も廃止して、同様のフラグで制御するように変更する予定です。
1150         * (初期値:システム定数のUSE_TABLE_READER_RENDERER[={@og.value org.opengion.hayabusa.common.SystemData#USE_TABLE_READER_RENDERER}])。
1151         *
1152         * @og.rev 5.2.1.0 (2010/10/01) 新規作成
1153         *
1154         * @param  flag コードリソースのラベル逆変換を行うかどうか
1155         * @see         org.opengion.hayabusa.common.SystemData#USE_TABLE_READER_RENDERER
1156         */
1157        public void setUseRenderer( final String flag ) {
1158                useRenderer = nval( getRequestParameter( flag ),useRenderer );
1159        }
1160
1161        /**
1162         * 【TAG】matchKeysをカンマ区切りで指定します。
1163         *
1164         * @og.tag
1165         * ファイルから特定の行のみを読み取るためのmatchKeysを指定します。
1166         * matchKeysで指定したカラムに対して、matchValsの正規表現でチェックします。
1167         * この機能はTableReader_Defaultのみ有効です。
1168         * 通常は指定する必要はありません。
1169         *
1170         *
1171         * @og.rev 5.9.8.1 (2016/05/13) 新規作成
1172         *
1173         * @param   keys カラム列(カンマ区切り文字)
1174         */
1175        public void setMatchKeys( final String keys ) {
1176                matchKeys = getCSVParameter( keys );
1177
1178                if( matchVals != null && matchKeys.length != matchVals.length ) {
1179                        String errMsg = "matchKeys属性とmatchVals属性の個数が合いません。"
1180                                                + HybsSystem.CR
1181                                                + " matchKeys=[" + matchKeys.length + "]:KEYS="
1182                                                + StringUtil.array2csv( matchKeys ) + HybsSystem.CR
1183                                                + " matchVals=[" + matchVals.length + "]:VLAS="
1184                                                + StringUtil.array2csv( matchVals ) + HybsSystem.CR ;
1185                        throw new HybsSystemException( errMsg );
1186                }
1187        }
1188
1189        /**
1190         * 【TAG】matchKeysをカンマ区切りで指定します。
1191         *
1192         * @og.tag
1193         * ファイルから特定の行のみを読み取るためのmatchKeysを指定します。
1194         * matchKeysで指定したカラムに対して、matchValsの正規表現でチェックします。
1195         * この機能はTableReader_Defaultのみ有効です。
1196         * 通常は指定する必要はありません。
1197         *
1198         *
1199         * @og.rev 5.9.8.1 (2016/05/13) 新規作成
1200         *
1201         * @param   keys カラム列(カンマ区切り文字)
1202         */
1203        public void setMatchVals( final String keys ) {
1204                matchVals = getCSVParameter( keys );
1205
1206                if( matchKeys != null && matchKeys.length != matchVals.length ) {
1207                        String errMsg = "matchKeys属性とmatchVals属性の個数が合いません。"
1208                                                + HybsSystem.CR
1209                                                + " matchKeys=[" + matchKeys.length + "]:KEYS="
1210                                                + StringUtil.array2csv( matchKeys ) + HybsSystem.CR
1211                                                + " matchVals=[" + matchVals.length + "]:VLAS="
1212                                                + StringUtil.array2csv( matchVals ) + HybsSystem.CR ;
1213                        throw new HybsSystemException( errMsg );
1214                }
1215        }
1216
1217        /**
1218         * シリアライズ用のカスタムシリアライズ書き込みメソッド
1219         *
1220         * @og.rev 4.0.0.0 (2006/09/31) 新規追加
1221         * @serialData 一部のオブジェクトは、シリアライズされません。
1222         *
1223         * @param       strm    ObjectOutputStreamオブジェクト
1224         * @throws IOException  入出力エラーが発生した場合
1225         */
1226        private void writeObject( final ObjectOutputStream strm ) throws IOException {
1227                strm.defaultWriteObject();
1228        }
1229
1230        /**
1231         * シリアライズ用のカスタムシリアライズ読み込みメソッド
1232         *
1233         * ここでは、transient 宣言された内部変数の内、初期化が必要なフィールドのみ設定します。
1234         *
1235         * @og.rev 4.0.0.0 (2006/09/31) 新規追加
1236         * @serialData 一部のオブジェクトは、シリアライズされません。
1237         *
1238         * @param       strm    ObjectInputStreamオブジェクト
1239         * @see #release2()
1240         * @throws IOException  シリアライズに関する入出力エラーが発生した場合
1241         * @throws ClassNotFoundException       クラスを見つけることができなかった場合
1242         */
1243        private void readObject( final ObjectInputStream strm ) throws IOException , ClassNotFoundException {
1244                strm.defaultReadObject();
1245        }
1246
1247        /**
1248         * このオブジェクトの文字列表現を返します。
1249         * 基本的にデバッグ目的に使用します。
1250         *
1251         * @return このクラスの文字列表現
1252         */
1253        @Override
1254        public String toString() {
1255                return org.opengion.fukurou.util.ToString.title( this.getClass().getName() )
1256                                .println( "VERSION"                     ,VERSION        )
1257                                .println( "separator"           ,separator              )
1258                                .println( "fileURL"             ,fileURL                )
1259                                .println( "filename"            ,filename               )
1260                                .println( "encode"                      ,encode                 )
1261                                .println( "readerClass"         ,readerClass    )
1262                                .println( "maxRowCount"         ,maxRowCount    )
1263                                .println( "displayMsg"          ,displayMsg             )
1264                                .println( "executeCount"        ,executeCount   )
1265                                .println( "modifyType"          ,modifyType             )
1266                                .println( "checkColumns"        ,checkColumns   )
1267                                .println( "adjustColumns"       ,adjustColumns  )
1268                                .println( "nullCheck"           ,nullCheck              )
1269                                .println( "command"                     ,command                )
1270                                .println( "tableId"                     ,tableId                )
1271                                .println( "sheetName"           ,sheetName              )
1272                                .println( "sheetNos"            ,sheetNos               )               // 5.5.7.2 (2012/10/09)
1273                                .println( "columns"                     ,columns                )
1274                                .println( "useNumber"           ,useNumber              )
1275                                .println( "Other..."    ,getAttributes().getAttribute() )
1276                                .fixForm().toString() ;
1277        }
1278}