You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by he...@apache.org on 2002/12/14 12:36:11 UTC
cvs commit: jakarta-commons-sandbox/configuration/src/java/org/apache/commons/configuration PropertiesConfiguration.java
henning 2002/12/14 03:36:11
Modified: configuration/src/java/org/apache/commons/configuration
PropertiesConfiguration.java
Log:
- Factored out lots of the code into BasePropertyConfiguration. Here are
only the code to open up a file and allow access to a property stream.
- Also moved all code here that deals specifically with files.
- Style and comment cleanups
Revision Changes Path
1.6 +130 -353 jakarta-commons-sandbox/configuration/src/java/org/apache/commons/configuration/PropertiesConfiguration.java
Index: PropertiesConfiguration.java
===================================================================
RCS file: /home/cvs/jakarta-commons-sandbox/configuration/src/java/org/apache/commons/configuration/PropertiesConfiguration.java,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -r1.5 -r1.6
--- PropertiesConfiguration.java 3 Dec 2002 14:13:55 -0000 1.5
+++ PropertiesConfiguration.java 14 Dec 2002 11:36:11 -0000 1.6
@@ -56,89 +56,26 @@
import java.io.File;
import java.io.FileInputStream;
-import java.io.FileWriter;
+import java.io.FileNotFoundException;
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>
- *
+ * This is the "classic" Properties loader which loads the values from
+ * a single or multiple files (which can be chained with "include =".
+ * All given path references are either absolute or relative to the
+ * file name supplied in the Constructor.
+ * <p>
+ * In this class, empty PropertyConfigurations can be built, properties
+ * added and later saved. include statements are (obviously) not supported
+ * if you don't construct a PropertyConfiguration from a file.
+ * <p>
+ * If you want to use the getResourceAsStream() trick to load your
+ * resources without an absolute path, please take a look at the
+ * ClassPropertiesConfiguration which is intended to be used for this.
+ *
* @author <a href="mailto:stefano@apache.org">Stefano Mazzocchi</a>
* @author <a href="mailto:jon@latchkey.com">Jon S. Stevens</a>
* @author <a href="mailto:daveb@miceda-data">Dave Bryson</a>
@@ -149,348 +86,188 @@
* @author <a href="mailto:ipriha@surfeu.fi">Ilkka Priha</a>
* @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a>
* @author <a href="mailto:mpoeschl@marmot.at">Martin Poeschl</a>
+ * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
* @version $Id$
*/
-public class PropertiesConfiguration extends BaseConfiguration
+public class PropertiesConfiguration
+ extends BasePropertiesConfiguration
+ implements Configuration
{
-
/** File separator. */
protected String fileSeparator = System.getProperty("file.separator");
- /**
- * Base path of the configuration file used to create this Configuration
- * object.
- */
- protected String basePath;
-
- /**
- * This is the name of the property that can point to other
- * properties file for including other properties files.
- */
- protected static String include = "include";
-
+ /**
+ * Base path of the configuration file used to
+ * create this Configuration object. Might be null, then a
+ * "synthetic" PropertyConfiguration has been created which
+ * is not loaded from a file
+ **/
+ protected String basePath = null;
/**
- * Creates an empty Configuration
+ * Creates an empty PropertyConfiguration object which can be
+ * used to synthesize a new Properties file by adding values and
+ * then saving(). An object constructed by this C'tor can not be
+ * tickled into loading included files because it cannot supply a
+ * base for relative includes.
*/
public PropertiesConfiguration()
{
+ setIncludesAllowed(false);
}
/**
- * Creates and loads the extended properties from the specified file.
+ * Creates an empty PropertyConfiguration object with
+ * a Super-Object which is queries for every key.
*
- * @param file A String.
- * @throws IOException
+ * @param defaults Configuration defaults to use if key not in file
+ * @throws IOException Error while loading the properties file
*/
- public PropertiesConfiguration(String file) throws IOException
+ public PropertiesConfiguration(Configuration defaults)
+ throws IOException
{
- basePath = new File(file).getAbsolutePath();
- basePath = basePath.substring(0, basePath.lastIndexOf(fileSeparator) + 1);
-
- load(new FileInputStream(file));
+ this();
+ this.defaults = defaults;
}
/**
* Creates and loads the extended properties from the specified file.
+ * The specified file can contain "include = " properties which then
+ * are loaded and merged into the properties.
*
- * @param file A String.
- * @param defaultConfig Configuration defaults to use if key not in file
- * @throws IOException
+ * @param fileName The name of the Properties File to load.
+ * @throws IOException Error while loading the properties file
*/
- public PropertiesConfiguration(String file, Configuration defaultConfig)
+ public PropertiesConfiguration(String fileName)
throws IOException
{
- this(file);
- defaults = defaultConfig;
+ File file = new File(fileName);
+ File baseFile = file.getParentFile();
+
+ if (baseFile != null)
+ {
+ basePath = baseFile.getAbsolutePath();
+ setIncludesAllowed(true);
+ }
+ else
+ {
+ // For some unknown reason we have no path to load includes
+ // from. So, don't allow includes.
+ setIncludesAllowed(false);
+ }
+
+ load(getPropertyStream(file.getName()));
}
/**
- * Creates the extended properties with the specified defaults
+ * Creates and loads the extended properties from the specified file.
*
- * @param defaultConfig Configuration defaults to use if key not in file
- * @throws IOException
+ * @param file The name of the Properties File to load.
+ * @param defaults Configuration defaults to use if key not in file
+ * @throws IOException Error while loading the properties file
*/
- public PropertiesConfiguration(Configuration defaultConfig)
+ public PropertiesConfiguration(String file, Configuration defaults)
throws IOException
{
- defaults = defaultConfig;
+ this(file);
+ this.defaults = defaults;
}
/**
* Creates and loads the extended properties from the specified file.
*
- * @param file A String.
- * @param defaultFile A String.
- * @throws IOException
+ * @param file The name of the Properties File to load.
+ * @param defaultFile The name of a properties file whose values
+ * should be used if a key is not in the file.
+ * @throws IOException Error while loading the properties file
*/
public PropertiesConfiguration(String file, String defaultFile)
throws IOException
{
this(file);
- if (defaultFile != null)
+ if (StringUtils.isNotEmpty(defaultFile))
{
- defaults = new PropertiesConfiguration(defaultFile);
+ this.defaults = new PropertiesConfiguration(defaultFile);
}
}
/**
- * Load the properties from the given input stream.
+ * Gets a resource relative to the supplied base class or
+ * from the class loader if its an absolute reference (starting
+ * with a "/"
*
- * @param input An InputStream.
- * @throws IOException
+ * @param resourceName The resource Name
+ * @return An Input Stream
+ * @throws IOException Error while loading the properties file
*/
- 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
+ public InputStream getPropertyStream(String resourceName)
+ 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...
- }
- }
+ InputStream resource = null;
+ File file = null;
- if (reader == null)
+ if (resourceName.startsWith(fileSeparator))
{
- reader =
- new PropertiesReader(new InputStreamReader(input));
+ /*
+ * We have an absolute path so we'll
+ * use this.
+ */
+ file = new File(resourceName);
}
-
- try
+ else
{
- while (true)
+ if (StringUtils.isEmpty(basePath))
+ {
+ // Good luck... This will fail 99 out of 100 times.
+ file = new File(resourceName);
+ }
+ else
{
- String line = reader.readProperty();
- int equalSign = line.indexOf('=');
+ StringBuffer fileName = new StringBuffer();
+ fileName.append(basePath);
- if (equalSign > 0)
+ // My best friend. Paranoia.
+ if (!basePath.endsWith(fileSeparator))
{
- String key = line.substring(0, equalSign).trim();
- String value = line.substring(equalSign + 1).trim();
+ fileName.append(fileSeparator);
+ }
- /*
- * Configure produces lines like this ... just
- * ignore them.
- */
- if ("".equals(value))
- {
- continue;
- }
-
- if (getInclude() != null &&
- key.equalsIgnoreCase(getInclude()))
- {
- /*
- * Recursively load properties files.
- */
- File file = null;
-
- if (value.startsWith(fileSeparator))
- {
- /*
- * We have an absolute path so we'll
- * use this.
- */
- file = new File(value);
- }
- else
- {
- /*
- * We have a relative path, and we have
- * two possible forms here. If we have the
- * "./" form then just strip that off first
- * before continuing.
- */
- if (value.startsWith("." + fileSeparator))
- {
- value = value.substring(2);
- }
-
- file = new File(basePath + value);
- }
-
- if (file != null && file.exists() && file.canRead())
- {
- load(new FileInputStream(file));
- }
- }
- else
- {
- addProperty(key, value);
- }
+ //
+ // We have a relative path, and we have
+ // two possible forms here. If we have the
+ // "./" form then just strip that off first
+ // before continuing.
+ //
+ if (resourceName.startsWith("." + fileSeparator))
+ {
+ fileName.append(resourceName.substring(2));
}
+ else
+ {
+ fileName.append(resourceName);
+ }
+
+ file = new File(fileName.toString());
}
}
- catch (NullPointerException e)
- {
- /*
- * Should happen only when EOF is reached.
- */
- return;
- }
- }
-
- /**
- * 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();)
+ if (file == null || !file.exists())
{
- String key = (String) i.next();
- String value = StringUtils.join(this.getStringArray(key), ", ");
- out.writeProperty(key, value);
+ throw new FileNotFoundException("Could not open File "
+ + resourceName);
}
- 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;
- }
-
-
- /**
- * 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.
- *
- * @return A String.
- * @exception IOException
- */
- public String readProperty() throws IOException
+ else
{
- StringBuffer buffer = new StringBuffer();
-
- try
+ if (file.canRead())
{
- while (true)
- {
- String line = readLine().trim();
- if ((line.length() != 0) && (line.charAt(0) != '#'))
- {
- if (line.endsWith("\\"))
- {
- line = line.substring(0, line.length() - 1);
- buffer.append(line);
- }
- else
- {
- buffer.append(line);
- break;
- }
- }
- }
+ resource = new FileInputStream(file);
}
- catch (NullPointerException e)
+ else
{
- return null;
+ throw new IOException("File " + resourceName
+ + " exists but could not be read.");
}
-
- 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
+ return resource;
+ }
}
--
To unsubscribe, e-mail: <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>