added settings project

This commit is contained in:
Rafael Chaves 2007-12-29 08:54:03 +00:00
parent a133341bd7
commit 68f112c4ac
7 changed files with 428 additions and 0 deletions

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
<classpathentry kind="output" path="bin"/>
</classpath>

View File

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>org.umlgraph.settings</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.pde.ManifestBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.pde.SchemaBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.pde.PluginNature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

View File

@ -0,0 +1,8 @@
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Settings
Bundle-SymbolicName: org.umlgraph.settings
Bundle-Version: 5.1.0.qualifier
Bundle-Vendor: umlgraph.org
Export-Package: org.umlgraph.settings
Bundle-RequiredExecutionEnvironment: J2SE-1.5

View File

@ -0,0 +1,4 @@
source.. = src/
output.. = bin/
bin.includes = META-INF/,\
.

View File

@ -0,0 +1,14 @@
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
* 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.
*/
public interface SettingDefinitions {
}

View File

@ -0,0 +1,103 @@
package org.umlgraph.settings;
import java.util.Arrays;
import java.util.StringTokenizer;
/**
* A key for accessing a specific setting.
*
*/
public class SettingKey {
private static final String PATH_DELIMITER = "/";
private static final String OPTION_DELIMITER = "@";
private static final String[] EMPTY_CONTEXT_PATH = {};
private String[] nodePath;
private String key;
public SettingKey(String[] nodePath, String key) {
this.nodePath = nodePath;
this.key = key;
}
public SettingKey(String stringKey) {
int atIndex = stringKey.indexOf(OPTION_DELIMITER);
if (atIndex >= 0) {
if (atIndex == stringKey.length() - 1)
throw new IllegalArgumentException("argument: " + stringKey);
key = stringKey.substring(atIndex + 1);
if (atIndex == 0) {
nodePath = EMPTY_CONTEXT_PATH;
return;
}
}
String nodePathStr = atIndex < 0 ? stringKey : stringKey.substring(0,
atIndex);
StringTokenizer pathSegmenter = new StringTokenizer(nodePathStr,
PATH_DELIMITER);
nodePath = new String[pathSegmenter.countTokens()];
int i = 0;
while (pathSegmenter.hasMoreTokens())
nodePath[i++] = pathSegmenter.nextToken();
}
public String[] getNodePath() {
return nodePath;
}
public boolean isRoot() {
return nodePath.length == 0;
}
public boolean hasKey() {
return key != null;
}
public String getKey() {
return key;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((key == null) ? 0 : key.hashCode());
result = prime * result + Arrays.hashCode(nodePath);
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
final SettingKey other = (SettingKey) obj;
if (key == null) {
if (other.key != null)
return false;
} else if (!key.equals(other.key))
return false;
if (!Arrays.equals(nodePath, other.nodePath))
return false;
return true;
}
@Override
public String toString() {
StringBuffer result = new StringBuffer(PATH_DELIMITER);
for (int i = 0; i < nodePath.length; i++) {
result.append(nodePath[i]);
result.append(PATH_DELIMITER);
}
if (hasKey()) {
result.append(OPTION_DELIMITER);
result.append(key);
}
return result.toString();
}
}

View File

@ -0,0 +1,264 @@
package org.umlgraph.settings;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.Map;
/**
* A typed hierarchic preference mechanism that takes advantage of generics for
* providing a simpler protocol.
*
* Features:
* <ul>
* <li>default values</li>
* <li>contexts are hierarchic, option value lookup falls back to parent if
* option is not found at the current level</li>
* <li> options are typed, so an attempt at setting them with the wrong value
* type causes an exception </li>
* <li> option contexts are statically typed, meaning that set of available
* options for a context is defined at compile time and trying to set an
* unexpected option value causes an exception. </li>
* </ul>
* Non-features:
* <ul>
* <li> persistence </li>
* </ul>
*/
public class Settings {
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>();
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;
}
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);
}
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);
}
/**
* 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());
}
/**
* 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());
}
/**
* 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 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 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);
}
/**
* 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) {
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);
}
}
public <T> void set(String path, T value) {
set(new SettingKey(path), value);
}
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);
}
/**
* 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
}
}