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.fukurou.db; 017 018import java.io.File; 019import java.net.URL; 020import java.util.ArrayList; 021import java.util.LinkedHashMap; 022import java.util.List; 023import java.util.Locale; 024import java.util.Map; 025import java.util.Collections; 026 027import org.opengion.fukurou.util.StringUtil; 028import org.opengion.fukurou.util.FileUtil; 029import org.opengion.fukurou.util.HybsDateUtil; // 6.9.2.1 (2018/03/12) 030import org.opengion.fukurou.system.OgRuntimeException ; // 6.4.2.0 (2016/01/29) 031import org.opengion.fukurou.system.LogWriter; 032import org.opengion.fukurou.system.HybsConst; // 7.2.3.1 (2020/04/17) 033import org.opengion.fukurou.xml.DomParser; 034import org.w3c.dom.Document; 035import org.w3c.dom.Element; 036import org.w3c.dom.Node; 037import org.w3c.dom.NodeList; 038import org.w3c.dom.NamedNodeMap; // 6.9.2.0 (2018/03/05) 039 040import static org.opengion.fukurou.system.HybsConst.BUFFER_MIDDLE; // 6.1.0.0 (2014/12/26) refactoring 041 042/** 043 * DB設定XMLの内容をJAXBを利用してロードする 044 * Driverをロードする 045 * 上記2つの機能を備えたクラスです 046 * 047 * 外部からはgetDbidメソッドを利用してDB設定(ExpandedDbid型)を取得します。 048 * DB設定情報が無い場合にXMLを読みにいきます。 049 * このDBIDを決めるキーは、内部取り込み字に、大文字変換されますので、大文字・ 050 * 小文字の区別はありません。 051 * 052 * @og.rev 4.0.0.0 (2007/10/25) 新規作成 053 * @og.rev 5.1.7.0 (2010/06/01) org.opengion.fukurou.xml.jaxb.dbid 関係 廃止 054 * @og.group 初期化 055 * 056 * @version 4.0 057 * @author 高橋正和 058 * @since JDK6.0, 059 */ 060// 8.5.5.1 (2024/02/29) spotbugs CT_CONSTRUCTOR_THROW(コンストラクタで、Excweptionを出さない) class を final にすれば、警告は消える。 061// public class DatabaseConfig { 062public final class DatabaseConfig { 063 064 /** fukurou内で完結させるため、HybsDataからは読み込まずにここに書く */ 065 private static final String DEFAULT_DRIVER = "oracle.jdbc.OracleDriver"; 066 067 // 6.4.3.3 (2016/03/04) 初期 DBConfig.xml ファイルの設定。 068 /** 初期ファイルの設定 {@value} */ 069 public static final String DB_CONFIG_FILE = "../DBConfig.xml" ; 070 071 /** XMLファイル関連 */ 072 private final String xmlFilename; // 5.7.2.2 (2014/01/24) 073 074 /** 6.4.3.1 (2016/02/12) Collections.synchronizedMap で同期処理を行います。 */ 075 private final Map<String, EDbid> dbidMap = Collections.synchronizedMap( new LinkedHashMap<>() ); // 5.6.7.0 (2013/07/27) 076 /** 6.4.3.1 (2016/02/12) Collections.synchronizedList で同期処理を行います。 */ 077 private final List<String> driverList = Collections.synchronizedList( new ArrayList<>() ); 078 079 /** 5.6.7.0 (2013/07/27) プルダウンメニュー用の情報の、キャッシュ用変数。 */ 080 private String codeKeyVal ; // 初めて要求されたときに、セットします。 081 082 /** 5.6.6.0 (2013/07/05) 表題(title)属性を追加 */ 083 private static final String[] DBID_INFO_KEYS 084 = { "dbidKey", "title", "url", "user", "password", "readonly" 085 , "mincount", "maxcount", "pooltime", "applicationInfo","property" }; 086 087 /* DBDRIVERのキーのを管理します。5.1.9.0 (2010/08/01) */ 088 private static final String DBDRIVER_CLASS_KEY = "class"; 089 090 /** 091 * 初期値を使ってXMLを読み込む 092 * xmlFilenameの初期値は../DBConfig.xml 093 * 094 * @og.rev 4.3.1.1 (2008/08/23) 自分のコンストラクターを呼ぶように修正 095 */ 096 public DatabaseConfig() { 097 this( DB_CONFIG_FILE ); 098 } 099 100 /** 101 * XMLファイルの名前を指定して読み込む 102 * 103 * @og.rev 5.1.9.0 (2010/08/01) クラスローダー外からでもDBConfig.xmlを取得できるようにする 104 * @og.rev 5.6.7.0 (2013/07/27) オブジェクト作成時に初期化も行っておきます。 105 * @og.rev 5.6.8.2 (2013/09/20) Tomcat8で、クラスローダーが変更されているのでその対応 106 * @og.rev 5.7.2.2 (2014/01/24) WEB-INF/classes フォルダがないと、xmlURL がnull になる対応。 107 * @og.rev 5.7.2.3 (2014/01/31) ファイルの存在チェックを追加します。 108 * @og.rev 6.4.3.3 (2016/03/04) 初期 DBConfig.xml ファイルの設定。 109 * @og.rev 6.6.0.0 (2016/12/01) コンテキストパスから、##バージョン番号を取り去った値を返すようにします。 110 * @og.rev 6.8.5.1 (2018/01/15) ClassLoader変数名を、clsl から、loader に変更(他の変数名と整合性を持たす)。 111 * 112 * @param infile XMLファイルの名前 113 */ 114 public DatabaseConfig( final String infile ) { 115 final String xmlfile = infile == null || infile.isEmpty() ? DB_CONFIG_FILE : infile ; // 引数が無い場合の初期設定を行います。 116 String fileName = null; 117 118 // 6.3.9.1 (2015/11/27) In J2EE, getClassLoader() might not work as expected. Use Thread.currentThread().getContextClassLoader() instead.(PMD) 119 final ClassLoader loader = Thread.currentThread().getContextClassLoader(); 120 URL xmlURL = loader.getResource( xmlfile ); 121 122 // 5.6.8.2 (2013/09/20) Tomcat8で、xmlURL が取得できなくなっている・・・ようだ。 123 // 6.4.1.1 (2016/01/16) PMD refactoring. Avoid if (x != y) ..; else ..; 124 if( xmlURL == null ) { 125 xmlURL = loader.getResource( "/" ); // クラスパスのベースURL 126 // 5.7.2.2 (2014/01/24) Tomcat7で、WEB-INF/classes フォルダがないと、xmlURL がnull になる。 127 if( xmlURL != null ) { 128 final File temp = new File( xmlURL.getPath() , xmlfile ); 129 if( temp.exists() ) { fileName = temp.getAbsolutePath(); } 130 } 131 } 132 else { 133 fileName = xmlURL.getFile().replaceAll( "%23%23","##" ); // 6.6.0.0 (2016/12/01) 134 // 5.7.2.3 (2014/01/31) ファイルの存在チェックを追加します。 135 if( ! new File( fileName ).exists() ) { fileName = null; } 136 } 137 138 // 5.1.9.0 (2010/08/01) クラスローダー外からでもDBConfig.xmlを取得できるようにする 139 if( fileName == null && new File( xmlfile ).exists() ) { 140 fileName = xmlfile; 141 } 142 143 if( fileName == null ) { 144 // 5.5.7.2 (2012/10/09) コメント追加 145 final String errMsg = "DBConfig.xmlが見つかりません。File=[" + xmlfile + "]\n" 146 + " WEB-INF/classes フォルダがないと、相対パスで見つけることができません。" ; 147 throw new OgRuntimeException( errMsg ); 148 } 149 150 xmlFilename = fileName; 151 152 init(); // 5.6.7.0 (2013/07/27) 153 } 154 155 /** 156 * dbidKeyをキーにしてExpandedDbid型でマップの内容を返す。 157 * 存在しない場合はNULLを返します。 158 * キーが無い場合に初期化を行う。 159 * 160 * @og.rev 4.0.0.1 (2007/12/04) EDbid#clone() 廃止 161 * @og.rev 5.6.7.0 (2013/07/27) synchronized メソッドにします。 162 * @og.rev 6.0.0.1 (2014/04/25) Collections.synchronizedMap を使用します。 163 * 164 * @param key XMLで登録したdbidKey 165 * 166 * @return EDbid型オブジェクト 167 */ 168 public EDbid getDbid( final String key ) { 169 return dbidMap.get( key.toUpperCase( Locale.JAPAN ) ) ; 170 } 171 172 /** 173 * マップをクリアします。 174 * XMLファイルを再読み込みする場合に使用します。 175 * 176 * @og.rev 5.1.9.0 (2010/08/01) ドライバーのリストもクリアする。 177 * @og.rev 5.6.7.0 (2013/07/27) synchronized メソッドにします。 178 * @og.rev 6.0.0.1 (2014/04/25) Collections.synchronizedMap を使用します。 179 */ 180 public void reload() { 181 dbidMap.clear(); 182 driverList.clear(); 183 init(); 184 } 185 186 /** 187 * 初期化処理 188 * 189 * DB設定XMLファイル(DBConfig.xml)を読み込みます。 190 * このファイルから、ドライバーリストの取得、DBIDのオブジェクトマップの作成を 191 * 行います。 192 * EDbidオブジェクト は、環境変数で、共通の初期値を定義しておくことが可能です。 193 * 項目として、REALM_URL、REALM_NAME、REALM_PASSWORD が設定可能です。 194 * 195 * ドライバーリストの取得後、Class.forName で、ドライバの登録も行います。 196 * 197 * @og.rev 5.1.7.0 (2010/06/01) org.opengion.fukurou.xml.jaxb.dbid 関係 廃止 198 * @og.rev 5.6.7.0 (2013/07/27) dbidMap,driverList を書き込むのではなく、作成します。 199 * @og.rev 7.2.3.1 (2020/04/17) System.getenv → HybsConst.getenv 変更(サービス化対応) 200 */ 201 private void init() { 202 final Document doc = DomParser.read( new File(xmlFilename) ) ; 203 final Element firstRoot = doc.getDocumentElement(); 204 205 makeDriverList( firstRoot ); // 5.6.7.0 (2013/07/27) 206 207 // 5.6.7.0 (2013/07/27) を、かけておきます。 208 synchronized ( this ) { 209 for( final String dr : driverList ) { 210 try { 211 Class.forName( dr ); 212// } catch( final ClassNotFoundException ex ) { // 7.0.0.1 (2018/10/09) LinkageErrorが発生したので、いっそすべてをcatchします。 213 } catch( final Throwable th ) { 214 final String errMsg = "ドライバクラスが見つかりません。[" + dr + "]" ; 215 LogWriter.log( errMsg ); 216 LogWriter.log( th ); 217 } 218 } 219 } 220 221 final EDbid defDdbid = new EDbid(); // 初期値 222// defDdbid.setUrl( System.getenv( "REALM_URL" ) ); 223// defDdbid.setUser( System.getenv( "REALM_NAME" ) ); 224// defDdbid.setPassword( System.getenv( "REALM_PASSWORD" ) ); 225 defDdbid.setUrl( HybsConst.getenv( "REALM_URL" ) ); // 7.2.3.1 (2020/04/17) 226 defDdbid.setUser( HybsConst.getenv( "REALM_NAME" ) ); // 7.2.3.1 (2020/04/17) 227 defDdbid.setPassword( HybsConst.getenv( "REALM_PASSWORD" ) ); // 7.2.3.1 (2020/04/17) 228 229 makeDbidMap( firstRoot,defDdbid ); // 5.6.7.0 (2013/07/27) 230 } 231 232 /** 233 * ドライバーリストを取得します。 234 * 235 * DB設定XMLファイル(DBConfig.xml)の、class タグを取り込みます。 236 * このファイルから、ドライバーリストを取得します。 237 * 238 * 内部的に3段階の処理が実行されます。 239 * 第1Step:DBConfig.xml から、ドライバーリストを取得 240 * 第2Step:ドライバーリストが存在しない場合、環境変数の REALM_DRIVER からドライバーを取得 241 * 第3Step:それでも存在しない場合、このクラスの DEFAULT_DRIVER 定数 からドライバーを取得 242 * 243 * @og.rev 5.1.7.0 (2010/06/01) org.opengion.fukurou.xml.jaxb.dbid 関係 廃止 244 * @og.rev 5.1.9.0 (2010/08/01) ドライバ一覧のListをオブジェクト変数化 245 * @og.rev 5.6.7.0 (2013/07/27) driverList を書き込むのではなく、作成します。 246 * @og.rev 5.6.7.0 (2013/07/27) synchronized メソッドにします。 247 * @og.rev 7.2.3.1 (2020/04/17) System.getenv → HybsConst.getenv 変更(サービス化対応) 248 * 249 * @param element DB設定XMLファイルのElementオブジェクト 250 */ 251 private void makeDriverList( final Element element ) { 252 253 final NodeList list = element.getElementsByTagName( "class" ) ; 254 final int num = list.getLength(); 255 for( int i=0; i<num; i++ ) { 256 final Element cls = (Element)list.item(i); 257 driverList.add( cls.getTextContent() ); 258 } 259 260 if( driverList.isEmpty() ) { 261// final String realmDriver = System.getenv( "REALM_DRIVER" ); 262 final String realmDriver = HybsConst.getenv( "REALM_DRIVER" ); // 7.2.3.1 (2020/04/17) 263 if( realmDriver != null && realmDriver.length() > 0 ) { 264 driverList.add( realmDriver ); 265 } 266 } 267 268 if( driverList.isEmpty() ) { driverList.add( DEFAULT_DRIVER ); } 269 } 270 271 /** 272 * EDbidオブジェクトのマップを取得します。 273 * 274 * DB設定XMLファイル(DBConfig.xml)の、dbid タグを取り込みます。 275 * このファイルから、EDbidオブジェクトの属性情報を取得し、オブジェクトを構築します。 276 * 277 * EDbidオブジェクト は、初期値をコピーして、作成していきます。 278 * EDbidオブジェクトをマップから取り出すキーとなる、dbidKey は、大文字化して設定します。 279 * 280 * 7.0.5.0 (2019/09/09) 281 * begin,end,step,var,items 属性に対して、stepを年月指定できるように、type属性を追加しました。 282 * type="month" で、begin,end を、年月として処理します。 283 * 284 * @og.rev 5.1.7.0 (2010/06/01) org.opengion.fukurou.xml.jaxb.dbid 関係 廃止 285 * @og.rev 5.1.9.0 (2010/08/01) Mapを返すように変更 286 * @og.rev 5.5.2.0 (2012/05/01) property追加 287 * @og.rev 5.6.6.0 (2013/07/05) 表題(title)属性の取得 288 * @og.rev 5.6.7.0 (2013/07/27) 内部MapをDBConfig.xmlの読み込み順に変更。 289 * @og.rev 5.6.7.0 (2013/07/27) dbidMap を書き込むのではなく、作成します。 290 * @og.rev 5.6.7.0 (2013/07/27) synchronized メソッドにします。 291 * @og.rev 5.6.7.1 (2013/08/09) DEFAULT と、RESOURCE の DBIDキーがなければ、内部的に作成します。 292 * @og.rev 5.6.8.0 (2013/09/06) RESOURCE の DBIDキーを内部作成時に、title も設定します。 293 * @og.rev 6.4.3.4 (2016/03/11) computeIfAbsent と、新しい clone(String) メソッドを使用する。 294 * @og.rev 6.8.2.4 (2017/11/20) 環境変数( ${env.XXXX} ) を処理できるようにします。 295 * @og.rev 6.9.2.0 (2018/03/05) dbidに、begin,end,step,var,items 属性を追加します(影響は、ForEachObject内)。 296 * @og.rev 7.0.5.0 (2019/09/09) dbidに、type 属性を追加します(影響は、ForEachObject内)。 297 * 298 * @param element DB設定XMLファイルのElementオブジェクト 299 * @param defDdbid 初期情報の設定された、EDbidオブジェクト 300 */ 301 private void makeDbidMap( final Element element , final EDbid defDdbid ) { 302 final NodeList list = element.getElementsByTagName( "dbid" ) ; 303 final int num = list.getLength(); 304 for( int i=0; i<num; i++ ) { 305 final Element ele = (Element)list.item(i); 306 final ForEachObject forEach = new ForEachObject( ele ); 307 308 while( forEach.hasNext() ) { 309 final NodeList childs = ele.getChildNodes(); 310 final int numChild = childs.getLength(); 311 final EDbid dbid = defDdbid.clone(); // 初期値をコピーして、作成 312 for( int j=0; j<numChild; j++ ) { 313 final Node nd = childs.item(j); 314 if( nd.getNodeType() == Node.ELEMENT_NODE ) { 315 final Element el = (Element)nd; 316 final String tag = el.getTagName(); 317// // 6.8.2.4 (2017/11/20) 環境変数( ${env.XXXX} ) を処理できるようにします。 318// final String txt = envText( el.getTextContent() ); 319 // 6.9.2.0 (2018/03/05) 変数の置き換え( ${var} )と、環境変数( ${env.XXXX} ) を処理します。 320 final String txt = forEach.getText( el.getTextContent() ); 321 322 // dbidKey は、toUpperCase して、大文字のみとする。 323 // 6.8.2.4 (2017/11/20) 環境変数( ${env.XXXX} ) を処理できるようにします。 324 if( "dbidKey".equals( tag ) ) { 325 if( txt != null && txt.length() > 0 ) { 326 dbid.setDbidKey( txt.toUpperCase( Locale.JAPAN ) ); 327 } 328 } 329 else if( "title".equals( tag ) ) { dbid.setTitle( txt ); } // 5.6.6.0 (2013/07/05) 表題(title)属性の取得 330 else if( "url".equals( tag ) ) { dbid.setUrl( txt ); } 331 else if( "user".equals( tag ) ) { dbid.setUser( txt ); } 332 else if( "password".equals( tag ) ) { dbid.setPassword( txt ); } 333 else if( "readonly".equals( tag ) ) { dbid.setReadonly( txt ); } 334 else if( "mincount".equals( tag ) ) { dbid.setMincount( txt ); } 335 else if( "maxcount".equals( tag ) ) { dbid.setMaxcount( txt ); } 336 else if( "pooltime".equals( tag ) ) { dbid.setPooltime( txt ); } 337 else if( "applicationInfo".equals( tag ) ) { dbid.setApplicationInfo( txt ); } 338 else if( "property".equals( tag ) ) { dbid.addProp( txt ); } // 5.5.2.0 (2012/05/01) 339 else { 340 System.err.println( "警告:dbid に新しい属性が、追加されています。" ); 341 } 342 } 343 } 344 dbidMap.put( dbid.getDbidKey(), dbid ); // 5.6.7.0 (2013/07/27) 復活 345 } 346 } 347 348 // 5.6.7.1 (2013/08/09) DEFAULT と、RESOURCE の DBIDキーがなければ、内部的に作成します。 349 // 6.4.3.4 (2016/03/11) computeIfAbsent と、新しい clone(String) メソッドを使用する。 350 // Map#computeIfAbsent : 戻り値は、既存の、または計算された値。追加有り、置換なし、削除なし 351 dbidMap.computeIfAbsent( "DEFAULT", k -> defDdbid.clone( "DEFAULT" ) ); // DEFAULT が存在するか確認する。 352 353 // 6.4.3.4 (2016/03/11) computeIfAbsent と、新しい clone(String) メソッドを使用する。 354 // Map#computeIfAbsent : 戻り値は、既存の、または計算された値。追加有り、置換なし、削除なし 355 dbidMap.computeIfAbsent( "RESOURCE", k -> defDdbid.clone( "RESOURCE" ) ); // RESOURCE が存在するか確認する。 356 } 357 358// /** 359// * 環境変数( ${env.XXX} )を含むテキストを処理します。 360// * 361// * 環境変数を含まない場合は、引数の orgTxt を返します。 362// * 363// * @og.rev 6.8.2.4 (2017/11/20) 環境変数( ${env.XXXX} ) を処理できるようにします。 364// * 365// * @param orgTxt 環境変数( ${env.XXX} )を含む可能性のあるテキスト 366// * @return 環境変数を処理したテキスト 367// */ 368// private String envText( final String orgTxt ) { 369// final int st = orgTxt.indexOf( "${env." ); 370// if( st >= 0 ) { 371// final int ed = orgTxt.indexOf( '}' , st ); 372// if( ed >= 0 ) { 373// final String envKey = orgTxt.substring( st + "${env.".length() , ed ); 374// final String envTxt = orgTxt.substring( 0,st ) + System.getenv( envKey ) + orgTxt.substring( ed+1 ); 375// return envText( envTxt ); // ループすべきだが、再帰処理で対応します。 376// } 377// else { 378// final String errMsg = xmlFilename + " の環境変数( ${env.XXX} )の整合性が取れていません。" + orgTxt ; 379// throw new OgRuntimeException( errMsg ); 380// } 381// } 382// 383// return orgTxt; 384// } 385 386 /** 387 * dbidの属性処理が、煩雑になってきたので、内部クラスにまとめます。 388 * 389 * begin,end,step,var,items 属性で、ループ処理を行うための設定を取得します。 390 * items が未指定の場合は、begin,end,step による、数字(文字列)の配列を返します。 391 * itemsが、定義されている場合は、カンマで分割後、文字列の配列を返します。 392 * それぞれ、初期値があり、begin=0 , end=0 or items要素数,step=1, 393 * 394 * @og.rev 7.0.5.0 (2019/09/09) type属性を追加。 395 * begin,end,step,var,items 属性に対して、stepを年月指定できるように、type属性を追加しました。 396 * type="month" で、begin,end を、年月として処理します。 397 * 398 * @og.rev 6.9.2.1 (2018/03/12) dbidに、begin,end,step,var,items 属性を追加します。 399 * @og.rev 7.0.5.0 (2019/09/09) dbidに、type 属性を追加します。 400 */ 401 private static final class ForEachObject { 402 private final String attVar ; // var 属性の値を、${xxxx} に置き換えた文字列。未定義は、null 403 private final String[] items ; // items 属性のCSV分割か、begin,end,step の数字文字列の配列 404 405 private int idx = -1; // hasNext() で、先にアップするので、一つ引いておきます。 406 407 /** 408 * Elementオブジェクトを指定して、インスタンスを生成するコンストラクタです。 409 * 410 * @og.rev 6.9.2.1 (2018/03/12) dbidに、begin,end,step,var,items 属性を追加します。 411 * @og.rev 7.0.5.0 (2019/09/09) dbidに、type 属性を追加します。 412 * 413 * @param ele DB設定XMLファイルのElementオブジェクト 414 */ 415 public ForEachObject( final Element ele ) { 416 // 6.9.2.0 (2018/03/05) dbidに、begin,end,step,var 属性を追加します。 417 if( ele.hasAttributes() ) { 418 final NamedNodeMap attNode = ele.getAttributes(); 419// final int attBgn = StringUtil.nval( getAttri( attNode,"begin" ),0 ); // 7.0.5.0 (2019/09/09) 削除 420// final int attStp = StringUtil.nval( getAttri( attNode,"step" ),1 ); // 7.0.5.0 (2019/09/09) (ifの中へ)移動 421 final String tmpVar = getAttri( attNode,"var" ); 422 attVar = StringUtil.isNull( tmpVar ) ? null : ( "${" + tmpVar + "}" ) ; // 置換元定数を作成します。 423 424// final String endStr = getAttri( attNode,"end" ); // 7.0.5.0 (2019/09/09) (ifの中へ)移動 425 final String itms = getAttri( attNode,"items" ); 426 if( StringUtil.isNull( itms ) ) { 427 final String bgiStr = getAttri( attNode,"begin" ); // 7.0.5.0 (2019/09/09) 追加 428 final String endStr = getAttri( attNode,"end" ); // 7.0.5.0 (2019/09/09) (ifの中へ)移動 429 final int attStp = StringUtil.nval( getAttri( attNode,"step" ),1 ); 430 431 final String typStr = getAttri( attNode,"type" ); // 7.0.5.0 (2019/09/09) 新規追加 432 if( "month".equalsIgnoreCase( typStr ) ) { // 7.0.5.0 (2019/09/09) 新規追加 433 items = HybsDateUtil.stepYM( bgiStr,endStr,attStp ); 434 } 435 else { 436 final int attBgn = StringUtil.nval( bgiStr,0 ); // 7.0.5.0 (2019/09/09) 文字列化をint化 437 438 final int attEnd = StringUtil.nval( endStr,attBgn+1 ); // とりあえず 1回は回すため。 439 final List<String> list = new ArrayList<>(); 440 for( int i=attBgn; i<attEnd; i+=attStp ) { 441 list.add( String.valueOf( i ) ); 442 } 443 444// items = list.toArray( new String[list.size()] ) ; 445 items = list.toArray( new String[0] ) ; // 8.5.4.2 (2024/01/12) PMD 7.0.0 OptimizableToArrayCall 対応 446 } 447 } 448 else { 449 items = itms.split( "," ); 450 } 451 } 452 else { 453 attVar = null; 454 items = new String[] { "0" }; // 最低1回は回せるように。 455 } 456 } 457 458 /** 459 * 反復処理でさらに要素がある場合にtrueを返します。 460 * 461 * この判定で、内部カウンタを、プラスしていますので、 462 * ループ判定時にのみ、呼び出してください。 463 * 464 * @og.rev 6.9.2.1 (2018/03/12) 新規追加 465 * 466 * @return 反復処理でさらに要素がある場合はtrue 467 */ 468 public boolean hasNext() { return ++idx < items.length; } 469 470 /** 471 * 引数の文字列に対して、var 属性と item要素の置換を行います。 472 * 473 * さらに、${env.XXXX} 環境変数の置換と、日付文字列{@DATE.XXXX}の置換も 474 * 行います。 475 * この処理では、内部カウンタはアップしませんので、inTxt を替えて、何度でも 476 * 呼び出すことが可能です。 477 * 478 * @og.rev 6.9.2.1 (2018/03/12) 新規追加 479 * @og.rev 7.2.5.0 (2020/06/01) ${env.XXXX} 環境変数 は、{@ENV.XXXX} も対応します。 480 * 481 * @param inTxt 置換元の文字列 482 * @return items属性に対応して置換された、文字列 483 */ 484 public String getText( final String inTxt ) { 485 String rtnTxt = StringUtil.replace( inTxt , attVar , items[idx] ); // attVar が null の場合、inTxt が戻される。 486 rtnTxt = StringUtil.replaceText( rtnTxt , "${env." , "}" , System::getenv ); // 環境変数置換 487 rtnTxt = StringUtil.replaceText( rtnTxt , "{@ENV." , "}" , System::getenv ); // 7.2.5.0 (2020/06/01) 環境変数置換 488 rtnTxt = StringUtil.replaceText( rtnTxt , "{@DATE." , "}" , HybsDateUtil::getDateFormat ); // 日付文字列置換 489 490 return rtnTxt; 491 } 492 493 /** 494 * 属性を取得する簡易メソッドです。 495 * 496 * 引数に、ノードのコレクションと、属性のキーワードを指定することで、属性値を返します。 497 * 498 * @og.rev 6.9.2.0 (2018/03/05) 新規追加 499 * @og.rev 7.2.5.0 (2020/06/01) ${env.XXXX} 環境変数 は、{@ENV.XXXX} も対応します。 500 * 501 * @param nodeMap 名前を指定してアクセスできるノードのコレクション 502 * @param key 属性のキーワード 503 * @return 属性値(キーに対応する属性が無い場合は、null) 504 */ 505 private String getAttri( final NamedNodeMap nodeMap,final String key ) { 506 final Node attNode = nodeMap.getNamedItem( key ); 507 508// return attNode == null ? null : attNode.getNodeValue() ; 509 510 String rtnTxt = attNode == null ? null : attNode.getNodeValue() ; 511 512 rtnTxt = StringUtil.replaceText( rtnTxt , "${env." , "}" , System::getenv ); // 環境変数置換 513 rtnTxt = StringUtil.replaceText( rtnTxt , "{@ENV." , "}" , System::getenv ); // 7.2.5.0 (2020/06/01) 環境変数置換 514 rtnTxt = StringUtil.replaceText( rtnTxt , "{@DATE." , "}" , HybsDateUtil::getDateFormat ); // 日付文字列置換 515 516 return rtnTxt; 517 } 518 } 519 520 /* ------------------------------------------------------------------------------------ 521 * 522 * 以下は、DBConfig.xml編集用のメソッドです。 523 * 編集用のメソッドでは、オブジェクト化されたDBID及びDBDRIVERの情報は使用せずに、 524 * DBConfig.xmlからその情報を再度読み出して、SET/GETしています。 525 * (オブジェクトとして依存しているのは、DBConfig.xmlのファイル名のみです) 526 * 527 * ------------------------------------------------------------------------------------- 528 */ 529 /** 530 * DBIDとして管理している項目のキーの一覧を配列形式で返します。 531 * 532 * @og.rev 5.1.9.0 (2010/08/01) 新規作成 533 * 534 * @return 項目のキー一覧 535 * @og.rtnNotNull 536 */ 537 public static String[] getDbidInfoKeys() { 538 return DBID_INFO_KEYS.clone(); 539 } 540 541 /** 542 * 全てのDBIDの属性情報のリスト(配列)で返します。 543 * 544 * 値の順番については、{@link #getDbidInfoKeys()}で返されるキーの一覧と同じです。 545 * 546 * @og.rev 5.1.9.0 (2010/08/01) 新規作成 547 * @og.rev 5.5.2.1 (2012/05/07) propertiesを出力 548 * @og.rev 5.6.6.0 (2013/07/05) 表題(title)属性を追加 549 * @og.rev 5.6.7.0 (2013/07/27) 内部MapをDBConfig.xmlの読み込み順に変更。 550 * @og.rev 6.3.9.0 (2015/11/06) Use block level rather than method level synchronization.(PMD) 551 * 552 * @return 全てのDBIDの属性情報のリスト(配列) 553 * @og.rtnNotNull 554 * @see #getDbidInfoKeys() 555 */ 556 public String[][] getDbidInfo() { 557 // 6.3.9.0 (2015/11/06) 色々やりたいが、今はsynchronizedブロックにするだけにします。 558 synchronized( dbidMap ) { 559 final String[][] dbidInfo = new String[dbidMap.size()][DBID_INFO_KEYS.length]; // 8.5.4.2 (2024/01/12) PMD 7.0.0 LocalVariableCouldBeFinal 560 int idx = 0; 561 for( final EDbid dbid : dbidMap.values() ) { 562 dbidInfo[idx][0] = dbid.getDbidKey(); 563 dbidInfo[idx][1] = dbid.getTitle(); // 5.6.6.0 (2013/07/05) 表題(title)属性を追加 564 dbidInfo[idx][2] = dbid.getUrl(); 565 dbidInfo[idx][3] = dbid.getUser(); 566 dbidInfo[idx][4] = dbid.getPassword(); 567 dbidInfo[idx][5] = String.valueOf( dbid.isReadonly() ); 568 dbidInfo[idx][6] = String.valueOf( dbid.getMincount() ); 569 dbidInfo[idx][7] = String.valueOf( dbid.getMaxcount() ); 570 dbidInfo[idx][8] = String.valueOf( dbid.getPooltime() ); 571 dbidInfo[idx][9] = String.valueOf( dbid.isApplicationInfo() ); 572 dbidInfo[idx][10]= String.valueOf( dbid.getProps().toString() ); // 5.5.2.1 (2012/05/07) 573 idx++; 574 } 575 576 return dbidInfo; 577 } 578 } 579 580 /** 581 * 全てのDBIDの属性情報のリスト(配列)をセットします。 582 * 583 * このメソッドを呼び出すと、DBConfig.xmlで定義されているDBID情報一覧を"一旦削除し"、 584 * その上で、引数のDBID情報一覧をDBConfig.xmlに書き込みます。 585 * 586 * 値の順番については、{@link #getDbidInfoKeys()}で返されるキーの一覧と同じです。 587 * 588 * 書き込みの直前に、同じフォルダにタイムスタンプを付加したバックアップファイルを作成します。 589 * 590 * @og.rev 5.1.9.0 (2010/08/01) 新規作成 591 * @og.rev 5.6.7.0 (2013/07/27) 内部MapをDBConfig.xmlの読み込み順に変更。 592 * 593 * @param dbidVals 全てのDBIDの属性情報の配列の配列 594 * @see #getDbidInfoKeys() 595 */ 596 public void setDbidInfo( final String[][] dbidVals ) { 597 FileUtil.copy( xmlFilename, xmlFilename + "_" + System.currentTimeMillis() ); 598 599 final Document doc = DomParser.read( new File(xmlFilename) ) ; 600 final Element firstRoot = doc.getDocumentElement(); 601 deleteChildElements( firstRoot, "dbid" ); 602 603 if( dbidVals != null && dbidVals.length > 0 ) { 604 // 5.6.7.0 (2013/07/27) 内部MapをDBConfig.xmlの読み込み順に変更(なので、廃止)。 605 // 8.5.4.2 (2024/01/12) PMD 7.0.0 ForLoopCanBeForeach 606// for( int i=0; i<dbidVals.length; i++ ) { 607 for( final String[] vals : dbidVals ) { 608 final Element newEle = doc.createElement( "dbid" ); 609// for( int j=0; j<dbidVals[i].length; j++ ) { 610 for( int j=0; j<vals.length; j++ ) { 611 final Element newChEle = doc.createElement( DBID_INFO_KEYS[j] ); 612// newChEle.setTextContent( dbidVals[i][j] ); 613 newChEle.setTextContent( vals[j] ); 614 newEle.appendChild( newChEle ); 615 } 616 firstRoot.appendChild( newEle ); 617 firstRoot.appendChild( doc.createTextNode( "\n\n" ) ); 618 } 619 } 620 621 DomParser.write( new File(xmlFilename), doc ); 622 623 reload(); // 5.6.7.0 (2013/07/27) DBIDの属性情報のリストを更新後、初期化します。 624 } 625 626 /** 627 * DBドライバーの属性キーを返します。 628 * 629 * @og.rev 5.1.9.0 (2010/08/01) 新規作成 630 * 631 * @return DBドライバーの属性キー 632 * @og.rtnNotNull 633 */ 634 public static String getDriverKey() { 635 return DBDRIVER_CLASS_KEY; 636 } 637 638 /** 639 * DBドライバーのリスト(配列)を返します。 640 * 641 * @og.rev 5.1.9.0 (2010/08/01) 新規作成 642 * @og.rev 5.6.7.0 (2013/07/27) driverList を書き込むのではなく、作成します。 643 * 644 * @return DBドライバーリスト(配列) 645 * @og.rtnNotNull 646 */ 647 public String[] getDriverList() { 648// return driverList.toArray( new String[driverList.size()] ); 649 return driverList.toArray( new String[0] ); // 8.5.4.2 (2024/01/12) PMD 7.0.0 OptimizableToArrayCall 対応 650 } 651 652 /** 653 * DBドライバーのリスト(配列)をセットします。 654 * 655 * このメソッドを呼び出すと、DBConfig.xmlで定義されているclass一覧を"一旦削除し"、 656 * その上で、引数のDBドライバー一覧をDBConfig.xmlに書き込みます。 657 * 658 * 書き込みの直前に、同じフォルダにタイムスタンプを付加したバックアップファイルを作成します。 659 * 660 * @og.rev 5.1.9.0 (2010/08/01) 新規作成 661 * @og.rev 5.6.7.0 (2013/07/27) DBドライバーのリストを更新後、初期化します。 662 * 663 * @param drivers DBドライバーの配列(可変長引数) 664 */ 665 public void setDriverList( final String... drivers ) { 666 FileUtil.copy( xmlFilename, xmlFilename + "_" + System.currentTimeMillis() ); 667 668 final Document doc = DomParser.read( new File(xmlFilename) ); 669 final Element firstRoot = doc.getDocumentElement(); 670 671 final Element parent = (Element)firstRoot.getElementsByTagName( "dbDriver" ).item( 0 ); 672 deleteChildElements( parent, "class" ); 673 674 // 6.1.1.0 (2015/01/17) 可変長引数でもnullは来る。 675 if( drivers != null && drivers.length > 0 ) { 676 // 8.5.4.2 (2024/01/12) PMD 7.0.0 ForLoopCanBeForeach 677// for( int i=0; i<drivers.length; i++ ) { 678 for( final String driver : drivers ) { 679 final Element newEle = doc.createElement( "class" ); 680// newEle.setTextContent( drivers[i] ); 681 newEle.setTextContent( driver ); 682 parent.appendChild( newEle ); 683 } 684 } 685 686 DomParser.write( new File(xmlFilename), doc ); 687 688 reload(); // 5.6.7.0 (2013/07/27) DBドライバーのリストを更新後、初期化します。 689 } 690 691 /** 692 * DBID情報のキーとタイトルから、プルダウンメニューを作成するための情報を取得します。 693 * 694 * このメソッドを呼び出すと、DBConfig.xmlで定義されている dbidKey と、title 属性から、 695 * 「key1:val1 key2:val2 ・・・」という文字列を作成します。 696 * これを利用すれば、プルダウンメニューが簡単に作成できます。 697 * 698 * @og.rev 5.6.7.0 (2013/07/27) プルダウンメニュー用の情報を作成します。 699 * @og.rev 5.6.7.1 (2013/08/09) 表題(title)属性のスペース対策 700 * @og.rev 6.2.6.0 (2015/06/19) 表題(title)属性のスペース対策(KEY:LBL をダブルクオートで囲う) 701 * @og.rev 6.3.9.0 (2015/11/06) Use block level rather than method level synchronization.(PMD) 702 * @og.rev 7.1.0.0 (2020/01/20) DB接続できないDBIDはプルダウンメニューに含めない。 703 * @og.rev 7.2.3.1 (2020/04/17) 超特殊処理:Derby の場合は、エラーメッセージを出さない。 704 * 705 * @return プルダウンメニューを作成するための情報 706 */ 707 public String getCodeKeyVal() { 708 if( codeKeyVal == null ) { 709 final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE ); 710 // 6.3.9.0 (2015/11/06) 色々やりたいが、今はsynchronizedブロックにするだけにします。 711 synchronized( dbidMap ) { 712 for( final EDbid dbid : dbidMap.values() ) { 713 final String key = dbid.getDbidKey(); 714 final String dbName = dbid.getDbProductName(); // 7.2.3.1 (2020/04/17) 715 try { // 7.1.0.0 (2020/01/20) 716// if( dbid.getDbProductName() == null ) { 717 if( dbName == null ) { 718 ConnectionFactory.getDBName( key ); // 7.1.0.0 (2020/01/20) DB接続テスト 719 } 720 721 final String lbl = StringUtil.nval( dbid.getTitle() , key ); 722 // 6.0.2.5 (2014/10/31) char を append する。 723 if( lbl.indexOf( ' ' ) >= 0 ) { // 5.6.7.1 (2013/08/09) スペース対策 724 buf.append( '"' ).append( key ).append( ':' ).append( lbl ).append( '"' ); 725 } 726 else { 727 buf.append( key ).append( ':' ).append( lbl ); 728 } 729 buf.append( ' ' ); 730 } 731 // catch( final OgRuntimeException ex ) { // 7.1.0.0 (2020/01/20) エラー時 732 catch( final RuntimeException ex ) { // 7.1.0.0 (2020/01/20) エラー時 733 // 7.2.3.1 (2020/04/17) 超特殊処理:Derby の場合は、エラーメッセージを出さない。 734 // ProductやdbNameはnullなので、URLから判定します。 735 final String dbUrl = dbid.getUrl(); 736 // 7.2.9.5 (2020/11/28) 737 if( dbUrl == null || !dbUrl.contains( "derby" ) ) { 738 System.err.println( "警告:" + dbUrl + "\t\n" + ex.getMessage() ); 739 } 740 741// if( dbUrl != null && dbUrl.contains( "derby" ) ) { 742// // final String errMsg = "DBID=[" + key + "] 接続できません" ; // エラーメッセージの簡素化 743// // System.err.println( errMsg ); 744// } 745// else { 746// System.err.println( "警告:" + dbUrl + "\t\n" + ex.getMessage() ); 747// } 748 } 749 } 750 } 751 752 buf.setLength( buf.length()-1 ); // 最後のスペースを削除 753 codeKeyVal = buf.toString(); 754 } 755 756 return codeKeyVal; 757 } 758 759 /** 760 * 親要素を基点として、引数で指定されたタグ名を持つ子要素を削除します。 761 * 762 * @og.rev 5.6.7.0 (2013/07/27) staticメソッド を イスタンスメソッドに変更 763 * 764 * @param parent 親要素 765 * @param childTagName 削除する子要素のタグ名 766 */ 767 private void deleteChildElements( final Element parent, final String childTagName ) { 768 Node child = parent.getFirstChild(); 769 boolean isDel = false; 770 while( child != null ) { 771 // エレメント間の改行Cも削除するため、次の異なる要素が来るまでは削除し続けます。 772 if( child.getNodeType() == Node.ELEMENT_NODE ) { 773 // 6.4.4.1 (2016/03/18) 774 isDel = ((Element)child).getTagName().equalsIgnoreCase( childTagName ); 775 } 776 777 final Node next = child.getNextSibling(); 778 if( isDel ) { 779 parent.removeChild( child ); 780 } 781 child = next; 782 } 783 } 784}