henning 2002/12/14 03:33:46 Added: configuration/src/java/org/apache/commons/configuration BasePropertiesConfiguration.java Log: - moved from PropertiesConfiguration - factored out the code that is necessary to open a PropertyStream - changed the EOF logic from throwing a NullPointerException (and later catch it) to actually check for the null value from the reader and react accordingly - moved to StringUtils.split() from the check for the "=" sign - clean up split logic to use "continue" and "break" to escape and continue in the property reading loop and the PropertyReader - make "include = file1, file2, file3" work - Allow derived classes to lock including (when the created object has no backing file or resource and include has no real meaning) - various comment and style cleanups Revision Changes Path 1.1 jakarta-commons-sandbox/configuration/src/java/org/apache/commons/configuration/BasePropertiesConfiguration.java Index: BasePropertiesConfiguration.java =================================================================== package org.apache.commons.configuration; /* ==================================================================== * The Apache Software License, Version 1.1 * * Copyright (c) 1999-2002 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowlegement: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowlegement may appear in the software itself, * if and wherever such third-party acknowlegements normally appear. * * 4. The names "The Jakarta Project", "Commons", and "Apache Software * Foundation" must not be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact [EMAIL PROTECTED] * * 5. Products derived from this software may not be called "Apache" * nor may "Apache" appear in their names without prior written * permission of the Apache Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. */ import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.LineNumberReader; import java.io.Reader; import java.io.UnsupportedEncodingException; import java.util.Date; import java.util.Iterator; import org.apache.commons.lang.StringUtils; /** * loads the configuration from a properties file. <p> * * <p>The properties file syntax is explained here: * * <ul> * <li> * Each property has the syntax <code>key = value</code> * </li> * <li> * The <i>key</i> may use any character but the equal sign '='. * </li> * <li> * <i>value</i> may be separated on different lines if a backslash * is placed at the end of the line that continues below. * </li> * <li> * If <i>value</i> is a list of strings, each token is separated * by a comma ','. * </li> * <li> * Commas in each token are escaped placing a backslash right before * the comma. * </li> * <li> * If a <i>key</i> is used more than once, the values are appended * like if they were on the same line separated with commas. * </li> * <li> * Blank lines and lines starting with character '#' are skipped. * </li> * <li> * If a property is named "include" (or whatever is defined by * setInclude() and getInclude() and the value of that property is * the full path to a file on disk, that file will be included into * the ConfigurationsRepository. You can also pull in files relative * to the parent configuration file. So if you have something * like the following: * * include = additional.properties * * Then "additional.properties" is expected to be in the same * directory as the parent configuration file. * * Duplicate name values will be replaced, so be careful. * * </li> * </ul> * * <p>Here is an example of a valid extended properties file: * * <p><pre> * # lines starting with # are comments * * # This is the simplest property * key = value * * # A long property may be separated on multiple lines * longvalue = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa \ * aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa * * # This is a property with many tokens * tokens_on_a_line = first token, second token * * # This sequence generates exactly the same result * tokens_on_multiple_lines = first token * tokens_on_multiple_lines = second token * * # commas may be escaped in tokens * commas.excaped = Hi\, what'up? * </pre> * * @author <a href="mailto:[EMAIL PROTECTED]">Stefano Mazzocchi</a> * @author <a href="mailto:[EMAIL PROTECTED]">Jon S. Stevens</a> * @author <a href="mailto:daveb@miceda-data">Dave Bryson</a> * @author <a href="mailto:[EMAIL PROTECTED]">Geir Magnusson Jr.</a> * @author <a href="mailto:[EMAIL PROTECTED]">Leon Messerschmidt</a> * @author <a href="mailto:[EMAIL PROTECTED]">Kent Johnson</a> * @author <a href="mailto:[EMAIL PROTECTED]">Daniel Rall</a> * @author <a href="mailto:[EMAIL PROTECTED]">Ilkka Priha</a> * @author <a href="mailto:[EMAIL PROTECTED]">Jason van Zyl</a> * @author <a href="mailto:[EMAIL PROTECTED]">Martin Poeschl</a> * @author <a href="mailto:[EMAIL PROTECTED]">Henning P. Schmiedehausen</a> * @version $Id: BasePropertiesConfiguration.java,v 1.1 2002/12/14 11:33:46 henning Exp $ */ public abstract class BasePropertiesConfiguration extends BaseConfiguration { /** Allow file inclusion or not */ private boolean includesAllowed = false; /** * This is the name of the property that can point to other * properties file for including other properties files. */ protected static String include = "include"; /** * Implementations of this class must implement this method. * * @param resourceName The Resource to load * @return An Input Stream * * @throws IOException Error while loading the properties file */ protected abstract InputStream getPropertyStream(String resourceName) throws IOException; /** * Load the properties from the given input stream. * * @param input An InputStream. * @throws IOException */ public void load(InputStream input) throws IOException { load(input, null); } /** * Load the properties from the given input stream and using the specified * encoding. * * @param input An InputStream. * @param enc An encoding. * @exception IOException */ public synchronized void load(InputStream input, String enc) throws IOException { PropertiesReader reader = null; if (enc != null) { try { reader = new PropertiesReader(new InputStreamReader(input, enc)); } catch (UnsupportedEncodingException e) { // Get one with the default encoding... } } if (reader == null) { reader = new PropertiesReader(new InputStreamReader(input)); } while (true) { String line = reader.readProperty(); if (line == null) { break; // EOF } String [] parts = StringUtils.split(line, "="); if (parts.length >= 2) { String key = parts[0].trim(); String value = parts[1].trim(); /* * Configure produces lines like this ... just * ignore them. */ if (StringUtils.isEmpty(value)) { continue; // do .. while } if (StringUtils.isNotEmpty(getInclude()) && key.equalsIgnoreCase(getInclude())) { if (getIncludesAllowed()) { String [] files = StringUtils.split(value, ","); for (int cnt = 0 ; cnt < files.length ; cnt++) { load(getPropertyStream(files[cnt].trim())); } } } else { addProperty(key, value); } } } } /** * save properties to a file. * properties with multiple values are saved comma seperated. * * @param filename name of the properties file * @throws IOException */ public void save(String filename) throws IOException { File file = new File(filename); PropertiesWriter out = new PropertiesWriter(file); out.writeComment("written by PropertiesConfiguration"); out.writeComment(new Date().toString()); for (Iterator i = this.getKeys(); i.hasNext(); ) { String key = (String) i.next(); String value = StringUtils.join(this.getStringArray(key), ", "); out.writeProperty(key, value); } out.flush(); out.close(); } /** * Gets the property value for including other properties files. * By default it is "include". * * @return A String. */ public String getInclude() { return this.include; } /** * Sets the property value for including other properties files. * By default it is "include". * * @param inc A String. */ public void setInclude(String inc) { this.include = inc; } /** * Controls whether additional files can be loaded by the include = <xxx> * statement or not. Base rule is, that objects created by the empty * C'tor can not have included files. * * @param boolean includesAllowed True if Includes are allowed. */ protected void setIncludesAllowed(boolean includesAllowed) { this.includesAllowed = includesAllowed; } /** * Reports the status of file inclusion. * * @return True if include files are loaded. */ public boolean getIncludesAllowed() { return this.includesAllowed; } /** * This class is used to read properties lines. These lines do * not terminate with new-line chars but rather when there is no * backslash sign a the end of the line. This is used to * concatenate multiple lines for readability. */ class PropertiesReader extends LineNumberReader { /** * Constructor. * * @param reader A Reader. */ public PropertiesReader(Reader reader) { super(reader); } /** * Read a property. Returns null if Stream is * at EOF. Concatenates lines ending with "\". * Skips lines beginning with "#" and empty lines. * * @return A string containing a property value or null * * @exception IOException */ public String readProperty() throws IOException { StringBuffer buffer = new StringBuffer(); while (true) { String line = readLine(); if (line == null) { // EOF return null; } line = line.trim(); if (StringUtils.isEmpty(line) || (line.charAt(0) == '#')) { continue; } if (line.endsWith("\\")) { line = line.substring(0, line.length() - 1); buffer.append(line); } else { buffer.append(line); break; } } return buffer.toString(); } } // class PropertiesReader /** * This class is used to write properties lines. */ class PropertiesWriter extends FileWriter { /** * Constructor. * * @param file the proerties file * @throws IOException */ public PropertiesWriter(File file) throws IOException { super(file); } /** * Write a property. * * @param key * @param value * @exception IOException */ public void writeProperty(String key, String value) throws IOException { write(key + " = " + value + "\n"); } /** * Write a comment. * * @param comment * @exception IOException */ public void writeComment(String comment) throws IOException { write("# " + comment + "\n"); } } // class PropertiesWriter }
-- To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]> For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>