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.util; 017 018import java.util.Map; 019import java.util.LinkedHashMap; 020import java.util.Collections; // 6.4.3.1 (2016/02/12) refactoring 021import java.util.List; 022import java.util.ArrayList; 023import java.util.Iterator; 024import java.util.Arrays; 025import java.util.Date; 026import java.util.Locale; 027 028import java.text.DateFormat; 029import java.text.SimpleDateFormat; 030 031import org.opengion.fukurou.system.OgRuntimeException ; // 6.4.2.0 (2016/01/29) 032import static org.opengion.fukurou.system.HybsConst.CR; // 6.1.0.0 (2014/12/26) refactoring 033import static org.opengion.fukurou.system.HybsConst.BUFFER_MIDDLE; // 6.1.0.0 (2014/12/26) refactoring 034 035/** 036 * Argument は、バッチ処理の main メソッドの引数を解析するクラスです。 037 * Argument は、3つのタイプに分かれます。 038 * 039 * [コメント] : # で始まる引数で、使用されません。(登録もされません。) 040 * [引数] : #,-,= 以外で始まる通常の文字列。登録の順番が指定されます。 041 * [プロパティ]: - で始まり、キーと値を=で区切っているパラメータです。順序は無関係。 042 * 043 * これらのタイプを混在させても構いません。[引数]は、[コメント] や[プロパティ]を 044 * 無視した、入力の順番が重要視されます。取り出す場合も、番号で取り出します。 045 * 最初の[引数]が、0 で、以降 引数個数-1 までの番号で取り出します。 046 * [プロパティ]は、順番は無視し、キー部を指定することで取り出せます。 047 * ただし、キー部を重複して登録することは出来ません。なお、キー部の頭の文字列のみで 048 * 取り出すメソッドがあるため、key1,key2,key3 などと指定して、key で取り出せば、 049 * 複数プロパティを同一キーで取り出すことが可能です。 050 * [プロパティ]の指定では、キーと値を=で区切りますが、その前後にスペースを 051 * 入れないで下さい。引数の前後に = が付く文字列は指定できません。 052 * 053 * java Program AAA BBB #CCC -DD=XX -EE=YY -FF=ZZ GGG 054 * ~~~ ~~~ ~~~~ ~~~~~~ ~~~~~~ ~~~~~~ ~~~ 055 * [コメント] : #CCC 056 * [引数] : [0]=AAA , [1]=BBB , [2]=GGG 057 * [プロパティ]: key=DD,val=XX key=EE,val=YY key=FF,val=ZZ 058 * 059 * Argument の整合性チェックは、3つのパターンがあります。 060 * 061 * [引数]個数指定 :引数自身の最小個数、最大個数を登録しておくことで、プロパティのハイフン忘れ等を防止します。 062 * [プロパティ]必須チェック :必須キーが登録されたかどうかのチェックを行います。 063 * [プロパティ]整合性チェック : 指定されているキーのみ登録可能です。 064 * 065 * これらのチェックで、整合性チェックのみ、Argument の登録時に行います。 066 * それ以外は、取り出し時まで、判断できません。 067 * (取り出しは、登録がすべて終了したのちに行われると仮定しています) 068 * 069 * [プロパティ]のキー部の大文字・小文字は、厳格に判定しています。 070 * [プロパティ]設定可能なプロパティの値を指定することで、誤記入を防止します。 071 * 072 * @version 4.0 073 * @author Kazuhiko Hasegawa 074 * @since JDK5.0, 075 */ 076public final class Argument { 077 /** Argument引数のタイプ [コメント]は、無視されます。 {@value} */ 078 public static final int CMNT = 0; // [コメント] 079 080 /** Argument引数のタイプ [引数]は、入力順にアクセスできます。 {@value} */ 081 public static final int ARGS = 1; // [引数] 082 083 /** Argument引数のタイプ [プロパティ]は、-KEY=VALUE 形式でキーでアクセスできます。 {@value} */ 084 public static final int PROP = 2; // [プロパティ] 085 086 private boolean argOkFlag ; 087 private final List<String> argments = new ArrayList<>(); 088 /** 6.4.3.1 (2016/02/12) Collections.synchronizedMap で同期処理を行います。 */ 089 private final Map<String,String> propMap = Collections.synchronizedMap( new LinkedHashMap<>() ); 090 091 private int argRangeMin ; // 初期値:0 092 private int argRangeMax = 200 ; // 本当は、Windows の引数の上限値を設定 093 094 /** 6.4.3.1 (2016/02/12) Collections.synchronizedMap で同期処理を行います。 */ 095 private final Map<String,String> mustProparty = Collections.synchronizedMap( new LinkedHashMap<>() ); 096 /** 6.4.3.1 (2016/02/12) Collections.synchronizedMap で同期処理を行います。 */ 097 private final Map<String,String> usableProparty = Collections.synchronizedMap( new LinkedHashMap<>() ); 098 099 private final String programID ; 100 101 /** 102 * この Argument を使用している プログラムID(Javaクラス名)を指定して 103 * インスタンスを作成します。 104 * toString() する際に、表示します。 105 * 106 * @param pgid プログラムID 107 */ 108 public Argument( final String pgid ) { 109 programID = pgid; 110 } 111 112 /** 113 * Argument の配列文字列から、引数やプロパティをセットします。 114 * [プロパティ]のキー部の大文字・小文字は、厳格に判定しています。 115 * これは、main メソッド等で単独起動する場合に、引数そのままを 116 * セットする場合に使用します。 117 * 118 * @param args 引数配列(可変長引数) 119 * @see #putArgument( String ) 120 */ 121 public void setArgument( final String... args ) { 122 // 8.5.4.2 (2024/01/12) PMD 7.0.0 ForLoopCanBeForeach 123// for( int i=0; i<args.length; i++ ) { 124// putArgument( args[i] ); 125// } 126 for( final String arg : args ) { 127 putArgument( arg ); 128 } 129 } 130 131 /** 132 * Argument の文字列から、引数かプロパティをセットします。 133 * [プロパティ]のキー部の大文字・小文字は、厳格に判定しています。 134 * Argument を設定する時に、タイプ判断として、getArgumentType( String ) を 135 * 使用します。よって、不正な Argument を設定した場合は、強制終了されます。 136 * 137 * @og.rev 6.4.8.3 (2016/07/15) key,val 分解後は、#putArgument(String,String) 138 * @og.rev 8.5.5.1 (2024/02/29) switch を if 文に置き換えます。 139 * 140 * @param arg 引数 141 * @see #putArgument( String,String ) 142 */ 143 public void putArgument( final String arg ) { 144 final int type = getArgumentType( arg ); 145 if( ARGS == type ) { argments.add( arg ); } 146 else if( PROP == type ) { 147 final int sep = arg.indexOf( '=' ); // sep は、 0 以上保証済み 148 final String key = arg.substring(1,sep); 149 final String val = arg.substring(sep+1); 150 putArgument( key,val ); // 6.4.8.3 (2016/07/15) 151 } 152 153 // 8.5.5.1 (2024/02/29) switch を if 文に置き換え 154// switch( type ) { 155// case CMNT : break; 156// case ARGS : argments.add( arg ); break; 157// case PROP : 158// final int sep = arg.indexOf( '=' ); // sep は、 0 以上保証済み 159// final String key = arg.substring(1,sep); 160// final String val = arg.substring(sep+1); 161// putArgument( key,val ); // 6.4.8.3 (2016/07/15) 162// break; 163// default: break; 164// } 165 } 166 167 /** 168 * Argument の文字列から、プロパティをセットします。 169 * [プロパティ]のキー部の大文字・小文字は、厳格に判定しています。 170 * このメソッドは、引数 や コメントの判断を行いません。プロパティ のみ 171 * 設定されるものとして、処理します。 172 * プロパティの key=val が初めから分割されている場合の簡易メソッドです。 173 * 174 * @og.rev 6.4.8.3 (2016/07/15) val で、「\t」と、「\n」の文字列を、タブと改行に変換します。 175 * @og.rev 6.4.8.4 (2016/07/22) 元に戻します。タブと改行は、ここで変換できません。 176 * 177 * @param key プロパティのキー 178 * @param val プロパティの値 179 * @see #putArgument( String ) 180 */ 181 public void putArgument( final String key,final String val ) { 182 checkProparty( key ); // 3.8.0.1 (2005/06/17) 183 propMap.put( key,val ); 184 } 185 186 /** 187 * [引数]個数指定を設定します。 188 * 最大値、最小値を登録しておくことで、個数が、規定から外れていないか 189 * どうかを確認します。 190 * エラー判定は、実際に、[引数]を取り出すときに行われます。 191 * このチェックの登録は、putArgument( String ) の前でも後でもよく、 192 * getArgument の実行前であれば、いつでも構いません。 193 * 設定しない場合の初期値は、0~200 です。 194 * 195 * @param min [引数]の最小個数(初期値:0) 196 * @param max [引数]の最大個数(初期値:200) 197 */ 198 public void setArgRange( final int min, final int max ) { 199 argRangeMin = min ; 200 argRangeMax = max ; 201 } 202 203 /** 204 * [プロパティ]必須チェック Map 登録 205 * 必須キーが登録されたかどうかのチェックを行います。 206 * マスト判定は、実際に、[プロパティ]を取り出すときに行われます。 207 * すべてのプロパティーがセットし終わったかどうかの判断が出来ないためです。 208 * それ以外のチェックは、putArgument( String ) 時に行われるので、それまでに 209 * mustProparty のMapを登録しておく必要があります。 210 * ただし、引数文字列の記述チェック(使用してもよい値の配列チェック)は、 211 * #getProparty( String , String , String[] ) で行われるので、取得時になります。 212 * 213 * 設定しない場合の初期値は、制限なしです。 214 * 指定のMapのValue値には、エラー時のコメントを記述しておきます。 215 * 216 * @og.rev 6.4.3.1 (2016/02/12) Collections.synchronizedMap に置き換え。 217 * 218 * @param mustProp 必須キーのMap 219 * @see #getProparty( String , String , String[] ) 220 */ 221 public void setMustProparty( final Map<String,String> mustProp ) { 222 mustProparty.putAll( mustProp ) ; 223 } 224 225 /** 226 * [プロパティ]整合性チェック Map 登録 227 * 指定されているキーのみ登録可能です。 228 * エラー判定は、実際に、[プロパティ]を取り出すときに行われます。 229 * このチェックの登録は、putArgument( String ) 時に行われるので、それまでに 230 * usableProparty のMapを登録しておく必要があります。 231 * ただし、引数文字列の記述チェック(使用してもよい値の配列チェック)は、 232 * #getProparty( String , String , String[] ) で行われるので、取得時になります。 233 * 234 * 設定しない場合の初期値は、制限なしです。 235 * 指定のMapのValue値には、このキーに対する解説を登録しておきます。 236 * 237 * @og.rev 6.4.3.1 (2016/02/12) Collections.synchronizedMap に置き換え。 238 * 239 * @param useProp 使用可能キーのMap 240 */ 241 public void setUsableProparty( final Map<String,String> useProp ) { 242 usableProparty.putAll( useProp ) ; 243 } 244 245 /** 246 * Argument の文字列から、そのタイプを判断します。 247 * 引数の形式が不正な場合(例えば、キーと値の分離の = の前後にスペースが入った場合) 248 * RuntimeException で強制終了します。 249 * 250 * [コメント] : # で始まる引数で、使用されません。(登録もされません。) 251 * [引数] : #,-,= 以外で始まる通常の文字列。登録の順番が指定されます。 252 * [プロパティ]: - で始まり、キーと値を=で区切っているパラメータです。順序は無関係。 253 * 254 * ※ 引数の設定方法が間違っている場合、RuntimeException が throw されます。 255 * 256 * @og.rev 5.3.4.0 (2011/04/01) 空文字列など無関係なパラメータは処理しないように変更 257 * @og.rev 6.4.8.3 (2016/07/15) KEY=VALUE の VALUE が、ゼロ文字列でも許可します。 258 * 259 * @param arg 引数 260 * 261 * @return 引数タイプ(CMNT,ARGS,PROP) 262 * @see Argument#CMNT [コメント] 263 * @see Argument#ARGS [引数] 264 * @see Argument#PROP [プロパティ] 265 */ 266 public int getArgumentType( final String arg ) { 267 // 8.5.5.1 (2024/02/29) PMD 7.0.0 OnlyOneReturn メソッドには終了ポイントが 1 つだけ必要 268 final int rtn; 269 270 // 8.5.4.2 (2024/01/12) PMD 7.0.0 InefficientEmptyStringCheck 対応 271// if( arg == null || arg.trim().isEmpty() || '#' == arg.charAt(0) ) { 272 if( StringUtil.isNull( arg ) || '#' == arg.charAt(0) ) { 273// return CMNT; 274 rtn = CMNT; 275 } 276 else if( '=' == arg.charAt(0) ) { // 不正引数 277 final String errMsg = "引数の = の前後には、スペースを入れないで下さい。" 278 + " BAD Argument=[" + arg + "]" ; 279 throw new OgRuntimeException( errMsg ); 280 } 281 else if( '-' == arg.charAt(0) ) { 282 final int sep = arg.indexOf( '=' ); 283 // if( sep > 0 && sep < arg.length()-1 ) { 284 if( sep > 0 && sep < arg.length() ) { // 6.4.8.3 (2016/07/15) 285// return PROP; 286 rtn = PROP; 287 } 288 else { 289 final String errMsg = "-KEY を指定する場合は、= を続けて、VALUEを指定して下さい。" 290 + " -KEY=VALUE 形式 BAD Argument=[" + arg + "]" ; 291 throw new OgRuntimeException( errMsg ); 292 } 293 } 294 else { 295// return ARGS ; 296 rtn = ARGS ; 297 } 298 return rtn; 299 } 300 301 /** 302 * 指定の番号に対する[引数]を返します。 303 * [引数]は、#,-,= 以外で始まる通常の文字列として登録されています。 304 * 登録された順番で取得します。 305 * 306 * ※ 引数の設定方法が間違っている場合、RuntimeException が throw されます。 307 * 308 * @param adrs 番号 309 * 310 * @return [引数] 311 */ 312 public String getArgument( final int adrs ) { 313 // 以下のチェックは、getArgument が呼ばれて一度のみの実行でよい。 314 if( ! argOkFlag ) { 315 if( argRangeMin < argments.size() || argments.size() < argRangeMax ) { 316 final String errMsg = "[引数]個数が最小/最大個数を満たしていません。" 317 + " Min:" + argRangeMin + " <= " + argments.size() + " < Max:" + argRangeMax ; 318 throw new OgRuntimeException( errMsg ); 319 } 320 argOkFlag = true; 321 } 322 323 if( argments.size() <= adrs ) { 324 final String errMsg = "指定のアドレスは、[引数]設定個数外です。" 325 + " Size:" + argments.size() + " <= " + adrs ; 326 throw new OgRuntimeException( errMsg ); 327 } 328 329 return argments.get( adrs ); 330 } 331 332 /** 333 * 指定の番号に対する[引数]を返します。 334 * def には、文字列の初期値を指定しておきます。adrs に対応する値が、null の場合、 335 * この def をそのまま返します。 336 * 337 * 処理は、getArgument( int ) の結果を、使用しています。 338 * 339 * @param adrs 番号 340 * @param def 値が null の場合の初期値 341 * 342 * @return [引数] 343 * @see #getArgument( int ) 344 */ 345 public String getArgument( final int adrs, final String def ) { 346 final String value = getArgument( adrs ); 347 // 6.4.1.1 (2016/01/16) PMD refactoring. Avoid if (x != y) ..; else ..; 348 return value == null ? def : value ; 349 } 350 351 /** 352 * 指定の番号に対する[引数]を返します。 353 * def には、数字の初期値を指定しておきます。adrs に対応する値が、null の場合、 354 * この def をそのまま返します。 355 * 356 * 処理は、getArgument( int ) の結果を、使用しています。 357 * 358 * @param adrs 番号 359 * @param def 値が null の場合の初期値 360 * 361 * @return [引数] 362 * @see #getArgument( int ) 363 */ 364 public int getArgument( final int adrs, final int def ) { 365 final String value = getArgument( adrs ); 366 // 6.4.1.1 (2016/01/16) PMD refactoring. Avoid if (x != y) ..; else ..; 367 return value == null ? def : Integer.parseInt( value ) ; 368 } 369 370 /** 371 * 指定の番号に対する[引数]を返します。 372 * def には、boolean の初期値を指定しておきます。adrs に対応する値が、null の場合、 373 * この def をそのまま返します。 374 * 375 * 処理は、getArgument( int ) の結果を、使用しています。 376 * 377 * @param adrs 番号 378 * @param def 値が null の場合の初期値 379 * 380 * @return [引数] 381 * @see #getArgument( int ) 382 */ 383 public boolean getArgument( final int adrs, final boolean def ) { 384 final String value = getArgument( adrs ); 385 return ( value == null ) ? def : Boolean.parseBoolean( value ) ; // 6.1.0.0 (2014/12/26) refactoring 386 } 387 388 /** 389 * [プロパティ]整合性チェック 実行 390 * 設定された整合性チェックを実行します。 391 * 複数キーに対応する為に、先頭からの判定も行います。 392 * チェックするキーの大文字・小文字は、厳格に判定しています。 393 * 394 * ※ 引数の設定方法が間違っている場合、RuntimeException が throw されます。 395 * 396 * @og.rev 5.1.5.0 (2010/04/01) 判定の条件が、重複していたので修正。 397 * @og.rev 6.4.3.1 (2016/02/12) Collections.synchronizedMap に置き換え。 398 * @og.rev 6.4.3.3 (2016/03/04) Iterator 処理を、拡張for文に変更。 399 * 400 * @param key チェックする入力キー 401 */ 402 private void checkProparty( final String key ) { 403 404 // 第1の判定。 propMap にすでに存在していれば、エラーになる。 405 if( propMap.get( key ) != null ) { 406 final StringBuilder errMsg = new StringBuilder( BUFFER_MIDDLE ) 407 .append( "キー[" ).append( key ).append( "]は、すでに指定済みです。" ).append( CR ) 408 .append( " 登録済み:-" ) 409 .append( key ).append( '=' ).append( propMap.get( key ) ) // 6.0.2.5 (2014/10/31) char を append する。 410 .append( CR ); 411 throw new OgRuntimeException( errMsg.toString() ); 412 } 413 414 // 6.4.3.1 (2016/02/12) インスタンスで初期化しているため、null はない。 415 if( !mustProparty.isEmpty() ) { // 6.4.3.1 (2016/02/12) 416 // 第2の判定。 mustProparty に存在すれば、即抜けする。 417 if( mustProparty.containsKey( key ) ) { return; } 418 419 // 第3の判定。複数キー(先頭一致キー)の場合もありうるため、先頭からの比較を行う。 420 // 6.4.3.3 (2016/03/04) Iterator 処理を、拡張for分に変更。判定は、keyのみでよい 421 for( final String propKey : mustProparty.keySet() ) { 422 if( key.startsWith( propKey ) ) { return ; } // マッチすれば、即抜ける。 423 } 424 } 425 426 // 5.1.5.0 (2010/04/01) 判定の条件が、重複していたので修正。 427 // 6.4.3.1 (2016/02/12) インスタンスで初期化しているため、null はない。 428 if( !usableProparty.isEmpty() ) { // 6.4.3.1 (2016/02/12) 429 // 第4の判定。 usableProparty に存在すれば、即抜けする。 430 if( usableProparty.containsKey( key ) ) { return ; } 431 432 // 第5の判定。複数キー(先頭一致キー)の場合もありうるため、先頭からの比較を行う。 433 // 6.4.3.3 (2016/03/04) Iterator 処理を、拡張for分に変更。判定は、keyのみでよい 434 for( final String propKey : usableProparty.keySet() ) { 435 if( key.startsWith( propKey ) ) { return ; } // マッチすれば、即抜ける。 436 } 437 438 // そこまで探して見つからない場合は、定義外引数エラー 439 final StringBuilder errMsg = new StringBuilder( BUFFER_MIDDLE ) 440 .append( "-KEY が、指定の整合性リストに含まれていません。" ) 441 .append( CR ) 442 .append( " -KEY=VALUE 形式 BAD Key=[" ).append( key ).append( ']' ) // 6.0.2.5 (2014/10/31) char を append する。 443 .append( CR ) 444 .append( toString() ); 445 throw new OgRuntimeException( errMsg.toString() ); 446 } 447 } 448 449 /** 450 * 内部で使用する[プロパティ]を、キーを指定して取得します。 451 * 値が設定されていない場合は、 null を返します。 452 * [プロパティ]のキー部の大文字・小文字は、厳格に判定しています。 453 * 454 * ※ 引数の設定方法が間違っている場合、RuntimeException が throw されます。 455 * 456 * @og.rev 6.4.3.1 (2016/02/12) Collections.synchronizedMap に置き換え。 457 * 458 * @param key 引数のキー 459 * 460 * @return 引数に対する値 461 */ 462 public String getProparty( final String key ) { 463 464 final String value = propMap.get( key ); 465 466 // 値が null で must 設定があり、かつマストキーが指定している場合。 467 if( value == null && 468 // 6.4.3.1 (2016/02/12) インスタンスで初期化しているため、null はない。 469 !mustProparty.isEmpty() && // 6.4.3.1 (2016/02/12) 470 mustProparty.containsKey( key ) ) { 471 final String errMsg = "指定の[プロパティ]は、必須キーですが、値が null です。" 472 + " Key:" + key + " 説明:" + mustProparty.get( key ) 473 + CR + toString() ; 474 throw new OgRuntimeException( errMsg ); 475 } 476 477 return value ; 478 } 479 480 /** 481 * 内部で使用する[プロパティ]を、キーを指定して取得します。 482 * [プロパティ]のキー部の大文字・小文字は、厳格に判定しています。 483 * def には、文字列の初期値を指定しておきます。key に対応する値が、null の場合、 484 * この def をそのまま返します。 485 * 486 * 処理は、getProparty( String ) の結果を、使用しています。 487 * 488 * @param key キー 489 * @param def 値が null の場合の初期値 490 * 491 * @return [プロパティ] 492 * @see #getProparty( String ) 493 */ 494 public String getProparty( final String key, final String def ) { 495 final String value = getProparty( key ); 496 // 6.4.1.1 (2016/01/16) PMD refactoring. Avoid if (x != y) ..; else ..; 497 return value == null ? def : value ; 498 } 499 500 /** 501 * 内部で使用する[プロパティ]を、キーを指定して取得します。 502 * [プロパティ]のキー部の大文字・小文字は、厳格に判定しています。 503 * def には、文字列の初期値を指定しておきます。key に対応する値が、null の場合、 504 * この def をそのまま返します。 505 * list 配列には、登録できる文字列配列を指定します。この文字列に含まれない 506 * 値が設定されていた場合は、エラーになります。 507 * 508 * 処理は、getProparty( String ) の結果を、使用しています。 509 * 510 * ※ 引数の設定方法が間違っている場合、RuntimeException が throw されます。 511 * 512 * @param key キー 513 * @param def 値が null の場合の初期値 514 * @param list 値として存在できる文字列配列(可変長引数) 515 * 516 * @return [プロパティ] 517 * @see #getProparty( String ) 518 */ 519 public String getProparty( final String key, final String def, final String... list ) { 520 final String value = getProparty( key,def ); 521 if( value != null ) { 522 boolean isOK = false; 523 // 8.5.4.2 (2024/01/12) PMD 7.0.0 ForLoopCanBeForeach 524// for( int i=0; i<list.length; i++ ) { 525// if( value.equalsIgnoreCase( list[i] ) ) { 526 for( final String str : list ) { 527 if( value.equalsIgnoreCase( str ) ) { 528 isOK = true; break; 529 } 530 } 531 if( !isOK ) { 532 final String errMsg = key + " は、" + Arrays.toString( list ) 533 + " から指定してください。" + CR 534 + "-" + key + "=[" + value + "]" ; 535 throw new OgRuntimeException( errMsg ); 536 } 537 } 538 539 return value ; 540 } 541 542 /** 543 * 内部で使用する[プロパティ]を、キーを指定して取得します。 544 * [プロパティ]のキー部の大文字・小文字は、厳格に判定しています。 545 * def には、数字の初期値を指定しておきます。key に対応する値が、null の場合、 546 * この def をそのまま返します。 547 * 548 * 処理は、getProparty( String ) の結果を、使用しています。 549 * 550 * @param key キー 551 * @param def 値が null の場合の初期値 552 * 553 * @return [プロパティ] 554 * @see #getProparty( String ) 555 */ 556 public int getProparty( final String key, final int def ) { 557 final String value = getProparty( key ); 558 // 6.4.1.1 (2016/01/16) PMD refactoring. Avoid if (x != y) ..; else ..; 559 return value == null ? def : Integer.parseInt( value ) ; 560 } 561 562 /** 563 * 内部で使用する[プロパティ]を、キーを指定して取得します。 564 * [プロパティ]のキー部の大文字・小文字は、厳格に判定しています。 565 * def には、boolean の初期値を指定しておきます。key に対応する値が、null の場合、 566 * この def をそのまま返します。 567 * 568 * 処理は、getProparty( String ) の結果を、使用しています。 569 * 570 * @param key キー 571 * @param def 値が null の場合の初期値 572 * 573 * @return [プロパティ] 574 * @see #getProparty( String ) 575 */ 576 public boolean getProparty( final String key, final boolean def ) { 577 final String value = getProparty( key ); 578 return ( value == null ) ? def : Boolean.parseBoolean( value ) ; // 6.1.0.0 (2014/12/26) refactoring 579 } 580 581 /** 582 * 内部で使用する[プロパティ]を、キーを指定して取得します。 583 * [プロパティ]のキー部の大文字・小文字は、厳格に判定しています。 584 * key プロパティは、通常の引数として指定できる簡易的な値を設定します。 585 * keyFile プロパティ は、ファイル名を指定し、そのファイルの中身を 586 * 取得して返します。通常は1行であるが、時には複数行のデータを指定 587 * したい場合に、2つのパラメータを使いますが、設定値は、同じ引数として 588 * 使用したいケースに便利です。 589 * key プロパティと、keyFile プロパティ は、同時指定できません。 590 * これは、指定方法の間違い等を避ける為です。 591 * どちらも、null である可能性はあります。 592 * 593 * ※ 同時指定時、または、must 必須時に null の場合、RuntimeException が throw されます。 594 * 595 * @param key キー 596 * @param keyFile 設定ファイル名 597 * @param must 必須条件[true/false] 598 * 599 * @return [プロパティ] 600 * @see #getProparty( String ) 601 */ 602 public String getFileProparty( final String key, final String keyFile, final boolean must ) { 603 return getFileProparty( key,keyFile,null,must ); 604 } 605 606 /** 607 * 内部で使用する[プロパティ]を、キーを指定して取得します。 608 * [プロパティ]のキー部の大文字・小文字は、厳格に判定しています。 609 * key プロパティは、通常の引数として指定できる簡易的な値を設定します。 610 * keyFile プロパティ は、ファイル名を指定し、そのファイルの中身を 611 * 取得して返します。通常は1行であるが、時には複数行のデータを指定 612 * したい場合に、2つのパラメータを使いますが、設定値は、同じ引数として 613 * 使用したいケースに便利です。 614 * key プロパティと、keyFile プロパティ は、同時指定できません。 615 * これは、指定方法の間違い等を避ける為です。 616 * どちらも、null である可能性はあります。 617 * 618 * ※ 同時指定時、または、must 必須時に null の場合、RuntimeException が throw されます。 619 * 620 * @og.rev 6.4.5.1 (2016/04/28) FileStringのコンストラクター変更 621 * @og.rev 6.4.5.2 (2016/05/06) fukurou.util.FileString から、fukurou.util.FileUtil に移動。 622 * 623 * @param key キー 624 * @param keyFile 設定ファイル名 625 * @param encode keyFile読取エンコード(null はデフォルトエンコード) 626 * @param must 必須条件[true/false] 627 * 628 * @return [プロパティ] 629 * @see #getProparty( String ) 630 */ 631 public String getFileProparty( final String key, final String keyFile, 632 final String encode,final boolean must ) { 633 String val = getProparty( key ); 634 final String valFile = getProparty( keyFile ); 635 636 if( val != null && valFile != null ) { 637 final String errMsg = key + "か、" + keyFile + " は、両方同時に指定できません。[" + val + "],[" + valFile + "]"; 638 throw new OgRuntimeException( errMsg ); 639 } 640 641 if( valFile != null ) { 642 // 6.4.5.1 (2016/04/28) FileStringのコンストラクター変更 643 val = FileUtil.getValue( valFile , encode ); // 6.4.5.2 (2016/05/06) 644 } 645 646 if( must && val == null ) { 647 final String errMsg = key + "か、" + keyFile + " は、片方必須です。"; 648 throw new OgRuntimeException( errMsg ); 649 } 650 651 return val; 652 } 653 654 /** 655 * 内部で使用する[プロパティ]を、キーを先頭に含む値を取得します。 656 * [プロパティ]のキー部の大文字・小文字は、厳格に判定しています。 657 * 値が設定されていない場合は、String[0] を返します。 658 * HybsEntry のキーに設定される値は、引数の先頭キーを除いた文字列です。 659 * 例えば、"const_" のような値を与えて、const_AA, const_BB, const_CC の 660 * 3つのキーが選定された場合、キーは、AA, BB, CC のみ返します。 661 * 662 * @param startsKey 引数の先頭のキー 663 * 664 * @return 引数に対する[プロパティ]のHybsEntry 665 * @og.rtnNotNull 666 */ 667 public HybsEntry[] getEntrys( final String startsKey ) { 668// final ArrayList<HybsEntry> list = new ArrayList<>(); 669 final List<HybsEntry> list = new ArrayList<>(); // 8.5.4.2 (2024/01/12) PMD 7.0.0 LooseCoupling 670 final int len = startsKey.length(); 671 672 final Iterator<Map.Entry<String,String>> ite = propMap.entrySet().iterator(); // 4.3.3.6 (2008/11/15) Generics警告対応 673 while( ite.hasNext() ) { 674 final Map.Entry<String,String> entry = ite.next(); // 4.3.3.6 (2008/11/15) Generics警告対応 675 final String key = entry.getKey(); // 4.3.3.6 (2008/11/15) Generics警告対応 676 if( key.startsWith( startsKey ) ) { 677 list.add( new HybsEntry( key.substring( len ), entry.getValue() ) ); // 4.3.3.6 (2008/11/15) Generics警告対応 678 } 679 } 680 681// return list.toArray( new HybsEntry[list.size()] ) ; 682 return list.toArray( new HybsEntry[0] ) ; // 8.5.4.2 (2024/01/12) PMD 7.0.0 OptimizableToArrayCall 対応 683 } 684 685 /** 686 * 入力文字列に、{@XXXX}関係の文字列変換を行います。 687 * 引数に含まれる {@XXXX}=YYYY という入力に対して、inMsg に 688 * 含まれる{@XXXX} 文字列を、YYYY という文字列に変換します。 689 * それ以外に、予約文字変換として、 690 * {@ARG.XXX} 引数に使用された値を再利用(割り当て)します。 691 * {@DATE.XXX} SimpleDateFormat 形式の文字を変換します。(日付、時刻等) 692 * {@ENV.XXX} システムプロパティーの文字を変換します。(java -Dkey=value オプション) 693 * 694 * @param inMsg 入力文字列 695 * 696 * @return 変換後文字列 697 */ 698 public String changeParam( final String inMsg ) { 699 if( inMsg == null ) { return inMsg; } 700 701 String message = inMsg; 702 703 // {@ARG.XXXX} 変数の置換処理 704 int adrs = message.indexOf( "{@ARG." ) ; 705 while( adrs >= 0 ) { 706 final int end = message.indexOf( '}',adrs ) ; 707 final String key = message.substring( adrs+6,end ); 708 final String oldData = "{@ARG." + key + "}" ; 709 // 注意:{@XXX}と異なり、{@ARG.XXX} では、XXX で propMap を検索する。 710 final String newData = StringUtil.nval( getProparty( key ),"" ); 711 message = StringUtil.replace( message,oldData,newData ); 712 adrs = message.indexOf( "{@ARG.",adrs ) ; 713 } 714 // {@DATE.XXXX} 変数の置換処理 715 adrs = message.indexOf( "{@DATE." ) ; 716 if( adrs >= 0 ) { 717 final Date dt = new Date(); 718 while( adrs >= 0 ) { 719 final int end = message.indexOf( '}',adrs ) ; 720 final String key = message.substring( adrs+7,end ); 721 final String oldData = "{@DATE." + key + "}" ; 722 final DateFormat formatter = new SimpleDateFormat( key, Locale.JAPAN ); 723 final String newData = StringUtil.nval( formatter.format(dt),"" ); 724 message = StringUtil.replace( message,oldData,newData ); 725 adrs = message.indexOf( "{@DATE.",adrs ) ; 726 } 727 } 728 // {@ENV.XXXX} 変数の置換処理 729 adrs = message.indexOf( "{@ENV." ) ; 730 while( adrs >= 0 ) { 731 final int end = message.indexOf( '}',adrs ) ; 732 final String key = message.substring( adrs+6,end ); 733 final String oldData = "{@ENV." + key + "}" ; 734 final String newData = System.getProperty( key,"" ); 735 message = StringUtil.replace( message,oldData,newData ); 736 adrs = message.indexOf( "{@ENV.",adrs ) ; 737 } 738 739 // 残りのメッセージ本文中の置換文字列を処理します。 740 adrs = message.indexOf( "{@" ) ; 741 while( adrs >= 0 ) { 742 final int end = message.indexOf( '}',adrs ) ; 743 final String key = message.substring( adrs,end+1 ); // +1 注意 744 final String oldData = key ; 745 // 注意:{@ARG.XXX} と異なり、{@XXX} そのもので propMap を検索する。 746 final String newData = StringUtil.nval( getProparty( key ),"" ); 747 message = StringUtil.replace( message,oldData,newData ); 748 adrs = message.indexOf( "{@",adrs ) ; 749 } 750 751 return message; 752 } 753 754 /** 755 * このオブジェクトの内部表現を、文字列にして返します。 756 * クラス名 + 起動時の引数リストを表示します。 757 * 758 * @return 引数に対する値 759 * @og.rtnNotNull 760 */ 761 @Override // Object 762 public String toString() { 763 final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE ); 764 765 buf.append( "java " ).append( programID ).append( CR ); 766 767 if( ! argments.isEmpty() ) { 768 // 8.5.4.2 (2024/01/12) PMD 7.0.0 ForLoopCanBeForeach 769// for( int i=0; i<argments.size(); i++ ) { 770// buf.append( ' ' ).append( argments.get(i) ); // 6.0.2.5 (2014/10/31) char を append する。 771// } 772 for( final String arg : argments ) { 773 buf.append( ' ' ).append( arg ); // 6.0.2.5 (2014/10/31) char を append する。 774 } 775 buf.append( CR ); 776 } 777 778 final Iterator<Map.Entry<String,String>> propIte = propMap.entrySet().iterator(); // 4.3.3.6 (2008/11/15) Generics警告対応 779 while( propIte.hasNext() ) { 780 final Map.Entry<String,String> entry = propIte.next(); // 4.3.3.6 (2008/11/15) Generics警告対応 781 final String key = entry.getKey(); // 4.3.3.6 (2008/11/15) Generics警告対応 782 Object val = entry.getValue(); 783 if( key.startsWith( "passwd" ) ) { 784 val = "*****" ; 785 } 786 787 buf.append( " -" ).append( key ).append( '=' ).append( val ); // 6.0.2.5 (2014/10/31) char を append する。 788 buf.append( CR ); 789 } 790 791 return buf.toString(); 792 } 793 794 /** 795 * このクラスの使用方法を返します。 796 * 797 * @return このクラスの使用方法 798 * @og.rtnNotNull 799 */ 800 public String usage() { 801 final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE ) 802 .append( toString() ) 803 .append( CR ) 804 .append( propMapToString( "[ Must Proparty List ]" , mustProparty ) ) 805 .append( propMapToString( "[ Usable Proparty List ]", usableProparty ) ); 806 807 return buf.toString(); 808 } 809 810 /** 811 * プロパティーを文字列に変換します。 812 * 813 * propMap の キーの最大長さを求め、位置あわせのためのスペースを追加します。 814 * 815 * @param title タイトル 816 * @param propMap プロパティー(Mapオブジェクト) 817 * 818 * @return プロパティー文字列 819 * @og.rtnNotNull 820 */ 821 private String propMapToString( final String title,final Map<String,String> propMap ) { 822 final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE ); 823 824 if( propMap != null ) { 825 buf.append( title ).append( CR ); 826 827 // キーの長さをそろえるための処理 828 int maxLen = 0; 829 final Iterator<String> keyIte = propMap.keySet().iterator(); // 4.3.3.6 (2008/11/15) Generics警告対応 830 while( keyIte.hasNext() ) { 831 final int len = keyIte.next().length(); // 4.3.3.6 (2008/11/15) Generics警告対応 832 if( len > maxLen ) { maxLen = len; } 833 } 834 835 final char[] ch = new char[maxLen]; 836 Arrays.fill( ch,' ' ); // スペースで埋めます。 837 // 8.5.4.2 (2024/01/12) PMD 7.0.0 StringInstantiation 対応 838// final String SPACE = new String( ch ); 839 final String SPACE = String.valueOf( ch ); 840 841 final String VAL_SPACE = CR + SPACE + " " ; 842 843 final Iterator<Map.Entry<String,String>> propIte = propMap.entrySet().iterator(); // 4.3.3.6 (2008/11/15) Generics警告対応 844 while( propIte.hasNext() ) { 845 final Map.Entry<String,String> entry = propIte.next(); // 4.3.3.6 (2008/11/15) Generics警告対応 846 final String key = entry.getKey(); // 4.3.3.6 (2008/11/15) Generics警告対応 847 String val = entry.getValue(); // 4.3.3.6 (2008/11/15) Generics警告対応 848 if( val != null ) { val = val.replaceAll( CR,VAL_SPACE ); } 849 // 8.5.4.2 (2024/01/12) PMD 7.0.0 ConsecutiveAppendsShouldReuse 対応 850 buf.append( " -" ).append( key ) 851 .append( SPACE.substring( key.length() ) ) // 使用されるキー 852 .append( " : " ).append( val ) // その説明 853 .append( CR ); 854 } 855 } 856 857 return buf.toString(); 858 } 859}