com.thaiopensource.validate.nvdl.ContextMap Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of wicketstuff-jing Show documentation
Show all versions of wicketstuff-jing Show documentation
Jing is a validator for RELAX NG and other schema languages. This
project was taken from http://code.google.com/p/jing-trang and
mavenized for inclusion in the Wicket Stuff HTML Validator.
The code was taken from the 20091111 release.
package com.thaiopensource.validate.nvdl;
import com.thaiopensource.util.Equal;
import java.util.Vector;
import java.util.Hashtable;
import java.util.Enumeration;
import java.util.NoSuchElementException;
/**
* Keeps modes depending on context.
* The structure of the context map is
*
* stores the mode for
* / in rootValue
* "" in otherValue (this is for relative paths)
* stores a hash with the last path elements as key and
* ContextMap objects as values.
*
* A path like a/b and mode x
* will be represented by 3 ContextMap objects
* ContextMap b ---> ContextMap a ---> ContextMap otherValue=x
*
* Addind also /a/b and mode y will give
*
* ContextMap b ---> ContextMap a ---> ContextMap (otherValue=x, rootValue=y)
*
* Adding a2/b and mode w will give
*
* ContextMap b ---> ContextMap a ---> ContextMap (otherValue=x, rootValue=y)
* a2 ---> ContextMap otherValue=w
*/
class ContextMap {
/**
* Stores the mode associated with an absolute path.
*/
private Object rootValue;
/**
* Stores a mode associated with a relative path.
*/
private Object otherValue;
/**
* Stores a hash map with with the key the last local name and
* as values other ContextMap objects.
*/
private final Hashtable nameTable = new Hashtable();
/**
* Get the mode matching a list of local names.
* A root more returned means an exact matching of the given local names
* with the local names from the context map. Otherwise we can get either
* a mode stored as otherValue or null if the given context does not match
* any of the stored paths.
* @param context The list of local names that represent a section context
* (path from root local element names from the same namespace).
* @return A mode or null.
*/
Object get(Vector context) {
return get(context, context.size());
}
/**
* Adds a single path (isRoot, names) and a mode to be used for this path = context.
* @param isRoot True if the path starts with /
* @param names The local names that form the path.
* @param value The mode.
* @return true if there is no duplicate path, false otherwise.
*/
boolean put(boolean isRoot, Vector names, Object value) {
return put(isRoot, names, names.size(), value);
}
/**
* Get the mode matching a list of local names.
* A root more returned means an exact matching of the given local names
* with the local names from the context map. Otherwise we can get either
* a mode stored as otherValue or null if the given context does not match
* any of the stored paths.
* @param context The list of local names that represent a section context
* (path from root local element names from the same namespace).
* @param len The lenght we should take from the list.
* @return A mode or null.
*/
private Object get(Vector context, int len) {
if (len > 0) {
ContextMap nestedMap = (ContextMap)nameTable.get(context.elementAt(len - 1));
if (nestedMap != null) {
Object value = nestedMap.get(context, len - 1);
if (value != null)
return value;
}
}
if (rootValue != null && len == 0)
return rootValue;
return otherValue;
}
/**
* Adds a single path (isRoot, names) and a mode to be used for this path = context.
* @param isRoot True if the path starts with /
* @param names The local names that form the path.
* @param len The length if the names vector.
* @param value The mode.
* @return true if there is no duplicate path, false otherwise.
*/
private boolean put(boolean isRoot, Vector names, int len, Object value) {
if (len == 0) {
// if we have only /
if (isRoot) {
if (rootValue != null)
return false;
rootValue = value;
}
// We followed all the paths, it is not root,
// then we store the mode as the other value.
else {
if (otherValue != null)
return false;
otherValue = value;
}
return true;
}
else {
// get the last local name from the path
Object name = names.elementAt(len - 1);
// Get the context map mapped in nameTable to that name.
ContextMap nestedMap = (ContextMap)nameTable.get(name);
// Not preset then create it.
if (nestedMap == null) {
nestedMap = new ContextMap();
nameTable.put(name, nestedMap);
}
// Add the rest of the path names in the nested context map.
return nestedMap.put(isRoot, names, len - 1, value);
}
}
/**
* Chek that this context map is equals with
* a specified context map.
*/
public boolean equals(Object obj) {
if (!(obj instanceof ContextMap))
return false;
ContextMap other = (ContextMap)obj;
if (!Equal.equal(this.rootValue, other.rootValue)
|| !Equal.equal(this.otherValue, other.otherValue))
return false;
// We want jing to work with JDK 1.1 so we cannot use Hashtable.equals
if (this.nameTable.size() != other.nameTable.size())
return false;
for (Enumeration e = nameTable.keys(); e.hasMoreElements();) {
Object key = e.nextElement();
if (!nameTable.get(key).equals(other.nameTable.get(key)))
return false;
}
return true;
}
/**
* Get a hashcode for this context map.
*/
public int hashCode() {
int hc = 0;
if (rootValue != null)
hc ^= rootValue.hashCode();
if (otherValue != null)
hc ^= otherValue.hashCode();
for (Enumeration e = nameTable.keys(); e.hasMoreElements();) {
Object key = e.nextElement();
hc ^= key.hashCode();
hc ^= nameTable.get(key).hashCode();
}
return hc;
}
/**
* Creates an Enumeration implementation that enumerates all the
* modes stored in this context map and in the nested context maps.
*/
static private class Enumerator implements Enumeration {
/**
* Store this context map root value.
*/
private Object rootValue;
/**
* Store this context map other value.
*/
private Object otherValue;
/**
* Stores the enumeration of modes of the current subMap.
*/
private Enumeration subMapValues;
/**
* Stores the ContextMap objects from the nameTable.
*/
private final Enumeration subMaps;
private Enumerator(ContextMap map) {
rootValue = map.rootValue;
otherValue = map.otherValue;
subMaps = map.nameTable.elements();
}
/**
* Advance to the next context map values
* in subMapValues and to the next element
* in subMap enumeration, if needed.
*/
private void prep() {
while ((subMapValues == null || !subMapValues.hasMoreElements()) && subMaps.hasMoreElements())
subMapValues = ((ContextMap)subMaps.nextElement()).values();
}
/**
* True if we have more elements.
*/
public boolean hasMoreElements() {
prep();
return rootValue != null || otherValue != null || (subMapValues != null && subMapValues.hasMoreElements());
}
/**
* Get the next element (mode in this case).
*/
public Object nextElement() {
if (rootValue != null) {
Object tem = rootValue;
rootValue = null;
return tem;
}
if (otherValue != null) {
Object tem = otherValue;
otherValue = null;
return tem;
}
prep();
if (subMapValues == null)
throw new NoSuchElementException();
return subMapValues.nextElement();
}
}
/**
* Get an enumeration with all the modes in this context map.
* @return An enumeration containing Mode objects.
*/
Enumeration values() {
return new Enumerator(this);
}
}