Added a convenient toString implementation for multimaps.
[jsvc.git] / src / dolda / jsvc / util / WrappedMultiMap.java
CommitLineData
78f5d120
FT
1package dolda.jsvc.util;
2
3import dolda.jsvc.MultiMap;
4import java.util.*;
5
6public class WrappedMultiMap<K, V> implements MultiMap<K, V> {
7 private Map<K, Collection<V>> bk;
8 private EntrySet entryset;
9 private Values values;
10
11 public WrappedMultiMap(Map<K, Collection<V>> bk) {
12 this.bk = bk;
13 }
14
15 private V get1(Collection<V> vs) {
16 if(vs == null)
17 return(null);
18 Iterator<V> i = vs.iterator();
19 if(!i.hasNext())
20 return(null);
21 return(i.next());
22 }
23
24 public void clear() {
25 modified();
26 bk.clear();
27 }
28
29 public boolean containsKey(Object key) {
30 Collection<V> vs = bk.get(key);
31 if(vs == null)
32 return(false);
33 return(!vs.isEmpty());
34 }
35
36 public boolean equals(Object o) {
37 return(bk.equals(o));
38 }
39
40 public V get(Object key) {
41 return(get1(bk.get(key)));
42 }
43
44 public Collection<V> values(K key) {
45 Collection<V> vs = bk.get(key);
46 if(vs == null) {
47 vs = new LinkedList<V>();
48 bk.put(key, vs);
49 }
50 return(vs);
51 }
52
53 public int hashCode() {
54 return(bk.hashCode());
55 }
56
57 public boolean isEmpty() {
58 return(values().isEmpty());
59 }
60
61 public Set<K> keySet() {
62 return(bk.keySet());
63 }
64
65 public V put(K key, V value) {
66 Collection<V> vs = new LinkedList<V>();
67 vs.add(value);
68 modified();
69 return(get1(bk.put(key, vs)));
70 }
71
72 public void add(K key, V value) {
73 modified();
74 values(key).add(value);
75 }
76
77 public Collection<V> putValues(K key, Collection<V> values) {
78 modified();
79 return(bk.put(key, values));
80 }
81
82 private class DumbEntry implements Map.Entry<K, V> {
83 private K key;
84 private V value;
85
86 public DumbEntry(K key, V value) {
87 this.key = key;
88 this.value = value;
89 }
90
91 public boolean equals(Object o) {
92 if(!(o instanceof Map.Entry))
93 return(false);
94 Map.Entry oe = (Map.Entry)o;
95 return(((key == null)?(oe.getKey() == null):key.equals(oe.getKey())) &&
96 ((value == null)?(oe.getValue() == null):value.equals(oe.getValue())));
97 }
98
99 public K getKey() {
100 return(key);
101 }
102
103 public V getValue() {
104 return(value);
105 }
106
107 public int hashCode() {
108 return(key.hashCode() + value.hashCode());
109 }
110
111 public V setValue(V value) {
112 throw(new UnsupportedOperationException());
113 }
114 }
115
116 private class EntrySet extends AbstractSet<Map.Entry<K, V>> {
117 public Iterator<Map.Entry<K, V>> iterator() {
118 return(new Iterator<Map.Entry<K, V>>() {
119 private Iterator<Map.Entry<K, Collection<V>>> bki = bk.entrySet().iterator();
120 private K curkey;
121 private Iterator<V> vsi = null;
122
123 public boolean hasNext() {
124 if((vsi != null) && vsi.hasNext())
125 return(true);
126 return(bki.hasNext());
127 }
128
129 public Map.Entry<K, V> next() {
130 if((vsi == null) || !vsi.hasNext()) {
131 Map.Entry<K, Collection<V>> ne = bki.next();
132 curkey = ne.getKey();
133 vsi = ne.getValue().iterator();
134 }
135 return(new DumbEntry(curkey, vsi.next()));
136 }
137
138 public void remove() {
139 modified();
140 vsi.remove();
141 }
142 });
143 }
144
145 public int size() {
146 return(WrappedMultiMap.this.size());
147 }
148
149 public boolean remove(Object o) {
150 modified();
151 return(WrappedMultiMap.this.remove(o) != null);
152 }
153
154 public void clear() {
155 modified();
156 bk.clear();
157 }
158 }
159
160 private class Values extends AbstractCollection<V> {
161 public Iterator<V> iterator() {
162 return(new Iterator<V>() {
163 Iterator<Map.Entry<K, V>> bki = WrappedMultiMap.this.entrySet().iterator();
164
165 public boolean hasNext() {
166 return(bki.hasNext());
167 }
168
169 public V next() {
170 return(bki.next().getValue());
171 }
172
173 public void remove() {
174 modified();
175 bki.remove();
176 }
177 });
178 }
179
180 public int size() {
181 return(WrappedMultiMap.this.size());
182 }
183
184 public boolean contains(Object o) {
185 return(containsValue(o));
186 }
187
188 public void clear() {
189 modified();
190 bk.clear();
191 }
192 }
193
194 public Set<Map.Entry<K, V>> entrySet() {
195 if(entryset == null)
196 entryset = new EntrySet();
197 return(entryset);
198 }
199
200 public Collection<V> values() {
201 if(values == null)
202 values = new Values();
203 return(values);
204 }
205
206 public void putAll(Map<? extends K, ? extends V> m) {
207 modified();
208 for(Map.Entry<? extends K, ? extends V> e : m.entrySet())
209 add(e.getKey(), e.getValue());
210 }
211
212 public V remove(Object key) {
213 modified();
214 return(get1(bk.remove(key)));
215 }
216
217 public boolean containsValue(Object value) {
218 for(Collection<V> vs : bk.values()) {
219 if(vs.contains(value))
220 return(true);
221 }
222 return(false);
223 }
224
225 public int size() {
226 int i = 0;
227 for(Collection<V> vs : bk.values())
228 i += vs.size();
229 return(i);
230 }
231
232 protected void modified() {}
eb0e45b7
FT
233
234 public String toString() {
235 StringBuilder buf = new StringBuilder();
236 buf.append("{\n");
237 for(Map.Entry<K, V> e : entrySet()) {
238 buf.append("\t");
239 buf.append(e.getKey().toString());
240 buf.append(" = \"");
241 buf.append(e.getValue().toString());
242 buf.append("\",\n");
243 }
244 buf.append("}\n");
245 return(buf.toString());
246 }
78f5d120 247}