/*
* XNap
*
* A pure java file sharing client.
*
* See AUTHORS for copyright information.
*
* This program 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 program 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
*
*/
package xnap.util;
import xnap.*;
import xnap.net.*;
import xnap.util.prefs.Validator;
import java.beans.*;
import java.io.*;
import java.util.*;
import org.apache.log4j.Logger;
public abstract class PreferencesSupport {
//--- Constant(s) ---
public static final String ARRAY_SEPARATOR = ";";
//--- Data field(s) ---
protected static Logger logger = Logger.getLogger(PreferencesSupport.class);
protected transient PropertyChangeSupport propertyChange
= new PropertyChangeSupport(this);
/**
* Determines if preferences need to be saved.
*/
protected boolean changedFlag = false;
/**
* Preferences database.
*/
protected File prefsFile;
/**
* Version of database format.
*/
protected int version;
/**
* Version of database when read.
*/
protected int oldVersion = -1;
/**
*
*/
protected String namespace;
/**
* Preferences.
*/
protected Properties props = new Properties();
private Hashtable validatorsByKey = new Hashtable();
//--- Constructor(s) ---
public PreferencesSupport(String filename, int version, String namespace)
{
this.prefsFile = new File(filename);
this.version = version;
if (!namespace.endsWith(".")) {
namespace += ".";
}
this.namespace = namespace;
}
//--- Method(s) ---
public String getFilename()
{
return prefsFile.getAbsolutePath();
}
public void read(File f)
{
logger.info("reading " + f);
FileInputStream in = null;
try {
in = new FileInputStream(f);
props.load(in);
try {
oldVersion = Integer.parseInt
(props.getProperty("props.ver", "-1"));
}
catch (NumberFormatException e) {
oldVersion = -1;
}
if (oldVersion != -1 && oldVersion < getVersion()) {
logger.debug("converting from version " + oldVersion + " to "
+ getVersion());
convert(oldVersion);
}
}
catch (FileNotFoundException e) {
}
catch (IOException e) {
}
finally {
try {
if (in != null) {
in.close();
}
}
catch (Exception e) {
}
}
}
public void read()
{
read(prefsFile);
}
public boolean write()
{
if (!changedFlag) {
logger.info("nothing changed, not writing " + prefsFile);
return true;
}
logger.info("writing " + prefsFile);
FileOutputStream out = null;
try {
out = new FileOutputStream(prefsFile);
props.put("props.ver", version + "");
props.store(out, "This file was automatically generated.");
}
catch (IOException e) {
return false;
}
finally {
try {
if (out != null) {
out.close();
}
}
catch (Exception e) {
}
}
changedFlag = false;
return true;
}
public int getOldVersion()
{
return oldVersion;
}
public int getVersion()
{
return version;
}
public abstract void convert(int oldVersion);
public abstract void defaults();
public synchronized
void addPropertyChangeListener(PropertyChangeListener l)
{
propertyChange.addPropertyChangeListener(l);
}
public synchronized
void addPropertyChangeListener(String prop, PropertyChangeListener l)
{
propertyChange.addPropertyChangeListener(prop, l);
}
/**
* Fires PropertyChangeEvent without namespace.
*/
public void firePropertyChange(String key, Object oldValue,
Object newValue) {
// if (key.startsWith(namespace)) {
// key = key.substring(namespace.length() + 1);
// }
int i = key.lastIndexOf(".");
if (key.length() > i + 1) {
key = key.substring(i + 1);
}
propertyChange.firePropertyChange(key, oldValue, newValue);
}
public synchronized
void removePropertyChangeListener(PropertyChangeListener l) {
propertyChange.removePropertyChangeListener(l);
}
public boolean getBoolean(String key)
{
String val = getProperty(key, "false");
return val.equalsIgnoreCase("true");
}
public int getInt(String key)
{
try {
return Integer.parseInt(getProperty(key, "0"));
}
catch (NumberFormatException e) {
return 0;
}
}
public long getLong(String key)
{
try {
return Long.parseLong(getProperty(key, "0"));
}
catch (NumberFormatException e) {
return 0;
}
}
public String get(String key)
{
return getProperty(key, "");
}
public void set(String key, String newValue)
{
String oldValue = get(key);
if (!areObjectsEqual(newValue, oldValue)) {
setProperty(key, newValue);
firePropertyChange(key, oldValue, newValue);
}
}
public void set(String key, boolean newValue)
{
boolean oldValue = getBoolean(key);
if (newValue != oldValue) {
setProperty(key, newValue + "");
firePropertyChange(key, new Boolean(oldValue),
new Boolean(newValue));
}
}
public void set(String key, int newValue)
{
int oldValue = getInt(key);
if (newValue != oldValue) {
setProperty(key, newValue + "");
firePropertyChange(key, new Integer(oldValue),
new Integer(newValue));
}
}
public void set(String key, long newValue)
{
long oldValue = getLong(key);
if (newValue != oldValue) {
setProperty(key, newValue + "");
firePropertyChange(key, new Long(oldValue),
new Long(newValue));
}
}
public void setDefault(String key, String value, Validator validator)
{
if (validator != null) {
validatorsByKey.put(namespace + key, validator);
}
if (getProperty(key, null) == null) {
// property not set, use default value
setProperty(key, value, false);
}
else if (validator != null) {
try {
validator.validate(getProperty(key, ""));
}
catch (IllegalArgumentException e) {
logger.debug("invalid value: " + namespace + key + " = "
+ getProperty(key, "") + " [" + value + "]", e);
setProperty(key, value, false);
}
}
}
public void setDefault(String key, String value)
{
setDefault(key, value, null);
}
/**
* Ignores namespace.
*/
public void removeProperty(String key)
{
props.remove(key);
changedFlag = true;
}
/**
* Renames a property, used for conversion of property file formats.
* Ignores namespace. Does not fire change event.
*/
public void renameProperty(String oldKey, String newKey)
{
String value = props.getProperty(oldKey, null);
if (value != null) {
Object oldValue = props.remove(oldKey);
if (oldValue != null) {
props.setProperty(newKey, value);
changedFlag = true;
}
}
}
/**
* Returns a property.
*/
protected String getProperty(String key, String defaultValue)
{
String s = props.getProperty(namespace + key, defaultValue);
//Debug.log("Preferences.getProperty: " + namespace + key + " = " + s);
return s;
}
protected void setProperty(String key, String newValue, boolean validate)
{
if (validate) {
Validator v = (Validator)validatorsByKey.get(namespace + key);
if (v != null) {
try {
v.validate(newValue);
}
catch (IllegalArgumentException e) {
logger.debug("invalid value: " + namespace + key + " = "
+ newValue, e);
return;
}
}
}
props.setProperty(namespace + key, newValue);
changedFlag = true;
}
protected void setProperty(String key, String newValue)
{
setProperty(key, newValue, true);
}
/**
* Determine if 2 objects are equal, or both point to null.
*/
public static boolean areObjectsEqual(Object obj1, Object obj2) {
if (obj1 != null)
return obj1.equals(obj2);
else
return (obj1 == obj2);
}
}