    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 * ●形式：&lt;og:directWriteTable filename="[･･･]" ･･･ &gt;SELECT * FROM ZYXX &lt;/og:directWriteTable &gt;
    070 * ●body：あり(EVAL_BODY_BUFFERED:BODYを評価し、{&#064;XXXX} を解析します)
    071 *
    072 * ●Tag定義：
    073 *   &lt;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開始/終了文字(&gt;&lt;) 存在チェックを実施するかどうか[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 *   &gt;   ... Body ...
    105 *   &lt;/og:directWriteTable&gt;
    106 *
    107 * ●使用例
    108 *     &lt;og:directWriteTable
    109 *         dbid        = "ORCL"               接続データベースID(初期値:DEFAULT)
    110 *         separator   = ","                  ファイルの区切り文字(初期値:タブ)
    111 *         fileURL     = "{&#064;USER.ID}"    保存先ディレクトリ名
    112 *         filename    = "{&#064;filename}"   保存ファイル名
    113 *         encode      = "UnicodeLittle"      保存ファイルエンコード名
    114 *         useHeader   = "true"               保存ファイルにヘッダーを出力するかどうか
    115 *         useQuote    = "false"              データをダブルクオートで囲うかどうか
    116 *         useQuoteEscape = "true"            ダブルクオート文字が含まれる場合、エスケープするかどうか
    117 *         useReturnQuote = "true"            改行コードが含まれる場合、ダブルクオートで囲うかどうか
    118 *         replaceFrom = "&apos;,&quot;*%|"   置換元文字を指定。一文字単位で置換します。
    119 *         replaceTo   = "’，”＊％｜"       置換先文字を指定。一文字単位で置換します。
    120 *         zip         = "true"               ZIPファイルに圧縮するかどうか
    121 *         zipFilename = "Sample.zip"         ZIPファイルのファイル名
    122 *         fileAppend  = "true"               ファイルを追加モードで登録するかどうか
    123 *         displayMsg  = "MSG0033"            実行後の表示メッセージ
    124 *         fetchSize   = "200"                DB検索する場合のフェッチするサイズ
    125 *     &gt;
    126 *         SELECT * FROM ZYXX
    127 *     &lt;/og:directWriteTable &gt;
    128 *
    129 *     &lt;og:directWriteTable
    130 *         fileURL     = "{&#064;USER.ID}"    保存先ディレクトリ名
    131 *         filename    = "{&#064;filename}"   保存ファイル名
    132 *         names       = "AAA,BBB,CCC,･･･"    指定のキーに対応するリクエスト値を ARG_ARRAY にセットします。
    133 *         queryType   = "JDBCErrMsg"         JDBCErrMsg 形式のPL/SQL をコールします。
    134 *     &gt;
    135 *        { call PL/SQL(?,?,?,? ) }
    136 *     &lt;/og:directWriteTable &gt;
    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 の１文字づつを、対応するreplaceToの１文字づつに変換します。
    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(?,?,?,?)} で、４番目の引数には、
    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) または、２文字目が、
    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         * データ置換で、改行、復帰、タブを、指定する場合、２文字必要です。
    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のパラメータに
    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}