blob: a340f600373b8f8ee93940599f6f946274998ad5 [file] [log] [blame]
/*
* 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.shared.ldap.util;
import java.io.File;
import java.io.InputStream;
import java.io.IOException;
import java.io.FileInputStream;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Properties;
import org.apache.directory.shared.ldap.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>
* @version $Rev$
*/
public class PropertiesUtils
{
/** default properties file extension */
private static final String DOTPROPERTIES = ".properties";
// ------------------------------------------------------------------------
// 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
*/
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;
}
}
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
*/
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;
}
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
*/
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;
}
}
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
*/
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;
}
}
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 = props.getProperty( key ).trim().toLowerCase();
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();
}
}