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.db.Transaction;
019import org.opengion.fukurou.db.ResultSetValue;                                          // 6.0.4.0 (2014/11/28)
020import org.opengion.fukurou.util.ErrorMessage;
021import org.opengion.fukurou.util.FileUtil;
022import org.opengion.fukurou.util.StringUtil;
023import org.opengion.fukurou.system.Closer ;
024import org.opengion.fukurou.util.ToString;                                                      // 6.1.1.0 (2015/01/17)
025import static org.opengion.fukurou.util.StringUtil.nval ;
026import static org.opengion.fukurou.system.HybsConst.BR;                         // 6.1.0.0 (2014/12/26) refactoring
027import static org.opengion.fukurou.system.HybsConst.DB_FETCH_SIZE;      // 6.9.4.1 (2018/04/09)
028
029import org.opengion.hayabusa.common.HybsSystem;
030import org.opengion.hayabusa.common.HybsSystemException;
031import org.opengion.hayabusa.resource.GUIInfo;
032import org.opengion.hayabusa.resource.ResourceManager;
033import org.opengion.hayabusa.db.DBErrMsg;
034
035import java.sql.Connection;
036import java.sql.Statement;
037import java.sql.CallableStatement;
038import java.sql.ResultSet;
039import java.sql.SQLException;
040import java.sql.Types;
041import java.sql.Array;                                                          // 6.0.0.0 (2014/04/11) Oracle11g(11.2.0.3のドライバ) 対応。oracle.sql.ARRAY の置き換え
042import oracle.jdbc.OracleConnection;                            // 6.0.0.0 (2014/04/11) Oracle11g(11.2.0.3のドライバ) 対応
043import oracle.jdbc.OracleTypes;                                         // CURSOR が残る
044import oracle.jdbc.OracleCallableStatement;                     // CURSOR が残る
045
046import java.io.File;
047import java.io.PrintWriter;
048import java.io.FileOutputStream;
049import java.io.BufferedOutputStream;                            // 6.0.4.0 (2014/11/28)
050
051import java.io.IOException;
052import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;                       // 6.0.4.0 (2014/11/28)
053import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;        // 6.0.4.0 (2014/11/28)
054
055import java.util.Map;
056
057/**
058 * SELECT文を直接実行して、指定のファイルに出力するタグです。
059 *
060 * 中間の、データ(DBTableModel)を作成しないため、余計なメモリを取らず、
061 * 高速にデータを抜き出すことが可能です。
062 * 一方、抜き出すデータは生データのため、データの再利用等、システム的な
063 * 使用を想定しています。
064 * JDBCErrMsg 形式のPL/SQL をコールして、その検索結果(カーソル)を抜く事もできます。
065 *
066 * ※ このタグは、Transaction タグの対象です。
067 *
068 * @og.formSample
069 * ●形式:<og:directWriteTable filename="[・・・]" ・・・ >SELECT * FROM ZYXX </og:directWriteTable >
070 * ●body:あり(EVAL_BODY_BUFFERED:BODYを評価し、{@XXXX} を解析します)
071 *
072 * ●Tag定義:
073 *   <og:directWriteTable
074 *       fileURL            【TAG】保存先ディレクトリ名を指定します (初期値:FILE_URL[=filetemp/])
075 *       filename           【TAG】ファイルを作成するときのファイル名をセットします(初期値:システムパラメータのFILE_FILENAME)
076 *       encode             【TAG】ファイルを作成するときのファイルエンコーディング名をセットします (初期値:FILE_ENCODE[=UnicodeLittle])
077 *       fileAppend         【TAG】追加モードで書き込むかどうか[true/false]を指定します(初期値:false[通常モード])
078 *       zip                【TAG】結果をファイルに出力するときに、ZIPで圧縮するかどうか[true/false]を指定します(初期値:false)
079 *       zipFilename        【TAG】ZIPファイルを作成するときのZIPファイル名をセットします(初期値:filename + ".zip")
080 *       separator          【TAG】可変長ファイルを作成するときの項目区切り文字をセットします (初期値:TAB_SEPARATOR)
081 *       useHeader          【TAG】ヘッダーを書き込むかどうか[true/false]を指定します(初期値:true)
082 *       useQuote           【TAG】データをダブルクオートで囲うかどうか指定します(初期値:false)
083 *       useQuoteEscape     【TAG】データ中にダブルクオート文字が含まれる場合、エスケープするかどうか指定します(初期値:true)
084 *       useReturnQuote     【TAG】データ中に改行コードが含まれる場合、ダブルクオートで囲うかどうか指定します(初期値:true)
085 *       replaceFrom        【TAG】置換元文字を指定。一文字単位で置換します(初期値:null 置換なし)。
086 *       replaceTo          【TAG】置換先文字を指定。一文字単位で置換します。
087 *       displayMsg         【TAG】検索結果を画面上に表示するメッセージリソースIDを指定します(初期値:VIEW_DISPLAY_MSG[=])
088 *       notfoundMsg        【TAG】検索結果がゼロ件の場合に表示するメッセージリソースIDを指定します(初期値:MSG0077[対象データはありませんでした])
089 *       fetchSize          【TAG】(通常は使いません)データのフェッチサイズを指定します(初期値:DB_FETCH_SIZE[={@og.value org.opengion.fukurou.system.HybsConst#DB_FETCH_SIZE}])
090 *       names              【TAG】PL/SQLを利用する場合の引数にセットすべき データの名称をCSV形式で複数指定します
091 *       queryType          【TAG】Query を発行する為のクラスID(JDBC,JDBCErrMsg)を指定します({@og.doc03Link queryType 初期値:JDBC})
092 *       dbid               【TAG】(通常は使いません)検索時のDB接続IDを指定します(初期値:DEFAULT)
093 *       useNumber          【TAG】行番号を出力するかどうか(初期値:true)
094 *       quotCheck          【TAG】リクエスト情報の シングルクォート(') 存在チェックを実施するかどうか[true/false]を設定します(初期値:USE_SQL_INJECTION_CHECK)
095 *       xssCheck           【TAG】リクエスト情報の HTMLTag開始/終了文字(><) 存在チェックを実施するかどうか[true/false]を設定します (初期値:USE_XSS_CHECK[=true])
096 *       useTimeView        【TAG】処理時間を表示する TimeView を表示するかどうかを指定します
097 *                                      (初期値:VIEW_USE_TIMEBAR[={@og.value SystemData#VIEW_USE_TIMEBAR}])。
098 *       useSLabel          【TAG】7.0.7.0 (2019/12/13) エラーメッセージにSLABELを利用するかどうか[true/false]を指定します(初期値:false)
099 *       mapObjKey          【TAG】7.0.7.1 (2019/12/24) valueタグのaction=MAPOBJ を使用したラベル変換を行う場合の、MAPOBJキーを指定します。
100 *       caseKey            【TAG】このタグ自体を利用するかどうかの条件キーを指定します(初期値:null)
101 *       caseVal            【TAG】このタグ自体を利用するかどうかの条件値を指定します(初期値:null)
102 *       caseNN             【TAG】指定の値が、null/ゼロ文字列 でない場合(Not Null=NN)は、このタグは使用されます(初期値:判定しない)
103 *       caseNull           【TAG】指定の値が、null/ゼロ文字列 の場合は、このタグは使用されます(初期値:判定しない)
104 *       caseIf             【TAG】指定の値が、true/TRUE文字列の場合は、このタグは使用されます(初期値:判定しない)
105 *       debug              【TAG】デバッグ情報を出力するかどうか[true/false]を指定します(初期値:false)
106 *   >   ... Body ...
107 *   </og:directWriteTable>
108 *
109 * ●使用例
110 *     <og:directWriteTable
111 *         dbid        = "ORCL"               接続データベースID(初期値:DEFAULT)
112 *         separator   = ","                  ファイルの区切り文字(初期値:タブ)
113 *         fileURL     = "{@USER.ID}"    保存先ディレクトリ名
114 *         filename    = "{@filename}"   保存ファイル名
115 *         encode      = "UnicodeLittle"      保存ファイルエンコード名
116 *         useHeader   = "true"               保存ファイルにヘッダーを出力するかどうか
117 *         useQuote    = "false"              データをダブルクオートで囲うかどうか
118 *         useQuoteEscape = "true"            ダブルクオート文字が含まれる場合、エスケープするかどうか
119 *         useReturnQuote = "true"            改行コードが含まれる場合、ダブルクオートで囲うかどうか
120 *         replaceFrom = "',"*%|"        置換元文字を指定。一文字単位で置換します。
121 *         replaceTo   = "’,”*%|"       置換先文字を指定。一文字単位で置換します。
122 *         zip         = "true"               ZIPファイルに圧縮するかどうか
123 *         zipFilename = "Sample.zip"         ZIPファイルのファイル名
124 *         fileAppend  = "true"               ファイルを追加モードで登録するかどうか
125 *         displayMsg  = "MSG0033"            実行後の表示メッセージ
126 *         fetchSize   = "200"                DB検索する場合のフェッチするサイズ
127 *     >
128 *         SELECT * FROM ZYXX 
129 *     </og:directWriteTable >
130 *
131 *     <og:directWriteTable
132 *         fileURL     = "{@USER.ID}"    保存先ディレクトリ名
133 *         filename    = "{@filename}"   保存ファイル名
134 *         names       = "AAA,BBB,CCC,・・・"    指定のキーに対応するリクエスト値を ARG_ARRAY にセットします。
135 *         queryType   = "JDBCErrMsg"         JDBCErrMsg 形式のPL/SQL をコールします。
136 *     >
137 *        { call PL/SQL(?,?,?,? ) } 
138 *     </og:directWriteTable >
139 *
140 * @og.rev 3.5.6.0 (2004/06/18) 新規作成
141 * @og.rev 3.6.1.0 (2005/01/05) PL/SQLコール(JDBCErrMsg 形式)の実行を追加
142 * @og.group ファイル出力
143 *
144 * @version  4.0
145 * @author   Kazuhiko Hasegawa
146 * @since    JDK5.0,
147 */
148public class DirectWriteTableTag extends CommonTagSupport {
149        /** このプログラムのVERSION文字列を設定します。   {@value} */
150        private static final String VERSION = "7.0.7.1 (2019/12/24)" ;
151        private static final long serialVersionUID = 707120191224L ;
152
153        private static final String TAB_SEPARATOR       = "\t" ;
154        private static final String ERR_MSG_ID          = HybsSystem.ERR_MSG_KEY;               // 6.4.1.1 (2016/01/16) errMsgId → ERR_MSG_ID  refactoring
155
156        private final int DB_MAX_QUERY_TIMEOUT          = HybsSystem.sysInt( "DB_MAX_QUERY_TIMEOUT" ) ;
157        private static final String ARG_ARRAY           = "ARG_ARRAY" ;
158        private static final String ERR_MSG                     = "ERR_MSG" ;
159        private static final String ERR_MSG_ARRAY       = "ERR_MSG_ARRAY" ;
160
161//      /** 6.9.3.0 (2018/03/26) データ検索時のフェッチサイズ  */
162//      private static final int DB_FETCH_SIZE          = HybsSystem.sysInt( "DB_FETCH_SIZE" ) ;
163
164        // 4.0.0.0 (2007/10/10) dbid の初期値を、"DEFAULT" から null に変更
165        private String  dbid            ;
166        private String  separator       = TAB_SEPARATOR;        // 項目区切り文字
167        private boolean useHeader       = true;                         // ヘッダーの使用可否
168        private boolean useQuote        ;                                       // 6.0.3.0 (2014/11/13) ダブルクオートで囲うかどうか
169        private boolean useQuoteEscape  = true;                 // 6.0.3.0 (2014/11/13) データ中にダブルクオート文字が含まれる場合、エスケープするかどうか
170        private boolean useReturnQuote  = true;                 // 6.0.3.0 (2014/11/13) データ中に改行コードが含まれる場合、ダブルクオートで囲うかどうか
171        private String  fileURL         = HybsSystem.sys( "FILE_URL" );
172        private String  filename        = HybsSystem.sys( "FILE_FILENAME" );    // ファイル名
173        private String  sql                     ;
174        private String  encode          = HybsSystem.sys( "FILE_ENCODE"   );    // ファイルエンコーディング  "DEFAULT","JISAutoDetect" ,"JIS", "EUC_JP", "MS932", "SJIS" , "Windows-31J" , "Shift_JIS"
175        private boolean fileAppend      ;                                       // ファイルをAPPENDモードで出力するか
176        private boolean zip                     ;                                       // ファイルをZIPするか
177        private String  zipFilename     ;                                       // ZIPファイル名
178        private String  displayMsg      = HybsSystem.sys( "VIEW_DISPLAY_MSG" );
179        private String  notfoundMsg     = "MSG0077";            // 対象データはありませんでした。
180        private long    dyStart         ;                                       // 実行時間測定用のDIV要素を出力します。
181        private boolean useTimeView     = HybsSystem.sysBool( "VIEW_USE_TIMEBAR" );             // 6.3.6.0 (2015/08/16)
182        private int             fetchSize       = DB_FETCH_SIZE ;       // フェッチする行数(初期値:1001)   6.9.3.0 (2018/03/26) 初期値を100→HybsConst.DB_FETCH_SIZE に変更
183        private boolean useNumber       = true;                         // 5.5.7.1(2012/10/05) 行番号出力
184
185        private String  replaceFrom     ;                                       // 6.0.3.0 (2014/11/13) 置換元文字を指定
186        private String  replaceTo       ;                                       // 6.0.3.0 (2014/11/13) 置換先文字を指定
187
188        private boolean quotCheck       = HybsSystem.sysBool( "USE_SQL_INJECTION_CHECK" );      // 6.2.2.0 (2015/03/27)
189        private boolean xssCheck        = HybsSystem.sysBool( "USE_XSS_CHECK" );                        // 6.2.2.0 (2015/03/27)
190
191        // 3.6.1.0 (2005/01/05) PL/SQLコール(JDBCErrMsg 形式)への対応
192        private boolean queryType       = true;                         // ノーマルは、true/ JDBCErrMsg の時は、false
193        private String  names           ;                                       // 指定のリクエスト変数を、ARG_ARRAY にセットします。
194        private int             errCode         = ErrorMessage.OK;
195        private transient ErrorMessage errMessage       ;
196        private boolean useSLabel       ;                                       // 7.0.7.0 (2019/12/13) エラーメッセージにSLABELを利用するかどうか[true/false]を指定します(初期値:false)
197        private String  mapObjKey       ;                                       // 7.0.7.1 (2019/12/24) valueタグのaction=MAPOBJ を使用したラベル変換を行う場合の、MAPOBJキーを指定します。
198
199        /**
200         * デフォルトコンストラクター
201         *
202         * @og.rev 6.4.2.0 (2016/01/29) PMD refactoring. Each class should declare at least one constructor.
203         */
204        public DirectWriteTableTag() { super(); }               // これも、自動的に呼ばれるが、空のメソッドを作成すると警告されるので、明示的にしておきます。
205
206        /**
207         * Taglibの開始タグが見つかったときに処理する doStartTag() を オーバーライドします。
208         *
209         * @og.rev 6.0.3.0 (2014/11/13) 置換元文字,置換先文字のチェック
210         * @og.rev 6.3.4.0 (2015/08/01) caseKey,caseVal,caseNN,caseNull,caseIf 属性対応
211         * @og.rev 6.4.8.1 (2016/07/02) xssCheckを、doStartTag に移動
212         *
213         * @return      後続処理の指示( EVAL_BODY_BUFFERED )
214         */
215        @Override
216        public int doStartTag() {
217                // 6.4.1.1 (2016/01/16) PMD refactoring. A method should have only one exit point, and that should be the last statement in the method
218                // 反転注意、if ロジック統合
219                if( useTag() ) {
220                        dyStart = System.currentTimeMillis();           // 時間測定用
221
222                        useXssCheck( xssCheck );                        // 6.4.8.1 (2016/07/02)
223
224                        // 6.0.3.0 (2014/11/13) 置換元文字,置換先文字を指定
225                        if( ( replaceFrom != null || replaceTo != null ) &&
226                                ( replaceFrom == null || replaceTo == null || replaceFrom.length() != replaceTo.length() ) ) {
227                                        final String errMsg = "置換元文字と置換先文字の文字数が異なります。" + CR
228                                                                + " replaceFrom=[" + replaceFrom + "] , replaceTo=[" + replaceTo + "]"
229                                                                + CR ;
230                                        throw new HybsSystemException( errMsg );
231                        }
232
233                        return EVAL_BODY_BUFFERED ;     // Body を評価する。( extends BodyTagSupport 時)
234                }
235                else {
236                        return SKIP_BODY;
237                }
238        }
239
240        /**
241         * Taglibのタグ本体を処理する doAfterBody() を オーバーライドします。
242         *
243         * @og.rev 3.8.6.3 (2006/11/30) SQL 文の前後のスペースを取り除きます。
244         * @og.rev 6.2.2.0 (2015/03/27) XSSチェック,クォートチェック をサポートします。
245         * @og.rev 6.4.8.1 (2016/07/02) xssCheckを、doStartTag に移動
246         *
247         * @return      後続処理の指示(SKIP_BODY)
248         */
249        @Override
250        public int doAfterBody() {
251                // 6.2.2.0 (2015/03/27) XSSチェック,クォートチェック をサポートします。
252                useQuotCheck( quotCheck );
253
254                sql = getBodyString();
255                if( sql == null || sql.isEmpty() ) {
256                        final String errMsg = "BODY 部の検索用 Select文は、必須です。";
257                        throw new HybsSystemException( errMsg );
258                }
259                sql = sql.trim();
260                return SKIP_BODY ;                              // Body を評価しない
261        }
262
263        /**
264         * Taglibの終了タグが見つかったときに処理する doEndTag() を オーバーライドします。
265         *
266         * @og.rev 3.6.1.0 (2005/01/05) PL/SQLコール(JDBCErrMsg 形式)への対応
267         * @og.rev 4.0.0.0 (2007/10/18) メッセージリソース統合( getResource().getMessage ⇒ getResource().getLabel )
268         * @og.rev 6.0.4.0 (2014/11/28) Zip処理を、ZipOutputStream → ZipArchiveOutputStream に変更
269         * @og.rev 6.3.4.0 (2015/08/01) caseKey,caseVal,caseNN,caseNull,caseIf 属性対応
270         * @og.rev 6.3.8.0 (2015/09/11) FileUtil#getPrintWriter( OutputStream,String ) を使用。
271         * @og.rev 7.0.7.0 (2019/12/13) useSLabel 属性を追加。
272         *
273         * @return      後続処理の指示
274         */
275        @Override
276        public int doEndTag() {
277                debugPrint();           // 4.0.0 (2005/02/28)
278                if( !useTag() ) { return EVAL_PAGE ; }  // 6.3.4.0 (2015/08/01)
279
280                PrintWriter pw = null;
281                final int executeCount;
282                try {
283                        if( zip ) {
284                                final String directory = HybsSystem.url2dir( fileURL );
285
286                                if( zipFilename == null ) { zipFilename = filename + ".zip"; }
287                                ZipArchiveOutputStream gzip = null;                     // 6.0.4.0 (2014/11/28)
288                                try {
289                                        // 6.0.4.0 (2014/11/28) Zip処理を、ZipOutputStream → ZipArchiveOutputStream に変更
290                                        gzip = new ZipArchiveOutputStream(
291                                                                new BufferedOutputStream (
292                                                                        new FileOutputStream (
293                                                                                new File( directory,zipFilename ))));   // 6.0.4.0 (2014/11/28)
294                                        gzip.setEncoding( "Windows-31J" );
295                                        gzip.putArchiveEntry( new ZipArchiveEntry( filename ) );
296                                        // 6.0.4.0 (2014/11/28) ファイルのencode を指定できるようにする。
297                                        // 6.3.8.0 (2015/09/11) FileUtil#getPrintWriter( OutputStream,String ) を使用。
298                                        pw = FileUtil.getPrintWriter( gzip,encode );            // 6.3.8.0 (2015/09/11)
299                                        executeCount = create( pw ) ;
300
301                                        pw.flush();
302                                        gzip.closeArchiveEntry();                               // 6.0.4.0 (2014/11/28)
303                                        gzip.finish() ;
304                                }
305                                finally {
306                                        Closer.ioClose( gzip );         // 4.0.0 (2006/01/31) close 処理時の IOException を無視
307                                }
308                        }
309                        else {
310                                pw = getPrintWriter();
311                                executeCount = create( pw );
312                        }
313                } catch( final IOException ex ) {
314                        final String errMsg = "Error in DirectWriteTableTag: " + toString();
315                        throw new HybsSystemException( errMsg,ex );             // 3.5.5.4 (2004/04/15) 引数の並び順変更
316                } finally {
317                        Closer.ioClose( pw );           // 4.0.0 (2006/01/31) close 処理時の IOException を無視
318                }
319
320                // 3.6.1.0 (2005/01/05) 検索結果の件数を、"DB.COUNT" キーでリクエストにセットする。
321                setRequestAttribute( "DB.COUNT"   , String.valueOf( executeCount ) );
322                setRequestAttribute( "DB.ERR_CODE", String.valueOf( errCode ) );
323
324                final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE );
325
326                // 実行件数の表示
327                if( executeCount > 0 && displayMsg != null && displayMsg.length() > 0 ) {
328                        buf.append( executeCount )
329                                .append( getResource().getLabel( displayMsg ) )
330                                .append( BR );
331                }
332                else if( executeCount == 0 && notfoundMsg != null && notfoundMsg.length() > 0 ) {
333                        buf.append( getResource().getLabel( notfoundMsg ) )
334                                .append( BR );
335                }
336
337                // 3.6.1.0 (2005/01/05) TaglibUtil.makeHTMLErrorTable メソッドを利用
338//              final String err = TaglibUtil.makeHTMLErrorTable( errMessage,getResource() );
339                final String err = TaglibUtil.makeHTMLErrorTable( errMessage,getResource(),useSLabel );         // 7.0.7.0 (2019/12/13)
340                if( err != null && err.length() > 0 ) {
341                        buf.append( err );
342                        setSessionAttribute( ERR_MSG_ID,errMessage );
343                }
344                else {
345                        removeSessionAttribute( ERR_MSG_ID );
346                }
347
348                jspPrint( buf.toString() );
349
350                // 3.6.1.0 (2005/01/05) 警告時に停止していましたが、継続処理させます。
351                int rtnCode = EVAL_PAGE;
352                if( errCode >= ErrorMessage.NG )  {     // 異常
353                        rtnCode = SKIP_PAGE;
354                }
355
356                // 4.0.0 (2005/01/31) セキュリティチェック(データアクセス件数登録)
357                final long dyTime = System.currentTimeMillis()-dyStart;
358                final GUIInfo guiInfo = (GUIInfo)getSessionAttribute( HybsSystem.GUIINFO_KEY );
359                if( guiInfo != null ) { guiInfo.addReadCount( executeCount,dyTime,sql ); }
360
361                if( useTimeView ) {             // 6.3.6.0 (2015/08/16)
362                        // 時間測定用の DIV 要素を出力
363                        jspPrint( "<div id=\"queryTime\" value=\"" + (dyTime) + "\"></div>" );  // 3.5.6.3 (2004/07/12)
364                }
365                return rtnCode ;
366        }
367
368        /**
369         * タグリブオブジェクトをリリースします。
370         * キャッシュされて再利用されるので、フィールドの初期設定を行います。
371         *
372         * @og.rev 3.6.1.0 (2005/01/05) PL/SQLコール(JDBCErrMsg 形式)への対応
373         * @og.rev 4.0.0.0 (2007/10/10) dbid の初期値を、"DEFAULT" から null に変更
374         * @og.rev 5.5.7.1 (2012/10/05) useNumber追加
375         * @og.rev 6.0.3.0 (2014/11/13) useHeader,useQuote,useQuoteEscape,useReturnQuote,replaceFrom,replaceTo追加
376         * @og.rev 6.2.2.0 (2015/03/27) XSSチェック,クォートチェック をサポートします。
377         * @og.rev 6.9.3.0 (2018/03/26) fetchSizeの初期値を100→HybsConst.DB_FETCH_SIZE に変更
378         * @og.rev 7.0.7.0 (2019/12/13) useSLabel 属性を追加。
379         * @og.rev 7.0.7.1 (2019/12/24) mapObjKey 属性を追加。
380         */
381        @Override
382        protected void release2() {
383                super.release2();
384                separator       = TAB_SEPARATOR;        // 項目区切り文字
385                fileURL         = HybsSystem.sys( "FILE_URL" );
386                filename        = HybsSystem.sys( "FILE_FILENAME" );    // ファイル名
387                sql                     = null;
388                encode          = HybsSystem.sys( "FILE_ENCODE" );              // ファイルエンコーディング  "DEFAULT","JISAutoDetect" ,"JIS", "EUC_JP", "MS932", "SJIS" , "Windows-31J" , "Shift_JIS"
389                fileAppend      = false;                        // ファイルをAPPENDモードで出力するか
390                zip                     = false;                        // ファイルをZIPするか
391                zipFilename     = null;                         // ZIPファイル名
392                displayMsg      = HybsSystem.sys( "VIEW_DISPLAY_MSG" );
393                notfoundMsg     = "MSG0077";            // 対象データはありませんでした。
394                dbid            = null;
395                fetchSize       = DB_FETCH_SIZE ;       // フェッチする行数(初期値:0 参考にしない)               6.9.3.0 (2018/03/26) 初期値を100→→HybsConst.DB_FETCH_SIZE に変更
396                useTimeView     = HybsSystem.sysBool( "VIEW_USE_TIMEBAR" );     // 6.3.6.0 (2015/08/16)
397                queryType       = true;                         // ノーマルは、true/ JDBCErrMsg の時は、false
398                names           = null;                         // 指定のリクエスト変数を、ARG_ARRAY にセットします。
399                errCode         = ErrorMessage.OK;
400                errMessage      = null;
401                useNumber       = true;                         // 5.5.7.1 (2012/10/05)
402                useHeader       = true;                         // ヘッダーの使用可否  … 6.0.3.0 (2014/11/13) 追加
403                useQuote        = false;                        // 6.0.3.0 (2014/11/13) ダブルクオートで囲うかどうか
404                useQuoteEscape  = true;                 // 6.0.3.0 (2014/11/13) データ中にダブルクオート文字が含まれる場合、エスケープするかどうか
405                useReturnQuote  = true;                 // 6.0.3.0 (2014/11/13) データ中に改行コードが含まれる場合、ダブルクオートで囲うかどうか
406                replaceFrom     = null;                         // 6.0.3.0 (2014/11/13) 置換元文字を指定
407                replaceTo       = null;                         // 6.0.3.0 (2014/11/13) 置換先文字を指定
408                quotCheck       = HybsSystem.sysBool( "USE_SQL_INJECTION_CHECK" );      // 6.2.2.0 (2015/03/27)
409                xssCheck        = HybsSystem.sysBool( "USE_XSS_CHECK" );                        // 6.2.2.0 (2015/03/27)
410                useSLabel       = false;                        // 7.0.7.0 (2019/12/13) エラーメッセージにSLABELを利用するかどうか[true/false]を指定します(初期値:false)
411                mapObjKey       = null;                         // 7.0.7.1 (2019/12/24) valueタグのaction=MAPOBJ を使用したラベル変換を行う場合の、MAPOBJキーを指定します。
412        }
413
414        /**
415         * 実オブジェクトを生成して,OutputStream に書き込みます。
416         *
417         * @og.rev 3.6.1.0 (2005/01/05) PL/SQLコール(JDBCErrMsg 形式)への対応
418         * @og.rev 3.8.6.0 (2006/09/29) ヘッダーにラベルを出力するように修正
419         * @og.rev 3.8.7.0 (2006/12/15) アクセスログ取得の為,ApplicationInfoオブジェクトを設定
420         * @og.rev 4.3.4.3 (2008/12/22) (Oracle11gDriver対応)PL/SQLコールの場合に、"クローズされた文です。"のエラーが発生する問題に対応
421         * @og.rev 5.1.9.0 (2010/08/01) Transaction 対応
422         * @og.rev 5.2.2.0 (2010/11/01) 改行を含む場合は、ダブルクオートを強制的に前後に追加する。
423         * @og.rev 5.2.2.0 (2010/11/01) ダブルクオートを含む場合は、その直前にダブルクオートを強制的に追加する。
424         * @og.rev 5.3.0.0 (2010/12/01) executeCall メソッドの引数見直し
425         * @og.rev 5.3.7.0 (2011/07/01) TransactionReal の引数変更
426         * @og.rev 5.5.7.1 (2012/10/05) useNumberの追加
427         * @og.rev 6.0.3.0 (2014/11/13) useQuote,useQuoteEscape,useReturnQuote,replaceFrom,replaceToの追加
428         * @og.rev 6.0.3.0 (2014/11/13) ヘッダーとラベルを、指定の separator で出力するように変更します。
429         * @og.rev 6.0.4.0 (2014/11/28) ResultSetValue を使用するように変更。
430         * @og.rev 6.2.0.0 (2015/02/27) データ出力の先頭カンマの判定処理変更
431         * @og.rev 6.3.6.1 (2015/08/28) Transaction でAutoCloseableを使用したtry-with-resources構築に対応。
432         * @og.rev 7.0.7.1 (2019/12/24) mapObjKey 属性を追加。
433         *
434         * @param   outPW 出力先のPrintWriterオブジェクト
435         *
436         * @return      検索件数
437         */
438        @SuppressWarnings(value={"unchecked"})
439        private int create( final PrintWriter outPW )  {
440                final int executeCount;
441                Statement stmt = null;
442                CallableStatement callStmt = null; // 4.3.4.3 (2008/12/22)
443                ResultSet resultSet = null ;
444
445                // 6.3.6.1 (2015/08/28) Transaction でAutoCloseableを使用したtry-with-resources構築に対応。
446                try( final Transaction tran = getTransaction() ) {
447                        final Connection conn = tran.getConnection( dbid );                             // 5.1.9.0 (2010/08/01) Transaction 対応
448                        // 3.6.1.0 (2005/01/05)
449                        if( queryType ) {               // JDBC 通常の SELECT 文
450                                stmt = conn.createStatement();
451                                if( fetchSize > 0 ) { stmt.setFetchSize( fetchSize ); }
452                                resultSet = stmt.executeQuery( sql );
453                        }
454                        else {                                  // PL/SQL Call 文
455                                String[] values = null;
456                                if( names != null ) {
457                                        final String[] nameArray = StringUtil.csv2Array( names );
458                                        values = getRequest( nameArray );
459                                }
460                                callStmt  = conn.prepareCall( sql );
461                                resultSet = executeCall( conn,callStmt,values );                // 5.3.0.0 (2010/12/01)
462                        }
463                        if( resultSet == null ) { return 0; }
464
465                        // 6.0.4.0 (2014/11/28) ResultSetValue を使用するように変更。
466                        final ResultSetValue rsv = new ResultSetValue( resultSet );
467                        final int numberOfColumns =  rsv.getColumnCount();
468
469                        // ヘッダー部の出力
470                        if( useHeader && numberOfColumns > 0 ) {
471                                final StringBuilder headName  = new StringBuilder( BUFFER_MIDDLE );
472                                final StringBuilder headLabel = new StringBuilder( BUFFER_MIDDLE );
473                                if( useNumber ){                                                // 6.0.3.0 (2014/11/13) ヘッダー部の useNumber 対応漏れ
474                                        headName.append(  "#Name" );
475                                        headLabel.append( "#Label" );
476                                }
477
478                                Map<String,String> mapObj = null;               // 7.0.7.1 (2019/12/24) mapObjKey 属性を追加。
479                                if( mapObjKey != null ) {
480                                        
481                                        mapObj = (Map<String,String>)getRequestAttribute( mapObjKey );
482                                }
483
484                                final ResourceManager resource = getResource();
485                                // 6.0.4.0 (2014/11/28) ResultSetValue を使用するように変更。
486                                for( int clmNo=0; clmNo<numberOfColumns; clmNo++ ) {
487                                        final String clm = rsv.getColumnName(clmNo);
488                                        if( clmNo > 0 || useNumber ){                                           // 5.5.7.1 (2012/10/05)
489                                                //この場合だけセパレータ出力する。
490                                                headName.append( separator );                                   // 6.0.3.0 (2014/11/13)
491                                                headLabel.append( separator );                                  // 6.0.3.0 (2014/11/13)
492                                        }
493                                        headName.append( clm );                                                         // 6.0.3.0 (2014/11/13)
494//                                      headLabel.append( resource.getLabel( clm ) );           // 6.0.3.0 (2014/11/13)
495                                        // 7.0.7.1 (2019/12/24) mapObjKey 属性を追加。
496                                        String lbl = resource.getLabel( clm );
497                                        if( mapObj != null ) {
498                                                lbl = mapObj.getOrDefault( clm,lbl );                   // 7.0.7.1 (2019/12/24) Mapの値を優先して、null なら リソース使用
499                                        }
500                                        headLabel.append( lbl );                                                        // 6.0.3.0 (2014/11/13)
501                                }
502                                outPW.println( headName.toString() );
503                                outPW.println( headLabel.toString() );
504                        }
505
506                        int rowNo = 0;
507                        // 6.0.4.0 (2014/11/28) ResultSetValue を使用するように変更。
508                        while( rsv.next() ) {
509                                // 6.0.4.0 (2014/11/28) ResultSetValue を使用するように変更。
510                                if( useNumber ){                                        // 5.5.7.1 (2012/10/05)
511                                        if( useQuote ) { outPW.print( "\"" + rowNo + "\"" ); }  // 行番号
512                                        else {                   outPW.print( rowNo ); }
513                                }
514                                for( int clmNo=0; clmNo<numberOfColumns; clmNo++ ) {
515                                        // 6.0.2.5 (2014/10/31) refactoring:Avoid empty if statements 警告の対応
516                                        if( clmNo > 0 || useNumber ){                                   // 6.2.0.0 (2015/02/27)
517                                                //この場合だけセパレータ出力する。
518                                                outPW.print( separator );
519                                        }
520                                        String sval = replace( rsv.getValue(clmNo) );                           // 禁則文字の置換処理
521                                        if( sval != null && sval.length() > 0 ) {
522                                                // 6.0.3.0 (2014/11/13) データ中にダブルクオート文字が含まれる場合、エスケープするかどうか
523                                                if( useQuoteEscape && sval.indexOf( '"' ) >= 0 ) { sval = sval.replaceAll( "\"" ,"\"\"" ) ; }
524                                                // 6.0.3.0 (2014/11/13) データ中に改行コードが含まれる場合、ダブルクオートで囲うかどうか
525                                                if( useQuote || useReturnQuote && sval.indexOf( CR ) >= 0 ) {
526                                                        sval = "\"" + sval + "\"" ;
527                                                }
528                                        }
529                                        else {
530                                                sval = useQuote ? "\"\"" : "" ;
531                                        }
532                                        outPW.print( sval );
533                                }
534                                outPW.println();
535                                rowNo++ ;
536                        }
537                        executeCount = rowNo ;
538                        tran.commit();                          // 6.3.6.1 (2015/08/28)
539                }
540                catch( final SQLException ex ) {                // catch は、close() されてから呼ばれます。
541                        final String errMsg = "データベース処理を実行できませんでした。"
542                                                 + CR + '[' + sql + ']' + CR
543                                                 + "err=[" + ex.getSQLState() + ']'
544                                                 + ex.getMessage();
545                        throw new HybsSystemException( errMsg,ex );
546                }
547                finally {                                               // finally は、close() されてから呼ばれます。
548                        Closer.resultClose( resultSet );
549                        Closer.stmtClose( stmt );
550                        Closer.stmtClose( callStmt );   // 4.3.4.3 (2008/12/22)
551                }
552
553                return executeCount ;
554        }
555
556        /**
557         * replaceFrom,replaceTo に基づく禁則文字の置換処理を行います。
558         *
559         * replaceFrom の1文字づつを、対応するreplaceToの1文字づつに変換します。
560         * replaceFrom と replaceTo の文字数は同じでなければなりません。
561         *
562         * @og.rev 6.0.3.0 (2014/11/13) 新規追加
563         *
564         * @param   str 置換する文字列
565         *
566         * @return      置換後の文字列
567         */
568        private String replace( final String str ) {
569                String rtn = str;
570                if( rtn != null && replaceFrom != null && replaceTo != null ) {
571                        for( int i=0; i<replaceTo.length(); i++ ) {
572                                rtn = rtn.replace( replaceFrom.charAt(i) , replaceTo.charAt(i) );               // charの置き換えは、全件
573                        }
574                }
575                return rtn ;
576        }
577
578        /**
579         * 引数配列付のクエリーを実行します。
580         * 処理自体は, #execute() と同様に、各サブクラスの実装に依存します。
581         * これは、CallableStatement を用いて、データベース検索処理を行います。
582         * {call TYPE3B01.TYPE3B01(?,?,?,?)} で、4番目の引数には、
583         * names で指定したリクエスト情報が、ARG_ARRAY 配列に順次セットされます。
584         * 使用する場合は、一旦わかり易い変数に受けて利用してください。
585         * 呼び出す PL/SQL では、検索系PL/SQL です。
586         *
587         * @og.rev 3.6.1.0 (2005/01/05) PL/SQLコール(JDBCErrMsg 形式)への対応
588         * @og.rev 4.3.4.3 (2008/12/22) (Oracle11gDriver対応)PL/SQLコールの場合に、"クローズされた文です。"のエラーが発生する問題に対応
589         * @og.rev 5.3.0.0 (2010/12/01) executeCall メソッドの引数見直し
590         * @og.rev 6.0.0.0 (2014/04/11) Oracle11g(11.2.0.3のドライバ)対応
591         *
592         * @param       conn            コネクション
593         * @param   callStmt    コーラブルステートメント
594         * @param   args                オブジェクトの引数配列(可変長引数)
595         *
596         * @return      結果オブジェクト
597         */
598        private ResultSet executeCall( final Connection conn,final CallableStatement callStmt,final String... args ) throws SQLException {
599                callStmt.setQueryTimeout( DB_MAX_QUERY_TIMEOUT );
600                if( fetchSize > 0 ) { callStmt.setFetchSize( fetchSize ); }
601                final Map<String,Class<?>> map = conn.getTypeMap();
602                try {
603                        map.put( ERR_MSG,Class.forName( "org.opengion.hayabusa.db.DBErrMsg" ) );
604                }
605                catch( final ClassNotFoundException ex ) {
606                        final String errMsg = "org.opengion.hayabusa.db.DBErrMsg クラスが見つかりません。" + CR
607                                        + ex.getMessage();                      // // 5.1.8.0 (2010/07/01) errMsg 修正
608                        throw new HybsSystemException( errMsg,ex );             // 3.5.5.4 (2004/04/15) 引数の並び順変更
609                }
610
611                // 6.0.0.0 (2014/04/11) Oracle11g(11.2.0.3のドライバ)対応 http://docs.oracle.com/cd/E28389_01/web.1111/b60995/thirdparty.htm
612                final Array newArray = ((OracleConnection)conn).createOracleArray( ARG_ARRAY, StringUtil.rTrims( args ));               // 6.0.0.0 (2014/04/11) Oracle11g(11.2.0.3のドライバ)対応
613
614                callStmt.registerOutParameter(1, Types.INTEGER);
615                callStmt.registerOutParameter(2, Types.ARRAY,ERR_MSG_ARRAY);            // 6.0.0.0 (2014/04/11) Oracle11g(11.2.0.3のドライバ)対応
616                callStmt.registerOutParameter(3, OracleTypes.CURSOR);
617                callStmt.setArray( 4,newArray );                                                                        // 6.0.0.0 (2014/04/11) Oracle11g(11.2.0.3のドライバ)対応
618
619                callStmt.execute();
620
621                errCode = callStmt.getInt(1);
622
623                // 6.4.1.1 (2016/01/16) PMD refactoring. Avoid declaring a variable if it is unreferenced before a possible exit point.
624                ResultSet resultSet = null;
625                if( errCode < ErrorMessage.NG ) {               // 異常以外の場合
626                        resultSet = ((OracleCallableStatement)callStmt).getCursor(3);
627                }
628                if( errCode > ErrorMessage.OK ) {               // 正常以外の場合
629                        final Array rtn3 = callStmt.getArray(2);                                                                // 6.0.0.0 (2014/04/11) Oracle11g(11.2.0.3のドライバ)対応
630                        final Object[] rtnval3 = (Object[])rtn3.getArray();
631                        errMessage = new ErrorMessage( "Query_JDBCErrMsg Error!!" );
632                        for( int i=0; i<rtnval3.length; i++ ) {
633                                final DBErrMsg er = (DBErrMsg)rtnval3[i];
634                                if( er == null ) { break; }
635                                errMessage.addMessage( er.getErrMsg() );
636                        }
637                }
638                return resultSet;
639        }
640
641        /**
642         * PrintWriter を取得します。
643         *
644         * ここでは、一般的なファイル出力を考慮した PrintWriter を作成します。
645         *
646         * @og.rev 3.7.1.1 (2005/05/23) フォルダがない場合は、複数階層分のフォルダを自動で作成します。
647         * @og.rev 3.8.0.0 (2005/06/07) FileUtil#getPrintWriter を利用。
648         * @og.rev 5.6.1.0 (2013/02/01) 3.7.1.1のコメントに入っているが対応されていないのでフォルダ作成追加
649         *
650         * @return       出力用PrintWriterオブジェクト
651         * @og.rtnNotNull
652         */
653        private PrintWriter getPrintWriter() {
654                if( filename == null ) {
655                        final String errMsg = "ファイル名がセットされていません。";
656                        throw new HybsSystemException( errMsg );
657                }
658                final String directory = HybsSystem.url2dir( fileURL );
659
660                // 5.6.1.0 (2013/02/01) 
661                final File dir = new File(directory);
662                if( ! dir.exists() && ! dir.mkdirs() ) {
663                        final String errMsg = "ディレクトリの作成に失敗しました。[" + directory + "]";
664                        throw new HybsSystemException( errMsg );
665                }
666
667                // ※ 注意 StringUtil.urlAppend を組み込んでいる意図が不明。一旦削除していますが、注意
668                // 3.8.0.0 (2005/06/07) FileUtil#getPrintWriter を利用。
669        //      out = FileUtil.getPrintWriter( StringUtil.urlAppend( directory,filename ),fileAppend,encode);
670
671                // 処理を簡素化します。
672                return FileUtil.getPrintWriter( new File( directory,filename ),encode,fileAppend );
673        }
674
675        /**
676         * 名称配列を元に、リクエスト情報のデータを取得します。
677         *
678         * @og.rev 3.6.1.0 (2005/01/05) PL/SQLコール(JDBCErrMsg 形式)への対応
679         *
680         * @param       nameArray       キーとなる名称の配列(可変長引数)
681         *
682         * @return      そのリクエスト情報
683         * @og.rtnNotNull
684         */
685        private String[] getRequest( final String... nameArray ) {
686                String[] rtn = new String[nameArray.length];
687
688                for( int i=0; i<rtn.length; i++ ) {
689                        rtn[i] = getRequestValue( nameArray[i] );
690                }
691
692                return rtn;
693        }
694
695        /**
696         * 【TAG】(通常は使いません)検索時のDB接続IDを指定します(初期値:DEFAULT)。
697         *
698         * @og.tag
699         *   検索時のDB接続IDを指定します。初期値は、DEFAULT です。
700         *
701         * @param       id DB接続ID
702         */
703        public void setDbid( final String id ) {
704                dbid = nval( getRequestParameter( id ),dbid );
705        }
706
707        /**
708         * 【TAG】可変長ファイルを作成するときの項目区切り文字(セパレータ)をセットします(初期値:TAB_SEPARATOR)。
709         *
710         * @og.tag 可変長ファイルを作成するときの項目区切り文字をセットします。
711         * (初期値:ローカル定義のTAB_SEPARATOR)。
712         *
713         * @param   sep セパレータ
714         * @see         #TAB_SEPARATOR
715         */
716        public void setSeparator( final String sep ) {
717                separator = nval( getRequestParameter( sep ),TAB_SEPARATOR );
718        }
719
720        /**
721         * 【TAG】保存先ディレクトリ名を指定します
722         *              (初期値:FILE_URL[={@og.value SystemData#FILE_URL}])。
723         *
724         * @og.tag
725         * この属性で指定されるディレクトリに、ファイルをセーブします。
726         * 指定方法は、通常の fileURL 属性と同様に、先頭が、'/' (UNIX) または、2文字目が、
727         * ":" (Windows)の場合は、指定のURLそのままのディレクトリに、そうでない場合は、
728         * fileURL = "{&#064;USER.ID}" と指定すると、FILE_URL 属性で指定のフォルダの下に、
729         * さらに、各個人ID別のフォルダを作成して、そこにセーブします。
730         * (初期値:システム定数のFILE_URL[={@og.value SystemData#FILE_URL}])。
731         *
732         * @og.rev 3.5.4.3 (2004/01/05) 内部処理を、makeFileURL に移動。
733         * @og.rev 4.0.0.0 (2005/01/31) StringUtil.urlAppend メソッドの利用
734         * @og.rev 4.0.0.0 (2007/11/20) 指定されたディレクトリ名の最後が"\"or"/"で終わっていない場合に、"/"を付加する。
735         * @og.rev 6.4.2.1 (2016/02/05) URLの最後に、"/" を追加する処理を廃止。
736         *
737         * @param       url 保存先ディレクトリ名
738         * @see         org.opengion.hayabusa.common.SystemData#FILE_URL
739         */
740        public void setFileURL( final String url ) {
741                final String furl = nval( getRequestParameter( url ),null );
742                if( furl != null ) {
743                        fileURL = StringUtil.urlAppend( fileURL,furl );
744                }
745        }
746
747        /**
748         * 【TAG】ファイルを作成するときのファイル名をセットします(初期値:システムパラメータのFILE_FILENAME)。
749         *
750         * @og.tag ファイルを作成するときのファイル名をセットします。
751         *
752         * @param   fname ファイル名
753         */
754        public void setFilename( final String fname ) {
755                filename = nval( getRequestParameter( fname ),filename );
756        }
757
758        /**
759         * 【TAG】ファイルを作成するときのファイルエンコーディング名をセットします
760         *              (初期値:FILE_ENCODE[={@og.value SystemData#FILE_ENCODE}])。
761         *
762         * @og.tag
763         * "DEFAULT","JISAutoDetect" ,"JIS", "EUC_JP", "MS932", "SJIS" , "Windows-31J" , "Shift_JIS"
764         * (初期値:システム定数のFILE_ENCODE[={@og.value SystemData#FILE_ENCODE}])。
765         *
766         * @og.rev 2.2.0.0 (2002/12/17) 中国語(国際化)対応 エンコードの取得方法変更
767         * @og.rev 3.1.3.0 (2003/04/10) FILE_ENCODE から、エンコード情報を取得する。
768         *
769         * @param   enc ファイルエンコーディング名
770         * @see     <a href="http://www.iana.org/assignments/character-sets">IANA Charset Registry</a>
771         * @see         org.opengion.hayabusa.common.SystemData#FILE_ENCODE
772         */
773        public void setEncode( final String enc ) {
774                encode = nval( getRequestParameter( enc ),encode );
775        }
776
777        /**
778         * 【TAG】ヘッダーを書き込むかどうか[true/false]を指定します(初期値:true)。
779         *
780         * @og.tag
781         *  #Name ・・・・ ヘッダーの書き込みを指定します。
782         * 通常は、書き込み(true)にしておき、使用側でコメントと解釈するように
783         * 処理を行うべきです。コメントのため、append モードで途中に現れても
784         * 無視できます。また、エンジン標準でデータを取り込む場合に、データの配置が
785         * 変更されても取り込みプログラムはそのまま使用できます。
786         * 初期値は、true(書き込む)です。
787         *
788         * @param   flag ヘッダー有無 [true:書き込む/false:書き込まない]
789         */
790        public void setUseHeader( final String flag ) {
791                useHeader = nval( getRequestParameter( flag ),useHeader );
792        }
793
794        /**
795         * 【TAG】データをダブルクオートで囲うかどうか指定します(初期値:false)。
796         *
797         * @og.tag
798         * データを出力する場合、ダブルクオートで囲うかどうか指定します。
799         * 主に、区切り文字(separator)を、タブではなく、カンマを使う場合に、使用します。
800         * なお、ヘッダー部は、この指定に関わらず、ダブルクオートで囲いません。
801         * 初期値は、false(囲わない)です。
802         *
803         * @og.rev 6.0.3.0 (2014/11/13) 新規追加
804         *
805         * @param   flag ダブルクオート使用 [true:書き込む/false:書き込まない]
806         */
807        public void setUseQuote( final String flag ) {
808                useQuote = nval( getRequestParameter( flag ),useQuote );
809        }
810
811        /**
812         * 【TAG】データ中にダブルクオート文字が含まれる場合、エスケープするかどうか指定します(初期値:true)。
813         *
814         * @og.tag
815         * データ中にダブルクオート文字が含まれる場合、エスケープするかどうか指定します。
816         * ここでいうエスケープとは、ダブルクオート文字を重ねる処理を指します。
817         * 初期値は、互換性の関係で、true(処理する)です。
818         *
819         * @og.rev 6.0.3.0 (2014/11/13) 新規追加
820         *
821         * @param   flag ダブルクオートエスケープ有無 [true:する/false:しない]
822         */
823        public void setUseQuoteEscape( final String flag ) {
824                useQuoteEscape = nval( getRequestParameter( flag ),useQuoteEscape );
825        }
826
827        /**
828         * 【TAG】データ中に改行コードが含まれる場合、ダブルクオートで囲うかどうか指定します(初期値:true)。
829         *
830         * @og.tag
831         * データ中に改行コードが含まれたテキストの場合、EXCELで開くと、改行されてしまう。
832         * その場合、ダブルクオートで囲うと、セルに設定してくれます。
833         * この処理は、useQuote="true" にすると、無条件に、データは囲われます。
834         * 初期値は、互換性の関係で、true(処理する)です。
835         *
836         * @og.rev 6.0.3.0 (2014/11/13) 新規追加
837         *
838         * @param   flag 改行コード処理 [true:する/false:しない]
839         * @see         #setUseQuote( String )
840         */
841        public void setUseReturnQuote( final String flag ) {
842                useReturnQuote = nval( getRequestParameter( flag ),useReturnQuote );
843        }
844
845        /**
846         * 【TAG】一文字単位で置換する置換元文字を指定します(初期値:null 置換なし)。
847         *
848         * @og.tag
849         * データ出力時に、禁則文字を、置き換える元の文字を指定します。
850         * ここでは、一文字単位で、置換しますので、禁則文字は、連続の文字列の
851         * 形で、指定します。
852         * なお、ヘッダー部は、この指定に関わらず、ダブルクオートで囲いません。
853         * 初期値は、null の場合は、何も変換しません。
854         * 文字数は、replaceTo と同じでなければなりません。
855         *
856         * @og.rev 6.0.3.0 (2014/11/13) 新規追加
857         * @og.rev 6.2.2.0 (2015/03/27) \n,\r,\t をサポートします。
858         *
859         * @param   str 置換元文字
860         */
861        public void setReplaceFrom( final String str ) {
862                replaceFrom = changeRNT( nval( getRequestParameter( str ),replaceFrom ) );
863        }
864
865        /**
866         * 【TAG】一文字単位で置換する置換先文字を指定します。
867         *
868         * @og.tag
869         * データ出力時に、禁則文字を、置き換える先の文字を指定します。
870         * ここでは、一文字単位で、置換しますので、禁則文字は、連続の文字列の
871         * 形で、指定します。(例えば、全角文字にするとか)
872         * 初期値は、null の場合は、何も変換しません。
873         * 文字数は、replaceFrom と同じでなければなりません。
874         *
875         * @og.rev 6.0.3.0 (2014/11/13) 新規追加
876         * @og.rev 6.2.2.0 (2015/03/27) \n,\r,\t をサポートします。
877         *
878         * @param   str 置換先文字
879         */
880        public void setReplaceTo( final String str ) {
881                replaceTo = changeRNT( nval( getRequestParameter( str ),replaceTo ) );
882        }
883
884        /**
885         * replaceFrom,replaceTo で、\n,\r,\t をサポートします。
886         *
887         * データ置換で、改行、復帰、タブを、指定する場合、2文字必要です。
888         * ここでは、\n,\r,\t が指定された場合、キャラクタコードに置き換えます。
889         *
890         * @og.rev 6.2.2.0 (2015/03/27) \n,\r,\t をサポートします。
891         *
892         * @param       str 置換先文字
893         * @return      置換先文字
894         */
895        private String changeRNT( final String str ) {
896                String rtn = str ;
897                if( rtn != null && !rtn.isEmpty() ) {
898                        final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE );
899                        for( int i=0; i<rtn.length(); i++ ) {
900                                char ch = rtn.charAt(i) ;
901                                if( ch == '\\' ) {
902                                        final char ch2 = rtn.charAt(++i) ;              // ¥ の次の文字(n,r,tのみサポート)
903                                        switch( ch2 ) {
904                                                case 'n' : ch = '\n'; break;
905                                                case 'r' : ch = '\r'; break;
906                                                case 't' : ch = '\t'; break;
907                                                default  : 
908                                                        final String errMsg = getClass().getName()
909                                                                                         + "の置換文字列で、「\\" + ch2 + "」は、サポートされていません。";
910                                                        System.err.println( errMsg );
911                                                        break;
912                                        }
913                                }
914                                buf.append( ch );
915                        }
916                        rtn = buf.toString();
917                }
918                return rtn ;
919        }
920
921        /**
922         * 【TAG】追加モードで書き込むかどうか[true/false]を指定します(初期値:false[新規モード])。
923         *
924         * @og.tag
925         * ファイルを書き込む場合、追加モードで書き込むかどうかをセットします。
926         * 新規モード(true)の場合、既存のファイルが存在し、かつ書き込み許可があれば、
927         * 上書きで新規に作成します。
928         * 初期値は、false(新規モード)です。
929         *
930         * @param   flag 追加モード [true:追加モード/false:新規モード]
931         */
932        public void setFileAppend( final String flag ) {
933                fileAppend = nval( getRequestParameter( flag ),fileAppend );
934        }
935
936        /**
937         * 【TAG】結果をファイルに出力するときに、ZIPで圧縮するかどうか[true/false]を指定します(初期値:false)。
938         *
939         * @og.tag
940         * 大量に抜き出す場合、そのまま、サーバーから取り出すだけでも大変です。
941         * zip 属性を、true にすると、GZIP で圧縮したファイルを作成します。
942         * 初期値は、false(圧縮しない)です。
943         *
944         * @param  flag ZIP圧縮 [true:する/それ以外:しない]
945         * @see    #setZipFilename( String )
946         */
947        public void setZip( final String flag ) {
948                zip = nval( getRequestParameter( flag ),zip );
949        }
950
951        /**
952         * 【TAG】ZIPファイルを作成するときのZIPファイル名をセットします(初期値:filename + ".zip")。
953         *
954         * @og.tag
955         * zip 属性に、true を指定した場合に、ZIPファイル化します。その場合のファイル名を指定します。
956         * なにも指定しない場合は、filename + ".zip" になります。
957         *
958         * @param   zipFile ZIPファイル名
959         * @see #setZip( String )
960         */
961        public void setZipFilename( final String zipFile ) {
962                zipFilename = nval( getRequestParameter( zipFile ),zipFilename );
963        }
964
965        /**
966         * 【TAG】検索結果を画面上に表示するメッセージリソースIDを指定します
967         *              (初期値:VIEW_DISPLAY_MSG[={@og.value SystemData#VIEW_DISPLAY_MSG}])。
968         *
969         * @og.tag
970         * ここでは、検索結果の件数や登録された件数をまず出力し、
971         * その次に、ここで指定したメッセージをリソースから取得して
972         * 表示します。
973         * 件数を表示させる場合は、displayMsg = "MSG0033"[ 件検索しました] をセットしてください。
974         * 表示させたくない場合は, displayMsg = "" をセットしてください。
975         * (初期値:システム定数のVIEW_DISPLAY_MSG[={@og.value SystemData#VIEW_DISPLAY_MSG}])。
976         *
977         * @param       id 結果表示メッセージID
978         */
979        public void setDisplayMsg( final String id ) {
980                final String ids = getRequestParameter( id );
981                if( ids != null ) { displayMsg = ids; }
982        }
983
984        /**
985         * 【TAG】検索結果がゼロ件の場合に表示するメッセージリソースIDを指定します(初期値:MSG0077[対象データはありませんでした])。
986         *
987         * @og.tag
988         * ここでは、検索結果がゼロ件の場合のみ、特別なメッセージを表示させます。
989         * 従来は、displayMsg と兼用で、『0 件検索しました』という表示でしたが、
990         * displayMsg の初期表示は、OFF になりましたので、ゼロ件の場合のみ別に表示させます。
991         * 表示させたくない場合は, notfoundMsg = "" をセットしてください。
992         * 初期値は、MSG0077[対象データはありませんでした]です。
993         *
994         * @param       id ゼロ件時表示メッセージID
995         */
996        public void setNotfoundMsg( final String id ) {
997                final String ids = getRequestParameter( id );
998                if( ids != null ) { notfoundMsg = ids; }
999        }
1000
1001        /**
1002         * 【TAG】(通常は使いません)データのフェッチサイズを指定します
1003         *              (初期値:DB_FETCH_SIZE[={@og.value org.opengion.fukurou.system.HybsConst#DB_FETCH_SIZE}])。
1004         *
1005         * @og.tag
1006         * より多くの行が必要なときに、データベースから取り出す必要がある行数に
1007         * ついてのヒントを JDBC ドライバに提供します。
1008         * 指定された行数は、この Statement を使って作成された結果セットにだけ影響します。
1009         * 指定された値が 0 の場合、ヒントは無視されます。
1010         * (初期値:システム定数のDB_FETCH_SIZE[={@og.value org.opengion.fukurou.system.HybsConst#DB_FETCH_SIZE}])。
1011         *
1012         * @param       size フェッチ行数
1013         */
1014        public void setFetchSize( final String size ) {
1015                fetchSize = nval( getRequestParameter( size ),fetchSize );
1016        }
1017
1018        /**
1019         * 【TAG】PL/SQLを利用する場合の引数にセットすべき データの名称をCSV形式で複数指定します。
1020         *
1021         * @og.tag
1022         * 複数ある場合は、CSV形式で渡します。
1023         * PL/SQL を使用しない場合は、無視されます。
1024         *
1025         * @og.rev 3.6.1.0 (2005/01/05) PL/SQLコール(JDBCErrMsg 形式)への対応
1026         *
1027         * @param       nm 引数の名称 (CSV形式)
1028         */
1029        public void setNames( final String nm ) {
1030                names = nval( getRequestParameter( nm ),names );
1031        }
1032
1033        /**
1034         * 【TAG】Query を発行する為のクラスID(JDBC,JDBCErrMsg)を指定します({@og.doc03Link queryType 初期値:JDBC})。
1035         *
1036         * @og.tag
1037         * ストアドプロシージャ等を実行する場合に、queryType="JDBCErrMsg" を
1038         * 指定する必要があります。(それ以外の指定は、初期値の JDBC になります。)
1039         * 初期値は、"JDBC" です。
1040         * {@og.doc03Link queryType Query_**** クラス}
1041         *
1042         * @og.rev 3.6.1.0 (2005/01/05) PL/SQLコール(JDBCErrMsg 形式)への対応
1043         *
1044         * @param       id Query発行クラスID
1045         */
1046        public void setQueryType( final String id ) {
1047                // 内部的には、JDBCErrMsg:false / それ以外:true で管理しています。
1048                queryType = ! "JDBCErrMsg".equalsIgnoreCase( getRequestParameter( id ) );
1049        }
1050
1051        /**
1052         * 【TAG】ファイル出力時に、行番号情報を、出力する/しない[true/false]を指定します(初期値:true)。
1053         *
1054         * @og.tag
1055         * 通常のフォーマットでは、各行の先頭に行番号を出力します。
1056         * これは、#NAME 属性を使用する場合には、必ず出力する必要があります。
1057         * (#NAME 属性は、読み取り時にあれば、自動的にカラムに割り当てられます。)
1058         * この、先頭の行番号が不要な場合(つまり、他のシステムへのデータ出力等)
1059         * の為に出力する場合に、false を設定することで、行番号列を出力しない
1060         * ようにできます。
1061         * 初期値は、true(出力する) です。
1062         * 
1063         * @og.rev 5.5.7.1 (2012/10/05) 新規追加
1064         * @param  flag 行番号出力 [true:する/それ以外:しない]
1065         */
1066        public void setUseNumber( final String flag ) {
1067                useNumber = nval( getRequestParameter( flag ),useNumber );
1068        }
1069
1070        /**
1071         * 【TAG】リクエスト情報の シングルクォート(') 存在チェックを実施するかどうか[true/false]を設定します
1072         *              (初期値:USE_SQL_INJECTION_CHECK[={@og.value SystemData#USE_SQL_INJECTION_CHECK}])。
1073         *
1074         * @og.tag
1075         * SQLインジェクション対策の一つとして、暫定的ではありますが、SQLのパラメータに
1076         * 渡す文字列にシングルクォート(') を許さない設定にすれば、ある程度は防止できます。
1077         * 数字タイプの引数には、 or 5=5 などのシングルクォートを使用しないコードを埋めても、
1078         * 数字チェックで検出可能です。文字タイプの場合は、必ず (')をはずして、
1079         * ' or 'A' like 'A のような形式になる為、(')チェックだけでも有効です。
1080         * (') が含まれていたエラーにする(true)/かノーチェックか(false)を指定します。
1081         * 初期値は、SystemData#USE_SQL_INJECTION_CHECK です。
1082         *
1083         * @og.rev 6.2.2.0 (2015/03/27) XSSチェック,クォートチェック をサポートします。
1084         *
1085         * @param   flag クォートチェック [true:する/それ以外:しない]
1086         */
1087        public void setQuotCheck( final String flag ) {
1088                quotCheck = nval( getRequestParameter( flag ),quotCheck );
1089        }
1090
1091        /**
1092         * 【TAG】リクエスト情報の HTMLTag開始/終了文字(&gt;&lt;) 存在チェックを実施するかどうか[true/false]を設定します
1093         *              (初期値:USE_XSS_CHECK[={@og.value SystemData#USE_XSS_CHECK}])。
1094         *
1095         * @og.tag
1096         * クロスサイトスクリプティング(XSS)対策の一環としてless/greater than signについてのチェックを行います。
1097         * (&gt;&lt;) が含まれていたエラーにする(true)/かノーチェックか(false)を指定します。
1098         * (初期値:システム定数のUSE_XSS_CHECK[={@og.value SystemData#USE_XSS_CHECK}])
1099         *
1100         * @og.rev 6.2.2.0 (2015/03/27) XSSチェック,クォートチェック をサポートします。
1101         *
1102         * @param       flag    XSSチェック [true:する/false:しない]
1103         * @see         org.opengion.hayabusa.common.SystemData#USE_XSS_CHECK
1104         */
1105        public void setXssCheck( final String flag ) {
1106                xssCheck = nval( getRequestParameter( flag ),xssCheck );
1107        }
1108
1109        /**
1110         * 【TAG】処理時間を表示する TimeView を表示するかどうか[true:する/false:しない]を指定します
1111         *              (初期値:VIEW_USE_TIMEBAR[={@og.value SystemData#VIEW_USE_TIMEBAR}])。
1112         *
1113         * @og.tag
1114         * true に設定すると、処理時間を表示するバーイメージが表示されます。
1115         * これは、DB検索、APサーバー処理、画面表示の各処理時間をバーイメージで
1116         * 表示させる機能です。処理時間の目安になります。
1117         * (初期値:VIEW_USE_TIMEBAR[={@og.value SystemData#VIEW_USE_TIMEBAR}])。
1118         *
1119         * @og.rev 6.3.6.0 (2015/08/16) useTimeView の初期値を、VIEW_USE_TIMEBAR にする。
1120         *
1121         * @param       flag    処理時間を表示 [true:する/false:しない]
1122         */
1123        public void setUseTimeView( final String flag ) {
1124                useTimeView = nval( getRequestParameter( flag ),useTimeView );
1125        }
1126
1127        /**
1128         * 【TAG】エラーメッセージにSLABELを利用するかどうか[true/false]を指定します(初期値:false)。
1129         *
1130         * @og.tag
1131         * 通常のエラーメッセージは、ラベル(長)が使われますが、これをラベル(短)を使いたい場合に、true にセットします。
1132         * ここでのラベル(短)は、タグ修飾なしの、ラベル(短)です。
1133         * 標準はfalse:利用しない=ラベル(長)です。
1134         * true/false以外を指定した場合はfalse扱いとします。
1135         *
1136         * ラベルリソースの概要説明があれば表示しますが、useSLabel="true" 時は、概要説明を表示しません。
1137         *
1138         * @og.rev 7.0.7.0 (2019/12/13) 新規追加
1139         *
1140         * @param prm SLABEL利用 [true:利用する/false:利用しない]
1141         */
1142        public void setUseSLabel( final String prm ) {
1143                useSLabel = nval( getRequestParameter( prm ),useSLabel );
1144        }
1145
1146        /**
1147         * 【TAG】valueタグのaction=MAPOBJ を使用したラベル変換を行う場合の、MAPOBJキーを指定します。
1148         *
1149         * @og.tag
1150         * 
1151         * DirectWriteTableTagでは、SQL文から直接ファイルを作成するため、headLabel はresource から
1152         * 取得します。
1153         * 通常の DBTableModel を作成する場合には、ColumnEditorTag でuseLabelMapとしてSQL文でキーとラベルの
1154         * Mapを作成してラベルの書き換えが行えますが、それと同等の事を行うためには、一旦、valueタグで、
1155         * command="SQL" action=MAPOBJ で、キーとラベルのMapを作成して、ラベルとして使用します。
1156         * なお、Mapオブジェクトは、scope="request" でのみやり取り可能です。
1157         *
1158         * @og.rev 7.0.7.1 (2019/12/24) mapObjKey 属性を追加。
1159         *
1160         * @param key valueタグで作成したMAPOBJを取り出すときのキー
1161         */
1162        public void setMapObjKey( final String key ) {
1163                mapObjKey = nval( getRequestParameter( key ),mapObjKey );
1164        }
1165
1166        /**
1167         * このオブジェクトの文字列表現を返します。
1168         * 基本的にデバッグ目的に使用します。
1169         *
1170         * @return このクラスの文字列表現
1171         * @og.rtnNotNull
1172         */
1173        @Override
1174        public String toString() {
1175                return ToString.title( this.getClass().getName() )
1176                                .println( "VERSION"             ,VERSION        )
1177                                .println( "dbid"                ,dbid           )
1178                                .println( "separator"   ,separator      )
1179                                .println( "useHeader"   ,useHeader      )
1180                                .println( "fileURL"             ,fileURL        )
1181                                .println( "filename"    ,filename       )
1182                                .println( "sql"                 ,sql            )
1183                                .println( "encode"              ,encode         )
1184                                .println( "fileAppend"  ,fileAppend     )
1185                                .println( "zip"                 ,zip            )
1186                                .println( "zipFilename" ,zipFilename)
1187                                .println( "displayMsg"  ,displayMsg     )
1188                                .println( "fetchSize"   ,fetchSize      )
1189                                .println( "queryType"   ,queryType      )
1190                                .println( "names"               ,names          )
1191                                .println( "errCode"             ,errCode        )
1192                                .println( "Other..."    ,getAttributes().getAttribute() )
1193                                .fixForm().toString() ;
1194        }
1195}