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 java.util.Map; 019 020import org.opengion.fukurou.util.ErrorMessage; 021import org.opengion.fukurou.util.JSONScan; 022import org.opengion.fukurou.util.ToString; 023import org.opengion.hayabusa.db.DBColumn; 024import org.opengion.hayabusa.db.DBTableModel; 025 026import static org.opengion.fukurou.util.StringUtil.nval; 027 028/** 029 * IOr (Information Organizer) に接続し、データベースに追加/更新/削除を行うタグです。 030 * 031 * DBTableModel内のデータを JSON形式 の文字列に出力し、IOr へデータ登録を要求します。 032 * DBTableModel内のデータより loadFile が優先されます。 033 * 034 * 実行後にリクエストパラメータに以下の値がセットされます。 035 * DB.COUNT : 実行結果の件数 036 * DB.ERR_CODE : 実行結果のエラーコード 037 * DB.ERR_MSG : 実行結果のエラーメッセージ 038 * 039 * ※ このタグは、Transaction タグの対象です。 040 * 041 * @og.formSample 042 * ●形式: 043 * <og:iorUpdate 044 * url = "http://・・・ " 必須 045 * authURL = "http://・・・ " 必須 046 * authUserPass = "admin:******" 必須 047 * appliName = "データテーブル名" 048 * callMethod = "saveReport" 049 * /> 050 * 051 * ●Tag定義: 052 * <og:iorUpdate 053 * url ○【TAG】アクセスする URL を指定します (必須) 054 * proxyHost 【TAG】プロキシ経由で接続する場合の、プロキシホスト名を指定します 055 * proxyPort 【TAG】プロキシ経由で接続する場合の、プロキシポート番号を指定します 056 * timeout 【TAG】通信リンクのオープン時に、指定された秒単位のタイム・アウト値を使用します 057 * (初期値:URL_CONNECT_TIMEOUT[={@og.value SystemData#URL_CONNECT_TIMEOUT}]) 058 * authURL ○【TAG】JSONコードで認証するURLを指定します (必須) 059 * authUserPass ○【TAG】Basic認証を使用して接続する場合のユーザー:パスワードを指定します (必須) 060 * companyId 【TAG】企業IDを指定します 061 * appliName 【TAG】アプリケーションの名前を指定します 062 * callMethod 【TAG】関数名を指定します 063 * display 【TAG】接続の結果を表示するかどうかを指定します (初期値:false) 064 * loadFile 【TAG】ファイルからURL接続結果に相当するデータを読み取ります 065 * scope 【TAG】キャッシュする場合のスコープ[request/page/session/application]を指定します (初期値:session) 066 * selectedAll 【TAG】データを全件選択済みとして処理するかどうか[true/false]を指定します(初期値:false) 067 * selectedOne 【TAG】データを1件選択済みとして処理するかどうか[true/false]を指定します(初期値:false) 068 * displayMsg 【TAG】実行結果を画面上に表示するメッセージリソースIDを指定します (初期値:VIEW_DISPLAY_MSG[=]) 069 * tableId 【TAG】(通常は使いません)結果のDBTableModelを、sessionに登録するときのキーを指定します 070 * stopError 【TAG】処理エラーの時に処理を中止するかどうか[true/false]を設定します (初期値:true) 071 * dispError 【TAG】エラー時にメッセージを表示するか[true/false]を設定します。通常はstopErrorと併用 (初期値:true) 072 * quotCheck 【TAG】リクエスト情報の シングルクォート(') 存在チェックを実施するかどうか[true/false]を設定します 073 * (初期値:USE_SQL_INJECTION_CHECK) 074 * useTimeView 【TAG】処理時間を表示する TimeView を表示するかどうかを指定します 075 * (初期値:VIEW_USE_TIMEBAR[={@og.value SystemData#VIEW_USE_TIMEBAR}]) 076 * caseKey 【TAG】このタグ自体を利用するかどうかの条件キーを指定します (初期値:null) 077 * caseVal 【TAG】このタグ自体を利用するかどうかの条件値を指定します (初期値:null) 078 * caseNN 【TAG】指定の値が、null/ゼロ文字列 でない場合(Not Null=NN)は、このタグは使用されます (初期値:判定しない) 079 * caseNull 【TAG】指定の値が、null/ゼロ文字列 の場合は、このタグは使用されます (初期値:判定しない) 080 * caseIf 【TAG】指定の値が、true/TRUE文字列の場合は、このタグは使用されます (初期値:判定しない) 081 * debug 【TAG】デバッグ情報を出力するかどうか[true/false]を指定します (初期値:false) 082 * /> 083 * 084 * ●使用例 085 * <og:iorUpdate 086 * url = "http://・・・ " 087 * authURL = "http://・・・ " 088 * authUserPass = "admin:******" 089 * appliName = "データテーブル名" 090 * callMethod = "saveReport" 091 * /> 092 * 093 * @og.rev 8.0.2.0 (2021/11/30) 新規作成 094 * @og.group その他部品 095 * 096 * @version 8.0 097 * @author LEE.M 098 * @since JDK17.0, 099 */ 100public class IorUpdateTag extends IorQueryTag { 101 /** このプログラムのVERSION文字列を設定します。 {@value} */ 102 private static final String VERSION = "8.0.2.0 (2021/11/30)" ; 103 private static final long serialVersionUID = 802020211130L ; 104 105 private boolean selectedAll ; // データの全件選択済 106 private boolean selectedOne ; // データの1件選択済 107 private boolean quotCheck ; // クオートチェック 108 109 /** 110 * デフォルトコンストラクター 111 * 112 */ 113 public IorUpdateTag() { super(); } // これも、自動的に呼ばれるが、空のメソッドを作成すると警告されるので、明示的にしておきます。 114 115 /** 116 * Taglibの開始タグが見つかったときに処理する doStartTag() を オーバーライドします。 117 * 118 * @return 後続処理の指示 119 */ 120 @Override 121 public int doStartTag() { 122 if( useTag() ) { 123 dyStart = System.currentTimeMillis(); // 現在時刻 124 125 table = (DBTableModel)getObject( tableId ); 126 startQueryTransaction( tableId ); 127 128 if( table == null || table.getRowCount() == 0 ) { return SKIP_BODY ; } 129 130 super.quotCheck = quotCheck; 131 } 132 return SKIP_BODY; // Body を評価しない 133 } 134 135 /** 136 * Taglibの終了タグが見つかったときに処理する doEndTag() を オーバーライドします。 137 * 138 * @return 後続処理の指示 139 */ 140 @Override 141 public int doEndTag() { 142 143 debugPrint(); 144 if( !useTag() ) { return EVAL_PAGE ; } 145 146 // ユーザー:パスワード から ユーザーとパスワードを取得します。 147 checkUsrPw(); 148 149 // 読取ファイル指定無し 150 if( loadFile == null ) { 151 // テーブルモデル から JSON形式 に変更します。 152 postData = tbl2Json(); 153 } 154 // 読取ファイル指定有り 155 else { 156 // ファイル からデータを読取ります。 157 postData = outJson(); 158 } 159 160 // URLに対して応答結果を取得します。 161 rtnData = retResponse(); 162 163 int errCode = ErrorMessage.OK; // エラーコード 164 // 応答結果の HTTPステータスコード を設定します。 165 errCode = getStatus( rtnData ); 166 167 int rtnCode = EVAL_PAGE; 168 // 正常/警告 169 if( errCode < ErrorMessage.NG ) { 170 // 応答結果の 実行件数 を取得します。 171 executeCount = getCount( rtnData ); 172 if( executeCount > 0 ){ 173 // 処理後のメッセージを作成します。 174 errCode = makeMessage(); 175 } 176 } 177 // 異常 178 else { 179 rtnCode = stopError ? SKIP_PAGE : EVAL_PAGE ; 180 } 181 182 // 処理時間(queryTime)などの情報出力の有効/無効を指定します。 183 if( useTimeView ) { 184 final long dyTime = System.currentTimeMillis() - dyStart; 185 jspPrint( "<div id=\"queryTime\" value=\"" + (dyTime) + "\"></div>" ); 186 } 187 return rtnCode; 188 } 189 190 /** 191 * タグリブオブジェクトをリリースします。 192 * キャッシュされて再利用されるので、フィールドの初期設定を行います。 193 */ 194 @Override 195 protected void release2() { 196 super.release2(); 197 selectedAll = false; // データの全件選択済 198 selectedOne = false; // データの1件選択済 199 quotCheck = false; // クオートチェック 200 } 201 202 /** 203 * テーブルモデル から JSON形式 に変更します。 204 * 205 * @return JSON形式の文字列 206 */ 207 private String tbl2Json() { 208 final int[] rowNo = getParameterRows(); 209 final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE ); 210 211 if( rowNo.length > 0 ) { 212 // --------------------------------------------------------------------- 213 // 共通要求キーを設定します。 214 // 例:{"company_id":"XXXXX","user_id":"admin","session_id":"$session_id$","report_name":"YYYYY" …} 215 // --------------------------------------------------------------------- 216 setComJson(); 217 buf.append( JSONScan.map2Json( mapParam ) ); 218 219 // --------------------------------------------------------------------- 220 // 共通要求キー以外の キーを設定します。 221 // --------------------------------------------------------------------- 222 // 共通要求キーの末尾に ,"data":{ 文字列を追加します。 223 // 例:{"company_id":"XXXXX", …}を {"company_id":"XXXXX", … ,"data":{ …} に 224 buf.setLength(buf.length()-1); 225 buf.append( ",\"data\":{\n\"headers\":[\n" ); 226 227 // --------------------------------------------------------------------- 228 // テーブルモデルの列を追加します。 229 // 例:"headers": [{"display_label": "品目番号", "display": "PN"}, … ],"rows" … 230 // --------------------------------------------------------------------- 231 final DBColumn[] clms = table.getDBColumns(); 232 233 for( final DBColumn clm : clms ) { 234 // キーと値をマッピングします。 235 final Map<String,String> mapHeader = Map.of( IOR_DISP_LBL , clm.getLabel() , IOR_DISP_KEY ,clm.getName() ); 236 237 buf.append( JSONScan.map2Json( mapHeader ) ) 238 .append( ',' ); 239 } 240 241 // --------------------------------------------------------------------- 242 // テーブルモデルの行を追加します。 243 // 例:"rows": [{"cols": [1, "GEN", "20211130", 32.4, "kg"]}, … ]}} 244 // --------------------------------------------------------------------- 245 buf.setLength(buf.length()-1); 246 buf.append( "],\n\"rows\":[\n" ); 247 248 int row; 249 for( int i=0; i<rowNo.length; i++ ) { 250 row = rowNo[i]; 251 252 buf.append( i == 0 ? "{\"cols\":[" : ",\n{\"cols\":[" ); 253 for( int j=0; j<clms.length; j++ ) { 254 buf.append( '"' ) 255 .append( table.getValue( row, j ) ) 256 .append( "\"," ); 257 } 258 buf.setLength(buf.length()-1); 259 buf.append( "]}" ); 260 } 261 buf.append( "\n]}}" ); 262 } 263 return buf.toString(); 264 } 265 266 /** 267 * 表示データの HybsSystem.ROW_SEL_KEY を元に、選ばれた 行番号の 268 * 配列を返します。 269 * なにも選ばれていない場合は、サイズ0の配列を返します。 270 * 271 * @return 選ばれた 行番号 (選ばれていない場合は、サイズ0の配列を返す) 272 * @og.rtnNotNull 273 */ 274 @Override 275 protected int[] getParameterRows() { 276 final int[] rowNo; 277 if( selectedAll ) { 278 final int rowCnt = table.getRowCount(); 279 rowNo = new int[ rowCnt ]; 280 for( int i=0; i<rowCnt; i++ ) { 281 rowNo[i] = i; 282 } 283 } 284 else if( selectedOne ) { 285 rowNo = new int[] {0}; 286 } 287 else { 288 rowNo = super.getParameterRows(); 289 } 290 return rowNo; 291 } 292 293 /** 294 * 【TAG】データを全件選択済みとして処理するかどうか[true/false]を指定します(初期値:false)。 295 * 296 * @og.tag 297 * 全てのデータを選択済みデータとして扱って処理します。 298 * 全件処理する場合に、(true/false)を指定します。 299 * 初期値は false です。 300 * 301 * changeOnly よりも selectedAll="true" が優先されます。 302 * 303 * @param all データを全件選択済み [true:全件選択済み/false:通常] 304 */ 305 public void setSelectedAll( final String all ) { 306 selectedAll = nval( getRequestParameter( all ),selectedAll ); 307 } 308 309 /** 310 * 【TAG】データを1件選択済みとして処理するかどうか[true/false]を指定します(初期値:false)。 311 * 312 * @og.tag 313 * 先頭行の1件だけを選択済みとして処理します。 314 * まとめ処理のデータを処理する場合などに使われます。 315 * 初期値は false です。 316 * 317 * @param one 先頭行の1件だけを選択済みとして処理するかどうか [true:処理する/false:通常] 318 */ 319 public void setSelectedOne( final String one ) { 320 selectedOne = nval( getRequestParameter( one ),selectedOne ); 321 } 322 323 /** 324 * このオブジェクトの文字列表現を返します。 325 * 基本的にデバッグ目的に使用します。 326 * 327 * @return このクラスの文字列表現 328 * @og.rtnNotNull 329 */ 330 @Override 331 public String toString() { 332 return ToString.title( this.getClass().getName() ) 333 .println( "VERSION" ,VERSION ) 334 .fixForm().toString() 335 + CR 336 + super.toString() ; 337 } 338}