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