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" ならば、1行分のデータを選択された行番号の次に挿入します。
044 * また、追加、変更、削除された、DBTableModelオブジェクト でも、内部には元のデータを
045 * 持っているため、command="RESET" で元の状態に戻すことが可能です。
046 *
047 * @og.formSample
048 * ●形式:
049 *       ・<og:entry command="…">
050 *             <og:columnSet command="…" />
051 *         </og:entry>
052 *       ・<og:entry command="…" />
053 *             ・・・columnSetを使わない場合でもresult.jspから次画面(insert,modify,copy.jsp等)に
054 *                にDBTableModelをもっていく場合には、必ず2を書いてください。
055 *                (取消のとき、エンジン内でDBTableModelを操作するのに使用する為)
056 * ●body:あり(EVAL_BODY_BUFFERED:BODYを評価し、{@XXXX} を解析します)
057 *
058 * ●Tag定義:
059 *   <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】(通常は使いません)カラムIDの存在チェックを行うかどうか[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 *   >   ... Body ...
076 *   </og:entry>
077 *
078 * ●使用例
079 *    <og:entry command="{@command}"  >
080 *        <og:columnSet command="{@command}" columnId="ECNO"   action="CLEAR" />
081 *        <og:columnSet command="{@command}" columnId="JYOKYO" action="SET" value="1" />
082 *    </og:entry>
083 *
084 *    <og:entry command="MODIFY" rows="1" >
085 *        <og:columnSet  command="MODIFY" columnId="key" action="TBLSET" value="[key][lang]"/>
086 *    </og:entry>
087 *
088 *    action="ADD" は、DBTypeに依存した方法で、既存の値を、+1 します。
089 *    <og:entry command="{@command}" repeatCount="5" >
090 *        <og:columnSet  command="{@command}" columnId="YKNO" action="ADD" />
091 *    </og:entry>
092 *
093 *    action="ADD" は、DBTypeに依存した方法で、既存の値に、value の値を加算します。
094 *    <og:entry command="{@command}" repeatCount="5" >
095 *        <og:columnSet  command="{@command}" columnId="YKNO" action="ADD" value="5" />
096 *    </og:entry>
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   値をクリア(ゼロストリング "" )します。
119 *      ADD     現在の値を +1 します。  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の初期値を利用して、1レコードごとに、+1した値をセットします。
132 *      PREFIX  valueの値を後ろから検索し、指定のカラム値の前半部分を取得します(記号は含みません)。
133 *      SUFIX   valueの値を後ろから検索し、指定のカラム値の後半部分を取得します(記号は含みません)。
134 *      その他  カラムのDBType の valueAction メソッドを呼び出します。自由に設定可能です。
135 *
136 *    [strictCheck属性]は、カラムIDの存在チェックを行うかどうかを指定します(初期値:true)
137 *      true    カラムIDがDBTableModel に存在しない場合は、エラーになる。
138 *      false   カラムIDが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 引数に渡す事の出来る アクションコマンド  +1 {@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) カラムIDの存在チェックを行うかどうかを指定します。
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 ) {                // 2回目以降
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の初期値を利用して、1レコードごとに、+1した値をセットします。
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,(v,t,p) -> getFormtVal(v,t,p,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,(v,t,p) -> getFormtVal(v,t,p,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) 1文字 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の初期値を利用して、1レコードごとに、+1した値をセットします。
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 );          // 分割記号は含まないので+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         * 初期値は、1回です。
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】(通常は使いません)カラムIDの存在チェックを行うかどうか[true/false]を指定します(初期値:true)。
1176         *
1177         * @og.tag
1178         * true の場合、カラムIDがDBTableModel に存在しない場合は、エラーになります。
1179         * false の場合、カラムIDが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}