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 *       caseKey            【TAG】このタグ自体を利用するかどうかの条件キーを指定します(初期値:null)
099 *       caseVal            【TAG】このタグ自体を利用するかどうかの条件値を指定します(初期値:null)
100 *       caseNN             【TAG】指定の値が、null/ゼロ文字列 でない場合(Not Null=NN)は、このタグは使用されます(初期値:判定しない)
101 *       caseNull           【TAG】指定の値が、null/ゼロ文字列 の場合は、このタグは使用されます(初期値:判定しない)
102 *       caseIf             【TAG】指定の値が、true/TRUE文字列の場合は、このタグは使用されます(初期値:判定しない)
103 *       debug              【TAG】デバッグ情報を出力するかどうか[true/false]を指定します(初期値:false)
104 *   >   ... Body ...
105 *   </og:directWriteTable>
106 *
107 * ●使用例
108 *     <og:directWriteTable
109 *         dbid        = "ORCL"               接続データベースID(初期値:DEFAULT)
110 *         separator   = ","                  ファイルの区切り文字(初期値:タブ)
111 *         fileURL     = "{@USER.ID}"    保存先ディレクトリ名
112 *         filename    = "{@filename}"   保存ファイル名
113 *         encode      = "UnicodeLittle"      保存ファイルエンコード名
114 *         useHeader   = "true"               保存ファイルにヘッダーを出力するかどうか
115 *         useQuote    = "false"              データをダブルクオートで囲うかどうか
116 *         useQuoteEscape = "true"            ダブルクオート文字が含まれる場合、エスケープするかどうか
117 *         useReturnQuote = "true"            改行コードが含まれる場合、ダブルクオートで囲うかどうか
118 *         replaceFrom = "',"*%|"   置換元文字を指定。一文字単位で置換します。
119 *         replaceTo   = "’,”*%|"       置換先文字を指定。一文字単位で置換します。
120 *         zip         = "true"               ZIPファイルに圧縮するかどうか
121 *         zipFilename = "Sample.zip"         ZIPファイルのファイル名
122 *         fileAppend  = "true"               ファイルを追加モードで登録するかどうか
123 *         displayMsg  = "MSG0033"            実行後の表示メッセージ
124 *         fetchSize   = "200"                DB検索する場合のフェッチするサイズ
125 *     >
126 *         SELECT * FROM ZYXX 
127 *     </og:directWriteTable >
128 *
129 *     <og:directWriteTable
130 *         fileURL     = "{@USER.ID}"    保存先ディレクトリ名
131 *         filename    = "{@filename}"   保存ファイル名
132 *         names       = "AAA,BBB,CCC,・・・"    指定のキーに対応するリクエスト値を ARG_ARRAY にセットします。
133 *         queryType   = "JDBCErrMsg"         JDBCErrMsg 形式のPL/SQL をコールします。
134 *     >
135 *        { call PL/SQL(?,?,?,? ) } 
136 *     </og:directWriteTable >
137 *
138 * @og.rev 3.5.6.0 (2004/06/18) 新規作成
139 * @og.rev 3.6.1.0 (2005/01/05) PL/SQLコール(JDBCErrMsg 形式)の実行を追加
140 * @og.group ファイル出力
141 *
142 * @version  4.0
143 * @author   Kazuhiko Hasegawa
144 * @since    JDK5.0,
145 */
146public class DirectWriteTableTag extends CommonTagSupport {
147        /** このプログラムのVERSION文字列を設定します。   {@value} */
148        private static final String VERSION = "6.9.3.0 (2018/03/26)" ;
149        private static final long serialVersionUID = 693020180326L ;
150
151        private static final String TAB_SEPARATOR       = "\t" ;
152        private static final String ERR_MSG_ID          = HybsSystem.ERR_MSG_KEY;               // 6.4.1.1 (2016/01/16) errMsgId → ERR_MSG_ID  refactoring
153
154        private final int DB_MAX_QUERY_TIMEOUT          = HybsSystem.sysInt( "DB_MAX_QUERY_TIMEOUT" ) ;
155        private static final String ARG_ARRAY           = "ARG_ARRAY" ;
156        private static final String ERR_MSG                     = "ERR_MSG" ;
157        private static final String ERR_MSG_ARRAY       = "ERR_MSG_ARRAY" ;
158
159//      /** 6.9.3.0 (2018/03/26) データ検索時のフェッチサイズ  */
160//      private static final int DB_FETCH_SIZE          = HybsSystem.sysInt( "DB_FETCH_SIZE" ) ;
161
162        // 4.0.0.0 (2007/10/10) dbid の初期値を、"DEFAULT" から null に変更
163        private String  dbid            ;
164        private String  separator       = TAB_SEPARATOR;        // 項目区切り文字
165        private boolean useHeader       = true;                         // ヘッダーの使用可否
166        private boolean useQuote        ;                                       // 6.0.3.0 (2014/11/13) ダブルクオートで囲うかどうか
167        private boolean useQuoteEscape  = true;                 // 6.0.3.0 (2014/11/13) データ中にダブルクオート文字が含まれる場合、エスケープするかどうか
168        private boolean useReturnQuote  = true;                 // 6.0.3.0 (2014/11/13) データ中に改行コードが含まれる場合、ダブルクオートで囲うかどうか
169        private String  fileURL         = HybsSystem.sys( "FILE_URL" );
170        private String  filename        = HybsSystem.sys( "FILE_FILENAME" );    // ファイル名
171        private String  sql                     ;
172        private String  encode          = HybsSystem.sys( "FILE_ENCODE"   );    // ファイルエンコーディング  "DEFAULT","JISAutoDetect" ,"JIS", "EUC_JP", "MS932", "SJIS" , "Windows-31J" , "Shift_JIS"
173        private boolean fileAppend      ;                                       // ファイルをAPPENDモードで出力するか
174        private boolean zip                     ;                                       // ファイルをZIPするか
175        private String  zipFilename     ;                                       // ZIPファイル名
176        private String  displayMsg      = HybsSystem.sys( "VIEW_DISPLAY_MSG" );
177        private String  notfoundMsg     = "MSG0077";            // 対象データはありませんでした。
178        private long    dyStart         ;                                       // 実行時間測定用のDIV要素を出力します。
179        private boolean useTimeView     = HybsSystem.sysBool( "VIEW_USE_TIMEBAR" );             // 6.3.6.0 (2015/08/16)
180        private int             fetchSize       = DB_FETCH_SIZE ;       // フェッチする行数(初期値:1001)   6.9.3.0 (2018/03/26) 初期値を100→HybsConst.DB_FETCH_SIZE に変更
181        private boolean useNumber       = true;                         // 5.5.7.1(2012/10/05) 行番号出力
182
183        private String  replaceFrom     ;                                       // 6.0.3.0 (2014/11/13) 置換元文字を指定
184        private String  replaceTo       ;                                       // 6.0.3.0 (2014/11/13) 置換先文字を指定
185
186        private boolean quotCheck       = HybsSystem.sysBool( "USE_SQL_INJECTION_CHECK" );      // 6.2.2.0 (2015/03/27)
187        private boolean xssCheck        = HybsSystem.sysBool( "USE_XSS_CHECK" );                        // 6.2.2.0 (2015/03/27)
188
189        // 3.6.1.0 (2005/01/05) PL/SQLコール(JDBCErrMsg 形式)への対応
190        private boolean queryType       = true;                         // ノーマルは、true/ JDBCErrMsg の時は、false
191        private String  names           ;                                       // 指定のリクエスト変数を、ARG_ARRAY にセットします。
192        private int             errCode         = ErrorMessage.OK;
193        private transient ErrorMessage errMessage       ;
194
195        /**
196         * デフォルトコンストラクター
197         *
198         * @og.rev 6.4.2.0 (2016/01/29) PMD refactoring. Each class should declare at least one constructor.
199         */
200        public DirectWriteTableTag() { super(); }               // これも、自動的に呼ばれるが、空のメソッドを作成すると警告されるので、明示的にしておきます。
201
202        /**
203         * Taglibの開始タグが見つかったときに処理する doStartTag() を オーバーライドします。
204         *
205         * @og.rev 6.0.3.0 (2014/11/13) 置換元文字,置換先文字のチェック
206         * @og.rev 6.3.4.0 (2015/08/01) caseKey,caseVal,caseNN,caseNull,caseIf 属性対応
207         * @og.rev 6.4.8.1 (2016/07/02) xssCheckを、doStartTag に移動
208         *
209         * @return      後続処理の指示( EVAL_BODY_BUFFERED )
210         */
211        @Override
212        public int doStartTag() {
213                // 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
214                // 反転注意、if ロジック統合
215                if( useTag() ) {
216                        dyStart = System.currentTimeMillis();           // 時間測定用
217
218                        useXssCheck( xssCheck );                        // 6.4.8.1 (2016/07/02)
219
220                        // 6.0.3.0 (2014/11/13) 置換元文字,置換先文字を指定
221                        if( ( replaceFrom != null || replaceTo != null ) &&
222                                ( replaceFrom == null || replaceTo == null || replaceFrom.length() != replaceTo.length() ) ) {
223                                        final String errMsg = "置換元文字と置換先文字の文字数が異なります。" + CR
224                                                                + " replaceFrom=[" + replaceFrom + "] , replaceTo=[" + replaceTo + "]"
225                                                                + CR ;
226                                        throw new HybsSystemException( errMsg );
227                        }
228
229                        return EVAL_BODY_BUFFERED ;     // Body を評価する。( extends BodyTagSupport 時)
230                }
231                else {
232                        return SKIP_BODY;
233                }
234
235        }
236
237        /**
238         * Taglibのタグ本体を処理する doAfterBody() を オーバーライドします。
239         *
240         * @og.rev 3.8.6.3 (2006/11/30) SQL 文の前後のスペースを取り除きます。
241         * @og.rev 6.2.2.0 (2015/03/27) XSSチェック,クォートチェック をサポートします。
242         * @og.rev 6.4.8.1 (2016/07/02) xssCheckを、doStartTag に移動
243         *
244         * @return      後続処理の指示(SKIP_BODY)
245         */
246        @Override
247        public int doAfterBody() {
248                // 6.2.2.0 (2015/03/27) XSSチェック,クォートチェック をサポートします。
249                useQuotCheck( quotCheck );
250
251                sql = getBodyString();
252                if( sql == null || sql.isEmpty() ) {
253                        final String errMsg = "BODY 部の検索用 Select文は、必須です。";
254                        throw new HybsSystemException( errMsg );
255                }
256                sql = sql.trim();
257                return SKIP_BODY ;                              // Body を評価しない
258        }
259
260        /**
261         * Taglibの終了タグが見つかったときに処理する doEndTag() を オーバーライドします。
262         *
263         * @og.rev 3.6.1.0 (2005/01/05) PL/SQLコール(JDBCErrMsg 形式)への対応
264         * @og.rev 4.0.0.0 (2007/10/18) メッセージリソース統合( getResource().getMessage ⇒ getResource().getLabel )
265         * @og.rev 6.0.4.0 (2014/11/28) Zip処理を、ZipOutputStream → ZipArchiveOutputStream に変更
266         * @og.rev 6.3.4.0 (2015/08/01) caseKey,caseVal,caseNN,caseNull,caseIf 属性対応
267         * @og.rev 6.3.8.0 (2015/09/11) FileUtil#getPrintWriter( OutputStream,String ) を使用。
268         *
269         * @return      後続処理の指示
270         */
271        @Override
272        public int doEndTag() {
273                debugPrint();           // 4.0.0 (2005/02/28)
274                if( !useTag() ) { return EVAL_PAGE ; }  // 6.3.4.0 (2015/08/01)
275
276                PrintWriter pw = null;
277                final int executeCount;
278                try {
279                        if( zip ) {
280                                final String directory = HybsSystem.url2dir( fileURL );
281
282                                if( zipFilename == null ) { zipFilename = filename + ".zip"; }
283                                ZipArchiveOutputStream gzip = null;                     // 6.0.4.0 (2014/11/28)
284                                try {
285                                        // 6.0.4.0 (2014/11/28) Zip処理を、ZipOutputStream → ZipArchiveOutputStream に変更
286                                        gzip = new ZipArchiveOutputStream(
287                                                                new BufferedOutputStream (
288                                                                        new FileOutputStream (
289                                                                                new File( directory,zipFilename ))));   // 6.0.4.0 (2014/11/28)
290                                        gzip.setEncoding( "Windows-31J" );
291                                        gzip.putArchiveEntry( new ZipArchiveEntry( filename ) );
292                                        // 6.0.4.0 (2014/11/28) ファイルのencode を指定できるようにする。
293                                        // 6.3.8.0 (2015/09/11) FileUtil#getPrintWriter( OutputStream,String ) を使用。
294                                        pw = FileUtil.getPrintWriter( gzip,encode );            // 6.3.8.0 (2015/09/11)
295                                        executeCount = create( pw ) ;
296
297                                        pw.flush();
298                                        gzip.closeArchiveEntry();                               // 6.0.4.0 (2014/11/28)
299                                        gzip.finish() ;
300                                }
301                                finally {
302                                        Closer.ioClose( gzip );         // 4.0.0 (2006/01/31) close 処理時の IOException を無視
303                                }
304                        }
305                        else {
306                                pw = getPrintWriter();
307                                executeCount = create( pw );
308                        }
309                } catch( final IOException ex ) {
310                        final String errMsg = "Error in DirectWriteTableTag: " + toString();
311                        throw new HybsSystemException( errMsg,ex );             // 3.5.5.4 (2004/04/15) 引数の並び順変更
312                } finally {
313                        Closer.ioClose( pw );           // 4.0.0 (2006/01/31) close 処理時の IOException を無視
314                }
315
316                // 3.6.1.0 (2005/01/05) 検索結果の件数を、"DB.COUNT" キーでリクエストにセットする。
317                setRequestAttribute( "DB.COUNT"   , String.valueOf( executeCount ) );
318                setRequestAttribute( "DB.ERR_CODE", String.valueOf( errCode ) );
319
320                final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE );
321
322                // 実行件数の表示
323                if( executeCount > 0 && displayMsg != null && displayMsg.length() > 0 ) {
324                        buf.append( executeCount )
325                                .append( getResource().getLabel( displayMsg ) )
326                                .append( BR );
327                }
328                else if( executeCount == 0 && notfoundMsg != null && notfoundMsg.length() > 0 ) {
329                        buf.append( getResource().getLabel( notfoundMsg ) )
330                                .append( BR );
331                }
332
333                // 3.6.1.0 (2005/01/05) TaglibUtil.makeHTMLErrorTable メソッドを利用
334                final String err = TaglibUtil.makeHTMLErrorTable( errMessage,getResource() );
335                if( err != null && err.length() > 0 ) {
336                        buf.append( err );
337                        setSessionAttribute( ERR_MSG_ID,errMessage );
338                }
339                else {
340                        removeSessionAttribute( ERR_MSG_ID );
341                }
342
343                jspPrint( buf.toString() );
344
345                // 3.6.1.0 (2005/01/05) 警告時に停止していましたが、継続処理させます。
346                int rtnCode = EVAL_PAGE;
347                if( errCode >= ErrorMessage.NG )  {     // 異常
348                        rtnCode = SKIP_PAGE;
349                }
350
351                // 4.0.0 (2005/01/31) セキュリティチェック(データアクセス件数登録)
352                final long dyTime = System.currentTimeMillis()-dyStart;
353                final GUIInfo guiInfo = (GUIInfo)getSessionAttribute( HybsSystem.GUIINFO_KEY );
354                if( guiInfo != null ) { guiInfo.addReadCount( executeCount,dyTime,sql ); }
355
356                if( useTimeView ) {             // 6.3.6.0 (2015/08/16)
357                        // 時間測定用の DIV 要素を出力
358                        jspPrint( "<div id=\"queryTime\" value=\"" + (dyTime) + "\"></div>" );  // 3.5.6.3 (2004/07/12)
359                }
360                return rtnCode ;
361        }
362
363        /**
364         * タグリブオブジェクトをリリースします。
365         * キャッシュされて再利用されるので、フィールドの初期設定を行います。
366         *
367         * @og.rev 3.6.1.0 (2005/01/05) PL/SQLコール(JDBCErrMsg 形式)への対応
368         * @og.rev 4.0.0.0 (2007/10/10) dbid の初期値を、"DEFAULT" から null に変更
369         * @og.rev 5.5.7.1 (2012/10/05) useNumber追加
370         * @og.rev 6.0.3.0 (2014/11/13) useHeader,useQuote,useQuoteEscape,useReturnQuote,replaceFrom,replaceTo追加
371         * @og.rev 6.2.2.0 (2015/03/27) XSSチェック,クォートチェック をサポートします。
372         * @og.rev 6.9.3.0 (2018/03/26) fetchSizeの初期値を100→HybsConst.DB_FETCH_SIZE に変更
373         */
374        @Override
375        protected void release2() {
376                super.release2();
377                separator       = TAB_SEPARATOR;        // 項目区切り文字
378                fileURL         = HybsSystem.sys( "FILE_URL" );
379                filename        = HybsSystem.sys( "FILE_FILENAME" );    // ファイル名
380                sql                     = null;
381                encode          = HybsSystem.sys( "FILE_ENCODE" );              // ファイルエンコーディング  "DEFAULT","JISAutoDetect" ,"JIS", "EUC_JP", "MS932", "SJIS" , "Windows-31J" , "Shift_JIS"
382                fileAppend      = false;                        // ファイルをAPPENDモードで出力するか
383                zip                     = false;                        // ファイルをZIPするか
384                zipFilename     = null;                         // ZIPファイル名
385                displayMsg      = HybsSystem.sys( "VIEW_DISPLAY_MSG" );
386                notfoundMsg     = "MSG0077";            // 対象データはありませんでした。
387                dbid            = null;
388                fetchSize       = DB_FETCH_SIZE ;       // フェッチする行数(初期値:0 参考にしない)               6.9.3.0 (2018/03/26) 初期値を100→→HybsConst.DB_FETCH_SIZE に変更
389                useTimeView     = HybsSystem.sysBool( "VIEW_USE_TIMEBAR" );     // 6.3.6.0 (2015/08/16)
390                queryType       = true;                         // ノーマルは、true/ JDBCErrMsg の時は、false
391                names           = null;                         // 指定のリクエスト変数を、ARG_ARRAY にセットします。
392                errCode         = ErrorMessage.OK;
393                errMessage      = null;
394                useNumber       = true;                         // 5.5.7.1 (2012/10/05)
395                useHeader       = true;                         // ヘッダーの使用可否  … 6.0.3.0 (2014/11/13) 追加
396                useQuote        = false;                        // 6.0.3.0 (2014/11/13) ダブルクオートで囲うかどうか
397                useQuoteEscape  = true;                 // 6.0.3.0 (2014/11/13) データ中にダブルクオート文字が含まれる場合、エスケープするかどうか
398                useReturnQuote  = true;                 // 6.0.3.0 (2014/11/13) データ中に改行コードが含まれる場合、ダブルクオートで囲うかどうか
399                replaceFrom     = null;                         // 6.0.3.0 (2014/11/13) 置換元文字を指定
400                replaceTo       = null;                         // 6.0.3.0 (2014/11/13) 置換先文字を指定
401                quotCheck       = HybsSystem.sysBool( "USE_SQL_INJECTION_CHECK" );      // 6.2.2.0 (2015/03/27)
402                xssCheck        = HybsSystem.sysBool( "USE_XSS_CHECK" );                        // 6.2.2.0 (2015/03/27)
403        }
404
405        /**
406         * 実オブジェクトを生成して,OutputStream に書き込みます。
407         *
408         * @og.rev 3.6.1.0 (2005/01/05) PL/SQLコール(JDBCErrMsg 形式)への対応
409         * @og.rev 3.8.6.0 (2006/09/29) ヘッダーにラベルを出力するように修正
410         * @og.rev 3.8.7.0 (2006/12/15) アクセスログ取得の為,ApplicationInfoオブジェクトを設定
411         * @og.rev 4.3.4.3 (2008/12/22) (Oracle11gDriver対応)PL/SQLコールの場合に、"クローズされた文です。"のエラーが発生する問題に対応
412         * @og.rev 5.1.9.0 (2010/08/01) Transaction 対応
413         * @og.rev 5.2.2.0 (2010/11/01) 改行を含む場合は、ダブルクオートを強制的に前後に追加する。
414         * @og.rev 5.2.2.0 (2010/11/01) ダブルクオートを含む場合は、その直前にダブルクオートを強制的に追加する。
415         * @og.rev 5.3.0.0 (2010/12/01) executeCall メソッドの引数見直し
416         * @og.rev 5.3.7.0 (2011/07/01) TransactionReal の引数変更
417         * @og.rev 5.5.7.1 (2012/10/05) useNumberの追加
418         * @og.rev 6.0.3.0 (2014/11/13) useQuote,useQuoteEscape,useReturnQuote,replaceFrom,replaceToの追加
419         * @og.rev 6.0.3.0 (2014/11/13) ヘッダーとラベルを、指定の separator で出力するように変更します。
420         * @og.rev 6.0.4.0 (2014/11/28) ResultSetValue を使用するように変更。
421         * @og.rev 6.2.0.0 (2015/02/27) データ出力の先頭カンマの判定処理変更
422         * @og.rev 6.3.6.1 (2015/08/28) Transaction でAutoCloseableを使用したtry-with-resources構築に対応。
423         *
424         * @param   outPW 出力先のPrintWriterオブジェクト
425         *
426         * @return      検索件数
427         */
428        private int create( final PrintWriter outPW )  {
429                final int executeCount;
430                Statement stmt = null;
431                CallableStatement callStmt = null; // 4.3.4.3 (2008/12/22)
432                ResultSet resultSet = null ;
433
434                // 6.3.6.1 (2015/08/28) Transaction でAutoCloseableを使用したtry-with-resources構築に対応。
435                try( final Transaction tran = getTransaction() ) {
436                        final Connection conn = tran.getConnection( dbid );                             // 5.1.9.0 (2010/08/01) Transaction 対応
437                        // 3.6.1.0 (2005/01/05)
438                        if( queryType ) {               // JDBC 通常の SELECT 文
439                                stmt = conn.createStatement();
440                                if( fetchSize > 0 ) { stmt.setFetchSize( fetchSize ); }
441                                resultSet = stmt.executeQuery( sql );
442                        }
443                        else {                                  // PL/SQL Call 文
444                                String[] values = null;
445                                if( names != null ) {
446                                        final String[] nameArray = StringUtil.csv2Array( names );
447                                        values = getRequest( nameArray );
448                                }
449                                callStmt  = conn.prepareCall( sql );
450                                resultSet = executeCall( conn,callStmt,values );                // 5.3.0.0 (2010/12/01)
451                        }
452                        if( resultSet == null ) { return 0; }
453
454                        // 6.0.4.0 (2014/11/28) ResultSetValue を使用するように変更。
455                        final ResultSetValue rsv = new ResultSetValue( resultSet );
456                        final int numberOfColumns =  rsv.getColumnCount();
457
458                        // ヘッダー部の出力
459                        if( useHeader && numberOfColumns > 0 ) {
460                                final StringBuilder headName  = new StringBuilder( BUFFER_MIDDLE );
461                                final StringBuilder headLabel = new StringBuilder( BUFFER_MIDDLE );
462                                if( useNumber ){                                        // 6.0.3.0 (2014/11/13) ヘッダー部の useNumber 対応漏れ
463                                        headName.append(  "#Name" );
464                                        headLabel.append( "#Label" );
465                                }
466                                final ResourceManager resource = getResource();
467                                // 6.0.4.0 (2014/11/28) ResultSetValue を使用するように変更。
468                                for( int clmNo=0; clmNo<numberOfColumns; clmNo++ ) {
469                                        final String clm = rsv.getColumnName(clmNo);
470                                        if( clmNo > 0 || useNumber ){                                           // 5.5.7.1 (2012/10/05)
471                                                //この場合だけセパレータ出力する。
472                                                headName.append( separator );                                   // 6.0.3.0 (2014/11/13)
473                                                headLabel.append( separator );                                  // 6.0.3.0 (2014/11/13)
474                                        }
475                                        headName.append( clm );                                                         // 6.0.3.0 (2014/11/13)
476                                        headLabel.append( resource.getLabel( clm ) );           // 6.0.3.0 (2014/11/13)
477                                }
478                                outPW.println( headName.toString() );
479                                outPW.println( headLabel.toString() );
480                        }
481
482                        int rowNo = 0;
483                        // 6.0.4.0 (2014/11/28) ResultSetValue を使用するように変更。
484                        while( rsv.next() ) {
485                                // 6.0.4.0 (2014/11/28) ResultSetValue を使用するように変更。
486                                if( useNumber ){                                        // 5.5.7.1 (2012/10/05)
487                                        if( useQuote ) { outPW.print( "\"" + rowNo + "\"" ); }  // 行番号
488                                        else {                   outPW.print( rowNo ); }
489                                }
490                                for( int clmNo=0; clmNo<numberOfColumns; clmNo++ ) {
491                                        // 6.0.2.5 (2014/10/31) refactoring:Avoid empty if statements 警告の対応
492                                        if( clmNo > 0 || useNumber ){                                   // 6.2.0.0 (2015/02/27)
493                                                //この場合だけセパレータ出力する。
494                                                outPW.print( separator );
495                                        }
496                                        String sval = replace( rsv.getValue(clmNo) );                           // 禁則文字の置換処理
497                                        if( sval != null && sval.length() > 0 ) {
498                                                // 6.0.3.0 (2014/11/13) データ中にダブルクオート文字が含まれる場合、エスケープするかどうか
499                                                if( useQuoteEscape && sval.indexOf( '"' ) >= 0 ) { sval = sval.replaceAll( "\"" ,"\"\"" ) ; }
500                                                // 6.0.3.0 (2014/11/13) データ中に改行コードが含まれる場合、ダブルクオートで囲うかどうか
501                                                if( useQuote || useReturnQuote && sval.indexOf( CR ) >= 0 ) {
502                                                        sval = "\"" + sval + "\"" ;
503                                                }
504                                        }
505                                        else {
506                                                sval = useQuote ? "\"\"" : "" ;
507                                        }
508                                        outPW.print( sval );
509                                }
510                                outPW.println();
511                                rowNo++ ;
512                        }
513                        executeCount = rowNo ;
514                        tran.commit();                          // 6.3.6.1 (2015/08/28)
515                }
516                catch( final SQLException ex ) {                // catch は、close() されてから呼ばれます。
517                        final String errMsg = "データベース処理を実行できませんでした。"
518                                                 + CR + '[' + sql + ']' + CR
519                                                 + "err=[" + ex.getSQLState() + ']'
520                                                 + ex.getMessage();
521                        throw new HybsSystemException( errMsg,ex );
522                }
523                finally {                                               // finally は、close() されてから呼ばれます。
524                        Closer.resultClose( resultSet );
525                        Closer.stmtClose( stmt );
526                        Closer.stmtClose( callStmt );   // 4.3.4.3 (2008/12/22)
527                }
528
529                return executeCount ;
530        }
531
532        /**
533         * replaceFrom,replaceTo に基づく禁則文字の置換処理を行います。
534         *
535         * replaceFrom の1文字づつを、対応するreplaceToの1文字づつに変換します。
536         * replaceFrom と replaceTo の文字数は同じでなければなりません。
537         *
538         * @og.rev 6.0.3.0 (2014/11/13) 新規追加
539         *
540         * @param   str 置換する文字列
541         *
542         * @return      置換後の文字列
543         */
544        private String replace( final String str ) {
545                String rtn = str;
546                if( rtn != null && replaceFrom != null && replaceTo != null ) {
547                        for( int i=0; i<replaceTo.length(); i++ ) {
548                                rtn = rtn.replace( replaceFrom.charAt(i) , replaceTo.charAt(i) );               // charの置き換えは、全件
549                        }
550                }
551                return rtn ;
552        }
553
554        /**
555         * 引数配列付のクエリーを実行します。
556         * 処理自体は, #execute() と同様に、各サブクラスの実装に依存します。
557         * これは、CallableStatement を用いて、データベース検索処理を行います。
558         * {call TYPE3B01.TYPE3B01(?,?,?,?)} で、4番目の引数には、
559         * names で指定したリクエスト情報が、ARG_ARRAY 配列に順次セットされます。
560         * 使用する場合は、一旦わかり易い変数に受けて利用してください。
561         * 呼び出す PL/SQL では、検索系PL/SQL です。
562         *
563         * @og.rev 3.6.1.0 (2005/01/05) PL/SQLコール(JDBCErrMsg 形式)への対応
564         * @og.rev 4.3.4.3 (2008/12/22) (Oracle11gDriver対応)PL/SQLコールの場合に、"クローズされた文です。"のエラーが発生する問題に対応
565         * @og.rev 5.3.0.0 (2010/12/01) executeCall メソッドの引数見直し
566         * @og.rev 6.0.0.0 (2014/04/11) Oracle11g(11.2.0.3のドライバ)対応
567         *
568         * @param       conn            コネクション
569         * @param   callStmt    コーラブルステートメント
570         * @param   args                オブジェクトの引数配列(可変長引数)
571         *
572         * @return      結果オブジェクト
573         */
574        private ResultSet executeCall( final Connection conn,final CallableStatement callStmt,final String... args ) throws SQLException {
575                callStmt.setQueryTimeout( DB_MAX_QUERY_TIMEOUT );
576                if( fetchSize > 0 ) { callStmt.setFetchSize( fetchSize ); }
577                final Map<String,Class<?>> map = conn.getTypeMap();
578                try {
579                        map.put( ERR_MSG,Class.forName( "org.opengion.hayabusa.db.DBErrMsg" ) );
580                }
581                catch( final ClassNotFoundException ex ) {
582                        final String errMsg = "org.opengion.hayabusa.db.DBErrMsg クラスが見つかりません。" + CR
583                                        + ex.getMessage();                      // // 5.1.8.0 (2010/07/01) errMsg 修正
584                        throw new HybsSystemException( errMsg,ex );             // 3.5.5.4 (2004/04/15) 引数の並び順変更
585                }
586
587                // 6.0.0.0 (2014/04/11) Oracle11g(11.2.0.3のドライバ)対応 http://docs.oracle.com/cd/E28389_01/web.1111/b60995/thirdparty.htm
588                final Array newArray = ((OracleConnection)conn).createOracleArray( ARG_ARRAY, StringUtil.rTrims( args ));               // 6.0.0.0 (2014/04/11) Oracle11g(11.2.0.3のドライバ)対応
589
590                callStmt.registerOutParameter(1, Types.INTEGER);
591                callStmt.registerOutParameter(2, Types.ARRAY,ERR_MSG_ARRAY);            // 6.0.0.0 (2014/04/11) Oracle11g(11.2.0.3のドライバ)対応
592                callStmt.registerOutParameter(3, OracleTypes.CURSOR);
593                callStmt.setArray( 4,newArray );                                                                        // 6.0.0.0 (2014/04/11) Oracle11g(11.2.0.3のドライバ)対応
594
595                callStmt.execute();
596
597                errCode = callStmt.getInt(1);
598
599                // 6.4.1.1 (2016/01/16) PMD refactoring. Avoid declaring a variable if it is unreferenced before a possible exit point.
600                ResultSet resultSet = null;
601                if( errCode < ErrorMessage.NG ) {               // 異常以外の場合
602                        resultSet = ((OracleCallableStatement)callStmt).getCursor(3);
603                }
604                if( errCode > ErrorMessage.OK ) {               // 正常以外の場合
605                        final Array rtn3 = callStmt.getArray(2);                                                                // 6.0.0.0 (2014/04/11) Oracle11g(11.2.0.3のドライバ)対応
606                        final Object[] rtnval3 = (Object[])rtn3.getArray();
607                        errMessage = new ErrorMessage( "Query_JDBCErrMsg Error!!" );
608                        for( int i=0; i<rtnval3.length; i++ ) {
609                                final DBErrMsg er = (DBErrMsg)rtnval3[i];
610                                if( er == null ) { break; }
611                                errMessage.addMessage( er.getErrMsg() );
612                        }
613                }
614                return resultSet;
615        }
616
617        /**
618         * PrintWriter を取得します。
619         *
620         * ここでは、一般的なファイル出力を考慮した PrintWriter を作成します。
621         *
622         * @og.rev 3.7.1.1 (2005/05/23) フォルダがない場合は、複数階層分のフォルダを自動で作成します。
623         * @og.rev 3.8.0.0 (2005/06/07) FileUtil#getPrintWriter を利用。
624         * @og.rev 5.6.1.0 (2013/02/01) 3.7.1.1のコメントに入っているが対応されていないのでフォルダ作成追加
625         *
626         * @return       出力用PrintWriterオブジェクト
627         * @og.rtnNotNull
628         */
629        private PrintWriter getPrintWriter() {
630                if( filename == null ) {
631                        final String errMsg = "ファイル名がセットされていません。";
632                        throw new HybsSystemException( errMsg );
633                }
634                final String directory = HybsSystem.url2dir( fileURL );
635
636                // 5.6.1.0 (2013/02/01) 
637                final File dir = new File(directory);
638                if( ! dir.exists() && ! dir.mkdirs() ) {
639                        final String errMsg = "ディレクトリの作成に失敗しました。[" + directory + "]";
640                        throw new HybsSystemException( errMsg );
641                }
642
643                // ※ 注意 StringUtil.urlAppend を組み込んでいる意図が不明。一旦削除していますが、注意
644                // 3.8.0.0 (2005/06/07) FileUtil#getPrintWriter を利用。
645        //      out = FileUtil.getPrintWriter( StringUtil.urlAppend( directory,filename ),fileAppend,encode);
646
647                // 処理を簡素化します。
648                return FileUtil.getPrintWriter( new File( directory,filename ),encode,fileAppend );
649        }
650
651        /**
652         * 名称配列を元に、リクエスト情報のデータを取得します。
653         *
654         * @og.rev 3.6.1.0 (2005/01/05) PL/SQLコール(JDBCErrMsg 形式)への対応
655         *
656         * @param       nameArray       キーとなる名称の配列(可変長引数)
657         *
658         * @return      そのリクエスト情報
659         * @og.rtnNotNull
660         */
661        private String[] getRequest( final String... nameArray ) {
662                String[] rtn = new String[nameArray.length];
663
664                for( int i=0; i<rtn.length; i++ ) {
665                        rtn[i] = getRequestValue( nameArray[i] );
666                }
667
668                return rtn;
669        }
670
671        /**
672         * 【TAG】(通常は使いません)検索時のDB接続IDを指定します(初期値:DEFAULT)。
673         *
674         * @og.tag
675         *   検索時のDB接続IDを指定します。初期値は、DEFAULT です。
676         *
677         * @param       id DB接続ID
678         */
679        public void setDbid( final String id ) {
680                dbid = nval( getRequestParameter( id ),dbid );
681        }
682
683        /**
684         * 【TAG】可変長ファイルを作成するときの項目区切り文字(セパレータ)をセットします(初期値:TAB_SEPARATOR)。
685         *
686         * @og.tag 可変長ファイルを作成するときの項目区切り文字をセットします。
687         * (初期値:ローカル定義の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 org.opengion.fukurou.system.HybsConst#DB_FETCH_SIZE}])。
980         *
981         * @og.tag
982         * より多くの行が必要なときに、データベースから取り出す必要がある行数に
983         * ついてのヒントを JDBC ドライバに提供します。
984         * 指定された行数は、この Statement を使って作成された結果セットにだけ影響します。
985         * 指定された値が 0 の場合、ヒントは無視されます。
986         * (初期値:システム定数のDB_FETCH_SIZE[={@og.value org.opengion.fukurou.system.HybsConst#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}