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