package com.digi.config.util; import java.awt.Color; import java.awt.Font; import java.io.*; import java.util.*; import java.net.*; import java.applet.*; /** *

ConfigSettings reads and parses the content of a user defined * configuration file and provides a set of query functions to retrieve * these configuration information. *

The default configuration file pathname is config.ini in the * classpath. *

Environment Configuration File Definitions

*
    *
  1. Comment *
     *      Syntax :    //
     * 
    * *
  2. Section Name *
     *      Syntax :    [section_name]
     * 
    * *
  3. Tag *
     *      Syntax :    tag  = value
     * 
    * *
  4. Tag Substitution *
     *      Syntax :    $([[section_name]:]tag)
     * 
    * *
* This is also an observable and sends notifications to the registered observers, * passing a modified settings object. */ public class ConfigSettings extends Observable { /** * Environment configuration file name used in the current application. */ private String configFileName=System.getProperty("ConfigFileName","config.ini"); private static ConfigSettings theInstance=null; // The only instance /** * Constant to use when dealing with configuration settings in the System * category. * NOTE: this actually points to the System Properties. */ public final static String CATEGORY_SYSTEM="System"; /** * Constant to use when dealing with general configuration settings */ public final static String CATEGORY_CFG="General"; /* This maintains a hashtable of vector2 objects */ private Hashtable ivSectionTable=new Hashtable(); /* Vector holding all the default value finders */ private Vector ivDefValFunction=new Vector(); private ModifiedSettings ivModSettings=null; // Holds the modified settings sent out to listeners /** Ini file is first searched in class path . If not found, it is created in the path whereever the tool is run. Look for the class com.digi.util.ConfigSettings. Get its full path name and create the file in the directory where com directory exists*/ private String iniFileName=null; //===================================================================== // Static methods //===================================================================== /** * This method returns the only instance of the configsettings object *

* @return ConfigSettings */ public static ConfigSettings getInstance() { if (theInstance==null) { theInstance=new ConfigSettings(); } return theInstance; } //===================================================================== // Instance Methods //===================================================================== /** * Constructor *

*/ private ConfigSettings() { // Load the ini file if it is available try { load_profile(); } catch (Exception e) { System.out.println("Error loading configuration profile: "); e.printStackTrace(); } addDefaultValueFinderListener(new DefaultConfigSettings()); } /** * This method adds a defaultvalue finder listener. *

* @param def the default value finder class */ public void addDefaultValueFinderListener(DefaultValueFinder def) { ivDefValFunction.addElement(def); } /** * Returns environment configuration file pathname. * @return the configuration file name */ public String getConfigFileName() { return configFileName; } /** * Returns value of specified ProfileProperty as a string. Returns null if section/tag is not found. * * @param section Section name in the profile * @param tag Tag name * @return Replacement text of the input tag */ public String getProfileProperty(String section, String tag) { return getProfileProperty(section,tag,null,null); } /** * Returns value of specified ProfileProperty as a string. Returns null if section/tag is not found. * Caller specifies both a primary and fallback set of section/tag pairs. The search order is: *

    *
  1. primary section/tag ini entry
  2. *
  3. fallback section/tag ini entry
  4. *
  5. primary section/tag defaultValueFinder
  6. *
  7. fallback section/tag defaultValueFinder
  8. *
* * @param section First section name in the profile to look for * @param tag First tag name to look for * @param fallbackSection Second section name in the profile to look for * @param fallbackTag Second tag name to look for * @return Replacement text of the input tag */ public String getProfileProperty(String section, String tag, String fallbackSection, String fallbackTag) { String retStr=null; // Try looking up the primary section/tag item in the ini file if (section.equals(CATEGORY_SYSTEM)) { // If this is the SYSTEM section, pull it from the System properties retStr = System.getProperty(tag); } else { // otherwise look it up in the table Vector2 v=(Vector2)ivSectionTable.get(section); if (v!=null) { retStr=(String)v.get(tag); } } if ((retStr==null) && (fallbackSection!=null)) { // Didn't find the primary section/tag, look for the fallback in the ini file if (fallbackSection.equals(CATEGORY_SYSTEM)) { // If this is the SYSTEM section, pull it from the System properties retStr = System.getProperty(fallbackTag); } else { // otherwise look it up in the table Vector2 v=(Vector2)ivSectionTable.get(fallbackSection); if (v!=null) { retStr=(String)v.get(fallbackTag); } } } if (retStr==null) { // didn't find primary or fallback section/tag in ini file... check default value finders for primary section/tag Enumeration e=ivDefValFunction.elements(); while ((retStr==null)&&(e.hasMoreElements())) { retStr=((DefaultValueFinder)e.nextElement()).getDefaultValue(section, tag); } } if ((retStr==null) && (fallbackSection!=null)) { // last chance, check default value finders for fallback section/tag Enumeration e=ivDefValFunction.elements(); while ((retStr==null)&&(e.hasMoreElements())) { retStr=((DefaultValueFinder)e.nextElement()).getDefaultValue(fallbackSection, fallbackTag); } } return retStr; } /** * Returns the Profile Property as a String. Returns value of defRetVal if section/tag not found. * * @param section Section name in the profile * @param tag Tag name * @param defRetVal Default return String if none is found. * @return Replacement text of the input tag */ public String getProfileProperty(String section, String tag, String defRetVal) { String retValue=getProfileProperty(section, tag); return(retValue!=null?retValue:defRetVal); } /** * Returns the Profile Property as a boolean. Returns value of false if section/tag not found. * * @param section Section name in the profile * @param tag Tag name * @return boolean value of property */ public boolean getBooleanProfileProperty(String section, String tag) { return getBooleanProfileProperty(section,tag,null,null); } /** * Returns the Profile Property as a boolean. Returns value of false if section/tag not found. * Caller specifies both a primary and fallback set of section/tag pairs. The search order is: *
    *
  1. primary section/tag ini entry
  2. *
  3. fallback section/tag ini entry
  4. *
  5. primary section/tag defaultValueFinder
  6. *
  7. fallback section/tag defaultValueFinder
  8. *
* * @param section First section name in the profile to look for * @param tag First tag name to look for * @param fallbackSection Second section name in the profile to look for * @param fallbackTag Second tag name to look for * @return boolean value of property */ public boolean getBooleanProfileProperty(String section, String tag, String fallbackSection, String fallbackTag) { return Boolean.valueOf(getProfileProperty(section,tag,fallbackSection,fallbackTag)).booleanValue(); } /** * Returns the Profile property as integer. Returns value of -1 if section/tag not found. * * @param section Section of the property * @param tag Key of the property * @return integer value */ public int getIntegerProfileProperty(String section, String tag) { return getIntegerProfileProperty(section,tag,null,null); } /** * Returns the Profile property as integer. Returns value of -1 if section/tag not found. * Caller specifies both a primary and fallback set of section/tag pairs. The search order is: *
    *
  1. primary section/tag ini entry
  2. *
  3. fallback section/tag ini entry
  4. *
  5. primary section/tag defaultValueFinder
  6. *
  7. fallback section/tag defaultValueFinder
  8. *
* * @param section First section name in the profile to look for * @param tag First tag name to look for * @param fallbackSection Second section name in the profile to look for * @param fallbackTag Second tag name to look for * @return integer value */ public int getIntegerProfileProperty(String section, String tag, String fallbackSection, String fallbackTag) { try { return Integer.parseInt(getProfileProperty(section,tag,fallbackSection,fallbackTag)); } catch (NumberFormatException e) { return -1; } } /** * Returns the Profile property as a color. Returns null if the section/tag is not found. * @param section First section name in the profile to look for * @param tag First tag name to look for * @return Color Color */ public Color getColorProfileProperty(String section, String tag) { return getColorProfileProperty(section,tag,null,null); } /** * Returns the Profile property as a color. Returns null if the section/tag is not found. * Caller specifies both a primary and fallback set of section/tag pairs. The search order is: *
    *
  1. primary section/tag ini entry
  2. *
  3. fallback section/tag ini entry
  4. *
  5. primary section/tag defaultValueFinder
  6. *
  7. fallback section/tag defaultValueFinder
  8. *
* * @param section First section name in the profile to look for * @param tag First tag name to look for * @param fallbackSection Second section name in the profile to look for * @param fallbackTag Second tag name to look for * @return Color Color */ public Color getColorProfileProperty(String section, String tag, String fallbackSection, String fallbackTag) { String clr=getProfileProperty(section,tag,fallbackSection,fallbackTag); Color c=null; int r =0; int g =0; int b =0; int a =255; if (clr!=null) { StringTokenizer st=new StringTokenizer(clr, ", ", false); try { r=Integer.parseInt(st.nextToken()); g=Integer.parseInt(st.nextToken()); b=Integer.parseInt(st.nextToken()); if (st.hasMoreTokens()) { a=Integer.parseInt(st.nextToken()); } c=new Color(r, g, b, a); } catch (Exception e) { SystemLog.debug("Error loading color '"+tag+"' from profile",e); } } return c; } /** * Returns the Profile property as a font. Returns null if the section/tag is not found. * * @param section Section name in the profile * @param tag Tag name * @return font */ public Font getFontProfileProperty(String section, String tag) { return getFontProfileProperty(section,tag,null,null); } /** * Returns the Profile property as a color. Returns null if the section/tag is not found. * Caller specifies both a primary and fallback set of section/tag pairs. The search order is: *
    *
  1. primary section/tag ini entry
  2. *
  3. fallback section/tag ini entry
  4. *
  5. primary section/tag defaultValueFinder
  6. *
  7. fallback section/tag defaultValueFinder
  8. *
* * @param section First section name in the profile to look for * @param tag First tag name to look for * @param fallbackSection Second section name in the profile to look for * @param fallbackTag Second tag name to look for * @return font */ public Font getFontProfileProperty(String section, String tag, String fallbackSection, String fallbackTag) { String options=getProfileProperty(section,tag,fallbackSection,fallbackTag); Font f=null; String name; int size=16; int style=0; if (options!=null) { StringTokenizer st=new StringTokenizer(options, ", ", false); try { name=st.nextToken(); if (st.hasMoreTokens()) { size=Integer.parseInt(st.nextToken()); } if (st.hasMoreTokens()) { style=Integer.parseInt(st.nextToken()); } f = new Font(name, style, size); } catch (Exception e) { SystemLog.debug("Error loading font '"+tag+"' from profile",e); } } return f; } /** * Sets value of the specified tag. This method * returns null if the tag is not found. * @param section Section name in the profile * @param tag Tag name * @param value Value to set */ public synchronized void setProfileProperty(String section, String tag, String value) { // If this is the SYSTEM section, push it out to the System properties if (section.equals(CATEGORY_SYSTEM)) { System.setProperty(tag, value); return; } // Otherwise put the update into the table String preValue=getProfileProperty(section, tag); String retStr =null; Vector2 v =(Vector2)ivSectionTable.get(section); if (v==null) { //create vector v=new Vector2(); ivSectionTable.put(section, v); } else { //To avoid duplicate remove the already existing one int keyIdx=v.keyIndexOf(tag); if (keyIdx!=-1) { v.removeElementAt(keyIdx); } } v.put(tag, value); if ((preValue==null)||(!preValue.equals(value))) // Value has changed { if (ivModSettings==null) { ivModSettings=new ModifiedSettings(); } Hashtable modSection=(Hashtable)ivModSettings.getSections(); Hashtable sectionHt=(Hashtable)modSection.get(section); if (sectionHt==null) { sectionHt=new Hashtable(); modSection.put(section, sectionHt); } sectionHt.put(tag, value); } } /** * Sets value of the specified tag. This method * returns null if the tag is not found. * @param section Section name in the profile * @param tag Tag name * @param value Value to set */ public void setBooleanProfileProperty(String section, String tag, boolean value) { Boolean b=new Boolean(value); setProfileProperty(section, tag, b.toString()); } /** * Sets value of the specified tag. This method * returns null if the tag is not found. * @param section Section name in the profile * @param tag Tag name * @param c Color to set */ public void setColorProfileProperty(String section, String tag, Color c) { StringWriter sw=new StringWriter(); PrintWriter pw=new PrintWriter(sw); pw.print(c.getRed()+"," +c.getGreen()+"," +c.getBlue()); setProfileProperty(section, tag, sw.getBuffer().toString()); } /** * Sets value of the specified tag. This method * returns null if the tag is not found. * @param section Section name in the profile * @param tag Tag name * @param value Value to set */ public void setIntegerProfileProperty(String section, String tag, int value) { Integer b=new Integer(value); setProfileProperty(section, tag, b.toString()); } /** * This method saves the config settings to the file *

*/ public synchronized void save_profile() throws IOException { // If ini file has not been created yet, determine where it should go if (iniFileName==null) { iniFileName=PathLocater.getDefaultSaveFileName(configFileName); } //System.out.println("Saving config settings to '"+iniFileName+"'"); PathLocater.createPathToFile(iniFileName); PrintWriter pw=new PrintWriter(new FileWriter(iniFileName), true); list(pw); setChanged(); if (ivModSettings!=null) // If there were no changes ivModSettings will be null { notifyObservers(ivModSettings); ivModSettings.getSections().clear(); } } /** * List properties, for debugging. * @param out Output Stream */ public void list(PrintWriter out) { //Time Stamp out.println("// " +new Date()); //Print keys without section first Vector2 noSection=(Vector2)ivSectionTable.get(""); if (noSection!=null) { int cnt=noSection.size(); for (int idx=0; idx1&&txt.charAt(0)=='"' && txt.charAt(txtLength-1)=='"') { // white spaces within the '"' delimiter are significant // **** DON'T trim. **** txt=txt.substring(1, txtLength-1); } // Put key into Vector2 table - make sure no duplicate key in Vector2 int keyIdx=curSection.keyIndexOf(key); if (keyIdx!=-1) { curSection.removeElementAt(keyIdx); } curSection.put(key, txt); } } catch (IOException io) { throw io; } try { s.close(); } catch (IOException io) { throw io; } } //============================================================= // Static helper methods //============================================================= /** * Gets boolean value of the specified key in the specified category. This method * returns false if the value associated with the category/key is not actually a * boolean value. *

* The logic will first look for the value by searching the specified category in the * ConfigSettings for the specified key. If either the category or the key cannot be found, * the logic will perform the same search in the DefaultConfigSettings. If a value is still * not found, a MissingResourceException is thrown. * * @param category is the name of the setting category to search * @param key is the name of the key to the value within the category * @return true if and only if the value associated with * the category/key is true. * * @throws IllegalArgumentException if the category or key values are either not * provided or are empty Strings. * @throws MissingResourceException if a value for the specified category/key is * not found. */ public static boolean getBoolean(String category, String key) { return getInstance().getBooleanProfileProperty(category, key); } /** * Gets boolean value of the specified key in the specified category. This method * returns false if the value associated with the category/key is not actually a * boolean value. *

* The logic will first look for the value by searching the specified category in the * ConfigSettings for the specified key. If either the category or the key cannot be found, * the logic will perform the same search in the DefaultConfigSettings. If a value is still * not found, a MissingResourceException is thrown. * * @param category is the name of the setting category to search * @param key is the name of the key to the value within the category * @return true if and only if the value associated with * the category/key is true. * * @throws IllegalArgumentException if the category or key values are either not * provided or are empty Strings. * @throws MissingResourceException if a value for the specified category/key is * not found. */ public static boolean getBoolean(String category, String key, String fallbackSection, String fallbackTag) { return getInstance().getBooleanProfileProperty(category, key, fallbackSection, fallbackTag); } /** * Sets the boolean value of the specified key in the specified category. If the key * already exists in this category, the provided value will replace the existing value. * * @param category is the name of the setting category into which the key/value pair is * inserted. If it does not exist, it will be created. * @param key is the name of the key to the value within the category * @param value is the boolean value to be inserted into the ConfigSettings * * @throws IllegalArgumentException if the category or key values are either not * provided or are empty Strings. */ public static void setBoolean(String category, String key, boolean value) { getInstance().setBooleanProfileProperty(category, key, value); } /** * Gets integer value of the specified key in the specified category. *

* The logic will first look for the value by searching the specified category in the * ConfigSettings for the specified key. If either the category or the key cannot be found, * the logic will perform the same search in the DefaultConfigSettings. If a value is still * not found, false is returned. * * @param category is the name of the setting category to search * @param key is the name of the key to the value within the category * @return true if and only if the value associated with * the category/key is true. * * @throws IllegalArgumentException if the category or key values are either not * provided or are empty Strings. * @throws MissingResourceException if a value for the specified category/key is * not found. * @throws NumberFormatException if the requested value is not actually an integer. */ public static int getInteger(String category, String key) { return getInstance().getIntegerProfileProperty(category, key); } /** * Gets integer value of the specified key in the specified category. *

* The logic will first look for the value by searching the specified category in the * ConfigSettings for the specified key. If either the category or the key cannot be found, * the logic will perform the same search in the DefaultConfigSettings. If a value is still * not found, false is returned. * * @param category is the name of the setting category to search * @param key is the name of the key to the value within the category * @return true if and only if the value associated with * the category/key is true. * * @throws IllegalArgumentException if the category or key values are either not * provided or are empty Strings. * @throws MissingResourceException if a value for the specified category/key is * not found. * @throws NumberFormatException if the requested value is not actually an integer. */ public static int getInteger(String category, String key, String fallbackSection, String fallbackTag) { return getInstance().getIntegerProfileProperty(category, key, fallbackSection, fallbackTag); } /** * Sets the integer value of the specified key in the specified category. If the key * already exists in this category, the provided value will replace the existing value. * * @param category is the name of the setting category into which the key/value pair is * inserted. If it does not exist, it will be created. * @param key is the name of the key to the value within the category * @param value is the integer value to be inserted into the ConfigSettings * * @throws IllegalArgumentException if the category or key values are either not * provided or are empty Strings. */ public static void setInteger(String category, String key, int value) { getInstance().setIntegerProfileProperty(category, key, value); } /** * Gets font value of the specified tag. This method * returns null if the tag is not found. * @param section Section name in the profile * @param tag Tag name * @return font */ public static Font getFont(String section, String tag) { return getInstance().getFontProfileProperty(section,tag,null,null); } /** * Gets font value of the specified tag. This method * returns null if the tag is not found. * @param section Section name in the profile * @param tag Tag name * @return font */ public static Font getFont(String section, String tag, String fallbackSection, String fallbackTag) { return getInstance().getFontProfileProperty(section,tag,fallbackSection,fallbackTag); } /** * Gets color value of the specified key in the specified category. This method * returns false if the value associated with the category/key is not actually a * color value. *

* The logic will first look for the value by searching the specified category in the * ConfigSettings for the specified key. If either the category or the key cannot be found, * the logic will perform the same search in the DefaultConfigSettings. If a value is still * not found, a MissingResourceException is thrown. * * @param category is the name of the setting category to search * @param key is the name of the key to the value within the category * @return true if and only if the value associated with * the category/key is true. * * @throws IllegalArgumentException if the category or key values are either not * provided or are empty Strings. * @throws MissingResourceException if a value for the specified category/key is * not found. */ public static Color getColor(String category, String key) { return getInstance().getColorProfileProperty(category, key); } /** * Gets color value of the specified key in the specified category. This method * returns false if the value associated with the category/key is not actually a * color value. *

* The logic will first look for the value by searching the specified category in the * ConfigSettings for the specified key. If either the category or the key cannot be found, * the logic will perform the same search in the DefaultConfigSettings. If a value is still * not found, a MissingResourceException is thrown. * * @param category is the name of the setting category to search * @param key is the name of the key to the value within the category * @return true if and only if the value associated with * the category/key is true. * * @throws IllegalArgumentException if the category or key values are either not * provided or are empty Strings. * @throws MissingResourceException if a value for the specified category/key is * not found. */ public static Color getColor(String category, String key, String fallbackSection, String fallbackTag) { return getInstance().getColorProfileProperty(category, key, fallbackSection, fallbackTag); } /** * Sets the color value of the specified key in the specified category. If the key * already exists in this category, the provided value will replace the existing value. * * @param category is the name of the setting category into which the key/value pair is * inserted. If it does not exist, it will be created. * @param key is the name of the key to the value within the category * @param value is the color value to be inserted into the ConfigSettings * * @throws IllegalArgumentException if the category or key values are either not * provided or are empty Strings. */ public static void setColor(String category, String key, Color value) { getInstance().setColorProfileProperty(category, key, value); } /** * Gets value of the specified key within the specified category in the ConfigSettings. * If a value is not found, the same search will be repeated in the DefaultConfigSettings. * If a value is still not found, a MissingResourceException will be thrown. An exception * to this search order occurs when the category = 'System'. In that case, only the System * properties are searched. * * NOTE: the category and key parameters are case sensitive. * * @param category is the name of the setting category to search * @param key is the name of the key to the value within the category * @return the String associated with the specified category/key. * * @throws IllegalArgumentException if the category or key values are either not * provided or are empty Strings. * @throws MissingResourceException if a value for the specified category/key is * not found. */ public static String getProperty(String category, String key) { if ((category==null)||(key==null)) { throw new IllegalArgumentException("Category and Key are MANDATORY parameters"); } String retValue=getInstance().getProfileProperty(category, key); if (retValue==null) { throw new MissingResourceException("Value not found for category: " + category+" and key: " +key, category, key); } return retValue; } //end getProperty /** * Gets value of the specified key within the specified category in the ConfigSettings. * If a value is not found, the same search will be repeated in the DefaultConfigSettings. * If a value is still not found, a MissingResourceException will be thrown. An exception * to this search order occurs when the category = 'System'. In that case, only the System * properties are searched. * * NOTE: the category and key parameters are case sensitive. * * @param category is the name of the setting category to search * @param key is the name of the key to the value within the category * @return the String associated with the specified category/key. * * @throws IllegalArgumentException if the category or key values are either not * provided or are empty Strings. * @throws MissingResourceException if a value for the specified category/key is * not found. */ public static String getProperty(String category, String key, String fallbackSection, String fallbackTag) { if ((category==null)||(key==null)) { throw new IllegalArgumentException("Category and Key are MANDATORY parameters"); } String retValue=getInstance().getProfileProperty(category, key, fallbackSection, fallbackTag); if (retValue==null) { throw new MissingResourceException("Value not found for category: " + category+" and key: " +key, category, key); } return retValue; } //end getProperty /** * Gets value of the specified key within the specified category in the ConfigSettings. * If a value is not found, the same search will be repeated in the DefaultConfigSettings. * If a value is still not found, the provided dftRetValue will be returned. An exception * to this search order occurs when the category = 'System'. In that case, only the System * properties are searched (but the provided dftRetValue is still returned if a value is * not found in the System Properties). * * NOTE: the category and key parameters are case sensitive. It is suggested that callers * always use the constants provided by this class when specifying the category. * * @param category is the name of the setting category to search * @param key is the name of the key to the value within the category * @param dftRetValue is the default return String if a value for the specified category/key * is not found in the configSettings. * @return the String associated with the specified category/key. If one is not * found in the configSettings, the provided default value will be returned. * * @throws IllegalArgumentException if the category or key values are either not * provided or are empty Strings. * @throws MissingResourceException if a value for the specified category/key is * not found. */ public static String getProperty(String category, String key, String dftRetValue) { String retValue=null; try { retValue=getProperty(category, key); } catch (MissingResourceException mre) { retValue=dftRetValue; } return retValue; } /** * Sets the provided value under the specified key within the specified category in the ConfigSettings. * If the key/value already exists in the specified category, the value will be replaced. If the * specified category does not already exist, it will be created. * * NOTE: the category and key parameters are case sensitive. It is strongly suggested that the * constants for the categories provided by this class are used when specifying the category parameter. * * NOTE: values placed in the System or CFG categories * will NOT be persisted between restarts of this application. * * @param category is the name of the setting category to search * @param key is the name of the key to the value within the category * @param value is the String value to be placed in the ConfigSettings * * @throws IllegalArgumentException if the category or key values are * empty Strings. * @throws NullPointerException if the category, key or value are null. */ public static void setProperty(String category, String key, String value) { if ((category.length()==0)||(key.length()==0)) { throw new IllegalArgumentException("Category and Key are MANDATORY parameters and must not be empty Strings"); } getInstance().setProfileProperty(category, key, value); } //end setProperty /** * This method saves the config settings to the ini file *

*/ public static void save() throws IOException { getInstance().save_profile(); } }