1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.myfaces.util;
20
21 import java.util.AbstractMap;
22 import java.util.AbstractSet;
23 import java.util.Collection;
24 import java.util.Collections;
25 import java.util.Enumeration;
26 import java.util.Iterator;
27 import java.util.List;
28 import java.util.Map;
29 import java.util.NoSuchElementException;
30 import java.util.Set;
31
32
33
34
35
36
37
38 public abstract class AbstractThreadSafeAttributeMap<V> extends AbstractMap<String, V>
39 {
40 private Set<String> _keySet = new KeySet();
41 private Collection<V> _values = new Values();
42 private Set<Entry<String, V>> _entrySet = new EntrySet();
43
44 @Override
45 public void clear()
46 {
47 final List<String> names = Collections.list(getAttributeNames());
48
49 for (String name : names)
50 {
51 removeAttribute(name);
52 }
53 }
54
55 @Override
56 public final boolean containsKey(final Object key)
57 {
58 return getAttribute(key.toString()) != null;
59 }
60
61 @Override
62 public boolean containsValue(final Object findValue)
63 {
64 if (findValue == null)
65 {
66 return false;
67 }
68
69 for (final Enumeration<String> e = getAttributeNames(); e.hasMoreElements();)
70 {
71 final Object value = getAttribute(e.nextElement());
72 if (findValue.equals(value))
73 {
74 return true;
75 }
76 }
77
78 return false;
79 }
80
81 @Override
82 public Set<Entry<String, V>> entrySet()
83 {
84 return _entrySet;
85 }
86
87 @Override
88 public V get(final Object key)
89 {
90 return getAttribute(key.toString());
91 }
92
93 @Override
94 public boolean isEmpty()
95 {
96 return !getAttributeNames().hasMoreElements();
97 }
98
99 @Override
100 public Set<String> keySet()
101 {
102 return _keySet;
103 }
104
105 @Override
106 public final V put(final String key, final V value)
107 {
108 final V retval = getAttribute(key);
109 setAttribute(key, value);
110 return retval;
111 }
112
113 @Override
114 public void putAll(final Map<? extends String, ? extends V> t)
115 {
116 for (final Entry<? extends String, ? extends V> entry : t.entrySet())
117 {
118 setAttribute(entry.getKey(), entry.getValue());
119 }
120 }
121
122 @Override
123 public final V remove(final Object key)
124 {
125 final String keyString = key.toString();
126 final V retval = getAttribute(keyString);
127 removeAttribute(keyString);
128 return retval;
129 }
130
131 @Override
132 public int size()
133 {
134 int size = 0;
135 for (final Enumeration<String> e = getAttributeNames(); e.hasMoreElements();)
136 {
137 size++;
138 e.nextElement();
139 }
140 return size;
141 }
142
143 @Override
144 public Collection<V> values()
145 {
146 return _values;
147 }
148
149 abstract protected V getAttribute(String key);
150
151 abstract protected void setAttribute(String key, V value);
152
153 abstract protected void removeAttribute(String key);
154
155 abstract protected Enumeration<String> getAttributeNames();
156
157 private abstract class AbstractAttributeSet<E> extends AbstractSet<E>
158 {
159 @Override
160 public boolean isEmpty()
161 {
162 return AbstractThreadSafeAttributeMap.this.isEmpty();
163 }
164
165 @Override
166 public int size()
167 {
168 return AbstractThreadSafeAttributeMap.this.size();
169 }
170
171 @Override
172 public void clear()
173 {
174 AbstractThreadSafeAttributeMap.this.clear();
175 }
176 }
177
178 private final class KeySet extends AbstractAttributeSet<String>
179 {
180 @Override
181 public Iterator<String> iterator()
182 {
183 return new KeyIterator();
184 }
185
186 @Override
187 public boolean contains(final Object o)
188 {
189 return AbstractThreadSafeAttributeMap.this.containsKey(o);
190 }
191
192 @Override
193 public boolean remove(final Object o)
194 {
195 return AbstractThreadSafeAttributeMap.this.remove(o) != null;
196 }
197
198 }
199
200 private abstract class AbstractAttributeIterator<E> implements Iterator<E>
201 {
202
203
204
205
206
207
208 protected final Iterator<String> _i = Collections.list(getAttributeNames()).iterator();
209 protected String _currentKey;
210
211 public void remove()
212 {
213 if (_currentKey == null)
214 {
215 throw new NoSuchElementException("You must call next() at least once");
216 }
217 AbstractThreadSafeAttributeMap.this.remove(_currentKey);
218 }
219
220 public boolean hasNext()
221 {
222 return _i.hasNext();
223 }
224
225 public E next()
226 {
227 _currentKey = _i.next();
228 return getValue(_currentKey);
229 }
230
231 protected abstract E getValue(String attributeName);
232 }
233
234 private final class KeyIterator extends AbstractAttributeIterator<String>
235 {
236 @Override
237 protected String getValue(final String attributeName)
238 {
239 return attributeName;
240 }
241 }
242
243 private class Values extends AbstractAttributeSet<V>
244 {
245 @Override
246 public Iterator<V> iterator()
247 {
248 return new ValuesIterator();
249 }
250
251 @Override
252 public boolean contains(final Object o)
253 {
254 if (o == null)
255 {
256 return false;
257 }
258
259 for (final Iterator<V> it = iterator(); it.hasNext();)
260 {
261 if (o.equals(it.next()))
262 {
263 return true;
264 }
265 }
266
267 return false;
268 }
269
270 @Override
271 public boolean remove(final Object o)
272 {
273 if (o == null)
274 {
275 return false;
276 }
277
278 for (final Iterator<V> it = iterator(); it.hasNext();)
279 {
280 if (o.equals(it.next()))
281 {
282 it.remove();
283 return true;
284 }
285 }
286
287 return false;
288 }
289 }
290
291 private class ValuesIterator extends AbstractAttributeIterator<V>
292 {
293 @Override
294 protected V getValue(final String attributeName)
295 {
296 return AbstractThreadSafeAttributeMap.this.get(attributeName);
297 }
298 }
299
300 private final class EntrySet extends AbstractAttributeSet<Entry<String, V>>
301 {
302 @Override
303 public Iterator<Entry<String, V>> iterator()
304 {
305 return new EntryIterator();
306 }
307
308 @SuppressWarnings("unchecked")
309 @Override
310 public boolean contains(final Object o)
311 {
312 if (!(o instanceof Entry))
313 {
314 return false;
315 }
316
317 final Entry<String, V> entry = (Entry<String, V>)o;
318 final Object key = entry.getKey();
319 final Object value = entry.getValue();
320 if (key == null || value == null)
321 {
322 return false;
323 }
324
325 return value.equals(AbstractThreadSafeAttributeMap.this.get(key));
326 }
327
328 @SuppressWarnings("unchecked")
329 @Override
330 public boolean remove(final Object o)
331 {
332 if (!(o instanceof Entry))
333 {
334 return false;
335 }
336
337 final Entry<String, V> entry = (Entry<String, V>)o;
338 final Object key = entry.getKey();
339 final Object value = entry.getValue();
340 if (key == null || value == null || !value.equals(AbstractThreadSafeAttributeMap.this.get(key)))
341 {
342 return false;
343 }
344
345 return AbstractThreadSafeAttributeMap.this.remove(((Entry<String, V>)o).getKey()) != null;
346 }
347 }
348
349
350
351
352
353 private final class EntryIterator extends AbstractAttributeIterator<Entry<String, V>>
354 {
355 @Override
356 protected Entry<String, V> getValue(final String attributeName)
357 {
358
359
360 return new EntrySetEntry(attributeName);
361 }
362 }
363
364 private final class EntrySetEntry implements Entry<String, V>
365 {
366 private final String _currentKey;
367
368 public EntrySetEntry(final String currentKey)
369 {
370 _currentKey = currentKey;
371 }
372
373 public String getKey()
374 {
375 return _currentKey;
376 }
377
378 public V getValue()
379 {
380 return AbstractThreadSafeAttributeMap.this.get(_currentKey);
381 }
382
383 public V setValue(final V value)
384 {
385 return AbstractThreadSafeAttributeMap.this.put(_currentKey, value);
386 }
387
388 @Override
389 public int hashCode()
390 {
391 int result = 1;
392 result = 31 * result + ((_currentKey == null) ? 0 : _currentKey.hashCode());
393 return result;
394 }
395
396 @Override
397 public boolean equals(final Object obj)
398 {
399 if (this == obj)
400 {
401 return true;
402 }
403 if (obj == null)
404 {
405 return false;
406 }
407 if (getClass() != obj.getClass())
408 {
409 return false;
410 }
411 final EntrySetEntry other = (EntrySetEntry)obj;
412 if (_currentKey == null)
413 {
414 if (other._currentKey != null)
415 {
416 return false;
417 }
418 }
419 else if (!_currentKey.equals(other._currentKey))
420 {
421 return false;
422 }
423 return true;
424 }
425
426 }
427 }