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