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.length() == 0 || arg.startsWith( "#" ) ) { 240 if( arg == null || arg.trim().length() == 0 || arg.startsWith( "#" ) ) { // 5.3.4.0 (2011/04/01) 241 return CMNT; 242 } 243 else if( arg.startsWith( "=" ) || arg.endsWith( "=" ) ) { // 不正引数 244 String errMsg = "引数の = の前後には、スペースを入れないで下さい。" 245 + " BAD Argument=[" + arg + "]" ; 246 throw new RuntimeException( errMsg ); 247 } 248 else if( arg.startsWith( "-" ) ) { 249 int sep = arg.indexOf( '=' ); 250 if( sep > 0 && sep < arg.length()-1 ) { 251 return PROP; 252 } 253 else { 254 String errMsg = "-KEY を指定する場合は、= を続けて、VALUEを指定して下さい。" 255 + " -KEY=VALUE 形式 BAD Argument=[" + arg + "]" ; 256 throw new RuntimeException( errMsg ); 257 } 258 } 259 else { 260 return ARGS ; 261 } 262 } 263 264 /** 265 * 指定の番号に対する[引数]を返します。 266 * [引数]は、#,-,= 以外で始まる通常の文字列として登録されています。 267 * 登録された順番で取得します。 268 * 269 * ※ 引数の設定方法が間違っている場合、RuntimeException が throw されます。 270 * 271 * @param adrs 番号 272 * 273 * @return [引数] 274 */ 275 public String getArgument( final int adrs ) { 276 // 以下のチェックは、getArgument が呼ばれて一度のみの実行でよい。 277 if( ! argOkFlag ) { 278 if( argRangeMin < argments.size() || argments.size() < argRangeMax ) { 279 String errMsg = "[引数]個数が最小/最大個数を満たしていません。" 280 + " Min:" + argRangeMin + " <= " + argments.size() + " < Max:" + argRangeMax ; 281 throw new RuntimeException( errMsg ); 282 } 283 argOkFlag = true; 284 } 285 286 if( argments.size() <= adrs ) { 287 String errMsg = "指定のアドレスは、[引数]設定個数外です。" 288 + " Size:" + argments.size() + " <= " + adrs ; 289 throw new RuntimeException( errMsg ); 290 } 291 292 return argments.get( adrs ); 293 } 294 295 /** 296 * 指定の番号に対する[引数]を返します。 297 * def には、文字列の初期値を指定しておきます。adrs に対応する値が、null の場合、 298 * この def をそのまま返します。 299 * 300 * 処理は、getArgument( int ) の結果を、使用しています。 301 * 302 * @param adrs 番号 303 * @param def 値が null の場合の初期値 304 * 305 * @return [引数] 306 * @see #getArgument( int ) 307 */ 308 public String getArgument( final int adrs, final String def ) { 309 String value = getArgument( adrs ); 310 return ( value != null ) ? value : def ; 311 } 312 313 /** 314 * 指定の番号に対する[引数]を返します。 315 * def には、数字の初期値を指定しておきます。adrs に対応する値が、null の場合、 316 * この def をそのまま返します。 317 * 318 * 処理は、getArgument( int ) の結果を、使用しています。 319 * 320 * @param adrs 番号 321 * @param def 値が null の場合の初期値 322 * 323 * @return [引数] 324 * @see #getArgument( int ) 325 */ 326 public int getArgument( final int adrs, final int def ) { 327 String value = getArgument( adrs ); 328 return ( value != null ) ? Integer.parseInt( value ) : def ; 329 } 330 331 /** 332 * 指定の番号に対する[引数]を返します。 333 * def には、boolean の初期値を指定しておきます。adrs に対応する値が、null の場合、 334 * この def をそのまま返します。 335 * 336 * 処理は、getArgument( int ) の結果を、使用しています。 337 * 338 * @param adrs 番号 339 * @param def 値が null の場合の初期値 340 * 341 * @return [引数] 342 * @see #getArgument( int ) 343 */ 344 public boolean getArgument( final int adrs, final boolean def ) { 345 String value = getArgument( adrs ); 346 return ( value != null ) ? Boolean.valueOf( value ).booleanValue() : def ; 347 } 348 349 /** 350 * [プロパティ]整合性チェック 実行 351 * 設定された整合性チェックを実行します。 352 * 複数キーに対応する為に、先頭からの判定も行います。 353 * チェックするキーの大文字・小文字は、厳格に判定しています。 354 * 355 * ※ 引数の設定方法が間違っている場合、RuntimeException が throw されます。 356 * 357 * @og.rev 5.1.5.0 (2010/04/01) 判定の条件が、重複していたので修正。 358 * 359 * @param key チェックする入力キー 360 */ 361 private void checkProparty( final String key ) { 362 363 // 第1の判定。 proparty にすでに存在していれば、エラーになる。 364 if( proparty.get( key ) != null ) { 365 StringBuilder errMsg = new StringBuilder(); 366 367 errMsg.append( "キー[" ).append( key ).append( "]は、すでに指定済みです。" ).append( CR ); 368 errMsg.append( " 登録済み:-" ).append( key ).append( "=" ).append( proparty.get( key ) ); 369 errMsg.append( CR ); 370 throw new RuntimeException( errMsg.toString() ); 371 } 372 373 if( mustProparty != null ) { 374 // 第2の判定。 mustProparty に存在すれば、即抜けする。 375 if( mustProparty.containsKey( key ) ) { return; } 376 377 // 第3の判定。複数キー(先頭一致キー)の場合もありうるため、先頭からの比較を行う。 378 Iterator<Map.Entry<String,String>> ite = mustProparty.entrySet().iterator(); // 4.3.3.6 (2008/11/15) Generics警告対応 379 while( ite.hasNext() ) { 380 Map.Entry<String,String> entry = ite.next(); // 4.3.3.6 (2008/11/15) Generics警告対応 381 String propKey = entry.getKey(); // 4.3.3.6 (2008/11/15) Generics警告対応 382 if( key.startsWith( propKey ) ) { return ; } // マッチすれば、即抜ける。 383 } 384 } 385 386 // 5.1.5.0 (2010/04/01) 判定の条件が、重複していたので修正。 387// if( usableProparty != null && !usableProparty.containsKey( key ) ) { 388 if( usableProparty != null ) { 389 // 第4の判定。 usableProparty に存在すれば、即抜けする。 390 if( usableProparty.containsKey( key ) ) { return ; } 391 392 // 第5の判定。複数キー(先頭一致キー)の場合もありうるため、先頭からの比較を行う。 393 Iterator<Map.Entry<String,String>> ite = usableProparty.entrySet().iterator(); // 4.3.3.6 (2008/11/15) Generics警告対応 394 while( ite.hasNext() ) { 395 Map.Entry<String,String> entry = ite.next(); // 4.3.3.6 (2008/11/15) Generics警告対応 396 String propKey = entry.getKey(); // 4.3.3.6 (2008/11/15) Generics警告対応 397 if( key.startsWith( propKey ) ) { return ; } // マッチすれば、即抜ける。 398 } 399 400 // そこまで探して見つからない場合は、定義外引数エラー 401 StringBuilder errMsg = new StringBuilder(); 402 403 errMsg.append( "-KEY が、指定の整合性リストに含まれていません。" ); 404 errMsg.append( CR ) ; 405 errMsg.append( " -KEY=VALUE 形式 BAD Key=[" ).append( key ).append( "]" ); 406 errMsg.append( CR ) ; 407 errMsg.append( toString() ) ; 408 throw new RuntimeException( errMsg.toString() ); 409 } 410 } 411 412 /** 413 * 内部で使用する[プロパティ]を、キーを指定して取得します。 414 * 値が設定されていない場合は、 null を返します。 415 * [プロパティ]のキー部の大文字・小文字は、厳格に判定しています。 416 * 417 * ※ 引数の設定方法が間違っている場合、RuntimeException が throw されます。 418 * 419 * @param key 引数のキー 420 * 421 * @return 引数に対する値 422 */ 423 public String getProparty( final String key ) { 424 425 String value = proparty.get( key ); 426 427 // 値が null で must 設定があり、かつマストキーが指定している場合。 428 if( value == null && 429 mustProparty != null && 430 mustProparty.containsKey( key ) ) { 431 String errMsg = "指定の[プロパティ]は、必須キーですが、値が null です。" 432 + " Key:" + key + " 説明:" + mustProparty.get( key ) 433 + CR + toString() ; 434 throw new RuntimeException( errMsg ); 435 } 436 437 return value ; 438 } 439 440 /** 441 * 内部で使用する[プロパティ]を、キーを指定して取得します。 442 * [プロパティ]のキー部の大文字・小文字は、厳格に判定しています。 443 * def には、文字列の初期値を指定しておきます。key に対応する値が、null の場合、 444 * この def をそのまま返します。 445 * 446 * 処理は、getProparty( String ) の結果を、使用しています。 447 * 448 * @param key キー 449 * @param def 値が null の場合の初期値 450 * 451 * @return [プロパティ] 452 * @see #getProparty( String ) 453 */ 454 public String getProparty( final String key, final String def ) { 455 String value = getProparty( key ); 456 return ( value != null ) ? value : def ; 457 } 458 459 /** 460 * 内部で使用する[プロパティ]を、キーを指定して取得します。 461 * [プロパティ]のキー部の大文字・小文字は、厳格に判定しています。 462 * def には、文字列の初期値を指定しておきます。key に対応する値が、null の場合、 463 * この def をそのまま返します。 464 * list 配列には、登録できる文字列配列を指定します。この文字列に含まれない 465 * 値が設定されていた場合は、エラーになります。 466 * 467 * 処理は、getProparty( String ) の結果を、使用しています。 468 * 469 * ※ 引数の設定方法が間違っている場合、RuntimeException が throw されます。 470 * 471 * @param key キー 472 * @param def 値が null の場合の初期値 473 * @param list 値として存在できる文字列リスト 474 * 475 * @return [プロパティ] 476 * @see #getProparty( String ) 477 */ 478 public String getProparty( final String key, final String def, final String[] list ) { 479 String value = getProparty( key,def ); 480 if( value != null ) { 481 boolean isOK = false; 482 for( int i=0; i<list.length; i++ ) { 483 if( value.equalsIgnoreCase( list[i] ) ) { 484 isOK = true; break; 485 } 486 } 487 if( !isOK ) { 488 String errMsg = key + " は、" + Arrays.toString( list ) 489 + " から指定してください。" + CR 490 + "-" + key + "=[" + value + "]" ; 491 throw new RuntimeException( errMsg ); 492 } 493 } 494 495 return value ; 496 } 497 498 /** 499 * 内部で使用する[プロパティ]を、キーを指定して取得します。 500 * [プロパティ]のキー部の大文字・小文字は、厳格に判定しています。 501 * def には、数字の初期値を指定しておきます。key に対応する値が、null の場合、 502 * この def をそのまま返します。 503 * 504 * 処理は、getProparty( String ) の結果を、使用しています。 505 * 506 * @param key キー 507 * @param def 値が null の場合の初期値 508 * 509 * @return [プロパティ] 510 * @see #getProparty( String ) 511 */ 512 public int getProparty( final String key, final int def ) { 513 String value = getProparty( key ); 514 return ( value != null ) ? Integer.parseInt( value ) : def ; 515 } 516 517 /** 518 * 内部で使用する[プロパティ]を、キーを指定して取得します。 519 * [プロパティ]のキー部の大文字・小文字は、厳格に判定しています。 520 * def には、boolean の初期値を指定しておきます。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 boolean getProparty( final String key, final boolean def ) { 532 String value = getProparty( key ); 533 return ( value != null ) ? Boolean.valueOf( value ).booleanValue() : def ; 534 } 535 536 /** 537 * 内部で使用する[プロパティ]を、キーを指定して取得します。 538 * [プロパティ]のキー部の大文字・小文字は、厳格に判定しています。 539 * key プロパティは、通常の引数として指定できる簡易的な値を設定します。 540 * keyFile プロパティ は、ファイル名を指定し、そのファイルの中身を 541 * 取得して返します。通常は1行であるが、時には複数行のデータを指定 542 * したい場合に、2つのパラメータを使いますが、設定値は、同じ引数として 543 * 使用したいケースに便利です。 544 * key プロパティと、keyFile プロパティ は、同時指定できません。 545 * これは、指定方法の間違い等を避ける為です。 546 * どちらも、null である可能性はあります。 547 * 548 * ※ 同時指定時、または、must 必須時に null の場合、RuntimeException が throw されます。 549 * 550 * @param key キー 551 * @param keyFile 設定ファイル名 552 * @param must 必須条件[true/false] 553 * 554 * @return [プロパティ] 555 * @see #getProparty( String ) 556 */ 557 public String getFileProparty( final String key, final String keyFile, final boolean must ) { 558 return getFileProparty( key,keyFile,null,must ); 559 } 560 561 /** 562 * 内部で使用する[プロパティ]を、キーを指定して取得します。 563 * [プロパティ]のキー部の大文字・小文字は、厳格に判定しています。 564 * key プロパティは、通常の引数として指定できる簡易的な値を設定します。 565 * keyFile プロパティ は、ファイル名を指定し、そのファイルの中身を 566 * 取得して返します。通常は1行であるが、時には複数行のデータを指定 567 * したい場合に、2つのパラメータを使いますが、設定値は、同じ引数として 568 * 使用したいケースに便利です。 569 * key プロパティと、keyFile プロパティ は、同時指定できません。 570 * これは、指定方法の間違い等を避ける為です。 571 * どちらも、null である可能性はあります。 572 * 573 * ※ 同時指定時、または、must 必須時に null の場合、RuntimeException が throw されます。 574 * 575 * @param key キー 576 * @param keyFile 設定ファイル名 577 * @param encode keyFile読取エンコード(null はデフォルトエンコード) 578 * @param must 必須条件[true/false] 579 * 580 * @return [プロパティ] 581 * @see #getProparty( String ) 582 */ 583 public String getFileProparty( final String key, final String keyFile, 584 final String encode,final boolean must ) { 585 String val = getProparty( key ); 586 String valFile = getProparty( keyFile ); 587 588 if( val != null && valFile != null ) { 589 String errMsg = key + "か、" + keyFile + " は、両方同時に指定できません。[" + val + "],[" + valFile + "]"; 590 throw new RuntimeException( errMsg ); 591 } 592 593 if( valFile != null ) { 594 FileString fs = new FileString(); 595 fs.setFilename( valFile ); 596 fs.setEncode( encode ); 597 val = fs.getValue(); 598 } 599 600 if( must && val == null ) { 601 String errMsg = key + "か、" + keyFile + " は、片方必須です。"; 602 throw new RuntimeException( errMsg ); 603 } 604 605 return val; 606 } 607 608 /** 609 * 内部で使用する[プロパティ]を、キーを先頭に含む値を取得します。 610 * [プロパティ]のキー部の大文字・小文字は、厳格に判定しています。 611 * 値が設定されていない場合は、String[0] を返します。 612 * HybsEntry のキーに設定される値は、引数の先頭キーを除いた文字列です。 613 * 例えば、"const_" のような値を与えて、const_AA, const_BB, const_CC の 614 * 3つのキーが選定された場合、キーは、AA, BB, CC のみ返します。 615 * 616 * @param startsKey 引数の先頭のキー 617 * 618 * @return 引数に対する[プロパティ]のHybsEntry 619 */ 620 public HybsEntry[] getEntrys( final String startsKey ) { 621 622 ArrayList<HybsEntry> list = new ArrayList<HybsEntry>(); 623 int len = startsKey.length(); 624 625 Iterator<Map.Entry<String,String>> ite = proparty.entrySet().iterator(); // 4.3.3.6 (2008/11/15) Generics警告対応 626 while( ite.hasNext() ) { 627 Map.Entry<String,String> entry = ite.next(); // 4.3.3.6 (2008/11/15) Generics警告対応 628 String key = entry.getKey(); // 4.3.3.6 (2008/11/15) Generics警告対応 629 if( key.startsWith( startsKey ) ) { 630 list.add( new HybsEntry( key.substring( len ), entry.getValue() ) ); // 4.3.3.6 (2008/11/15) Generics警告対応 631 } 632 } 633 634 return list.toArray( new HybsEntry[list.size()] ) ; 635 } 636 637 /** 638 * 入力文字列に、{@XXXX}関係の文字列変換を行います。 639 * 引数に含まれる {@XXXX}=YYYY という入力に対して、inMsg に 640 * 含まれる{@XXXX} 文字列を、YYYY という文字列に変換します。 641 * それ以外に、予約文字変換として、 642 * {@ARG.XXX} 引数に使用された値を再利用(割り当て)します。 643 * {@DATE.XXX} SimpleDateFormat 形式の文字を変換します。(日付、時刻等) 644 * {@ENV.XXX} システムプロパティーの文字を変換します。(java -Dkey=value オプション) 645 * 646 * @param inMsg 入力文字列 647 * 648 * @return 変換後文字列 649 */ 650 public String changeParam( final String inMsg ) { 651 if( inMsg == null ) { return inMsg; } 652 653 String message = inMsg; 654 655 // {@ARG.XXXX} 変数の置換処理 656 int adrs = message.indexOf( "{@ARG." ) ; 657 while( adrs >= 0 ) { 658 int end = message.indexOf( '}',adrs ) ; 659 String key = message.substring( adrs+6,end ); 660 String oldData = "{@ARG." + key + "}" ; 661 // 注意:{@XXX}と異なり、{@ARG.XXX} では、XXX で proparty を検索する。 662 String newData = StringUtil.nval( getProparty( key ),"" ); 663 message = StringUtil.replace( message,oldData,newData ); 664 adrs = message.indexOf( "{@ARG.",adrs ) ; 665 } 666 // {@DATE.XXXX} 変数の置換処理 667 adrs = message.indexOf( "{@DATE." ) ; 668 if( adrs >= 0 ) { 669 Date dt = new Date(); 670 while( adrs >= 0 ) { 671 int end = message.indexOf( '}',adrs ) ; 672 String key = message.substring( adrs+7,end ); 673 String oldData = "{@DATE." + key + "}" ; 674 DateFormat formatter = new SimpleDateFormat( key, Locale.JAPANESE ); 675 String newData = StringUtil.nval( formatter.format(dt),"" ); 676 message = StringUtil.replace( message,oldData,newData ); 677 adrs = message.indexOf( "{@DATE.",adrs ) ; 678 } 679 } 680 // {@ENV.XXXX} 変数の置換処理 681 adrs = message.indexOf( "{@ENV." ) ; 682 while( adrs >= 0 ) { 683 int end = message.indexOf( '}',adrs ) ; 684 String key = message.substring( adrs+6,end ); 685 String oldData = "{@ENV." + key + "}" ; 686 String newData = System.getProperty( key,"" ); 687 message = StringUtil.replace( message,oldData,newData ); 688 adrs = message.indexOf( "{@ARG.",adrs ) ; 689 } 690 691 // 残りのメッセージ本文中の置換文字列を処理します。 692 adrs = message.indexOf( "{@" ) ; 693 while( adrs >= 0 ) { 694 int end = message.indexOf( '}',adrs ) ; 695 String key = message.substring( adrs,end+1 ); // +1 注意 696 String oldData = key ; 697 // 注意:{@ARG.XXX} と異なり、{@XXX} そのもので proparty を検索する。 698 String newData = StringUtil.nval( getProparty( key ),"" ); 699 message = StringUtil.replace( message,oldData,newData ); 700 adrs = message.indexOf( "{@",adrs ) ; 701 } 702 703 return message; 704 } 705 706 /** 707 * このオブジェクトの内部表現を、文字列にして返します。 708 * クラス名 + 起動時の引数リストを表示します。 709 * 710 * @return 引数に対する値 711 */ 712 @Override 713 public String toString() { 714 StringBuilder buf = new StringBuilder(); 715 716 buf.append( "java " ).append( programID ).append( CR ); 717 718 if( ! argments.isEmpty() ) { 719 for( int i=0; i<argments.size(); i++ ) { 720 buf.append( " " ).append( argments.get(i) ); 721 } 722 buf.append( CR ); 723 } 724 725 Iterator<Map.Entry<String,String>> propIte = proparty.entrySet().iterator(); // 4.3.3.6 (2008/11/15) Generics警告対応 726 while( propIte.hasNext() ) { 727 Map.Entry<String,String> entry = propIte.next(); // 4.3.3.6 (2008/11/15) Generics警告対応 728 String key = entry.getKey(); // 4.3.3.6 (2008/11/15) Generics警告対応 729 Object val = entry.getValue(); 730 if( key.startsWith( "passwd" ) ) { 731 val = "*****" ; 732 } 733 734 buf.append( " -" ).append( key ).append( "=" ).append( val ); 735 buf.append( CR ); 736 } 737 738 return buf.toString(); 739 } 740 741 /** 742 * このクラスの使用方法を返します。 743 * 744 * @return このクラスの使用方法 745 */ 746 public String usage() { 747 StringBuilder buf = new StringBuilder(); 748 749 buf.append( toString() ); 750 buf.append( CR ); 751 752 buf.append( propartyToString( "[ Must Proparty List ]",mustProparty ) ); 753 754 buf.append( propartyToString( "[ Usable Proparty List ]",usableProparty ) ); 755 756 return buf.toString(); 757 } 758 759 /** 760 * プロパティーを文字列に変換します。 761 * 762 * proparty の キーの最大長さを求め、位置あわせのためのスペースを追加します。 763 * 764 * @param title タイトル 765 * @param proparty プロパティー(Mapオブジェクト) 766 * 767 * @return プロパティー文字列 768 */ 769 private String propartyToString( final String title,final Map<String,String> proparty ) { 770 StringBuilder buf = new StringBuilder(); 771 772 if( proparty != null ) { 773 buf.append( title ).append( CR ); 774 775 // キーの長さをそろえるための処理 776 int maxLen = 0; 777 Iterator<String> keyIte = proparty.keySet().iterator(); // 4.3.3.6 (2008/11/15) Generics警告対応 778 while( keyIte.hasNext() ) { 779 int len = keyIte.next().length(); // 4.3.3.6 (2008/11/15) Generics警告対応 780 if( len > maxLen ) { maxLen = len; } 781 } 782 783 char[] ch = new char[maxLen]; 784 Arrays.fill( ch,' ' ); // スペースで埋めます。 785 String SPACE = new String( ch ); 786 String VAL_SPACE = CR + SPACE + " " ; 787 788 Iterator<Map.Entry<String,String>> propIte = proparty.entrySet().iterator(); // 4.3.3.6 (2008/11/15) Generics警告対応 789 while( propIte.hasNext() ) { 790 Map.Entry<String,String> entry = propIte.next(); // 4.3.3.6 (2008/11/15) Generics警告対応 791 String key = entry.getKey(); // 4.3.3.6 (2008/11/15) Generics警告対応 792 String val = entry.getValue(); // 4.3.3.6 (2008/11/15) Generics警告対応 793 if( val != null ) { val = val.replaceAll( CR,VAL_SPACE ); } 794 buf.append( " -" ).append( key ); 795 buf.append( SPACE.substring( key.length() ) ); // 使用されるキー 796 buf.append( " : " ).append( val ) ; // その説明 797 buf.append( CR ); 798 } 799 } 800 801 return buf.toString(); 802 } 803}