/* * Copyright 2004 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.myfaces.context.servlet; import java.util.AbstractSet; import java.util.ArrayList; import java.util.Collection; import java.util.Enumeration; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.NoSuchElementException; import java.util.Set; /** * Helper Map implementation for use with different Attribute Maps. * * @author Anton Koinov (latest modification by $Author$) * @version $Revision$ $Date$ */ public abstract class AbstractAttributeMap implements Map { private Set _keySet; private Collection _values; private Set _entrySet; public void clear() { List names = new ArrayList(); for (Enumeration e = getAttributeNames(); e.hasMoreElements();) { names.add(e.nextElement()); } for (Iterator it = names.iterator(); it.hasNext();) { removeAttribute((String) it.next()); } } public boolean containsKey(Object key) { return getAttribute(key.toString()) != null; } public boolean containsValue(Object findValue) { if (findValue == null) { return false; } for (Enumeration e = getAttributeNames(); e.hasMoreElements();) { Object value = getAttribute((String) e.nextElement()); if (findValue.equals(value)) { return true; } } return false; } public Set entrySet() { return (_entrySet != null) ? _entrySet : (_entrySet = new EntrySet()); } public Object get(Object key) { return getAttribute(key.toString()); } public boolean isEmpty() { return !getAttributeNames().hasMoreElements(); } public Set keySet() { return (_keySet != null) ? _keySet : (_keySet = new KeySet()); } public Object put(Object key, Object value) { String key_ = key.toString(); Object retval = getAttribute(key_); setAttribute(key_, value); return retval; } public void putAll(Map t) { for (Iterator it = t.entrySet().iterator(); it.hasNext();) { Entry entry = (Entry) it.next(); setAttribute(entry.getKey().toString(), entry.getValue()); } } public Object remove(Object key) { String key_ = key.toString(); Object retval = getAttribute(key_); removeAttribute(key_); return retval; } public int size() { int size = 0; for (Enumeration e = getAttributeNames(); e.hasMoreElements();) { size++; e.nextElement(); } return size; } public Collection values() { return (_values != null) ? _values : (_values = new Values()); } abstract protected Object getAttribute(String key); abstract protected void setAttribute(String key, Object value); abstract protected void removeAttribute(String key); abstract protected Enumeration getAttributeNames(); private class KeySet extends AbstractSet { public Iterator iterator() { return new KeyIterator(); } public boolean isEmpty() { return AbstractAttributeMap.this.isEmpty(); } public int size() { return AbstractAttributeMap.this.size(); } public boolean contains(Object o) { return AbstractAttributeMap.this.containsKey(o); } public boolean remove(Object o) { return AbstractAttributeMap.this.remove(o) != null; } public void clear() { AbstractAttributeMap.this.clear(); } } private class KeyIterator implements Iterator { protected final Enumeration _e = getAttributeNames(); protected Object _currentKey; public void remove() { // remove() may cause ConcurrentModificationException. // We could throw an exception here, but not throwing an exception // allows one call to remove() to succeed if (_currentKey == null) { throw new NoSuchElementException( "You must call next() at least once"); } AbstractAttributeMap.this.remove(_currentKey); } public boolean hasNext() { return _e.hasMoreElements(); } public Object next() { return _currentKey = _e.nextElement(); } } private class Values extends KeySet { public Iterator iterator() { return new ValuesIterator(); } public boolean contains(Object o) { return AbstractAttributeMap.this.containsValue(o); } public boolean remove(Object o) { if (o == null) { return false; } for (Iterator it = iterator(); it.hasNext();) { if (o.equals(it.next())) { it.remove(); return true; } } return false; } } private class ValuesIterator extends KeyIterator { public Object next() { super.next(); return AbstractAttributeMap.this.get(_currentKey); } } private class EntrySet extends KeySet { public Iterator iterator() { return new EntryIterator(); } public boolean contains(Object o) { if (!(o instanceof Entry)) { return false; } Entry entry = (Entry) o; Object key = entry.getKey(); Object value = entry.getValue(); if (key == null || value == null) { return false; } return value.equals(AbstractAttributeMap.this.get(key)); } public boolean remove(Object o) { if (!(o instanceof Entry)) { return false; } Entry entry = (Entry) o; Object key = entry.getKey(); Object value = entry.getValue(); if (key == null || value == null || !value.equals(AbstractAttributeMap.this.get(key))) { return false; } return AbstractAttributeMap.this.remove(((Entry) o).getKey()) != null; } } /** * Not very efficient since it generates a new instance of <code>Entry</code> * for each element and still internaly uses the <code>KeyIterator</code>. * It is more efficient to use the <code>KeyIterator</code> directly. */ private class EntryIterator extends KeyIterator { public Object next() { super.next(); // Must create new Entry every time--value of the entry must stay // linked to the same attribute name return new EntrySetEntry(_currentKey); } } private class EntrySetEntry implements Entry { private final Object _currentKey; public EntrySetEntry(Object currentKey) { _currentKey = currentKey; } public Object getKey() { return _currentKey; } public Object getValue() { return AbstractAttributeMap.this.get(_currentKey); } public Object setValue(Object value) { return AbstractAttributeMap.this.put(_currentKey, value); } } }