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.db.DBErrMsg; 021import org.opengion.hayabusa.resource.GUIInfo; 022import org.opengion.hayabusa.resource.ResourceManager; 023import org.opengion.fukurou.db.Transaction; 024import org.opengion.fukurou.db.TransactionReal; 025import org.opengion.fukurou.util.ErrorMessage; 026import org.opengion.fukurou.util.FileUtil; 027import org.opengion.fukurou.util.StringUtil; 028import org.opengion.fukurou.util.Closer ; 029import static org.opengion.fukurou.util.StringUtil.nval ; 030 031import java.util.Locale ; 032 033import java.sql.Connection; 034import java.sql.Statement; 035import java.sql.CallableStatement; 036import java.sql.ResultSet; 037import java.sql.ResultSetMetaData; 038import java.sql.SQLException; 039import java.sql.Types; 040// import java.sql.Array; // 5.7.2.2 (2014/01/24) Oracle11g(11.2.0.3のドライバ) 対応。oracle.sql.ARRAY の置き換え 041import oracle.sql.ARRAY; // 5.7.2.2 (2014/01/24) Oracle11g(11.2.0.3のドライバ) 対応 042import oracle.sql.ArrayDescriptor; // 5.7.2.2 (2014/01/24) Oracle11g(11.2.0.3のドライバ) 対応 043// import oracle.jdbc.OracleConnection; // 5.7.2.2 (2014/01/24) Oracle11g(11.2.0.3のドライバ) 対応 044 045import oracle.jdbc.OracleTypes; // CURSOR が残る 046import oracle.jdbc.OracleCallableStatement; // CURSOR が残る 047 048import java.io.File; 049import java.io.PrintWriter; 050import java.io.FileOutputStream; 051import java.io.IOException; 052import java.io.ObjectOutputStream; 053import java.io.ObjectInputStream; 054import java.util.zip.ZipOutputStream; 055import java.util.zip.ZipEntry; 056 057import java.util.Map; 058 059/** 060 * SELECT文を直接実行して、指定のファイルに出力するタグです。 061 * 062 * 中間の、データ(DBTableModel)を作成しないため、余計なメモリを取らず、 063 * 高速にデータを抜き出すことが可能です。 064 * 一方、抜き出すデータは生データのため、データの再利用等、システム的な 065 * 使用を想定しています。 066 * JDBCErrMsg 形式のPL/SQL をコールして、その検索結果(カーソル)を抜きこともできます。 067 * 068 * ※ このタグは、Transaction タグの対象です。 069 * 070 * @og.formSample 071 * ●形式:<og:directWriteTable filename="[・・・]" ・・・ >SELECT * FROM ZYXX </og:directWriteTable > 072 * ●body:あり(EVAL_BODY_BUFFERED:BODYを評価し、{@XXXX} を解析します) 073 * 074 * ●Tag定義: 075 * <og:directWriteTable 076 * fileURL 【TAG】保存先ディレクトリ名を指定します (初期値:FILE_URL[=filetemp/]) 077 * filename 【TAG】ファイルを作成するときのファイル名をセットします(初期値:システムパラメータのFILE_FILENAME) 078 * zipFilename 【TAG】ZIPファイルを作成するときのZIPファイル名をセットします(初期値:filename + ".zip") 079 * encode 【TAG】ファイルを作成するときのファイルエンコーディング名をセットします (初期値:FILE_ENCODE[=UnicodeLittle]) 080 * fileAppend 【TAG】追加モードで書き込むかどうか[true/false]を指定します(初期値:false[通常モード]) 081 * zip 【TAG】結果をファイルに出力するときに、ZIPで圧縮するかどうか[true/false]を指定します(初期値:false) 082 * separator 【TAG】可変長ファイルを作成するときの項目区切り文字をセットします (初期値:TAB_SEPARATOR[= ]) 083 * useHeader 【TAG】ヘッダーを書き込むかどうか[true/false]を指定します(初期値:true) 084 * displayMsg 【TAG】検索結果を画面上に表示するメッセージリソースIDを指定します(初期値:MSG0033[ 件検索しました]) 085 * notfoundMsg 【TAG】検索結果がゼロ件の場合に表示するメッセージリソースIDを指定します(初期値:MSG0077[対象データはありませんでした]) 086 * fetchSize 【TAG】(通常は使いません)データのフェッチサイズを指定します(初期値:100) 087 * names 【TAG】PL/SQLを利用する場合の引数にセットすべき データの名称をCSV形式で複数指定します 088 * queryType 【TAG】Query を発行する為のクラスID(JDBC,JDBCErrMsg)を指定します({@og.doc03Link queryType 初期値:JDBC}) 089 * dbid 【TAG】(通常は使いません)検索時のDB接続IDを指定します(初期値:DEFAULT) 090 * useNumber 【TAG】行番号を出力するかどうか(初期値:true) 091 * debug 【TAG】デバッグ情報を出力するかどうか[true/false]を指定します(初期値:false) 092 * > ... Body ... 093 * </og:directWriteTable> 094 * 095 * ●使用例 096 * <og:directWriteTable 097 * dbid = "ORCL" 接続データベースID(初期値:DEFAULT) 098 * separator = "," ファイルの区切り文字(初期値:タブ) 099 * fileURL = "{@USER.ID}" 保存先ディレクトリ名 100 * filename = "{@filename}" 保存ファイル名 101 * encode = "UnicodeLittle" 保存ファイルエンコード名 102 * useHeader = "true" 保存ファイルにヘッダーを出力するかどうか 103 * zip = "true" ZIPファイルに圧縮するかどうか 104 * zipFilename = "Sample.zip" ZIPファイルのファイル名 105 * fileAppend = "true" ファイルを追加モードで登録するかどうか 106 * displayMsg = "MSG0033" 実行後の表示メッセージ 107 * fetchSize = "200" DB検索する場合のフェッチするサイズ 108 * > 109 * SELECT * FROM ZYXX 110 * </og:directWriteTable > 111 * 112 * <og:directWriteTable 113 * fileURL = "{@USER.ID}" 保存先ディレクトリ名 114 * filename = "{@filename}" 保存ファイル名 115 * names = "AAA,BBB,CCC,・・・" 指定のキーに対応するリクエスト値を ARG_ARRAY にセットします。 116 * queryType = "JDBCErrMsg" JDBCErrMsg 形式のPL/SQL をコールします。 117 * > 118 * { call PL/SQL(?,?,?,? ) } 119 * </og:directWriteTable > 120 * 121 * @og.rev 3.5.6.0 (2004/06/18) 新規作成 122 * @og.rev 3.6.1.0 (2005/01/05) PL/SQLコール(JDBCErrMsg 形式)の実行を追加 123 * @og.group ファイル出力 124 * 125 * @version 4.0 126 * @author Kazuhiko Hasegawa 127 * @since JDK5.0, 128 */ 129public class DirectWriteTableTag extends CommonTagSupport { 130 //* このプログラムのVERSION文字列を設定します。 {@value} */ 131 private static final String VERSION = "5.7.2.3 (2014/01/31)" ; 132 133 private static final long serialVersionUID = 572320140131L ; 134 135 private static final String TAB_SEPARATOR = "\t" ; 136 private static final String errMsgId = HybsSystem.ERR_MSG_KEY; 137 138 private final int DB_MAX_QUERY_TIMEOUT = HybsSystem.sysInt( "DB_MAX_QUERY_TIMEOUT" ) ; 139// private static final String ARG_ARRAY = HybsSystem.sys( "ARG_ARRAY" ) ; 140// private static final String ERR_MSG = HybsSystem.sys( "ERR_MSG" ) ; 141// private static final String ERR_MSG_ARRAY = HybsSystem.sys( "ERR_MSG_ARRAY" ) ; 142 private static final String ARG_ARRAY = "ARG_ARRAY" ; 143 private static final String ERR_MSG = "ERR_MSG" ; 144 private static final String ERR_MSG_ARRAY = "ERR_MSG_ARRAY" ; 145 146 // 4.0.0.0 (2007/10/10) dbid の初期値を、"DEFAULT" から null に変更 147// private String dbid = "DEFAULT"; 148 private String dbid = null; 149 private String separator = TAB_SEPARATOR; // 項目区切り文字 150 private boolean useHeader = true; // ヘッダーの使用可否 151 private String fileURL = HybsSystem.sys( "FILE_URL" ); 152 private String filename = HybsSystem.sys( "FILE_FILENAME" ); // ファイル名 153 private String zipFilename = null; // ZIPファイル名 154 private String sql = null; 155 private String encode = HybsSystem.sys( "FILE_ENCODE" ); // ファイルエンコーディング "DEFAULT","JISAutoDetect" ,"JIS", "EUC_JP", "MS932", "SJIS" , "Windows-31J" , "Shift_JIS" 156 private boolean fileAppend = false; // ファイルをAPPENDモードで出力するか 157 private boolean zip = false; // ファイルをZIPするか 158// private String displayMsg = "MSG0033"; // 件検索しました。 159 private String displayMsg = HybsSystem.sys( "VIEW_DISPLAY_MSG" ); 160 private String notfoundMsg = "MSG0077"; // 対象データはありませんでした。 161 private long dyStart = 0; // 実行時間測定用のDIV要素を出力します。 162 private int fetchSize = 100 ; // フェッチする行数(初期値:100) 163 private boolean useNumber = true; // 5.5.7.1(2012/10/05) 行番号出力 164 165 // 3.6.1.0 (2005/01/05) PL/SQLコール(JDBCErrMsg 形式)への対応 166 private boolean queryType = true; // ノーマルは、true/ JDBCErrMsg の時は、false 167 private String names = null; // 指定のリクエスト変数を、ARG_ARRAY にセットします。 168 private int errCode = ErrorMessage.OK; 169 private transient ErrorMessage errMessage = null; 170 171 /** 172 * Taglibの開始タグが見つかったときに処理する doStartTag() を オーバーライドします。 173 * 174 * @return 後続処理の指示( EVAL_BODY_BUFFERED ) 175 */ 176 @Override 177 public int doStartTag() { 178 dyStart = System.currentTimeMillis(); // 時間測定用 179 return( EVAL_BODY_BUFFERED ); // Body を評価する。( extends BodyTagSupport 時) 180 } 181 182 /** 183 * Taglibのタグ本体を処理する doAfterBody() を オーバーライドします。 184 * 185 * @og.rev 3.8.6.3 (2006/11/30) SQL 文の前後のスペースを取り除きます。 186 * 187 * @return 後続処理の指示(SKIP_BODY) 188 */ 189 @Override 190 public int doAfterBody() { 191 sql = getBodyString(); 192 if( sql == null || sql.length() == 0 ) { 193 String errMsg = "BODY 部の検索用 Select文は、必須です。"; 194 throw new HybsSystemException( errMsg ); 195 } 196 sql = sql.trim(); 197 return(SKIP_BODY); // Body を評価しない 198 } 199 200 /** 201 * Taglibの終了タグが見つかったときに処理する doEndTag() を オーバーライドします。 202 * 203 * @og.rev 3.6.1.0 (2005/01/05) PL/SQLコール(JDBCErrMsg 形式)への対応 204 * @og.rev 4.0.0.0 (2007/10/18) メッセージリソース統合( getResource().getMessage ⇒ getResource().getLabel ) 205 * 206 * @return 後続処理の指示 207 */ 208 @Override 209 public int doEndTag() { 210 debugPrint(); // 4.0.0 (2005/02/28) 211 212 PrintWriter pw = null; 213 final int executeCount; 214 try { 215 if( zip ) { 216 String directory = HybsSystem.url2dir( fileURL ); 217 218 if( zipFilename == null ) { zipFilename = filename + ".zip"; } 219 ZipOutputStream gzip = null; 220 try { 221 gzip = new ZipOutputStream( 222 new FileOutputStream( 223 StringUtil.urlAppend( directory,zipFilename ))); 224 gzip.putNextEntry( new ZipEntry( filename ) ); 225 pw = new PrintWriter( gzip ); 226 executeCount = create( pw ) ; 227 228 pw.flush(); 229 gzip.closeEntry(); 230 gzip.finish() ; 231 } 232 finally { 233 Closer.ioClose( gzip ); // 4.0.0 (2006/01/31) close 処理時の IOException を無視 234 } 235 } 236 else { 237 pw = getPrintWriter(); 238 executeCount = create( pw ); 239 } 240 } catch( IOException ex ) { 241 String errMsg = "Error in DirectWriteTableTag: " + toString(); 242 throw new HybsSystemException( errMsg,ex ); // 3.5.5.4 (2004/04/15) 引数の並び順変更 243 } finally { 244 Closer.ioClose( pw ); // 4.0.0 (2006/01/31) close 処理時の IOException を無視 245 } 246 247 // 3.6.1.0 (2005/01/05) 検索結果の件数を、"DB.COUNT" キーでリクエストにセットする。 248 setRequestAttribute( "DB.COUNT" , String.valueOf( executeCount ) ); 249 setRequestAttribute( "DB.ERR_CODE", String.valueOf( errCode ) ); 250 251 StringBuilder buf = new StringBuilder( HybsSystem.BUFFER_SMALL ); 252 253 // 実行件数の表示 254// boolean useStatusBar = HybsSystem.sysBool( "VIEW_USE_DISPLAY_MSG" ); 255// if( useStatusBar && executeCount > 0 && displayMsg != null && displayMsg.length() > 0 ) { 256 if( executeCount > 0 && displayMsg != null && displayMsg.length() > 0 ) { 257 buf.append( executeCount ); 258// buf.append( getResource().getMessage( displayMsg ) ); 259 buf.append( getResource().getLabel( displayMsg ) ); 260 buf.append( HybsSystem.BR ); 261 } 262 else if( executeCount == 0 && notfoundMsg != null && notfoundMsg.length() > 0 ) { 263// buf.append( getResource().getMessage( notfoundMsg ) ); 264 buf.append( getResource().getLabel( notfoundMsg ) ); 265 buf.append( HybsSystem.BR ); 266 } 267 268 // 3.6.1.0 (2005/01/05) TaglibUtil.makeHTMLErrorTable メソッドを利用 269 String err = TaglibUtil.makeHTMLErrorTable( errMessage,getResource() ); 270 if( err != null && err.length() > 0 ) { 271 buf.append( err ); 272 setSessionAttribute( errMsgId,errMessage ); 273 } 274 else { 275 removeSessionAttribute( errMsgId ); 276 } 277 278 jspPrint( buf.toString() ); 279 280 // 時間測定用の DIV 要素を出力 281 long dyTime = System.currentTimeMillis()-dyStart; 282 jspPrint( "<div id=\"queryTime\" value=\"" + (dyTime) + "\"></div>" ); // 3.5.6.3 (2004/07/12) 283 284 // 3.6.1.0 (2005/01/05) 警告時に停止していましたが、継続処理させます。 285 int rtnCode = EVAL_PAGE; 286 if( errCode >= ErrorMessage.NG ) { // 異常 287 rtnCode = SKIP_PAGE; 288 } 289 290 // 4.0.0 (2005/01/31) セキュリティチェック(データアクセス件数登録) 291 GUIInfo guiInfo = (GUIInfo)getSessionAttribute( HybsSystem.GUIINFO_KEY ); 292 if( guiInfo != null ) { guiInfo.addReadCount( executeCount,dyTime,sql ); } 293 294 return( rtnCode ); 295 } 296 297 /** 298 * タグリブオブジェクトをリリースします。 299 * キャッシュされて再利用されるので、フィールドの初期設定を行います。 300 * 301 * @og.rev 3.6.1.0 (2005/01/05) PL/SQLコール(JDBCErrMsg 形式)への対応 302 * @og.rev 4.0.0.0 (2007/10/10) dbid の初期値を、"DEFAULT" から null に変更 303 * @og.rev 5.5.7.1 (2012/10/05) useNumber追加 304 */ 305 @Override 306 protected void release2() { 307 super.release2(); 308 separator = TAB_SEPARATOR; // 項目区切り文字 309 fileURL = HybsSystem.sys( "FILE_URL" ); 310 filename = HybsSystem.sys( "FILE_FILENAME" ); // ファイル名 311 zipFilename = null; // ZIPファイル名 312 sql = null; 313 encode = HybsSystem.sys( "FILE_ENCODE" ); // ファイルエンコーディング "DEFAULT","JISAutoDetect" ,"JIS", "EUC_JP", "MS932", "SJIS" , "Windows-31J" , "Shift_JIS" 314 fileAppend = false; // ファイルをAPPENDモードで出力するか 315 zip = false; // ファイルをZIPするか 316// displayMsg = "MSG0033"; // 件検索しました。 317 displayMsg = HybsSystem.sys( "VIEW_DISPLAY_MSG" ); 318 notfoundMsg = "MSG0077"; // 対象データはありませんでした。 319// dbid = "DEFAULT"; 320 dbid = null; 321 fetchSize = 100 ; // フェッチする行数(初期値:0 参考にしない) 322 dyStart = 0; 323 queryType = true; // ノーマルは、true/ JDBCErrMsg の時は、false 324 names = null; // 指定のリクエスト変数を、ARG_ARRAY にセットします。 325 errCode = ErrorMessage.OK; 326 errMessage = null; 327 useNumber = true; // 5.5.7.1 (2012/10/05) 328 } 329 330 /** 331 * 実オブジェクトを生成して,OutputStream に書き込みます。 332 * 333 * @og.rev 3.6.1.0 (2005/01/05) PL/SQLコール(JDBCErrMsg 形式)への対応 334 * @og.rev 3.8.6.0 (2006/09/29) ヘッダーにラベルを出力するように修正 335 * @og.rev 3.8.7.0 (2006/12/15) アクセスログ取得の為,ApplicationInfoオブジェクトを設定 336 * @og.rev 4.3.4.3 (2008/12/22) (Oracle11gDriver対応)PL/SQLコールの場合に、"クローズされた文です。"のエラーが発生する問題に対応 337 * @og.rev 5.1.9.0 (2010/08/01) Transaction 対応 338 * @og.rev 5.2.2.0 (2010/11/01) 改行を含む場合は、ダブルクオートを強制的に前後に追加する。 339 * @og.rev 5.2.2.0 (2010/11/01) ダブルクオートを含む場合は、その直前にダブルクオートを強制的に追加する。 340 * @og.rev 5.3.0.0 (2010/12/01) executeCall メソッドの引数見直し 341 * @og.rev 5.3.7.0 (2011/07/01) TransactionReal の引数変更 342 * @og.rev 5.5.7.1 (2012/10/05) useNumberの追加 343 * 344 * @param out PrintWriterオブジェクト 345 * 346 * @return 検索件数 347 */ 348 private int create( final PrintWriter out ) { 349 final int executeCount; 350 Statement stmt = null; 351 CallableStatement callStmt = null; // 4.3.4.3 (2008/12/22) 352 ResultSet resultSet = null ; 353 boolean errFlag = true; 354// Connection conn = null; 355 Transaction tran = null; // 5.1.9.0 (2010/08/01) Transaction 対応 356 try { 357 // 5.1.9.0 (2010/08/01) Transaction 対応 358 TransactionTag tranTag = (TransactionTag)findAncestorWithClass( this,TransactionTag.class ); 359 if( tranTag == null ) { 360// tran = new TransactionReal( dbid,getApplicationInfo() ); 361 tran = new TransactionReal( getApplicationInfo() ); // 5.3.7.0 (2011/07/01) 引数変更 362 } 363 else { 364 tran = tranTag.getTransaction(); 365 } 366// conn = ConnectionFactory.connection( dbid,getApplicationInfo() ); // 3.8.7.0 (2006/12/15) 367 368 Connection conn = tran.getConnection( dbid ); // 5.1.9.0 (2010/08/01) Transaction 対応 369 // 3.6.1.0 (2005/01/05) 370 if( queryType ) { // JDBC 通常の SELECT 文 371 stmt = conn.createStatement(); 372 if( fetchSize > 0 ) { stmt.setFetchSize( fetchSize ); } 373 resultSet = stmt.executeQuery( sql ); 374 } 375 else { // PL/SQL Call 文 376 String[] values = null; 377 if( names != null ) { 378 String[] nameArray = StringUtil.csv2Array( names ); 379 values = getRequest( nameArray ); 380 } 381 callStmt = conn.prepareCall( sql ); 382// resultSet = executeCall( conn,callStmt,sql,values ); // 4.3.4.3 (2008/12/22) 383 resultSet = executeCall( conn,callStmt,values ); // 5.3.0.0 (2010/12/01) 384 } 385 if( resultSet == null ) { return 0; } 386 387 ResultSetMetaData metaData = resultSet.getMetaData(); 388 int numberOfColumns = metaData.getColumnCount(); 389 390 // ヘッダー部の出力 391 if( useHeader && numberOfColumns > 0 ) { 392 StringBuilder headName = new StringBuilder(); 393 StringBuilder headLabel = new StringBuilder(); 394 headName.append( "#Name" ); 395 headLabel.append( "#Label" ); 396 String clm ; 397 ResourceManager resource = getResource(); 398 for(int column = 1; column <= numberOfColumns; column++) { 399 clm = (metaData.getColumnLabel(column)).toUpperCase(Locale.JAPAN); 400 headName.append( TAB_SEPARATOR ).append( clm ); 401 headLabel.append( TAB_SEPARATOR ).append( resource.getLabel( clm ) ); 402 } 403 out.println( headName.toString() ); 404 out.println( headLabel.toString() ); 405 } 406 407 int rowNo = 0; 408 Object obj ; 409 while( resultSet.next() ) { 410 if( useNumber ){ // 5.5.7.1 (2012/10/05) 411 out.print( rowNo ); // 行番号 412 } 413 for(int column = 1; column <= numberOfColumns; column++) { 414 if( column == 1 && !useNumber && !useHeader ){ // 5.5.7.1 (2012/10/05) 415 //この場合だけセパレータ出力しない 416 } 417 else{ 418 out.print( separator ); 419 } 420 obj = resultSet.getObject(column); 421 if( obj != null ) { 422// out.print( obj ); 423 // 5.2.2.0 (2010/11/01) 改行、ダブルクオート等の処理 424 String sval = obj.toString(); 425 if( sval.indexOf( '"' ) >= 0 ) { sval = sval.replaceAll( "\"" ,"\"\"" ) ; } 426 if( sval.indexOf( HybsSystem.CR ) >= 0 ) { 427 sval = "\"" + sval + "\"" ; 428 } 429 out.print( sval ); 430 } 431 } 432 out.println(); 433 rowNo++ ; 434 } 435 executeCount = rowNo ; 436 errFlag = false; // エラーではない 437 } 438 catch ( SQLException ex ) { // 3.6.1.0 (2005/01/05) 439 String errMsg = "データベース処理を実行できませんでした。" 440 + HybsSystem.CR + stmt + HybsSystem.CR 441 + "err=[" + ex.getSQLState() + "]" 442 + ex.getMessage(); 443 throw new HybsSystemException( errMsg,ex ); 444 } 445 finally { 446 Closer.resultClose( resultSet ); 447 Closer.stmtClose( stmt ); 448 Closer.stmtClose( callStmt ); // 4.3.4.3 (2008/12/22) 449 if( tran != null ) { // 5.5.2.6 (2012/05/25) findbugs対応 450 tran.close( errFlag ); // 5.1.9.0 (2010/08/01) Transaction 対応 451 } 452// if( errFlag ) { ConnectionFactory.remove( conn,dbid ); } // 削除 453// else { ConnectionFactory.close( conn,dbid ); } // 返却 454// conn = null; 455 } 456 457 return executeCount ; 458 } 459 460 /** 461 * 引数配列付のクエリーを実行します。 462 * 処理自体は, #execute() と同様に、各サブクラスの実装に依存します。 463 * これは、CallableStatement を用いて、データベース検索処理を行います。 464 * {call TYPE3B01.TYPE3B01(?,?,?,?)} で、4番目の引数には、 465 * names で指定したリクエスト情報が、ARG_ARRAY 配列に順次セットされます。 466 * 使用する場合は、一旦わかり易い変数に受けて利用してください。 467 * 呼び出す PL/SQL では、検索系PL/SQL です。 468 * 469 * @og.rev 3.6.1.0 (2005/01/05) PL/SQLコール(JDBCErrMsg 形式)への対応 470 * @og.rev 4.3.4.3 (2008/12/22) (Oracle11gDriver対応)PL/SQLコールの場合に、"クローズされた文です。"のエラーが発生する問題に対応 471 * @og.rev 5.3.0.0 (2010/12/01) executeCall メソッドの引数見直し 472 * @og.rev 5.7.2.2 (2014/01/24) Oracle11g(11.2.0.3のドライバ)対応 473 * @og.rev 5.7.2.3 (2014/01/31) Oracle11g(11.2.0.3のドライバ)対応は、Ver5 では行わない(戻す)。 474 * 475 * @param conn コネクション 476 * @param callStmt コーラブルステートメント 477 * @param args オブジェクトの引数配列 478 * 479 * @return 結果オブジェクト 480 */ 481// private ResultSet executeCall( final Connection conn,final CallableStatement callStmt,final String sql,final String[] args ) throws SQLException { 482 private ResultSet executeCall( final Connection conn,final CallableStatement callStmt,final String[] args ) throws SQLException { 483// CallableStatement callStmt = null ; // 4.3.4.3 (2008/12/22) 484 ResultSet resultSet = null; 485// try { 486// callStmt = conn.prepareCall( sql ); 487 callStmt.setQueryTimeout( DB_MAX_QUERY_TIMEOUT ); 488 if( fetchSize > 0 ) { callStmt.setFetchSize( fetchSize ); } 489 Map<String,Class<?>> map = conn.getTypeMap(); 490 try { 491 map.put( ERR_MSG,Class.forName( "org.opengion.hayabusa.db.DBErrMsg" ) ); 492 } 493 catch( ClassNotFoundException ex ) { 494 String errMsg = "org.opengion.hayabusa.db.DBErrMsg クラスが見つかりません。" + HybsSystem.CR 495 + ex.getMessage(); // // 5.1.8.0 (2010/07/01) errMsg 修正 496 throw new HybsSystemException( errMsg,ex ); // 3.5.5.4 (2004/04/15) 引数の並び順変更 497 } 498 499 // 5.7.2.2 (2014/01/24) Oracle11g(11.2.0.3のドライバ)対応 http://docs.oracle.com/cd/E28389_01/web.1111/b60995/thirdparty.htm 500 ArrayDescriptor sd = ArrayDescriptor.createDescriptor( ARG_ARRAY, conn ); 501 ARRAY newArray = new ARRAY( sd,conn,StringUtil.rTrims( args ) ); 502// Array newArray = ((OracleConnection)conn).createOracleArray( ARG_ARRAY, StringUtil.rTrims( args )); // 5.7.2.2 (2014/01/24) Oracle11g(11.2.0.3のドライバ)対応 503 504 callStmt.registerOutParameter(1, Types.INTEGER); 505 callStmt.registerOutParameter(2, OracleTypes.ARRAY,ERR_MSG_ARRAY); // 5.7.2.2 (2014/01/24) Oracle11g(11.2.0.3のドライバ)対応 506// callStmt.registerOutParameter(2, Types.ARRAY,ERR_MSG_ARRAY); // 5.7.2.2 (2014/01/24) Oracle11g(11.2.0.3のドライバ)対応 507 callStmt.registerOutParameter(3, OracleTypes.CURSOR); 508 ((OracleCallableStatement)callStmt).setARRAY( 4,newArray ); // 5.7.2.2 (2014/01/24) Oracle11g(11.2.0.3のドライバ)対応 509// callStmt.setArray( 4,newArray ); // 5.7.2.2 (2014/01/24) Oracle11g(11.2.0.3のドライバ)対応 510 511 callStmt.execute(); 512 513 errCode = callStmt.getInt(1); 514 515 if( errCode < ErrorMessage.NG ) { // 異常以外の場合 516 resultSet = ((OracleCallableStatement)callStmt).getCursor(3); 517 } 518 if( errCode > ErrorMessage.OK ) { // 正常以外の場合 519 ARRAY rtn3 = ((OracleCallableStatement)callStmt).getARRAY(2); // 5.7.2.2 (2014/01/24) Oracle11g(11.2.0.3のドライバ)対応 520// Array rtn3 = callStmt.getArray(2); // 5.7.2.2 (2014/01/24) Oracle11g(11.2.0.3のドライバ)対応 521 Object[] rtnval3 = (Object[])rtn3.getArray(); 522 errMessage = new ErrorMessage( "Query_JDBCErrMsg Error!!" ); 523 for( int i=0; i<rtnval3.length; i++ ) { 524 DBErrMsg er = (DBErrMsg)rtnval3[i]; 525 if( er == null ) { break; } 526 errMessage.addMessage( er.getErrMsg() ); 527 } 528 } 529// } 530// finally { 531// Closer.stmtClose( callStmt ); 532// callStmt = null; 533// } 534 return resultSet; 535 } 536 537 /** 538 * PrintWriter を取得します。 539 * 540 * ここでは、一般的なファイル出力を考慮した PrintWriter を作成します。 541 * 542 * @og.rev 3.7.1.1 (2005/05/23) フォルダがない場合は、複数階層分のフォルダを自動で作成します。 543 * @og.rev 3.8.0.0 (2005/06/07) FileUtil#getPrintWriter を利用。 544 * @og.rev 5.6.1.0 (2013/02/01) 3.7.1.1のコメントに入っているが対応されていないのでフォルダ作成追加 545 * 546 * @return 出力用PrintWriterオブジェクト 547 */ 548 private PrintWriter getPrintWriter() { 549 if( filename == null ) { 550 String errMsg = "ファイル名がセットされていません。"; 551 throw new HybsSystemException( errMsg ); 552 } 553 String directory = HybsSystem.url2dir( fileURL ); 554 555 // 5.6.1.0 (2013/02/01) 556 File dir = new File(directory); 557 if( ! dir.exists() && ! dir.mkdirs() ) { 558 String errMsg = "ディレクトリの作成に失敗しました。[" + directory + "]"; 559 throw new HybsSystemException( errMsg ); 560 } 561 562 563 // ※ 注意 StringUtil.urlAppend を組み込んでいる意図が不明。一旦削除していますが、注意 564 // 3.8.0.0 (2005/06/07) FileUtil#getPrintWriter を利用。 565 // out = FileUtil.getPrintWriter( StringUtil.urlAppend( directory,filename ),fileAppend,encode); 566 567// 処理を簡素化します。 568// PrintWriter out = FileUtil.getPrintWriter( new File( directory,filename ),encode,fileAppend ); 569// return out ; 570 return FileUtil.getPrintWriter( new File( directory,filename ),encode,fileAppend ); 571 } 572 573 /** 574 * 名称配列を元に、リクエスト情報のデータを取得します。 575 * 576 * @og.rev 3.6.1.0 (2005/01/05) PL/SQLコール(JDBCErrMsg 形式)への対応 577 * 578 * @param nameArray キーとなる名称の配列 579 * 580 * @return そのリクエスト情報 581 */ 582 private String[] getRequest( final String[] nameArray ) { 583 String[] rtn = new String[nameArray.length]; 584 585 for( int i=0; i<rtn.length; i++ ) { 586 rtn[i] = getRequestValue( nameArray[i] ); 587 } 588 589 return rtn; 590 } 591 592 /** 593 * 【TAG】(通常は使いません)検索時のDB接続IDを指定します(初期値:DEFAULT)。 594 * 595 * @og.tag 596 * 検索時のDB接続IDを指定します。初期値は、DEFAULT です。 597 * 598 * @param id データベース接続ID 599 */ 600 public void setDbid( final String id ) { 601 dbid = nval( getRequestParameter( id ),dbid ); 602 } 603 604 /** 605 * 【TAG】可変長ファイルを作成するときの項目区切り文字をセットします 606 * (初期値:TAB_SEPARATOR[={@og.value #TAB_SEPARATOR}])。 607 * 608 * @og.tag 可変長ファイルを作成するときの項目区切り文字をセットします。 609 * (初期値:ローカル定義のTAB_SEPARATOR[={@og.value #TAB_SEPARATOR}])。 610 * 611 * @param sep 項目区切り文字 612 * @see #TAB_SEPARATOR 613 */ 614 public void setSeparator( final String sep ) { 615 separator = nval( getRequestParameter( sep ),TAB_SEPARATOR ); 616 } 617 618 /** 619 * 【TAG】保存先ディレクトリ名を指定します 620 * (初期値:FILE_URL[={@og.value org.opengion.hayabusa.common.SystemData#FILE_URL}])。 621 * 622 * @og.tag 623 * この属性で指定されるディレクトリに、ファイルをセーブします。 624 * 指定方法は、通常の fileURL 属性と同様に、先頭が、'/' (UNIX) または、2文字目が、 625 * ":" (Windows)の場合は、指定のURLそのままのディレクトリに、そうでない場合は、 626 * fileURL = "{@USER.ID}" と指定すると、FILE_URL 属性で指定のフォルダの下に、 627 * さらに、各個人ID別のフォルダを作成して、そこにセーブします。 628 * (初期値:システム定数のFILE_URL[={@og.value org.opengion.hayabusa.common.SystemData#FILE_URL}])。 629 * 630 * @og.rev 3.5.4.3 (2004/01/05) 内部処理を、makeFileURL に移動。 631 * @og.rev 4.0.0.0 (2005/01/31) StringUtil.urlAppend メソッドの利用 632 * @og.rev 4.0.0.0 (2007/11/20) 指定されたディレクトリ名の最後が"\"or"/"で終わっていない場合に、"/"を付加する。 633 * 634 * @param url 保存先ディレクトリ名 635 * @see org.opengion.hayabusa.common.SystemData#FILE_URL 636 */ 637 public void setFileURL( final String url ) { 638 String furl = nval( getRequestParameter( url ),null ); 639 if( furl != null ) { 640 char ch = furl.charAt( furl.length()-1 ); 641 if( ch != '/' && ch != '\\' ) { furl = furl + "/"; } 642 fileURL = StringUtil.urlAppend( fileURL,furl ); 643 } 644 } 645 646 /** 647 * 【TAG】ファイルを作成するときのファイル名をセットします(初期値:システムパラメータのFILE_FILENAME)。 648 * 649 * @og.tag ファイルを作成するときのファイル名をセットします。 650 * 651 * @param fname ファイル名 652 */ 653 public void setFilename( final String fname ) { 654 filename = nval( getRequestParameter( fname ),filename ); 655 } 656 657 /** 658 * 【TAG】ZIPファイルを作成するときのZIPファイル名をセットします(初期値:filename + ".zip")。 659 * 660 * @og.tag 661 * zip 属性に、true を指定した場合に、ZIPファイル化します。その場合のファイル名を指定します。 662 * なにも指定しない場合は、filename + ".zip" になります。 663 * 664 * @param zipFile ZIPファイル名 665 * @see #setZip( String ) 666 */ 667 public void setZipFilename( final String zipFile ) { 668 zipFilename = nval( getRequestParameter( zipFile ),zipFilename ); 669 } 670 671 /** 672 * 【TAG】ファイルを作成するときのファイルエンコーディング名をセットします 673 * (初期値:FILE_ENCODE[={@og.value org.opengion.hayabusa.common.SystemData#FILE_ENCODE}])。 674 * 675 * @og.tag 676 * "DEFAULT","JISAutoDetect" ,"JIS", "EUC_JP", "MS932", "SJIS" , "Windows-31J" , "Shift_JIS" 677 * (初期値:システム定数のFILE_ENCODE[={@og.value org.opengion.hayabusa.common.SystemData#FILE_ENCODE}])。 678 * 679 * @og.rev 2.2.0.0 (2002/12/17) 中国語(国際化)対応 エンコードの取得方法変更 680 * @og.rev 3.1.3.0 (2003/04/10) FILE_ENCODE から、エンコード情報を取得する。 681 * 682 * @param enc ファイルエンコーディング名 683 * @see <a href="http://www.iana.org/assignments/character-sets">IANA Charset Registry</a> 684 * @see org.opengion.hayabusa.common.SystemData#FILE_ENCODE 685 */ 686 public void setEncode( final String enc ) { 687 encode = nval( getRequestParameter( enc ),encode ); 688 } 689 690 /** 691 * 【TAG】ヘッダーを書き込むかどうか[true/false]を指定します(初期値:true)。 692 * 693 * @og.tag 694 * #Name ・・・・ ヘッダーの書き込みを指定します。 695 * 通常は、書き込み(true)にしておき、使用側でコメントと解釈するように 696 * 処理を行うべきです。コメントのため、append モードで途中に現れても 697 * 無視できます。また、エンジン標準でデータを取り込む場合に、データの配置が 698 * 変更されても取り込みプログラムはそのまま使用できます。 699 * 初期値は、true(書き込む)です。 700 * 701 * @param flag ヘッダーを書き込むかどうか [true:書き込む/false:書き込まない] 702 */ 703 public void setUseHeader( final String flag ) { 704 useHeader = nval( getRequestParameter( flag ),useHeader ); 705 } 706 707 /** 708 * 【TAG】追加モードで書き込むかどうか[true/false]を指定します(初期値:false[通常モード])。 709 * 710 * @og.tag 711 * ファイルを書き込む場合、追加モードで書き込むかどうかをセットします。 712 * 新規モード(true)の場合、既存のファイルが存在し、かつ書き込み許可があれば、 713 * 上書きで新規に作成します。 714 * 初期値は、false(新規モード)です。 715 * 716 * @param flag [true:追加モード/false:新規モード] 717 */ 718 public void setFileAppend( final String flag ) { 719 fileAppend = nval( getRequestParameter( flag ),fileAppend ); 720 } 721 722 /** 723 * 【TAG】結果をファイルに出力するときに、ZIPで圧縮するかどうか[true/false]を指定します(初期値:false)。 724 * 725 * @og.tag 726 * 大量に抜き出す場合、そのまま、サーバーから取り出すだけでも大変です。 727 * zip 属性を、true にすると、GZIP で圧縮したファイルを作成します。 728 * 初期値は、false(圧縮しない)です。 729 * 730 * @param flag ZIPで圧縮 [true:する/それ以外:しない] 731 * @see #setZipFilename( String ) 732 */ 733 public void setZip( final String flag ) { 734 zip = nval( getRequestParameter( flag ),zip ); 735 } 736 737 /** 738 * 【TAG】検索結果を画面上に表示するメッセージリソースIDを指定します(初期値:MSG0033[ 件検索しました])。 739 * 740 * @og.tag 741 * ここでは、検索結果の件数や登録された件数をまず出力し、 742 * その次に、ここで指定したメッセージをリソースから取得して 743 * 表示します。 744 * 表示させたくない場合は, displayMsg = "" をセットしてください。 745 * 初期値は、検索件数を表示します。 746 * 747 * @param id ディスプレイに表示させるメッセージ ID 748 */ 749 public void setDisplayMsg( final String id ) { 750 String ids = getRequestParameter( id ); 751 if( ids != null ) { displayMsg = ids; } 752 } 753 754 /** 755 * 【TAG】検索結果がゼロ件の場合に表示するメッセージリソースIDを指定します(初期値:MSG0077[対象データはありませんでした])。 756 * 757 * @og.tag 758 * ここでは、検索結果がゼロ件の場合のみ、特別なメッセージを表示させます。 759 * 従来は、displayMsg と兼用で、『0 件検索しました』という表示でしたが、 760 * displayMsg の初期表示は、OFF になりましたので、ゼロ件の場合のみ別に表示させます。 761 * 表示させたくない場合は, notfoundMsg = "" をセットしてください。 762 * 初期値は、MSG0077[対象データはありませんでした]です。 763 * 764 * @param id ディスプレイに表示させるメッセージ ID 765 */ 766 public void setNotfoundMsg( final String id ) { 767 String ids = getRequestParameter( id ); 768 if( ids != null ) { notfoundMsg = ids; } 769 } 770 771 /** 772 * 【TAG】(通常は使いません)データのフェッチサイズを指定します(初期値:100)。 773 * 774 * @og.tag 775 * より多くの行が必要なときに、データベースから取り出す必要がある行数に 776 * ついてのヒントを JDBC ドライバに提供します。 777 * 指定された行数は、この Statement を使って作成された結果セットにだけ影響します。 778 * 指定された値が 0 の場合、ヒントは無視されます。 779 * 初期値は、100 です。 780 * 781 * @param size フェッチする行数(初期値:100) 782 */ 783 public void setFetchSize( final String size ) { 784 fetchSize = nval( getRequestParameter( size ),fetchSize ); 785 } 786 787 /** 788 * 【TAG】PL/SQLを利用する場合の引数にセットすべき データの名称をCSV形式で複数指定します。 789 * 790 * @og.tag 791 * 複数ある場合は、カンマ区切り文字で渡します。 792 * PL/SQL を使用しない場合は、無視されます。 793 * 794 * @og.rev 3.6.1.0 (2005/01/05) PL/SQLコール(JDBCErrMsg 形式)への対応 795 * 796 * @param nm 引数の名称(複数ある場合は、カンマ区切り文字) 797 */ 798 public void setNames( final String nm ) { 799 names = nval( getRequestParameter( nm ),names ); 800 } 801 802 /** 803 * 【TAG】Query を発行する為のクラスID(JDBC,JDBCErrMsg)を指定します({@og.doc03Link queryType 初期値:JDBC})。 804 * 805 * @og.tag 806 * ストアドプロシージャ等を実行する場合に、queryType="JDBCErrMsg" を 807 * 指定する必要があります。(それ以外の指定は、初期値の JDBC になります。) 808 * 初期値は、"JDBC" です。 809 * {@og.doc03Link queryType Query_**** クラス} 810 * 811 * @og.rev 3.6.1.0 (2005/01/05) PL/SQLコール(JDBCErrMsg 形式)への対応 812 * 813 * @param id Query を発行する為の実クラス ID 814 */ 815 public void setQueryType( final String id ) { 816 // 内部的には、JDBCErrMsg:false / それ以外:true で管理しています。 817 queryType = ! "JDBCErrMsg".equalsIgnoreCase( getRequestParameter( id ) ); 818 } 819 820 /** 821 * 【TAG】ファイルに行番号を出力するかどうか(初期値:true) 822 * 823 * @og.tag 824 * ファイルに行番号を出力するかどうかを指定します。 825 * 初期値は、true(出力する)です。 826 * 827 * @og.rev 5.5.7.1 (2012/10/05) 新規追加 828 * @param flag 行番号出力 [true:する/それ以外:しない] 829 */ 830 public void setUseNumber( final String flag ) { 831 useNumber = nval( getRequestParameter( flag ),useNumber ); 832 } 833 834 /** 835 * シリアライズ用のカスタムシリアライズ書き込みメソッド 836 * 837 * @og.rev 4.0.0.0 (2006/09/31) 新規追加 838 * @serialData 一部のオブジェクトは、シリアライズされません。 839 * 840 * @param strm ObjectOutputStreamオブジェクト 841 * @throws IOException シリアライズに関する入出力エラーが発生した場合 842 */ 843 private void writeObject( final ObjectOutputStream strm ) throws IOException { 844 strm.defaultWriteObject(); 845 } 846 847 /** 848 * シリアライズ用のカスタムシリアライズ読み込みメソッド 849 * 850 * ここでは、transient 宣言された内部変数の内、初期化が必要なフィールドのみ設定します。 851 * 852 * @og.rev 4.0.0.0 (2006/09/31) 新規追加 853 * @serialData 一部のオブジェクトは、シリアライズされません。 854 * 855 * @param strm ObjectInputStreamオブジェクト 856 * @see #release2() 857 */ 858 private void readObject( final ObjectInputStream strm ) throws IOException , ClassNotFoundException { 859 strm.defaultReadObject(); 860 } 861 862 /** 863 * このオブジェクトの文字列表現を返します。 864 * 基本的にデバッグ目的に使用します。 865 * 866 * @return このクラスの文字列表現 867 */ 868 @Override 869 public String toString() { 870 return org.opengion.fukurou.util.ToString.title( this.getClass().getName() ) 871 .println( "VERSION" ,VERSION ) 872 .println( "dbid" ,dbid ) 873 .println( "separator" ,separator ) 874 .println( "useHeader" ,useHeader ) 875 .println( "fileURL" ,fileURL ) 876 .println( "filename" ,filename ) 877 .println( "zipFilename" ,zipFilename) 878 .println( "sql" ,sql ) 879 .println( "encode" ,encode ) 880 .println( "fileAppend" ,fileAppend ) 881 .println( "zip" ,zip ) 882 .println( "displayMsg" ,displayMsg ) 883 .println( "dyStart" ,dyStart ) 884 .println( "fetchSize" ,fetchSize ) 885 .println( "queryType" ,queryType ) 886 .println( "names" ,names ) 887 .println( "errCode" ,errCode ) 888 .println( "Other..." ,getAttributes().getAttribute() ) 889 .fixForm().toString() ; 890 } 891}