001package com.thetransactioncompany.util; 002 003 004import java.net.MalformedURLException; 005import java.net.URI; 006import java.net.URISyntaxException; 007import java.net.URL; 008import java.util.Properties; 009 010 011/** 012 * Provides typed retrieval of {@link java.util.Properties} as {@code boolean}, 013 * {@code int}, {@code long}, {@code float}, {@code double}, 014 * {@link java.lang.String}, {@link java.net.URL}, {@link java.net.URI} or 015 * {@code enum} values. 016 * 017 * @author Vladimir Dzhuvinov 018 */ 019public class PropertyRetriever { 020 021 022 /** 023 * The properties to parse. 024 */ 025 private final Properties props; 026 027 028 /** 029 * {@code true} if system property override has been enabled, 030 * {@code false} if it's disabled. 031 */ 032 private final boolean enableSysPropOverride; 033 034 035 /** 036 * Creates a new retriever for the specified properties. System 037 * property override is disabled. 038 * 039 * @param props The properties. Must not be {@code null}. 040 */ 041 public PropertyRetriever(final Properties props) { 042 043 this(props, false); 044 } 045 046 047 /** 048 * Creates a new retriever for the specified properties. 049 * 050 * @param props The properties. Must not be 051 * {@code null}. 052 * @param enableSysPropOverride If {@code true} if system properties 053 * with the same names are present they 054 * will override the specified properties, 055 * {@code false} to disable this 056 * behaviour. 057 */ 058 public PropertyRetriever(final Properties props, final boolean enableSysPropOverride) { 059 060 this.props = new Properties(); 061 this.props.putAll(props); 062 063 this.enableSysPropOverride = enableSysPropOverride; 064 if (enableSysPropOverride) { 065 // Overwrite 066 this.props.putAll(System.getProperties()); 067 } 068 } 069 070 071 /** 072 * Gets the system property override setting. 073 * 074 * @return {@code true} if system property override has been enabled, 075 * {@code false} if it's disabled. 076 */ 077 public boolean systemPropertyOverrideIsEnabled() { 078 079 return enableSysPropOverride; 080 } 081 082 083 /** 084 * Retrieves a boolean value. 085 * 086 * @param key The property name. 087 * 088 * @return The property as a boolean value. 089 * 090 * @throws PropertyParseException On a missing or invalid property. 091 */ 092 public boolean getBoolean(final String key) 093 throws PropertyParseException { 094 095 String value = props.getProperty(key); 096 097 if (value == null) 098 throw new PropertyParseException("Missing property", key); 099 100 if (value.equalsIgnoreCase("true")) 101 return true; 102 103 else if (value.equalsIgnoreCase("false")) 104 return false; 105 106 else 107 throw new PropertyParseException("Invalid boolean property", key, value); 108 } 109 110 111 /** 112 * Retrieves an optional boolean value. 113 * 114 * @param key The property name. 115 * @param def The default value if the property value is undefined or 116 * empty. 117 * 118 * @return The property as a boolean. 119 * 120 * @throws PropertyParseException On an invalid property. 121 */ 122 public boolean getOptBoolean(final String key, final boolean def) 123 throws PropertyParseException { 124 125 String value = props.getProperty(key); 126 127 if (value == null || value.trim().isEmpty()) 128 return def; 129 130 if (value.equalsIgnoreCase("true")) 131 return true; 132 133 if (value.equalsIgnoreCase("false")) 134 return false; 135 136 throw new PropertyParseException("Invalid boolean property", key, value); 137 } 138 139 140 /** 141 * Retrieves an integer value. 142 * 143 * @param key The property name. 144 * 145 * @return The property as an integer. 146 * 147 * @throws PropertyParseException On a missing or invalid property. 148 */ 149 public int getInt(final String key) 150 throws PropertyParseException { 151 152 String value = props.getProperty(key); 153 154 if (value == null) 155 throw new PropertyParseException("Missing property", key); 156 157 try { 158 return Integer.parseInt(value); 159 160 } catch (NumberFormatException e) { 161 162 throw new PropertyParseException("Invalid int property", key, value); 163 } 164 } 165 166 167 /** 168 * Retrieves an optional integer value. 169 * 170 * @param key The property name. 171 * @param def The default value if the property value is undefined or 172 * empty. 173 * 174 * @return The property as an integer. 175 * 176 * @throws PropertyParseException On an invalid property. 177 */ 178 public int getOptInt(final String key, final int def) 179 throws PropertyParseException { 180 181 String value = props.getProperty(key); 182 183 if (value == null || value.trim().isEmpty()) 184 return def; 185 186 try { 187 return Integer.parseInt(value); 188 189 } catch (NumberFormatException e) { 190 191 throw new PropertyParseException("Invalid int property", key); 192 } 193 } 194 195 196 /** 197 * Retrieves a long value. 198 * 199 * @param key The property name. 200 * 201 * @return The property as a long. 202 * 203 * @throws PropertyParseException On a missing or invalid property. 204 */ 205 public long getLong(final String key) 206 throws PropertyParseException { 207 208 String value = props.getProperty(key); 209 210 if (value == null) 211 throw new PropertyParseException("Missing property", key); 212 213 try { 214 return Long.parseLong(value); 215 216 } catch (NumberFormatException e) { 217 218 throw new PropertyParseException("Invalid long property", key, value); 219 } 220 } 221 222 223 /** 224 * Retrieves an optional long value. 225 * 226 * @param key The property name. 227 * @param def The default value if the property value is undefined or 228 * empty. 229 * 230 * @return The property as a long. 231 * 232 * @throws PropertyParseException On an invalid property. 233 */ 234 public long getOptLong(final String key, final long def) 235 throws PropertyParseException { 236 237 String value = props.getProperty(key); 238 239 if (value == null || value.trim().isEmpty()) 240 return def; 241 242 try { 243 return Long.parseLong(value); 244 245 } catch (NumberFormatException e) { 246 247 throw new PropertyParseException("Invalid long property", key, value); 248 } 249 } 250 251 252 /** 253 * Retrieves a float value. 254 * 255 * @param key The property name. 256 * 257 * @return The property as a float. 258 * 259 * @throws PropertyParseException On a missing or invalid property. 260 */ 261 public float getFloat(final String key) 262 throws PropertyParseException { 263 264 String value = props.getProperty(key); 265 266 if (value == null) 267 throw new PropertyParseException("Missing property", key); 268 269 try { 270 return Float.parseFloat(value); 271 272 } catch (NumberFormatException e) { 273 274 throw new PropertyParseException("Invalid float property", key, value); 275 } 276 } 277 278 279 /** 280 * Retrieves an optional float value. 281 * 282 * @param key The property name. 283 * @param def The default value if the property value is undefined or 284 * empty. 285 * 286 * @return The property as a float. 287 * 288 * @throws PropertyParseException On an invalid property. 289 */ 290 public float getOptFloat(final String key, final float def) 291 throws PropertyParseException { 292 293 String value = props.getProperty(key); 294 295 if (value == null || value.trim().isEmpty()) 296 return def; 297 298 try { 299 return Float.parseFloat(value); 300 301 } catch (NumberFormatException e) { 302 303 throw new PropertyParseException("Invalid float property", key, value); 304 } 305 } 306 307 308 /** 309 * Retrieves a double value. 310 * 311 * @param key The property name. 312 * 313 * @return The property as a double. 314 * 315 * @throws PropertyParseException On a missing or invalid property. 316 */ 317 public double getDouble(final String key) 318 throws PropertyParseException { 319 320 String value = props.getProperty(key); 321 322 if (value == null) 323 throw new PropertyParseException("Missing property", key); 324 325 try { 326 return Double.parseDouble(value); 327 328 } catch (NumberFormatException e) { 329 330 throw new PropertyParseException("Invalid double property", key, value); 331 } 332 } 333 334 335 /** 336 * Retrieves an optional double value. 337 * 338 * @param key The property name. 339 * @param def The default value if the property value is undefined or 340 * empty. 341 * 342 * @return The property as a double. 343 * 344 * @throws PropertyParseException On an invalid property. 345 */ 346 public double getOptDouble(final String key, final double def) 347 throws PropertyParseException { 348 349 String value = props.getProperty(key); 350 351 if (value == null || value.trim().isEmpty()) 352 return def; 353 354 try { 355 return Double.parseDouble(value); 356 357 } catch (NumberFormatException e) { 358 359 throw new PropertyParseException("Invalid double property", key, value); 360 } 361 } 362 363 364 /** 365 * Retrieves a string value. 366 * 367 * @param key The property name. 368 * 369 * @return The property as a string. 370 * 371 * @throws PropertyParseException On a missing or invalid property. 372 */ 373 public String getString(final String key) 374 throws PropertyParseException { 375 376 String value = props.getProperty(key); 377 378 if (value == null) 379 throw new PropertyParseException("Missing property", key); 380 381 return value; 382 } 383 384 385 /** 386 * Retrieves an optional string value. 387 * 388 * @param key The property name. 389 * @param def The default value if the property value is undefined or 390 * empty. 391 * 392 * @return The property as a string. 393 * 394 * @throws PropertyParseException On an invalid property. 395 */ 396 public String getOptString(final String key, final String def) 397 throws PropertyParseException { 398 399 String value = props.getProperty(key); 400 401 if (value == null || value.trim().isEmpty()) 402 return def; 403 404 return value; 405 } 406 407 408 /** 409 * Retrieves an enumerated string value. String case is ignored during 410 * comparison. 411 * 412 * @param key The property name. 413 * @param enums A string array defining the acceptable values. 414 * 415 * @return The property as a string. 416 * 417 * @throws PropertyParseException On a missing or invalid property. 418 */ 419 public String getEnumString(final String key, final String[] enums) 420 throws PropertyParseException { 421 422 String value = props.getProperty(key); 423 424 if (value == null) 425 throw new PropertyParseException("Missing property", key); 426 427 for (String en: enums) { 428 429 if (en.equalsIgnoreCase(value)) 430 return value; 431 } 432 433 throw new PropertyParseException("Invalid enum string property", key, value); 434 } 435 436 437 /** 438 * Retrieves an enumerated string value. String case is ignored during 439 * comparison. 440 * 441 * @param key The property name. 442 * @param enums A string array defining the acceptable values. 443 * @param def The default value if the property value is undefined or 444 * empty. 445 * 446 * @return The property as a string. 447 * 448 * @throws PropertyParseException On an invalid property. 449 */ 450 public String getOptEnumString(final String key, final String[] enums, final String def) 451 throws PropertyParseException { 452 453 String value = props.getProperty(key); 454 455 if (value == null || value.trim().isEmpty()) 456 return def; 457 458 for (String en: enums) { 459 460 if (en.equalsIgnoreCase(value)) 461 return value; 462 } 463 464 throw new PropertyParseException("Invalid enum string property", key, value); 465 } 466 467 468 /** 469 * Retrieves an enumerated constant. String case is ignored during 470 * comparison. 471 * 472 * @param key The property name. 473 * @param enumClass The enumeration class specifying the acceptable 474 * values. 475 * 476 * @return The matching enumerated constant. 477 * 478 * @throws PropertyParseException On a missing or invalid property. 479 */ 480 public <T extends Enum<T>> T getEnum(final String key, final Class<T> enumClass) 481 throws PropertyParseException { 482 483 String value = props.getProperty(key); 484 485 if (value == null) 486 throw new PropertyParseException("Missing property", key); 487 488 for (T en: enumClass.getEnumConstants()) { 489 490 if (en.toString().equalsIgnoreCase(value)) 491 return en; 492 } 493 494 // No match? -> raise exception 495 throw new PropertyParseException("Invalid enum property", key, value); 496 } 497 498 499 /** 500 * Retrieves an optional enumerated constant. String case is ignored 501 * during comparison. 502 * 503 * @param key The property name. 504 * @param enumClass The enumeration class specifying the acceptable 505 * values. 506 * @param def The default value if the property value is 507 * undefined or empty. 508 * 509 * @return The matching enumerated constant. 510 * 511 * @throws PropertyParseException On a missing or invalid property. 512 */ 513 public <T extends Enum<T>> T getOptEnum(final String key, final Class<T> enumClass, final T def) 514 throws PropertyParseException { 515 516 String value = props.getProperty(key); 517 518 if (value == null || value.trim().isEmpty()) 519 return def; 520 521 for (T en: enumClass.getEnumConstants()) { 522 523 if (en.toString().equalsIgnoreCase(value)) 524 return en; 525 } 526 527 // No match? -> raise exception 528 throw new PropertyParseException("Invalid enum property", key, value); 529 } 530 531 532 /** 533 * Retrieves a URI value. 534 * 535 * @param key The property name. 536 * 537 * @return The property as a URI. 538 * 539 * @throws PropertyParseException On a missing or invalid property. 540 */ 541 public URI getURI(final String key) 542 throws PropertyParseException { 543 544 String value = props.getProperty(key); 545 546 if (value == null) 547 throw new PropertyParseException("Missing property", key); 548 549 try { 550 return new URI(value); 551 552 } catch (URISyntaxException e) { 553 554 throw new PropertyParseException("Invalid URI property: " + e.getMessage(), key, value); 555 } 556 } 557 558 559 /** 560 * Retrieves an optional URI value. 561 * 562 * @param key The property name. 563 * @param def The default value if the property value is undefined or 564 * empty. 565 * 566 * @return The property as a URL. 567 * 568 * @throws PropertyParseException On an invalid property. 569 */ 570 public URI getOptURI(final String key, final URI def) 571 throws PropertyParseException { 572 573 String value = props.getProperty(key); 574 575 if (value == null || value.trim().isEmpty()) 576 return def; 577 578 try { 579 return new URI(value); 580 581 } catch (URISyntaxException e) { 582 583 throw new PropertyParseException("Invalid URI property: " + e.getMessage(), key, value); 584 } 585 } 586 587 588 /** 589 * Retrieves a URL value. 590 * 591 * @param key The property name. 592 * 593 * @return The property as a URL. 594 * 595 * @throws PropertyParseException On a missing or invalid property. 596 */ 597 public URL getURL(final String key) 598 throws PropertyParseException { 599 600 String value = props.getProperty(key); 601 602 if (value == null) 603 throw new PropertyParseException("Missing property", key); 604 605 try { 606 return new URL(value); 607 608 } catch (MalformedURLException e) { 609 610 throw new PropertyParseException("Invalid URL property: " + e.getMessage(), key, value); 611 } 612 } 613 614 615 /** 616 * Retrieves an optional URL value. 617 * 618 * @param key The property name. 619 * @param def The default value if the property value is undefined or 620 * empty. 621 * 622 * @return The property as a URL. 623 * 624 * @throws PropertyParseException On an invalid property. 625 */ 626 public URL getOptURL(final String key, final URL def) 627 throws PropertyParseException { 628 629 String value = props.getProperty(key); 630 631 if (value == null || value.trim().isEmpty()) 632 return def; 633 634 try { 635 return new URL(value); 636 637 } catch (MalformedURLException e) { 638 639 throw new PropertyParseException("Invalid URL property: " + e.getMessage(), key, value); 640 } 641 } 642}