    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.hayabusa.common.HybsSystem;
    019import org.opengion.hayabusa.db.DBColumn;
    020import org.opengion.hayabusa.db.DBTableModel;
    021import org.opengion.fukurou.model.ArrayDataModel;
    022import org.opengion.fukurou.model.Formatter;
    023import org.opengion.fukurou.util.Attributes;
    024import org.opengion.fukurou.util.ErrorMessage;
    025import org.opengion.fukurou.util.ToString;                                              // 6.1.1.0 (2015/01/17)
    026import org.opengion.fukurou.util.StringUtil ;                                   // 6.2.0.0 (2015/02/27)
    027import org.opengion.fukurou.util.ArraySet;                                              // 6.4.3.4 (2016/03/11)
    028
    029import static org.opengion.fukurou.util.StringUtil.nval ;
    030
    031import java.util.List;
    032import java.util.ArrayList;
    033import java.util.Enumeration;
    034import java.util.Locale ;
    035import java.util.Set;                                                                                   // 6.4.3.4 (2016/03/11)
    036
    037/**
    038 * 検索結果の DBTableModelオブジェクトに値を設定するタグです。
    039 *
    040 * columnSet と共に使用する場合は、entryタグ の command属性と、columnSetタグ の command属性が
    041 * 一致した場合のみ、処理されます。
    042 * entryタグは、そのコマンドにより、DBTableModelオブジェクトの値を設定します。
    043 * たとえば、command="INSERT" ならば、１行分のデータを選択された行番号の次に挿入します。
    044 * また、追加、変更、削除された、DBTableModelオブジェクト でも、内部には元のデータを
    045 * 持っているため、command="RESET" で元の状態に戻すことが可能です。
    046 *
    047 * @og.formSample
    048 * ●形式：
    049 *       ・&lt;og:entry command="…"&gt;
    050 *             &lt;og:columnSet command="…" /&gt;
    051 *         &lt;/og:entry&gt;
    052 *       ・&lt;og:entry command="…" /&gt;
    053 *             ･･･columnSetを使わない場合でもresult.jspから次画面(insert,modify,copy.jsp等)に
    054 *                にDBTableModelをもっていく場合には、必ず２を書いてください。
    055 *                (取消のとき、エンジン内でDBTableModelを操作するのに使用する為)
    056 * ●body：あり(EVAL_BODY_BUFFERED:BODYを評価し、{&#064;XXXX} を解析します)
    057 *
    058 * ●Tag定義：
    059 *   &lt;og:entry
    060 *       command          ○【TAG】コマンド (INSERT/COPY/MODIFY/DELETE/ENTRY/CHANGE/RESET/ALLRESET/ALLACTION/RESETDATA/INSERTONE/REALDELETE/REQENTRY/RAWSET)を設定します(必須)
    061 *       scope              【TAG】キャッシュする場合のスコープ[request/page/session/application]を指定します(初期値:session)
    062 *       repeatCount        【TAG】指定の回数分だけ、繰り返し処理を行う回数を指定します(初期値:1)
    063 *       tableId            【TAG】(通常は使いません)sessionから所得する DBTableModelオブジェクトの ID
    064 *       useConsistency     【TAG】Consistency キー による整合性チェックを行うかどうかを指定します(初期値:true)
    065 *       selectedAll        【TAG】データを全件選択済みとして処理するかどうか[true/false]を指定します(初期値:false)
    066 *       strictCheck        【TAG】(通常は使いません)カラムＩＤの存在チェックを行うかどうか[true/false]を指定します(初期値:true)
    067 *       noTransition       【TAG】(通常は使いません)画面遷移を行わない形式の登録方法を使用するかを指定します
    068 *       useSLabel          【TAG】7.0.7.0 (2019/12/13) ｴﾗｰﾒｯｾｰｼﾞにSLABELを利用するかどうか[true/false]を指定します(初期値:false)
    069 *       caseKey            【TAG】このタグ自体を利用するかどうかの条件キーを指定します(初期値:null)
    070 *       caseVal            【TAG】このタグ自体を利用するかどうかの条件値を指定します(初期値:null)
    071 *       caseNN             【TAG】指定の値が、null/ゼロ文字列 でない場合(Not Null=NN)は、このタグは使用されます(初期値:判定しない)
    072 *       caseNull           【TAG】指定の値が、null/ゼロ文字列 の場合は、このタグは使用されます(初期値:判定しない)
    073 *       caseIf             【TAG】指定の値が、true/TRUE文字列の場合は、このタグは使用されます(初期値:判定しない)
    074 *       debug              【TAG】デバッグ情報を出力するかどうか[true/false]を指定します(初期値:false)
    075 *   &gt;   ... Body ...
    076 *   &lt;/og:entry&gt;
    077 *
    078 * ●使用例
    079 *    &lt;og:entry command="{&#064;command}"  &gt;
    080 *        &lt;og:columnSet command="{&#064;command}" columnId="ECNO"   action="CLEAR" /&gt;
    081 *        &lt;og:columnSet command="{&#064;command}" columnId="JYOKYO" action="SET" value="1" /&gt;
    082 *    &lt;/og:entry&gt;
    083 *
    084 *    &lt;og:entry command="MODIFY" rows="1" &gt;
    085 *        &lt;og:columnSet  command="MODIFY" columnId="key" action="TBLSET" value="[key][lang]"/&gt;
    086 *    &lt;/og:entry&gt;
    087 *
    088 *    action="ADD" は、DBTypeに依存した方法で、既存の値を、＋１ します。
    089 *    &lt;og:entry command="{&#064;command}" repeatCount="5" &gt;
    090 *        &lt;og:columnSet  command="{&#064;command}" columnId="YKNO" action="ADD" /&gt;
    091 *    &lt;/og:entry&gt;
    092 *
    093 *    action="ADD" は、DBTypeに依存した方法で、既存の値に、value の値を加算します。
    094 *    &lt;og:entry command="{&#064;command}" repeatCount="5" &gt;
    095 *        &lt;og:columnSet  command="{&#064;command}" columnId="YKNO" action="ADD" value="5" /&gt;
    096 *    &lt;/og:entry&gt;
    097 *
    098 *    command属性 は、columnSetタグのcommand属性と同一の場合のみ、処理します。
    099 *    [command属性]
    100 *      INSERT     新規
    101 *      COPY       複写
    102 *      MODIFY     変更
    103 *      DELETE     削除
    104 *      ENTRY      エントリー
    105 *      CHANGE     チェンジ
    106 *      RESET      リセット         (RESET_ACTION_ALL_USE=true で、ALLRESET が呼ばれます)
    107 *      ALLRESET   全件リセット
    108 *      ALLACTION  オールアクション
    109 *      RESETDATA  リセットデータ
    110 *      INSERTONE  新規(1行のみ)
    111 *      REALDELETE 物理削除
    112 *      REQENTRY   リクエスト変数設定
    113 *      RAWSET     DBTableModelに直接セット                   7.2.9.0 (2020/10/12)
    114 *
    115 *    command属性 は、columnSetタグで指定します。
    116 *    [action属性]
    117 *      DEFAULT カラムリソースで定義した初期値をセットします。
    118 *      CLEAR   値をクリア(ゼロストリング &quot;&quot; )します。
    119 *      ADD     現在の値を ＋１ します。  0 ⇒ 1 , A ⇒ B , 9 ⇒ 10。value属性と併用すれば、指定の値を加算できます。
    120 *      SET     value で設定した値を 新しい値として登録します。
    121 *      NULLSET 元の値が NULL の場合だけ、value で設定した新しい値を登録します。
    122 *      LOWER   小文字に変換します。
    123 *      UPPER   大文字に変換します。
    124 *      COPY    value にコピー元のカラムIDをセットすれば、その値を代入します。
    125 *      TBLSET  DBTableModel の内容を取り込んで指定の columnId カラムに設定します。[カラム名] で指定できます。
    126 *              また、これは文字列を解析して、 value を作成しますので,文字列連結等に使用できます。
    127 *      TBLNULLSET 元の値が NULL の場合だけ、TBLSETを実行します。         6.9.9.0 (2018/08/20) 追加
    128 *      WRTCTRL writableControl を使用したカラムデータの先頭アンダーバーを削除します。
    129 *      DBMENU  DBMENUでパラメータ設定(コロン連結文字)を使用したカラムデータの先頭データのみにします。
    130 *      REQSET  valueで指定したカラムの値をキーに、リクエスト変数から値を取出し、セットします。
    131 *      SEQSET  valueの初期値を利用して、１レコードごとに、＋１した値をセットします。
    132 *      PREFIX  valueの値を後ろから検索し、指定のカラム値の前半部分を取得します(記号は含みません)。
    133 *      SUFIX   valueの値を後ろから検索し、指定のカラム値の後半部分を取得します(記号は含みません)。
    134 *      その他  カラムのDBType の valueAction メソッドを呼び出します。自由に設定可能です。
    135 *
    136 *    [strictCheck属性]は、カラムＩＤの存在チェックを行うかどうかを指定します(初期値:true)
    137 *      true    カラムＩＤがDBTableModel に存在しない場合は、エラーになる。
    138 *      false   カラムＩＤがDBTableModel に存在しない場合は、無視する。
    139 *
    140 * @og.group 画面登録
    141 *
    142 * @version  4.0
    143 * @author       Kazuhiko Hasegawa
    144 * @since    JDK5.0,
    145 */
    146public class EntryTag extends CommonTagSupport {
    147        /** このプログラムのVERSION文字列を設定します。   {@value} */
    148        private static final String VERSION = "7.2.9.0 (2020/10/12)" ;
    149        private static final long serialVersionUID = 729020201012L ;
    150
    151        /** command 引数に渡す事の出来る コマンド  新規 {@value} */
    152        public static final String CMD_INSERT   = "INSERT" ;
    153        /** command 引数に渡す事の出来る コマンド  複写 {@value} */
    154        public static final String CMD_COPY             = "COPY" ;
    155        /** command 引数に渡す事の出来る コマンド  変更 {@value} */
    156        public static final String CMD_MODIFY   = "MODIFY" ;
    157        /** command 引数に渡す事の出来る コマンド  削除 {@value} */
    158        public static final String CMD_DELETE   = "DELETE" ;
    159        /** command 引数に渡す事の出来る コマンド  エントリー {@value} */
    160        public static final String CMD_ENTRY    = "ENTRY" ;
    161        /** command 引数に渡す事の出来る コマンド  チェンジ {@value} */
    162        public static final String CMD_CHANGE   = "CHANGE" ;
    163        /** command 引数に渡す事の出来る コマンド  リセット {@value} */
    164        public static final String CMD_RESET    = "RESET" ;
    165        /** command 引数に渡す事の出来る コマンド  全件リセット {@value} */
    166        public static final String CMD_ALLRESET         = "ALLRESET" ;                          // 3.5.6.3 (2004/07/12)
    167        /** command 引数に渡す事の出来る コマンド  オールアクション{@value} */
    168        public static final String CMD_ALLACTION        = "ALLACTION" ;
    169        /** command 引数に渡す事の出来る コマンド  リセット(データのみ){@value} */
    170        public static final String CMD_RESETDATA        = "RESETDATA" ;                         // 4.3.3.0 (2008/10/01)
    171        /** command 引数に渡す事の出来る コマンド  追加(1行のみ){@value} */
    172        public static final String CMD_INSERTONE        = "INSERTONE" ;                         // 5.1.5.0 (2010/04/01)
    173        /** command 引数に渡す事の出来る コマンド  物理削除 {@value} */
    174        public static final String CMD_REALDELETE       = "REALDELETE" ;                        // 5.1.6.0 (2010/05/01)
    175        /** command 引数に渡す事の出来る コマンド  リクエスト変数設定 {@value} */
    176        public static final String CMD_REQENTRY         = "REQENTRY" ;                          // 5.6.1.2 (2013/02/22)
    177        /** command 引数に渡す事の出来る コマンド  DBTableModelに直接セット {@value} */
    178        public static final String CMD_RAWSET           = "RAWSET" ;                            // 7.2.9.0 (2020/10/12)
    179        // 6.4.3.4 (2016/03/11) String配列 から、Setに置き換えます。
    180
    181        private static final Set<String> COMMAND_SET = new ArraySet<>(
    182                                                        CMD_INSERT,CMD_COPY,CMD_MODIFY,CMD_DELETE,CMD_ENTRY,CMD_CHANGE,CMD_ALLACTION,
    183                                                        CMD_RESET,CMD_ALLRESET,CMD_RESETDATA,CMD_INSERTONE,CMD_REALDELETE,CMD_REQENTRY,CMD_RAWSET );
    184
    185        /** action 引数に渡す事の出来る アクションコマンド  初期値:{@value} */
    186        public static final String ACT_DEFAULT  = "DEFAULT" ;
    187        /** action 引数に渡す事の出来る アクションコマンド  クリア {@value} */
    188        public static final String ACT_CLEAR    = "CLEAR" ;
    189        /** action 引数に渡す事の出来る アクションコマンド  ＋１ {@value} */
    190        public static final String ACT_ADD      = "ADD" ;
    191        /** action 引数に渡す事の出来る アクションコマンド  小文字化{@value} */
    192        public static final String ACT_LOWER    = "LOWER" ;
    193        /** action 引数に渡す事の出来る アクションコマンド  大文字化{@value} */
    194        public static final String ACT_UPPER    = "UPPER" ;
    195        /** action 引数に渡す事の出来る アクションコマンド  コピー {@value} */
    196        public static final String ACT_COPY     = "COPY" ;
    197        /** action 引数に渡す事の出来る アクションコマンド  セット {@value} */
    198        public static final String ACT_SET      = "SET" ;
    199        // 3.4.0.3 (2003/09/10) NULLSET Action を追加します。
    200        /** action 引数に渡す事の出来る アクションコマンド  NULLセット {@value} */
    201        public static final String ACT_NULLSET  = "NULLSET" ;
    202        /** action 引数に渡す事の出来る アクションコマンド  テーブルセット {@value} */
    203        public static final String ACT_TBLSET   = "TBLSET" ;
    204        /** action 引数に渡す事の出来る アクションコマンド  テーブルNULLセット {@value} */
    205        public static final String ACT_TBLNULLSET   = "TBLNULLSET" ;    // 6.9.9.0 (2018/08/20)
    206        /** action 引数に渡す事の出来る アクションコマンド  ライトコントロール {@value} */
    207        public static final String ACT_WRTCTRL  = "WRTCTRL" ;                   // 3.8.1.5 (2006/03/30)
    208        /** action 引数に渡す事の出来る アクションコマンド  DBメニュー {@value} */
    209        public static final String ACT_DBMENU  = "DBMENU" ;                             // 3.8.5.3 (2006/08/07)
    210        /** action 引数に渡す事の出来る アクションコマンド  リクエスト値セット {@value} */
    211        public static final String ACT_REQSET  = "REQSET" ;                             // 5.4.2.1 (2011/12/09)
    212        /** action 引数に渡す事の出来る アクションコマンド  連番値セット {@value} */
    213        public static final String ACT_SEQSET  = "SEQSET" ;                             // 5.6.5.2 (2013/06/21)
    214        /** action 引数に渡す事の出来る アクションコマンド  PREFIX値セット {@value} */
    215        public static final String ACT_PREFIX  = "PREFIX" ;                             // 5.6.6.1 (2013/07/12)
    216        /** action 引数に渡す事の出来る アクションコマンド  SUFIX値セット {@value} */
    217        public static final String ACT_SUFIX   = "SUFIX" ;                              // 5.6.6.1 (2013/07/12)
    218
    219        // 3.5.6.0 (2004/06/18) すべてを protected から private に変更します。
    220        private transient       DBTableModel            table   ;
    221        private transient       List<Attributes>        values  ;               // 6.3.9.0 (2015/11/06) transient 追加
    222
    223        private String                          tableId         = HybsSystem.TBL_MDL_KEY;
    224        private String                          command         ;
    225        private int[]                           rowNo           ;
    226
    227        // 3.5.4.2 (2003/12/15) 指定の回数繰り返す機能を追加します。
    228        private int                             repeatCount     = 1;
    229
    230        // 3.5.5.7 (2004/05/10) Consistency キー による整合性チェックを行うかどうかを指定します。
    231        // 6.9.5.0 (2018/04/23) USE_CONSISTENCY 廃止(true固定)
    232//      private boolean                 useConsistency  = HybsSystem.sysBool( "USE_CONSISTENCY" );
    233        private boolean                 useConsistency  = true;         // 6.9.5.0 (2018/04/23)
    234
    235        // 3.8.1.1 (2005/11/21) 全件選択されたこととして、処理します。
    236        private boolean selectedAll     ;
    237
    238        // 3.5.6.4 (2004/07/16) RESET コマンドのデフォルト処理 に、ALLRESET を
    239        // 使用するかどうかを指定します(初期値:false(使用しない))。
    240        // 6.2.6.0 (2015/06/19) 初期値:true(使用する)にします。
    241        private final boolean RESET_ACTION_ALL_USE = HybsSystem.sysBool( "RESET_ACTION_ALL_USE" );
    242
    243        // 4.0.0 (2006/09/31) カラムＩＤの存在チェックを行うかどうかを指定します。
    244        private boolean strictCheck     = true;
    245
    246        private boolean noTransition;           // 4.3.3.0 (2008/10/01) 追加
    247
    248        // 5.6.5.2 (2013/06/21) SEQSET アクションのカウンター
    249        private int seqsetCnt   ;
    250
    251        // 7.0.7.0 (2019/12/13) ｴﾗｰﾒｯｾｰｼﾞにSLABELを利用するかどうか[true/false]を指定します(初期値:false)
    252        private boolean         useSLabel       ;
    253
    254        /**
    255         * デフォルトコンストラクター
    256         *
    257         * @og.rev 6.4.2.0 (2016/01/29) PMD refactoring. Each class should declare at least one constructor.
    258         */
    259        public EntryTag() { super(); }          // これも、自動的に呼ばれるが、空のメソッドを作成すると警告されるので、明示的にしておきます。
    260
    261        /**
    262         * Taglibの開始タグが見つかったときに処理する doStartTag() を オーバーライドします。
    263         *
    264         * @og.rev 5.1.9.0 (2010/08/01) 戻り値を、EVAL_BODY_INCLUDE → EVAL_BODY_BUFFERED に変更
    265         * @og.rev 6.3.4.0 (2015/08/01) caseKey,caseVal,caseNN,caseNull,caseIf 属性対応
    266         * @og.rev 6.4.3.4 (2016/03/11) String配列 から、Setに置き換えます。
    267         *
    268         * @return      後続処理の指示
    269         */
    270        @Override
    271        public int doStartTag() {
    272                // 6.3.4.0 (2015/08/01) useTag() の追加と、if条件の反転
    273                // 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
    274                return useTag() && check( command, COMMAND_SET ) ? EVAL_BODY_BUFFERED : SKIP_BODY;
    275        }
    276
    277        /**
    278         * Taglibの終了タグが見つかったときに処理する doEndTag() を オーバーライドします。
    279         *
    280         * @og.rev 3.1.1.2 (2003/04/04) Tomcat4.1 対応。release2() を doEndTag()で呼ぶ。
    281         * @og.rev 3.5.5.5 (2004/04/23) 登録時の 整合性パラメータチェックを行います。
    282         * @og.rev 3.5.5.6 (2004/04/27) JSP画面の作成不具合。ENTRY系で、command を投げた場合は、無視します。
    283         * @og.rev 3.5.5.7 (2004/05/10) Consistency キー による整合性チェックを行うかどうかを指定します。
    284         * @og.rev 3.5.5.8 (2004/05/20) Consistency キー による整合性チェックを checkConsistency() に集約します。
    285         * @og.rev 3.6.0.8 (2004/11/19) DBTableModel をセーブする時に、トランザクションチェックを行います。
    286         * @og.rev 4.3.3.0 (2008/10/01) noTransition 属性を追加します。
    287         * @og.rev 4.3.8.0 (2009/08/01) noTransition値取得のメソッド名変更
    288         * @og.rev 5.1.3.0 (2010/02/01) noTransitionのコントロールは、requestで行う。
    289         * @og.rev 6.3.4.0 (2015/08/01) caseKey,caseVal,caseNN,caseNull,caseIf 属性対応
    290         * @og.rev 6.4.3.4 (2016/03/11) String配列 から、Setに置き換えます。
    291         *
    292         * @return      後続処理の指示
    293         */
    294        @Override
    295        public int doEndTag() {
    296                debugPrint();           // 4.0.0 (2005/02/28)
    297                if( !useTag() ) { return EVAL_PAGE ; }  // 6.3.4.0 (2015/08/01)
    298
    299                // noTransition = isNoTransitionRequest() || noTransition; // 4.3.3.0 (2008/10/01) 追加
    300                noTransition = isNoTransitionRequest(); // 5.1.3.0 (2010/02/01)
    301                startQueryTransaction( tableId );               // 3.6.0.8 (2004/11/19)
    302                table = (DBTableModel)getObject( tableId );
    303                if( table != null && check( command, COMMAND_SET ) ) {
    304                        if( ! checkConsistency() ) { return SKIP_PAGE ; }
    305                        if( rowNo == null ) { rowNo = getParameterRows(); }             // 4.0.0 (2005/01/31)
    306
    307                        commandExec( command );
    308
    309                        // 3.6.0.8 (2004/11/19) トランザクションチェックを行います。
    310                        if( ! commitTableObject( tableId, table ) ) {
    311                                jspPrint( "EntryTag Query処理が割り込まれました。DBTableModel は登録しません。" );
    312                                return SKIP_PAGE;
    313                        }
    314                }
    315
    316                return EVAL_PAGE ;
    317        }
    318
    319        /**
    320         * タグリブオブジェクトをリリースします。
    321         *
    322         * キャッシュされて再利用されるので、フィールドの初期設定を行います。
    323         *
    324         * @og.rev 2.0.0.4 (2002/09/27) カスタムタグの release() メソッドを、追加
    325         * @og.rev 3.1.1.2 (2003/04/04) Tomcat4.1 対応。release2() を doEndTag()で呼ぶ。
    326         * @og.rev 3.5.4.2 (2003/12/15) 指定の回数繰り返す機能を追加します。
    327         * @og.rev 3.5.5.7 (2004/05/10) Consistency キー による整合性チェックを行うかどうかを指定します。
    328         * @og.rev 3.8.1.1 (2005/11/21) selectedAll 追加。全件選択されたこととして、処理します。
    329         * @og.rev 4.0.0.0 (2006/09/31) strictCheck 追加。
    330         * @og.rev 4.3.3.0 (2008/10/01) noTransition 属性を追加します。
    331         * @og.rev 5.6.5.2 (2013/06/21) seqsetCnt 属性を追加します。
    332         * @og.rev 6.9.5.0 (2018/04/23) USE_CONSISTENCY 廃止(true固定)
    333         * @og.rev 7.0.7.0 (2019/12/13) useSLabel 属性を追加。
    334         */
    335        @Override
    336        protected void release2() {
    337                super.release2();
    338                tableId                 = HybsSystem.TBL_MDL_KEY;
    339                table                   = null;
    340                command                 = null;
    341                rowNo                   = null;
    342                values                  = null;
    343                repeatCount             = 1;                    // 3.5.4.2 (2003/12/15)
    344//              useConsistency  = HybsSystem.sysBool( "USE_CONSISTENCY" );              // 3.5.5.7 (2004/05/10)
    345                useConsistency  = true;                 // 6.9.5.0 (2018/04/23) true固定
    346                selectedAll             = false;                // 3.8.1.1 (2005/11/21)
    347                strictCheck             = true;                 // 4.0.0 (2006/09/31)
    348                noTransition    = false;                // 4.3.3.0 (2008/10/01) 追加
    349                seqsetCnt               = 0;                    // 5.6.5.2 (2013/06/21) SEQSET アクションのカウンター
    350                useSLabel               = false;                // 7.0.7.0 (2019/12/13) ｴﾗｰﾒｯｾｰｼﾞにSLABELを利用するかどうか[true/false]を指定します(初期値:false)
    351        }
    352
    353        /**
    354         * 内部タグの ColumnSetTag より、個々のカラムの値を書き換える為の属性を指定します。
    355         *
    356         * 複数の値を受け取って、後ほど、すべてのカラムに対して処理を行います。
    357         *
    358         * @og.rev 3.1.0.0 (2003/03/20) Vector を使用している箇所で、非同期でも構わない箇所を、ArrayList に置換え。
    359         * @og.rev 3.1.2.0 (2003/04/07) taglib パッケージ内部で使用している箇所を protected 化する。
    360         *
    361         * @param   attri       属性リスト
    362         */
    363        protected void setAttributes( final Attributes attri ) {
    364                if( values == null ) { values = new ArrayList<>(); }
    365                if( command.equalsIgnoreCase( attri.get( "command" ) ) ) {
    366                        values.add( attri );
    367                }
    368        }
    369
    370        /**
    371         * 【TAG】(通常は使いません)結果のDBTableModelを、sessionに登録するときのキーを指定します
    372         *              (初期値:HybsSystem#TBL_MDL_KEY[={@og.value HybsSystem#TBL_MDL_KEY}])。
    373         *
    374         * @og.tag
    375         * 検索結果より、DBTableModelオブジェクトを作成します。これを、下流のviewタグ等に
    376         * 渡す場合に、通常は、session を利用します。その場合の登録キーです。
    377         * query タグを同時に実行して、結果を求める場合、同一メモリに配置される為、
    378         * この tableId 属性を利用して、メモリ空間を分けます。
    379         *              (初期値:HybsSystem#TBL_MDL_KEY[={@og.value HybsSystem#TBL_MDL_KEY}])。
    380         *
    381         * @param       id テーブルID (sessionに登録する時のID)
    382         */
    383        public void setTableId( final String id ) {
    384                tableId   = nval( getRequestParameter( id ),tableId );  // 3.8.0.9 (2005/10/17)
    385        }
    386
    387        /**
    388         * 【TAG】コマンド (INSERT/COPY/MODIFY/DELETE/ENTRY/CHANGE/RESET/ALLRESET/ALLACTION/RESETDATA/INSERTONE/REALDELETE/REQENTRY/RAWSET)を設定します。
    389         *
    390         * @og.tag
    391         * コマンドは,HTMLから(get/post)指定されますので,CMD_xxx で設定される
    392         * フィールド定数値のいづれかを、指定できます。
    393         *
    394         * @param       cmd コマンド (public static final 宣言されている文字列)
    395         * @see         <a href="../../../../constant-values.html#org.opengion.hayabusa.taglib.EntryTag.CMD_INSERT">コマンド定数</a>
    396         */
    397        public void setCommand( final String cmd ) {
    398                final String cmd2 = getRequestParameter( cmd );
    399                if( cmd2 != null && cmd2.length() > 0 ) { command = cmd2.toUpperCase(Locale.JAPAN); }
    400        }
    401
    402        /**
    403         * コマンドを実行します。
    404         *
    405         * コマンドは,HTMLから(get/post)指定されますので,setCommand()メソッドで
    406         * 登録します。
    407         * コマンドを登録すると同時に,実行も行ないます。
    408         *
    409         * @og.rev 3.5.6.3 (2004/07/12) ALLRESET コマンドを追加する。
    410         * @og.rev 4.3.3.0 (2008/10/01) RESETDATA コマンドを追加する。
    411         * @og.rev 5.1.5.0 (2010/04/01) INSERTONE コマンドを追加する。
    412         * @og.rev 5.1.6.0 (2010/05/01) REALDELETE コマンドを追加する。
    413         * @og.rev 5.6.1.2 (2013/02/22) REQENTRY コマンドを追加する。
    414         * @og.rev 7.2.9.0 (2020/10/12) RAWSET コマンドを追加する。
    415         *
    416         * @param   command コマンド (public static final 宣言されている文字列)
    417         */
    418        private void commandExec( final String command ) {
    419
    420                table.setDefaultRowWritable( false );
    421                table.setDefaultRowChecked(  false );
    422
    423                if( CMD_INSERT.equals(      command ) ) { insert() ; }
    424                else if( CMD_COPY.equals(   command ) ) { copy()   ; }
    425                else if( CMD_MODIFY.equals( command ) ) { modify() ; }
    426                else if( CMD_CHANGE.equals( command ) ) { change() ; }
    427                else if( CMD_DELETE.equals( command ) ) { delete() ; }
    428                else if( CMD_ENTRY.equals(  command ) ) { entry()  ; }
    429                else if( CMD_RESET.equals(  command ) ) {
    430                                if( RESET_ACTION_ALL_USE )              { allReset() ; }                // 3.5.6.4 (2004/07/16)
    431                                else                                                    { reset()    ; }
    432                }
    433                else if( CMD_ALLRESET.equals(    command ) ) { allReset()  ; }  // 3.5.6.3 (2004/07/12)
    434                else if( CMD_ALLACTION.equals(   command ) ) { allAction() ; }
    435                else if( CMD_RESETDATA.equals(   command ) ) { resetData() ; }  // 4.3.3.0 (2008/10/01)
    436                else if( CMD_INSERTONE.equals(   command ) ) { insertOne() ; }  // 5.1.5.0 (2010/04/01)
    437                else if( CMD_REALDELETE.equals(  command ) ) { realDelete() ; } // 5.1.6.0 (2010/05/01)
    438                else if( CMD_REQENTRY.equals(    command ) ) { reqEntry()  ; }  // 5.6.1.2 (2013/02/22)
    439                else if( CMD_RAWSET.equals(      command ) ) { rawSet()  ; }    // 7.2.9.0 (2020/10/12)
    440        }
    441
    442        /**
    443         * DBTableModelに行を追加します。
    444         *
    445         * 注意：writableカラムの暫定対応が入っています。単純な空白データを
    446         * インサートすると、カラムデータが null になる為､ 制御がおかしく
    447         * なります。
    448         *
    449         * @og.rev 3.5.4.2 (2003/12/15) repeatCount による繰り返し処理を追加
    450         * @og.rev 4.3.3.0 (2008/10/01) noTransition 属性対応
    451         *
    452         */
    453        private void insert() {
    454                if( rowNo.length == 0 ) { rowNo = new int[] { -1 }; }
    455
    456                final boolean rowWritableFlag = "WRITABLE".equalsIgnoreCase( table.getColumnName( 0 ) );        // writable 対策
    457                // src の作成は、各チェック毎に行う必要はない。最初の一度だけでよい。
    458                String[] src = new String[ table.getColumnCount() ];
    459                for( int j=0; j<src.length; j++ ) {
    460                        final DBColumn dbColumn = table.getDBColumn( j );
    461                        src[j] = dbColumn.getDefault();
    462                }
    463                if( rowWritableFlag ) { src[0] = "true"; }      // writable 対策
    464
    465                final int rowCount = table.getRowCount();
    466
    467                // 逆順にINSERTしないと、行番号がずれてしまう。
    468                for( int i=rowNo.length-1; i>=0; i-- ) {
    469                        int row = rowNo[i];
    470                        for( int cnt=0; cnt<repeatCount; cnt++ ) {
    471                                if( cnt >= 1 ) {                // ２回目以降
    472                                        src = table.getValues( row );
    473                                }
    474
    475                                String[] dst = new String[ table.getColumnCount() ];
    476                                System.arraycopy( src,0,dst,0,dst.length );
    477                                dst = setColumnValues( dst );
    478
    479                                // 4.3.3.0 (2008/10/01) noTransition属性対応
    480                                if( noTransition ) { row = rowCount; }
    481                                else { row ++; }                                        // 指定行の下に追加する。
    482                                table.addValues( dst,row );
    483                                table.setRowWritable( row,true );
    484                                table.setRowChecked(  row,true );
    485                        }
    486                }
    487        }
    488
    489        /**
    490         * DBTableModelに行を追加し、チェックされた行の値をセットします。
    491         *
    492         * @og.rev 3.5.4.2 (2003/12/15) repeatCount による繰り返し処理を追加
    493         * @og.rev 4.3.3.0 (2008/10/01) noTransition 属性対応
    494         *
    495         */
    496        private void copy() {
    497                if( rowNo.length == 0 ) { insert() ; return ;}
    498
    499                final int rowCount = table.getRowCount();
    500
    501                // 逆順にCOPYしないと、行番号がずれてしまう。
    502                for( int i=rowNo.length-1; i>=0; i-- ) {
    503                        for( int cnt=0; cnt<repeatCount; cnt++ ) {
    504                                final String[] src = table.getValues( rowNo[i]+cnt );
    505                                String[] dst = new String[ table.getColumnCount() ];
    506                                System.arraycopy( src,0,dst,0,dst.length );
    507                                dst = setColumnValues( dst );
    508
    509                                // 4.3.3.0 (2008/10/01) noTransition属性対応
    510                                int row = -1;
    511                                if( noTransition ) { row = rowCount; }
    512                                else { row = rowNo[i] + cnt + 1; }                      // 指定行の下に追加する。
    513
    514                                table.addValues( dst,row );
    515                                table.setRowWritable( row,true );
    516                                table.setRowChecked(  row,true );
    517                        }
    518                }
    519        }
    520
    521        /**
    522         * DBTableModelの行を書込み可とます。
    523         *
    524         * @og.rev 4.3.4.6 (2009/01/15) 画面遷移なし登録で既に改廃Cがセットされている場合は、columnSetタグの処理を行わない。
    525         *
    526         */
    527        private void modify() {
    528                for( int i=0; i<rowNo.length; i++ ) {
    529                        final String[] src = table.getValues( rowNo[i] );
    530                        String[] dst = new String[ table.getColumnCount() ];
    531                        System.arraycopy( src,0,dst,0,dst.length );
    532
    533                        // 4.3.4.6 (2009/01/15)
    534                        // 画面遷移なし登録の場合、既に改廃Cが付いている(編集されている)場合は、
    535                        // columnSetによる値のセットを行わない。
    536                        // (同じコマンドで複数のボタンを割り当てている場合、複数回の変更・削除によって、先に登録された
    537                        // 値が削除されてしまうため。
    538                        if( !( noTransition && table.getModifyType( rowNo[i] ) != null && table.getModifyType( rowNo[i] ).length() > 0 ) ){
    539                                dst = setColumnValues( dst );
    540                        }
    541
    542                        table.setValues( dst,rowNo[i] );
    543                        table.setRowWritable( rowNo[i],true );
    544                        table.setRowChecked(  rowNo[i],true );
    545                }
    546        }
    547
    548        /**
    549         * DBTableModelの行を変更します。
    550
    551         * @og.rev 4.3.4.6 (2009/01/15) 画面遷移なし登録で既に改廃Cがセットされている場合は、columnSetタグの処理を行わない。
    552         *
    553         */
    554        private void change() {
    555                for( int i=0; i<rowNo.length; i++ ) {
    556                        final String[] src = table.getValues( rowNo[i] );
    557                        String[] dst = new String[ table.getColumnCount() ];
    558                        System.arraycopy( src,0,dst,0,dst.length );
    559
    560                        // 4.3.4.6 (2009/01/15)
    561                        if( !( noTransition && table.getModifyType( rowNo[i] ) != null && table.getModifyType( rowNo[i] ).length() > 0 ) ){
    562                                dst = setColumnValues( dst );
    563                        }
    564
    565                        table.setValues( dst,rowNo[i] );
    566                }
    567        }
    568
    569        /**
    570         * DBTableModelの行を削除します。
    571         *
    572         * @og.rev 3.5.4.2 (2003/12/15) DELETE時にも値の書き換えができるようにします。
    573         * @og.rev 4.3.4.6 (2009/01/15) 画面遷移なし登録で既に改廃Cがセットされている場合は、columnSetタグの処理を行わない。
    574         *
    575         */
    576        private void delete() {
    577                for( int i=0; i<rowNo.length; i++ ) {
    578                        // 3.5.4.2 (2003/12/15) 書き換え処理を追加
    579                        final String[] src = table.getValues( rowNo[i] );
    580                        String[] dst = new String[ table.getColumnCount() ];
    581                        System.arraycopy( src,0,dst,0,dst.length );
    582
    583                        // 4.3.4.6 (2009/01/15)
    584                        if( !( noTransition && table.getModifyType( rowNo[i] ) != null && table.getModifyType( rowNo[i] ).length() > 0 ) ){
    585                                dst = setColumnValues( dst );
    586                        }
    587
    588                        table.rowDelete( dst,rowNo[i] );
    589                        table.setRowWritable( rowNo[i],true );
    590                        table.setRowChecked( rowNo[i],true );
    591                }
    592        }
    593
    594        /**
    595         * リクエスト情報から、セットされたカラム名と値を取り出し、設定します。
    596         *
    597         * 設定値は、個々のキー＋"__" ＋ 行番号 です。
    598         * よって、値は,一つだけ設定されています。
    599         *
    600         * @og.rev 3.5.3.1 (2003/10/31) チェックボックスカラムを指定します。
    601         * @og.rev 3.6.0.6 (2004/10/22) chboxNames 属性は廃止します。
    602         * @og.rev 5.6.1.2 (2013/02/22) setRequestValuesメソッドの互換性の対応。
    603         */
    604        private void entry() {
    605                if( rowNo.length > 0 ) {
    606                        setRequestValues( false );              // 5.6.1.2 (2013/02/22) 互換性
    607                        for( int i=0; i<rowNo.length; i++ ) {
    608                                final String[] src = table.getValues( rowNo[i] );
    609                                String[] dst = new String[ table.getColumnCount() ];
    610                                System.arraycopy( src,0,dst,0,dst.length );
    611                                dst = setColumnValues( dst );
    612
    613                                table.setValues( dst,rowNo[i] );
    614                                table.setRowWritable( rowNo[i],true );
    615                                table.setRowChecked(  rowNo[i],true );
    616                        }
    617                }
    618        }
    619
    620        /**
    621         * リクエスト情報のテーブルモデルデータを、リセットします。
    622         *
    623         * @og.rev 5.6.5.2 (2013/06/21) 行ループを 0～最終行の 降順で廻します。
    624         * @og.rev 6.9.3.1 (2018/04/02) RESET時に、must,mustAny属性をクリアします。
    625         */
    626        private void reset() {
    627                for( int i=rowNo.length-1; i>=0; i-- ) {
    628                        table.resetRow( rowNo[i] );
    629                }
    630                table.addMustType( -1,"clear" );                        // 6.9.3.1 (2018/04/02) RESET時に、must,mustAny属性をクリアします。
    631        }
    632
    633        /**
    634         * テーブルモデルデータを、全件リセットします。
    635         *
    636         * @og.rev 3.5.6.3 (2004/07/12) 新規作成
    637         * @og.rev 5.6.5.2 (2013/06/21) 行ループを 0～最終行の 降順で廻します。
    638         * @og.rev 6.2.6.0 (2015/06/19) 行ループを 0～最終行の 降順で廻してなかった。
    639         * @og.rev 6.9.3.1 (2018/04/02) RESET時に、must,mustAny属性をクリアします。
    640         */
    641        private void allReset() {
    642                final int rowCount = table.getRowCount();
    643                for( int row=rowCount-1; row>=0; row-- ) {
    644                        table.resetRow( row );
    645                }
    646                table.addMustType( -1,"clear" );                        // 6.9.3.1 (2018/04/02) RESET時に、must,mustAny属性をクリアします。
    647        }
    648
    649        /**
    650         * DBTableModelの全ての行に対して,値をセットします。
    651         *
    652         * @og.rev 5.6.5.2 (2013/06/21) 行ループを 0～最終行の 降順で廻します。
    653         * @og.rev 6.2.6.0 (2015/06/19) 行ループを 0～最終行の 降順で廻してなかった。
    654         */
    655        private void allAction() {
    656                final int rowCount = table.getRowCount();
    657                for( int row=rowCount-1; row>=0; row-- ) {
    658                        final String[] src = table.getValues( row );
    659                        String[] dst = new String[ table.getColumnCount() ];
    660                        System.arraycopy( src,0,dst,0,dst.length );
    661                        dst = setColumnValues( dst );
    662
    663                        table.setValues( dst,row );
    664                        table.setRowWritable( row,true );
    665                        table.setRowChecked(  row,true );
    666                }
    667        }
    668
    669        /**
    670         * リクエスト情報のテーブルモデルデータを、リセットします。
    671         * (但し、リセットされた行は、チェックされた状態のままになります)
    672         *
    673         * @og.rev 4.3.3.0 (2008/10/01) 新規作成
    674         * @og.rev 5.6.5.2 (2013/06/21) 行ループを 0～最終行の 降順で廻します。
    675         * @og.rev 6.2.6.0 (2015/06/19) 行ループを 0～最終行の 降順で廻してなかった。
    676         */
    677        private void resetData() {
    678                for( int i=rowNo.length-1; i>=0; i-- ) {
    679                        final String cdkh = table.getModifyType( rowNo[i] );
    680                        table.resetRow( rowNo[i] );
    681                        // 更新又は、削除の時のみ書き込み可能になる。
    682                        if( DBTableModel.UPDATE_TYPE.equals( cdkh ) || DBTableModel.DELETE_TYPE.equals( cdkh ) ) {
    683                                table.setRowWritable( rowNo[i],true );
    684                                table.setRowChecked(  rowNo[i],true );
    685                        }
    686                }
    687        }
    688
    689        /**
    690         * DBTableModelに行を追加します。(1行のみ)
    691         *
    692         * 行が選択されているかどうかに関わらず、1行のみを追加します。
    693         * (動きとしては、行が選択されていない状態でINSERTコマンドを発行した場合と同じです)
    694         *
    695         * @og.rev 5.1.5.0 (2010/04/01) 新規作成
    696         *
    697         */
    698        private void insertOne() {
    699                rowNo = new int[0];
    700                insert();
    701        }
    702
    703        /**
    704         * DBTableModelの行を物理削除します。
    705         *
    706         * 通常のデータベース等で削除する場合は、DELETE行も残しておかないと、どの行を削除するか
    707         * 判らなくなります。また、アプリケーションによっては、削除ではなく、フラグだけを立てる
    708         * ケースもあるため、現在の commend="DELETE" では、論理削除＋値の書き換えも可能になっています。
    709         * ここでの物理削除は、WriteTable など、ファイル出力時には、その行そのものをなくしておくほうが
    710         * 良いケースがあるためです。
    711         *
    712         * @og.rev 5.1.6.0 (2010/05/01) REALDELETE コマンドを追加する。
    713         */
    714        private void realDelete() {
    715                // 逆順にしないと、行番号がずれてしまう。
    716                for( int i=rowNo.length-1; i>=0; i-- ) {
    717                        table.removeValue( rowNo[i] );
    718                }
    719        }
    720
    721        /**
    722         * リクエスト情報から、セットされたカラム名と値を取り出し、設定します。
    723         *
    724         * 設定値は、個々のキー＋"__" ＋ 行番号 です。
    725         * ENTRYコマンドとの違いは、h_rowSel と無関係に、リクエストされた変数すべてを
    726         * 処理します。
    727         *
    728         * @og.rev 5.6.1.2 (2013/02/22) 新規追加
    729         */
    730        private void reqEntry() {
    731                setRequestValues( true );       // リクエストされた変数すべてを処理
    732                final int rowCount = table.getRowCount();
    733                for( int row=0; row<rowCount; row++ ) {
    734                        final String[] src = table.getValues( row );
    735                        String[] dst = new String[ table.getColumnCount() ];
    736                        System.arraycopy( src,0,dst,0,dst.length );
    737                        dst = setColumnValues( dst );
    738
    739                        table.setValues( dst,row );
    740                        table.setRowWritable( row,true );
    741                        table.setRowChecked(  row,true );
    742                }
    743        }
    744
    745        /**
    746         * DBTableModelに直接データをセットします。
    747         *
    748         * 改廃コードは付きません。
    749         *
    750         * @og.rev 7.2.9.0 (2020/10/12) RAWSET コマンドを追加する。
    751         */
    752        private void rawSet() {
    753                if( rowNo.length > 0 ) {
    754                        setRequestValues( false );              // 5.6.1.2 (2013/02/22) 互換性
    755                        for( int i=0; i<rowNo.length; i++ ) {
    756                                final String[] src = table.getValues( rowNo[i] );
    757                                setColumnValues( src );
    758                        }
    759                }
    760        }
    761
    762        /**
    763         * リクエスト情報から、セットされたカラム名と値を取り出し、設定します。
    764         *
    765         * 設定値は、個々のキー＋"__" ＋ 行番号 です。
    766         * よって、値は,一つだけ設定されています。
    767         * 引数のフラグは、選択行番号に関係なく、全件処理するかどうか[true:する/false:しない]を指定できます。
    768         *
    769         * @og.rev 3.1.0.0 (2003/03/20) 名前と行番号の区切り記号を "^" から "__" に変更。
    770         * @og.rev 3.5.5.0 (2004/03/12) 名前と行番号の区切り記号("__")を、HybsSystem.JOINT_STRING  に変更。
    771         * @og.rev 3.6.0.6 (2004/10/22) chboxNames 属性は廃止します。
    772         * @og.rev 3.8.0.1 (2005/06/17) チェックボックス対応で、エラーチェックをPL/SQLで行う場合の処理機能の追加
    773         * @og.rev 3.8.0.2 (2005/07/11) チェックボックス対応で、判定を DBColumnのgetEditor()を使用します
    774         * @og.rev 4.0.0.0 (2006/09/31) strictCheck 追加。
    775         * @og.rev 4.3.7.3 (2009/06/22) HSQLDB対応でリクエストが空文字の場合はnull文字に変換する
    776         * @og.rev 5.0.0.2 (2009/09/15) XSS対応(ALLはチェックしない)
    777         * @og.rev 5.6.1.2 (2013/02/22) isAllRow 引数追加
    778         *
    779         * @param isAllRows 全件処理 [true:する/false:しない]
    780         */
    781        private void setRequestValues( final boolean isAllRows ) {
    782                final Enumeration<?> enume = getParameterNames();               // 4.3.3.6 (2008/11/15) Generics警告対応
    783
    784                while( enume.hasMoreElements() ) {
    785                        final String key  = (String)(enume.nextElement());
    786                        final int    idx  = key.lastIndexOf(HybsSystem.JOINT_STRING);
    787
    788                        if( idx > 0 ) {
    789                                final String    column  = key.substring(0,idx);
    790                                final int               clmNo   = table.getColumnNo( column,strictCheck );
    791                                if( clmNo < 0 ) { continue; }   // strictCheck 対応
    792                                final DBColumn dbColumn = table.getDBColumn( clmNo );
    793                                final int      row      = Integer.parseInt( key.substring(idx + 2) );
    794                                // 5.0.0.2 (2009/09/15) 文字種別ALLはXSSチェックしない
    795                                // String   val      = dbColumn.valueSet( getRequestValue( key ) );
    796                                String   val = null;
    797                                if( "ALL".equals( dbColumn.getDbType() ) ){
    798                                        val = dbColumn.valueSet( getRequestValue( key, false ) );
    799                                }
    800                                else{
    801                                        val = dbColumn.valueSet( getRequestValue( key ) );
    802                                }
    803
    804                                // 3.6.0.6 (2004/10/22) チェックボックスはマルチでデータが来ます。
    805                                // 3.8.0.2 (2005/07/11) 判定を DBColumnのgetEditor()を使用
    806                                if( "0".equals(val) && "CHBOX".equals( dbColumn.getEditor() ) ) {
    807                                        final String[] vals = getRequestValues( key );
    808                                        if( vals != null ) {
    809                                                for( int i=0; i<vals.length; i++ ) {
    810                                                        if( "1".equals( vals[i] ) ) { val = "1"; break; }
    811                                                }
    812                                        }
    813                                }
    814
    815                                // 5.6.1.2 (2013/02/22) リクエスト変数すべてのデータを設定
    816                                if( isAllRows ) {
    817                                        // 4.3.7.3 (2009/06/22) HSQLDB対応
    818                                        if( val != null && val.isEmpty() ){
    819                                                val = null;
    820                                        }
    821                                        table.setValue(row, column, val );
    822                                }
    823                                // 従来のロジック(チェックを外してSUBMITするケースを想定している。)
    824                                else {
    825                                        // rowNo は、getParameterRows メソッドでソートされているので、
    826                                        // java.util.Arrays#binarySearch(int[] a, int key) が使えるはず。
    827                                        // 十分にテストしていないため、今は変更しない。
    828                                        for( int i=0; i<rowNo.length; i++ ) {
    829                                                if( rowNo[i] == row ) {
    830                                                        // 4.3.7.3 (2009/06/22) HSQLDB対応
    831                                                        if( val != null && val.isEmpty() ){
    832                                                                val = null;
    833                                                        }
    834                                                        table.setValue(row, column, val );
    835                                                }
    836                                        }
    837                                }
    838                        }
    839                }
    840        }
    841
    842        /**
    843         * 変換タイプを考慮した変換処理を行います。
    844         *
    845         * 変換タイプ(#:ﾗﾍﾞﾙ $:ﾚﾝﾃﾞﾗｰ !:値そのもの)は、カラム名の先頭に付けます。
    846         *
    847         * @og.rev 7.2.9.0 (2020/10/12) type(#,$,!)を考慮した関数型I/F対応
    848         *
    849         * @param val   変換元の文字列
    850         * @param type  変換タイプ(#:ﾗﾍﾞﾙ $:ﾚﾝﾃﾞﾗｰ !:値そのもの)
    851         * @param prm   ラベル変換時のパラメータ
    852         * @param clmNo ﾚﾝﾃﾞﾗｰ作成時のカラム番号(DBColumnをDBTableModelから取得するのに使用する)
    853         *
    854         * @return      変更後の文字列
    855         */
    856        private String getFormtVal( final String val, final char type, final String prm, final int clmNo ) {
    857                final String rtn ;
    858                switch( type ) {
    859                        case '#' :      if( prm == null || prm.isEmpty() ) { rtn = getLabel( val ) ; }
    860                                                else { rtn = getLabel( val + ' ' + prm ) ; }
    861                                                break;
    862                        case '$' :      final DBColumn dbColumn = table.getDBColumn( clmNo );
    863                                                rtn = dbColumn.getRendererValue( val ) ;
    864                                                break;
    865                        case '!' :      rtn = val ; break;
    866                        default  :      rtn = val ; break ;
    867                }
    868                return rtn ;
    869        }
    870
    871        /**
    872         * ColumnSetTag で指定された条件を元に、その行の値を書き換えます。
    873         *
    874         * @og.rev 3.6.0.6 (2004/10/22) conditionKey と、 conditionList 属性を追加
    875         * @og.rev 3.8.1.5 (2006/03/30) writableControl を使用したカラムデータの先頭アンダーバーを削除します。
    876         * @og.rev 4.0.0.0 (2006/09/31) strictCheck 追加。
    877         * @og.rev 4.3.7.3 (2009/06/22) HSQLDB対応で空文字→NULL
    878         * @og.rev 5.6.5.2 (2013/06/21) valueの初期値を利用して、１レコードごとに、＋１した値をセットします。
    879         * @og.rev 5.7.8.0 (2014/07/04) actionExec の引数を columnId ではなく、DBColumnオブジェクト に変更します。
    880         * @og.rev 6.4.3.4 (2016/03/11) Formatterに新しいコンストラクターを追加する。
    881         * @og.rev 6.9.9.0 (2018/08/20) action に、TBLNULLSETを追加。
    882         * @og.rev 7.2.9.0 (2020/10/12) type(#,$,!)を考慮した関数型I/F対応
    883         *
    884         * @param       val 指定行データ配列
    885         *
    886         * @return      変更後の指定行データ配列
    887         */
    888        private String[] setColumnValues( final String[] val ) {
    889                if( values != null ) {
    890                        final int size = values.size();
    891                        for( int i=0; i<size; i++ ) {
    892                                final Attributes attri = values.get( i );
    893                                final String columnId = attri.get( "columnId" );
    894                                final int clmNo = table.getColumnNo( columnId,strictCheck );
    895                                if( clmNo < 0 ) { continue; }   // strictCheck 対応
    896                                final String action = attri.get( "action" );
    897                                final String newVal = attri.get( "value"  );
    898                                final String oldVal = val[clmNo];
    899
    900                                // 3.6.0.6 (2004/10/22) 条件による処理の実行可否判定
    901                                final String conditionList = attri.get( "conditionList" );
    902                                if( conditionList != null ) {   // null の場合は、無条件実行
    903                                        final String conditionKey = attri.get( "conditionKey" );
    904                                        final int condClmNo = table.getColumnNo( conditionKey );
    905                                        final String condValue = "|" + val[condClmNo] + "|";
    906                                        if( conditionList.indexOf( condValue ) < 0 ) {
    907                                                continue;
    908                                        }
    909                                }
    910
    911                                if( ACT_COPY.equals( action ) ) {
    912                                        final int copyClmNo = table.getColumnNo( newVal );                              // newVal はコピー元カラム名
    913                                        val[clmNo] = val[copyClmNo];
    914                                }
    915                                else if( ACT_TBLSET.equals( action ) ) {
    916                                        final ArrayDataModel model = new ArrayDataModel( table.getNames() );
    917                                        model.setValues( val,0 );
    918                                        final Formatter format = new Formatter( model,newVal );                 // 6.4.3.4 (2016/03/11)
    919//                                      val[clmNo] = format.getFormatString( 0 );
    920                                        val[clmNo] = format.getFormatString( 0,null,(vl,tp,pm) -> getFormtVal(vl,tp,pm,clmNo) );                // 7.2.9.0 (2020/10/12)
    921                                }
    922                                // 6.9.9.0 (2018/08/20) action に、TBLNULLSETを追加。
    923                                else if( ACT_TBLNULLSET.equals( action ) ) {
    924                                        if( val[clmNo] == null || val[clmNo].isEmpty() ) {
    925                                                final ArrayDataModel model = new ArrayDataModel( table.getNames() );
    926                                                model.setValues( val,0 );
    927                                                final Formatter format = new Formatter( model,newVal );         // 6.4.3.4 (2016/03/11)
    928//                                              val[clmNo] = format.getFormatString( 0 );
    929                                                val[clmNo] = format.getFormatString( 0,null,(vl,tp,pm) -> getFormtVal(vl,tp,pm,clmNo) );        // 7.2.9.0 (2020/10/12)
    930                                        }
    931                                }
    932                                // 3.8.1.5 (2006/03/30) writableControl を使用したカラムデータの先頭アンダーバーを削除します。
    933                                else if( ACT_WRTCTRL.equals( action ) ) {
    934                                        if( StringUtil.startsChar( oldVal , '_' ) ) {                                   // 6.2.0.0 (2015/02/27) １文字 String.startsWith
    935                                                val[clmNo] = oldVal.substring( 1 );
    936                                        }
    937                                }
    938                                // 3.8.5.3 (2006/08/07) DBMENUでパラメータ設定(コロン連結文字)を使用したカラムデータの先頭データのみにします。
    939                                else if( ACT_DBMENU.equals( action ) ) {
    940                                        if( oldVal != null && oldVal.length() > 0 ) {
    941                                                final int adrs = oldVal.indexOf( ':' );
    942                                                if( adrs >= 0 ) {
    943                                                        val[clmNo] = oldVal.substring( 0,adrs );
    944                                                }
    945                                        }
    946                                }
    947                                // 5.4.2.1 (2011/12/09) valueで指定したカラムの値をキーに、リクエスト変数から値を取出し、セットします。
    948                                else if( ACT_REQSET.equals( action ) ) {
    949                                        if( newVal != null && newVal.length() > 0 ) {
    950                                                final int reqClmNo = table.getColumnNo( newVal );       // newVal はリクエスト取得元カラム名
    951                                                String reqClm = val[reqClmNo];                          // この時点では、コロン引数が付いている可能性がある。
    952
    953                                                final int adrs = reqClm.indexOf( ':' );                 // 先頭がカラム名
    954                                                if( adrs >= 0 ) {
    955                                                        reqClm = reqClm.substring( 0,adrs );    // コロンより前方の分だけ取り出す。
    956                                                }
    957                                                val[clmNo] = getRequestValue( reqClm );
    958                                        }
    959                                }
    960                                // 5.6.5.2 (2013/06/21) valueの初期値を利用して、１レコードごとに、＋１した値をセットします。
    961                                else if( ACT_SEQSET.equals( action ) ) {
    962                                        int intVal = seqsetCnt ;
    963                                        if( newVal != null && newVal.length() > 0 ) {
    964                                                intVal += Integer.parseInt( newVal );           // value の設定値
    965                                        }
    966                                        val[clmNo] = String.valueOf( intVal );
    967                                }
    968                                else {
    969                                        // 5.7.8.0 (2014/07/04) actionExec の引数を columnId ではなく、DBColumnオブジェクト に変更します。
    970                                        final DBColumn dbClm = table.getDBColumn( clmNo );
    971                                        val[clmNo] = actionExec( action,dbClm,oldVal,newVal );
    972                                }
    973
    974                                // 4.3.7.3 (2009/06/22) HSQLDB対応
    975                                if( val[clmNo] != null && val[clmNo].isEmpty()){
    976                                        val[clmNo] = null;
    977                                }
    978                        }
    979                }
    980                seqsetCnt ++ ;          // // 5.6.5.2 (2013/06/21) SEQSET のカウンター。
    981
    982                return val;
    983        }
    984
    985        /**
    986         * アクションを実行します。
    987         *
    988         * アクションは,指定のアクションコマンドに対応する処理を入力データに対して行います。
    989         *
    990         * @og.rev 3.4.0.3 (2003/09/10) NULLSET Action を追加します。
    991         * @og.rev 5.6.0.3 (2012/01/24) ADD Action に、value引数の値を加算する機能を追加します。
    992         * @og.rev 5.6.6.1 (2013/07/12) action に、PREFIX,SUFIX を追加します。
    993         * @og.rev 5.7.8.0 (2014/07/04) columnId ではなく、DBColumnオブジェクト に変更します。
    994         *
    995         * @param   action アクションコマンド
    996         * @param   dbColumn DBColumnオブジェクト
    997         * @param   oldValue 入力データ(旧データ)
    998         * @param   newValue 入力データ(新データ)
    999         *
    1000         * @return      実行後のデータ
    1001         * @see         <a href="../../../../constant-values.html#org.opengion.hayabusa.taglib.EntryTag.ACT_DEFAULT">アクション定数</a>
    1002         */
    1003        private String actionExec( final String action,final DBColumn dbColumn,final String oldValue,final String newValue ) {
    1004                String rtnVal = oldValue;
    1005
    1006                if( ACT_DEFAULT.equals(    action ) ) { rtnVal = dbColumn.getDefault(); }
    1007                else if( ACT_CLEAR.equals( action ) ) { rtnVal = ""; }
    1008                else if( ACT_SET.equals(   action ) ) { rtnVal = dbColumn.valueSet( newValue ); }
    1009                else if( ACT_ADD.equals(   action ) ) { rtnVal = dbColumn.valueAdd( oldValue,newValue ); }      // 5.6.0.3 (2012/01/24)
    1010                else if( ACT_LOWER.equals( action ) ) {
    1011                        if( oldValue == null ) { rtnVal = dbColumn.getDefault();  }
    1012                        else                   { rtnVal = oldValue.toLowerCase(Locale.JAPAN); }
    1013                }
    1014                else if( ACT_UPPER.equals( action ) ) {
    1015                        if( oldValue == null ) { rtnVal = dbColumn.getDefault();  }
    1016                        else                   { rtnVal = oldValue.toUpperCase(Locale.JAPAN); }
    1017                }
    1018                // 3.4.0.3 (2003/09/10) NULLSET Action を追加します。
    1019                else if( ACT_NULLSET.equals( action ) ) {
    1020                        if( oldValue == null || oldValue.isEmpty() ) {
    1021                                rtnVal = dbColumn.valueSet( newValue );
    1022                        }
    1023                }
    1024                // 5.6.6.1 (2013/07/12) PREFIX Action を追加します。
    1025                else if( ACT_PREFIX.equals( action ) ) {
    1026                        if( oldValue != null && oldValue.length() > 0 && newValue != null && newValue.length() > 0 ) {
    1027                                final int indx = oldValue.lastIndexOf( newValue );
    1028                                if( indx >= 0 ) {
    1029                                        rtnVal = oldValue.substring( 0,indx );
    1030                                }
    1031                        }
    1032                }
    1033                // 5.6.6.1 (2013/07/12) SUFIX Action を追加します。
    1034                else if( ACT_SUFIX.equals( action ) ) {
    1035                        if( oldValue != null && oldValue.length() > 0 && newValue != null && newValue.length() > 0 ) {
    1036                                final int indx = oldValue.lastIndexOf( newValue );
    1037                                if( indx >= 0 ) {
    1038                                        rtnVal = oldValue.substring( indx+1 );          // 分割記号は含まないので＋１する。
    1039                                }
    1040                        }
    1041                }
    1042                else {
    1043                        rtnVal = dbColumn.valueAction( action,oldValue,newValue );
    1044                }
    1045
    1046                if( rtnVal == null ) { rtnVal = dbColumn.getDefault(); }
    1047
    1048                return rtnVal;
    1049        }
    1050
    1051        /**
    1052         * 【TAG】指定の回数分だけ、繰り返し処理を行う回数を指定します(初期値:1)。
    1053         *
    1054         * @og.tag
    1055         * 追加や複写時に、指定の回数分だけ、処理を繰り返して、新規に行を
    1056         * 作成します。
    1057         * 繰り返しは、指定の行に対して行われ、繰り返し毎に、直前に作成された
    1058         * 行を元に処理します。これは、例えば、columnSet で、action="ADD"の場合に、
    1059         * 繰り返す毎に、ADD処理が実行されることを意味します。
    1060         * 行が指定されていない場合は、先頭空行に追加します。
    1061         * 初期値は、１回です。
    1062         *
    1063         * @og.rev 3.5.4.2 (2003/12/15) 新規追加
    1064         *
    1065         * @param       rc      繰り返し処理回数(初期値:1)
    1066         */
    1067        public void setRepeatCount( final String rc ) {
    1068                repeatCount = nval( getRequestParameter( rc ),repeatCount );
    1069        }
    1070
    1071        /**
    1072         * 【TAG】Consistency キー による整合性チェックを行うかどうか[true/false]を指定します(初期値:true)。
    1073         *
    1074         * @og.tag
    1075         * 検索結果を DBTableModel にセットする時に、整合性キーの Consistency キーを
    1076         * 作成します。これを、Viewタグでhidden出力しておき、Entryタグでデータ書き換え時に
    1077         * 整合性チェックを行います。これは、IEの戻るボタンで戻った場合に、画面の
    1078         * キーと検索結果の DBTableModel の内容が一致しない場合のエラーチェックに
    1079         * なります。
    1080         * この属性は、何らかのケースで、このエラーチェックを行いたくない場合に、
    1081         * false に設定することで、整合性チェックを行いません。
    1082         * 初期値は、true(整合性チェックを行う)です。
    1083         *
    1084         * @og.rev 3.5.5.7 (2004/05/10) 新規登録
    1085         *
    1086         * @param       ck      整合性チェック [true:行う/false:行わない]
    1087         */
    1088        public void setUseConsistency( final String ck ) {
    1089                useConsistency = nval( getRequestParameter( ck ),useConsistency );
    1090        }
    1091
    1092        /**
    1093         * DBTableModel の 整合性パラメータとリクエスト情報を比較チェックします。
    1094         * リクエスト情報は、その DBTableModel が出力された view で hidden 属性で
    1095         * 設定されます。
    1096         * 設定されるキーは、tableId が変更されていなければ、HybsSystem.CONSISTENCY_KEY です。
    1097         * 変更されていれば、HybsSystem.CONSISTENCY_KEY + tableId です。
    1098         *
    1099         * @og.rev 3.5.5.8 (2004/05/20) Consistency キー による整合性チェックを checkConsistency() に集約します。
    1100         * @og.rev 6.4.2.1 (2016/02/05) useConsistency の判定条件を見直します。
    1101         * @og.rev 6.9.8.0 (2018/05/28) consistencyKey に、tableId を考慮します。
    1102         * @og.rev 7.0.7.0 (2019/12/13) useSLabel 属性を追加。
    1103         *
    1104         * @return チェック結果  true:正常/false:異常
    1105         * @see org.opengion.hayabusa.common.HybsSystem#CONSISTENCY_KEY
    1106         */
    1107        private boolean checkConsistency() {
    1108                boolean rtn = true;
    1109
    1110                // 6.4.2.1 (2016/02/05) useConsistency の判定条件を、見直します。
    1111                if( useConsistency ) {
    1112                        // 6.9.8.0 (2018/05/28) consistencyKey に、tableId を考慮します。
    1113                        final String name       = HybsSystem.TBL_MDL_KEY.equals( tableId )
    1114                                                                        ? HybsSystem.CONSISTENCY_KEY
    1115                                                                        : HybsSystem.CONSISTENCY_KEY + tableId ;
    1116//                      final String consisKey = getRequestValue( HybsSystem.CONSISTENCY_KEY );
    1117                        final String consisKey = getRequestValue( name );                                               // 6.9.8.0 (2018/05/28)
    1118                        if( consisKey != null && consisKey.length() > 0 ) {
    1119                                if( ! consisKey.equals( table.getConsistencyKey() ) ) {
    1120                                        final ErrorMessage errMsgObj = new ErrorMessage( "Consistency Key Check Error!" );
    1121                                        errMsgObj.addMessage( 0,ErrorMessage.NG,"ERR0033.1" );                  // 画面とデータの整合性チェックでエラーが出ました。
    1122                                        errMsgObj.addMessage( 0,ErrorMessage.NG,"ERR0033.2" );                  // すでにデータは更新されている為、その画面からは登録できません。
    1123                                        errMsgObj.addMessage( 0,ErrorMessage.NG,"ERR0033.3" );                  // ブラウザの戻るボタンで戻り、登録すると、このエラーが出ます。
    1124//                                      jspPrint( TaglibUtil.makeHTMLErrorTable( errMsgObj,getResource() ) );
    1125                                        jspPrint( TaglibUtil.makeHTMLErrorTable( errMsgObj,getResource(),useSLabel ) );         // 7.0.7.0 (2019/12/13)
    1126                                        rtn = false;
    1127                                }
    1128                        }
    1129                        else {
    1130                                System.out.println( "EntryTag:Consistency Key is null" );
    1131                        }
    1132                }
    1133                return rtn ;
    1134        }
    1135
    1136        /**
    1137         * 表示データの HybsSystem.ROW_SEL_KEY を元に、選ばれた 行を処理の対象とします。
    1138         *
    1139         * @og.rev 3.8.1.1 (2005/11/21) selectedAll 追加。全件選択されたこととして、処理します。
    1140         * @og.rev 4.0.0.0 (2005/01/31) getParameterRows() を使用するように変更
    1141         *
    1142         * @return      選択行の配列
    1143         * @og.rtnNotNull
    1144         */
    1145        @Override
    1146        protected int[] getParameterRows() {
    1147                final int[] rowNo ;
    1148                if( selectedAll ) {
    1149                        final int rowCnt = table.getRowCount();         // 3.5.5.7 (2004/05/10)
    1150                        rowNo = new int[ rowCnt ];
    1151                        for( int i=0; i<rowCnt; i++ ) {
    1152                                rowNo[i] = i;
    1153                        }
    1154                } else {
    1155                        rowNo = super.getParameterRows();               // 4.0.0 (2005/01/31)
    1156                }
    1157                return rowNo ;
    1158        }
    1159
    1160        /**
    1161         * 【TAG】データを全件選択済みとして処理するかどうか[true/false]を指定します(初期値:false)。
    1162         *
    1163         * @og.tag
    1164         * 全てのデータを選択済みデータとして扱って処理します。
    1165         * 全件処理する場合に、(true/false)を指定します。
    1166         * 初期値は false です。
    1167         *
    1168         * @param  all 全件選択済み処理 [true:全件選択済み/false:通常]
    1169         */
    1170        public void setSelectedAll( final String all ) {
    1171                selectedAll = nval( getRequestParameter( all ),selectedAll );
    1172        }
    1173
    1174        /**
    1175         * 【TAG】(通常は使いません)カラムＩＤの存在チェックを行うかどうか[true/false]を指定します(初期値:true)。
    1176         *
    1177         * @og.tag
    1178         * true の場合、カラムＩＤがDBTableModel に存在しない場合は、エラーになります。
    1179         * false の場合、カラムＩＤがDBTableModel に存在しない場合は、無視します。
    1180         * これは、検索条件によって、設定されるカラムが異なる場合でも、entryタグを
    1181         * 正常に動作させたい場合に、使用します。
    1182         * 初期値は true (チェックを行う) です。
    1183         *
    1184         * @param  check 存在チェック [true:行う/false:行わない]
    1185         */
    1186        public void setStrictCheck( final String check ) {
    1187                strictCheck = nval( getRequestParameter( check ),strictCheck );
    1188        }
    1189
    1190        /**
    1191         * 【TAG】(通常は使いません)画面遷移を行わない形式の登録方法を使用するかを指定します。
    1192         *
    1193         * @og.tag
    1194         * 画面遷移なしの登録を行うかどうかを指定します。
    1195         * trueが指定された場合、entryタグでは、行の追加・複写時にDBTableModel上の最終行にデータを
    1196         * 追加します。
    1197         * 画面遷移なしモードの場合、途中行に挿入された場合、既にクライアントに出力されている
    1198         * チェックボックスの行番号や各入力フィールドの変数名との整合性を合わせるためには、
    1199         * 編集行以降の各変数値を全て再計算する必要があります。
    1200         * この処理は、レスポンス悪化に繋がるため、DBTableModel上は、中間に行の挿入を行いません。
    1201         * 但し画面表示上は、通常通り選択行の直下に行が挿入されるため、DBTableModelの順番と標準順が
    1202         * 異なります。(エンジン側では、各チェックボックスの値で行を識別しているため、問題は発生しません)
    1203         *
    1204         * この値は、og:headタグで設定値、または前画面からの値を継承するため、通常、この属性ではセットしません。
    1205         *
    1206         * @og.rev 4.3.3.0 (2008/10/01) 新規追加
    1207         * @og.rev 5.1.3.0 (2010/02/01) noTransition、ajaxSubmitのコントロールは、requestで行う。
    1208         *
    1209         * @param   noTrnstn 画面遷移を行わない形式の登録方法を使用するか
    1210         */
    1211        public void setNoTransition( final String noTrnstn ) {
    1212                setNoTransitionRequest( nval( getRequestParameter( noTrnstn ), isNoTransitionRequest() ) );
    1213        }
    1214
    1215        /**
    1216         * 【TAG】ｴﾗｰﾒｯｾｰｼﾞにSLABELを利用するかどうか[true/false]を指定します(初期値:false)。
    1217         *
    1218         * @og.tag
    1219         * 通常のｴﾗｰﾒｯｾｰｼﾞは、ﾗﾍﾞﾙ（長）が使われますが、これをﾗﾍﾞﾙ（短）を使いたい場合に、true にセットします。
    1220         * ここでのラベル（短）は、ﾀｸﾞ修飾なしの、ﾗﾍﾞﾙ（短）です。
    1221         * 標準はfalse:利用しない=ﾗﾍﾞﾙ（長）です。
    1222         * true/false以外を指定した場合はfalse扱いとします。
    1223         *
    1224         * ﾗﾍﾞﾙﾘｿｰｽの概要説明があれば表示しますが、useSLabel="true" 時は、概要説明を表示しません。
    1225         *
    1226         * @og.rev 7.0.7.0 (2019/12/13) 新規追加
    1227         *
    1228         * @param prm SLABEL利用 [true:利用する/false:利用しない]
    1229         */
    1230        public void setUseSLabel( final String prm ) {
    1231                useSLabel = nval( getRequestParameter( prm ),useSLabel );
    1232        }
    1233
    1234        /**
    1235         * このオブジェクトの文字列表現を返します。
    1236         * 基本的にデバッグ目的に使用します。
    1237         *
    1238         * @return このクラスの文字列表現
    1239         * @og.rtnNotNull
    1240         */
    1241        @Override
    1242        public String toString() {
    1243                return ToString.title( this.getClass().getName() )
    1244                                .println( "VERSION"                                     ,VERSION                                )
    1245                                .println( "tableId"                                     ,tableId                                )
    1246                                .println( "command"                                     ,command                                )
    1247                                .println( "rowNo"                               ,rowNo                          )
    1248                                .println( "repeatCount"                         ,repeatCount                    )
    1249                                .println( "useConsistency"                      ,useConsistency                 )
    1250                                .println( "selectedAll"                         ,selectedAll                    )
    1251                                .println( "strictCheck"                         ,strictCheck                    )
    1252                                .println( "noTransition"                        ,noTransition                   )
    1253                                .println( "RESET_ACTION_ALL_USE"        ,RESET_ACTION_ALL_USE   )
    1254                                .println( "Other..."                            ,getAttributes().getAttribute() )
    1255                                .fixForm().toString() ;
    1256        }
    1257}