/*
* Configuration.java
*
* This work is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* by the Free Software Foundation; either version 2 of the License,
* or (at your option) any later version.
*
* This work 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
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*
* Copyright (c) 2004 Per Cederberg. All rights reserved.
*/
package org.liquidsite.app.servlet;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Properties;
import org.liquidsite.core.data.ConfigurationData;
import org.liquidsite.core.data.ConfigurationPeer;
import org.liquidsite.core.data.DataObjectException;
import org.liquidsite.core.data.DataSource;
import org.liquidsite.util.db.DatabaseConnector;
/**
* The application configuration. This class contains support for
* reading and writing the configuration, as well as retrieving the
* individual properties. The configuration is divided into a
* configuration file containing the database properties, and a
* configuration table containing the rest of the configuration
* properties.
*
* @author Per Cederberg, <per at percederberg dot net>
* @version 1.0
*/
public class Configuration {
/**
* The configuration file header.
*/
private static final String FILE_HEADER =
"Liquid Site Database Configuration File";
/**
* The version number key.
*/
public static final String VERSION =
"liquidsite.version";
/**
* The database host name key.
*/
public static final String DATABASE_HOSTNAME =
"liquidsite.db.hostname";
/**
* The database name key.
*/
public static final String DATABASE_NAME =
"liquidsite.db.name";
/**
* The database user name key.
*/
public static final String DATABASE_USER =
"liquidsite.db.user";
/**
* The database password key.
*/
public static final String DATABASE_PASSWORD =
"liquidsite.db.password";
/**
* The database pool size key.
*/
public static final String DATABASE_POOL_SIZE =
"liquidsite.db.pool.size";
/**
* The mail server host name key.
*/
public static final String MAIL_HOST =
"liquidsite.mail.host";
/**
* The mail user name key.
*/
public static final String MAIL_USER =
"liquidsite.mail.user";
/**
* The mail from address key.
*/
public static final String MAIL_FROM =
"liquidsite.mail.from";
/**
* The mail header text key.
*/
public static final String MAIL_HEADER =
"liquidsite.mail.header";
/**
* The mail footer text key.
*/
public static final String MAIL_FOOTER =
"liquidsite.mail.footer";
/**
* The file data directory key.
*/
public static final String FILE_DIRECTORY =
"liquidsite.file.dir";
/**
* The statistics data directory key.
*/
public static final String STATS_DIRECTORY =
"liquidsite.stats.dir";
/**
* The temporary file upload directory key.
*/
public static final String UPLOAD_DIRECTORY =
"liquidsite.upload.tmpdir";
/**
* The file upload maximum size key.
*/
public static final String UPLOAD_MAX_SIZE =
"liquidsite.upload.maxsize";
/**
* The configuration file. If this file is set to null, the
* configuration is read-only.
*/
private File file;
/**
* The configuration properties present in the file.
*/
private Properties fileProperties;
/**
* The configuration properties present in the database.
*/
private Properties databaseProperties;
/**
* The initialized flag. This flag is set to true once the
* configuration file has been read correctly.
*/
private boolean initialized = false;
/**
* Creates a new read-only configuration. This constructor is
* only used for accessing configuration data in databases during
* the installation.
*/
public Configuration() {
this(null);
}
/**
* Creates a new configuration.
*
* @param file the configuration file to use
*/
public Configuration(File file) {
this.file = file;
this.databaseProperties = new Properties();
this.fileProperties = new Properties(databaseProperties);
try {
readFile();
} catch (ConfigurationException ignore) {
// Do nothing
}
}
/**
* Checks if this configuration has been properly initialized.
* The configuration is considered initialized if the config file
* could be read properly.
*
* @return true if this configuration was properly initialized, or
* false otherwise
*/
public boolean isInitialized() {
return initialized;
}
/**
* Returns a configuration property string value.
*
* @param key the configuration property key
* @param defaultValue the value to use if not set
*
* @return the configuration property string value, or
* the default value if undefined
*/
public String get(String key, String defaultValue) {
return fileProperties.getProperty(key, defaultValue);
}
/**
* Returns a configuration property integer value.
*
* @param key the configuration property key
* @param defaultValue the value to use if not set
*
* @return the configuration property integer value, or
* the default value if undefined
*/
public int getInt(String key, int defaultValue) {
String str = get(key, String.valueOf(defaultValue));
try {
return Integer.parseInt(str);
} catch (NumberFormatException e) {
return defaultValue;
}
}
/**
* Sets a configuration property value.
*
* @param key the configuration property key
* @param value the configuration property value
*/
public void set(String key, String value) {
if (key.startsWith("liquidsite.db.")) {
fileProperties.setProperty(key, value);
} else {
databaseProperties.setProperty(key, value);
}
}
/**
* Sets a configuration property value.
*
* @param key the configuration property key
* @param value the configuration property value
*/
public void set(String key, int value) {
set(key, String.valueOf(value));
}
/**
* Sets all configuration properties from a set. Any existing
* configuration properties with identical names will be
* overwritten.
*
* @param config the configuration properties
*/
public void setAll(Configuration config) {
Enumeration e;
String name;
e = config.fileProperties.propertyNames();
while (e.hasMoreElements()) {
name = (String) e.nextElement();
set(name, config.get(name, ""));
}
e = config.databaseProperties.propertyNames();
while (e.hasMoreElements()) {
name = (String) e.nextElement();
set(name, config.get(name, ""));
}
}
/**
* Reads the configuration. The configuration is read from both
* file and database.
*
* @param db the database connector to use
*
* @throws ConfigurationException if the configuration couldn't
* be read properly
*/
public void read(DatabaseConnector db)
throws ConfigurationException {
DataSource src = new DataSource(db);
readFile();
try {
readDatabase(src);
} finally {
src.close();
}
}
/**
* Reads the configuration file. The configuration file contains
* the file properties.
*
* @throws ConfigurationException if the configuration file
* couldn't be read properly
*/
private void readFile() throws ConfigurationException {
FileInputStream input;
String message;
// Check for missing file
if (file == null) {
return;
}
// Open configuration file
try {
input = new FileInputStream(file);
} catch (FileNotFoundException e) {
message = "couldn't read config file: " + file;
throw new ConfigurationException(message, e);
}
// Read configuration file
try {
fileProperties.load(input);
input.close();
initialized = true;
} catch (IOException e) {
try {
input.close();
} catch (IOException ignore) {
// Do nothing
}
message = "couldn't read config file: " + file;
throw new ConfigurationException(message, e);
}
}
/**
* Reads the configuration database table.
*
* @param src the data source to use
*
* @throws ConfigurationException if the database table couldn't
* be read properly
*/
private void readDatabase(DataSource src)
throws ConfigurationException {
ArrayList list;
ConfigurationData data;
String name;
String value;
String message;
try {
list = ConfigurationPeer.doSelectAll(src);
for (int i = 0; i < list.size(); i++) {
data = (ConfigurationData) list.get(i);
name = data.getString(ConfigurationData.NAME);
value = data.getString(ConfigurationData.VALUE);
set(name, value);
}
} catch (DataObjectException e) {
message = "couldn't read configuration database table";
throw new ConfigurationException(message, e);
}
}
/**
* Writes the configuration. The configuration is written to both
* file and database.
*
* @param db the database connector to use
*
* @throws ConfigurationException if the configuration couldn't
* be written properly
*/
public void write(DatabaseConnector db)
throws ConfigurationException {
DataSource src = new DataSource(db);
writeFile();
try {
writeDatabase(src);
} finally {
src.close();
}
}
/**
* Writes the configuration file. The configuration file contains
* the file properties.
*
* @throws ConfigurationException if the configuration file
* couldn't be written properly
*/
private void writeFile() throws ConfigurationException {
FileOutputStream output;
String message;
// Check for missing file
if (file == null) {
message = "no configuration file has been set";
throw new ConfigurationException(message);
}
// Open configuration file
try {
output = new FileOutputStream(file);
} catch (FileNotFoundException e) {
message = "couldn't write config file: " + file;
throw new ConfigurationException(message, e);
}
// Write configuration file
try {
fileProperties.store(output, FILE_HEADER);
output.close();
initialized = true;
} catch (IOException e) {
try {
output.close();
} catch (IOException ignore) {
// Do nothing
}
message = "couldn't write config file: " + file;
throw new ConfigurationException(message, e);
}
}
/**
* Writes the configuration database table. The configuration
* table is first cleared, then all the configuration keys are
* inserted.
*
* @param src the data source to use
*
* @throws ConfigurationException if the database table couldn't
* be written properly
*/
private void writeDatabase(DataSource src)
throws ConfigurationException {
ConfigurationData data;
Enumeration iter;
String name;
String value;
String message;
try {
ConfigurationPeer.doDeleteAll(src);
iter = databaseProperties.propertyNames();
while (iter.hasMoreElements()) {
name = (String) iter.nextElement();
value = get(name, "");
data = new ConfigurationData();
data.setString(ConfigurationData.NAME, name);
data.setString(ConfigurationData.VALUE, value);
ConfigurationPeer.doInsert(src, data);
}
} catch (DataObjectException e) {
message = "couldn't write configuration database table";
throw new ConfigurationException(message, e);
}
}
}