honoring contract w.r.t type checking

This commit is contained in:
Rafael Chaves 2007-12-29 09:09:17 +00:00
parent 34a34d6d27
commit f79248364e
3 changed files with 213 additions and 213 deletions

View File

@ -88,7 +88,7 @@ public class SettingTests extends TestCase {
Settings root = new Settings(TestBasicDefinitions.class);
root.set("@option1", "foo");
root.set("context1@option2", "bar");
root.set("context1/context2@option3", "zoo");
root.set("context1/context2@option3", true);
assertTrue(root.nodeExists(""));
assertTrue(root.nodeExists("/"));
@ -113,7 +113,6 @@ public class SettingTests extends TestCase {
Settings root = new Settings(TestBasicDefinitions.class);
root.set("@option2", "foo");
root.set("context1/@option3", Boolean.FALSE);
root.set("context1/@option4", 42);
root.set("context1/context2/@option1", "zoo");
root.set("context1/context2/@option2", "bar");
root.set("context1/context2/@option3", Boolean.TRUE);

View File

@ -3,8 +3,8 @@ package org.umlgraph.settings;
/**
* A tag interface for classes defining settings.
* Classes implementing tis interface are expected to
* define possible settings as public fields. Names of fields
* Classes implementing this interface are expected to
* define possible settings as public static fields. Names of fields
* are expected to be unique across different definition classes.
* In case a default value is desired, Java's field default value
* mechanism can be used.

View File

@ -1,6 +1,5 @@
package org.umlgraph.settings;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.HashMap;
@ -28,237 +27,239 @@ import java.util.Map;
*/
public class Settings {
private Class<? extends SettingDefinitions>[] definitions;
private Class<? extends SettingDefinitions>[] definitions;
/*
* The child setting nodes.
*/
private Map<String, Settings> children = new HashMap<String, Settings>();
/*
* The setting values defined for this setting node.
*/
private Map<String, Object> values = new HashMap<String, Object>();
/*
* The child setting nodes.
*/
private Map<String, Settings> children = new HashMap<String, Settings>();
/*
* The setting values defined for this setting node.
*/
private Map<String, Object> values = new HashMap<String, Object>();
private Settings parent;
private Settings parent;
/**
* Constructs a root settings object.
*
* @param definitions
* the setting definition classes
*/
public Settings(Class<? extends SettingDefinitions>... definitions) {
if (definitions.length == 0)
throw new IllegalArgumentException("no definitions provided");
this.definitions = definitions;
}
/**
* Constructs a root settings object.
*
* @param definitions
* the setting definition classes
*/
public Settings(Class<? extends SettingDefinitions>... definitions) {
if (definitions.length == 0)
throw new IllegalArgumentException("no definitions provided");
this.definitions = definitions;
}
private Settings(Settings parent) {
this.parent = parent;
}
private Settings(Settings parent) {
this.parent = parent;
}
/**
* Returns the setting node corresponding to the given path. If the node
* does not exist, returns a new empty node.
*
* @param path
* the setting node path
* @return the setting node corresponding to the given path
*/
public Settings node(String[] path) {
return createNode(path, 0);
}
/**
* Returns the setting node corresponding to the given path. If the node
* does not exist, returns a new empty node.
*
* @param path
* the setting node path
* @return the setting node corresponding to the given path
*/
public Settings node(String[] path) {
return createNode(path, 0);
}
public Settings node(String path) {
return node(new SettingKey(path).getNodePath());
}
public Settings node(String path) {
return node(new SettingKey(path).getNodePath());
}
/**
* Creates a setting node under the given path, or returns the existing one.
*/
private Settings createNode(String[] path, int start) {
if (path.length == start)
return this;
Settings found = children.get(path[start]);
if (found == null)
children.put(path[start], found = new Settings(this));
if (start == path.length - 1)
return found;
return found.createNode(path, start + 1);
}
/**
* Creates a setting node under the given path, or returns the existing one.
*/
private Settings createNode(String[] path, int start) {
if (path.length == start)
return this;
Settings found = children.get(path[start]);
if (found == null)
children.put(path[start], found = new Settings(this));
if (start == path.length - 1)
return found;
return found.createNode(path, start + 1);
}
/**
* Returns whether the given node exists.
*/
public boolean nodeExists(String[] path) {
return existingNode(path) != null;
}
/**
* Returns whether the given node exists.
*/
public boolean nodeExists(String[] path) {
return existingNode(path) != null;
}
public boolean nodeExists(String path) {
return nodeExists(new SettingKey(path).getNodePath());
}
public boolean nodeExists(String path) {
return nodeExists(new SettingKey(path).getNodePath());
}
/**
* Returns an existing setting node corresponding to the given path.
*
* @param path
* the setting path
* @return the settings object, or <code>null</code>
*/
public Settings existingNode(String[] segments) {
Settings current = this;
for (String segment : segments) {
current = current.children.get(segment);
if (current == null)
return null;
}
return current;
}
/**
* Returns an existing setting node corresponding to the given path.
*
* @param path
* the setting path
* @return the settings object, or <code>null</code>
*/
public Settings existingNode(String[] segments) {
Settings current = this;
for (String segment : segments) {
current = current.children.get(segment);
if (current == null)
return null;
}
return current;
}
public Settings existingNode(String path) {
return existingNode(new SettingKey(path).getNodePath());
}
public Settings existingNode(String path) {
return existingNode(new SettingKey(path).getNodePath());
}
/**
* Returns the value of the option corresponding to the given key. If
* acceptDefault is <code>true</code> and a value for the option does not
* exist, returns the default value. Otherwise, returns <code>null</code>.
*
* @param key
* the option key
* @param acceptDefault
* whether a default value should be returned
* @return the value for the given key, or <code>null</code>
*/
public <T> T get(SettingKey key, boolean acceptDefault) {
if (!acceptDefault) {
Settings node = existingNode(key.getNodePath());
return node == null ? null : (T) node.values.get(key.getKey());
}
Settings node = lastExistingNode(key.getNodePath(), 0);
return node.searchValue(key.getKey());
}
/**
* Returns the value of the option corresponding to the given key. If
* acceptDefault is <code>true</code> and a value for the option does not
* exist, returns the default value. Otherwise, returns <code>null</code>.
*
* @param key
* the option key
* @param acceptDefault
* whether a default value should be returned
* @return the value for the given key, or <code>null</code>
*/
public <T> T get(SettingKey key, boolean acceptDefault) {
if (!acceptDefault) {
Settings node = existingNode(key.getNodePath());
return node == null ? null : (T) node.values.get(key.getKey());
}
Settings node = lastExistingNode(key.getNodePath(), 0);
return node.searchValue(key.getKey());
}
private <T> T searchValue(String key) {
if (!isDefined(key))
throw new IllegalArgumentException("unknown setting: " + key);
T ownValue = (T) values.get(key);
if (ownValue != null)
return ownValue;
return (T) (parent == null ? getDefaultValue(key) : parent.searchValue(key));
}
private <T> T searchValue(String key) {
if (!isDefined(key))
throw new IllegalArgumentException("unknown setting: " + key);
T ownValue = (T) values.get(key);
if (ownValue != null)
return ownValue;
return (T) (parent == null ? getDefaultValue(key) : parent
.searchValue(key));
}
private boolean isDefined(String key) {
return findField(key) != null;
}
private boolean isDefined(String key) {
return findField(key) != null;
}
private <T> T getDefaultValue(String key) {
Field field = findField(key);
if (field == null)
throw new IllegalArgumentException(
"unknown setting or undefined default: " + key);
try {
return (T) field.get(null);
} catch (IllegalAccessException e) {
throw new IllegalArgumentException("unknown setting: " + key);
}
}
private <T> T getDefaultValue(String key) {
Field field = findField(key);
if (field == null)
throw new IllegalArgumentException(
"unknown setting or undefined default: " + key);
try {
return (T) field.get(null);
} catch (IllegalAccessException e) {
throw new IllegalArgumentException("unknown setting: " + key);
}
}
private Field findField(String key) {
if (parent != null)
return parent.findField(key);
for (Class<? extends SettingDefinitions> definitionClass : definitions)
try {
Field field = definitionClass.getDeclaredField(key);
if (!field.getType().isPrimitive() && Modifier.isStatic(field.getModifiers()))
return field;
} catch (NoSuchFieldException e) {
// keep looking...
}
return null;
}
private Field findField(String key) {
if (parent != null)
return parent.findField(key);
for (Class<? extends SettingDefinitions> definitionClass : definitions)
try {
Field field = definitionClass.getDeclaredField(key);
if (!field.getType().isPrimitive()
&& Modifier.isStatic(field.getModifiers()))
return field;
} catch (NoSuchFieldException e) {
// keep looking...
}
return null;
}
private Settings lastExistingNode(String[] nodePath, int start) {
if (start == nodePath.length)
return this;
Settings immediateChild = children.get(nodePath[start]);
return immediateChild == null ? this : immediateChild.lastExistingNode(
nodePath, start + 1);
}
private Settings lastExistingNode(String[] nodePath, int start) {
if (start == nodePath.length)
return this;
Settings immediateChild = children.get(nodePath[start]);
return immediateChild == null ? this : immediateChild.lastExistingNode(
nodePath, start + 1);
}
/**
* Returns the value of the option corresponding to the given path. If
* acceptDefault is <code>true</code> and a value for the option does not
* exist, returns the default value. Otherwise, returns <code>null</code>.
* This is just a convenience method for {@link #get(SettingKey, boolean)}.
*
* @param path
* the option path
* @param acceptDefault
* whether a default value should be returned
* @return the value for the given path, or <code>null</code>
*/
/**
* Returns the value of the option corresponding to the given path. If
* acceptDefault is <code>true</code> and a value for the option does not
* exist, returns the default value. Otherwise, returns <code>null</code>.
* This is just a convenience method for {@link #get(SettingKey, boolean)}.
*
* @param path
* the option path
* @param acceptDefault
* whether a default value should be returned
* @return the value for the given path, or <code>null</code>
*/
public <T> T get(String path, boolean acceptDefault) {
return get(new SettingKey(path), acceptDefault);
}
public <T> T get(String path, boolean acceptDefault) {
return get(new SettingKey(path), acceptDefault);
}
public <T> T get(String path) {
return get(new SettingKey(path), true);
}
public <T> T get(String path) {
return get(new SettingKey(path), true);
}
/**
* Sets the value for the given option.
*
* @param key
* the option key
* @param value
* the new value, or <code>null</code>
*/
public <T> void set(SettingKey key, T value) {
if (value == null) {
Settings node = existingNode(key.getNodePath());
if (node != null)
node.values.remove(key.getKey());
} else {
Settings node = createNode(key.getNodePath(), 0);
node.values.put(key.getKey(), value);
}
}
/**
* Sets the value for the given option.
*
* @param key
* the option key
* @param value
* the new value, or <code>null</code>
*/
public <T> void set(SettingKey key, T value) {
if (!isDefined(key.getKey()))
throw new IllegalArgumentException("unknown setting: " + key);
if (value == null) {
Settings node = existingNode(key.getNodePath());
if (node != null)
node.values.remove(key.getKey());
} else {
Field field = findField(key.getKey());
if (!field.getType().isAssignableFrom(value.getClass()))
throw new ClassCastException(value.getClass().getName());
Settings node = createNode(key.getNodePath(), 0);
node.values.put(key.getKey(), value);
}
}
public <T> void set(String path, T value) {
set(new SettingKey(path), value);
}
public <T> void set(String path, T value) {
set(new SettingKey(path), value);
}
public <T> void setToDefault(String path) {
setToDefault(new SettingKey(path));
}
public <T> void setToDefault(String path) {
setToDefault(new SettingKey(path));
}
/**
* Sets the given option to its current default value.
*
* @param settingKey
* the key to set to default
*/
public <T> void setToDefault(SettingKey key) {
Object defaultValue = getDefaultValue(key.getKey());
if (defaultValue == null)
throw new IllegalStateException("no default value for " + key);
set(key, defaultValue);
}
/**
* Sets the given option to its current default value.
*
* @param settingKey
* the key to set to default
*/
public <T> void setToDefault(SettingKey key) {
Object defaultValue = getDefaultValue(key.getKey());
if (defaultValue == null)
throw new IllegalStateException("no default value for " + key);
set(key, defaultValue);
}
/**
* Returns the parent settings, or <code>null</code> if this is a root
* setting.
*
* @return the parent settings, or <code>null</code>
*/
public Settings getParent() {
return parent;
}
public static void registerContext(
Class<? extends SettingDefinitions> contextType) {
// TODO Auto-generated method stub
}
/**
* Returns the parent settings, or <code>null</code> if this is a root
* setting.
*
* @return the parent settings, or <code>null</code>
*/
public Settings getParent() {
return parent;
}
}