AbstractPreferences.java
| Index Score | ||
|---|---|---|
![]() |
![]() |
org.xnap.util |
![]() |
![]() |
XNap 3 |
View: Reasons, Metrics, Source Code
These are the metrics that contribute to the Enerjy Score for this file, ranked by impact. So the metrics listed at the top influence the score to a greater extent that the metrics listed at the bottom.
/*
* XNap - A P2P framework and client.
*
* See the file 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.
*
* 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 org.xnap.util;
import java.awt.Color;
import java.awt.Font;
import java.awt.event.KeyEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.Hashtable;
import java.util.Properties;
import java.util.StringTokenizer;
import javax.swing.KeyStroke;
import org.apache.log4j.Logger;
import org.xnap.util.prefs.Validator;
/**
* This class provides a default implementation for a preferences framework.
* Methods are provided that can read and write native types, arrays and a few
* custom types.
*/
public abstract class AbstractPreferences {
//--- Constant(s) ---
public static final String ARRAY_SEPARATOR = ";";
//--- Data field(s) ---
protected static Logger logger = Logger.getLogger(AbstractPreferences.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;
/**
* The namespace is prefixed to each key.
*/
protected String namespace;
/**
* Preferences.
*/
protected Properties props = new Properties();
/**
* Maps keys to validators. Validators are used to validate input of
* set methods.
*/
private Hashtable validatorsByKey = new Hashtable();
//--- Constructor(s) ---
/**
* Constructs a <code>PreferencesSupport</code> object.
*
* @param filename the filename of the preferences file
* @param version the current version of the preferences, this version
* can be more recent than the version of the file
* @param namespace the namespace, used as a prefix for all keys
*/
public AbstractPreferences(String filename, int version, String namespace)
{
this.prefsFile = new File(filename);
this.version = version;
if (!namespace.endsWith(".")) {
namespace += ".";
}
this.namespace = namespace;
}
//--- Method(s) ---
/**
* Returns the absolute path of the preferences file.
*/
public String getFilename()
{
return prefsFile.getAbsolutePath();
}
/**
* Reads preferences from <code>f</code>.
*/
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) {
}
}
}
/**
* Reads preferences from default preferences file.
*/
public void read()
{
read(prefsFile);
}
/**
* Writes preferences to default preferences file. If preferences have not
* changed since the last read or write operation, no action is taken.
*
* @return true, if file is written successfully or preferences were not
* changed; false, if an <code>IOException</code> has occured
*/
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;
}
/**
* Returns the version of the preferences in the file at the point
* of the last read operation.
*/
public int getOldVersion()
{
return oldVersion;
}
/**
* Returns the current version of the preferences.
*/
public int getVersion()
{
return version;
}
/**
* Invoked by {@link #read()} to converts preferences from
* <code>oldVersion</code> to current version.
*/
public abstract void convert(int oldVersion);
/**
* Adds a preferences listener.
*/
public synchronized
void addPropertyChangeListener(PropertyChangeListener l)
{
propertyChange.addPropertyChangeListener(l);
}
/**
* Adds a preferences listener for a specific key.
*/
public synchronized
void addPropertyChangeListener(String key, PropertyChangeListener l)
{
propertyChange.addPropertyChangeListener(key, 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);
}
/**
* Removes a preferences listener.
*/
public synchronized
void removePropertyChangeListener(PropertyChangeListener l) {
propertyChange.removePropertyChangeListener(l);
}
public synchronized void removePropertyChangeListener
(String key, PropertyChangeListener l) {
propertyChange.removePropertyChangeListener(key, l);
}
public String get(String key)
{
return getProperty(key, "");
}
public String[] getArray(String key)
{
return StringHelper.toArray(getProperty(key, ""), ARRAY_SEPARATOR);
}
public boolean getBoolean(String key)
{
String val = getProperty(key, "false");
return val.equalsIgnoreCase("true");
}
public Color getColor(String key)
{
int val = getInt(key);
return new Color(val & 0xFF, (val >> 8) & 0xFF, (val >> 16) & 0xFF);
}
/**
* Always returns a valid font.
*/
public Font getFont(String key)
{
String val = getProperty(key, "");
StringTokenizer t = new StringTokenizer(val, ARRAY_SEPARATOR);
if (t.countTokens() >= 3) {
try {
String name = t.nextToken();
int style = Integer.parseInt(t.nextToken());
int size = Integer.parseInt(t.nextToken());
return new Font(name, style, size);
}
catch (NumberFormatException e) {
}
}
return new Font("Monospaced", 0, 12);
}
/**
* Reads a keystroke from the properties.
*
* @return null, if key was not found or value is invalid
*/
public KeyStroke getKeyStroke(String key)
{
String val = getProperty(key, "");
// this would be way easier but there seems to be no serialize
// method that can create the format recognized by getKeyStroke()
//return KeyStroke.getKeyStroke(key);
StringTokenizer t = new StringTokenizer(val, ARRAY_SEPARATOR);
if (t.countTokens() >= 3) {
try {
int keyCode = Integer.parseInt(t.nextToken());
int modifiers = Integer.parseInt(t.nextToken());
Character character = new Character(t.nextToken().charAt(0));
return (keyCode == KeyEvent.VK_UNDEFINED)
? KeyStroke.getKeyStroke(character, modifiers)
: KeyStroke.getKeyStroke(keyCode, modifiers);
}
catch (NumberFormatException e) {
}
}
return null;
}
/**
* Reads an integer from the properties.
*
* @return 0, if conversion fails; the value, otherwise
*/
public int getInt(String key)
{
try {
return Integer.parseInt(getProperty(key, "0"));
}
catch (NumberFormatException e) {
return 0;
}
}
public int[] getIntArray(String key)
{
return StringHelper.toIntArray(getProperty(key, ""), ARRAY_SEPARATOR);
}
public long getLong(String key)
{
try {
return Long.parseLong(getProperty(key, "0"));
}
catch (NumberFormatException e) {
return 0;
}
}
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, String[] newValue)
{
String[] oldValue = getArray(key);
if (!Arrays.equals(newValue, oldValue)) {
setProperty(key, StringHelper.toString(newValue, ARRAY_SEPARATOR));
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, Color newValue)
{
Color oldValue = getColor(key);
if (!newValue.equals(oldValue)) {
// encode color
int c = newValue.getRed()
| newValue.getGreen() << 8
| newValue.getBlue() << 16;
setProperty(key, c + "");
firePropertyChange(key, oldValue, newValue);
}
}
/**
* Saves a font.
*/
public void set(String key, Font newValue)
{
Font oldValue = getFont(key);
if (!newValue.equals(oldValue)) {
setProperty(key, toString(newValue));
firePropertyChange(key, oldValue, 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, int[] newValue)
{
int[] oldValue = getIntArray(key);
if (!Arrays.equals(newValue, oldValue)) {
setProperty(key, StringHelper.toString(newValue, ARRAY_SEPARATOR));
firePropertyChange(key, oldValue, newValue);
}
}
public void set(String key, KeyStroke newValue)
{
KeyStroke oldValue = getKeyStroke(key);
// we can use the != operator since KeyStroke objects are unique
if (newValue != oldValue) {
setProperty(key, toString(newValue));
firePropertyChange(key, oldValue, 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));
}
}
/**
* Sets a default property. If key already exists the value is not
* overwritten.
*
* <p>If a key already exists, the corresponding value is validated
* by <code>validator</code> and will replaced by <code>value</code>
* if the validation fails.
*
* @param key the key
* @param value the default value
* @param validator a validator that is invoked each time a value is set
*/
public synchronized 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 {
// validate already set value
validator.validate(getProperty(key, ""));
}
catch (IllegalArgumentException e) {
// set value is not valid, use default
logger.debug("invalid value: " + namespace + key + " = "
+ getProperty(key, "") + " [" + value + "]", e);
setProperty(key, value, false);
}
}
// else: value is already set and needs no validation
}
/**
* Sets a default property. If key already exists the value is not
* overwritten.
*
* @param key the key
* @param value the default value
*/
public void setDefault(String key, String value)
{
setDefault(key, value, null);
}
/**
* Ignores namespace.
*/
public synchronized 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 synchronized 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 synchronized String getProperty(String key, String defaultValue)
{
String s = props.getProperty(namespace + key, defaultValue);
return s;
}
/**
* Sets a property. <code>newValue</code> is validated if
* <code>validate</code> is set to true and a validator has been
* provided.
*
* @exception IllegalArgumentException if <code>newValue</code> is not valid
* @param key the key to set
* @param newValue the value to set
* @param validate if true, <code>newValue</code> will be validated
*/
protected synchronized void setProperty(String key, String newValue,
boolean validate)
{
if (validate) {
Validator v = (Validator)validatorsByKey.get(namespace + key);
if (v != null) {
v.validate(newValue);
}
}
props.setProperty(namespace + key, newValue);
changedFlag = true;
}
/**
* Sets a property. <code>newValue</code> is validated if a validator has
* been provided.
*
* @param key the key to set
* @param newValue the value to set
* @see #setProperty(String, String, boolean)
*/
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)
{
return (obj1 != null) ? obj1.equals(obj2) : (obj1 == obj2);
}
/**
* Determine if 2 arrays are equal, or both point to null.
*/
public static boolean areObjectsEqual(Object[] obj1, Object[] obj2)
{
return (obj1 != null) ? obj2 == null : Arrays.equals(obj1, obj2);
}
public static String toString(Font font)
{
// encode font
StringBuffer sb = new StringBuffer();
sb.append(font.getName());
sb.append(ARRAY_SEPARATOR);
sb.append(font.getStyle());
sb.append(ARRAY_SEPARATOR);
sb.append(font.getSize());
return sb.toString();
}
public static String toString(KeyStroke keystroke)
{
if (keystroke == null) {
return "";
}
// encode keystroke
StringBuffer sb = new StringBuffer();
sb.append(keystroke.getKeyCode());
sb.append(ARRAY_SEPARATOR);
sb.append(keystroke.getModifiers());
sb.append(ARRAY_SEPARATOR);
sb.append(keystroke.getKeyChar());
return sb.toString();
}
}
The table below shows all metrics for AbstractPreferences.java.




