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