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 errCode = makeMessage(); 172 } 173 // 異常 174 else { 175 rtnCode = stopError ? SKIP_PAGE : EVAL_PAGE ; 176 } 177 178 // 処理時間(queryTime)などの情報出力の有効/無効を指定します。 179 if( useTimeView ) { 180 final long dyTime = System.currentTimeMillis() - dyStart; 181 jspPrint( "<div id=\"queryTime\" value=\"" + (dyTime) + "\"></div>" ); 182 } 183 return rtnCode; 184 } 185 186 /** 187 * タグリブオブジェクトをリリースします。 188 * キャッシュされて再利用されるので、フィールドの初期設定を行います。 189 */ 190 @Override 191 protected void release2() { 192 super.release2(); 193 selectedAll = false; // データの全件選択済 194 selectedOne = false; // データの1件選択済 195 quotCheck = false; // クオートチェック 196 } 197 198 /** 199 * テーブルモデル から JSON形式 に変更します。 200 * 201 * @return JSON形式の文字列 202 */ 203 private String tbl2Json() { 204 final int[] rowNo = getParameterRows(); 205 final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE ); 206 207 if( rowNo.length > 0 ) { 208 // --------------------------------------------------------------------- 209 // 共通要求キーを設定します。 210 // 例:{"company_id":"XXXXX","user_id":"admin","session_id":"$session_id$","report_name":"YYYYY" …} 211 // --------------------------------------------------------------------- 212 setComJson(); 213 buf.append( JSONScan.map2Json( mapParam ) ); 214 215 // --------------------------------------------------------------------- 216 // 共通要求キー以外の キーを設定します。 217 // --------------------------------------------------------------------- 218 // 共通要求キーの末尾に ,"data":{ 文字列を追加します。 219 // 例:{"company_id":"XXXXX", …}を {"company_id":"XXXXX", … ,"data":{ …} に 220 buf.setLength(buf.length()-1); 221 buf.append( ",\"data\":{\n\"headers\":[\n" ); 222 223 // --------------------------------------------------------------------- 224 // テーブルモデルの列を追加します。 225 // 例:"headers": [{"display_label": "品目番号", "display": "PN"}, … ],"rows" … 226 // --------------------------------------------------------------------- 227 final DBColumn[] clms = table.getDBColumns(); 228 229 for( final DBColumn clm : clms ) { 230 // キーと値をマッピングします。 231 final Map<String,String> mapHeader = Map.of( IOR_DISP_LBL , clm.getLabel() , IOR_DISP_KEY ,clm.getName() ); 232 233 buf.append( JSONScan.map2Json( mapHeader ) ) 234 .append( ',' ); 235 } 236 237 // --------------------------------------------------------------------- 238 // テーブルモデルの行を追加します。 239 // 例:"rows": [{"cols": [1, "GEN", "20211130", 32.4, "kg"]}, … ]}} 240 // --------------------------------------------------------------------- 241 buf.setLength(buf.length()-1); 242 buf.append( "],\n\"rows\":[\n" ); 243 244 int row; 245 for( int i=0; i<rowNo.length; i++ ) { 246 row = rowNo[i]; 247 248 buf.append( i == 0 ? "{\"cols\":[" : ",\n{\"cols\":[" ); 249 for( int j=0; j<clms.length; j++ ) { 250 buf.append( '"' ) 251 .append( table.getValue( row, j ) ) 252 .append( "\"," ); 253 } 254 buf.setLength(buf.length()-1); 255 buf.append( "]}" ); 256 } 257 buf.append( "\n]}}" ); 258 } 259 return buf.toString(); 260 } 261 262 /** 263 * 表示データの HybsSystem.ROW_SEL_KEY を元に、選ばれた 行番号の 264 * 配列を返します。 265 * なにも選ばれていない場合は、サイズ0の配列を返します。 266 * 267 * @return 選ばれた 行番号 (選ばれていない場合は、サイズ0の配列を返す) 268 * @og.rtnNotNull 269 */ 270 @Override 271 protected int[] getParameterRows() { 272 final int[] rowNo; 273 if( selectedAll ) { 274 final int rowCnt = table.getRowCount(); 275 rowNo = new int[ rowCnt ]; 276 for( int i=0; i<rowCnt; i++ ) { 277 rowNo[i] = i; 278 } 279 } 280 else if( selectedOne ) { 281 rowNo = new int[] {0}; 282 } 283 else { 284 rowNo = super.getParameterRows(); 285 } 286 return rowNo; 287 } 288 289 /** 290 * 【TAG】データを全件選択済みとして処理するかどうか[true/false]を指定します(初期値:false)。 291 * 292 * @og.tag 293 * 全てのデータを選択済みデータとして扱って処理します。 294 * 全件処理する場合に、(true/false)を指定します。 295 * 初期値は false です。 296 * 297 * changeOnly よりも selectedAll="true" が優先されます。 298 * 299 * @param all データを全件選択済み [true:全件選択済み/false:通常] 300 */ 301 public void setSelectedAll( final String all ) { 302 selectedAll = nval( getRequestParameter( all ),selectedAll ); 303 } 304 305 /** 306 * 【TAG】データを1件選択済みとして処理するかどうか[true/false]を指定します(初期値:false)。 307 * 308 * @og.tag 309 * 先頭行の1件だけを選択済みとして処理します。 310 * まとめ処理のデータを処理する場合などに使われます。 311 * 初期値は false です。 312 * 313 * @param one 先頭行の1件だけを選択済みとして処理するかどうか [true:処理する/false:通常] 314 */ 315 public void setSelectedOne( final String one ) { 316 selectedOne = nval( getRequestParameter( one ),selectedOne ); 317 } 318 319 /** 320 * このオブジェクトの文字列表現を返します。 321 * 基本的にデバッグ目的に使用します。 322 * 323 * @return このクラスの文字列表現 324 * @og.rtnNotNull 325 */ 326 @Override 327 public String toString() { 328 return ToString.title( this.getClass().getName() ) 329 .println( "VERSION" ,VERSION ) 330 .fixForm().toString() 331 + CR 332 + super.toString() ; 333 } 334}