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.common.HybsSystemException; 020import org.opengion.hayabusa.resource.GUIInfo; 021import org.opengion.fukurou.db.Transaction; 022import org.opengion.fukurou.db.TransactionReal; 023import org.opengion.fukurou.util.FileUtil; 024import org.opengion.fukurou.util.Closer ; 025import org.opengion.fukurou.util.StringUtil; 026import org.opengion.fukurou.xml.HybsXMLSave ; 027 028import static org.opengion.fukurou.util.StringUtil.nval ; 029 030import java.sql.Connection; 031 032import java.io.File; 033import java.io.BufferedReader; 034import java.util.Map; 035import java.util.HashMap; 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 * debug 【TAG】デバッグ情報を出力するかどうか[true/false]を指定します(初期値:false) 102 * /> 103 * 104 * ●使用例 105 * <og:directXMLSave 106 * dbid = "ORCL" 接続データベースID(初期値:DEFAULT) 107 * fileURL = "{@USER.ID}" 読み取り元ディレクトリ名 108 * filename = "{@filename}" 読み取り元ファイル名 109 * displayMsg = "MSG0040" 登録完了後のメッセージ 110 * /> 111 * 112 * @og.group ファイル入力 113 * @og.rev 4.0.0.0 (2007/03/08) 新規追加 114 * 115 * @version 4.0 116 * @author Kazuhiko Hasegawa 117 * @since JDK5.0, 118 */ 119public class DirectXMLSaveTag extends CommonTagSupport { 120 //* このプログラムのVERSION文字列を設定します。 {@value} */ 121 private static final String VERSION = "5.6.7.0 (2013/07/27)" ; 122 123 private static final long serialVersionUID = 567020130727L ; 124 125 private static final String ENCODE = "UTF-8"; 126 // 4.0.0.0 (2007/10/10) dbid の初期値を、"DEFAULT" から null に変更 127// private String dbid = "DEFAULT"; 128 private String dbid = null; 129 private String fileURL = HybsSystem.sys( "FILE_URL" ); // 4.0.0 (2005/01/31) 130 private String filename = HybsSystem.sys( "FILE_FILENAME" ); // ファイル名 131 private String displayMsg = "MSG0040"; // 件登録しました。 132 private String[] keys = null; 133 private String[] vals = null; 134 private long dyStart = 0; // 実行時間測定用のDIV要素を出力します。 135 136 /** 137 * Taglibの開始タグが見つかったときに処理する doStartTag() を オーバーライドします。 138 * 139 * @og.rev 5.6.6.1 (2013/07/12) caseKey 、caseVal 属性対応 140 * 141 * @return 後続処理の指示( SKIP_BODY ) 142 */ 143 @Override 144 public int doStartTag() { 145 // 5.6.6.1 (2013/07/12) caseKey 、caseVal 属性対応 146 if( useTag() ) { 147 dyStart = System.currentTimeMillis(); // 時間測定用 148 } 149 return( SKIP_BODY ); // Body を評価しない 150 } 151 152 /** 153 * Taglibの終了タグが見つかったときに処理する doEndTag() を オーバーライドします。 154 * 155 * @og.rev 4.0.0.0 (2007/10/18) メッセージリソース統合( getResource().getMessage ⇒ getResource().getLabel ) 156 * @og.rev 4.0.0.1 (2007/12/03) try 〜 catch 〜 finally をきちんと行う。 157 * @og.rev 5.1.9.0 (2010/08/01) Transaction 対応 158 * @og.rev 5.3.7.0 (2011/07/01) TransactionReal の引数変更 159 * @og.rev 5.5.2.6 (2012/05/25) findbugs対応。例外経路で null 値を利用することが保証されています。 160 * @og.rev 5.6.6.1 (2013/07/12) caseKey 、caseVal 属性対応 161 * @og.rev 5.6.7.0 (2013/07/27) DDL(データ定義言語:Data Definition Language)の処理件数追加 162 * 163 * @return 後続処理の指示 164 */ 165 @Override 166 public int doEndTag() { 167 debugPrint(); // 4.0.0 (2005/02/28) 168 // 5.6.6.1 (2013/07/12) caseKey 、caseVal 属性対応 169 if( !useTag() ) { return(EVAL_PAGE); } 170 171 BufferedReader reader = null; 172 final int insCnt ; 173 final int updCnt ; 174 final int delCnt ; 175 final int ddlCnt ; // 5.6.7.0 (2013/07/27) DDL処理件数追加 176 boolean errFlag = true; 177// Connection conn = null; 178 Transaction tran = null; // 5.1.9.0 (2010/08/01) Transaction 対応 179 try { 180 // 5.1.9.0 (2010/08/01) Transaction 対応 181 TransactionTag tranTag = (TransactionTag)findAncestorWithClass( this,TransactionTag.class ); 182 if( tranTag == null ) { 183// tran = new TransactionReal( dbid,getApplicationInfo() ); 184 tran = new TransactionReal( getApplicationInfo() ); // 5.3.7.0 (2011/07/01) 引数変更 185 } 186 else { 187 tran = tranTag.getTransaction(); 188 } 189// conn = ConnectionFactory.connection( dbid,getApplicationInfo() ); // 3.8.7.0 (2006/12/15) 190 191 Connection conn = tran.getConnection( dbid ); // 5.1.9.0 (2010/08/01) Transaction 対応 192 HybsXMLSave save = new HybsXMLSave( conn ); 193 if( keys != null ) { save.setAfterMap( getAfterMap() ); } 194 195 reader = getBufferedReader(); 196 save.insertXML( reader ); 197 insCnt = save.getInsertCount(); 198 updCnt = save.getUpdateCount(); 199 delCnt = save.getDeleteCount(); 200 ddlCnt = save.getDDLCount(); // 5.6.7.0 (2013/07/27) DDL処理件数追加 201// Closer.commit( conn ); 202 tran.commit(); // 5.1.9.0 (2010/08/01) Transaction 対応 203 errFlag = false; // エラーではない 204 } 205 catch( Throwable ex ) { 206// Closer.rollback( conn ); 207 if( tran != null ) { // 5.5.2.6 (2012/05/25) findbugs対応 208 tran.rollback(); // 5.1.9.0 (2010/08/01) Transaction 対応 209 } 210 throw new HybsSystemException( ex ); 211 } 212 finally { 213 if( tran != null ) { // 5.5.2.6 (2012/05/25) findbugs対応 214 tran.close( errFlag ); 215 } 216// if( errFlag ) { ConnectionFactory.remove( conn,dbid ); } // 削除 217// else { ConnectionFactory.close( conn,dbid ); } // 返却 218// Closer.connClose( conn ); 219 Closer.ioClose( reader ); 220 } 221 222 // 実行件数の表示 223 // 4.0.0 (2005/11/30) 出力順の変更。一番最初に出力します。 224 if( displayMsg != null && displayMsg.length() > 0 ) { 225 StringBuilder buf = new StringBuilder(); 226 buf.append( "INS:" ).append( insCnt ); 227 buf.append( " / UPD:" ).append( updCnt ); 228 buf.append( " / DEL:" ).append( delCnt ); 229 buf.append( " / DDL:" ).append( ddlCnt ); // 5.6.7.0 (2013/07/27) DDL処理件数追加 230// buf.append( getResource().getMessage( displayMsg ) ); 231 buf.append( getResource().getLabel( displayMsg ) ); 232 buf.append( HybsSystem.BR ); 233 234 jspPrint( buf.toString() ); 235 } 236 237 // 時間測定用の DIV 要素を出力 238 long dyTime = System.currentTimeMillis()-dyStart; 239 jspPrint( "<div id=\"queryTime\" value=\"" + (dyTime) + "\"></div>" ); // 3.5.6.3 (2004/07/12) 240 241 // 4.0.0 (2005/01/31) セキュリティチェック(データアクセス件数登録) 242 GUIInfo guiInfo = (GUIInfo)getSessionAttribute( HybsSystem.GUIINFO_KEY ); 243 if( guiInfo != null ) { guiInfo.addWriteCount( insCnt,dyTime,fileURL + filename ); } 244 245 return(EVAL_PAGE); 246 } 247 248 /** 249 * タグリブオブジェクトをリリースします。 250 * キャッシュされて再利用されるので、フィールドの初期設定を行います。 251 * 252 * @og.rev 4.0.0.0 (2007/10/10) dbid の初期値を、"DEFAULT" から null に変更 253 */ 254 @Override 255 protected void release2() { 256 super.release2(); 257// dbid = "DEFAULT"; 258 dbid = null; 259 fileURL = HybsSystem.sys( "FILE_URL" ); // 4.0.0 (2005/01/31) 260 filename = HybsSystem.sys( "FILE_FILENAME" ); // ファイル名 261 displayMsg = "MSG0040"; // 件登録しました。 262 keys = null; 263 vals = null; 264 } 265 266 /** 267 * BufferedReader を取得します。 268 * 269 * ここでは、一般的なファイル出力を考慮した BufferedReader を作成します。 270 * 271 * @return ファイル入力用BufferedReaderオブジェクト 272 */ 273 private BufferedReader getBufferedReader() { 274 if( filename == null ) { 275 String errMsg = "ファイル名がセットされていません。"; 276 throw new HybsSystemException( errMsg ); 277 } 278 String directory = HybsSystem.url2dir( fileURL ); 279 File file = new File( StringUtil.urlAppend( directory,filename ) ); 280 281 BufferedReader out = FileUtil.getBufferedReader( file,ENCODE ); 282 283 return out ; 284 } 285 286 /** 287 * BufferedReader を取得します。 288 * 289 * ここでは、一般的なファイル出力を考慮した BufferedReader を作成します。 290 * 291 * @og.rev 5.6.6.1 (2013/07/12) key が null や ゼロ文字列の場合は、Map に追加しません。 292 * 293 * @return ファイル入力用BufferedReader 294 */ 295 private Map<String,String> getAfterMap() { 296 Map<String,String> map = new HashMap<String,String>(); 297 298 for( int i=0; i<keys.length; i++ ) { 299 if( keys[i] != null && keys[i].length() > 0 ) { // 5.6.6.1 (2013/07/12) 300 map.put( keys[i],vals[i] ); 301 } 302 } 303 return map ; 304 } 305 306 /** 307 * 【TAG】(通常は使いません)検索時のDB接続IDを指定します(初期値:DEFAULT)。 308 * 309 * @og.tag 310 * 検索時のDB接続IDを指定します。初期値は、DEFAULT です。 311 * 312 * @param id データベース接続ID 313 */ 314 public void setDbid( final String id ) { 315 dbid = nval( getRequestParameter( id ),dbid ); 316 } 317 318 /** 319 * 【TAG】読み取り元ディレクトリ名を指定します 320 * (初期値:FILE_URL[={@og.value org.opengion.hayabusa.common.SystemData#FILE_URL}])。 321 * 322 * @og.tag 323 * この属性で指定されるディレクトリより、ファイルを読み取ります。 324 * 指定方法は、通常の fileURL 属性と同様に、先頭が、'/' (UNIX) または、2文字目が、 325 * ":" (Windows)の場合は、指定のURLそのままのディレクトリに、そうでない場合は、 326 * fileURL = "{@USER.ID}" と指定すると、FILE_URL 属性で指定のフォルダの下に、 327 * さらに、各個人ID別のフォルダの下より、読み取ります。 328 * (初期値:システム定数のFILE_URL[={@og.value org.opengion.hayabusa.common.SystemData#FILE_URL}])。 329 * 330 * @og.rev 4.0.0.0 (2007/11/20) 指定されたディレクトリ名の最後が"\"or"/"で終わっていない場合に、"/"を付加する。 331 * 332 * @param url ファイルURL 333 * @see org.opengion.hayabusa.common.SystemData#FILE_URL 334 */ 335 public void setFileURL( final String url ) { 336 String furl = nval( getRequestParameter( url ),null ); 337 if( furl != null ) { 338 char ch = furl.charAt( furl.length()-1 ); 339 if( ch != '/' && ch != '\\' ) { furl = furl + "/"; } 340 fileURL = StringUtil.urlAppend( fileURL,furl ); 341 } 342 } 343 344 /** 345 * 【TAG】ファイルを作成するときのファイル名をセットします 346 * (初期値:FILE_FILENAME[={@og.value org.opengion.hayabusa.common.SystemData#FILE_FILENAME}])。 347 * 348 * @og.tag 349 * ファイルを作成するときのファイル名をセットします。 350 * (初期値:システム定数のFILE_FILENAME[={@og.value org.opengion.hayabusa.common.SystemData#FILE_FILENAME}])。 351 * 352 * @param filename ファイル名 353 * @see org.opengion.hayabusa.common.SystemData#FILE_FILENAME 354 */ 355 public void setFilename( final String filename ) { 356 this.filename = nval( getRequestParameter( filename ),this.filename ); 357 } 358 359 /** 360 * 【TAG】query の結果を画面上に表示するメッセージIDを指定します(初期値:MSG0040[ 件登録しました])。 361 * 362 * @og.tag 363 * ここでは、検索結果の件数や登録された件数をまず出力し、 364 * その次に、ここで指定したメッセージをリソースから取得して 365 * 表示します。 366 * 表示させたくない場合は, displayMsg = "" をセットしてください。 367 * 初期値は、検索件数を表示します。 368 * ※ この属性には、リクエスト変数({@XXXX})は使用できません。 369 * 370 * @param id ディスプレイに表示させるメッセージ ID 371 */ 372 public void setDisplayMsg( final String id ) { 373 if( id != null ) { displayMsg = id; } 374 } 375 376 /** 377 * 【TAG】XMLファイルを読み取った後で指定するキーをCSV形式で複数指定します。 378 * 379 * @og.tag 380 * XMLファイルを読み取った後で、データを変更できます。 381 * 変更するカラム名(キー)をCSV形式で指定します。 382 * XMLファイルにキーが存在していた場合は、vals で指定の値に書き換えます。 383 * キーが存在していない場合は、ここで指定するキーと値が、データとして 384 * 追加されます。 385 * 例えば、登録日や、登録者、または、テンプレートより各システムID毎に 386 * 登録するなどの使い方を想定しています。 387 * 分解方法は、CSV変数を先に分解してから、getRequestParameter で値を取得します。 388 * こうしないとデータ自身にカンマを持っている場合に分解をミスる為です。 389 * 390 * @param key リンク先に渡すキー 391 * @see #setVals( String ) 392 */ 393 public void setKeys( final String key ) { 394 keys = getCSVParameter( key ); 395 } 396 397 /** 398 * 【TAG】XMLファイルを読み取った後で指定する値をCSV形式で複数指定します。 399 * 400 * @og.tag 401 * XMLファイルを読み取った後で、データを変更できます。 402 * 変更する値をCSV形式で指定します。 403 * XMLファイルにキーが存在していた場合は、vals で指定の値に書き換えます。 404 * キーが存在していない場合は、ここで指定するキーと値が、データとして 405 * 追加されます。 406 * 例えば、登録日や、登録者、または、テンプレートより各システムID毎に 407 * 登録するなどの使い方を想定しています。 408 * 分解方法は、CSV変数を先に分解してから、getRequestParameter で値を取得します。 409 * こうしないとデータ自身にカンマを持っている場合に分解をミスる為です。 410 * 411 * @param val keys属性に対応する値 412 * @see #setKeys( String ) 413 */ 414 public void setVals( final String val ) { 415 vals = getCSVParameter( val ); 416 } 417 418 /** 419 * このオブジェクトの文字列表現を返します。 420 * 基本的にデバッグ目的に使用します。 421 * 422 * @return このクラスの文字列表現 423 */ 424 @Override 425 public String toString() { 426 return org.opengion.fukurou.util.ToString.title( this.getClass().getName() ) 427 .println( "VERSION" ,VERSION ) 428 .println( "dbid" ,dbid ) 429 .println( "fileURL" ,fileURL ) 430 .println( "filename" ,filename ) 431 .println( "displayMsg" ,displayMsg ) 432 .println( "dyStart" ,dyStart ) 433 .println( "Other..." ,getAttributes().getAttribute() ) 434 .fixForm().toString() ; 435 } 436}