Package: CaseInsensitiveMap

CaseInsensitiveMap

nameinstructionbranchcomplexitylinemethod
CaseInsensitiveMap()
M: 0 C: 8
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 3
100%
M: 0 C: 1
100%
CaseInsensitiveMap(CaseInsensitiveMap)
M: 0 C: 13
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 4
100%
M: 0 C: 1
100%
clear()
M: 0 C: 4
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 2
100%
M: 0 C: 1
100%
containsKey(Object)
M: 0 C: 11
100%
M: 0 C: 2
100%
M: 0 C: 2
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
containsValue(Object)
M: 0 C: 5
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
entrySet()
M: 0 C: 8
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
get(Object)
M: 0 C: 11
100%
M: 0 C: 2
100%
M: 0 C: 2
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
keySet()
M: 0 C: 7
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
put(String, Object)
M: 0 C: 14
100%
M: 0 C: 2
100%
M: 0 C: 2
100%
M: 0 C: 3
100%
M: 0 C: 1
100%
remove(Object)
M: 0 C: 11
100%
M: 0 C: 2
100%
M: 0 C: 2
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
size()
M: 0 C: 4
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
values()
M: 0 C: 4
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%

Coverage

1: /*******************************************************************************
2: * Copyright (c) 2008, 2010 VMware Inc.
3: * All rights reserved. This program and the accompanying materials
4: * are made available under the terms of the Eclipse Public License v1.0
5: * which accompanies this distribution, and is available at
6: * http://www.eclipse.org/legal/epl-v10.html
7: *
8: * Contributors:
9: * VMware Inc. - initial contribution
10: *******************************************************************************/
11:
12: package org.eclipse.virgo.util.common;
13:
14: import java.util.AbstractMap;
15: import java.util.AbstractSet;
16: import java.util.Collection;
17: import java.util.Iterator;
18: import java.util.Map;
19: import java.util.Set;
20: import java.util.concurrent.ConcurrentHashMap;
21:
22: /**
23: * {@link CaseInsensitiveMap} is a {@link Map} from <code>String</code> keys to values which is case-insensitive and
24: * case-preserving with respect to the keys in the map.
25: * <p />
26: *
27: * <strong>Concurrent Semantics</strong><br />
28: *
29: * This class is not necessarily thread safe.
30: *
31: * @param <V> range type parameter
32: */
33: public class CaseInsensitiveMap<V> extends AbstractMap<String, V> {
34:
35: private final Map<CaseInsensitiveKey, V> map = new ConcurrentHashMap<CaseInsensitiveKey, V>();
36:
37: private static final class KeySet extends AbstractSet<String> {
38:
39: private static final class KeySetIterator implements Iterator<String> {
40:
41: private Iterator<CaseInsensitiveKey> iterator;
42:
43: public KeySetIterator(Iterator<CaseInsensitiveKey> iterator) {
44: this.iterator = iterator;
45: }
46:
47: /**
48: * {@inheritDoc}
49: */
50: public boolean hasNext() {
51: return this.iterator.hasNext();
52: }
53:
54: /**
55: * {@inheritDoc}
56: */
57: public String next() {
58: return this.iterator.next().toString();
59: }
60:
61: /**
62: * {@inheritDoc}
63: */
64: public void remove() {
65: this.iterator.remove();
66: }
67: }
68:
69: private final Set<CaseInsensitiveKey> keySet;
70:
71: public KeySet(Set<CaseInsensitiveKey> keySet) {
72: this.keySet = keySet;
73: }
74:
75: /**
76: * Not supported for sets returned by <code>Map.keySet</code>.
77: */
78: @Override
79: public boolean add(String o) {
80: throw new UnsupportedOperationException("Map.keySet must return a Set which does not support add");
81: }
82:
83: /**
84: * Not supported for sets returned by <code>Map.keySet</code>.
85: */
86: @Override
87: public boolean addAll(Collection<? extends String> c) {
88: throw new UnsupportedOperationException("Map.keySet must return a Set which does not support addAll");
89: }
90:
91: /**
92: * {@inheritDoc}
93: */
94: @Override
95: public void clear() {
96: this.keySet.clear();
97: }
98:
99: /**
100: * {@inheritDoc}
101: */
102: @Override
103: public boolean contains(Object o) {
104: return o instanceof String ? this.keySet.contains(CaseInsensitiveKey.objectToKey(o)) : false;
105: }
106:
107: /**
108: * {@inheritDoc}
109: */
110: @Override
111: public Iterator<String> iterator() {
112: return new KeySetIterator(this.keySet.iterator());
113: }
114:
115: /**
116: * {@inheritDoc}
117: */
118: @Override
119: public boolean remove(Object o) {
120: // The following can throw ClassCastException which conforms to the method specification.
121: return this.keySet.remove(CaseInsensitiveKey.objectToKey(o));
122: }
123:
124: /**
125: * {@inheritDoc}
126: */
127: @Override
128: public int size() {
129: return this.keySet.size();
130: }
131:
132: }
133:
134: private static final class EntrySet<V> extends AbstractSet<Entry<String, V>> {
135:
136: private static final class MapEntry<V> implements Entry<String, V> {
137:
138: private final Entry<CaseInsensitiveMap.CaseInsensitiveKey, V> entry;
139:
140: public MapEntry(Entry<CaseInsensitiveMap.CaseInsensitiveKey, V> entry) {
141: this.entry = entry;
142: }
143:
144: /**
145: * {@inheritDoc}
146: */
147: public String getKey() {
148: return this.entry.getKey().toString();
149: }
150:
151: /**
152: * {@inheritDoc}
153: */
154: public V getValue() {
155: return this.entry.getValue();
156: }
157:
158: /**
159: * {@inheritDoc}
160: */
161: public V setValue(V value) {
162: return this.entry.setValue(value);
163: }
164:
165: /**
166: * Get the underlying {@link Map.Entry}.
167: *
168: * @return the underlying <code>Entry</code>
169: */
170: public Entry<CaseInsensitiveMap.CaseInsensitiveKey, V> getEntry() {
171: return this.entry;
172: }
173: }
174:
175: private static final class EntrySetIterator<V> implements Iterator<Entry<String, V>> {
176:
177: private final Iterator<Entry<CaseInsensitiveKey, V>> iterator;
178:
179: public EntrySetIterator(Iterator<Entry<CaseInsensitiveKey, V>> iterator) {
180: this.iterator = iterator;
181: }
182:
183: /**
184: * {@inheritDoc}
185: */
186: public boolean hasNext() {
187: return this.iterator.hasNext();
188: }
189:
190: /**
191: * {@inheritDoc}
192: */
193: public Entry<String, V> next() {
194: return new MapEntry<V>(this.iterator.next());
195: }
196:
197: /**
198: * {@inheritDoc}
199: */
200: public void remove() {
201: this.iterator.remove();
202: }
203: }
204:
205: private final Set<Entry<CaseInsensitiveKey, V>> entrySet;
206:
207: private final CaseInsensitiveMap<V> map;
208:
209: public EntrySet(Set<Entry<CaseInsensitiveKey, V>> entrySet, CaseInsensitiveMap<V> map) {
210: this.entrySet = entrySet;
211: this.map = map;
212: }
213:
214: /**
215: * Not supported for sets returned by <code>Map.entrySet</code>.
216: */
217: @Override
218: public boolean add(Entry<String, V> o) {
219: throw new UnsupportedOperationException("Map.entrySet must return a Set which does not support add");
220: }
221:
222: /**
223: * Not supported for sets returned by <code>Map.entrySet</code>.
224: */
225: @Override
226: public boolean addAll(Collection<? extends Entry<String, V>> c) {
227: throw new UnsupportedOperationException("Map.entrySet must return a Set which does not support addAll");
228: }
229:
230: /**
231: * {@inheritDoc}
232: */
233: @Override
234: public void clear() {
235: this.entrySet.clear();
236: }
237:
238: /**
239: * {@inheritDoc}
240: */
241: @SuppressWarnings("unchecked")
242: @Override
243: public boolean contains(Object o) {
244: if (o instanceof Entry) {
245: Entry<String, V> e = (Entry<String, V>) o;
246: V value = this.map.get(e.getKey());
247: return value.equals(e.getValue());
248: }
249: return false;
250: }
251:
252: /**
253: * {@inheritDoc}
254: */
255: @Override
256: public Iterator<Entry<String, V>> iterator() {
257: return new EntrySetIterator<V>(this.entrySet.iterator());
258: }
259:
260: /**
261: * {@inheritDoc}
262: */
263: @SuppressWarnings("unchecked")
264: @Override
265: public boolean remove(Object o) {
266: try {
267: return this.entrySet.remove(((MapEntry<V>) o).getEntry());
268: } catch (ClassCastException e) {
269: }
270: return false;
271: }
272:
273: /**
274: * {@inheritDoc}
275: */
276: @Override
277: public int size() {
278: return this.entrySet.size();
279: }
280:
281: }
282:
283: static final class CaseInsensitiveKey {
284:
285: private final String key;
286:
287: private CaseInsensitiveKey(String key) {
288: this.key = key;
289: }
290:
291: /**
292: * {@inheritDoc}
293: */
294: @Override
295: public int hashCode() {
296: final int prime = 31;
297: int result = 1;
298: result = prime * result + key.toLowerCase().hashCode();
299: return result;
300: }
301:
302: /**
303: * {@inheritDoc}
304: */
305: @Override
306: public boolean equals(Object obj) {
307: if (this == obj) {
308: return true;
309: }
310: if (obj == null) {
311: return false;
312: }
313: if (getClass() != obj.getClass()) {
314: return false;
315: }
316: CaseInsensitiveKey other = (CaseInsensitiveKey) obj;
317: if (key == null) {
318: if (other.key != null) {
319: return false;
320: }
321: } else if (!key.equalsIgnoreCase(other.key)) {
322: return false;
323: }
324: return true;
325: }
326:
327: /**
328: * {@inheritDoc}
329: */
330: @Override
331: public String toString() {
332: return key;
333: }
334:
335: /**
336: * Convert the given key <code>Object</code> to a {@link CaseInsensitiveKey}.
337: * <p/>
338: * Pre-condition: <code>key</code> instanceof <code>String</code>
339: *
340: * @param key the key to be converted
341: * @return the <code>CaseInsensitiveKey</code> corresponding to the given key
342: */
343: public static CaseInsensitiveKey objectToKey(Object key) {
344: return new CaseInsensitiveKey((String) key);
345: }
346:
347: }
348:
349: public CaseInsensitiveMap() {
350: }
351:
352: public CaseInsensitiveMap(CaseInsensitiveMap<? extends V> map) {
353: this.map.putAll(map.map);
354: }
355: /**
356: * {@inheritDoc}
357: */
358: @Override
359: public void clear() {
360: this.map.clear();
361: }
362:
363: /**
364: * {@inheritDoc}
365: */
366: @Override
367: public boolean containsKey(Object key) {
368:• return key instanceof String ? this.map.containsKey(CaseInsensitiveKey.objectToKey(key)) : false;
369: }
370:
371: /**
372: * {@inheritDoc}
373: */
374: @Override
375: public boolean containsValue(Object value) {
376: return this.map.containsValue(value);
377: }
378:
379: /**
380: * {@inheritDoc}
381: */
382: @Override
383: public Set<Entry<String, V>> entrySet() {
384: return new EntrySet<V>(this.map.entrySet(), this);
385: }
386:
387: /**
388: * {@inheritDoc}
389: */
390: @Override
391: public V get(Object key) {
392:• return key instanceof String ? this.map.get(CaseInsensitiveKey.objectToKey(key)) : null;
393: }
394:
395: /**
396: * {@inheritDoc}
397: */
398: @Override
399: public Set<String> keySet() {
400: return new KeySet(this.map.keySet());
401: }
402:
403: /**
404: * {@inheritDoc}
405: */
406: @Override
407: public V put(String key, V value) {
408:• if (key == null) {
409: throw new NullPointerException("CaseInsensitiveMap does not permit null keys");
410: }
411: return this.map.put(CaseInsensitiveKey.objectToKey(key), value);
412: }
413:
414: /**
415: * {@inheritDoc}
416: */
417: @Override
418: public V remove(Object key) {
419:• return key instanceof String ? this.map.remove(CaseInsensitiveKey.objectToKey(key)) : null;
420: }
421:
422: /**
423: * {@inheritDoc}
424: */
425: @Override
426: public int size() {
427: return this.map.size();
428: }
429:
430: /**
431: * {@inheritDoc}
432: */
433: @Override
434: public Collection<V> values() {
435: return this.map.values();
436: }
437:
438: }