001/*
002 * Copyright 2024-2025 Ping Identity Corporation
003 * All Rights Reserved.
004 */
005/*
006 * Copyright 2024-2025 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-2025 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.Map;
044import java.util.Properties;
045import java.util.concurrent.ConcurrentHashMap;
046import java.util.concurrent.atomic.AtomicInteger;
047
048import static com.unboundid.util.UtilityMessages.*;
049
050
051
052/**
053 * This class provides a mechanism for retrieving the values of specified
054 * properties in the form of either Java system properties or process
055 * environment variables (using an alternative name generated from the provided
056 * property name using the
057 * {@link #generateEnvironmentVariableNameFromPropertyName} method).  System
058 * properties will be given a higher priority than environment variables, and
059 * the value can be parsed in accordance with a number of syntaxes.
060 */
061@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
062public final class PropertyManager
063{
064  /**
065   * A reference to the length of time in milliseconds that property information
066   * should be cached after retrieving it.
067   */
068  @NotNull private static final AtomicInteger CACHE_DURATION_MILLIS =
069       new AtomicInteger(0);
070
071
072
073  /**
074   * A map containing cached property information.
075   */
076  @NotNull private static final Map<String,PropertyManagerCacheRecord> CACHE =
077     new ConcurrentHashMap<>();
078
079
080
081  /**
082   * Prevents this utility class from being instantiated.
083   */
084  private PropertyManager()
085  {
086    // No implementation is required.
087  }
088
089
090
091  /**
092   * Retrieves the value of the specified system property or environment
093   * variable.
094   *
095   * @param  propertyName  The name of the system property to retrieve, and to
096   *                       use to generate an alternative environment variable.
097   *                       It must not be {@code null} or empty.
098   *
099   * @return  The requested value, or {@code null} if it has not been set as
100   *          either a system property or an environment variable.
101   */
102  @Nullable()
103  public static String get(@NotNull final String propertyName)
104  {
105    return get(propertyName, null);
106  }
107
108
109
110  /**
111   * Retrieves the value of the specified system property or environment
112   * variable.
113   *
114   * @param  propertyName  The name of the system property to retrieve, and to
115   *                       use to generate an alternative environment variable.
116   *                       It must not be {@code null} or empty.
117   * @param  defaultValue  The default value to return if neither the system
118   *                       property nor associated environment variable have
119   *                       been set.  It may be {@code null} if no default value
120   *                       should be returned.
121   *
122   * @return  The requested value, or {@code null} if it has not been set as
123   *          either a system property or an environment variable.
124   */
125  @Nullable()
126  public static String get(@NotNull final String propertyName,
127                           @Nullable final String defaultValue)
128  {
129    // See if there is a valid cache record for the property.  If so, then use
130    // it.
131    final int cacheDurationMillis = CACHE_DURATION_MILLIS.get();
132    if (cacheDurationMillis > 0)
133    {
134      final PropertyManagerCacheRecord cacheRecord = CACHE.get(propertyName);
135      if ((cacheRecord != null) && (! cacheRecord.isExpired()))
136      {
137        return cacheRecord.stringValue(defaultValue);
138      }
139    }
140
141
142    // See if the property is defined via a system property.
143    final String systemPropertyValue =
144         StaticUtils.getSystemProperty(propertyName);
145    if (systemPropertyValue != null)
146    {
147      if (cacheDurationMillis > 0)
148      {
149        CACHE.put(propertyName, new PropertyManagerCacheRecord(propertyName,
150             systemPropertyValue, cacheDurationMillis));
151      }
152
153      return systemPropertyValue;
154    }
155
156
157    // See if the property is defined via an environment variable.
158    final String environmentVariableValue =
159         StaticUtils.getEnvironmentVariable(propertyName);
160    if (environmentVariableValue != null)
161    {
162      if (cacheDurationMillis > 0)
163      {
164        CACHE.put(propertyName, new PropertyManagerCacheRecord(propertyName,
165             environmentVariableValue, cacheDurationMillis));
166      }
167
168      return environmentVariableValue;
169    }
170
171    final String alternativeEnvironmentVariableName =
172         generateEnvironmentVariableNameFromPropertyName(propertyName);
173    if (! alternativeEnvironmentVariableName.equals(propertyName))
174    {
175      final String alternativeEnvironmentVariableValue =
176           StaticUtils.getEnvironmentVariable(
177                alternativeEnvironmentVariableName);
178      if (alternativeEnvironmentVariableValue != null)
179      {
180        if (cacheDurationMillis > 0)
181        {
182          CACHE.put(propertyName, new PropertyManagerCacheRecord(propertyName,
183               alternativeEnvironmentVariableValue, cacheDurationMillis));
184        }
185
186        return alternativeEnvironmentVariableValue;
187      }
188    }
189
190
191    // If we've gotten here, then the property is not defined.  Cache that it's
192    // not defined, if appropriate.
193    if (cacheDurationMillis > 0)
194    {
195      CACHE.put(propertyName, new PropertyManagerCacheRecord(propertyName,
196           null, cacheDurationMillis));
197    }
198
199    return defaultValue;
200  }
201
202
203
204  /**
205   * Retrieves the value of the specified property or environment variable as a
206   * Boolean value.
207   *
208   * @param  propertyName  The name of the system property to retrieve, and to
209   *                       use to generate an alternative environment variable.
210   *                       It must not be {@code null} or empty.
211   *
212   * @return  The Boolean value of the specified property or environment
213   *          variable, or {@code null} if neither are set or are set to a
214   *          value that cannot be parsed as a Boolean.
215   */
216  @Nullable()
217  public static Boolean getBoolean(@NotNull final String propertyName)
218  {
219    return getBoolean(propertyName, null);
220  }
221
222
223
224  /**
225   * Retrieves the value of the specified property or environment variable as a
226   * Boolean value.
227   *
228   * @param  propertyName  The name of the system property to retrieve, and to
229   *                       use to generate an alternative environment variable.
230   *                       It must not be {@code null} or empty.
231   * @param  defaultValue  The default value to return if neither the system
232   *                       property nor associated environment variable have
233   *                       been set, or if the value cannot be parsed as a
234   *                       Boolean.  It may be {@code null} if no default value
235   *                       should be returned.
236   *
237   * @return  The Boolean value of the specified property or environment
238   *          variable, or the provided default value if neither are set or are
239   *          set to a value that cannot be parsed as a Boolean.
240   */
241  @Nullable()
242  public static Boolean getBoolean(@NotNull final String propertyName,
243                                   @Nullable final Boolean defaultValue)
244  {
245    return getBoolean(propertyName, defaultValue, false);
246  }
247
248
249
250  /**
251   * Retrieves the value of the specified property or environment variable as a
252   * Boolean value.
253   *
254   * @param  propertyName         The name of the system property to retrieve,
255   *                              and to use to generate an alternative
256   *                              environment variable.  It must not be
257   *                              {@code null} or empty.
258   * @param  defaultValue         The default value to return if neither the
259   *                              system property nor associated environment
260   *                              variable have been set, or if the value cannot
261   *                              be parsed as a Boolean and
262   *                              {@code throwOnInvalidValue} is {@code false}.
263   *                              It may be {@code null} if no default value
264   *                              should be returned.
265   * @param  throwOnInvalidValue  Indicates whether this method should throw an
266   *                              {@code IllegalArgumentException} if the
267   *                              system property or environment variable is
268   *                              set but its value cannot be parsed as a
269   *                              Boolean.
270   *
271   * @return  The Boolean value of the specified property or environment
272   *          variable, or the provided default value if neither are set or are
273   *          set to a value that cannot be parsed as a Boolean and
274   *          {@code throwOnInvalidValue} is {@code false}.
275   *
276   * @throws  IllegalArgumentException  If the property or environment variable
277   *                                    is set, but its value cannot be parsed
278   *                                    as a Boolean, and
279   *                                    {@code throwOnInvalidValue} is
280   *                                    {@code true}.
281   */
282  @Nullable()
283  public static Boolean getBoolean(@NotNull final String propertyName,
284                                   @Nullable final Boolean defaultValue,
285                                   final boolean throwOnInvalidValue)
286         throws IllegalArgumentException
287  {
288    // See if there is a valid cache record for the property.  If so, then use
289    // it.
290    final int cacheDurationMillis = CACHE_DURATION_MILLIS.get();
291    if (cacheDurationMillis > 0)
292    {
293      final PropertyManagerCacheRecord cacheRecord = CACHE.get(propertyName);
294      if ((cacheRecord != null) && (! cacheRecord.isExpired()))
295      {
296        return cacheRecord.booleanValue(defaultValue, throwOnInvalidValue);
297      }
298    }
299
300
301    final String stringValue = get(propertyName);
302    if (stringValue == null)
303    {
304      return defaultValue;
305    }
306
307    final Boolean booleanValue = parseBoolean(stringValue);
308    if (booleanValue == null)
309    {
310      if (throwOnInvalidValue)
311      {
312        throw new IllegalArgumentException(
313             ERR_PROPERTY_MANAGER_NOT_BOOLEAN.get(
314                  getIdentifierString(propertyName), stringValue));
315      }
316      else
317      {
318        return defaultValue;
319      }
320    }
321    else
322    {
323      return booleanValue;
324    }
325  }
326
327
328
329  /**
330   * Attempts to parse the provided string value as a {@code Boolean}.
331   *
332   * @param  stringValue  The string value to parse.  It must not be
333   *                      {@code null}.
334   *
335   * @return  The {@code Boolean} value that was parsed from the given string,
336   *          or {@code null} if the provided string could not be parsed as a
337   *          {@code Boolean}.
338   */
339  @Nullable()
340  static Boolean parseBoolean(@NotNull final String stringValue)
341  {
342    final String lowerValue = StaticUtils.toLowerCase(stringValue.trim());
343    switch (lowerValue)
344    {
345      case "true":
346      case "t":
347      case "yes":
348      case "y":
349      case "on":
350      case "1":
351        return Boolean.TRUE;
352      case "false":
353      case "f":
354      case "no":
355      case "n":
356      case "off":
357      case "0":
358        return Boolean.FALSE;
359      default:
360        return null;
361    }
362  }
363
364
365
366  /**
367   * Retrieves the value of the specified property or environment variable as an
368   * integer.
369   *
370   * @param  propertyName  The name of the system property to retrieve, and to
371   *                       use to generate an alternative environment variable.
372   *                       It must not be {@code null} or empty.
373   *
374   * @return  The integer value of the specified property or environment
375   *          variable, or {@code null} if neither are set or are set to a
376   *          value that cannot be parsed as an integer.
377   */
378  @Nullable()
379  public static Integer getInt(@NotNull final String propertyName)
380  {
381    return getInt(propertyName, null);
382  }
383
384
385
386  /**
387   * Retrieves the value of the specified property or environment variable as an
388   * integer.
389   *
390   * @param  propertyName  The name of the system property to retrieve, and to
391   *                       use to generate an alternative environment variable.
392   *                       It must not be {@code null} or empty.
393   * @param  defaultValue  The default value to return if neither the system
394   *                       property nor associated environment variable have
395   *                       been set, or if the value cannot be parsed as an
396   *                       integer.  It may be {@code null} if no default value
397   *                       should be returned.
398   *
399   * @return  The integer value of the specified property or environment
400   *          variable, or the provided default value if neither are set or are
401   *          set to a value that cannot be parsed as an integer.
402   */
403  @Nullable()
404  public static Integer getInt(@NotNull final String propertyName,
405                               @Nullable final Integer defaultValue)
406  {
407    return getInt(propertyName, defaultValue, false);
408  }
409
410
411
412  /**
413   * Retrieves the value of the specified property or environment variable as an
414   * integer.
415   *
416   * @param  propertyName         The name of the system property to retrieve,
417   *                              and to use to generate an alternative
418   *                              environment variable.  It must not be
419   *                              {@code null} or empty.
420   * @param  defaultValue         The default value to return if neither the
421   *                              system property nor associated environment
422   *                              variable have been set, or if the value cannot
423   *                              be parsed as an integer and
424   *                              {@code throwOnInvalidValue} is {@code false}.
425   *                              It may be {@code null} if no default value
426   *                              should be returned.
427   * @param  throwOnInvalidValue  Indicates whether this method should throw an
428   *                              {@code IllegalArgumentException} if the
429   *                              system property or environment variable is
430   *                              set but its value cannot be parsed as an
431   *                              integer.
432   *
433   * @return  The integer value of the specified property or environment
434   *          variable, or the provided default value if neither are set or are
435   *          set to a value that cannot be parsed as an integer and
436   *          {@code throwOnInvalidValue} is {@code false}.
437   *
438   * @throws  IllegalArgumentException  If the property or environment variable
439   *                                    is set, but its value cannot be parsed
440   *                                    as an integer, and
441   *                                    {@code throwOnInvalidValue} is
442   *                                    {@code true}.
443   */
444  @Nullable()
445  public static Integer getInt(@NotNull final String propertyName,
446                               @Nullable final Integer defaultValue,
447                               final boolean throwOnInvalidValue)
448         throws IllegalArgumentException
449  {
450    // See if there is a valid cache record for the property.  If so, then use
451    // it.
452    final int cacheDurationMillis = CACHE_DURATION_MILLIS.get();
453    if (cacheDurationMillis > 0)
454    {
455      final PropertyManagerCacheRecord cacheRecord = CACHE.get(propertyName);
456      if ((cacheRecord != null) && (! cacheRecord.isExpired()))
457      {
458        return cacheRecord.intValue(defaultValue, throwOnInvalidValue);
459      }
460    }
461
462
463    final String stringValue = get(propertyName);
464    if (stringValue == null)
465    {
466      return defaultValue;
467    }
468
469    try
470    {
471      return Integer.parseInt(stringValue.trim());
472    }
473    catch (final Exception e)
474    {
475      Debug.debugException(e);
476      if (throwOnInvalidValue)
477      {
478        throw new IllegalArgumentException(
479             ERR_PROPERTY_MANAGER_NOT_INT.get(getIdentifierString(propertyName),
480                  stringValue),
481             e);
482      }
483      else
484      {
485        return defaultValue;
486      }
487    }
488  }
489
490
491
492  /**
493   * Retrieves the value of the specified property or environment variable as a
494   * long.
495   *
496   * @param  propertyName  The name of the system property to retrieve, and to
497   *                       use to generate an alternative environment variable.
498   *                       It must not be {@code null} or empty.
499   *
500   * @return  The long value of the specified property or environment variable,
501   *          or {@code null} if neither are set or are set to a value that
502   *          cannot be parsed as a long.
503   */
504  @Nullable()
505  public static Long getLong(@NotNull final String propertyName)
506  {
507    return getLong(propertyName, null);
508  }
509
510
511
512  /**
513   * Retrieves the value of the specified property or environment variable as a
514   * long.
515   *
516   * @param  propertyName  The name of the system property to retrieve, and to
517   *                       use to generate an alternative environment variable.
518   *                       It must not be {@code null} or empty.
519   * @param  defaultValue  The default value to return if neither the system
520   *                       property nor associated environment variable have
521   *                       been set, or if the value cannot be parsed as a long.
522   *                       It may be {@code null} if no default value should be
523   *                       returned.
524   *
525   * @return  The long value of the specified property or environment variable,
526   *          or the provided default value if neither are set or are set to a
527   *          value that cannot be parsed as a long.
528   */
529  @Nullable()
530  public static Long getLong(@NotNull final String propertyName,
531                             @Nullable final Long defaultValue)
532  {
533    return getLong(propertyName, defaultValue, false);
534  }
535
536
537
538  /**
539   * Retrieves the value of the specified property or environment variable as a
540   * long.
541   *
542   * @param  propertyName         The name of the system property to retrieve,
543   *                              and to use to generate an alternative
544   *                              environment variable.  It must not be
545   *                              {@code null} or empty.
546   * @param  defaultValue         The default value to return if neither the
547   *                              system property nor associated environment
548   *                              variable have been set, or if the value cannot
549   *                              be parsed as a long and
550   *                              {@code throwOnInvalidValue} is {@code false}.
551   *                              It may be {@code null} if no default value
552   *                              should be returned.
553   * @param  throwOnInvalidValue  Indicates whether this method should throw an
554   *                              {@code IllegalArgumentException} if the
555   *                              system property or environment variable is
556   *                              set but its value cannot be parsed as a
557   *                              long.
558   *
559   * @return  The long value of the specified property or environment variable,
560   *          or the provided default value if neither are set or are set to a
561   *          value that cannot be parsed as a long and
562   *          {@code throwOnInvalidValue} is {@code false}.
563   *
564   * @throws  IllegalArgumentException  If the property or environment variable
565   *                                    is set, but its value cannot be parsed
566   *                                    as a long, and
567   *                                    {@code throwOnInvalidValue} is
568   *                                    {@code true}.
569   */
570  @Nullable()
571  public static Long getLong(@NotNull final String propertyName,
572                             @Nullable final Long defaultValue,
573                             final boolean throwOnInvalidValue)
574         throws IllegalArgumentException
575  {
576    // See if there is a valid cache record for the property.  If so, then use
577    // it.
578    final int cacheDurationMillis = CACHE_DURATION_MILLIS.get();
579    if (cacheDurationMillis > 0)
580    {
581      final PropertyManagerCacheRecord cacheRecord = CACHE.get(propertyName);
582      if ((cacheRecord != null) && (! cacheRecord.isExpired()))
583      {
584        return cacheRecord.longValue(defaultValue, throwOnInvalidValue);
585      }
586    }
587
588
589    final String stringValue = get(propertyName);
590    if (stringValue == null)
591    {
592      return defaultValue;
593    }
594
595    try
596    {
597      return Long.parseLong(stringValue.trim());
598    }
599    catch (final Exception e)
600    {
601      Debug.debugException(e);
602      if (throwOnInvalidValue)
603      {
604        throw new IllegalArgumentException(
605             ERR_PROPERTY_MANAGER_NOT_LONG.get(
606                  getIdentifierString(propertyName), stringValue),
607             e);
608      }
609      else
610      {
611        return defaultValue;
612      }
613    }
614  }
615
616
617
618  /**
619   * Retrieves the value of the specified property or environment variable as
620   * a list of comma-delimited values.  Any spaces around commas will be
621   * trimmed.
622   *
623   * @param  propertyName  The name of the system property to retrieve, and to
624   *                       use to generate an alternative environment variable.
625   *                       It must not be {@code null} or empty.
626   *
627   * @return  An unmodifiable list containing the comma-delimited values of the
628   *          specified property or environment variable, or an empty list if
629   *          neither is set.
630   */
631  @NotNull()
632  public static List<String> getCommaDelimitedList(
633              @NotNull final String propertyName)
634  {
635    return getCommaDelimitedList(propertyName, true);
636  }
637
638
639
640  /**
641   * Retrieves the value of the specified property or environment variable as
642   * a list of comma-delimited values.  Any spaces around commas will be
643   * trimmed.
644   *
645   * @param  propertyName  The name of the system property to retrieve, and to
646   *                       use to generate an alternative environment variable.
647   *                       It must not be {@code null} or empty.
648   * @param  trimItems     Indicates whether the individual items in the list
649   *                       should be trimmed to remove leading and/or trailing
650   *                       spaces.
651   *
652   * @return  An unmodifiable list containing the comma-delimited values of the
653   *          specified property or environment variable, or an empty list if
654   *          neither is set.
655   */
656  @NotNull()
657  public static List<String> getCommaDelimitedList(
658              @NotNull final String propertyName,
659              final boolean trimItems)
660  {
661    final List<String> items = new ArrayList<>();
662
663    final String stringValue = get(propertyName);
664    if (stringValue != null)
665    {
666      int startPos = 0;
667      while (true)
668      {
669        final int commaPos = stringValue.indexOf(',', startPos);
670        if (commaPos < 0)
671        {
672          String substring = stringValue.substring(startPos);
673          if (trimItems)
674          {
675            substring = substring.trim();
676          }
677
678          items.add(substring);
679          break;
680        }
681        else
682        {
683          String substring = stringValue.substring(startPos, commaPos);
684          if (trimItems)
685          {
686            substring = substring.trim();
687          }
688
689          items.add(substring);
690          startPos = commaPos + 1;
691        }
692      }
693    }
694
695    return Collections.unmodifiableList(items);
696  }
697
698
699
700  /**
701   * Retrieves a {@code Properties} object with values for any of the specified
702   * properties that are currently set.
703   *
704   * @param  propertyNames  The name of the properties whose values should be
705   *                        retrieved.  It must not be {@code null}, but may be
706   *                        empty.
707   *
708   * @return  A {@code Properties} object with any of the specified properties
709   *          that are set as either JVM system properties or environment
710   *          variables.  It may be empty if none of the specified properties
711   *          have been set.
712   */
713  @NotNull()
714  public static Properties getProperties(@NotNull final String... propertyNames)
715  {
716    final Properties properties = new Properties();
717
718    for (final String propertyName : propertyNames)
719    {
720      final String propertyValue = get(propertyName);
721      if (propertyValue != null)
722      {
723        properties.setProperty(propertyName, propertyValue);
724      }
725    }
726
727    return properties;
728  }
729
730
731
732  /**
733   * Generates an alternative environment variable name that can be used for a
734   * given property name.  All alphabetic letters in the provided name will be
735   * converted to uppercase, and all characters other than ASCII letters and
736   * digits will be converted to underscores.
737   *
738   * @param  propertyName  The property name to use to generate the environment
739   *                       variable name.  It must not be {@code null} or empty.
740   *
741   * @return  The alternative environment variable name generated from the given
742   *          property name.
743   */
744  @NotNull()
745  public static String generateEnvironmentVariableNameFromPropertyName(
746              @NotNull final String propertyName)
747  {
748    final String upperPropertyName =
749         StaticUtils.toUpperCase(propertyName.trim());
750
751    final int length = upperPropertyName.length();
752    final StringBuilder buffer = new StringBuilder(length);
753    for (int i=0; i < length; i++)
754    {
755      final char c = upperPropertyName.charAt(i);
756      if (((c >= 'A') && (c <= 'Z')) ||
757           ((c >= '0') && (c <= '9')))
758      {
759        buffer.append(c);
760      }
761      else
762      {
763        buffer.append('_');
764      }
765    }
766
767    return buffer.toString();
768  }
769
770
771
772  /**
773   * Retrieves an identifier string that can be used to indicate how the value
774   * of the specified property was obtained.  The returned value will be one of:
775   * <UL>
776   *   <LI>system property '{propertyName}'</LI>
777   *   <LI>environment variable '{propertyName}'</LI>
778   *   <LI>environment variable '{alternativeName}'</LI>
779   * </UL>
780   *
781   * @param  propertyName  The property name for which to retrieve the
782   *                       identifier.
783   *
784   * @return  The identifier string for the provided property name, or
785   *          {@code null} if the specified property is not set as either a
786   *          system property or an environment variable (including with an
787   *          alternative name).
788   */
789  @Nullable()
790  static String getIdentifierString(@NotNull final String propertyName)
791  {
792    if (StaticUtils.getSystemProperty(propertyName) != null)
793    {
794      return INFO_PROPERTY_MANAGER_SYSTEM_PROPERY_IDENTIFIER.get(propertyName);
795    }
796
797    if (StaticUtils.getEnvironmentVariable(propertyName) != null)
798    {
799      return INFO_PROPERTY_MANAGER_ENVIRONMENT_VARIABLE_IDENTIFIER.get(
800           propertyName);
801    }
802
803    final String alternativeName =
804         generateEnvironmentVariableNameFromPropertyName(propertyName);
805    if (StaticUtils.getEnvironmentVariable(alternativeName) != null)
806    {
807      return INFO_PROPERTY_MANAGER_ENVIRONMENT_VARIABLE_IDENTIFIER.get(
808           alternativeName);
809    }
810
811    return null;
812  }
813
814
815
816  /**
817   * Retrieves the maximum length of time in milliseconds that property values
818   * should be cached for faster retrieval.  A value of zero indicates that no
819   * caching should be performed.  A value of {@code Integer.MAX_VALUE}
820   * indicates that cache records should never expire.
821   *
822   * @return  The maximum length of time in milliseconds that property values
823   *          should be cached for faster retrieval.
824   */
825  public static int getCacheDurationMillis()
826  {
827    return CACHE_DURATION_MILLIS.get();
828  }
829
830
831
832  /**
833   * Specifies the maximum length of time in milliseconds that property values
834   * should be cached for faster retrieval.
835   *
836   * @param  cacheDurationMillis  The maximum length of time in milliseconds
837   *                              that property values should be cached for
838   *                              faster retrieval.  A value that is less than
839   *                              or equal to zero indicates that values should
840   *                              not be cached.  A value of
841   *                              {@code Integer.MAX_VALUE} indicates that cache
842   *                              records should never expire.
843   */
844  public static void setCacheDurationMillis(final int cacheDurationMillis)
845  {
846    if (cacheDurationMillis > 0)
847    {
848      PropertyManager.CACHE_DURATION_MILLIS.set(cacheDurationMillis);
849    }
850    else
851    {
852      PropertyManager.CACHE_DURATION_MILLIS.set(0);
853    }
854  }
855
856
857
858  /**
859   * Retrieves a handle to the cache.  This method is only intended for testing
860   * purposes.
861   *
862   * @return  A handle to the cache.
863   */
864  @NotNull()
865  static Map<String,PropertyManagerCacheRecord> getCache()
866  {
867    return CACHE;
868  }
869
870
871
872  /**
873   * Populates the cache with current values obtained from system properties
874   * and environment variables.  This will not have any effect if caching is
875   * disabled.
876   */
877  public static void populateCache()
878  {
879    clearCache();
880
881    final int cacheDurationMillis = CACHE_DURATION_MILLIS.get();
882    if (cacheDurationMillis <= 0)
883    {
884      return;
885    }
886
887    for (final Map.Entry<String,String> envVar :
888         StaticUtils.getEnvironmentVariables().entrySet())
889    {
890      final String propertyName = envVar.getKey();
891      final String stringValue = envVar.getValue();
892
893      CACHE.put(propertyName, new PropertyManagerCacheRecord(propertyName,
894           stringValue, cacheDurationMillis));
895    }
896
897    for (final Map.Entry<Object,Object> systemProperty :
898         StaticUtils.getSystemProperties().entrySet())
899    {
900      final String propertyName = String.valueOf(systemProperty.getKey());
901      final String stringValue = String.valueOf(systemProperty.getValue());
902
903      CACHE.put(propertyName, new PropertyManagerCacheRecord(propertyName,
904           stringValue, cacheDurationMillis));
905    }
906  }
907
908
909
910  /**
911   * Clears any cached property information.
912   */
913  public static void clearCache()
914  {
915    CACHE.clear();
916  }
917}