| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| */ |
| package org.apache.directory.api.util; |
| |
| |
| import java.io.File; |
| import java.io.FileInputStream; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.util.Enumeration; |
| import java.util.Hashtable; |
| import java.util.Properties; |
| |
| import org.apache.directory.api.util.exception.NotImplementedException; |
| |
| |
| /** |
| * A utility class used for accessing, finding, merging and macro expanding |
| * properties, on disk, via URLS or as resources. |
| * |
| * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> |
| */ |
| public final class PropertiesUtils |
| { |
| /** default properties file extension */ |
| private static final String DOTPROPERTIES = ".properties"; |
| |
| |
| /** |
| * Private constructor |
| */ |
| private PropertiesUtils() |
| { |
| } |
| |
| |
| // ------------------------------------------------------------------------ |
| // Utilities for discovering Properties |
| // ------------------------------------------------------------------------ |
| |
| /** |
| * Loads a properties object in a properties file if it exists relative to |
| * the filename ${user.home}. If the file ${user.home}/[filename] does not |
| * exist then one last attempt to find the file is made if filename does not |
| * have a .properties extension. If so and |
| * ${user.home}/[filename].properties exists then it is loaded. |
| * |
| * @param filename |
| * the properties file name with or without an extension |
| * @return the user properties object |
| */ |
| public static Properties findUserProperties( String filename ) |
| { |
| return findProperties( new File( System.getProperty( "user.home" ) ), filename ); |
| } |
| |
| |
| /** |
| * Create a new properties object and load the properties file if it exists |
| * relative to [dir]/[filename] or [dir]/[filename].properties. |
| * |
| * @param dir |
| * the base directory |
| * @param filename |
| * the full fine name or the base name w/o the extension |
| * @return the loaded properties object |
| */ |
| public static Properties findProperties( File dir, String filename ) |
| { |
| final File asis = new File( dir, filename ); |
| |
| if ( asis.exists() ) |
| { |
| return getProperties( asis ); |
| } |
| |
| if ( filename.endsWith( DOTPROPERTIES ) ) |
| { |
| String noExt = filename.substring( 0, filename.length() - 11 ); |
| if ( new File( dir, noExt ).exists() ) |
| { |
| return getProperties( new File( dir, noExt ) ); |
| } |
| |
| return new Properties(); |
| } |
| |
| File withExt = new File( dir, filename + DOTPROPERTIES ); |
| if ( withExt.exists() ) |
| { |
| return getProperties( withExt ); |
| } |
| |
| return new Properties(); |
| } |
| |
| |
| /** |
| * Load a properties from a resource relative to a supplied class. First an |
| * attempt is made to locate a property file colocated with the class with |
| * the name [class].properties. If this cannot be found or errors result an |
| * empty Properties file is returned. |
| * |
| * @param ref |
| * a class to use for relative path references |
| * @return the static properties |
| */ |
| // This will suppress PMD.EmptyCatchBlock warnings in this method |
| @SuppressWarnings("PMD.EmptyCatchBlock") |
| public static Properties getStaticProperties( Class<?> ref ) |
| { |
| final Properties properties = new Properties(); |
| final String address = ref.toString().replace( '.', '/' ); |
| final String path = address + ".properties"; |
| InputStream input = ref.getResourceAsStream( path ); |
| |
| if ( null != input ) |
| { |
| try |
| { |
| properties.load( input ); |
| } |
| catch ( IOException e ) |
| { |
| return properties; |
| } |
| finally |
| { |
| if ( input != null ) |
| { |
| try |
| { |
| input.close(); |
| } |
| catch ( IOException e ) |
| { |
| // Empty catch, we can't more than trying to close |
| } |
| } |
| } |
| } |
| |
| return properties; |
| } |
| |
| |
| /** |
| * Load properties from a resource relative to a supplied class and path. |
| * |
| * @param ref |
| * a class to use for relative path references |
| * @param path |
| * the relative path to the resoruce |
| * @return the static properties |
| */ |
| // This will suppress PMD.EmptyCatchBlock warnings in this method |
| @SuppressWarnings("PMD.EmptyCatchBlock") |
| public static Properties getStaticProperties( Class<?> ref, String path ) |
| { |
| Properties properties = new Properties(); |
| InputStream input = ref.getResourceAsStream( path ); |
| |
| if ( input == null ) |
| { |
| return properties; |
| } |
| |
| try |
| { |
| properties.load( input ); |
| } |
| catch ( IOException e ) |
| { |
| return properties; |
| } |
| finally |
| { |
| if ( input != null ) |
| { |
| try |
| { |
| input.close(); |
| } |
| catch ( IOException e ) |
| { |
| // Empty catch, we can't more than trying to close |
| } |
| } |
| } |
| |
| return properties; |
| } |
| |
| |
| /** |
| * Creates a properties object and loads the properties in the file |
| * otherwise and empty property object will be returned. |
| * |
| * @param file |
| * the properties file |
| * @return the properties object |
| */ |
| public static Properties getProperties( File file ) |
| { |
| Properties properties = new Properties(); |
| |
| if ( null == file ) |
| { |
| return properties; |
| } |
| |
| if ( file.exists() ) |
| { |
| try |
| { |
| final FileInputStream fis = new FileInputStream( file ); |
| try |
| { |
| properties.load( fis ); |
| } |
| finally |
| { |
| fis.close(); |
| } |
| } |
| catch ( IOException e ) |
| { |
| return properties; |
| } |
| } |
| |
| return properties; |
| } |
| |
| |
| /** |
| * Loads a properties file as a CL resource if it exists and returns an |
| * empty Properties object otherwise. |
| * |
| * @param classloader |
| * the loader to use for the resources |
| * @param path |
| * the path to the resource |
| * @return the loaded or new Properties |
| */ |
| // This will suppress PMD.EmptyCatchBlock warnings in this method |
| @SuppressWarnings("PMD.EmptyCatchBlock") |
| public static Properties getProperties( ClassLoader classloader, String path ) |
| { |
| Properties properties = new Properties(); |
| InputStream input = classloader.getResourceAsStream( path ); |
| |
| if ( input != null ) |
| { |
| try |
| { |
| properties.load( input ); |
| } |
| catch ( IOException e ) |
| { |
| return properties; |
| } |
| finally |
| { |
| if ( input != null ) |
| { |
| try |
| { |
| input.close(); |
| } |
| catch ( IOException e ) |
| { |
| // Empty catch, we can't more than trying to close |
| } |
| } |
| } |
| } |
| |
| return properties; |
| } |
| |
| |
| /** |
| * Loads a properties file as a class resource if it exists and returns an |
| * empty Properties object otherwise. |
| * |
| * @param clazz |
| * the class to use for resolving the resources |
| * @param path |
| * the relative path to the resource |
| * @return the loaded or new Properties |
| */ |
| // This will suppress PMD.EmptyCatchBlock warnings in this method |
| @SuppressWarnings("PMD.EmptyCatchBlock") |
| public static Properties getProperties( Class<?> clazz, String path ) |
| { |
| Properties properties = new Properties(); |
| InputStream input = clazz.getResourceAsStream( path ); |
| |
| if ( input != null ) |
| { |
| try |
| { |
| properties.load( input ); |
| } |
| catch ( IOException e ) |
| { |
| return properties; |
| } |
| finally |
| { |
| if ( input != null ) |
| { |
| try |
| { |
| input.close(); |
| } |
| catch ( IOException e ) |
| { |
| // Empty catch, we can't more than trying to close |
| } |
| } |
| } |
| } |
| |
| return properties; |
| } |
| |
| |
| // ------------------------------------------------------------------------ |
| // Utilities for operating on or setting Properties values |
| // ------------------------------------------------------------------------ |
| |
| /** |
| * Expands out a set of property key macros in the following format |
| * ${foo.bar} where foo.bar is a property key, by dereferencing the value of |
| * the key using the original source Properties and other optional |
| * Properties. If the original expanded Properties contain the value for the |
| * macro key, foo.bar, then dereferencing stops by using the value in the |
| * expanded Properties: the other optional Properties are NOT used at all. |
| * If the original expanded Properties do NOT contain the value for the |
| * macro key, then the optional Properties are used in order. The first of |
| * the optionals to contain the value for the macro key (foo.bar) shorts the |
| * search. Hence the first optional Properties in the array to contain a |
| * value for the macro key (foo.bar) is used to set the expanded value. If a |
| * macro cannot be expanded because it's key was not defined within the |
| * expanded Properties or one of the optional Properties then it is left as |
| * is. |
| * |
| * @param expanded |
| * the Properties to perform the macro expansion upon |
| * @param optionals |
| * null or an optional set of Properties to use for dereferencing |
| * macro keys (foo.bar) |
| */ |
| public static void macroExpand( Properties expanded, Properties[] optionals ) |
| { |
| // Handle null optionals |
| if ( null == optionals ) |
| { |
| optionals = new Properties[0]; |
| } |
| |
| Enumeration<?> list = expanded.propertyNames(); |
| |
| while ( list.hasMoreElements() ) |
| { |
| String key = ( String ) list.nextElement(); |
| String macro = expanded.getProperty( key ); |
| |
| int n = macro.indexOf( "${" ); |
| if ( n < 0 ) |
| { |
| continue; |
| } |
| |
| int m = macro.indexOf( "}", n + 2 ); |
| if ( m < 0 ) |
| { |
| continue; |
| } |
| |
| final String symbol = macro.substring( n + 2, m ); |
| |
| if ( expanded.containsKey( symbol ) ) |
| { |
| final String value = expanded.getProperty( symbol ); |
| final String head = macro.substring( 0, n ); |
| final String tail = macro.substring( m + 1 ); |
| final String resolved = head + value + tail; |
| expanded.put( key, resolved ); |
| continue; |
| } |
| |
| /* |
| * Check if the macro key exists within the array of optional |
| * Properties. Set expanded value to first Properties with the key |
| * and break out of the loop. |
| */ |
| for ( int ii = 0; ii < optionals.length; ii++ ) |
| { |
| if ( optionals[ii].containsKey( symbol ) ) |
| { |
| final String value = optionals[ii].getProperty( symbol ); |
| final String head = macro.substring( 0, n ); |
| final String tail = macro.substring( m + 1 ); |
| final String resolved = head + value + tail; |
| expanded.put( key, resolved ); |
| break; |
| } |
| } |
| } |
| } |
| |
| |
| /** |
| * Discovers a value within a set of Properties either halting on the first |
| * time the property is discovered or continuing on to take the last value |
| * found for the property key. |
| * |
| * @param key |
| * a property key |
| * @param sources |
| * a set of source Properties |
| * @param haltOnDiscovery |
| * true if we stop on finding a value, false otherwise |
| * @return the value found or null |
| */ |
| public static String discover( String key, Properties[] sources, boolean haltOnDiscovery ) |
| { |
| String retval = null; |
| |
| for ( int ii = 0; ii < sources.length; ii++ ) |
| { |
| if ( sources[ii].containsKey( key ) ) |
| { |
| retval = sources[ii].getProperty( key ); |
| |
| if ( haltOnDiscovery ) |
| { |
| break; |
| } |
| } |
| } |
| |
| return retval; |
| } |
| |
| |
| /** |
| * Merges a set of properties from source Properties into a target |
| * properties instance containing keys. This method does not allow null |
| * overrides. |
| * |
| * @param keys |
| * the keys to discover values for |
| * @param sources |
| * the sources to search |
| * @param haltOnDiscovery |
| * true to halt on first find or false to continue to last find |
| */ |
| public static void discover( Properties keys, Properties[] sources, boolean haltOnDiscovery ) |
| { |
| if ( null == sources || null == keys ) |
| { |
| return; |
| } |
| |
| /* |
| * H A N D L E S I N G L E V A L U E D K E Y S |
| */ |
| for ( Object key : keys.keySet() ) |
| { |
| String value = discover( ( String ) key, sources, haltOnDiscovery ); |
| |
| if ( value != null ) |
| { |
| keys.setProperty( ( String ) key, value ); |
| } |
| } |
| } |
| |
| |
| // ------------------------------------------------------------------------ |
| // Various Property Accessors |
| // ------------------------------------------------------------------------ |
| |
| /** |
| * Gets a String property as a boolean returning a defualt if the key is not |
| * present. In any case, true, on, 1 and yes strings return true and |
| * everything else returns |
| * |
| * @param props |
| * the properties to get the value from |
| * @param key |
| * the property key |
| * @param defaultValue |
| * the default value to return if key is not present |
| * @return true defaultValue if property does not exist, else return true if |
| * the String value is one of 'true', 'on', '1', 'yes', otherwise |
| * false is returned |
| */ |
| public static boolean get( Properties props, String key, boolean defaultValue ) |
| { |
| if ( props == null || !props.containsKey( key ) || props.getProperty( key ) == null ) |
| { |
| return defaultValue; |
| } |
| |
| String val = Strings.toLowerCase( Strings.trim( props.getProperty( key ) ) ); |
| return val.equals( "true" ) || val.equals( "on" ) || val.equals( "1" ) || val.equals( "yes" ); |
| } |
| |
| |
| /** |
| * Gets a property or entry value from a hashtable and tries to transform |
| * whatever the value may be to an primitive integer. |
| * |
| * @param ht |
| * the hashtable to access for the value |
| * @param key |
| * the key to use when accessing the ht |
| * @param defval |
| * the default value to use if the key is not contained in ht or |
| * if the value cannot be represented as a primitive integer. |
| * @return the primitive integer representation of a hashtable value |
| */ |
| public static int get( Hashtable<String, Object> ht, Object key, int defval ) |
| { |
| if ( ht == null || !ht.containsKey( key ) || ht.get( key ) == null ) |
| { |
| return defval; |
| } |
| |
| Object obj = ht.get( key ); |
| |
| if ( obj instanceof Byte ) |
| { |
| return ( ( Byte ) obj ).intValue(); |
| } |
| if ( obj instanceof Short ) |
| { |
| return ( ( Short ) obj ).intValue(); |
| } |
| if ( obj instanceof Integer ) |
| { |
| return ( ( Integer ) obj ).intValue(); |
| } |
| if ( obj instanceof Long ) |
| { |
| return ( ( Long ) obj ).intValue(); |
| } |
| if ( obj instanceof String ) |
| { |
| try |
| { |
| return Integer.parseInt( ( String ) obj ); |
| } |
| catch ( NumberFormatException ne ) |
| { |
| ne.printStackTrace(); |
| return defval; |
| } |
| } |
| |
| return defval; |
| } |
| |
| |
| public static long get( Properties props, String key, long defaultValue ) |
| { |
| if ( props == null || !props.containsKey( key ) || props.getProperty( key ) == null ) |
| { |
| return defaultValue; |
| } |
| |
| throw new NotImplementedException(); |
| } |
| |
| |
| public static byte get( Properties props, String key, byte defaultValue ) |
| { |
| if ( props == null || !props.containsKey( key ) || props.getProperty( key ) == null ) |
| { |
| return defaultValue; |
| } |
| |
| throw new NotImplementedException(); |
| } |
| |
| |
| public static char get( Properties props, String key, char defaultValue ) |
| { |
| if ( props == null || !props.containsKey( key ) || props.getProperty( key ) == null ) |
| { |
| return defaultValue; |
| } |
| |
| throw new NotImplementedException(); |
| } |
| } |