001: /*
002: * Copyright 2004 The Apache Software Foundation.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package org.apache.myfaces.util;
017:
018: import java.util.AbstractMap;
019: import java.util.AbstractSet;
020: import java.util.ArrayList;
021: import java.util.Collection;
022: import java.util.Enumeration;
023: import java.util.Iterator;
024: import java.util.List;
025: import java.util.Map;
026: import java.util.NoSuchElementException;
027: import java.util.Set;
028:
029: /**
030: * Helper Map implementation for use with different Attribute Maps.
031: *
032: * @author Anton Koinov (latest modification by $Author: mbr $)
033: * @version $Revision: 517047 $ $Date: 2007-03-12 00:22:47 +0100 (Mo, 12 Mrz 2007) $
034: */
035: public abstract class AbstractAttributeMap<V> extends
036: AbstractMap<String, V> {
037: private Set<String> _keySet;
038: private Collection<V> _values;
039: private Set<Entry<String, V>> _entrySet;
040:
041: public void clear() {
042: List<String> names = new ArrayList<String>();
043: for (Enumeration<String> e = getAttributeNames(); e
044: .hasMoreElements();) {
045: names.add(e.nextElement());
046: }
047:
048: for (Iterator it = names.iterator(); it.hasNext();) {
049: removeAttribute((String) it.next());
050: }
051: }
052:
053: public boolean containsKey(Object key) {
054: return getAttribute(key.toString()) != null;
055: }
056:
057: public boolean containsValue(Object findValue) {
058: if (findValue == null) {
059: return false;
060: }
061:
062: for (Enumeration<String> e = getAttributeNames(); e
063: .hasMoreElements();) {
064: Object value = getAttribute(e.nextElement());
065: if (findValue.equals(value)) {
066: return true;
067: }
068: }
069:
070: return false;
071: }
072:
073: @Override
074: public Set<Entry<String, V>> entrySet() {
075: return (_entrySet != null) ? _entrySet
076: : (_entrySet = new EntrySet());
077: }
078:
079: public V get(Object key) {
080: return getAttribute(key.toString());
081: }
082:
083: public boolean isEmpty() {
084: return !getAttributeNames().hasMoreElements();
085: }
086:
087: public Set<String> keySet() {
088: return (_keySet != null) ? _keySet : (_keySet = new KeySet());
089: }
090:
091: public V put(String key, V value) {
092: V retval = getAttribute(key);
093: setAttribute(key, value);
094: return retval;
095: }
096:
097: public void putAll(Map<? extends String, ? extends V> t) {
098: for (Iterator<? extends Entry<? extends String, ? extends V>> it = t
099: .entrySet().iterator(); it.hasNext();) {
100: Entry<? extends String, ? extends V> entry = it.next();
101: setAttribute(entry.getKey(), entry.getValue());
102: }
103: }
104:
105: @Override
106: public V remove(Object key) {
107: String key_ = key.toString();
108: V retval = getAttribute(key_);
109: removeAttribute(key_);
110: return retval;
111: }
112:
113: @Override
114: public int size() {
115: int size = 0;
116: for (Enumeration e = getAttributeNames(); e.hasMoreElements();) {
117: size++;
118: e.nextElement();
119: }
120: return size;
121: }
122:
123: @Override
124: public Collection<V> values() {
125: return (_values != null) ? _values : (_values = new Values());
126: }
127:
128: abstract protected V getAttribute(String key);
129:
130: abstract protected void setAttribute(String key, V value);
131:
132: abstract protected void removeAttribute(String key);
133:
134: abstract protected Enumeration<String> getAttributeNames();
135:
136: private abstract class AbstractAttributeSet<E> extends
137: AbstractSet<E> {
138: @Override
139: public boolean isEmpty() {
140: return AbstractAttributeMap.this .isEmpty();
141: }
142:
143: @Override
144: public int size() {
145: return AbstractAttributeMap.this .size();
146: }
147:
148: @Override
149: public void clear() {
150: AbstractAttributeMap.this .clear();
151: }
152: }
153:
154: private class KeySet extends AbstractAttributeSet<String> {
155: @Override
156: public Iterator<String> iterator() {
157: return new KeyIterator();
158: }
159:
160: @Override
161: public boolean contains(Object o) {
162: return AbstractAttributeMap.this .containsKey(o);
163: }
164:
165: @Override
166: public boolean remove(Object o) {
167: return AbstractAttributeMap.this .remove(o) != null;
168: }
169:
170: }
171:
172: private abstract class AbstractAttributeIterator<E> implements
173: Iterator<E> {
174: protected final Enumeration<String> _e = getAttributeNames();
175: protected String _currentKey;
176:
177: public void remove() {
178: // remove() may cause ConcurrentModificationException.
179: // We could throw an exception here, but not throwing an exception
180: // allows one call to remove() to succeed
181: if (_currentKey == null) {
182: throw new NoSuchElementException(
183: "You must call next() at least once");
184: }
185: AbstractAttributeMap.this .remove(_currentKey);
186: }
187:
188: public boolean hasNext() {
189: return _e.hasMoreElements();
190: }
191:
192: public E next() {
193: return getValue(_currentKey = _e.nextElement());
194: }
195:
196: protected abstract E getValue(String attributeName);
197: }
198:
199: private class KeyIterator extends AbstractAttributeIterator<String> {
200: @Override
201: protected String getValue(String attributeName) {
202: return attributeName;
203: }
204: }
205:
206: private class Values extends AbstractAttributeSet<V> {
207: @Override
208: public Iterator<V> iterator() {
209: return new ValuesIterator();
210: }
211:
212: @Override
213: public boolean contains(Object o) {
214: if (o == null) {
215: return false;
216: }
217:
218: for (Iterator it = iterator(); it.hasNext();) {
219: if (o.equals(it.next())) {
220: return true;
221: }
222: }
223:
224: return false;
225: }
226:
227: @Override
228: public boolean remove(Object o) {
229: if (o == null) {
230: return false;
231: }
232:
233: for (Iterator it = iterator(); it.hasNext();) {
234: if (o.equals(it.next())) {
235: it.remove();
236: return true;
237: }
238: }
239:
240: return false;
241: }
242: }
243:
244: private class ValuesIterator extends AbstractAttributeIterator<V> {
245: @Override
246: protected V getValue(String attributeName) {
247: return AbstractAttributeMap.this .get(attributeName);
248: }
249: }
250:
251: private class EntrySet extends
252: AbstractAttributeSet<Entry<String, V>> {
253: @Override
254: public Iterator<Entry<String, V>> iterator() {
255: return new EntryIterator();
256: }
257:
258: @Override
259: public boolean contains(Object o) {
260: if (!(o instanceof Entry)) {
261: return false;
262: }
263:
264: Entry entry = (Entry) o;
265: Object key = entry.getKey();
266: Object value = entry.getValue();
267: if (key == null || value == null) {
268: return false;
269: }
270:
271: return value.equals(AbstractAttributeMap.this .get(key));
272: }
273:
274: @Override
275: public boolean remove(Object o) {
276: if (!(o instanceof Entry)) {
277: return false;
278: }
279:
280: Entry entry = (Entry) o;
281: Object key = entry.getKey();
282: Object value = entry.getValue();
283: if (key == null
284: || value == null
285: || !value
286: .equals(AbstractAttributeMap.this .get(key))) {
287: return false;
288: }
289:
290: return AbstractAttributeMap.this .remove(((Entry) o)
291: .getKey()) != null;
292: }
293: }
294:
295: /**
296: * Not very efficient since it generates a new instance of <code>Entry</code> for each element and still internaly
297: * uses the <code>KeyIterator</code>. It is more efficient to use the <code>KeyIterator</code> directly.
298: */
299: private class EntryIterator extends
300: AbstractAttributeIterator<Entry<String, V>> {
301: @Override
302: protected Entry<String, V> getValue(String attributeName) {
303: // Must create new Entry every time--value of the entry must stay
304: // linked to the same attribute name
305: return new EntrySetEntry(attributeName);
306: }
307: }
308:
309: private class EntrySetEntry implements Entry<String, V> {
310: private final String _currentKey;
311:
312: public EntrySetEntry(String currentKey) {
313: _currentKey = currentKey;
314: }
315:
316: public String getKey() {
317: return _currentKey;
318: }
319:
320: public V getValue() {
321: return AbstractAttributeMap.this .get(_currentKey);
322: }
323:
324: public V setValue(V value) {
325: return AbstractAttributeMap.this .put(_currentKey, value);
326: }
327:
328: @Override
329: public int hashCode() {
330: final int PRIME = 31;
331: int result = 1;
332: result = PRIME
333: * result
334: + ((_currentKey == null) ? 0 : _currentKey
335: .hashCode());
336: return result;
337: }
338:
339: @Override
340: public boolean equals(Object obj) {
341: if (this == obj)
342: return true;
343: if (obj == null)
344: return false;
345: if (getClass() != obj.getClass())
346: return false;
347: final EntrySetEntry other = (EntrySetEntry) obj;
348: if (_currentKey == null) {
349: if (other._currentKey != null)
350: return false;
351: } else if (!_currentKey.equals(other._currentKey))
352: return false;
353: return true;
354: }
355:
356: }
357: }
|