Package asia.redact.bracket.properties

Source Code of asia.redact.bracket.properties.Properties$Factory

/*
*  This file is part of Bracket Properties
*  Copyright 2011 David R. Smith
*
*/
package asia.redact.bracket.properties;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.URL;
import java.text.ParseException;
import java.util.Comparator;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import asia.redact.bracket.properties.alt.DotPropertiesParser;
import asia.redact.bracket.properties.line.LineScanner;

/**
* <pre>
* In java, java.util.Properties is not an Interface. Bracket Properties
* has one, which allows (among other things) for both a standard and a sorted implementation. The
* standard implementation is backed by a LinkedHashMap, which keeps insertion
* order intact. This is a critical issue for non-trivial use of Properties files.
*
* Properties is also the home to the static Factory, which is the supported way to
* instantiate a Bracket Properties object.
*
* </pre>
* @author Dave
*
*/
public interface Properties {

  /**
   * Can be used to get direct access to the Entry data structures
   * @return
   */
  public Map<String, ValueModel> getPropertyMap();
 
  /**
   * Get the value.
   * @param key
   * @return
   */
  public String get(String key);
 
  /**
   * Coerce to an integer value. Obviously this works better if the value is actually an integer.
   * @param key
   * @return
   */
  public int intValue(String key);
  /**
   * Coerce to a long value. Obviously this works better if the value is actually a long.
   * @param key
   * @return
   */
  public long longValue(String key);
 
  /**
   * Date value here is assumed to be a long
   * @param key
   * @return
   */
  public java.util.Date dateValue(String key);
 
  /**
   * Just syntactical sugar to use a SimpleDateFormat
   *
   * @param key
   * @param format
   * @return
   * @throws ParseException
   */
  public java.util.Date dateValue(String key, String format) throws ParseException;
 
 
  /**
   * <pre>Get the properties as a tree of nodes. For example,
   *
   * a.b.c=something
   * a.b.c.d=something else
   *
   * looks like
   *
   * a
   *   b
   *     c - something
   *       d - something else
   *      
   *  This method is identical in results to getTree(regex) where the regex
   *  is "\\.". That is, the separator token in the key is a full stop
   * 
   *  Obviously this works better if your keys are delimited by dot characters
   *  </pre>
  
   * @return
   */
  public Node getTree();
 
  /**
   * <pre>
   * Get the properties as a tree of nodes with a selector
   *
   * a.b.c=something
   * a.b.c.d=something else
   * a.b.c.e.f=item
   * a.b.c.e=item2
   * </pre>
   *
   *
   */
  public Node getTree(GroupParams params);
 
  /**
   * Get the list of comments, return an empty list if none
   *
   * @param key
   * @return
   */
  public List<String> getComments(String key);
 
  /**
   * The char found in the parse, normally '='
   *
   * @param key
   * @return
   */
  public char getSeparator(String key);
 
  /**
   * Add the key and value or values. Useful with multi-line entries
   *
   * @param key
   * @param values
   */
  public void put(String key, String ... values);
 
  /**
   * Number of entries in the underlying map
   *
   * @return
   */
  public int size();
  /**
   * remove all entries from the underlying map
   */
  public void clear();
 
  /**
   * <pre>
   * get(key) will throw a RuntimeException if the key does not
   * exist. This method can be used to test for a key prior to
   * calling get().
   *
   * Returns true if the underlying map has this key
   *
   * </pre>
   * @param key
   * @return
   */
  public boolean containsKey(String key);
 
  /**
   * Returns true if the key exists and has a non-empty value
   *
   * @param key
   * @return
   */
  public boolean hasValue(String key);
 
  /**
   * Overwrite existing keys with the new ones, keep those existing ones that don't collide
   * This operation is non-destructive on the input
   * does not concatenate comments
   *
   * @param props
   * @return the merged properties
   */
  public Properties merge(Properties props);
 
  /**
   * Overwrite existing keys with the new ones, keep those existing ones that don't collide
   * This operation is non-destructive on the input
   *
   * @param props
   * @return the merged properties
   */
  public Properties merge(Properties props, boolean mergeComments);
 
  /**
   * Cause a graph to become the contents of the properties file. Destructive
   * to current entries, so this is not very useful yet
   *
   *
   * @param rootNode
   */
  public void synchronize(Node rootNode);
 
  /**
   * <pre>
   * Mode is the available combinations of lexer and parser
   *
   * BasicToken - PropertiesLexer and PropertiesParser.
   * Input is a String and a list of tokens is created, then the list
   * is parsed. Trivial. Possibly good for small properties files
   *
   * Compatibility - PropertiesLexer and PropertiesParser.
   * Same parser as above but an attempt is made to retain
   * java.util.Properties compatibility in the parse.
   *
   * Line - LineScanner and PropertiesParser2.
   * Uses the LineScanner which is essentially a BufferedReader, and there is no
   * separate token list, parser works directly off lines. Should work best for
   * larger properties files. Probably the best option full stop.
   *
   *  Usage:
   *
   *  Properties.Factory.Mode = Properties.Mode.StreamingToken;
   *  Properties props = Properties.Factory.getInstance(reader);
   * 
   *  </pre>
   *
   * @author Dave
   *
   */
 
  public enum Mode {
    BasicToken,Compatibility,Line;
  }
 
  /**
   * <pre>
   * The default mode is the trivial memory mode, which is BasicToken.
   *
   * You can change the Mode of the factory globally by setting it to a different value like this:
   *
   * Properties.mode = Mode.Line;
   *
   * which changes the mode (and thus the parser/lexer) to Line.
   *
   * </pre>
   *
   * @author Dave
   *
   */
  public static final class Factory {
   
    public static Mode mode = Mode.BasicToken;
  //  private final static Logger log = Logger.getLogger("asia.redact.bracket.properties.Properties.Factory");
   
    public static Properties getInstance(){
      return new PropertiesImpl();
    }
   
    public synchronized static Properties getInstance(URL url){
      try {
        return Factory.getInstance(url.openStream());
      } catch (IOException e) {
        throw new RuntimeException("IOException caught",e);
      }
     
    }
    public synchronized static Properties getInstance(Reader reader){
      switch(mode){
        case BasicToken: return new PropertiesImpl(reader);
        case Compatibility: {
            PropertiesLexer lexer = new PropertiesLexer(reader);
            lexer.lex();
            List<PropertiesToken> list = lexer.getList();
            PropertiesImpl props = new PropertiesImpl();
            PropertiesParser p = new PropertiesParser(list, props);
            p.setTrimValues(true);
            p.parse();
            return props;
         
        }
        case Line:{
         
            LineScanner lexer = new LineScanner(reader);
            PropertiesImpl props = new PropertiesImpl();
            new PropertiesParser2(lexer,props).parse();
            return props;
         
        }
        }
      return new PropertiesImpl(reader);
    }
    public synchronized static Properties getInstance(InputStream in){
      switch(mode){
        case BasicToken: return new PropertiesImpl(in);
        case Compatibility: {
       
            PropertiesLexer lexer = new PropertiesLexer(in);
            lexer.lex();
            List<PropertiesToken> list = lexer.getList();
            PropertiesImpl props = new PropertiesImpl();
            PropertiesParser p = new PropertiesParser(list, props);
            p.setTrimValues(true);
            p.parse();
            return props;
         
        }
        case Line:{
         
            LineScanner lexer = new LineScanner(new InputStreamReader(in));
            PropertiesImpl props = new PropertiesImpl();
            new PropertiesParser2(lexer,props).parse();
            return props;
         
        }
          }
      return new PropertiesImpl(in);
    }
   
    /**
     * Load from a legacy Properties file object
     *
     * @param legacy
     * @return
     */
    public static Properties getInstance(java.util.Properties legacy){
      return new PropertiesImpl(legacy);
    }
    /**
     * baseName is something like a.b.c.MyProperty which with Locale.AU will be
     * a search path like /a.b.c.MyProperty_en_AU.properties
     *
     * @param baseName
     * @param locale
     * @return
     */
    public static Properties getInstance(String baseName, Locale locale) {
      LocaleStringBuilder builder = new LocaleStringBuilder(baseName,locale);
      List<String> list = builder.getSearchStrings();
      PropertiesImpl base = new PropertiesImpl();
      for(String s: list){
        InputStream in = null;
        try {
          in = Thread.currentThread().getClass().getResourceAsStream(s);
          if(in != null){
            base.merge(Properties.Factory.getInstance(in));
          }
        }finally{
          if(in != null)
            try {
              in.close();
            } catch (IOException e) {
              e.printStackTrace();
            }
        }
       
      }
      return base;
    }
   
   
    /**
     * The input file must have been generated by OutputAdapter.writeAsXML(Writer) or meet the same
     * requirements as regards form. This is not yet documented but looking at the test case files you can
     * figure it out.
     *
     * @throws RuntimeException if it fails due to I/O
     *
     * @param file
     * @return
     */
    public synchronized static Properties getInstanceFromXML(File file) {
      FileInputStream in = null;
      try {
        in = new FileInputStream(file);
        InputStreamReader reader = new InputStreamReader(in);
        BufferedReader breader = new BufferedReader(reader);
        ParseXML parser = new ParseXML();
        parser.parse(breader);
        return parser.getProps();
      } catch (FileNotFoundException e) {
        throw new RuntimeException(e);
      }
     
    }
   
    public synchronized static Properties sortedInstance(Properties props){
        SortedPropertiesImpl impl = new SortedPropertiesImpl();
        return impl.merge(props);
    }
   
    public synchronized static Properties sortedInstance(Properties props, Comparator<String> comp){
      SortedPropertiesImpl impl = new SortedPropertiesImpl(comp);
      return impl.merge(props);
    }
   
    public synchronized static Properties getDotInstance(Reader reader){
      LineScanner lexer = new LineScanner(reader);
      DotPropertiesParser p = new DotPropertiesParser(lexer);
      p.parse();
      return p.getProperties();
    }
   
    public synchronized static Properties getDotInstance(InputStream in){
      LineScanner lexer = new LineScanner(new InputStreamReader(in));
      DotPropertiesParser p = new DotPropertiesParser(lexer);
      p.parse();
      return p.getProperties();
    }
  }

}
TOP

Related Classes of asia.redact.bracket.properties.Properties$Factory

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.