~ubuntu-branches/ubuntu/utopic/jing-trang/utopic

« back to all changes in this revision

Viewing changes to mod/nvdl/src/main/com/thaiopensource/validate/nvdl/ContextMap.java

  • Committer: Bazaar Package Importer
  • Author(s): Samuel Thibault
  • Date: 2009-09-01 15:53:03 UTC
  • Revision ID: james.westby@ubuntu.com-20090901155303-2kweef05h5v9j3ni
Tags: upstream-20090818
ImportĀ upstreamĀ versionĀ 20090818

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
package com.thaiopensource.validate.nvdl;
 
2
 
 
3
import com.thaiopensource.util.Equal;
 
4
 
 
5
import java.util.Vector;
 
6
import java.util.Hashtable;
 
7
import java.util.Enumeration;
 
8
import java.util.NoSuchElementException;
 
9
 
 
10
/**
 
11
 * Keeps modes depending on context.
 
12
 * The structure of the context map is
 
13
 * 
 
14
 * stores the mode for 
 
15
 *  /  in rootValue
 
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.
 
19
 * 
 
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
 
23
 * 
 
24
 * Addind also /a/b and mode y will give
 
25
 * 
 
26
 * ContextMap b ---> ContextMap a ---> ContextMap (otherValue=x, rootValue=y)
 
27
 * 
 
28
 * Adding a2/b and mode w will give
 
29
 * 
 
30
 *  ContextMap b ---> ContextMap a ---> ContextMap (otherValue=x, rootValue=y)
 
31
 *                              a2 ---> ContextMap otherValue=w
 
32
 */
 
33
class ContextMap {
 
34
  /**
 
35
   * Stores the mode associated with an absolute path.
 
36
   */
 
37
  private Object rootValue;
 
38
  /**
 
39
   * Stores a mode associated with a relative path.
 
40
   */
 
41
  private Object otherValue;
 
42
  /**
 
43
   * Stores a hash map with with the key the last local name and 
 
44
   * as values other ContextMap objects.
 
45
   */
 
46
  private final Hashtable nameTable = new Hashtable();
 
47
 
 
48
  /**
 
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.
 
57
   */  
 
58
  Object get(Vector context) {
 
59
    return get(context, context.size());
 
60
  }
 
61
  
 
62
  /**
 
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.
 
68
   */
 
69
  boolean put(boolean isRoot, Vector names, Object value) {
 
70
    return put(isRoot, names, names.size(), value);
 
71
  }
 
72
 
 
73
  /**
 
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.
 
83
   */
 
84
  private Object get(Vector context, int len) {
 
85
    if (len > 0) {
 
86
      ContextMap nestedMap = (ContextMap)nameTable.get(context.elementAt(len - 1));
 
87
      if (nestedMap != null) {
 
88
        Object value = nestedMap.get(context, len - 1);
 
89
        if (value != null)
 
90
          return value;
 
91
      }
 
92
    }
 
93
    if (rootValue != null && len == 0)
 
94
      return rootValue;
 
95
    return otherValue;
 
96
  }
 
97
 
 
98
  /**
 
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.
 
105
   */
 
106
  private boolean put(boolean isRoot, Vector names, int len, Object value) {
 
107
    if (len == 0) {
 
108
      // if we have only /
 
109
      if (isRoot) {
 
110
        if (rootValue != null)
 
111
          return false;
 
112
        rootValue = value;
 
113
      }
 
114
      // We followed all the paths, it is not root, 
 
115
      // then we store the mode as the other value.
 
116
      else {
 
117
        if (otherValue != null)
 
118
          return false;
 
119
        otherValue = value;
 
120
      }
 
121
      return true;
 
122
    }
 
123
    else {
 
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);
 
132
      }
 
133
      // Add the rest of the path names in the nested context map.
 
134
      return nestedMap.put(isRoot, names, len - 1, value);
 
135
    }
 
136
  }
 
137
 
 
138
  /**
 
139
   * Chek that this context map is equals with
 
140
   * a specified context map.
 
141
   */
 
142
  public boolean equals(Object obj) {
 
143
    if (!(obj instanceof ContextMap))
 
144
      return false;
 
145
    ContextMap other = (ContextMap)obj;
 
146
    if (!Equal.equal(this.rootValue, other.rootValue)
 
147
        || !Equal.equal(this.otherValue, other.otherValue))
 
148
      return false;
 
149
    // We want jing to work with JDK 1.1 so we cannot use Hashtable.equals
 
150
    if (this.nameTable.size() != other.nameTable.size())
 
151
      return false;
 
152
    for (Enumeration e = nameTable.keys(); e.hasMoreElements();) {
 
153
      Object key = e.nextElement();
 
154
      if (!nameTable.get(key).equals(other.nameTable.get(key)))
 
155
        return false;
 
156
    }
 
157
    return true;
 
158
  }
 
159
 
 
160
  /**
 
161
   * Get a hashcode for this context map.
 
162
   */
 
163
  public int hashCode() {
 
164
    int hc = 0;
 
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();
 
173
    }
 
174
    return hc;
 
175
  }
 
176
 
 
177
  /**
 
178
   * Creates an Enumeration implementation that enumerates all the 
 
179
   * modes stored in this context map and in the nested context maps.
 
180
   */
 
181
  static private class Enumerator implements Enumeration {
 
182
    /**
 
183
     * Store this context map root value.
 
184
     */
 
185
    private Object rootValue;
 
186
    
 
187
    /**
 
188
     * Store this context map other value.
 
189
     */
 
190
    private Object otherValue;
 
191
    
 
192
    /**
 
193
     * Stores the enumeration of modes of the current subMap.
 
194
     */
 
195
    private Enumeration subMapValues;
 
196
    
 
197
    /**
 
198
     * Stores the ContextMap objects from the nameTable.
 
199
     */
 
200
    private final Enumeration subMaps;
 
201
 
 
202
    private Enumerator(ContextMap map) {
 
203
      rootValue = map.rootValue;
 
204
      otherValue = map.otherValue;
 
205
      subMaps = map.nameTable.elements();
 
206
    }
 
207
 
 
208
    /**
 
209
     * Advance to the next context map values
 
210
     * in subMapValues and to the next element 
 
211
     * in subMap enumeration, if needed.
 
212
     */
 
213
    private void prep() {
 
214
      while ((subMapValues == null || !subMapValues.hasMoreElements()) && subMaps.hasMoreElements())
 
215
        subMapValues = ((ContextMap)subMaps.nextElement()).values();
 
216
    }
 
217
 
 
218
    /**
 
219
     * True if we have more elements.
 
220
     */
 
221
    public boolean hasMoreElements() {
 
222
      prep();
 
223
      return rootValue != null || otherValue != null || (subMapValues != null && subMapValues.hasMoreElements());
 
224
    }
 
225
 
 
226
    /**
 
227
     * Get the next element (mode in this case).
 
228
     */
 
229
    public Object nextElement() {
 
230
      if (rootValue != null) {
 
231
        Object tem = rootValue;
 
232
        rootValue = null;
 
233
        return tem;
 
234
      }
 
235
      if (otherValue != null) {
 
236
        Object tem = otherValue;
 
237
        otherValue = null;
 
238
        return tem;
 
239
      }
 
240
      prep();
 
241
      if (subMapValues == null)
 
242
        throw new NoSuchElementException();
 
243
      return subMapValues.nextElement();
 
244
    }
 
245
  }
 
246
 
 
247
  /**
 
248
   * Get an enumeration with all the modes in this context map.
 
249
   * @return An enumeration containing Mode objects.
 
250
   */
 
251
  Enumeration values() {
 
252
    return new Enumerator(this);
 
253
  }
 
254
}