0001: /*
0002: ** Copyright (c) 1997 by Tim Endres
0003: **
0004: ** This program is free software.
0005: **
0006: ** You may redistribute it and/or modify it under the terms of the GNU
0007: ** General Public License as published by the Free Software Foundation.
0008: ** Version 2 of the license should be included with this distribution in
0009: ** the file LICENSE, as well as License.html. If the license is not
0010: ** included with this distribution, you may find a copy at the FSF web
0011: ** site at 'www.gnu.org' or 'www.fsf.org', or you may write to the
0012: ** Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139 USA.
0013: **
0014: ** THIS SOFTWARE IS PROVIDED AS-IS WITHOUT WARRANTY OF ANY KIND,
0015: ** NOT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY. THE AUTHOR
0016: ** OF THIS SOFTWARE, ASSUMES _NO_ RESPONSIBILITY FOR ANY
0017: ** CONSEQUENCE RESULTING FROM THE USE, MODIFICATION, OR
0018: ** REDISTRIBUTION OF THIS SOFTWARE.
0019: **
0020: */
0021:
0022: package com.ice.util;
0023:
0024: import java.lang.reflect.*;
0025: import java.io.*;
0026: import java.awt.*;
0027: import java.util.*;
0028: import java.net.*;
0029:
0030: /**
0031: * The UserProperties class. This class is used to extend
0032: * the concept of System.getProperty(). This class adds the
0033: * following features:
0034: *
0035: * <ul>
0036: * <li> A hierarchical property definition structure.
0037: * <li> Typed property retrieval with default values.
0038: * <li> Hierarchical overrides allowings properties to
0039: * be overridden on a per user or per host or per host
0040: * and user basis.
0041: * <li> The ability to load from any valid resource, including
0042: * files stored in JAR files, files located via the file system,
0043: * which includes networked file systems, as well as any other
0044: * resource that can be identified via a URL, including web pages,
0045: * FTP-ed files, and more.
0046: * </ul>
0047: *
0048: * <p>
0049: * Here is how it works. We have <em>six</em> levels of
0050: * properties which are loaded based on various settings.
0051: * The levels look like this:
0052: *
0053: * <ol>
0054: * <li> Hardwired defaults.
0055: * <li> Application defined defaults.
0056: * <li> Defaults resource.
0057: * <li> System level resource list.
0058: * <li> Application property file.
0059: * <li> Application resource list.
0060: * </ol>
0061: *
0062: * <p>
0063: * Resource lists are colon (:) separated strings listing
0064: * resource names to be loaded into the properties.
0065: *
0066: * <p>
0067: * In a typical deployment, the developer will place the
0068: * defaults resource in the JAR file containing the application's
0069: * classes. This file will then define the application properties
0070: * file, which will usually be left empty allowing the user to
0071: * place all customizations in this local file. For distributed
0072: * applications, system resources will typically be supplied via
0073: * simple web pages, which allows for automatic updates of many
0074: * properties. The application resource list is then typically
0075: * reserved for specific user customizations, or for distributed
0076: * customizations, or updates.
0077: *
0078: * <p>
0079: * Typically, the System Resource List is defined in the
0080: * Defaults Resource. However, it can also be defined by
0081: * the application defaults, or can be hardwired into the
0082: * code if desired. Further, the Application Resource List
0083: * is typically defined by the Application Property File,
0084: * although it can be defined in any of the previous loaded
0085: * resources.
0086: *
0087: * <p>
0088: * Also note that the application prefix can be set at any
0089: * point up to and including the defaults resource. After
0090: * the defaults resource is loaded, the prefix property is
0091: * consulted, and if set, is used as the new application
0092: * prefix. The prefix property is named by adding together
0093: * the application's package name and the string 'propertyPrefix'.
0094: * Thus, the prefix property for 'com.ice.jcvs' would be named
0095: * 'com.ice.jcvs.propertyPrefix', and would typically be set
0096: * in the defaults resource.
0097: *
0098: * <p>
0099: * Things the application <strong>must</strong> do to use this class:
0100: *
0101: * <ul>
0102: * <li> Set the property prefix via UserProperties.setPropertyPrefix()
0103: * <li> Set the defaults resource via UserProperties.setDefaultsResource()
0104: * <li> Process any arguments via UserProperties.processOptions()
0105: * <li> Load all properties.
0106: * </ul>
0107: *
0108: * <p>
0109: * Here is an example from a typical main():
0110: * <pre>
0111: * UserProperties.setPropertyPrefix( "WebTool." );
0112: *
0113: * UserProperties.setDefaultsResource
0114: * ( "/com/ice/webtool/defaults.txt" );
0115: *
0116: * // PROCESS PROPERTIES OPTIONS
0117: * // The returned args are those not processed.
0118: * args = UserProperties.processOptions( args );
0119: *
0120: * // Now app should process remaining arguments...
0121: *
0122: * // LOAD PROPERTIES
0123: * UserProperties.loadProperties( "com.ice.webtool", null );
0124: * </pre>
0125: *
0126: * <p>
0127: * Properties are accessed via the getProperty() methods, which
0128: * provide versions for String, int, double, and boolean values.
0129: * Any property is looked for as follows:
0130: *
0131: * <ol>
0132: * <li> fullname.osname.username
0133: * <li> fullname.username
0134: * <li> fullname.osname
0135: * <li> fullname
0136: * </ol>
0137: *
0138: * Whichever property is found first is returned.
0139: * The <em>fullname</em> consists of the property name prefixed
0140: * by the application's property prefix. The username and osname
0141: * suffixes are used to override general properties by os or by
0142: * user. These suffixes are printed at startup to System.err.
0143: * The osname suffix is the osname with spaces replaced by
0144: * underscores. The username suffix is the user's name with
0145: * spaces replaced by underscores.
0146: *
0147: * <p>
0148: * If the property name starts with a period
0149: * (.), then the prefix is not added to get the full name.
0150: * If the property name ends with a period (.), then none
0151: * of the suffixes are applied, and only the name is used
0152: * to search for a property.
0153: *
0154: * <p>
0155: * Thus, while the property name "mainWindow.x" would match
0156: * a property definition named "prefix.mainWindow.x.user", the
0157: * property ".mainWindow.x." would match a property with only
0158: * that name and no prefix or suffix, and the property
0159: * "mainWindow.x." would match "prefix.mainWindow.x" only
0160: * and not allow for suffix overrides.
0161: *
0162: * <p>
0163: * The following parameters are understood by processOptions():
0164: *
0165: * <ul>
0166: * <li> -propPrefix prefix -- sets the property prefix.
0167: * <li> -propFile filename -- sets the application property file.
0168: * <li> -propDefaults resource -- sets the defaults resource name.
0169: * <li> -propDebug -- turns on debugging of property handling.
0170: * <li> -propVerbose -- turns on verbosity.
0171: * <li> -propOS osname -- set the property os suffix.
0172: * <li> -propUser username -- set the property user name suffix.
0173: * </ul>
0174: *
0175: * @version $Revision: 1.10 $
0176: * @author Tim Endres,
0177: * <a href="mailto:time@ice.com">time@ice.com</a>.
0178: */
0179:
0180: public abstract class UserProperties {
0181: private static final String PREFIX_PROPERTY = "propertyPrefix";
0182: private static final String DEFAULTS_RSRC_NAME = ".com.ice.global.defaultsResource.";
0183:
0184: private static final String GLOBAL_RSRCLIST_NAME = ".com.ice.global.propertyResourceList";
0185: private static final String GLOBAL_RSRC_PREFIX = ".com.ice.global.propertyResource.";
0186:
0187: private static final String APP_RSRCLIST_NAME = ".com.ice.local.propertyResourceList";
0188: private static final String APP_RSRC_PREFIX = ".com.ice.local.propertyResource.";
0189:
0190: private static final String LOCAL_PROPERTY = "global.localPropertyFile";
0191: private static final String LOCAL_DEFAULT = null;
0192:
0193: private static final String DYNAMIC_PROPERTY_VERSION = "1.0";
0194:
0195: private static boolean debug;
0196: private static boolean verbose;
0197:
0198: private static String osname;
0199: private static String userName;
0200: private static String userHome;
0201: private static String javaHome;
0202:
0203: private static String prefix;
0204:
0205: private static String osSuffix;
0206: private static String userSuffix;
0207:
0208: private static String defaultsResource;
0209: private static String localPropertyFile;
0210:
0211: /**
0212: * This is a Hashtable of Vectors. The table keys are
0213: * dynamic property package names. Each Vector contains
0214: * the list of property names in the dynamic package.
0215: */
0216: private static Hashtable dynKeysTable;
0217:
0218: /**
0219: * This is a Hashtable of Strings. The table keys are
0220: * dynamic property package names. Each String is the
0221: * pathname to the property file for the dynamic package.
0222: */
0223: private static Hashtable dynPathTable;
0224:
0225: /**
0226: * Used for temporary working properties.
0227: */
0228: private static Properties workingProps;
0229:
0230: static {
0231: UserProperties.debug = false;
0232: UserProperties.verbose = false;
0233:
0234: UserProperties.prefix = null;
0235:
0236: UserProperties.defaultsResource = null;
0237: UserProperties.localPropertyFile = null;
0238:
0239: UserProperties.dynKeysTable = new Hashtable();
0240: UserProperties.dynPathTable = new Hashtable();
0241: UserProperties.workingProps = new Properties();
0242:
0243: UserProperties.osname = System.getProperty("os.name");
0244: UserProperties.userName = System.getProperty("user.name");
0245: UserProperties.userHome = System.getProperty("user.home");
0246: UserProperties.javaHome = System.getProperty("java.home");
0247:
0248: UserProperties.osSuffix = UserProperties.osname.replace(' ',
0249: '_');
0250: UserProperties.userSuffix = UserProperties.userName.replace(
0251: ' ', '_');
0252: }
0253:
0254: static public String getOSName() {
0255: return UserProperties.osname;
0256: }
0257:
0258: static public String getUserHome() {
0259: return UserProperties.userHome;
0260: }
0261:
0262: static public String getUserName() {
0263: return UserProperties.userName;
0264: }
0265:
0266: static public void setDebug(boolean debug) {
0267: UserProperties.debug = debug;
0268: }
0269:
0270: static public void setVerbose(boolean verbose) {
0271: UserProperties.verbose = verbose;
0272: }
0273:
0274: static public void setLocalPropertyFile(String fileName) {
0275: UserProperties.localPropertyFile = fileName;
0276: }
0277:
0278: static public void setDefaultsResource(String rsrcName) {
0279: UserProperties.defaultsResource = rsrcName;
0280: }
0281:
0282: static public void setOSSuffix(String suffix) {
0283: UserProperties.osSuffix = suffix;
0284: }
0285:
0286: static public void setUserSuffix(String suffix) {
0287: UserProperties.userSuffix = suffix;
0288: }
0289:
0290: static public void setPropertyPrefix(String prefix) {
0291: if (prefix.endsWith("."))
0292: UserProperties.prefix = prefix;
0293: else
0294: UserProperties.prefix = prefix + ".";
0295: }
0296:
0297: static public String getPropertyPrefix() {
0298: return UserProperties.prefix;
0299: }
0300:
0301: static public String getLineSeparator() {
0302: return System.getProperty("line.separator", "\n");
0303: }
0304:
0305: static public Font getFont(String name, Font defaultFont) {
0306: return Font.getFont(UserProperties.prefixedPropertyName(name),
0307: defaultFont);
0308: }
0309:
0310: static public Color getColor(String name, Color defaultColor) {
0311: return Color
0312: .getColor(UserProperties.prefixedPropertyName(name),
0313: defaultColor);
0314: }
0315:
0316: static public String prefixedPropertyName(String name) {
0317: return UserProperties.prefix + name;
0318: }
0319:
0320: public static String normalizePropertyName(String name) {
0321: if (name.startsWith("."))
0322: return name.substring(1);
0323: else
0324: return UserProperties.prefixedPropertyName(name);
0325: }
0326:
0327: /**
0328: * Retrieve a system string property.
0329: * Returns a provided default value if the property
0330: * is not defined.
0331: *
0332: * @param name The name of the property to retrieve.
0333: * @param defval A default string value.
0334: * @return The string value of the named property.
0335: */
0336:
0337: static private String getOverridableProperty(String name,
0338: String defval) {
0339: String value = null;
0340: String overName = null;
0341: String fullName = null;
0342:
0343: fullName = UserProperties.normalizePropertyName(name);
0344:
0345: if (fullName.endsWith(".")) {
0346: fullName = fullName.substring(0, fullName.length() - 1);
0347: value = System.getProperty(fullName, defval);
0348: if (UserProperties.debug)
0349: System.err
0350: .println("UserProperties.getOverridableProperty: "
0351: + fullName + " = '" + value + "'");
0352: return value;
0353: }
0354:
0355: if (UserProperties.osSuffix != null
0356: && UserProperties.userSuffix != null) {
0357: overName = fullName + "." + UserProperties.osSuffix + "."
0358: + UserProperties.userSuffix;
0359: value = System.getProperty(overName, null);
0360: if (UserProperties.debug)
0361: System.err
0362: .println("UserProperties.getOverridableProperty: "
0363: + overName + " = '" + value + "'");
0364: if (value != null)
0365: return value;
0366: }
0367:
0368: if (UserProperties.userSuffix != null) {
0369: overName = fullName + "." + UserProperties.userSuffix;
0370: value = System.getProperty(overName, null);
0371: if (UserProperties.debug)
0372: System.err
0373: .println("UserProperties.getOverridableProperty: "
0374: + overName + " = '" + value + "'");
0375: if (value != null)
0376: return value;
0377: }
0378:
0379: if (UserProperties.osSuffix != null) {
0380: overName = fullName + "." + UserProperties.osSuffix;
0381: value = System.getProperty(overName, null);
0382: if (UserProperties.debug)
0383: System.err
0384: .println("UserProperties.getOverridableProperty: "
0385: + overName + " = '" + value + "'");
0386: if (value != null)
0387: return value;
0388: }
0389:
0390: if (value == null) {
0391: value = System.getProperty(fullName, null);
0392: if (UserProperties.debug)
0393: System.err
0394: .println("UserProperties.getOverridableProperty: "
0395: + fullName + " = '" + value + "'");
0396: }
0397:
0398: if (value == null) {
0399: value = defval;
0400: if (UserProperties.debug)
0401: System.err
0402: .println("UserProperties.getOverridableProperty: "
0403: + name
0404: + " defaulted to '"
0405: + value
0406: + "'");
0407: }
0408:
0409: return value;
0410: }
0411:
0412: /**
0413: * Retrieve a system string property.
0414: * Returns a provided default value if the property
0415: * is not defined.
0416: *
0417: * @param name The name of the property to retrieve.
0418: * @param defval A default string value.
0419: * @return The string value of the named property.
0420: */
0421:
0422: static public String getProperty(String name, String defval) {
0423: String result = UserProperties.getOverridableProperty(name,
0424: defval);
0425: return result;
0426: }
0427:
0428: /**
0429: * Retrieve a system integer property.
0430: * Returns a provided default value if the property
0431: * is not defined.
0432: *
0433: * @param name The name of the property to retrieve.
0434: * @param defval A default integer value.
0435: * @return The integer value of the named property.
0436: */
0437:
0438: static public int getProperty(String name, int defval) {
0439: int result = defval;
0440:
0441: String val = UserProperties.getProperty(name, null);
0442:
0443: if (val != null) {
0444: try {
0445: result = Integer.parseInt(val);
0446: } catch (NumberFormatException ex) {
0447: result = defval;
0448: }
0449: }
0450:
0451: return result;
0452: }
0453:
0454: /**
0455: * Retrieve a system long property.
0456: * Returns a provided default value if the property
0457: * is not defined.
0458: *
0459: * @param name The name of the property to retrieve.
0460: * @param defval A default integer value.
0461: * @return The integer value of the named property.
0462: */
0463:
0464: static public long getProperty(String name, long defval) {
0465: long result = defval;
0466:
0467: String val = UserProperties.getProperty(name, null);
0468:
0469: if (val != null) {
0470: try {
0471: result = Long.parseLong(val);
0472: } catch (NumberFormatException ex) {
0473: result = defval;
0474: }
0475: }
0476:
0477: return result;
0478: }
0479:
0480: /**
0481: * Retrieve a system double property.
0482: * Returns a provided default value if the property
0483: * is not defined.
0484: *
0485: * @param name The name of the property to retrieve.
0486: * @param defval A default double value.
0487: * @return The double value of the named property.
0488: */
0489:
0490: static public double getProperty(String name, double defval) {
0491: double result = defval;
0492:
0493: String val = UserProperties.getProperty(name, null);
0494:
0495: if (val != null) {
0496: try {
0497: result = Double.valueOf(val).doubleValue();
0498: } catch (NumberFormatException ex) {
0499: result = defval;
0500: }
0501: }
0502:
0503: return result;
0504: }
0505:
0506: /**
0507: * Retrieve a system boolean property.
0508: * Returns a provided default value if the property
0509: * is not defined.
0510: *
0511: * @param name The name of the property to retrieve.
0512: * @param defval A default boolean value.
0513: * @return The boolean value of the named property.
0514: */
0515:
0516: static public boolean getProperty(String name, boolean defval) {
0517: boolean result = defval;
0518:
0519: String val = UserProperties.getProperty(name, null);
0520:
0521: if (val != null) {
0522: if (val.equalsIgnoreCase("T")
0523: || val.equalsIgnoreCase("TRUE")
0524: || val.equalsIgnoreCase("Y")
0525: || val.equalsIgnoreCase("YES"))
0526: result = true;
0527: else if (val.equalsIgnoreCase("F")
0528: || val.equalsIgnoreCase("FALSE")
0529: || val.equalsIgnoreCase("N")
0530: || val.equalsIgnoreCase("NO"))
0531: result = false;
0532: }
0533:
0534: return result;
0535: }
0536:
0537: /**
0538: * Retrieve a system string array property list. String
0539: * arrays are represented by colon separated strings.
0540: * Returns a provided default value if the property
0541: * is not defined.
0542: *
0543: * @param name The name of the property to retrieve.
0544: * @param defval A default boolean value.
0545: * @return The string array value of the named property.
0546: */
0547:
0548: static public String[] getStringArray(String name, String[] defval) {
0549: String[] result = defval;
0550:
0551: String val = UserProperties.getProperty(name, null);
0552:
0553: if (val != null) {
0554: result = StringUtilities.splitString(val, ":");
0555: }
0556:
0557: return result;
0558: }
0559:
0560: static public Vector getStringVector(String name, Vector defval) {
0561: Vector result = defval;
0562:
0563: String[] sa = UserProperties.getStringArray(name, null);
0564:
0565: if (sa != null) {
0566: result = new Vector();
0567: for (int s = 0; s < sa.length; ++s)
0568: result.addElement(sa[s]);
0569: }
0570:
0571: return result;
0572: }
0573:
0574: /**
0575: * Retrieve a system Class constant property.
0576: *
0577: * @param name The name of the property to retrieve.
0578: * @param defval A default integer value.
0579: * @return The integer value of the named property.
0580: */
0581:
0582: static public int getClassConstant(String name, int defval) {
0583: int result = defval;
0584:
0585: String val = UserProperties.getProperty(name, null);
0586:
0587: if (val != null) {
0588: int index = val.lastIndexOf(".");
0589:
0590: if (index > 0) {
0591: try {
0592: String className = val.substring(0, index);
0593: String constName = val.substring(index + 1);
0594: Class cls = Class.forName(className);
0595: Field fld = cls.getField(constName);
0596: result = fld.getInt(null);
0597: } catch (Exception ex) {
0598: result = defval;
0599: ICETracer
0600: .traceWithStack("Exception getting constant.");
0601: }
0602: }
0603: }
0604:
0605: return result;
0606: }
0607:
0608: /**
0609: * Establishes critical default properties.
0610: *
0611: * @param props The system properties to add properties into.
0612: */
0613:
0614: static public void defaultProperties(Properties props) {
0615: props.put("com.ice.util.UserProperties.revision",
0616: "$Revision: 1.10 $");
0617: props.put("copyright", "Copyright (c) by Tim Endres");
0618:
0619: //
0620: // Define the following to create a global
0621: // enterprise-wide defaults resource...
0622: // e.g.
0623: //
0624: // props.put
0625: // ( UserProperties.DEFAULTS_RSRC_NAME,
0626: // "http://www.ice.com/properties/defaults.txt" );
0627: //
0628: }
0629:
0630: static public void includeProperties(Properties into,
0631: Properties from) {
0632: Enumeration numer = from.keys();
0633:
0634: for (; numer.hasMoreElements();) {
0635: Object key = null;
0636:
0637: try {
0638: key = (String) numer.nextElement();
0639: } catch (NoSuchElementException ex) {
0640: key = null;
0641: }
0642:
0643: if (key != null) {
0644: into.put(key, from.get(key));
0645: }
0646: }
0647: }
0648:
0649: static public void addDefaultProperties(Properties props,
0650: Properties defaultProps) {
0651: UserProperties.includeProperties(props, defaultProps);
0652: }
0653:
0654: /**
0655: * Loads a properties stream into the System properties table.
0656: *
0657: * @param path The properties data's input stream.
0658: * @param props The system properties to add properties into.
0659: */
0660:
0661: static private boolean loadPropertiesStream(InputStream in,
0662: Properties props) throws IOException {
0663: props.load(in);
0664: return true;
0665: }
0666:
0667: static private void doLoadPropertiesFile(String path,
0668: Properties props, Properties loaded) throws IOException {
0669: FileInputStream in;
0670: boolean result = true;
0671:
0672: try {
0673: in = new FileInputStream(path);
0674: } catch (IOException ex) {
0675: throw new IOException("opening property file '" + path
0676: + "' - " + ex.getMessage());
0677: }
0678:
0679: try {
0680: if (loaded != null) {
0681: UserProperties.loadPropertiesStream(in, loaded);
0682: UserProperties.includeProperties(props, loaded);
0683: } else {
0684: UserProperties.loadPropertiesStream(in, props);
0685: }
0686: } catch (IOException ex) {
0687: throw new IOException("loading property file '" + path
0688: + "' - " + ex.getMessage());
0689: }
0690:
0691: try {
0692: in.close();
0693: } catch (IOException ex) {
0694: throw new IOException("closing property file '" + path
0695: + "' - " + ex.getMessage());
0696: }
0697: }
0698:
0699: /**
0700: * Loads a named properties file into the System properties table.
0701: *
0702: * @param path The properties file's pathname.
0703: * @param props The system properties to add properties into.
0704: * @param loaded If not null, insert properties here before loading.
0705: */
0706:
0707: static private boolean loadPropertiesFile(String path,
0708: Properties props, Properties loaded) {
0709: FileInputStream in;
0710: boolean result = true;
0711:
0712: if (UserProperties.debug)
0713: System.err.println("Loading property file '" + path + "'.");
0714:
0715: try {
0716: UserProperties.doLoadPropertiesFile(path, props, loaded);
0717: } catch (IOException ex) {
0718: System.err.println("ERROR " + ex.getMessage());
0719: result = false;
0720: }
0721:
0722: if (result)
0723: System.err.println("Loaded property file '" + path + "'.");
0724:
0725: return result;
0726: }
0727:
0728: /**
0729: * Loads a named properties file into the System properties table.
0730: * This method fails <em>silently,</em>, as we do not care if the
0731: * file is there, and it is a feature that the user can remove the
0732: * file to <em>reset</em> their settings.
0733: *
0734: * @param path The properties file's pathname.
0735: * @param props The system properties to add properties into.
0736: */
0737:
0738: static private void loadDynamicProperties(String name, String path) {
0739: Properties dynProps = new Properties();
0740: Properties sysProps = System.getProperties();
0741:
0742: if (UserProperties.debug)
0743: System.err.println("Loading '" + name
0744: + "' protperties from '" + path + "'.");
0745:
0746: try {
0747: UserProperties.doLoadPropertiesFile(path, sysProps,
0748: dynProps);
0749: UserProperties.addDynamicPropertyKeys(name, dynProps);
0750: System.err.println("Loaded '" + name
0751: + "' properties from '" + path + "'.");
0752: } catch (IOException ex) {
0753: // Silently fail on dynamic property files!
0754: }
0755: }
0756:
0757: static private boolean loadPropertiesResource(String name,
0758: Properties props) {
0759: InputStream in;
0760: boolean result = false;
0761:
0762: if (UserProperties.debug)
0763: System.err.println("Load properties resource '" + name
0764: + "'");
0765:
0766: try {
0767: in = ResourceUtilities.openNamedResource(name);
0768: UserProperties.loadPropertiesStream(in, props);
0769: in.close();
0770: result = true;
0771: } catch (java.io.IOException ex) {
0772: System.err.println("ERROR loading properties resource '"
0773: + name + "' - " + ex.getMessage());
0774: }
0775:
0776: return result;
0777: }
0778:
0779: private static void loadPropertyResourceList(String listPropName,
0780: String rsrcPrefix, Properties props) {
0781: String rsrcListStr = UserProperties.getProperty(listPropName,
0782: null);
0783:
0784: if (rsrcListStr != null) {
0785: String[] rsrcList = StringUtilities.splitString(
0786: rsrcListStr, ":");
0787:
0788: for (int rIdx = 0; rsrcList != null
0789: && rIdx < rsrcList.length; ++rIdx) {
0790: String rsrcTag = rsrcPrefix + rsrcList[rIdx];
0791:
0792: String rsrcName = UserProperties.getProperty(rsrcTag,
0793: null);
0794:
0795: if (rsrcName != null) {
0796: boolean result = UserProperties
0797: .loadPropertiesResource(rsrcName, props);
0798:
0799: if (!result) {
0800: System.err
0801: .println("ERROR loading property resource '"
0802: + rsrcName + "'");
0803: }
0804: }
0805: }
0806: }
0807: }
0808:
0809: // UNDONE
0810: // This routine need to use JNDI (?) to get a 'global' property
0811: // file name (typically on a network mounted volume) to read,
0812: // which should in turn set the name of the local property file.
0813: // JNDI should also set some 'critical' properties, such as
0814: // the important OTA hostnames, service ports, etc.
0815:
0816: // REVIEW
0817: // UNDONE
0818: // This routine should have a 'filter' that filters out all
0819: // global properties that do not start with prefix?
0820:
0821: /**
0822: * Load all related properties for this application.
0823: * This class method will look for a global properties
0824: * file, loading it if found, then looks for a local
0825: * properties file and loads that.
0826: */
0827:
0828: static public void loadProperties(String packageName,
0829: Properties appProps) {
0830: boolean result;
0831: File propFile;
0832: String propPath;
0833: String propName;
0834: String rsrcName;
0835:
0836: if (UserProperties.debug) {
0837: UserProperties.printContext(System.err);
0838: }
0839:
0840: Properties sysProps = System.getProperties();
0841:
0842: if (sysProps == null)
0843: return;
0844:
0845: UserProperties.defaultProperties(sysProps);
0846:
0847: //
0848: // ---- PROCESS THE DEFAULT PROPERTIES RESOURCE
0849: //
0850: rsrcName = UserProperties.defaultsResource;
0851: if (rsrcName == null) {
0852: rsrcName = UserProperties.getProperty(
0853: UserProperties.DEFAULTS_RSRC_NAME, null);
0854: }
0855:
0856: if (UserProperties.debug)
0857: System.err.println("Default Properties Resource '"
0858: + rsrcName + "'");
0859:
0860: if (rsrcName != null) {
0861: result = UserProperties.loadPropertiesResource(rsrcName,
0862: sysProps);
0863:
0864: System.err.println("Loaded " + (result ? "the " : "no ")
0865: + "default properties.");
0866: }
0867:
0868: //
0869: // ---- PROCESS THE APPLICATION DEFAULT PROPERTIES
0870: //
0871: if (appProps != null) {
0872: if (UserProperties.debug)
0873: System.err
0874: .println("Adding application default properties.");
0875:
0876: UserProperties.addDefaultProperties(sysProps, appProps);
0877: }
0878:
0879: //
0880: // ---- PROCESS THE PREFIX PROPERTY
0881: //
0882: String newPrefix = UserProperties.prefix;
0883: if (UserProperties.debug)
0884: System.err.println("Prefix '" + newPrefix + "'");
0885:
0886: if (newPrefix == null) {
0887: UserProperties.getProperty(packageName + "."
0888: + UserProperties.PREFIX_PROPERTY, null);
0889:
0890: if (newPrefix != null) {
0891: if (UserProperties.debug)
0892: System.err.println("Prefix via property '"
0893: + newPrefix + "'");
0894:
0895: UserProperties.setPropertyPrefix(newPrefix);
0896: if (UserProperties.verbose)
0897: System.err.println("Property prefix set to '"
0898: + newPrefix + "'");
0899: }
0900: }
0901:
0902: //
0903: // ---- PROCESS THE GLOBAL PROPERTIES RESOURCES
0904: //
0905: UserProperties.loadPropertyResourceList(
0906: UserProperties.GLOBAL_RSRCLIST_NAME,
0907: UserProperties.GLOBAL_RSRC_PREFIX, sysProps);
0908:
0909: //
0910: // ---- PROCESS THE GLOBAL DYNAMIC PROPERTY REGISTRATIONS
0911: //
0912: UserProperties.processDynamicProperties();
0913:
0914: //
0915: // ---- PROCESS THE LOCAL PROPERTIES FILE
0916: //
0917: propPath = UserProperties.localPropertyFile;
0918: if (propPath == null) {
0919: propPath = UserProperties.getProperty(
0920: UserProperties.LOCAL_PROPERTY,
0921: UserProperties.LOCAL_DEFAULT);
0922: }
0923:
0924: if (UserProperties.debug)
0925: System.err
0926: .println("Local property file '" + propPath + "'");
0927:
0928: if (propPath != null) {
0929: propFile = new File(propPath);
0930: if (propFile.exists()) {
0931: result = UserProperties.loadPropertiesFile(propPath,
0932: sysProps, null);
0933:
0934: if (!result) {
0935: System.err
0936: .println("ERROR loading local property file '"
0937: + propPath + "'");
0938: }
0939: }
0940: }
0941:
0942: //
0943: // ---- PROCESS THE GLOBAL PROPERTIES RESOURCES
0944: //
0945: UserProperties.loadPropertyResourceList(
0946: UserProperties.APP_RSRCLIST_NAME,
0947: UserProperties.APP_RSRC_PREFIX, sysProps);
0948: }
0949:
0950: private static void processDynamicProperties() {
0951: //
0952: // First, register any dynamic property definitions
0953: // defined by global properties.
0954: //
0955: Properties sysProps = System.getProperties();
0956:
0957: String dynPropList = sysProps.getProperty(
0958: "global.dynamicPropList", null);
0959:
0960: if (dynPropList != null) {
0961: String[] dynList = StringUtilities.splitString(dynPropList,
0962: ":");
0963:
0964: for (int sIdx = 0; sIdx < dynList.length; ++sIdx) {
0965: String dynName = dynList[sIdx];
0966:
0967: String pathPropName = "global.dynamicPropFile."
0968: + dynName;
0969:
0970: String dynPath = sysProps.getProperty(pathPropName,
0971: null);
0972:
0973: if (dynPath != null) {
0974: if (dynPath.startsWith("~" + File.separator)) {
0975: dynPath = sysProps.getProperty("user.home", "")
0976: + dynPath.substring(2);
0977: }
0978:
0979: UserProperties.registerDynamicProperties(dynName,
0980: dynPath, new Properties());
0981: }
0982: }
0983: }
0984:
0985: // Now, we do the actual loading of dynamic properties.
0986: Enumeration names = UserProperties.dynKeysTable.keys();
0987: for (; names.hasMoreElements();) {
0988: String name = (String) names.nextElement();
0989:
0990: String path = (String) UserProperties.dynPathTable
0991: .get(name);
0992:
0993: UserProperties.loadDynamicProperties(name, path);
0994: }
0995: }
0996:
0997: public static void registerDynamicProperties(String name,
0998: String path, Properties props) {
0999: UserProperties.dynPathTable.put(name, path);
1000: UserProperties.addDynamicPropertyKeys(name, props);
1001: }
1002:
1003: private static void addDynamicPropertyKeys(String name,
1004: Properties dynProps) {
1005: Vector dynKeys = (Vector) UserProperties.dynKeysTable.get(name);
1006:
1007: if (dynKeys == null) {
1008: dynKeys = (dynProps == null) ? new Vector(0) : new Vector(
1009: dynProps.size());
1010:
1011: UserProperties.dynKeysTable.put(name, dynKeys);
1012: }
1013:
1014: if (dynProps != null) {
1015: // Ensure all key names are
1016: Enumeration keys = dynProps.keys();
1017: for (; keys.hasMoreElements();) {
1018: String keyName = (String) keys.nextElement();
1019: if (!dynKeys.contains(keyName))
1020: dynKeys.addElement(keyName);
1021: }
1022: }
1023: }
1024:
1025: /**
1026: * This method expects the property keys to be
1027: * <strong>normalized</strong>, meaning that they are
1028: * the full property name with the prefix added on.
1029: */
1030:
1031: private static void copyDynamicProperties(String name,
1032: Properties props) {
1033: String path = (String) UserProperties.dynPathTable.get(name);
1034: Vector keys = (Vector) UserProperties.dynKeysTable.get(name);
1035:
1036: if (keys == null || path == null)
1037: throw new NoSuchElementException(
1038: "you have not registered the dynamic property "
1039: + "package named '" + name + "'");
1040:
1041: Properties sysProps = System.getProperties();
1042:
1043: try {
1044: Enumeration numer = props.keys();
1045: for (; numer.hasMoreElements();) {
1046: String key = (String) numer.nextElement();
1047: if (key != null) {
1048: String normalKey = UserProperties
1049: .normalizePropertyName(key);
1050:
1051: sysProps.put(normalKey, props.get(key));
1052:
1053: if (!keys.contains(normalKey))
1054: keys.addElement(normalKey);
1055: }
1056: }
1057: } catch (NoSuchElementException ex) {
1058: }
1059: }
1060:
1061: public static void setDynamicProperties(String name,
1062: Properties props) {
1063: UserProperties.copyDynamicProperties(name, props);
1064: }
1065:
1066: /**
1067: * This method expects the property keys to be <strong>not</strong>
1068: * <em>normalized</em>, meaning that they are the full
1069: * property name with the prefix added on.
1070: */
1071:
1072: public static void setDynamicProperty(String name, String propName,
1073: String propValue) {
1074: UserProperties.workingProps.clear();
1075: UserProperties.workingProps.put(propName, propValue);
1076: UserProperties.setDynamicProperties(name,
1077: UserProperties.workingProps);
1078: }
1079:
1080: /**
1081: * This method removes a property from the dynamic properties.
1082: */
1083:
1084: public static void removeDynamicProperty(String name,
1085: String propName) {
1086: String path = (String) UserProperties.dynPathTable.get(name);
1087: Vector keys = (Vector) UserProperties.dynKeysTable.get(name);
1088:
1089: if (keys == null || path == null)
1090: throw new NoSuchElementException(
1091: "you have not registered the dynamic property "
1092: + "package named '" + name + "'");
1093:
1094: String normalKey = UserProperties
1095: .normalizePropertyName(propName);
1096:
1097: if (keys.contains(normalKey)) {
1098: keys.removeElement(normalKey);
1099: System.getProperties().remove(normalKey);
1100: }
1101: }
1102:
1103: public static void saveDynamicProperties(String name)
1104: throws IOException {
1105: String path = (String) UserProperties.dynPathTable.get(name);
1106: Vector keys = (Vector) UserProperties.dynKeysTable.get(name);
1107:
1108: if (keys == null || path == null)
1109: throw new NoSuchElementException(
1110: "you have not registered the dynamic property "
1111: + "package named '" + name + "'");
1112:
1113: Properties dynProps = new Properties();
1114: Properties sysProps = System.getProperties();
1115:
1116: int count = keys.size();
1117: for (int idx = 0; idx < count; ++idx) {
1118: String pName = (String) keys.elementAt(idx);
1119: dynProps.put(pName, sysProps.get(pName));
1120: }
1121:
1122: UserProperties.saveDynamicPropFile(name, path, dynProps);
1123: }
1124:
1125: //
1126: // UNDONE
1127: // We should use an intermediate file and move at completion. This
1128: // would eliminate the file being trashed on an IOException.
1129: //
1130: private static void saveDynamicPropFile(String name, String path,
1131: Properties dynProps) throws IOException {
1132: String eol = System.getProperty("line.separator", "\n");
1133: String comment = eol
1134: + "## -------------------- W A R N I N G -------------------- "
1135: + eol
1136: + "# This file is automatically generated."
1137: + eol
1138: + "# Any changes you make to this file will be overwritten."
1139: + eol
1140: + "## ---------------------------------------------------------"
1141: + eol + "#";
1142:
1143: FileOutputStream out = new FileOutputStream(path);
1144:
1145: dynProps.put("global.dynPropVersion." + name,
1146: UserProperties.DYNAMIC_PROPERTY_VERSION);
1147:
1148: dynProps.save(out, comment);
1149:
1150: out.close();
1151: }
1152:
1153: public static void printContext(PrintStream out) {
1154: out.println("os.name = '" + UserProperties.osname + "'");
1155: out.println("user.name = '" + UserProperties.userName + "'");
1156: out.println("user.home = '" + UserProperties.userHome + "'");
1157: out.println("java.home = '" + UserProperties.javaHome + "'");
1158:
1159: out.println("");
1160:
1161: out.println("prefix = '" + UserProperties.prefix + "'");
1162: out.println("osSuffix = '" + UserProperties.osSuffix + "'");
1163: out.println("userSuffix = '" + UserProperties.userSuffix + "'");
1164:
1165: out.println("");
1166: }
1167:
1168: public static void printUsage(PrintStream out) {
1169: out.println("Properties options:");
1170:
1171: out.println(" -propDebug -- "
1172: + "turns on debugging of property loading");
1173: out.println(" -propVerbose -- "
1174: + "turns on verbose messages during loading");
1175:
1176: out.println(" -propDefaults rsrcName -- "
1177: + "sets default properties resource name");
1178: out.println(" -propFile path -- "
1179: + "sets application property file path");
1180:
1181: out.println(" -propOS suffix -- "
1182: + "sets the os suffix");
1183: out.println(" -propUser suffix -- "
1184: + "sets the user suffix");
1185: out.println(" -propPrefix prefix -- "
1186: + "sets application property prefix");
1187: }
1188:
1189: static public String[] processOptions(String[] args) {
1190: Vector newArgs = new Vector(args.length);
1191:
1192: for (int iArg = 0; iArg < args.length; ++iArg) {
1193: if (args[iArg].equals("-propPrefix")
1194: && (iArg + 1) < args.length) {
1195: UserProperties.setPropertyPrefix(args[++iArg]);
1196: } else if (args[iArg].equals("-propFile")
1197: && (iArg + 1) < args.length) {
1198: UserProperties.setLocalPropertyFile(args[++iArg]);
1199: } else if (args[iArg].equals("-propDefaults")
1200: && (iArg + 1) < args.length) {
1201: UserProperties.setDefaultsResource(args[++iArg]);
1202: } else if (args[iArg].equals("-propDebug")) {
1203: UserProperties.setDebug(true);
1204: } else if (args[iArg].equals("-propVerbose")) {
1205: UserProperties.setVerbose(true);
1206: } else if (args[iArg].equals("-propOS")
1207: && (iArg + 1) < args.length) {
1208: UserProperties.setOSSuffix(args[++iArg]);
1209: } else if (args[iArg].equals("-propUser")
1210: && (iArg + 1) < args.length) {
1211: UserProperties.setUserSuffix(args[++iArg]);
1212: } else {
1213: newArgs.addElement(args[iArg]);
1214: }
1215: }
1216:
1217: String[] result = new String[newArgs.size()];
1218: for (int i = 0; i < newArgs.size(); ++i)
1219: result[i] = (String) newArgs.elementAt(i);
1220:
1221: return result;
1222: }
1223:
1224: }
|