| 
What this is
 Other links
 The source code
/*
** Copyright (c) 1997 by Tim Endres
** 
** This program is free software.
** 
** You may redistribute it and/or modify it under the terms of the GNU
** General Public License as published by the Free Software Foundation.
** Version 2 of the license should be included with this distribution in
** the file LICENSE, as well as License.html. If the license is not
** included	with this distribution, you may find a copy at the FSF web
** site at 'www.gnu.org' or 'www.fsf.org', or you may write to the
** Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139 USA.
**
** THIS SOFTWARE IS PROVIDED AS-IS WITHOUT WARRANTY OF ANY KIND,
** NOT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY. THE AUTHOR
** OF THIS SOFTWARE, ASSUMES _NO_ RESPONSIBILITY FOR ANY
** CONSEQUENCE RESULTING FROM THE USE, MODIFICATION, OR
** REDISTRIBUTION OF THIS SOFTWARE. 
** 
*/
package com.ice.util;
import java.lang.reflect.*;
import java.io.*;
import java.awt.*;
import java.util.*;
import java.net.*;
/**
 * The UserProperties class. This class is used to extend
 * the concept of System.getProperty(). This class adds the
 * following features:
 *
 * <ul>
 * <li> A hierarchical property definition structure.
 * <li> Typed property retrieval with default values.
 * <li> Hierarchical overrides allowings properties to
 * be overridden on a per user or per host or per host
 * and user basis.
 * <li> The ability to load from any valid resource, including
 * files stored in JAR files, files located via the file system,
 * which includes networked file systems, as well as any other
 * resource that can be identified via a URL, including web pages,
 * FTP-ed files, and more.
 * </ul>
 *
 * <p>
 * Here is how it works. We have <em>six levels of
 * properties which are loaded based on various settings.
 * The levels look like this:
 *
 * <ol>
 * <li> Hardwired defaults.
 * <li> Application defined defaults.
 * <li> Defaults resource.
 * <li> System level resource list.
 * <li> Application property file.
 * <li> Application resource list.
 * </ol>
 *
 * <p>
 * Resource lists are colon (:) separated strings listing
 * resource names to be loaded into the properties.
 *
 * <p>
 * In a typical deployment, the developer will place the
 * defaults resource in the JAR file containing the application's
 * classes. This file will then define the application properties
 * file, which will usually be left empty allowing the user to
 * place all customizations in this local file. For distributed
 * applications, system resources will typically be supplied via
 * simple web pages, which allows for automatic updates of many
 * properties. The application resource list is then typically
 * reserved for specific user customizations, or for distributed
 * customizations, or updates.
 *
 * <p>
 * Typically, the System Resource List is defined in the
 * Defaults Resource. However, it can also be defined by
 * the application defaults, or can be hardwired into the
 * code if desired. Further, the Application Resource List
 * is typically defined by the Application Property File,
 * although it can be defined in any of the previous loaded
 * resources.
 *
 * <p>
 * Also note that the application prefix can be set at any
 * point up to and including the defaults resource. After
 * the defaults resource is loaded, the prefix property is
 * consulted, and if set, is used as the new application
 * prefix. The prefix property is named by adding together
 * the application's package name and the string 'propertyPrefix'.
 * Thus, the prefix property for 'com.ice.jcvs' would be named
 * 'com.ice.jcvs.propertyPrefix', and would typically be set
 * in the defaults resource.
 *
 * <p>
 * Things the application <strong>must do to use this class:
 *
 * <ul>
 * <li> Set the property prefix via UserProperties.setPropertyPrefix()
 * <li> Set the defaults resource via UserProperties.setDefaultsResource()
 * <li> Process any arguments via UserProperties.processOptions()
 * <li> Load all properties.
 * </ul>
 *
 * <p>
 * Here is an example from a typical main():
 * <pre>
 *		UserProperties.setPropertyPrefix( "WebTool." );
 *
 *		UserProperties.setDefaultsResource
 *			( "/com/ice/webtool/defaults.txt" );
 *
 *		// PROCESS PROPERTIES OPTIONS
 *		// The returned args are those not processed.
 *		args = UserProperties.processOptions( args );
 *
 *		// Now app should process remaining arguments...
 *
 *		// LOAD PROPERTIES 
 *		UserProperties.loadProperties( "com.ice.webtool", null );
 * </pre>
 *
 * <p>
 * Properties are accessed via the getProperty() methods, which
 * provide versions for String, int, double, and boolean values.
 * Any property is looked for as follows:
 *
 * <ol>
 * <li> fullname.osname.username
 * <li> fullname.username
 * <li> fullname.osname
 * <li> fullname
 * </ol>
 *
 * Whichever property is found first is returned.
 * The <em>fullname consists of the property name prefixed
 * by the application's property prefix. The username and osname
 * suffixes are used to override general properties by os or by
 * user. These suffixes are printed at startup to System.err.
 * The osname suffix is the osname with spaces replaced by
 * underscores. The username suffix is the user's name with
 * spaces replaced by underscores.
 *
 * <p>
 * If the property name starts with a period
 * (.), then the prefix is not added to get the full name.
 * If the property name ends with a period (.), then none
 * of the suffixes are applied, and only the name is used
 * to search for a property.
 *
 * <p>
 * Thus, while the property name "mainWindow.x" would match
 * a property definition named "prefix.mainWindow.x.user", the
 * property ".mainWindow.x." would match a property with only
 * that name and no prefix or suffix, and the property
 * "mainWindow.x." would match "prefix.mainWindow.x" only
 * and not allow for suffix overrides.
 *
 * <p>
 * The following parameters are understood by processOptions():
 *
 * <ul>
 * <li> -propPrefix prefix     -- sets the property prefix.
 * <li> -propFile filename     -- sets the application property file.
 * <li> -propDefaults resource -- sets the defaults resource name.
 * <li> -propDebug             -- turns on debugging of property handling.
 * <li> -propVerbose           -- turns on verbosity.
 * <li> -propOS osname         -- set the property os suffix.
 * <li> -propUser username     -- set the property user name suffix.
 * </ul>
 *
 * @version $Revision: 1.10 $
 * @author Tim Endres,
 *    <a href="mailto:time@ice.com">time@ice.com.
 */
public abstract class
UserProperties
	{
	private static final String		PREFIX_PROPERTY = "propertyPrefix";
	private static final String		DEFAULTS_RSRC_NAME = ".com.ice.global.defaultsResource.";
	private static final String		GLOBAL_RSRCLIST_NAME = ".com.ice.global.propertyResourceList";
	private static final String		GLOBAL_RSRC_PREFIX = ".com.ice.global.propertyResource.";
	private static final String		APP_RSRCLIST_NAME = ".com.ice.local.propertyResourceList";
	private static final String		APP_RSRC_PREFIX = ".com.ice.local.propertyResource.";
	private static final String		LOCAL_PROPERTY = "global.localPropertyFile";
	private static final String		LOCAL_DEFAULT = null;
	private static final String		DYNAMIC_PROPERTY_VERSION = "1.0";
	private static boolean		debug;
	private static boolean		verbose;
	private static String		osname;
	private static String		userName;
	private static String		userHome;
	private static String		javaHome;
	private static String		prefix;
	private static String		osSuffix;
	private static String		userSuffix;
	private static String		defaultsResource;
	private static String		localPropertyFile;
	/**
	 * This is a Hashtable of Vectors. The table keys are
	 * dynamic property package names. Each Vector contains
	 * the list of property names in the dynamic package.
	 */
	private static Hashtable	dynKeysTable;
	/**
	 * This is a Hashtable of Strings. The table keys are
	 * dynamic property package names. Each String is the
	 * pathname to the property file for the dynamic package.
	 */
	private static Hashtable	dynPathTable;
	/**
	 * Used for temporary working properties.
	 */
	private static Properties	workingProps;
	static
		{
		UserProperties.debug = false;
		UserProperties.verbose = false;
		UserProperties.prefix = null;
		UserProperties.defaultsResource = null;
		UserProperties.localPropertyFile = null;
		UserProperties.dynKeysTable = new Hashtable();
		UserProperties.dynPathTable = new Hashtable();
		UserProperties.workingProps = new Properties();
		UserProperties.osname = System.getProperty( "os.name" );
		UserProperties.userName = System.getProperty( "user.name" );
		UserProperties.userHome = System.getProperty( "user.home" );
		UserProperties.javaHome = System.getProperty( "java.home" );
		UserProperties.osSuffix =
			UserProperties.osname.replace( ' ', '_' );
		UserProperties.userSuffix =
			UserProperties.userName.replace( ' ', '_' );
		}
	static public String
	getOSName()
		{
		return UserProperties.osname;
		}
	static public String
	getUserHome()
		{
		return UserProperties.userHome;
		}
	static public String
	getUserName()
		{
		return UserProperties.userName;
		}
	static public void
	setDebug( boolean debug )
		{
		UserProperties.debug = debug;
		}
	static public void
	setVerbose( boolean verbose )
		{
		UserProperties.verbose = verbose;
		}
	static public void
	setLocalPropertyFile( String fileName )
		{
		UserProperties.localPropertyFile = fileName;
		}
	static public void
	setDefaultsResource( String rsrcName )
		{
		UserProperties.defaultsResource = rsrcName;
		}
	static public void
	setOSSuffix( String suffix )
		{
		UserProperties.osSuffix = suffix;
		}
	static public void
	setUserSuffix( String suffix )
		{
		UserProperties.userSuffix = suffix;
		}
	static public void
	setPropertyPrefix( String prefix )
		{
		if ( prefix.endsWith( "." ) )
			UserProperties.prefix = prefix;
		else
			UserProperties.prefix = prefix + ".";
		}
	static public String
	getPropertyPrefix()
		{
		return UserProperties.prefix;
		}
	static public String
	getLineSeparator()
		{
		return System.getProperty( "line.separator", "\n" );
		}
	static public Font
	getFont( String name, Font defaultFont )
		{
		return
			Font.getFont
				( UserProperties.prefixedPropertyName( name ),
					defaultFont );
		}
	static public Color
	getColor( String name, Color defaultColor )
		{
		return
			Color.getColor
				( UserProperties.prefixedPropertyName( name ),
					defaultColor );
		}
	static public String
	prefixedPropertyName( String name )
		{
		return UserProperties.prefix + name;
		}
	public static String
	normalizePropertyName( String name )
		{
		if ( name.startsWith( "." ) )
			return name.substring(1);
		else
			return UserProperties.prefixedPropertyName( name );
		}
	/**
	 * Retrieve a system string property.
	 * Returns a provided default value if the property
	 * is not defined.
	 *
	 * @param name The name of the property to retrieve.
	 * @param defval A default string value.
	 * @return The string value of the named property.
	 */
	static private String
	getOverridableProperty( String name, String defval )
		{
		String		value = null;
		String		overName = null;
		String		fullName = null;
		fullName = UserProperties.normalizePropertyName( name );
		if ( fullName.endsWith( "." ) )
			{
			fullName = fullName.substring( 0, fullName.length() - 1 );
			value = System.getProperty( fullName, defval );
			if ( UserProperties.debug )
				System.err.println
					( "UserProperties.getOverridableProperty: "
						+ fullName + " = '" + value + "'" );
			return value;
			}
		if ( UserProperties.osSuffix != null
				&& UserProperties.userSuffix != null )
			{
			overName =
				fullName + "." + UserProperties.osSuffix
				 + "." + UserProperties.userSuffix;
			value = System.getProperty( overName, null );
			if ( UserProperties.debug )
				System.err.println
					( "UserProperties.getOverridableProperty: "
						+ overName + " = '" + value + "'" );
			if ( value != null )
				return value;
			}
		if ( UserProperties.userSuffix != null )
			{
			overName = fullName + "." + UserProperties.userSuffix;
			value = System.getProperty( overName, null );
			if ( UserProperties.debug )
				System.err.println
					( "UserProperties.getOverridableProperty: "
						+ overName + " = '" + value + "'" );
			if ( value != null )
				return value;
			}
		if ( UserProperties.osSuffix != null )
			{
			overName = fullName + "." + UserProperties.osSuffix;
			value = System.getProperty( overName, null );
			if ( UserProperties.debug )
				System.err.println
					( "UserProperties.getOverridableProperty: "
						+ overName + " = '" + value + "'" );
			if ( value != null )
				return value;
			}
		if ( value == null )
			{
			value = System.getProperty( fullName, null );
			if ( UserProperties.debug )
				System.err.println
					( "UserProperties.getOverridableProperty: "
						+ fullName + " = '" + value + "'" );
			}
		if ( value == null )
			{
			value = defval;
			if ( UserProperties.debug )
				System.err.println
					( "UserProperties.getOverridableProperty: "
						+ name + " defaulted to '" + value + "'" );
			}
		return value;
		}
	/**
	 * Retrieve a system string property.
	 * Returns a provided default value if the property
	 * is not defined.
	 *
	 * @param name The name of the property to retrieve.
	 * @param defval A default string value.
	 * @return The string value of the named property.
	 */
	static public String
	getProperty( String name, String defval )
		{
		String result =
			UserProperties.getOverridableProperty
				( name, defval );
		return result;
		}
	/**
	 * Retrieve a system integer property.
	 * Returns a provided default value if the property
	 * is not defined.
	 *
	 * @param name The name of the property to retrieve.
	 * @param defval A default integer value.
	 * @return The integer value of the named property.
	 */
	static public int
	getProperty( String name, int defval )
		{
		int result = defval;
		String val = UserProperties.getProperty( name, null );
		if ( val != null )
			{
			try { result = Integer.parseInt( val ); }
				catch ( NumberFormatException ex )
					{ result = defval; }
			}
		return result;
		}
	/**
	 * Retrieve a system long property.
	 * Returns a provided default value if the property
	 * is not defined.
	 *
	 * @param name The name of the property to retrieve.
	 * @param defval A default integer value.
	 * @return The integer value of the named property.
	 */
	static public long
	getProperty( String name, long defval )
		{
		long result = defval;
		String val = UserProperties.getProperty( name, null );
		if ( val != null )
			{
			try { result = Long.parseLong( val ); }
				catch ( NumberFormatException ex )
					{ result = defval; }
			}
		return result;
		}
	/**
	 * Retrieve a system double property.
	 * Returns a provided default value if the property
	 * is not defined.
	 *
	 * @param name The name of the property to retrieve.
	 * @param defval A default double value.
	 * @return The double value of the named property.
	 */
	static public double
	getProperty( String name, double defval )
		{
		double result = defval;
		String val = UserProperties.getProperty( name, null );
		if ( val != null )
			{
			try { result = Double.valueOf( val ).doubleValue(); }
				catch ( NumberFormatException ex )
					{ result = defval; }
			}
		return result;
		}
	/**
	 * Retrieve a system boolean property.
	 * Returns a provided default value if the property
	 * is not defined.
	 *
	 * @param name The name of the property to retrieve.
	 * @param defval A default boolean value.
	 * @return The boolean value of the named property.
	 */
	static public boolean
	getProperty( String name, boolean defval )
		{
		boolean result = defval;
		String val = UserProperties.getProperty( name, null );
		if ( val != null )
			{
			if ( val.equalsIgnoreCase( "T" )
					|| val.equalsIgnoreCase( "TRUE" )
					|| val.equalsIgnoreCase( "Y" )
					|| val.equalsIgnoreCase( "YES" ) )
				result = true;
			else if ( val.equalsIgnoreCase( "F" )
					|| val.equalsIgnoreCase( "FALSE" )
					|| val.equalsIgnoreCase( "N" )
					|| val.equalsIgnoreCase( "NO" ) )
				result = false;
			}
		return result;
		}
	/**
	 * Retrieve a system string array property list. String
	 * arrays are represented by colon separated strings.
	 * Returns a provided default value if the property
	 * is not defined.
	 *
	 * @param name The name of the property to retrieve.
	 * @param defval A default boolean value.
	 * @return The string array value of the named property.
	 */
	static public String[]
	getStringArray( String name, String[] defval )
		{
		String[] result = defval;
		String val = UserProperties.getProperty( name, null );
		if ( val != null )
			{
			result = StringUtilities.splitString( val, ":" );
			}
		return result;
		}
	static public Vector
	getStringVector( String name, Vector defval )
		{
		Vector result = defval;
		String[] sa =
			UserProperties.getStringArray
				( name, null );
		if ( sa != null )
			{
			result = new Vector();
			for ( int s = 0 ; s < sa.length ; ++s )
				result.addElement( sa[s] );
			}
		return result;
		}
	/**
	 * Retrieve a system Class constant property.
	 *
	 * @param name The name of the property to retrieve.
	 * @param defval A default integer value.
	 * @return The integer value of the named property.
	 */
	static public int
	getClassConstant( String name, int defval )
		{
		int result = defval;
		String val = UserProperties.getProperty( name, null );
		if ( val != null )
			{
			int index = val.lastIndexOf( "." );
			if ( index > 0 )
				{
				try {
					String className = val.substring( 0, index );
					String constName = val.substring( index + 1);
					Class cls = Class.forName( className );
					Field fld = cls.getField( constName );
					result = fld.getInt( null );
					}
				catch ( Exception ex )
					{
					result = defval;
					ICETracer.traceWithStack
						( "Exception getting constant." );
					}
				}
			}
		return result;
		}
	/**
	 * Establishes critical default properties.
	 *
	 * @param props The system properties to add properties into.
	 */
	static public void
	defaultProperties( Properties props )
		{
		props.put( "com.ice.util.UserProperties.revision", "$Revision: 1.10 $" );
		props.put( "copyright", "Copyright (c) by Tim Endres" );
		//
		// Define the following to create a global
		// enterprise-wide defaults resource...
		// e.g.
		//
		// props.put
		//	( UserProperties.DEFAULTS_RSRC_NAME,
		//		"http://www.ice.com/properties/defaults.txt" );
		//
		}
	static public void
	includeProperties( Properties into, Properties from )
		{
		Enumeration enum = from.keys();
		for ( ; enum.hasMoreElements() ; )
			{
			Object key = null;
			try { key = (String)enum.nextElement(); }
				catch ( NoSuchElementException ex )
					{ key = null; }
			
			if ( key != null )
				{
				into.put( key, from.get( key ) );
				}
			}
		}
	static public void
	addDefaultProperties( Properties props, Properties defaultProps )
		{
		UserProperties.includeProperties( props, defaultProps );
		}
	/**
	 * Loads a properties stream into the System properties table.
	 *
	 * @param path The properties data's input stream.
	 * @param props The system properties to add properties into.
	 */
	static private boolean
	loadPropertiesStream( InputStream in, Properties props )
		throws IOException
		{
		props.load( in );
		return true;
		}
	static private void
	doLoadPropertiesFile( String path, Properties props, Properties loaded )
		throws IOException
		{
		FileInputStream	in;
		boolean			result = true;
		try { in = new FileInputStream( path ); }
		catch ( IOException ex )
			{
			throw new IOException
				( "opening property file '" + path
					+ "' - " + ex.getMessage() );
			}
		try {
			if ( loaded != null )
				{
				UserProperties.loadPropertiesStream( in, loaded );
				UserProperties.includeProperties( props, loaded );
				}
			else
				{
				UserProperties.loadPropertiesStream( in, props );
				}
			}
		catch ( IOException ex )
			{
			throw new IOException
				( "loading property file '" + path
					+ "' - " + ex.getMessage() );
			}
		try { in.close(); }
		catch ( IOException ex )
			{
			throw new IOException
				( "closing property file '" + path
					+ "' - " + ex.getMessage() );
			}
		}
	/**
	 * Loads a named properties file into the System properties table.
	 *
	 * @param path The properties file's pathname.
	 * @param props The system properties to add properties into.
	 * @param loaded If not null, insert properties here before loading.
	 */
	static private boolean
	loadPropertiesFile( String path, Properties props, Properties loaded )
		{
		FileInputStream	in;
		boolean			result = true;
		if ( UserProperties.debug )
			System.err.println
				( "Loading property file '" + path + "'." );
		try {
			UserProperties.doLoadPropertiesFile( path, props, loaded );
			}
		catch ( IOException ex )
			{
			System.err.println
				( "ERROR " + ex.getMessage() );
			result = false;
			}
		if ( result )
			System.err.println
				( "Loaded property file '" + path + "'." );
		return result;
		}
	/**
	 * Loads a named properties file into the System properties table.
	 * This method fails <em>silently,, as we do not care if the
	 * file is there, and it is a feature that the user can remove the
	 * file to <em>reset their settings.
	 *
	 * @param path The properties file's pathname.
	 * @param props The system properties to add properties into.
	 */
	static private void
	loadDynamicProperties( String name, String path )
		{
		Properties	dynProps = new Properties();
		Properties	sysProps = System.getProperties();
		if ( UserProperties.debug )
			System.err.println
				( "Loading  '" + name
					+ "' protperties from '" + path + "'." );
		try {
			UserProperties.doLoadPropertiesFile( path, sysProps, dynProps );
			UserProperties.addDynamicPropertyKeys( name, dynProps );
			System.err.println
				( "Loaded '" + name + "' properties from '" + path + "'." );
			}
		catch ( IOException ex )
			{
			// Silently fail on dynamic property files!
			}
		}
	static private boolean
	loadPropertiesResource( String name, Properties props )
		{
		InputStream	in;
		boolean		result = false;
		if ( UserProperties.debug )
			System.err.println
				( "Load properties resource '" + name + "'" );
		try {
			in = ResourceUtilities.openNamedResource( name );
			UserProperties.loadPropertiesStream( in, props );
			in.close();
			result = true;
			}
		catch ( java.io.IOException ex )
			{
			System.err.println
				( "ERROR loading properties resource '"
					+ name + "' - " + ex.getMessage() );
			}
		return result;
		}
	private static void
	loadPropertyResourceList(
			String listPropName, String rsrcPrefix, Properties props )
		{
		String rsrcListStr = 
			UserProperties.getProperty( listPropName, null );
		if ( rsrcListStr != null )
			{
			String[] rsrcList =
				StringUtilities.splitString( rsrcListStr, ":" );
			
			for ( int rIdx = 0
					; rsrcList != null && rIdx < rsrcList.length
						; ++rIdx )
				{
				String rsrcTag = rsrcPrefix + rsrcList[rIdx];
				String rsrcName =
					UserProperties.getProperty( rsrcTag, null );
				if ( rsrcName != null )
					{
					boolean result =
						UserProperties.loadPropertiesResource
							( rsrcName, props );
					if ( ! result )
						{
						System.err.println
							( "ERROR loading property resource '"
								+ rsrcName + "'" );
						}
					}
				}
			}
		}
	// UNDONE
	// This routine need to use JNDI (?) to get a 'global' property
	// file name (typically on a network mounted volume) to read,
	// which should in turn set the name of the local property file.
	// JNDI should also set some 'critical' properties, such as
	// the important OTA hostnames, service ports, etc.
	
	// REVIEW
	// UNDONE
	// This routine should have a 'filter' that filters out all
	// global properties that do not start with prefix?
	
	/**
	 * Load all related properties for this application.
	 * This class method will look for a global properties
	 * file, loading it if found, then looks for a local
	 * properties file and loads that.
	 */
	static public void
	loadProperties( String packageName, Properties appProps )
		{
		boolean			result;
		File			propFile;
		String			propPath;
		String			propName;
		String			rsrcName;
		if ( UserProperties.debug )
			{
			UserProperties.printContext( System.err );
			}
		Properties sysProps =
			System.getProperties();
		if ( sysProps == null )
			return;
		UserProperties.defaultProperties( sysProps );
		//
		// ---- PROCESS THE DEFAULT PROPERTIES RESOURCE
		//
		rsrcName = UserProperties.defaultsResource;
		if ( rsrcName == null )
			{
			rsrcName =
				UserProperties.getProperty
					( UserProperties.DEFAULTS_RSRC_NAME, null );
			}
		if ( UserProperties.debug )
			System.err.println
				( "Default Properties Resource '" + rsrcName + "'" );
		if ( rsrcName != null )
			{
			result = 
				UserProperties.loadPropertiesResource
					( rsrcName, sysProps );
			System.err.println
				( "Loaded "
					+ ( result ? "the " : "no " )
					+ "default properties." );
			}
		//
		// ---- PROCESS THE APPLICATION DEFAULT PROPERTIES
		//
		if ( appProps != null )
			{
			if ( UserProperties.debug )
				System.err.println
					( "Adding application default properties." );
			UserProperties.addDefaultProperties
				( sysProps, appProps );
			}
		//
		// ---- PROCESS THE PREFIX PROPERTY
		//
		String newPrefix = UserProperties.prefix;
		if ( UserProperties.debug )
			System.err.println
				( "Prefix '" + newPrefix + "'" );
		if ( newPrefix == null )
			{
			UserProperties.getProperty
				( packageName + "."
					+ UserProperties.PREFIX_PROPERTY, null );
			if ( newPrefix != null )
				{
				if ( UserProperties.debug )
					System.err.println
						( "Prefix via property '" + newPrefix + "'" );
				UserProperties.setPropertyPrefix( newPrefix );
				if ( UserProperties.verbose )
					System.err.println
						( "Property prefix set to '" + newPrefix + "'" );
				}
			}
		//
		// ---- PROCESS THE GLOBAL PROPERTIES RESOURCES
		//
		UserProperties.loadPropertyResourceList
			( UserProperties.GLOBAL_RSRCLIST_NAME,
				UserProperties.GLOBAL_RSRC_PREFIX, sysProps );
		//
		// ---- PROCESS THE GLOBAL DYNAMIC PROPERTY REGISTRATIONS
		//
		UserProperties.processDynamicProperties();
		//
		// ---- PROCESS THE LOCAL PROPERTIES FILE
		//
		propPath = UserProperties.localPropertyFile;
		if ( propPath == null )
			{
			propPath =
				UserProperties.getProperty
					( UserProperties.LOCAL_PROPERTY,
						UserProperties.LOCAL_DEFAULT );
			}
		if ( UserProperties.debug )
			System.err.println
				( "Local property file '" + propPath + "'" );
		if ( propPath != null )
			{
			propFile = new File( propPath );
			if ( propFile.exists() )
				{
				result =
					UserProperties.loadPropertiesFile
						( propPath, sysProps, null );
				if ( ! result )
					{
					System.err.println
						( "ERROR loading local property file '"
							+ propPath + "'" );
					}
				}
			}
		//
		// ---- PROCESS THE GLOBAL PROPERTIES RESOURCES
		//
		UserProperties.loadPropertyResourceList
			( UserProperties.APP_RSRCLIST_NAME,
				UserProperties.APP_RSRC_PREFIX, sysProps );
		}
	private static void
	processDynamicProperties()
		{
		//
		// First, register any dynamic property definitions
		// defined by global properties.
		//
		Properties sysProps = System.getProperties();
		String dynPropList =
			sysProps.getProperty( "global.dynamicPropList", null );
		if ( dynPropList != null )
			{
			String[] dynList =
				StringUtilities.splitString( dynPropList, ":" );
			for ( int sIdx = 0 ; sIdx < dynList.length ; ++sIdx )
				{
				String dynName = dynList[sIdx];
				String pathPropName =
					"global.dynamicPropFile." + dynName;
				String dynPath =
					sysProps.getProperty( pathPropName, null );
				if ( dynPath != null )
					{
					if ( dynPath.startsWith( "~" + File.separator ) )
						{
						dynPath =
							sysProps.getProperty( "user.home", "" )
								+ dynPath.substring( 2 );
						}
					UserProperties.registerDynamicProperties
						( dynName, dynPath, new Properties() );
					}
				}
			}
		// Now, we do the actual loading of dynamic properties.
		Enumeration names = UserProperties.dynKeysTable.keys();
		for ( ; names.hasMoreElements() ; )
			{
			String name = (String) names.nextElement();
			String path = (String)
				UserProperties.dynPathTable.get( name );
			UserProperties.loadDynamicProperties( name, path );
			}
		}
	public static void
	registerDynamicProperties( String name, String path, Properties props )
		{
		UserProperties.dynPathTable.put( name, path );
		UserProperties.addDynamicPropertyKeys( name, props );
		}
	private static void
	addDynamicPropertyKeys( String name, Properties dynProps )
		{
		Vector dynKeys = (Vector)
			UserProperties.dynKeysTable.get( name );
		if ( dynKeys == null )
			{
			dynKeys =
				( dynProps == null )
					? new Vector( 0 )
					: new Vector( dynProps.size() );
			UserProperties.dynKeysTable.put( name, dynKeys );
			}
		if ( dynProps != null )
			{
			// Ensure all key names are 
			Enumeration keys = dynProps.keys();
			for ( ; keys.hasMoreElements() ; )
				{
				String keyName = (String)keys.nextElement();
				if ( ! dynKeys.contains( keyName ) )
					dynKeys.addElement( keyName );
				}
			}
		}
	/**
	 * This method expects the property keys to be
	 * <strong>normalized, meaning that they are
	 * the full property name with the prefix added on.
	 */
	private static void
	copyDynamicProperties( String name, Properties props )
		{
		String path = (String) UserProperties.dynPathTable.get( name );
		Vector keys = (Vector) UserProperties.dynKeysTable.get( name );
		if ( keys == null || path == null )
			throw new NoSuchElementException
				( "you have not registered the dynamic property "
					+ "package named '" + name + "'" );
		Properties sysProps = System.getProperties();
		try {
			Enumeration enum = props.keys();
			for ( ; enum.hasMoreElements() ; )
				{
				String key = (String)enum.nextElement();
				if ( key != null )
					{
					String normalKey =
						UserProperties.normalizePropertyName( key );
					sysProps.put( normalKey, props.get( key ) );
					if ( ! keys.contains( normalKey ) )
						keys.addElement( normalKey );
					}
				}
			}
		catch ( NoSuchElementException ex )
			{ }
		}
	public static void
	setDynamicProperties( String name, Properties props )
		{
		UserProperties.copyDynamicProperties( name, props );
		}
	/**
	 * This method expects the property keys to be <strong>not
	 * <em>normalized, meaning that they are the full
	 * property name with the prefix added on.
	 */
	public static void
	setDynamicProperty( String name, String propName, String propValue )
		{
		UserProperties.workingProps.clear();
		UserProperties.workingProps.put( propName, propValue );
		UserProperties.setDynamicProperties
			( name, UserProperties.workingProps );
		}
	/**
	 * This method removes a property from the dynamic properties.
	 */
	public static void
	removeDynamicProperty( String name, String propName )
		{
		String path = (String) UserProperties.dynPathTable.get( name );
		Vector keys = (Vector) UserProperties.dynKeysTable.get( name );
		if ( keys == null || path == null )
			throw new NoSuchElementException
				( "you have not registered the dynamic property "
					+ "package named '" + name + "'" );
		String normalKey =
			UserProperties.normalizePropertyName( propName );
		if ( keys.contains( normalKey ) )
			{
			keys.removeElement( normalKey );
			System.getProperties().remove( normalKey );
			}
		}
	public static void
	saveDynamicProperties( String name )
		throws IOException
		{
		String path = (String) UserProperties.dynPathTable.get( name );
		Vector keys = (Vector) UserProperties.dynKeysTable.get( name );
		if ( keys == null || path == null )
			throw new NoSuchElementException
				( "you have not registered the dynamic property "
					+ "package named '" + name + "'" );
		Properties dynProps = new Properties();
		Properties sysProps = System.getProperties();
		
		int count = keys.size();
		for ( int idx = 0 ; idx < count ; ++idx )
			{
			String pName = (String) keys.elementAt(idx);
			dynProps.put( pName, sysProps.get( pName ) );
			}
		UserProperties.saveDynamicPropFile( name, path, dynProps );
		}
	//
	// UNDONE
	// We should use an intermediate file and move at completion. This
	// would eliminate the file being trashed on an IOException.
	//
	private static void
	saveDynamicPropFile( String name, String path, Properties dynProps )
		throws IOException
		{
		String eol = System.getProperty( "line.separator", "\n" );
		String comment = eol +
			"## --------------------  W A R N I N G  -------------------- " + eol +
			"#  This file is automatically generated." + eol +
			"#  Any changes you make to this file will be overwritten." + eol +
			"## ---------------------------------------------------------" + eol +
			"#";
		FileOutputStream out =
			new FileOutputStream( path );
		dynProps.put(
			"global.dynPropVersion." + name,
			UserProperties.DYNAMIC_PROPERTY_VERSION );
		dynProps.save( out, comment );
		out.close();
		}
	public static void
	printContext( PrintStream out )
		{
		out.println
			( "os.name    = '" + UserProperties.osname + "'" );
		out.println
			( "user.name  = '" + UserProperties.userName + "'" );
		out.println
			( "user.home  = '" + UserProperties.userHome + "'" );
		out.println
			( "java.home  = '" + UserProperties.javaHome + "'" );
		out.println( "" );
		out.println
			( "prefix     = '" + UserProperties.prefix + "'" );
		out.println
			( "osSuffix   = '" + UserProperties.osSuffix + "'" );
		out.println
			( "userSuffix = '" + UserProperties.userSuffix + "'" );
		out.println( "" );
		}
	public static void
	printUsage( PrintStream out )
		{
		out.println
			( "Properties options:" );
		out.println
			( "   -propDebug             -- "
				+ "turns on debugging of property loading" );
		out.println
			( "   -propVerbose           -- "
				+ "turns on verbose messages during loading" );
		out.println
			( "   -propDefaults rsrcName -- "
				+ "sets default properties resource name" );
		out.println
			( "   -propFile path         -- "
				+ "sets application property file path" );
		out.println
			( "   -propOS suffix         -- "
				+ "sets the os suffix" );
		out.println
			( "   -propUser suffix       -- "
				+ "sets the user suffix" );
		out.println
			( "   -propPrefix prefix     -- "
				+ "sets application property prefix" );
		}
	static public String []
	processOptions( String [] args )
		{
		Vector newArgs = new Vector( args.length );
		for ( int iArg = 0 ; iArg < args.length ; ++iArg )
			{
			if ( args[iArg].equals( "-propPrefix" )
						&& (iArg + 1) < args.length )
				{
				UserProperties.setPropertyPrefix( args[++iArg] );
				}
			else if ( args[iArg].equals( "-propFile" )
						&& (iArg + 1) < args.length )
				{
				UserProperties.setLocalPropertyFile( args[++iArg] );
				}
			else if ( args[iArg].equals( "-propDefaults" )
						&& (iArg + 1) < args.length )
				{
				UserProperties.setDefaultsResource( args[++iArg] );
				}
			else if ( args[iArg].equals( "-propDebug" ) )
				{
				UserProperties.setDebug( true );
				}
			else if ( args[iArg].equals( "-propVerbose" ) )
				{
				UserProperties.setVerbose( true );
				}
			else if ( args[iArg].equals( "-propOS" )
						&& (iArg + 1) < args.length )
				{
				UserProperties.setOSSuffix( args[++iArg] );
				}
			else if ( args[iArg].equals( "-propUser" )
						&& (iArg + 1) < args.length )
				{
				UserProperties.setUserSuffix( args[++iArg] );
				}
			else
				{
				newArgs.addElement( args[iArg] );
				}
			}
		String[] result = new String[ newArgs.size() ];
		for ( int i = 0 ; i < newArgs.size() ; ++i )
			result[i] = (String) newArgs.elementAt(i);
		return result;
		}
	}
 | 
| ... this post is sponsored by my books ... | |
         
           #1 New Release!  | 
      
         
           FP Best Seller  | 
  
Copyright 1998-2024 Alvin Alexander, alvinalexander.com
All Rights Reserved.
A percentage of advertising revenue from
pages under the /java/jwarehouse 
URI on this website is
paid back to open source projects.