001 package com.thaiopensource.validate.nrl; 002 003 import com.thaiopensource.util.Equal; 004 005 import java.util.Vector; 006 import java.util.Hashtable; 007 import java.util.Enumeration; 008 import java.util.NoSuchElementException; 009 010 class ContextMap { 011 private Object rootValue; 012 private Object otherValue; 013 private final Hashtable nameTable = new Hashtable(); 014 015 Object get(Vector context) { 016 return get(context, context.size()); 017 } 018 019 boolean put(boolean isRoot, Vector names, Object value) { 020 return put(isRoot, names, names.size(), value); 021 } 022 023 private Object get(Vector context, int len) { 024 if (len > 0) { 025 ContextMap nestedMap = (ContextMap)nameTable.get(context.elementAt(len - 1)); 026 if (nestedMap != null) { 027 Object value = nestedMap.get(context, len - 1); 028 if (value != null) 029 return value; 030 } 031 } 032 if (rootValue != null && len == 0) 033 return rootValue; 034 return otherValue; 035 } 036 037 private boolean put(boolean isRoot, Vector names, int len, Object value) { 038 if (len == 0) { 039 if (isRoot) { 040 if (rootValue != null) 041 return false; 042 rootValue = value; 043 } 044 else { 045 if (otherValue != null) 046 return false; 047 otherValue = value; 048 } 049 return true; 050 } 051 else { 052 Object name = names.elementAt(len - 1); 053 ContextMap nestedMap = (ContextMap)nameTable.get(name); 054 if (nestedMap == null) { 055 nestedMap = new ContextMap(); 056 nameTable.put(name, nestedMap); 057 } 058 return nestedMap.put(isRoot, names, len - 1, value); 059 } 060 } 061 062 public boolean equals(Object obj) { 063 if (!(obj instanceof ContextMap)) 064 return false; 065 ContextMap other = (ContextMap)obj; 066 if (!Equal.equal(this.rootValue, other.rootValue) 067 || !Equal.equal(this.otherValue, other.otherValue)) 068 return false; 069 // We want jing to work with JDK 1.1 so we cannot use Hashtable.equals 070 if (this.nameTable.size() != other.nameTable.size()) 071 return false; 072 for (Enumeration e = nameTable.keys(); e.hasMoreElements();) { 073 Object key = e.nextElement(); 074 if (!nameTable.get(key).equals(other.nameTable.get(key))) 075 return false; 076 } 077 return true; 078 } 079 080 public int hashCode() { 081 int hc = 0; 082 if (rootValue != null) 083 hc ^= rootValue.hashCode(); 084 if (otherValue != null) 085 hc ^= otherValue.hashCode(); 086 for (Enumeration e = nameTable.keys(); e.hasMoreElements();) { 087 Object key = e.nextElement(); 088 hc ^= key.hashCode(); 089 hc ^= nameTable.get(key).hashCode(); 090 } 091 return hc; 092 } 093 094 static private class Enumerator implements Enumeration { 095 private Object rootValue; 096 private Object otherValue; 097 private Enumeration subMapValues; 098 private final Enumeration subMaps; 099 100 private Enumerator(ContextMap map) { 101 rootValue = map.rootValue; 102 otherValue = map.otherValue; 103 subMaps = map.nameTable.elements(); 104 } 105 106 private void prep() { 107 while ((subMapValues == null || !subMapValues.hasMoreElements()) && subMaps.hasMoreElements()) 108 subMapValues = ((ContextMap)subMaps.nextElement()).values(); 109 } 110 111 public boolean hasMoreElements() { 112 prep(); 113 return rootValue != null || otherValue != null || (subMapValues != null && subMapValues.hasMoreElements()); 114 } 115 116 public Object nextElement() { 117 if (rootValue != null) { 118 Object tem = rootValue; 119 rootValue = null; 120 return tem; 121 } 122 if (otherValue != null) { 123 Object tem = otherValue; 124 otherValue = null; 125 return tem; 126 } 127 prep(); 128 if (subMapValues == null) 129 throw new NoSuchElementException(); 130 return subMapValues.nextElement(); 131 } 132 } 133 134 Enumeration values() { 135 return new Enumerator(this); 136 } 137 }