001/* 002 * Copyright 2024 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright 2024 Ping Identity Corporation 007 * 008 * Licensed under the Apache License, Version 2.0 (the "License"); 009 * you may not use this file except in compliance with the License. 010 * You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, software 015 * distributed under the License is distributed on an "AS IS" BASIS, 016 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 017 * See the License for the specific language governing permissions and 018 * limitations under the License. 019 */ 020/* 021 * Copyright (C) 2024 Ping Identity Corporation 022 * 023 * This program is free software; you can redistribute it and/or modify 024 * it under the terms of the GNU General Public License (GPLv2 only) 025 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only) 026 * as published by the Free Software Foundation. 027 * 028 * This program is distributed in the hope that it will be useful, 029 * but WITHOUT ANY WARRANTY; without even the implied warranty of 030 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 031 * GNU General Public License for more details. 032 * 033 * You should have received a copy of the GNU General Public License 034 * along with this program; if not, see <http://www.gnu.org/licenses>. 035 */ 036package com.unboundid.util; 037 038 039 040import java.util.ArrayList; 041import java.util.Collections; 042import java.util.List; 043import java.util.Properties; 044 045import static com.unboundid.util.UtilityMessages.*; 046 047 048 049/** 050 * This class provides a mechanism for retrieving the values of specified 051 * properties in the form of either Java system properties or process 052 * environment variables (using an alternative name generated from the provided 053 * property name using the 054 * {@link #generateEnvironmentVariableNameFromPropertyName} method). System 055 * properties will be given a higher priority than environment variables, and 056 * the value can be parsed in accordance with a number of syntaxes. 057 */ 058@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 059public final class PropertyManager 060{ 061 /** 062 * Prevents this utility class from being instantiated. 063 */ 064 private PropertyManager() 065 { 066 // No implementation is required. 067 } 068 069 070 071 /** 072 * Retrieves the value of the specified system property or environment 073 * variable. 074 * 075 * @param propertyName The name of the system property to retrieve, and to 076 * use to generate an alternative environment variable. 077 * It must not be {@code null} or empty. 078 * 079 * @return The requested value, or {@code null} if it has not been set as 080 * either a system property or an environment variable. 081 */ 082 @Nullable() 083 public static String get(@NotNull final String propertyName) 084 { 085 return get(propertyName, null); 086 } 087 088 089 090 /** 091 * Retrieves the value of the specified system property or environment 092 * variable. 093 * 094 * @param propertyName The name of the system property to retrieve, and to 095 * use to generate an alternative environment variable. 096 * It must not be {@code null} or empty. 097 * @param defaultValue The default value to return if neither the system 098 * property nor associated environment variable have 099 * been set. It may be {@code null} if no default value 100 * should be returned. 101 * 102 * @return The requested value, or {@code null} if it has not been set as 103 * either a system property or an environment variable. 104 */ 105 @Nullable() 106 public static String get(@NotNull final String propertyName, 107 @Nullable final String defaultValue) 108 { 109 final String systemPropertyValue = 110 StaticUtils.getSystemProperty(propertyName); 111 if (systemPropertyValue != null) 112 { 113 return systemPropertyValue; 114 } 115 116 final String environmentVariableValue = 117 StaticUtils.getEnvironmentVariable(propertyName); 118 if (environmentVariableValue != null) 119 { 120 return environmentVariableValue; 121 } 122 123 final String alternativeEnvironmentVariableName = 124 generateEnvironmentVariableNameFromPropertyName(propertyName); 125 if (! alternativeEnvironmentVariableName.equals(propertyName)) 126 { 127 final String alternativeEnvironmentVariableValue = 128 StaticUtils.getEnvironmentVariable( 129 alternativeEnvironmentVariableName); 130 if (alternativeEnvironmentVariableValue != null) 131 { 132 return alternativeEnvironmentVariableValue; 133 } 134 } 135 136 return defaultValue; 137 } 138 139 140 141 /** 142 * Retrieves the value of the specified property or environment variable as a 143 * Boolean value. 144 * 145 * @param propertyName The name of the system property to retrieve, and to 146 * use to generate an alternative environment variable. 147 * It must not be {@code null} or empty. 148 * 149 * @return The Boolean value of the specified property or environment 150 * variable, or {@code null} if neither are set or are set to a 151 * value that cannot be parsed as a Boolean. 152 */ 153 @Nullable() 154 public static Boolean getBoolean(@NotNull final String propertyName) 155 { 156 return getBoolean(propertyName, null); 157 } 158 159 160 161 /** 162 * Retrieves the value of the specified property or environment variable as a 163 * Boolean value. 164 * 165 * @param propertyName The name of the system property to retrieve, and to 166 * use to generate an alternative environment variable. 167 * It must not be {@code null} or empty. 168 * @param defaultValue The default value to return if neither the system 169 * property nor associated environment variable have 170 * been set, or if the value cannot be parsed as a 171 * Boolean. It may be {@code null} if no default value 172 * should be returned. 173 * 174 * @return The Boolean value of the specified property or environment 175 * variable, or the provided default value if neither are set or are 176 * set to a value that cannot be parsed as a Boolean. 177 */ 178 @Nullable() 179 public static Boolean getBoolean(@NotNull final String propertyName, 180 @Nullable final Boolean defaultValue) 181 { 182 return getBoolean(propertyName, defaultValue, false); 183 } 184 185 186 187 /** 188 * Retrieves the value of the specified property or environment variable as a 189 * Boolean value. 190 * 191 * @param propertyName The name of the system property to retrieve, 192 * and to use to generate an alternative 193 * environment variable. It must not be 194 * {@code null} or empty. 195 * @param defaultValue The default value to return if neither the 196 * system property nor associated environment 197 * variable have been set, or if the value cannot 198 * be parsed as a Boolean and 199 * {@code throwOnInvalidValue} is {@code false}. 200 * It may be {@code null} if no default value 201 * should be returned. 202 * @param throwOnInvalidValue Indicates whether this method should throw an 203 * {@code IllegalArgumentException} if the 204 * system property or environment variable is 205 * set but its value cannot be parsed as a 206 * Boolean. 207 * 208 * @return The Boolean value of the specified property or environment 209 * variable, or the provided default value if neither are set or are 210 * set to a value that cannot be parsed as a Boolean and 211 * {@code throwOnInvalidValue} is {@code false}. 212 * 213 * @throws IllegalArgumentException If the property or environment variable 214 * is set, but its value cannot be parsed 215 * as a Boolean, and 216 * {@code throwOnInvalidValue} is 217 * {@code true}. 218 */ 219 @Nullable() 220 public static Boolean getBoolean(@NotNull final String propertyName, 221 @Nullable final Boolean defaultValue, 222 final boolean throwOnInvalidValue) 223 throws IllegalArgumentException 224 { 225 final String stringValue = get(propertyName); 226 if (stringValue == null) 227 { 228 return defaultValue; 229 } 230 231 final String lowerValue = StaticUtils.toLowerCase(stringValue.trim()); 232 switch (lowerValue) 233 { 234 case "true": 235 case "t": 236 case "yes": 237 case "y": 238 case "on": 239 case "1": 240 return Boolean.TRUE; 241 case "false": 242 case "f": 243 case "no": 244 case "n": 245 case "off": 246 case "0": 247 return Boolean.FALSE; 248 default: 249 if (throwOnInvalidValue) 250 { 251 throw new IllegalArgumentException( 252 ERR_PROPERTY_MANAGER_NOT_BOOLEAN.get( 253 getIdentifierString(propertyName), stringValue)); 254 } 255 else 256 { 257 return defaultValue; 258 } 259 } 260 } 261 262 263 264 /** 265 * Retrieves the value of the specified property or environment variable as an 266 * integer. 267 * 268 * @param propertyName The name of the system property to retrieve, and to 269 * use to generate an alternative environment variable. 270 * It must not be {@code null} or empty. 271 * 272 * @return The integer value of the specified property or environment 273 * variable, or {@code null} if neither are set or are set to a 274 * value that cannot be parsed as an integer. 275 */ 276 @Nullable() 277 public static Integer getInt(@NotNull final String propertyName) 278 { 279 return getInt(propertyName, null); 280 } 281 282 283 284 /** 285 * Retrieves the value of the specified property or environment variable as an 286 * integer. 287 * 288 * @param propertyName The name of the system property to retrieve, and to 289 * use to generate an alternative environment variable. 290 * It must not be {@code null} or empty. 291 * @param defaultValue The default value to return if neither the system 292 * property nor associated environment variable have 293 * been set, or if the value cannot be parsed as an 294 * integer. It may be {@code null} if no default value 295 * should be returned. 296 * 297 * @return The integer value of the specified property or environment 298 * variable, or the provided default value if neither are set or are 299 * set to a value that cannot be parsed as an integer. 300 */ 301 @Nullable() 302 public static Integer getInt(@NotNull final String propertyName, 303 @Nullable final Integer defaultValue) 304 { 305 return getInt(propertyName, defaultValue, false); 306 } 307 308 309 310 /** 311 * Retrieves the value of the specified property or environment variable as an 312 * integer. 313 * 314 * @param propertyName The name of the system property to retrieve, 315 * and to use to generate an alternative 316 * environment variable. It must not be 317 * {@code null} or empty. 318 * @param defaultValue The default value to return if neither the 319 * system property nor associated environment 320 * variable have been set, or if the value cannot 321 * be parsed as an integer and 322 * {@code throwOnInvalidValue} is {@code false}. 323 * It may be {@code null} if no default value 324 * should be returned. 325 * @param throwOnInvalidValue Indicates whether this method should throw an 326 * {@code IllegalArgumentException} if the 327 * system property or environment variable is 328 * set but its value cannot be parsed as an 329 * integer. 330 * 331 * @return The integer value of the specified property or environment 332 * variable, or the provided default value if neither are set or are 333 * set to a value that cannot be parsed as an integer and 334 * {@code throwOnInvalidValue} is {@code false}. 335 * 336 * @throws IllegalArgumentException If the property or environment variable 337 * is set, but its value cannot be parsed 338 * as an integer, and 339 * {@code throwOnInvalidValue} is 340 * {@code true}. 341 */ 342 @Nullable() 343 public static Integer getInt(@NotNull final String propertyName, 344 @Nullable final Integer defaultValue, 345 final boolean throwOnInvalidValue) 346 throws IllegalArgumentException 347 { 348 final String stringValue = get(propertyName); 349 if (stringValue == null) 350 { 351 return defaultValue; 352 } 353 354 try 355 { 356 return Integer.parseInt(stringValue.trim()); 357 } 358 catch (final Exception e) 359 { 360 Debug.debugException(e); 361 if (throwOnInvalidValue) 362 { 363 throw new IllegalArgumentException( 364 ERR_PROPERTY_MANAGER_NOT_INT.get(getIdentifierString(propertyName), 365 stringValue), 366 e); 367 } 368 else 369 { 370 return defaultValue; 371 } 372 } 373 } 374 375 376 377 /** 378 * Retrieves the value of the specified property or environment variable as a 379 * long. 380 * 381 * @param propertyName The name of the system property to retrieve, and to 382 * use to generate an alternative environment variable. 383 * It must not be {@code null} or empty. 384 * 385 * @return The long value of the specified property or environment variable, 386 * or {@code null} if neither are set or are set to a value that 387 * cannot be parsed as a long. 388 */ 389 @Nullable() 390 public static Long getLong(@NotNull final String propertyName) 391 { 392 return getLong(propertyName, null); 393 } 394 395 396 397 /** 398 * Retrieves the value of the specified property or environment variable as a 399 * long. 400 * 401 * @param propertyName The name of the system property to retrieve, and to 402 * use to generate an alternative environment variable. 403 * It must not be {@code null} or empty. 404 * @param defaultValue The default value to return if neither the system 405 * property nor associated environment variable have 406 * been set, or if the value cannot be parsed as a long. 407 * It may be {@code null} if no default value should be 408 * returned. 409 * 410 * @return The long value of the specified property or environment variable, 411 * or the provided default value if neither are set or are set to a 412 * value that cannot be parsed as a long. 413 */ 414 @Nullable() 415 public static Long getLong(@NotNull final String propertyName, 416 @Nullable final Long defaultValue) 417 { 418 return getLong(propertyName, defaultValue, false); 419 } 420 421 422 423 /** 424 * Retrieves the value of the specified property or environment variable as a 425 * long. 426 * 427 * @param propertyName The name of the system property to retrieve, 428 * and to use to generate an alternative 429 * environment variable. It must not be 430 * {@code null} or empty. 431 * @param defaultValue The default value to return if neither the 432 * system property nor associated environment 433 * variable have been set, or if the value cannot 434 * be parsed as a long and 435 * {@code throwOnInvalidValue} is {@code false}. 436 * It may be {@code null} if no default value 437 * should be returned. 438 * @param throwOnInvalidValue Indicates whether this method should throw an 439 * {@code IllegalArgumentException} if the 440 * system property or environment variable is 441 * set but its value cannot be parsed as a 442 * long. 443 * 444 * @return The long value of the specified property or environment variable, 445 * or the provided default value if neither are set or are set to a 446 * value that cannot be parsed as a long and 447 * {@code throwOnInvalidValue} is {@code false}. 448 * 449 * @throws IllegalArgumentException If the property or environment variable 450 * is set, but its value cannot be parsed 451 * as a long, and 452 * {@code throwOnInvalidValue} is 453 * {@code true}. 454 */ 455 @Nullable() 456 public static Long getLong(@NotNull final String propertyName, 457 @Nullable final Long defaultValue, 458 final boolean throwOnInvalidValue) 459 throws IllegalArgumentException 460 { 461 final String stringValue = get(propertyName); 462 if (stringValue == null) 463 { 464 return defaultValue; 465 } 466 467 try 468 { 469 return Long.parseLong(stringValue.trim()); 470 } 471 catch (final Exception e) 472 { 473 Debug.debugException(e); 474 if (throwOnInvalidValue) 475 { 476 throw new IllegalArgumentException( 477 ERR_PROPERTY_MANAGER_NOT_LONG.get( 478 getIdentifierString(propertyName), stringValue), 479 e); 480 } 481 else 482 { 483 return defaultValue; 484 } 485 } 486 } 487 488 489 490 /** 491 * Retrieves the value of the specified property or environment variable as 492 * a list of comma-delimited values. Any spaces around commas will be 493 * trimmed. 494 * 495 * @param propertyName The name of the system property to retrieve, and to 496 * use to generate an alternative environment variable. 497 * It must not be {@code null} or empty. 498 * 499 * @return An unmodifiable list containing the comma-delimited values of the 500 * specified property or environment variable, or an empty list if 501 * neither is set. 502 */ 503 @NotNull() 504 public static List<String> getCommaDelimitedList( 505 @NotNull final String propertyName) 506 { 507 return getCommaDelimitedList(propertyName, true); 508 } 509 510 511 512 /** 513 * Retrieves the value of the specified property or environment variable as 514 * a list of comma-delimited values. Any spaces around commas will be 515 * trimmed. 516 * 517 * @param propertyName The name of the system property to retrieve, and to 518 * use to generate an alternative environment variable. 519 * It must not be {@code null} or empty. 520 * @param trimItems Indicates whether the individual items in the list 521 * should be trimmed to remove leading and/or trailing 522 * spaces. 523 * 524 * @return An unmodifiable list containing the comma-delimited values of the 525 * specified property or environment variable, or an empty list if 526 * neither is set. 527 */ 528 @NotNull() 529 public static List<String> getCommaDelimitedList( 530 @NotNull final String propertyName, 531 final boolean trimItems) 532 { 533 final List<String> items = new ArrayList<>(); 534 535 final String stringValue = get(propertyName); 536 if (stringValue != null) 537 { 538 int startPos = 0; 539 while (true) 540 { 541 final int commaPos = stringValue.indexOf(',', startPos); 542 if (commaPos < 0) 543 { 544 String substring = stringValue.substring(startPos); 545 if (trimItems) 546 { 547 substring = substring.trim(); 548 } 549 550 items.add(substring); 551 break; 552 } 553 else 554 { 555 String substring = stringValue.substring(startPos, commaPos); 556 if (trimItems) 557 { 558 substring = substring.trim(); 559 } 560 561 items.add(substring); 562 startPos = commaPos + 1; 563 } 564 } 565 } 566 567 return Collections.unmodifiableList(items); 568 } 569 570 571 572 /** 573 * Retrieves a {@code Properties} object with values for any of the specified 574 * properties that are currently set. 575 * 576 * @param propertyNames The name of the properties whose values should be 577 * retrieved. It must not be {@code null}, but may be 578 * empty. 579 * 580 * @return A {@code Properties} object with any of the specified properties 581 * that are set as either JVM system properties or environment 582 * variables. It may be empty if none of the specified properties 583 * have been set. 584 */ 585 @NotNull() 586 public static Properties getProperties(@NotNull final String... propertyNames) 587 { 588 final Properties properties = new Properties(); 589 590 for (final String propertyName : propertyNames) 591 { 592 final String propertyValue = get(propertyName); 593 if (propertyValue != null) 594 { 595 properties.setProperty(propertyName, propertyValue); 596 } 597 } 598 599 return properties; 600 } 601 602 603 604 /** 605 * Generates an alternative environment variable name that can be used for a 606 * given property name. All alphabetic letters in the provided name will be 607 * converted to uppercase, and all characters other than ASCII letters and 608 * digits will be converted to underscores. 609 * 610 * @param propertyName The property name to use to generate the environment 611 * variable name. It must not be {@code null} or empty. 612 * 613 * @return The alternative environment variable name generated from the given 614 * property name. 615 */ 616 @NotNull() 617 public static String generateEnvironmentVariableNameFromPropertyName( 618 @NotNull final String propertyName) 619 { 620 final String upperPropertyName = 621 StaticUtils.toUpperCase(propertyName.trim()); 622 623 final int length = upperPropertyName.length(); 624 final StringBuilder buffer = new StringBuilder(length); 625 for (int i=0; i < length; i++) 626 { 627 final char c = upperPropertyName.charAt(i); 628 if (((c >= 'A') && (c <= 'Z')) || 629 ((c >= '0') && (c <= '9'))) 630 { 631 buffer.append(c); 632 } 633 else 634 { 635 buffer.append('_'); 636 } 637 } 638 639 return buffer.toString(); 640 } 641 642 643 644 /** 645 * Retrieves an identifier string that can be used to indicate how the value 646 * of the specified property was obtained. The returned value will be one of: 647 * <UL> 648 * <LI>system property '{propertyName}'</LI> 649 * <LI>environment variable '{propertyName}'</LI> 650 * <LI>environment variable '{alternativeName}'</LI> 651 * </UL> 652 * 653 * @param propertyName The property name for which to retrieve the 654 * identifier. 655 * 656 * @return The identifier string for the provided property name, or 657 * {@code null} if the specified property is not set as either a 658 * system property or an environment variable (including with an 659 * alternative name). 660 */ 661 @Nullable() 662 static String getIdentifierString(@NotNull final String propertyName) 663 { 664 if (StaticUtils.getSystemProperty(propertyName) != null) 665 { 666 return INFO_PROPERTY_MANAGER_SYSTEM_PROPERY_IDENTIFIER.get(propertyName); 667 } 668 669 if (StaticUtils.getEnvironmentVariable(propertyName) != null) 670 { 671 return INFO_PROPERTY_MANAGER_ENVIRONMENT_VARIABLE_IDENTIFIER.get( 672 propertyName); 673 } 674 675 final String alternativeName = 676 generateEnvironmentVariableNameFromPropertyName(propertyName); 677 if (StaticUtils.getEnvironmentVariable(alternativeName) != null) 678 { 679 return INFO_PROPERTY_MANAGER_ENVIRONMENT_VARIABLE_IDENTIFIER.get( 680 alternativeName); 681 } 682 683 return null; 684 } 685}