Class PropertiesConfiguration

  • All Implemented Interfaces:
    java.lang.Cloneable, Configuration, EventSource, FileBasedConfiguration, ImmutableConfiguration, FileBased, FileLocatorAware, SynchronizerSupport

    public class PropertiesConfiguration
    extends BaseConfiguration
    implements FileBasedConfiguration, FileLocatorAware
    This is the "classic" Properties loader which loads the values from a single or multiple files (which can be chained with "include =". All given path references are either absolute or relative to the file name supplied in the constructor.

    In this class, empty PropertyConfigurations can be built, properties added and later saved. include statements are (obviously) not supported if you don't construct a PropertyConfiguration from a file.

    The properties file syntax is explained here, basically it follows the syntax of the stream parsed by Properties.load(java.io.Reader) and adds several useful extensions:

    • Each property has the syntax key <separator> value. The separators accepted are '=', ':' and any white space character. Examples:
        key1 = value1
        key2 : value2
        key3   value3
       
    • The key may use any character, separators must be escaped:
        key\:foo = bar
       
    • value may be separated on different lines if a backslash is placed at the end of the line that continues below.
    • The list delimiter facilities provided by AbstractConfiguration are supported, too. If an appropriate ListDelimiterHandler is set (for instance a D efaultListDelimiterHandler object configured with a comma as delimiter character), value can contain value delimiters and will then be interpreted as a list of tokens. So the following property definition
        key = This property, has multiple, values
       
      will result in a property with three values. You can change the handling of delimiters using the AbstractConfiguration.setListDelimiterHandler(ListDelimiterHandler) method. Per default, list splitting is disabled.
    • Commas in each token are escaped placing a backslash right before the comma.
    • If a key is used more than once, the values are appended like if they were on the same line separated with commas. Note: When the configuration file is written back to disk the associated PropertiesConfigurationLayout object (see below) will try to preserve as much of the original format as possible, i.e. properties with multiple values defined on a single line will also be written back on a single line, and multiple occurrences of a single key will be written on multiple lines. If the addProperty() method was called multiple times for adding multiple values to a property, these properties will per default be written on multiple lines in the output file, too. Some options of the PropertiesConfigurationLayout class have influence on that behavior.
    • Blank lines and lines starting with character '#' or '!' are skipped.
    • If a property is named "include" (or whatever is defined by setInclude() and getInclude() and the value of that property is the full path to a file on disk, that file will be included into the configuration. You can also pull in files relative to the parent configuration file. So if you have something like the following: include = additional.properties Then "additional.properties" is expected to be in the same directory as the parent configuration file. The properties in the included file are added to the parent configuration, they do not replace existing properties with the same key.
    • You can define custom error handling for the special key "include" by using setIncludeListener(ConfigurationConsumer).

    Here is an example of a valid extended properties file:

          # lines starting with # are comments
    
          # This is the simplest property
          key = value
    
          # A long property may be separated on multiple lines
          longvalue = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa \
                      aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
    
          # This is a property with many tokens
          tokens_on_a_line = first token, second token
    
          # This sequence generates exactly the same result
          tokens_on_multiple_lines = first token
          tokens_on_multiple_lines = second token
    
          # commas may be escaped in tokens
          commas.escaped = Hi\, what'up?
    
          # properties can reference other properties
          base.prop = /base
          first.prop = ${base.prop}/first
          second.prop = ${first.prop}/second
     

    A PropertiesConfiguration object is associated with an instance of the PropertiesConfigurationLayout class, which is responsible for storing the layout of the parsed properties file (i.e. empty lines, comments, and such things). The getLayout() method can be used to obtain this layout object. With setLayout() a new layout object can be set. This should be done before a properties file was loaded.

    Like other Configuration implementations, this class uses a Synchronizer object to control concurrent access. By choosing a suitable implementation of the Synchronizer interface, an instance can be made thread-safe or not. Note that access to most of the properties typically set through a builder is not protected by the Synchronizer. The intended usage is that these properties are set once at construction time through the builder and after that remain constant. If you wish to change such properties during life time of an instance, you have to use the lock() and unlock() methods manually to ensure that other threads see your changes.

    As this class extends AbstractConfiguration, all basic features like variable interpolation, list handling, or data type conversions are available as well. This is described in the chapter Basic features and AbstractConfiguration of the user's guide. There is also a separate chapter dealing with Properties files in special.

    See Also:
    Properties.load(java.io.Reader)
    • Field Detail

      • DEFAULT_INCLUDE_LISTENER

        public static final ConfigurationConsumer<ConfigurationException> DEFAULT_INCLUDE_LISTENER
        Defines default error handling for the special "include" key by throwing the given exception.
        Since:
        2.6
      • DEFAULT_ENCODING

        public static final java.lang.String DEFAULT_ENCODING
        The default encoding (ISO-8859-1 as specified by https://docs.oracle.com/javase/8/docs/api/java/util/Properties.html)
      • COMMENT_CHARS

        static final java.lang.String COMMENT_CHARS
        Constant for the supported comment characters.
        See Also:
        Constant Field Values
      • DEFAULT_SEPARATOR

        static final java.lang.String DEFAULT_SEPARATOR
        Constant for the default properties separator.
        See Also:
        Constant Field Values
      • UNESCAPE_CHARACTERS

        private static final java.lang.String UNESCAPE_CHARACTERS
        A string with special characters that need to be unescaped when reading a properties file. Properties escapes these characters when writing out a properties file.
        See Also:
        Constant Field Values
      • include

        private static java.lang.String include
        This is the name of the property that can point to other properties file for including other properties files.
      • includeOptional

        private static java.lang.String includeOptional
        This is the name of the property that can point to other properties file for including other properties files.

        If the file is absent, processing continues normally.

      • SEPARATORS

        private static final char[] SEPARATORS
        The list of possible key/value separators
      • WHITE_SPACE

        private static final char[] WHITE_SPACE
        The white space characters used as key/value separators.
      • LINE_SEPARATOR

        private static final java.lang.String LINE_SEPARATOR
        Constant for the platform specific line separator.
      • HEX_RADIX

        private static final int HEX_RADIX
        Constant for the radix of hex numbers.
        See Also:
        Constant Field Values
      • UNICODE_LEN

        private static final int UNICODE_LEN
        Constant for the length of a unicode literal.
        See Also:
        Constant Field Values
      • locator

        private FileLocator locator
        The current FileLocator.
      • includesAllowed

        private boolean includesAllowed
        Allow file inclusion or not
    • Constructor Detail

      • PropertiesConfiguration

        public PropertiesConfiguration()
        Creates an empty PropertyConfiguration object which can be used to synthesize a new Properties file by adding values and then saving().
    • Method Detail

      • countTrailingBS

        private static int countTrailingBS​(java.lang.String line)
        Returns the number of trailing backslashes. This is sometimes needed for the correct handling of escape characters.
        Parameters:
        line - the string to investigate
        Returns:
        the number of trailing backslashes
      • getInclude

        public static java.lang.String getInclude()
        Gets the property value for including other properties files. By default it is "include".
        Returns:
        A String.
      • getIncludeOptional

        public static java.lang.String getIncludeOptional()
        Gets the property value for including other properties files. By default it is "includeoptional".

        If the file is absent, processing continues normally.

        Returns:
        A String.
        Since:
        2.5
      • isCommentLine

        static boolean isCommentLine​(java.lang.String line)
        Tests whether a line is a comment, i.e. whether it starts with a comment character.
        Parameters:
        line - the line
        Returns:
        a flag if this is a comment line
        Since:
        1.3
      • needsUnescape

        private static boolean needsUnescape​(char ch)
        Checks whether the specified character needs to be unescaped. This method is called when during reading a property file an escape character ('\') is detected. If the character following the escape character is recognized as a special character which is escaped per default in a Java properties file, it has to be unescaped.
        Parameters:
        ch - the character in question
        Returns:
        a flag whether this character has to be unescaped
      • setInclude

        public static void setInclude​(java.lang.String inc)
        Sets the property value for including other properties files. By default it is "include".
        Parameters:
        inc - A String.
      • setIncludeOptional

        public static void setIncludeOptional​(java.lang.String inc)
        Sets the property value for including other properties files. By default it is "include".

        If the file is absent, processing continues normally.

        Parameters:
        inc - A String.
        Since:
        2.5
      • unescapeJava

        protected static java.lang.String unescapeJava​(java.lang.String str)

        Unescapes any Java literals found in the String to a Writer.

        This is a slightly modified version of the StringEscapeUtils.unescapeJava() function in commons-lang that doesn't drop escaped separators (i.e '\,').
        Parameters:
        str - the String to unescape, may be null
        Returns:
        the processed string
        Throws:
        java.lang.IllegalArgumentException - if the Writer is null
      • unescapeJava

        protected static java.lang.String unescapeJava​(java.lang.String str,
                                                       boolean jupCompatible)
        Unescapes Java literals found in the String to a Writer.

        When the parameter jupCompatible is false, the classic behavior is used (see unescapeJava(String)). When it's true a slightly different behavior that's compatible with Properties is used (see PropertiesConfiguration.JupIOFactory).

        Parameters:
        str - the String to unescape, may be null
        jupCompatible - whether unescaping is compatible with Properties; otherwise the classic behavior is used
        Returns:
        the processed string
        Throws:
        java.lang.IllegalArgumentException - if the Writer is null
      • clone

        public java.lang.Object clone()
        Creates a copy of this object.
        Overrides:
        clone in class BaseConfiguration
        Returns:
        the copy
      • createLayout

        private PropertiesConfigurationLayout createLayout()
        Creates a standard layout object. This configuration is initialized with such a standard layout.
        Returns:
        the newly created layout object
      • getFooter

        public java.lang.String getFooter()
        Gets the footer comment. This is a comment at the very end of the file.
        Returns:
        the footer comment
        Since:
        2.0
      • getHeader

        public java.lang.String getHeader()
        Gets the comment header.
        Returns:
        the comment header
        Since:
        1.1
      • getIOFactory

        public PropertiesConfiguration.IOFactory getIOFactory()
        Gets the IOFactory to be used for creating readers and writers when loading or saving this configuration.
        Returns:
        the IOFactory
        Since:
        1.7
      • getLayout

        public PropertiesConfigurationLayout getLayout()
        Gets the associated layout object.
        Returns:
        the associated layout object
        Since:
        1.3
      • initFileLocator

        public void initFileLocator​(FileLocator locator)
        Stores the current FileLocator for a following IO operation. The FileLocator is needed to resolve include files with relative file names.
        Specified by:
        initFileLocator in interface FileLocatorAware
        Parameters:
        locator - the current FileLocator
        Since:
        2.0
      • installLayout

        private void installLayout​(PropertiesConfigurationLayout layout)
        Installs a layout object. It has to be ensured that the layout is registered as change listener at this configuration. If there is already a layout object installed, it has to be removed properly.
        Parameters:
        layout - the layout object to be installed
      • isIncludesAllowed

        public boolean isIncludesAllowed()
        Reports the status of file inclusion.
        Returns:
        True if include files are loaded.
      • loadIncludeFile

        private void loadIncludeFile​(java.lang.String fileName,
                                     boolean optional,
                                     java.util.Deque<java.net.URL> seenStack)
                              throws ConfigurationException
        Helper method for loading an included properties file. This method is called by load() when an include property is encountered. It tries to resolve relative file names based on the current base path. If this fails, a resolution based on the location of this properties file is tried.
        Parameters:
        fileName - the name of the file to load
        optional - whether or not the fileName is optional
        seenStack - Stack of seen include URLs
        Throws:
        ConfigurationException - if loading fails
      • locateIncludeFile

        private java.net.URL locateIncludeFile​(java.lang.String basePath,
                                               java.lang.String fileName)
        Tries to obtain the URL of an include file using the specified (optional) base path and file name.
        Parameters:
        basePath - the base path
        fileName - the file name
        Returns:
        the URL of the include file or null if it cannot be resolved
      • propertyLoaded

        boolean propertyLoaded​(java.lang.String key,
                               java.lang.String value,
                               java.util.Deque<java.net.URL> seenStack)
                        throws ConfigurationException
        This method is invoked by the associated PropertiesConfigurationLayout object for each property definition detected in the parsed properties file. Its task is to check whether this is a special property definition (e.g. the include property). If not, the property must be added to this configuration. The return value indicates whether the property should be treated as a normal property. If it is false, the layout object will ignore this property.
        Parameters:
        key - the property key
        value - the property value
        seenStack - the stack of seen include URLs
        Returns:
        a flag whether this is a normal property
        Throws:
        ConfigurationException - if an error occurs
        Since:
        1.3
      • read

        public void read​(java.io.Reader in)
                  throws ConfigurationException,
                         java.io.IOException
        Reads the content of this object from the given reader. Client code should not call this method directly, but use a FileHandler for reading data. This implementation delegates to the associated layout object which does the actual loading. Note that this method does not do any synchronization. This lies in the responsibility of the caller. (Typically, the caller is a FileHandler object which takes care for proper synchronization.)
        Specified by:
        read in interface FileBased
        Parameters:
        in - the reader
        Throws:
        ConfigurationException - if a non-I/O related problem occurs, e.g. the data read does not have the expected format
        java.io.IOException - if an I/O error occurs.
        Since:
        2.0
      • setFooter

        public void setFooter​(java.lang.String footer)
        Sets the footer comment. If set, this comment is written after all properties at the end of the file.
        Parameters:
        footer - the footer comment
        Since:
        2.0
      • setHeader

        public void setHeader​(java.lang.String header)
        Sets the comment header.
        Parameters:
        header - the header to use
        Since:
        1.1
      • setIncludeListener

        public void setIncludeListener​(ConfigurationConsumer<ConfigurationException> includeListener)
        Sets the current include listener, may not be null.
        Parameters:
        includeListener - the current include listener, may not be null.
        Throws:
        java.lang.IllegalArgumentException - if the includeListener is null.
        Since:
        2.6
      • setIncludesAllowed

        public void setIncludesAllowed​(boolean includesAllowed)
        Controls whether additional files can be loaded by the include = <xxx> statement or not. This is true per default.
        Parameters:
        includesAllowed - True if Includes are allowed.
      • setIOFactory

        public void setIOFactory​(PropertiesConfiguration.IOFactory ioFactory)
        Sets the IOFactory to be used for creating readers and writers when loading or saving this configuration. Using this method a client can customize the reader and writer classes used by the load and save operations. Note that this method must be called before invoking one of the load() and save() methods. Especially, if you want to use a custom IOFactory for changing the PropertiesReader, you cannot load the configuration data in the constructor.
        Parameters:
        ioFactory - the new IOFactory (must not be null)
        Throws:
        java.lang.IllegalArgumentException - if the IOFactory is null
        Since:
        1.7
      • setLayout

        public void setLayout​(PropertiesConfigurationLayout layout)
        Sets the associated layout object.
        Parameters:
        layout - the new layout object; can be null, then a new layout object will be created
        Since:
        1.3
      • write

        public void write​(java.io.Writer out)
                   throws ConfigurationException,
                          java.io.IOException
        Writes the content of this object to the given writer. Client code should not call this method directly, but use a FileHandler for writing data. This implementation delegates to the associated layout object which does the actual saving. Note that, analogous to read(Reader), this method does not do any synchronization.
        Specified by:
        write in interface FileBased
        Parameters:
        out - the writer
        Throws:
        ConfigurationException - if a non-I/O related problem occurs, e.g. the data read does not have the expected format
        java.io.IOException - if an I/O error occurs.
        Since:
        2.0