001: /*
002: * The Apache Software License, Version 1.1
003: *
004: * Copyright (c) 2001-2004 Caucho Technology, Inc. All rights reserved.
005: *
006: * Redistribution and use in source and binary forms, with or without
007: * modification, are permitted provided that the following conditions
008: * are met:
009: *
010: * 1. Redistributions of source code must retain the above copyright
011: * notice, this list of conditions and the following disclaimer.
012: *
013: * 2. Redistributions in binary form must reproduce the above copyright
014: * notice, this list of conditions and the following disclaimer in
015: * the documentation and/or other materials provided with the
016: * distribution.
017: *
018: * 3. The end-user documentation included with the redistribution, if
019: * any, must include the following acknowlegement:
020: * "This product includes software developed by the
021: * Caucho Technology (http://www.caucho.com/)."
022: * Alternately, this acknowlegement may appear in the software itself,
023: * if and wherever such third-party acknowlegements normally appear.
024: *
025: * 4. The names "Hessian", "Resin", and "Caucho" must not be used to
026: * endorse or promote products derived from this software without prior
027: * written permission. For written permission, please contact
028: * info@caucho.com.
029: *
030: * 5. Products derived from this software may not be called "Resin"
031: * nor may "Resin" appear in their names without prior written
032: * permission of Caucho Technology.
033: *
034: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
035: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
036: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
037: * DISCLAIMED. IN NO EVENT SHALL CAUCHO TECHNOLOGY OR ITS CONTRIBUTORS
038: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
039: * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
040: * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
041: * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
042: * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
043: * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
044: * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
045: *
046: * @author Sam
047: */
048:
049: package com.caucho.portal.generic;
050:
051: import java.util.AbstractSet;
052: import java.util.Collection;
053: import java.util.HashMap;
054: import java.util.Iterator;
055: import java.util.Map;
056: import java.util.Set;
057: import java.util.logging.Logger;
058:
059: /**
060: * A Map that wraps another map and uses different keys in the wrapped
061: * map than the keys that are exposed.
062: *
063: * The constructor is passed the map to be wrapped, and a keyLinkMap
064: * that maps keys as they are used by users of the map to different keys that
065: * are really used in the wrapped map. If a key is used that is not int the
066: * keyLinkMap, the key is used unchanged in the wrapped map.
067: */
068: public class KeyLinkMap<K, V> implements Map<K, V> {
069: static protected final Logger log = Logger
070: .getLogger(KeyLinkMap.class.getName());
071:
072: private Map<K, K> _keyLinkMap;
073: private Map<K, K> _keyLinkReverseMap;
074: private Map<K, V> _map;
075:
076: private KeySet _keySet;
077: private EntrySet _entrySet;
078:
079: public static <K> Map<K, K> getReverseKeyLinkMap(
080: Map<K, K> keyLinkMap) {
081: Map<K, K> keyLinkReverseMap = new HashMap<K, K>();
082: Iterator<Map.Entry<K, K>> iter = keyLinkMap.entrySet()
083: .iterator();
084:
085: while (iter.hasNext()) {
086: Map.Entry<K, K> entry = iter.next();
087:
088: keyLinkReverseMap.put(entry.getValue(), entry.getKey());
089: }
090:
091: return keyLinkReverseMap;
092: }
093:
094: public KeyLinkMap(Map<K, V> map, Map<K, K> keyLinkMap,
095: Map<K, K> keyLinkReverseMap) {
096: _map = map;
097: _keyLinkMap = keyLinkMap;
098: _keyLinkReverseMap = keyLinkReverseMap;
099: }
100:
101: public int size() {
102: return _map.size();
103: }
104:
105: public boolean isEmpty() {
106: return _map.isEmpty();
107: }
108:
109: private K getMapKey(K key) {
110: K mapKey = key;
111:
112: if (_keyLinkMap != null) {
113: mapKey = _keyLinkMap.get(key);
114: if (mapKey == null)
115: mapKey = key;
116: }
117:
118: return mapKey;
119: }
120:
121: private K getReverseMapKey(K key) {
122: if (_keyLinkReverseMap == null)
123: return key;
124:
125: K mapKey = key;
126:
127: mapKey = _keyLinkReverseMap.get(key);
128:
129: if (mapKey == null)
130: mapKey = key;
131:
132: return mapKey;
133: }
134:
135: public boolean containsKey(Object key) {
136: return _map.containsKey(getMapKey((K) key));
137: }
138:
139: public V get(Object key) {
140: return _map.get(getMapKey((K) key));
141: }
142:
143: public Set<K> keySet() {
144: return _keySet == null ? (_keySet = new KeySet()) : _keySet;
145: }
146:
147: public Set<Map.Entry<K, V>> entrySet() {
148: return _entrySet == null ? (_entrySet = new EntrySet())
149: : _entrySet;
150: }
151:
152: public boolean containsValue(Object v) {
153: return _map.containsValue(v);
154: }
155:
156: public Collection<V> values() {
157: return _map.values();
158: }
159:
160: public V put(K key, V value) {
161: return _map.put(getMapKey(key), value);
162: }
163:
164: public void putAll(Map<? extends K, ? extends V> srcMap) {
165: Iterator<? extends Entry<? extends K, ? extends V>> iter = srcMap
166: .entrySet().iterator();
167:
168: while (iter.hasNext()) {
169: Map.Entry<? extends K, ? extends V> entry = iter.next();
170: put(entry.getKey(), entry.getValue());
171: }
172: }
173:
174: public V remove(Object key) {
175: return _map.remove(getMapKey((K) key));
176: }
177:
178: public void clear() {
179: _map.clear();
180: }
181:
182: private Iterator<K> newKeyIterator() {
183: if (_keyLinkMap == null)
184: return _map.keySet().iterator();
185: else
186: return new KeyIterator();
187:
188: }
189:
190: private Iterator<Map.Entry<K, V>> newEntryIterator() {
191: if (_keyLinkMap == null)
192: return _map.entrySet().iterator();
193: else
194: return new EntryIterator();
195: }
196:
197: private class KeySet extends AbstractSet<K> {
198: public Iterator<K> iterator() {
199: return newKeyIterator();
200: }
201:
202: public int size() {
203: return KeyLinkMap.this .size();
204: }
205:
206: public boolean contains(Object o) {
207: return KeyLinkMap.this .containsKey(o);
208: }
209:
210: public boolean remove(Object o) {
211: return KeyLinkMap.this .remove(o) != null;
212: }
213:
214: public void clear() {
215: KeyLinkMap.this .clear();
216: }
217: }
218:
219: private class EntrySet extends AbstractSet<Map.Entry<K, V>> {
220: public Iterator<Map.Entry<K, V>> iterator() {
221: return newEntryIterator();
222: }
223:
224: public boolean contains(Object o) {
225: if (!(o instanceof Map.Entry))
226: return false;
227:
228: Map.Entry<K, V> other = (Map.Entry<K, V>) o;
229:
230: V value = KeyLinkMap.this .get(other.getKey());
231:
232: if (value == null)
233: return other.getValue() == null;
234: else
235: return value.equals(other.getValue());
236: }
237:
238: public boolean remove(Object o) {
239: return KeyLinkMap.this .remove(o) != null;
240: }
241:
242: public int size() {
243: return KeyLinkMap.this .size();
244: }
245:
246: public void clear() {
247: KeyLinkMap.this .clear();
248: }
249: }
250:
251: private class KeyIterator implements Iterator<K> {
252: private Iterator<K> _iterator;
253:
254: KeyIterator() {
255: _iterator = _map.keySet().iterator();
256: }
257:
258: public boolean hasNext() {
259: return _iterator.hasNext();
260: }
261:
262: public K next() {
263: K next = _iterator.next();
264: K mapKey = KeyLinkMap.this .getReverseMapKey(next);
265:
266: return mapKey;
267: }
268:
269: public void remove() {
270: _iterator.remove();
271: }
272: }
273:
274: private class EntryIterator implements Iterator<Map.Entry<K, V>> {
275: private Iterator<Map.Entry<K, V>> _iterator;
276:
277: EntryIterator() {
278: _iterator = _map.entrySet().iterator();
279: }
280:
281: public boolean hasNext() {
282: return _iterator.hasNext();
283: }
284:
285: public Map.Entry<K, V> next() {
286: Map.Entry<K, V> nextEntry = _iterator.next();
287: K nextKey = nextEntry.getKey();
288:
289: K mapKey = KeyLinkMap.this .getReverseMapKey(nextEntry
290: .getKey());
291:
292: if (mapKey == nextKey)
293: return nextEntry;
294: else
295: return new MapEntry<K, V>(mapKey, nextEntry.getValue());
296: }
297:
298: public void remove() {
299: _iterator.remove();
300: }
301: }
302:
303: private class MapEntry<K, V> implements Map.Entry<K, V> {
304: private K _key;
305: private V _value;
306:
307: MapEntry(K key, V value) {
308: _key = key;
309: _value = value;
310: }
311:
312: public K getKey() {
313: return _key;
314: }
315:
316: public K setKey(K key) {
317: K oldKey = _key;
318: _key = key;
319: return oldKey;
320: }
321:
322: public V getValue() {
323: return _value;
324: }
325:
326: public V setValue(V value) {
327: V oldValue = _value;
328: _value = value;
329: return oldValue;
330: }
331:
332: public boolean equals(Object o) {
333: if (!(o instanceof Map.Entry))
334: return false;
335:
336: Map.Entry<K, V> other = (Map.Entry<K, V>) o;
337:
338: return (getKey() == null ? other.getKey() == null
339: : getKey().equals(other.getKey()))
340: && (getValue() == null ? other.getValue() == null
341: : getValue().equals(other.getValue()));
342: }
343:
344: public int hashCode() {
345: return (getKey() == null ? 0 : getKey().hashCode())
346: ^ (getValue() == null ? 0 : getValue().hashCode());
347: }
348: }
349: }
|