Package simtools.ui

Source Code of simtools.ui.UserProperties$Info

/* ==============================================
* Simtools : The tools library used in JSynoptic
* ==============================================
*
* Project Info:  http://jsynoptic.sourceforge.net/index.html
*
* This library is free software; you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Foundation;
* either version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with this
* library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307, USA.
*
* (C) Copyright 1999-2003, by :
*     Corporate:
*         Astrium SAS
*         EADS CRC
*     Individual:
*         Claude Cazenave
*     Nicolas Brodu
*
*
* $Id: UserProperties.java,v 1.9 2006/11/23 17:10:34 ogor Exp $
*
* Changes
* -------
* 25-Sep-2003 : Initial public release (NB);
*
*/

package simtools.ui;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Properties;
import java.util.StringTokenizer;

/**
* This class returns a user preferences as saved at previous use of the tool
*
* @author N. Brodu
* @author C. Cazenave
* @author A. Reglat
*/
public class UserProperties extends Properties {

  /**
   * The file to read and write properties to
   */
  protected File _file;

  /**
   * The product name to apply properties to
   */
  protected String _productName;

  /**
   * List of informations to write sorted properties in file.
   */
  protected LinkedList _infoList = new LinkedList();

    /**
     * The list of MasterProperties
     */
    private ArrayList masterPropertiesList;

  /**
   * The information class
   */
  protected static class Info {
    public static final String IMPORT_FILE_PREFIX = "@import";
        public static int KEY = 0;
    public static int COMMENT = 1;
    public static int EMPTY_LINE = 2;
        public static int MASTER_LINE = 3;

    // The info type. This is one of the 3 previous static values.
    public final int _type;
    // If KEY type, _value may be the key value
    // If COMMENT type, _value may be the comment itself
    // If EMPTY_LINE, _value may be null
    public final String _value;

    public Info(int type, String value) {
      _type = type;
      _value = value;
    }
  }

  /**
   * Creates user properties without reading values from the file.
   * If system property <code>productName + ".home"</code> is set then look
   * for properties file into this directory, else merely use the user home
   * directory.
   * Unlike the <code>Properties</code> class, there is no property list for
   * default values.
   *
   * @param productName the product name
   */
  public UserProperties(String productName) {
    this(productName, false);
  }

  /**
   * Creates user properties without reading values from the file.
   * If system property <code>productName + ".home"</code> is set then look
   * for properties file into this directory, else merely use the user home
   * directory.
   * Unlike the <code>Properties</code> class, there is no property list for
   * default values.
   *
   * @param productName the product name
   * @param useSystemDefaultValues true to use system properties defined
   * with -Dproperty=value at launch time. These default values are used only
   * when a property is not defined in user property file.
   */
  public UserProperties(String productName, boolean useSystemDefaultValues) {
    super(useSystemDefaultValues ? System.getProperties() : null);

    String home =
      System.getProperty(
        productName + ".home",
        System.getProperty("user.home", ""));

    _file = new File(home, "." + productName);
    // look in .productname/config which is now the default
    // But keep compatibility with the .productname file
    if ((!_file.exists()) && _file.mkdirs()) {
        _file = new File(_file, "config");
    }
    else if (_file.isDirectory()) _file = new File(_file, "config");
    _productName = productName;
  }

    /**
     * Contructor UserProperties
     * <br><b>Summary:</b><br>
     * The constructor of the class UserProperties.
     * Creates user properties without reading values from the file.
     * If system property <code>productName + ".home"</code> is set then look
     * for properties file into this directory, else merely use the user home
     * directory.
     * Unlike the <code>Properties</code> class, there is no property list for
     * default values.
     * @param propertyFile The file that contains the properties to be loaded.
     */
    public UserProperties(File propertyFile) {
        super(null);
        _file = propertyFile;
        _productName = propertyFile.getName();
    }

  /**
   * @returns the file to read and write properties to
   */
  public File getFile() {
    return _file;
  }

  protected boolean _propertiesLoadedFromFile = false;

  /**
   * Reads properties from the file defined in the constructor.
   * In case of error, default values will be used
   */
  public void read() {
    try {
      FileInputStream fis = new FileInputStream(_file);
      load(fis);
      _propertiesLoadedFromFile = true;

    } catch (FileNotFoundException fnfe) {
      // default values will be used
    } catch (IOException ioe) {
      // default values will be used
    }
  }

  /**
   * Writes properties to the file defined in the constructor.
   * In case of error, nothing happens
   */
  public void write() {
    try {
      FileOutputStream fos = new FileOutputStream(_file);
      store(fos, null);

    } catch (FileNotFoundException fnfe) {
      // nothing happens
    } catch (IOException ioe) {
      // nothing happens
    }
  }

  /**
   * Reads properties from the file defined in the constructor.
   */
  public void read2() throws FileNotFoundException, IOException {
    FileInputStream fis = new FileInputStream(_file);
    load(fis);
    _propertiesLoadedFromFile = true;
  }

    /**
     * Method <b>getProperty</b>
     * <br><b>Summary:</b><br>
     * Use this method to get a property.
     * Use the override order:
     * MasterFiles < local property < System property.
     * Means that: if a property is defined in local and in on of a master property file, the local one will be returned.
     * If defined in local and in system property, system property will be returned.
     * If the property cannot be found, return null.
     * Parameters:
     * @param key               The key of the property to find, or null if not found.
     */
    public String getProperty(String key){
        //The result of the method.
        String result = null;
        //We will parse the master properties, looking for the searched properties.
        if (masterPropertiesList!=null){
          for(Iterator masterFilesIterator = masterPropertiesList.iterator(); masterFilesIterator.hasNext();){
            UserProperties masterFile =  (UserProperties) masterFilesIterator.next();
            String masterResult = masterFile.getProperty(key);
            if(masterResult != null){
              result = masterResult;
            }
          }
        }
        //Then, try to read it from property file, using super method.
        String localResult = super.getProperty(key);
        //If non null, override the previously found one.
        if(localResult != null){
            result = localResult;
        }
        //And then, read from system properties, to permits properties overrides throught command line.
        String systemProperty = System.getProperty(key);
        //If non null, override the previously found one.
        if(systemProperty != null){
            result = systemProperty;
        }
        //return the result
        return result;
    }


  /**
   * Writes properties to the file defined in the constructor.
   */
  public void write2() throws FileNotFoundException, IOException {
    FileOutputStream fos = new FileOutputStream(_file);
    store(fos, null);
  }

  /**
   * Gets a string
   *
   * @param  name  property name
   * @param  value the default value
   * @return the value
   */
  public String getString(String name, String value) {
    return getProperty(name, value);
  }
  /**
   * Sets a string
   *
   * @param name  property name
   * @param value its new value
   */
  public void setString(String name, String value) {
    setProperty(name, value);
  }

  /**
   * Gets a boolean
   *
   * @param name property name
   * @param value the default value
   * @return the value
   */
  public boolean getBoolean(String name, boolean value) {
    String res=getProperty(name, value ? "TRUE" : "FALSE");
    return res.toUpperCase().equals("TRUE");
  }

  /**
   * Sets a boolean
   *
   * @param name property name
   * @param value the default value
   */
  public void setBoolean(String name, boolean value) {
    setProperty(name, value ? "TRUE" : "FALSE");
  }

  /**
   * Gets a double
   *
   * @param  name  property name
   * @param  value the default value
   * @return the value
   */
  public double getDouble(String name, double value) {
    String res = getProperty(name);
    if (res == null) {
      return value;
    }
    try {
      double rd = Double.parseDouble(res);
      return rd;
    } catch (NumberFormatException nfe) {
      return value;
    }
  }

  /**
   * Gets a float
   *
   * @param  name  property name
   * @param  value the default value
   * @return the value
   */
  public float getFloat(String name, float value) {
    return (float) getDouble(name, value);
  }

  /**
   * Sets a double
   *
   * @param name  property name
   * @param value its new value
   */
  public void setDouble(String name, double value) {
    setProperty(name, String.valueOf(value));
  }

  /**
   * Sets a float
   *
   * @param name  property name
   * @param value its new value
   */
  public void setFloat(String name, float value) {
    setProperty(name, String.valueOf(value));
  }

  /**
   * Gets a long
   *
   * @param  name  property name
   * @param  value the default value
   * @return the value
   */
  public long getLong(String name, long value) {
    String res = getProperty(name);
    if (res == null) {
      return value;
    }
    try {
      return Long.decode(res).longValue();
    } catch (NumberFormatException nfe) {
      return value;
    }
  }

  /**
   * Gets an int
   *
   * @param  name  property name
   * @param  value the default value
   * @return the value
   */
  public int getInt(String name, int value) {
    return (int) getLong(name, value);
  }

  /**
   * Gets a short
   *
   * @param  name  property name
   * @param  value the default value
   * @return the value
   */
  public short getShort(String name, short value) {
    return (short) getLong(name, value);
  }

  /**
   * Gets a byte
   *
   * @param  name  property name
   * @param  value the default value
   * @return the value
   */
  public byte getByte(String name, byte value) {
    return (byte) getLong(name, value);
  }

  /**
   * Sets a long
   *
   * @param name  property name
   * @param value its new value
   */
  public void setLong(String name, long value) {
    setProperty(name, String.valueOf(value));
  }

  /**
   * Sets an int
   *
   * @param name  property name
   * @param value its new value
   */
  public void setInt(String name, int value) {
    setProperty(name, String.valueOf(value));
  }

  /**
   * Sets a short
   *
   * @param name  property name
   * @param value its new value
   */
  public void setShort(String name, short value) {
    setProperty(name, String.valueOf(value));
  }

  /**
   * Sets a byte
   *
   * @param name  property name
   * @param value its new value
   */
  public void setByte(String name, byte value) {
    setProperty(name, String.valueOf(value));
  }

  /**
   * Calls the <tt>Hashtable</tt> method <code>put</code>. Provided for
   * parallelism with the <tt>getProperty</tt> method. Enforces use of
   * strings for property keys and values. The value returned is the
   * result of the <tt>Hashtable</tt> call to <code>put</code>.
   *
   * @param key the key to be placed into this property list.
   * @param value the value corresponding to <tt>key</tt>.
   * @return     the previous value of the specified key in this property
   *             list, or <code>null</code> if it did not have one.
   */
  public synchronized Object setProperty(String key, String value) {
        Object result = null;
        String localValue = super.getProperty(key);
        if(localValue != null){
            //If local value was previously defined. Set it.
            result = put(key, value);
        }else{
            //Else check in the Master files.
            String masterProperties = null;
            //We will parse the master properties, looking for the searched properties.
           
            if (masterPropertiesList!=null){
              Iterator masterFilesIterator = masterPropertiesList.iterator();
              while( masterFilesIterator.hasNext() && masterProperties == null){
                UserProperties masterFile =  (UserProperties) masterFilesIterator.next();
                masterProperties = masterFile.getProperty(key);
              }
            }
            //Now check the result.
            if(masterProperties != null && masterProperties.equals(value)){
                //We want to set the same properties/value as the master one.
                //Do nothing, master properties will be retrieved with getProperty.
                //Use master property as result.
                result = masterProperties;
            }else if(masterProperties == null || (masterProperties != null && !masterProperties.equals(value))){
                //This is a newly added property or
                //We have locally override the master value.
                // set it as local.
                _infoList.add(new Info(Info.KEY, key));
                result = put(key, value);
            }
        }
        return result;
  }

  /**
   * Add a comment at the end of the properties sequence. Do nothing if
   * properties file already exists.
   * The comment will appear prefixed by '#' in the properties file.
   *
   * @param comment the comment line
   */
  public void addComment(String comment) {
    if (_propertiesLoadedFromFile) return;

    comment = comment.trim();
    if (comment.length() == 0) {
      comment = "#";
    } else if (comment.charAt(0) != '#') {
      comment = "# " + comment;
    }
    _infoList.add(new Info(Info.COMMENT, comment));
  }

  /**
   * Add a new empty line at the end of the properties sequence. Do nothing if
   * properties file already exists.
   * Useful to separate group of properties.
   */
  public void addNewLine() {
    if (_propertiesLoadedFromFile) return;

    _infoList.add(new Info(Info.EMPTY_LINE, null));
  }

  protected static final String keyValueSeparators = "=: \t\r\n\f";

  protected static final String strictKeyValueSeparators = "=:";

  protected static final String specialSaveChars = "=: \t\r\n\f#!";

  protected static final String whiteSpaceChars = " \t\r\n\f";

  /**
   * Reads a property sequence from the input stream.
   * The  stream is assumed to be using the ISO 8859-1 character encoding.
   * Comments, property definitions with value, and empty line are recorded,
   * keeping them in order.
   *
   * @param      inStream     the input stream.
   * @exception  IOException  if an error occurred when reading from the
   *                          input stream.
   */
  public synchronized void load(InputStream inStream) throws IOException {
    _infoList = new LinkedList();
        masterPropertiesList = new ArrayList();
    BufferedReader in =
      new BufferedReader(new InputStreamReader(inStream, "8859_1"));

    while (true) {
      // Get next line
      String line = in.readLine();
      if (line == null)
        return;

      if (line.trim().length() == 0) {
        // Detect an empty line
        _infoList.add(new Info(Info.EMPTY_LINE, null));
      }
      if (line.length() > 0) {
        // Continue lines that end in slashes if they are not comments
        char firstChar = line.charAt(0);
        if ((firstChar == '#') || (firstChar == '!')) {
          // This is a comment line
          _infoList.add(new Info(Info.COMMENT, line));

        } else if(line.startsWith(Info.IMPORT_FILE_PREFIX)){
            //This is a master line.
                    //retrieve master fileName.
                    StringTokenizer stk = new StringTokenizer(line);
                    if(stk.countTokens() > 1){
                        //The first token is the Info.IMPORT_FILE_PREFIX, throw it away.
                        stk.nextToken();
                        //The next one should be the master file.
                        String masterFile = stk.nextToken();
                        //Create a UserProperties on it.
                        UserProperties up = new UserProperties(new File(masterFile));
                        try{
                            up.read2();
                            //Add it to master list.
                            masterPropertiesList.add(up);
                        }catch(IOException e){
                            System.err.println("Failed to read imported file:"+masterFile);
                        }
                        //Add it to info list, to keep write it in property file.
                        _infoList.add(new Info(Info.MASTER_LINE, masterFile));
                    }//Else bad number of tokens, do nothing.
                } else {
          // This is a property line (key + value)
          while (continueLine(line)) {
            String nextLine = in.readLine();
            if (nextLine == null)
              nextLine = "";
            String loppedLine =
              line.substring(0, line.length() - 1);
            // Advance beyond whitespace on new line
            int startIndex = 0;
            for (startIndex = 0;
              startIndex < nextLine.length();
              startIndex++)
              if (whiteSpaceChars
                .indexOf(nextLine.charAt(startIndex))
                == -1)
                break;
            nextLine =
              nextLine.substring(startIndex, nextLine.length());
            line = new String(loppedLine + nextLine);
          }

          // Find start of key
          int len = line.length();
          int keyStart;
          for (keyStart = 0; keyStart < len; keyStart++) {
            if (whiteSpaceChars.indexOf(line.charAt(keyStart))
              == -1)
              break;
          }

          // Blank lines are ignored
          if (keyStart == len)
            continue;

          // Find separation between key and value
          int separatorIndex;
          for (separatorIndex = keyStart;
            separatorIndex < len;
            separatorIndex++) {
            char currentChar = line.charAt(separatorIndex);
            if (currentChar == '\\')
              separatorIndex++;
            else if (keyValueSeparators.indexOf(currentChar) != -1)
              break;
          }

          // Skip over whitespace after key if any
          int valueIndex;
          for (valueIndex = separatorIndex;
            valueIndex < len;
            valueIndex++)
            if (whiteSpaceChars.indexOf(line.charAt(valueIndex))
              == -1)
              break;

          // Skip over one non whitespace key value separators if any
          if (valueIndex < len)
            if (strictKeyValueSeparators
              .indexOf(line.charAt(valueIndex))
              != -1)
              valueIndex++;

          // Skip over white space after other separators if any
          while (valueIndex < len) {
            if (whiteSpaceChars.indexOf(line.charAt(valueIndex))
              == -1)
              break;
            valueIndex++;
          }
          String key = line.substring(keyStart, separatorIndex);
          String value =
            (separatorIndex < len)
              ? line.substring(valueIndex, len)
              : "";

          // Convert then store key and value
          key = loadConvert(key);
          value = loadConvert(value);
          put(key, value);
          _infoList.add(new Info(Info.KEY, key));
        }
      }
    }
  }

  /*
   * Returns true if the given line is a line that must
   * be appended to the next line
   */
  protected boolean continueLine(String line) {
    int slashCount = 0;
    int index = line.length() - 1;
    while ((index >= 0) && (line.charAt(index--) == '\\'))
      slashCount++;
    return (slashCount % 2 == 1);
  }

  /*
   * Converts encoded &#92;uxxxx to unicode chars
   * and changes special saved chars to their original forms
   */
  protected String loadConvert(String theString) {
    char aChar;
    int len = theString.length();
    StringBuffer outBuffer = new StringBuffer(len);

    for (int x = 0; x < len;) {
      aChar = theString.charAt(x++);
      if (aChar == '\\') {
        aChar = theString.charAt(x++);
        if (aChar == 'u') {
          // Read the xxxx
          int value = 0;
          for (int i = 0; i < 4; i++) {
            aChar = theString.charAt(x++);
            switch (aChar) {
              case '0' :
              case '1' :
              case '2' :
              case '3' :
              case '4' :
              case '5' :
              case '6' :
              case '7' :
              case '8' :
              case '9' :
                value = (value << 4) + aChar - '0';
                break;
              case 'a' :
              case 'b' :
              case 'c' :
              case 'd' :
              case 'e' :
              case 'f' :
                value = (value << 4) + 10 + aChar - 'a';
                break;
              case 'A' :
              case 'B' :
              case 'C' :
              case 'D' :
              case 'E' :
              case 'F' :
                value = (value << 4) + 10 + aChar - 'A';
                break;
              default :
                throw new IllegalArgumentException(
                        "Malformed \\uxxxx encoding.");
            }
          }
          outBuffer.append((char) value);
        } else {
          if (aChar == 't')
            aChar = '\t';
          else if (aChar == 'r')
            aChar = '\r';
          else if (aChar == 'n')
            aChar = '\n';
          else if (aChar == 'f')
            aChar = '\f';
          outBuffer.append(aChar);
        }
      } else
        outBuffer.append(aChar);
    }
    return outBuffer.toString();
  }

  /*
   * Converts unicodes to encoded &#92;uxxxx
   * and writes out any of the characters in specialSaveChars
   * with a preceding slash
   */
  protected String saveConvert(String theString, boolean escapeSpace) {
    int len = theString.length();
    StringBuffer outBuffer = new StringBuffer(len * 2);

    for (int x = 0; x < len; x++) {
      char aChar = theString.charAt(x);
      switch (aChar) {
        case ' ' :
          if (x == 0 || escapeSpace)
            outBuffer.append('\\');

          outBuffer.append(' ');
          break;
        case '\\' :
          outBuffer.append('\\');
          outBuffer.append('\\');
          break;
        case '\t' :
          outBuffer.append('\\');
          outBuffer.append('t');
          break;
        case '\n' :
          outBuffer.append('\\');
          outBuffer.append('n');
          break;
        case '\r' :
          outBuffer.append('\\');
          outBuffer.append('r');
          break;
        case '\f' :
          outBuffer.append('\\');
          outBuffer.append('f');
          break;
        default :
          if ((aChar < 0x0020) || (aChar > 0x007e)) {
            outBuffer.append('\\');
            outBuffer.append('u');
            outBuffer.append(toHex((aChar >> 12) & 0xF));
            outBuffer.append(toHex((aChar >> 8) & 0xF));
            outBuffer.append(toHex((aChar >> 4) & 0xF));
            outBuffer.append(toHex(aChar & 0xF));
          } else {
            if (specialSaveChars.indexOf(aChar) != -1)
              outBuffer.append('\\');
            outBuffer.append(aChar);
          }
      }
    }
    return outBuffer.toString();
  }

  /**
   * Writes a property sequence in this <code>Properties</code> table to the
   * output stream in a format suitable for loading into a
   * <code>Properties</code> table using the <code>load</code> method. The
   * stream is written using the ISO 8859-1 character encoding.
   * Comments, property definitions with value, and empty line are written,
   * keeping them in creating order.
   *
   * @param   out      an output stream.
   * @param   header   Not used in this method
   * @exception        IOException if writing this property list to the
   *                   specified output stream throws an <tt>IOException</tt>.
   * @exception        ClassCastException  if this <code>Properties</code>
   *                   object                   contains any keys or values
   *                   that    are not <code>Strings</code>.
   * @exception        NullPointerException  if <code>out</code> is null.
   */
  public synchronized void store(OutputStream out, String header)
    throws IOException {
    BufferedWriter awriter;
    awriter = new BufferedWriter(new OutputStreamWriter(out, "8859_1"));

    for (int i = 0; i < _infoList.size(); i++) {
      Info info = (Info) _infoList.get(i);

      if (info._type == Info.COMMENT) {
        // Add a comment line
        awriter.write(info._value);
        awriter.newLine();

      } else if (info._type == Info.EMPTY_LINE) {
        // Add a empty line
        awriter.newLine();
      } else if (info._type == Info.MASTER_LINE) {
                awriter.write(Info.IMPORT_FILE_PREFIX+ " "+info._value);
                awriter.newLine();
            } else {
        // Add a property (key + value) line
        String key = info._value;

        String val = (String) get(key);
        key = saveConvert(key, true);

        /* No need to escape embedded and trailing spaces for value,
         * hence pass false to flag.
         */
        val = saveConvert(val, false);

        awriter.write(key + "=" + val);
        awriter.newLine();
      }
    }
    awriter.flush();
  }

  /**
   * Convert a nibble to a hex character
   *
   * @param  nibble  the nibble to convert.
   */
  protected static char toHex(int nibble) {
    return hexDigit[(nibble & 0xF)];
  }

  /** A table of hex digits */
  protected static final char[] hexDigit =
    {
      '0',
      '1',
      '2',
      '3',
      '4',
      '5',
      '6',
      '7',
      '8',
      '9',
      'A',
      'B',
      'C',
      'D',
      'E',
      'F' };

}
TOP

Related Classes of simtools.ui.UserProperties$Info

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.