2 * Copyright (c) 2009 The openGion Project.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
13 * either express or implied. See the License for the specific language
14 * governing permissions and limitations under the License.
16 package org.opengion.hayabusa.taglib;
18 import org.opengion.hayabusa.common.HybsSystem;
19 import org.opengion.hayabusa.common.HybsSystemException;
20 import org.opengion.hayabusa.db.DBTableModel;
21 import org.opengion.hayabusa.db.Query;
22 import org.opengion.hayabusa.db.DBSysArg;
23 import org.opengion.hayabusa.db.DBUserArg;
24 import org.opengion.hayabusa.resource.GUIInfo;
25 import org.opengion.fukurou.system.DateSet; // 6.4.2.0 (2016/01/29)
26 import org.opengion.fukurou.util.ErrorMessage;
27 import org.opengion.fukurou.util.StringUtil ;
28 import org.opengion.fukurou.util.ToString; // 6.1.1.0 (2015/01/17)
29 import org.opengion.fukurou.util.ArraySet; // 6.4.3.4 (2016/03/11)
31 import static org.opengion.fukurou.util.StringUtil.nval ;
32 import static org.opengion.fukurou.system.HybsConst.BR; // 6.1.0.0 (2014/12/26) refactoring
34 import java.util.Set; // 6.4.3.4 (2016/03/11)
37 * PLSQLをCALLしてデータベースにアクセスするタグです。
38 * queryType = "JDBCPLSQL" が、標準で用意されています。
39 * queryType と 実際のJavaクラスとの関連付けは、システムリソースの Query_JDBCPLSQL 属性です。
41 * DBTableModel内のデータを 配列でPL/SQLに渡してDB登録します。
43 * ※ このタグは、Transaction タグの対象です。
46 * ●形式:<og:plsqlUpdate command="…" names="…" dbType="…" queryType="JDBCPLSQL" >{plsql(?,?,?,?,?)} <og:plsqlUpdate>
47 * ●body:あり(EVAL_BODY_BUFFERED:BODYを評価し、{@XXXX} を解析します)
51 * queryType 【TAG】Query を発行する為のクラスIDを指定します({@og.doc03Link queryType 初期値:JDBCPLSQL})
52 * command 【TAG】コマンド (NEW,RENEW)をセットします(PlsqlUpdateTag,UpdateTag の場合は、ENTRY)
53 * scope 【TAG】キャッシュする場合のスコープ[request/page/session/application]を指定します(初期値:session)
54 * maxRowCount 【TAG】(通常は使いません)データの最大読み込み件数を指定します (初期値:DB_MAX_ROW_COUNT[=1000])(0:[無制限])
55 * skipRowCount 【TAG】(通常は使いません)データの読み始めの初期値を指定します
56 * notfoundMsg 【TAG】検索結果がゼロ件の場合に表示するメッセージリソースIDを指定します(初期値:MSG0077[対象データはありませんでした])
57 * names 【TAG】PL/SQLを利用する場合の引数にセットすべき データの名称をCSV形式で複数指定します
58 * dbType 【TAG】Queryオブジェクトに渡す引数のタイプ定義(例:type名_ARRAY)
59 * selectedAll 【TAG】データを全件選択済みとして処理するかどうか[true/false]を指定します(初期値:false)
60 * tableId 【TAG】(通常は使いません)結果のDBTableModelを、sessionに登録するときのキーを指定します
61 * dbid 【TAG】(通常は使いません)Queryオブジェクトを作成する時のDB接続IDを指定します
62 * stopError 【TAG】PLSQL/SQL処理エラーの時に処理を中止するかどうか[true/false]を設定します(初期値:true)
63 * dispError 【TAG】エラー時にメッセージを表示するか[true/false]を設定します。通常はstopErrorと併用(初期値:true)
64 * tableModelCommit 【TAG】テーブルモデルの確定処理を行うかどうか[true/false]を設定します(初期値:true)
65 * useTimeView 【TAG】処理時間を表示する TimeView を表示するかどうかを指定します
66 * (初期値:VIEW_USE_TIMEBAR[={@og.value SystemData#VIEW_USE_TIMEBAR}])。
67 * useSLabel 【TAG】7.0.7.0 (2019/12/13) エラーメッセージにSLABELを利用するかどうか[true/false]を指定します(初期値:false)
68 * caseKey 【TAG】このタグ自体を利用するかどうかの条件キーを指定します(初期値:null)
69 * caseVal 【TAG】このタグ自体を利用するかどうかの条件値を指定します(初期値:null)
70 * caseNN 【TAG】指定の値が、null/ゼロ文字列 でない場合(Not Null=NN)は、このタグは使用されます(初期値:判定しない)
71 * caseNull 【TAG】指定の値が、null/ゼロ文字列 の場合は、このタグは使用されます(初期値:判定しない)
72 * caseIf 【TAG】指定の値が、true/TRUE文字列の場合は、このタグは使用されます(初期値:判定しない)
73 * debug 【TAG】デバッグ情報を出力するかどうか[true/false]を指定します(初期値:false)
75 * </og:plsqlUpdate>
78 * ・引数/プロシジャーを他のJSPから渡す場合
80 * <og:hidden name="names" value="UNIQ,USRID,ECNO,EDBN" />
81 * <og:hidden name="SQL" value="{ call RKP0271E.RK0271E( ?,?,?,?,? ) }" />
84 * command = "{@command}"
85 * names = "{@names}" →PL/SQLに渡す引数(配列)のカラム名
86 * dbType = "RK0271ARG" →PL/SQLに渡す引数(配列)の定義ファイル名
87 * queryType = "JDBCPLSQL" >
88 * {@SQL} →CALLするPL/SQL
89 * </og:plsqlUpdate>
94 * command = "{@command}"
95 * names = "UNIQ,USRID,ECNO,EDBN" →PL/SQLに渡す引数(配列)のカラム名
96 * dbType = "RK0271ARG" →PL/SQLに渡す引数(配列)の定義ファイル名
97 * queryType = "JDBCPLSQL" >
98 * { call RKP0271E.RK0271E( ?,?,?,?,? )} →CALLするPL/SQL
99 * </og:plsqlUpdate>
102 * ・RKP0271E.RK0271E( ?,?,?,?,? )の「?」の意味
103 * (RKP0271E.spc)------------------------------------------------------------
104 * CREATE OR REPLACE PACKAGE RKP0271E AS
106 * P_KEKKA OUT NUMBER -- 1個目の「?」⇒結果 0:正常 1:警告 2:異常
107 * ,P_ERRMSGS OUT ERR_MSG_ARRAY -- 2個目の「?」⇒エラーメッセージ配列
108 * ,P_NAMES IN VARCHAR2 -- 3個目の「?」⇒カラム名チェック用文字列
109 * ,P_SYSARGS IN SYSARG_ARRAY -- 4個目の「?」⇒登録条件配列(改廃(A:追加/C:変更/D:削除)等がセットされます)
110 * ,P_RK0271 IN RK0271ARG_ARRAY -- 5個目の「?」⇒登録データ配列
113 * (RK0271ARG.sql)------------------------------------------------------------
114 * DROP TYPE RK0271ARG_ARRAY;
115 * CREATE OR REPLACE TYPE RK0271ARG AS OBJECT
123 * CREATE OR REPLACE TYPE RK0271ARG_ARRAY AS VARRAY(100) OF RK0271ARG;
129 * @author Kazuhiko Hasegawa
132 public class PlsqlUpdateTag extends QueryTag {
133 /** このプログラムのVERSION文字列を設定します。 {@value} */
134 private static final String VERSION = "7.0.7.0 (2019/12/13)" ;
135 private static final long serialVersionUID = 707020191213L ;
137 /** command 引数に渡す事の出来る コマンド 登録{@value} */
138 public static final String CMD_ENTRY = "ENTRY" ;
139 // 6.4.3.4 (2016/03/11) String配列 から、Setに置き換えます。
140 private static final Set<String> COMMAND_SET = new ArraySet<>( CMD_ENTRY );
143 protected String userDBType ;
145 // 3.5.2.0 (2003/10/20) 内部オブジェクトタイプ名を システムパラメータ で定義します。
146 private static final String SYSARG = "SYSARG";
147 private boolean selectedAll ;
149 private boolean isCommit = true; // 5.5.5.2 (2012/08/10) 6.0.2.5 (2014/10/31) refactoring
154 * @og.rev 6.4.2.0 (2016/01/29) PMD refactoring. Each class should declare at least one constructor.
156 public PlsqlUpdateTag() { super(); } // これも、自動的に呼ばれるが、空のメソッドを作成すると警告されるので、明示的にしておきます。
159 * Taglibの開始タグが見つかったときに処理する doStartTag() を オーバーライドします。
161 * @og.rev 6.3.4.0 (2015/08/01) caseKey,caseVal,caseNN,caseNull,caseIf 属性対応
162 * @og.rev 6.4.3.4 (2016/03/11) String配列 から、Setに置き換えます。
167 public int doStartTag() {
168 if( !useTag() ) { return SKIP_BODY ; } // 6.3.4.0 (2015/08/01)
170 dyStart = System.currentTimeMillis();
172 table = (DBTableModel)getObject( tableId );
173 if( table == null || table.getRowCount() == 0 ||
174 ! check( command, COMMAND_SET ) ) { return SKIP_BODY ; }
176 startQueryTransaction( tableId ); // 3.6.0.8 (2004/11/19)
177 return EVAL_BODY_BUFFERED ; // Body を評価する。( extends BodyTagSupport 時)
181 * Taglibの終了タグが見つかったときに処理する doEndTag() を オーバーライドします。
183 * @og.rev 3.1.1.2 (2003/04/04) Tomcat4.1 対応。release2() を doEndTag()で呼ぶ。
184 * @og.rev 3.5.5.2 (2004/04/02) TaglibUtil.makeHTMLErrorTable メソッドを利用
185 * @og.rev 3.6.0.8 (2004/11/19) DBTableModel をセーブする時に、トランザクションチェックを行います。
186 * @og.rev 3.6.1.0 (2005/01/05) オーバーフロー時と登録件数の表示をコメントします。
187 * @og.rev 4.3.3.0 (2008/09/22) 検索結果を、"DB.ERR_CODE" キーでリクエストにセットする。
188 * @og.rev 4.3.3.0 (2008/09/22) 属性 stopError の設定により、JSP処理を中止するかどうかを制御します。
189 * @og.rev 4.3.5.7 (2009/03/22) アクセスカウント不具合対応
190 * @og.rev 6.3.4.0 (2015/08/01) caseKey,caseVal,caseNN,caseNull,caseIf 属性対応
191 * @og.rev 6.4.1.2 (2016/01/22) QueryTag.errMsgId → QueryTag.ERR_MSG_ID refactoring
192 * @og.rev 6.4.3.4 (2016/03/11) String配列 から、Setに置き換えます。
193 * @og.rev 5.9.26.1 (2017/11/10) dispError対応
194 * @og.rev 6.9.9.0 (2018/08/20) 「ERR0041:検索処理中に割り込みの検索要求がありました」エラーを、標準のErrorMessageに追加するようにします。
195 * @og.rev 7.0.7.0 (2019/12/13) useSLabel 属性を追加。
200 public int doEndTag() {
201 debugPrint(); // 4.0.0 (2005/02/28)
202 if( !useTag() ) { return EVAL_PAGE ; } // 6.3.4.0 (2015/08/01)
204 String label = BR; // 検索しなかった場合。
205 if( check( command, COMMAND_SET ) ) {
206 // 6.9.9.0 (2018/08/20) 「ERR0041:検索処理中に割り込みの検索要求がありました」エラーを、標準のErrorMessageに追加するようにします。
207 if( table != null && ! commitTableObject( tableId, table ) ) {
208 if( errMessage == null ) { errMessage = new ErrorMessage( "PlsqlUpdateTag Query Error!" ); }
209 // ERR0041:検索処理中に割り込みの検索要求がありました。処理されません。
210 errMessage.addMessage( 0,ErrorMessage.NG,"ERR0041" );
211 errCode = ErrorMessage.NG;
214 // 3.5.5.2 (2004/04/02) TaglibUtil.makeHTMLErrorTable メソッドを利用
215 // final String err = TaglibUtil.makeHTMLErrorTable( errMessage,getResource() );
216 final String err = TaglibUtil.makeHTMLErrorTable( errMessage,getResource(),useSLabel ); // 7.0.7.0 (2019/12/13)
217 if( err != null && err.length() > 0 ) {
218 if( errCode >= ErrorMessage.NG ) { // 異常の場合
221 // 6.4.1.2 (2016/01/22) QueryTag.errMsgId → QueryTag.ERR_MSG_ID refactoring
222 setSessionAttribute( ERR_MSG_ID,errMessage );
225 // 6.4.1.2 (2016/01/22) QueryTag.errMsgId → QueryTag.ERR_MSG_ID refactoring
226 removeSessionAttribute( ERR_MSG_ID );
228 // 4.3.3.0 (2008/09/22) 検索結果を、"DB.ERR_CODE" キーでリクエストにセットする。
229 setRequestAttribute( "DB.ERR_CODE", String.valueOf( errCode ) );
230 // 5.9.26.1 (2017/11/10) エラーメッセージをリクエスト変数で持つようにしておく
231 setRequestAttribute( "DB.ERR_MSG", label );
233 // // 6.9.9.0 (2018/08/20) 「ERR0041:検索処理中に割り込みの検索要求がありました」エラーを、標準のErrorMessageに追加するようにします。
234 // // 3.6.0.8 (2004/11/19) トランザクションチェックを行います。
235 // // 4.0.0.0 (2007/11/29) 入れ子if の統合
236 // if( table != null && ! commitTableObject( tableId, table ) ) {
237 // jspPrint( "PlsqlUpdateTag Query処理が割り込まれました。DBTableModel は登録しません。" );
242 // 5.9.26.1 (2017/11/10) dispErrorで表示をコントロール
247 // 4.0.0 (2005/01/31) 処理時間集計
248 final long dyTime = System.currentTimeMillis()-dyStart;
250 // 4.0.0 (2005/01/31) セキュリティチェック(データアクセス件数登録)
251 final GUIInfo guiInfo = (GUIInfo) getSessionAttribute( HybsSystem.GUIINFO_KEY );
252 executeCount = getParameterRows().length ; // 4.3.5.7 (2009/03/16) アクセス件数不具合対応。チェック行と仮定
253 if( guiInfo != null ) { guiInfo.addWriteCount( executeCount,dyTime,sql ); }
255 // 4.3.3.0 (2008/09/22) 属性 stopError の設定により、処理を中止するかを判断します。
256 return errCode >= ErrorMessage.NG && stopError ? SKIP_PAGE : EVAL_PAGE ; // 6.4.2.1 (2016/02/05) PMD refactoring. Useless parentheses.
260 * タグリブオブジェクトをリリースします。
261 * キャッシュされて再利用されるので、フィールドの初期設定を行います。
263 * @og.rev 2.0.0.4 (2002/09/27) カスタムタグの release() メソッドを、追加
264 * @og.rev 3.1.1.2 (2003/04/04) Tomcat4.1 対応。release2() を doEndTag()で呼ぶ。
265 * @og.rev 3.5.2.0 (2003/10/20) sysDBType 廃止。SYSARG は、システムパラメータ で定義します。
266 * @og.rev 5.5.5.2 (2012/08/10) isTableModelCommit追加
269 protected void release2() {
273 isCommit = true; // 5.5.5.2 (2012/08/10) 6.0.2.5 (2014/10/31) refactoring
279 * @og.rev 2.1.2.3 (2002/12/02) データベース更新時に、更新フラグをセットするように変更
280 * @og.rev 3.5.0.0 (2003/09/17) カラム名ではなく、カラム番号を先に求めておく方式に変更。
281 * @og.rev 3.5.2.0 (2003/10/20) 内部オブジェクトタイプ名を システムパラメータ で定義します。
282 * @og.rev 3.5.4.2 (2003/12/15) HTMLTableViewForm クラス名変更(⇒ ViewForm_HTMLTable)
283 * @og.rev 3.5.6.0 (2004/06/18) DBRowHeader のパッケージプライベート化に伴なう変更
284 * @og.rev 4.0.0.0 (2005/01/31) setArguments 廃止、Query#execute に、引数をすべて追加
285 * @og.rev 4.3.0.0 (2008/07/22) DBSysArgの引数に日付、PG、ユーザーIDを追加
286 * @og.rev 5.5.5.2 (2012/08/10) isTableModelCommitによるテーブルモデル確定処理のコントロール
287 * @og.rev 6.4.2.0 (2016/01/29) DateSet.getDate( String ) を利用するように修正します。
289 * @param query オブジェクト
292 protected void execute( final Query query ) {
293 if( names == null ) {
294 final String errMsg = "names 属性が、設定されていません。" + CR
296 throw new HybsSystemException( errMsg ); // 3.5.5.4 (2004/04/15) 引数の並び順変更
299 final int[] rowNo = getParameterRows();
300 final int rowCount = rowNo.length ;
302 final String[] nameArray = StringUtil.csv2Array( names );
303 final int[] clmNo = getTableColumnNo( nameArray ); // 3.5.0.0
305 final String curdate = DateSet.getDate( "yyyyMMddHHmmss" ); // 6.4.2.0 (2016/01/29)
306 final String pgid = getGUIInfoAttri( "KEY" ); // 4.3.0.0
307 final String userid = getUser().getAttribute( "ID" ); // 4.3.0.0
309 DBSysArg[] sysArg = new DBSysArg[rowCount];
310 DBUserArg[] userArg = new DBUserArg[rowCount];
311 for( int i=0; i<rowCount; i++ ) {
312 final int row = rowNo[i];
313 final String cdkh = table.getModifyType( row );
314 sysArg[i] = new DBSysArg( SYSARG,row,cdkh,curdate,pgid,userid );
315 final String[] values = getTableModelData( clmNo,row ); // 3.5.0.0
316 userArg[i] = new DBUserArg( userDBType,nameArray,values );
318 query.execute( names,userDBType + "_ARRAY",sysArg,userArg );
319 errCode = query.getErrorCode();
320 errMessage = query.getErrorMessage();
322 // 6.9.7.0 (2018/05/14) PMD These nested if statements could be combined
323 // if( errCode < ErrorMessage.NG ) { // 異常以外の場合
324 // if( isCommit ) { // 5.5.5.2 (2012/08/10) 6.0.2.5 (2014/10/31) refactoring
325 if( errCode < ErrorMessage.NG && isCommit) { // 異常以外の場合
326 for( int j=rowCount-1; j>=0; j-- ) {
327 final int row = rowNo[j];
328 if( DBTableModel.DELETE_TYPE.equals( table.getModifyType( row ) ) ) {
329 table.removeValue( row );
332 table.resetModify( row );
342 * カラム名配列(String[])より、対応するカラムNo配列(int[])を作成します。
344 * @og.rev 3.5.0.0 (2003/09/17) 新規追加
346 * @param nameArray カラム名配列(可変長引数)
350 private int[] getTableColumnNo( final String... nameArray ) {
351 int[] clmNo = new int[ nameArray.length ];
352 for( int i=0; i<clmNo.length; i++ ) {
353 clmNo[i] = table.getColumnNo( nameArray[i] );
359 * 指定の行番号の、カラムNo配列(int[])に対応した値の配列を返します。
361 * 表示データの HybsSystem.ROW_SEL_KEY を元に、選ばれた 行を
364 * @og.rev 3.5.0.0 (2003/09/17) カラム名ではなく、カラム番号を受け取るように修正。
366 * @param clmNo カラムNo配列
369 * @return 行番号とカラムNo配列に対応した、値の配列
371 private String[] getTableModelData( final int[] clmNo,final int row ) {
372 String[] values = new String[ clmNo.length ];
373 for( int i=0; i<values.length; i++ ) {
374 values[i] = table.getValue( row,clmNo[i] ) ;
375 // NUMBER タイプのキャストエラーを防ぐ為の対応
376 if( values[i] != null && values[i].isEmpty() ) { values[i] = null; }
382 * 表示データの HybsSystem.ROW_SEL_KEY を元に、選ばれた 行を処理の対象とします。
384 * @og.rev 4.0.0.0 (2005/01/31) getParameterRows() を使用するように変更
390 protected int[] getParameterRows() {
393 final int rowCnt = table.getRowCount(); // 3.5.5.7 (2004/05/10)
394 rowNo = new int[ rowCnt ];
395 for( int i=0; i<rowCnt; i++ ) {
399 rowNo = super.getParameterRows(); // 4.0.0 (2005/01/31)
405 * 【TAG】Queryオブジェクトに渡す引数のタイプ定義(例:type名_ARRAY)。
408 * ここでは、type 定義のPL/SQL名を指定します。
409 * 行を表す配列は、type名_ARRAY という名称です。
411 * @param type 定義のPL/SQL名
413 public void setDbType( final String type ) {
414 userDBType = getRequestParameter( type );
418 * 【TAG】データを全件選択済みとして処理するかどうか[true/false]を指定します(初期値:false)。
421 * 全てのデータを選択済みデータとして扱って処理します。
422 * 全件処理する場合に、(true/false)を指定します。
425 * @param all データを全件選択済み [true:全件選択済み/false:通常]
427 public void setSelectedAll( final String all ) {
428 selectedAll = nval( getRequestParameter( all ),selectedAll );
432 * 【TAG】Query を発行する為のクラスIDを指定します({@og.doc03Link queryType 初期値:JDBCPLSQL})。
435 * 引数指定のINSERT/UPDATE文を実行する場合の、queryType 属性を使用します。
436 * このタグでは、execute( String ,String , DBSysArg[] , DBUserArg[] )を実行します。
437 * 代表的なクラスとして、"JDBCPLSQL" が標準で用意されています。
439 * タグにより使用できる/出来ないがありますが、これは、org.opengion.hayabusa.db
440 * 以下の Query_**** クラスの **** を与えます。
441 * これらは、Query インターフェースを継承したサブクラスです。
442 * {@og.doc03Link queryType Query_**** クラス}
444 * @og.rev 3.5.4.2 (2003/12/15) JavaDocコメント用にメソッド追加。
446 * @param id Queryを発行する為の実クラスID
447 * @see org.opengion.hayabusa.db.Query Queryのサブクラス
448 * @see org.opengion.hayabusa.db.Query#execute( String ,String , DBSysArg[] , DBUserArg[] )
451 public void setQueryType( final String id ) {
452 super.setQueryType( nval( id,"JDBCPLSQL" ) );
456 * 【TAG】テーブルモデルに対する確定処理を行うかどうかを指定します(初期値:true)。
459 * PlsqlUpdateタグで、エラーがなかった場合は通常、テーブルモデルの改廃に従って処理が行われます。
460 * (改廃Dについては削除処理を行い、その他については改廃を元に戻す)
462 * このパラメータをfalseに指定すると、テーブルモデルに対する処理を行いません。
463 * これは、例えばPL/SQLでエラーチェックのみを行いたい場合に有効です。
466 * @og.rev 5.5.5.2 (2012/08/10) 新規作成
468 * @param flag テーブルモデルの確定処理 [true:する/false:しない]
470 public void setTableModelCommit( final String flag ) {
471 isCommit = nval( getRequestParameter( flag ),isCommit ); // 6.0.2.5 (2014/10/31) refactoring
475 * このオブジェクトの文字列表現を返します。
478 * @return このクラスの文字列表現
482 public String toString() {
483 return ToString.title( this.getClass().getName() )
484 .println( "VERSION" ,VERSION )
485 .println( "selectedAll" ,selectedAll )
486 .fixForm().toString()