/* * Copyright 2004-2015 the Seasar Foundation and the Others. * * 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.seasar.framework.container.external; import java.util.AbstractCollection; import java.util.AbstractMap; import java.util.AbstractSet; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import org.seasar.framework.container.ExternalContext; /** * {@link ExternalContext}用の抽象 {@link Map}です。 * * @author shot * @author higa */ public abstract class AbstractExternalContextMap extends AbstractMap { private Set entrySet; private Set keySet; private Collection values; /** * {@link AbstractExternalContextMap}を作成します。 */ public AbstractExternalContextMap() { } public void clear() { // avoid ConcurrentModificationException List list = new ArrayList(); for (Iterator it = getAttributeNames(); it.hasNext();) { String key = (String) it.next(); list.add(key); } clearReally(list); } private void clearReally(List keys) { for (Iterator itr = keys.iterator(); itr.hasNext();) { String key = (String) itr.next(); removeAttribute(key); } } public boolean containsKey(Object key) { return (getAttribute(key.toString()) != null); } public boolean containsValue(Object value) { if (value != null) { for (Iterator it = getAttributeNames(); it.hasNext();) { String key = (String) it.next(); Object attributeValue = getAttribute(key); if (value.equals(attributeValue)) { return true; } } } return false; } public Set entrySet() { if (entrySet == null) { entrySet = new EntrySet(this); } return entrySet; } public Object get(Object key) { return getAttribute(key.toString()); } public Object put(Object key, Object value) { String keyStr = key.toString(); Object o = getAttribute(keyStr); setAttribute(keyStr, value); return o; } public void putAll(Map map) { for (Iterator itr = map.entrySet().iterator(); itr.hasNext();) { Map.Entry entry = (Map.Entry) itr.next(); String key = (String) entry.getKey(); setAttribute(key, entry.getValue()); } } public boolean isEmpty() { return !getAttributeNames().hasNext(); } public Set keySet() { if (keySet == null) { keySet = new KeySet(this); } return keySet; } public Object remove(Object key) { String keyStr = key.toString(); Object o = getAttribute(keyStr); removeAttribute(keyStr); return o; } public Collection values() { if (values == null) { values = new ValuesCollection(this); } return values; } /** * 属性の値を返します。 * * @param key * @return 属性の値 */ protected abstract Object getAttribute(String key); /** * 属性の値を設定します。 * * @param key * @param value */ protected abstract void setAttribute(String key, Object value); /** * 属性名の {@link Iterator}を返します。 * * @return */ protected abstract Iterator getAttributeNames(); /** * 属性を削除します。 * * @param key */ protected abstract void removeAttribute(String key); abstract class AbstractExternalContextSet extends AbstractSet { public int size() { int size = 0; for (Iterator itr = iterator(); itr.hasNext(); size++) { itr.next(); } return size; } } class EntrySet extends AbstractExternalContextSet { private AbstractExternalContextMap contextMap; /** * {@link EntrySet}を作成します。 * * @param contextMap */ public EntrySet(AbstractExternalContextMap contextMap) { this.contextMap = contextMap; } public Iterator iterator() { return new EntryIterator(contextMap); } public boolean remove(Object o) { if (!(o instanceof Map.Entry)) { return false; } Map.Entry entry = (Map.Entry) o; Object returnObj = contextMap.remove(entry.getKey()); return (returnObj != null); } } class KeySet extends AbstractExternalContextSet { private AbstractExternalContextMap contextMap; /** * {@link KeySet}を作成します。 * * @param contextMap */ public KeySet(AbstractExternalContextMap contextMap) { this.contextMap = contextMap; } public Iterator iterator() { return new KeyIterator(contextMap); } public boolean remove(Object o) { if (!(o instanceof String)) { return false; } String s = (String) o; Object returnObj = contextMap.remove(s); return (returnObj != null); } } class ValuesCollection extends AbstractCollection { private AbstractExternalContextMap contextMap; /** * {@link ValuesCollection}を作成します。 * * @param contextMap */ public ValuesCollection(AbstractExternalContextMap contextMap) { this.contextMap = contextMap; } public int size() { int size = 0; for (Iterator itr = iterator(); itr.hasNext(); size++) { itr.next(); } return size; } public Iterator iterator() { return new ValuesIterator(contextMap); } } abstract class AbstractExternalContextIterator implements Iterator { private final Iterator iterator; private final AbstractExternalContextMap contextMap; private String currentKey; private boolean removeCalled = false; /** * {@link AbstractExternalContextIterator}を作成します。 * * @param contextMap */ public AbstractExternalContextIterator( final AbstractExternalContextMap contextMap) { iterator = contextMap.getAttributeNames(); this.contextMap = contextMap; } public boolean hasNext() { return iterator.hasNext(); } public Object next() { currentKey = (String) iterator.next(); try { return doNext(); } finally { removeCalled = false; } } public void remove() { if (currentKey != null && !removeCalled) { doRemove(); removeCalled = true; } else { throw new IllegalStateException(); } } /** * 現在のキーを返します。 * * @return 現在のキー */ protected String getCurrentKey() { return currentKey; } /** * 値を返します。 * * @param key * @return 値 */ protected Object getValueFromMap(String key) { return contextMap.get(key); } /** * キーに対するエントリを削除します。 * * @param key */ protected void removeKeyFromMap(String key) { contextMap.remove(key); } /** * 値に対するエントリを削除します。 * * @param value */ protected void removeValueFromMap(Object value) { if (containsValue(value)) { for (Iterator itr = entrySet().iterator(); itr.hasNext();) { Map.Entry e = (Map.Entry) itr.next(); if (value.equals(e.getValue())) { contextMap.remove(e.getKey()); } } } } /** * 次の要素に移動します。 * * @return 次の要素 */ protected abstract Object doNext(); /** * 現在の要素を削除します。 */ protected abstract void doRemove(); } class EntryIterator extends AbstractExternalContextIterator { /** * {@link EntryIterator}を作成します。 * * @param contextMap */ public EntryIterator(AbstractExternalContextMap contextMap) { super(contextMap); } protected Object doNext() { String key = getCurrentKey(); return new ImmutableEntry(key, getValueFromMap(key)); } protected void doRemove() { String key = getCurrentKey(); removeKeyFromMap(key); } } class KeyIterator extends AbstractExternalContextIterator { /** * {@link KeyIterator}を作成します。 * * @param contextMap */ public KeyIterator(AbstractExternalContextMap contextMap) { super(contextMap); } protected Object doNext() { return getCurrentKey(); } protected void doRemove() { removeKeyFromMap(getCurrentKey()); } } class ValuesIterator extends AbstractExternalContextIterator { /** * {@link ValuesIterator}を作成します。 * * @param contextMap */ public ValuesIterator(AbstractExternalContextMap contextMap) { super(contextMap); } protected Object doNext() { String key = getCurrentKey(); return getValueFromMap(key); } protected void doRemove() { String key = getCurrentKey(); Object value = getValueFromMap(key); removeValueFromMap(value); } } /** * 変化しない {@link java.util.Map.Entry}です。 * */ protected static class ImmutableEntry implements Map.Entry { private final Object key; private final Object value; /** * {@link AbstractExternalContextMap.ImmutableEntry}を作成します。 * * @param key * @param value */ public ImmutableEntry(Object key, Object value) { this.key = key; this.value = value; } public Object getKey() { return key; } public Object getValue() { return value; } public Object setValue(Object arg0) { throw new UnsupportedOperationException("Immutable entry."); } public boolean equals(Object obj) { if (obj == null || !(obj instanceof ImmutableEntry)) { return false; } ImmutableEntry entry = (ImmutableEntry) obj; Object k = entry.getKey(); Object v = entry.getValue(); return (k == key || (k != null && k.equals(key))) && (v == value || (v != null && v.equals(value))); } public int hashCode() { return ((key != null) ? key.hashCode() : 0) ^ ((value != null) ? value.hashCode() : 0); } } }