1
package com.thaiopensource.validate.nvdl;
3
import com.thaiopensource.util.Equal;
5
import java.util.Vector;
6
import java.util.Hashtable;
7
import java.util.Enumeration;
8
import java.util.NoSuchElementException;
11
* Keeps modes depending on context.
12
* The structure of the context map is
16
* "" in otherValue (this is for relative paths)
17
* stores a hash with the last path elements as key and
18
* ContextMap objects as values.
20
* A path like a/b and mode x
21
* will be represented by 3 ContextMap objects
22
* ContextMap b ---> ContextMap a ---> ContextMap otherValue=x
24
* Addind also /a/b and mode y will give
26
* ContextMap b ---> ContextMap a ---> ContextMap (otherValue=x, rootValue=y)
28
* Adding a2/b and mode w will give
30
* ContextMap b ---> ContextMap a ---> ContextMap (otherValue=x, rootValue=y)
31
* a2 ---> ContextMap otherValue=w
35
* Stores the mode associated with an absolute path.
37
private Object rootValue;
39
* Stores a mode associated with a relative path.
41
private Object otherValue;
43
* Stores a hash map with with the key the last local name and
44
* as values other ContextMap objects.
46
private final Hashtable nameTable = new Hashtable();
49
* Get the mode matching a list of local names.
50
* A root more returned means an exact matching of the given local names
51
* with the local names from the context map. Otherwise we can get either
52
* a mode stored as otherValue or null if the given context does not match
53
* any of the stored paths.
54
* @param context The list of local names that represent a section context
55
* (path from root local element names from the same namespace).
56
* @return A mode or null.
58
Object get(Vector context) {
59
return get(context, context.size());
63
* Adds a single path (isRoot, names) and a mode to be used for this path = context.
64
* @param isRoot True if the path starts with /
65
* @param names The local names that form the path.
66
* @param value The mode.
67
* @return true if there is no duplicate path, false otherwise.
69
boolean put(boolean isRoot, Vector names, Object value) {
70
return put(isRoot, names, names.size(), value);
74
* Get the mode matching a list of local names.
75
* A root more returned means an exact matching of the given local names
76
* with the local names from the context map. Otherwise we can get either
77
* a mode stored as otherValue or null if the given context does not match
78
* any of the stored paths.
79
* @param context The list of local names that represent a section context
80
* (path from root local element names from the same namespace).
81
* @param len The lenght we should take from the list.
82
* @return A mode or null.
84
private Object get(Vector context, int len) {
86
ContextMap nestedMap = (ContextMap)nameTable.get(context.elementAt(len - 1));
87
if (nestedMap != null) {
88
Object value = nestedMap.get(context, len - 1);
93
if (rootValue != null && len == 0)
99
* Adds a single path (isRoot, names) and a mode to be used for this path = context.
100
* @param isRoot True if the path starts with /
101
* @param names The local names that form the path.
102
* @param len The length if the names vector.
103
* @param value The mode.
104
* @return true if there is no duplicate path, false otherwise.
106
private boolean put(boolean isRoot, Vector names, int len, Object value) {
110
if (rootValue != null)
114
// We followed all the paths, it is not root,
115
// then we store the mode as the other value.
117
if (otherValue != null)
124
// get the last local name from the path
125
Object name = names.elementAt(len - 1);
126
// Get the context map mapped in nameTable to that name.
127
ContextMap nestedMap = (ContextMap)nameTable.get(name);
128
// Not preset then create it.
129
if (nestedMap == null) {
130
nestedMap = new ContextMap();
131
nameTable.put(name, nestedMap);
133
// Add the rest of the path names in the nested context map.
134
return nestedMap.put(isRoot, names, len - 1, value);
139
* Chek that this context map is equals with
140
* a specified context map.
142
public boolean equals(Object obj) {
143
if (!(obj instanceof ContextMap))
145
ContextMap other = (ContextMap)obj;
146
if (!Equal.equal(this.rootValue, other.rootValue)
147
|| !Equal.equal(this.otherValue, other.otherValue))
149
// We want jing to work with JDK 1.1 so we cannot use Hashtable.equals
150
if (this.nameTable.size() != other.nameTable.size())
152
for (Enumeration e = nameTable.keys(); e.hasMoreElements();) {
153
Object key = e.nextElement();
154
if (!nameTable.get(key).equals(other.nameTable.get(key)))
161
* Get a hashcode for this context map.
163
public int hashCode() {
165
if (rootValue != null)
166
hc ^= rootValue.hashCode();
167
if (otherValue != null)
168
hc ^= otherValue.hashCode();
169
for (Enumeration e = nameTable.keys(); e.hasMoreElements();) {
170
Object key = e.nextElement();
171
hc ^= key.hashCode();
172
hc ^= nameTable.get(key).hashCode();
178
* Creates an Enumeration implementation that enumerates all the
179
* modes stored in this context map and in the nested context maps.
181
static private class Enumerator implements Enumeration {
183
* Store this context map root value.
185
private Object rootValue;
188
* Store this context map other value.
190
private Object otherValue;
193
* Stores the enumeration of modes of the current subMap.
195
private Enumeration subMapValues;
198
* Stores the ContextMap objects from the nameTable.
200
private final Enumeration subMaps;
202
private Enumerator(ContextMap map) {
203
rootValue = map.rootValue;
204
otherValue = map.otherValue;
205
subMaps = map.nameTable.elements();
209
* Advance to the next context map values
210
* in subMapValues and to the next element
211
* in subMap enumeration, if needed.
213
private void prep() {
214
while ((subMapValues == null || !subMapValues.hasMoreElements()) && subMaps.hasMoreElements())
215
subMapValues = ((ContextMap)subMaps.nextElement()).values();
219
* True if we have more elements.
221
public boolean hasMoreElements() {
223
return rootValue != null || otherValue != null || (subMapValues != null && subMapValues.hasMoreElements());
227
* Get the next element (mode in this case).
229
public Object nextElement() {
230
if (rootValue != null) {
231
Object tem = rootValue;
235
if (otherValue != null) {
236
Object tem = otherValue;
241
if (subMapValues == null)
242
throw new NoSuchElementException();
243
return subMapValues.nextElement();
248
* Get an enumeration with all the modes in this context map.
249
* @return An enumeration containing Mode objects.
251
Enumeration values() {
252
return new Enumerator(this);