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 static org.opengion.fukurou.util.StringUtil.*; 019 020import java.io.BufferedReader; 021import java.io.File; 022import java.sql.Connection; 023import java.util.HashMap; 024import java.util.Map; 025 026import org.opengion.fukurou.db.Transaction; 027import org.opengion.fukurou.db.TransactionReal; 028import org.opengion.fukurou.util.Closer ; 029import org.opengion.fukurou.util.FileUtil; 030import org.opengion.fukurou.util.StringUtil; 031import org.opengion.fukurou.xml.HybsXMLSave ; 032import org.opengion.hayabusa.common.HybsSystem; 033import org.opengion.hayabusa.common.HybsSystemException; 034import org.opengion.hayabusa.io.HybsFileOperationFactory; 035import org.opengion.hayabusa.resource.GUIInfo; 036 037/** 038 * 指定の拡張XDK形式ファイルを直接データベースに登録するデータ入力タグです。 039 * 040 * このクラスは、オラクル XDKの oracle.xml.sql.dml.OracleXMLSave クラスと 041 * ほぼ同様の目的で使用できる org.opengion.fukurou.xml.HybsXMLSave のラッパークラスです。 042 * 拡張XDK形式のXMLファイルを読み込み、データベースに INSERT します。 043 * 拡張XDK形式の元となる オラクル XDK(Oracle XML Developer's Kit)については、以下の 044 * リンクを参照願います。 045 * <a href="http://otn.oracle.co.jp/software/tech/xml/xdk/index.html" target="_blank" > 046 * XDK(Oracle XML Developer's Kit)</a> 047 * 048 * このタグでは、keys,vals を登録することにより、MLファイルに存在しないカラムを 049 * 追加したり、XMLファイルの情報を書き換えることが可能になります。 050 * 例えば、登録日や、登録者、または、テンプレートより各システムID毎に 051 * 登録するなどです。 052 * 053 * 拡張XDK形式とは、ROW 以外に、SQL処理用タグ(EXEC_SQL)を持つ XML ファイルです。 054 * また、登録するテーブル(table)を ROWSETタグの属性情報として付与することができます。 055 * (大文字小文字に注意) 056 * これは、オラクルXDKで処理する場合、無視されますので、同様に扱うことが出来ます。 057 * この、EXEC_SQL は、それそれの XMLデータをデータベースに登録する際に、 058 * SQL処理を自動的に流す為の、SQL文を記載します。 059 * この処理は、イベント毎に実行される為、その配置順は重要です。 060 * このタグは、複数記述することも出来ますが、BODY部には、1つのSQL文のみ記述します。 061 * 062 * ※ このタグは、Transaction タグの対象です。 063 * 064 * <ROWSET tableName="XX" > 065 * <EXEC_SQL> 最初に記載して、初期処理(データクリア等)を実行させる。 066 * delete from GEXX where YYYYY 067 * </EXEC_SQL> 068 * <MERGE_SQL> このSQL文で UPDATEして、結果が0件ならINSERTを行います。 069 * update GEXX set AA=[AA] , BB=[BB] where CC=[CC] 070 * </MERGE_SQL> 071 * <ROW num="1"> 072 * <カラム1>値1</カラム1> 073 * ・・・ 074 * <カラムn>値n</カラムn> 075 * </ROW> 076 * ・・・ 077 * <ROW num="n"> 078 * ・・・ 079 * </ROW> 080 * <EXEC_SQL> 最後に記載して、項目の設定(整合性登録)を行う。 081 * update GEXX set AA='XX' , BB='XX' where YYYYY 082 * </EXEC_SQL> 083 * <ROWSET> 084 * 085 * @og.formSample 086 * ●形式:<og:directXMLSave filename="[・・・]" ・・・ /> 087 * ●body:なし 088 * 089 * ●Tag定義: 090 * <og:directXMLSave 091 * dbid 【TAG】(通常は使いません)検索時のDB接続IDを指定します(初期値:DEFAULT) 092 * fileURL 【TAG】読み取り元ディレクトリ名を指定します (初期値:FILE_URL[=filetemp/]) 093 * filename 【TAG】ファイルを作成するときのファイル名をセットします (初期値:FILE_FILENAME[=file.xls]) 094 * displayMsg 【TAG】query の結果を画面上に表示するメッセージIDを指定します(初期値:MSG0040[ 件登録しました]) 095 * keys 【TAG】XMLファイルを読み取った後で指定するキーをCSV形式で複数指定します 096 * vals 【TAG】XMLファイルを読み取った後で指定する値をCSV形式で複数指定します 097 * caseKey 【TAG】このタグ自体を利用するかどうかの条件キーを指定します(初期値:null) 098 * caseVal 【TAG】このタグ自体を利用するかどうかの条件値を指定します(初期値:null) 099 * caseNN 【TAG】指定の値が、null/ゼロ文字列 でない場合(Not Null=NN)は、このタグは使用されます(初期値:true) 100 * caseNull 【TAG】指定の値が、null/ゼロ文字列 の場合は、このタグは使用されます(初期値:true) 101 * storageType 【TAG】読み取り元ストレージタイプを指定します(初期値:CLOUD_TARGET) 102 * bucketName 【TAG】読み取り元バケット名を指定します(初期値:CLOUD_BUCKET) 103 * debug 【TAG】デバッグ情報を出力するかどうか[true/false]を指定します(初期値:false) 104 * /> 105 * 106 * ●使用例 107 * <og:directXMLSave 108 * dbid = "ORCL" 接続データベースID(初期値:DEFAULT) 109 * fileURL = "{@USER.ID}" 読み取り元ディレクトリ名 110 * filename = "{@filename}" 読み取り元ファイル名 111 * displayMsg = "MSG0040" 登録完了後のメッセージ 112 * storageType = "aws" 読み取り元ストレージタイプを指定します(初期値:CLOUD_STORAGE) 113 * bucketName = "mybucket001" 読み取り元バケット名を指定します(初期値:CLOUD_BUCKET) 114 * /> 115 * 116 * @og.group ファイル入力 117 * @og.rev 4.0.0.0 (2007/03/08) 新規追加 118 * @og.rev 5.10.9.0 (2019/03/01) oota クラウドストレージ対応を追加。(Fileクラスを拡張) 119 * 120 * @version 4.0 121 * @author Kazuhiko Hasegawa 122 * @since JDK5.0, 123 */ 124public class DirectXMLSaveTag extends CommonTagSupport { 125 //* このプログラムのVERSION文字列を設定します。 {@value} */ 126 private static final String VERSION = "5.6.7.0 (2013/07/27)" ; 127 128 private static final long serialVersionUID = 567020130727L ; 129 130 private static final String ENCODE = "UTF-8"; 131 // 4.0.0.0 (2007/10/10) dbid の初期値を、"DEFAULT" から null に変更 132// private String dbid = "DEFAULT"; 133 private String dbid = null; 134 private String fileURL = HybsSystem.sys( "FILE_URL" ); // 4.0.0 (2005/01/31) 135 private String filename = HybsSystem.sys( "FILE_FILENAME" ); // ファイル名 136 private String displayMsg = "MSG0040"; // 件登録しました。 137 private String[] keys = null; 138 private String[] vals = null; 139 private long dyStart = 0; // 実行時間測定用のDIV要素を出力します。 140 private String storageType = null; // 5.10.9.0 (2019/03/01) クラウドストレージタイプ 141 private String bucketName = null; // 5.10.9.0 (2019/03/01) バケット名 142 143 /** 144 * Taglibの開始タグが見つかったときに処理する doStartTag() を オーバーライドします。 145 * 146 * @og.rev 5.6.6.1 (2013/07/12) caseKey 、caseVal 属性対応 147 * 148 * @return 後続処理の指示( SKIP_BODY ) 149 */ 150 @Override 151 public int doStartTag() { 152 // 5.6.6.1 (2013/07/12) caseKey 、caseVal 属性対応 153 if( useTag() ) { 154 dyStart = System.currentTimeMillis(); // 時間測定用 155 } 156 return( SKIP_BODY ); // Body を評価しない 157 } 158 159 /** 160 * Taglibの終了タグが見つかったときに処理する doEndTag() を オーバーライドします。 161 * 162 * @og.rev 4.0.0.0 (2007/10/18) メッセージリソース統合( getResource().getMessage ⇒ getResource().getLabel ) 163 * @og.rev 4.0.0.1 (2007/12/03) try 〜 catch 〜 finally をきちんと行う。 164 * @og.rev 5.1.9.0 (2010/08/01) Transaction 対応 165 * @og.rev 5.3.7.0 (2011/07/01) TransactionReal の引数変更 166 * @og.rev 5.5.2.6 (2012/05/25) findbugs対応。例外経路で null 値を利用することが保証されています。 167 * @og.rev 5.6.6.1 (2013/07/12) caseKey 、caseVal 属性対応 168 * @og.rev 5.6.7.0 (2013/07/27) DDL(データ定義言語:Data Definition Language)の処理件数追加 169 * 170 * @return 後続処理の指示 171 */ 172 @Override 173 public int doEndTag() { 174 debugPrint(); // 4.0.0 (2005/02/28) 175 // 5.6.6.1 (2013/07/12) caseKey 、caseVal 属性対応 176 if( !useTag() ) { return(EVAL_PAGE); } 177 178 BufferedReader reader = null; 179 final int insCnt ; 180 final int updCnt ; 181 final int delCnt ; 182 final int ddlCnt ; // 5.6.7.0 (2013/07/27) DDL処理件数追加 183 boolean errFlag = true; 184// Connection conn = null; 185 Transaction tran = null; // 5.1.9.0 (2010/08/01) Transaction 対応 186 try { 187 // 5.1.9.0 (2010/08/01) Transaction 対応 188 TransactionTag tranTag = (TransactionTag)findAncestorWithClass( this,TransactionTag.class ); 189 if( tranTag == null ) { 190// tran = new TransactionReal( dbid,getApplicationInfo() ); 191 tran = new TransactionReal( getApplicationInfo() ); // 5.3.7.0 (2011/07/01) 引数変更 192 } 193 else { 194 tran = tranTag.getTransaction(); 195 } 196// conn = ConnectionFactory.connection( dbid,getApplicationInfo() ); // 3.8.7.0 (2006/12/15) 197 198 Connection conn = tran.getConnection( dbid ); // 5.1.9.0 (2010/08/01) Transaction 対応 199 HybsXMLSave save = new HybsXMLSave( conn ); 200 if( keys != null ) { save.setAfterMap( getAfterMap() ); } 201 202 reader = getBufferedReader(); 203 save.insertXML( reader ); 204 insCnt = save.getInsertCount(); 205 updCnt = save.getUpdateCount(); 206 delCnt = save.getDeleteCount(); 207 ddlCnt = save.getDDLCount(); // 5.6.7.0 (2013/07/27) DDL処理件数追加 208// Closer.commit( conn ); 209 tran.commit(); // 5.1.9.0 (2010/08/01) Transaction 対応 210 errFlag = false; // エラーではない 211 } 212 catch( Throwable ex ) { 213// Closer.rollback( conn ); 214 if( tran != null ) { // 5.5.2.6 (2012/05/25) findbugs対応 215 tran.rollback(); // 5.1.9.0 (2010/08/01) Transaction 対応 216 } 217 throw new HybsSystemException( ex ); 218 } 219 finally { 220 if( tran != null ) { // 5.5.2.6 (2012/05/25) findbugs対応 221 tran.close( errFlag ); 222 } 223// if( errFlag ) { ConnectionFactory.remove( conn,dbid ); } // 削除 224// else { ConnectionFactory.close( conn,dbid ); } // 返却 225// Closer.connClose( conn ); 226 Closer.ioClose( reader ); 227 } 228 229 // 実行件数の表示 230 // 4.0.0 (2005/11/30) 出力順の変更。一番最初に出力します。 231 if( displayMsg != null && displayMsg.length() > 0 ) { 232 StringBuilder buf = new StringBuilder(); 233 buf.append( "INS:" ).append( insCnt ); 234 buf.append( " / UPD:" ).append( updCnt ); 235 buf.append( " / DEL:" ).append( delCnt ); 236 buf.append( " / DDL:" ).append( ddlCnt ); // 5.6.7.0 (2013/07/27) DDL処理件数追加 237// buf.append( getResource().getMessage( displayMsg ) ); 238 buf.append( getResource().getLabel( displayMsg ) ); 239 buf.append( HybsSystem.BR ); 240 241 jspPrint( buf.toString() ); 242 } 243 244 // 時間測定用の DIV 要素を出力 245 long dyTime = System.currentTimeMillis()-dyStart; 246 jspPrint( "<div id=\"queryTime\" value=\"" + (dyTime) + "\"></div>" ); // 3.5.6.3 (2004/07/12) 247 248 // 4.0.0 (2005/01/31) セキュリティチェック(データアクセス件数登録) 249 GUIInfo guiInfo = (GUIInfo)getSessionAttribute( HybsSystem.GUIINFO_KEY ); 250 if( guiInfo != null ) { guiInfo.addWriteCount( insCnt,dyTime,fileURL + filename ); } 251 252 return(EVAL_PAGE); 253 } 254 255 /** 256 * タグリブオブジェクトをリリースします。 257 * キャッシュされて再利用されるので、フィールドの初期設定を行います。 258 * 259 * @og.rev 4.0.0.0 (2007/10/10) dbid の初期値を、"DEFAULT" から null に変更 260 * @og.rev 5.10.9.0 (2019/03/01) storageType,bucketName属性を追加 261 */ 262 @Override 263 protected void release2() { 264 super.release2(); 265// dbid = "DEFAULT"; 266 dbid = null; 267 fileURL = HybsSystem.sys( "FILE_URL" ); // 4.0.0 (2005/01/31) 268 filename = HybsSystem.sys( "FILE_FILENAME" ); // ファイル名 269 displayMsg = "MSG0040"; // 件登録しました。 270 keys = null; 271 vals = null; 272 storageType = null; // 5.10.9.0 (2019/03/01) 273 bucketName = null; // 5.10.9.0 (2019/03/01) 274 } 275 276 /** 277 * BufferedReader を取得します。 278 * 279 * ここでは、一般的なファイル出力を考慮した BufferedReader を作成します。 280 * 281 * @og.rev 5.10.9.0 (2019/03/01) クラウドストレージ対応 282 * 283 * @return ファイル入力用BufferedReaderオブジェクト 284 */ 285 private BufferedReader getBufferedReader() { 286 if( filename == null ) { 287 String errMsg = "ファイル名がセットされていません。"; 288 throw new HybsSystemException( errMsg ); 289 } 290 String directory = HybsSystem.url2dir( fileURL ); 291 292 // 5.10.9.0 (2019/03/01) MODIFY 293// File file = new File( StringUtil.urlAppend( directory,filename ) ); 294 File file = HybsFileOperationFactory.create(storageType, bucketName, StringUtil.urlAppend( directory,filename)); 295 BufferedReader out = FileUtil.getBufferedReader( file,ENCODE ); 296 297 return out ; 298 } 299 300 /** 301 * BufferedReader を取得します。 302 * 303 * ここでは、一般的なファイル出力を考慮した BufferedReader を作成します。 304 * 305 * @og.rev 5.6.6.1 (2013/07/12) key が null や ゼロ文字列の場合は、Map に追加しません。 306 * 307 * @return ファイル入力用BufferedReader 308 */ 309 private Map<String,String> getAfterMap() { 310 Map<String,String> map = new HashMap<String,String>(); 311 312 for( int i=0; i<keys.length; i++ ) { 313 if( keys[i] != null && keys[i].length() > 0 ) { // 5.6.6.1 (2013/07/12) 314 map.put( keys[i],vals[i] ); 315 } 316 } 317 return map ; 318 } 319 320 /** 321 * 【TAG】(通常は使いません)検索時のDB接続IDを指定します(初期値:DEFAULT)。 322 * 323 * @og.tag 324 * 検索時のDB接続IDを指定します。初期値は、DEFAULT です。 325 * 326 * @param id データベース接続ID 327 */ 328 public void setDbid( final String id ) { 329 dbid = nval( getRequestParameter( id ),dbid ); 330 } 331 332 /** 333 * 【TAG】読み取り元ディレクトリ名を指定します 334 * (初期値:FILE_URL[={@og.value org.opengion.hayabusa.common.SystemData#FILE_URL}])。 335 * 336 * @og.tag 337 * この属性で指定されるディレクトリより、ファイルを読み取ります。 338 * 指定方法は、通常の fileURL 属性と同様に、先頭が、'/' (UNIX) または、2文字目が、 339 * ":" (Windows)の場合は、指定のURLそのままのディレクトリに、そうでない場合は、 340 * fileURL = "{@USER.ID}" と指定すると、FILE_URL 属性で指定のフォルダの下に、 341 * さらに、各個人ID別のフォルダの下より、読み取ります。 342 * (初期値:システム定数のFILE_URL[={@og.value org.opengion.hayabusa.common.SystemData#FILE_URL}])。 343 * 344 * @og.rev 4.0.0.0 (2007/11/20) 指定されたディレクトリ名の最後が"\"or"/"で終わっていない場合に、"/"を付加する。 345 * 346 * @param url ファイルURL 347 * @see org.opengion.hayabusa.common.SystemData#FILE_URL 348 */ 349 public void setFileURL( final String url ) { 350 String furl = nval( getRequestParameter( url ),null ); 351 if( furl != null ) { 352 char ch = furl.charAt( furl.length()-1 ); 353 if( ch != '/' && ch != '\\' ) { furl = furl + "/"; } 354 fileURL = StringUtil.urlAppend( fileURL,furl ); 355 } 356 } 357 358 /** 359 * 【TAG】ファイルを作成するときのファイル名をセットします 360 * (初期値:FILE_FILENAME[={@og.value org.opengion.hayabusa.common.SystemData#FILE_FILENAME}])。 361 * 362 * @og.tag 363 * ファイルを作成するときのファイル名をセットします。 364 * (初期値:システム定数のFILE_FILENAME[={@og.value org.opengion.hayabusa.common.SystemData#FILE_FILENAME}])。 365 * 366 * @param filename ファイル名 367 * @see org.opengion.hayabusa.common.SystemData#FILE_FILENAME 368 */ 369 public void setFilename( final String filename ) { 370 this.filename = nval( getRequestParameter( filename ),this.filename ); 371 } 372 373 /** 374 * 【TAG】query の結果を画面上に表示するメッセージIDを指定します(初期値:MSG0040[ 件登録しました])。 375 * 376 * @og.tag 377 * ここでは、検索結果の件数や登録された件数をまず出力し、 378 * その次に、ここで指定したメッセージをリソースから取得して 379 * 表示します。 380 * 表示させたくない場合は, displayMsg = "" をセットしてください。 381 * 初期値は、検索件数を表示します。 382 * ※ この属性には、リクエスト変数({@XXXX})は使用できません。 383 * 384 * @param id ディスプレイに表示させるメッセージ ID 385 */ 386 public void setDisplayMsg( final String id ) { 387 if( id != null ) { displayMsg = id; } 388 } 389 390 /** 391 * 【TAG】XMLファイルを読み取った後で指定するキーをCSV形式で複数指定します。 392 * 393 * @og.tag 394 * XMLファイルを読み取った後で、データを変更できます。 395 * 変更するカラム名(キー)をCSV形式で指定します。 396 * XMLファイルにキーが存在していた場合は、vals で指定の値に書き換えます。 397 * キーが存在していない場合は、ここで指定するキーと値が、データとして 398 * 追加されます。 399 * 例えば、登録日や、登録者、または、テンプレートより各システムID毎に 400 * 登録するなどの使い方を想定しています。 401 * 分解方法は、CSV変数を先に分解してから、getRequestParameter で値を取得します。 402 * こうしないとデータ自身にカンマを持っている場合に分解をミスる為です。 403 * 404 * @param key リンク先に渡すキー 405 * @see #setVals( String ) 406 */ 407 public void setKeys( final String key ) { 408 keys = getCSVParameter( key ); 409 } 410 411 /** 412 * 【TAG】XMLファイルを読み取った後で指定する値をCSV形式で複数指定します。 413 * 414 * @og.tag 415 * XMLファイルを読み取った後で、データを変更できます。 416 * 変更する値をCSV形式で指定します。 417 * XMLファイルにキーが存在していた場合は、vals で指定の値に書き換えます。 418 * キーが存在していない場合は、ここで指定するキーと値が、データとして 419 * 追加されます。 420 * 例えば、登録日や、登録者、または、テンプレートより各システムID毎に 421 * 登録するなどの使い方を想定しています。 422 * 分解方法は、CSV変数を先に分解してから、getRequestParameter で値を取得します。 423 * こうしないとデータ自身にカンマを持っている場合に分解をミスる為です。 424 * 425 * @param val keys属性に対応する値 426 * @see #setKeys( String ) 427 */ 428 public void setVals( final String val ) { 429 vals = getCSVParameter( val ); 430 } 431 432 /** 433 * 【TAG】読み取り元ストレージタイプを設定します。 434 * 435 * @og.tag 436 * ファイルを読み取り元の、ストレージタイプを設定します。 437 * 未設定の場合は、システムリソースの「CLOUD_TARGET」が参照されます。 438 * 自身のサーバを指定する場合は、「default」を設定してください。 439 * 440 * @og.rev 5.10.9.0 (2019/03/01) 新規追加 441 * 442 * @param storage ストレージタイプ 443 */ 444 public void setStorageType( final String storage ) { 445 storageType = nval( getRequestParameter( storage ), storageType ); 446 } 447 448 /** 449 * 【TAG】読み取り元バケット名を設定します。 450 * 451 * @og.tag 452 * ファイルを読み取り元の、バケット名を指定します。 453 * クラウドストレージ利用時のみ有効です。 454 * 未設定の場合は、システムリソースの「CLOUD_BUKET」が参照されます。 455 * 456 * @og.rev 5.10.9.0 (2019/03/01) 新規追加 457 * 458 * @param bucket バケット名 459 */ 460 public void setBucketName( final String bucket ) { 461 bucketName = nval( getRequestParameter( bucket ), bucketName ); 462 } 463 464 /** 465 * このオブジェクトの文字列表現を返します。 466 * 基本的にデバッグ目的に使用します。 467 * 468 * @og.rev 5.10.9.0 (2019/03/01) storageType,bucketNameを出力対象に追加。 469 * 470 * @return このクラスの文字列表現 471 */ 472 @Override 473 public String toString() { 474 return org.opengion.fukurou.util.ToString.title( this.getClass().getName() ) 475 .println( "VERSION" ,VERSION ) 476 .println( "dbid" ,dbid ) 477 .println( "fileURL" ,fileURL ) 478 .println( "filename" ,filename ) 479 .println( "displayMsg" ,displayMsg ) 480 .println( "dyStart" ,dyStart ) 481 .println( "storageType" ,storageType ) 482 .println( "bucketName" ,bucketName ) 483 .println( "Other..." ,getAttributes().getAttribute() ) 484 .fixForm().toString() ; 485 } 486}