001: /**
002: *
003: * Licensed to the Apache Software Foundation (ASF) under one or more
004: * contributor license agreements. See the NOTICE file distributed with
005: * this work for additional information regarding copyright ownership.
006: * The ASF licenses this file to You under the Apache License, Version 2.0
007: * (the "License"); you may not use this file except in compliance with
008: * the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing, software
013: * distributed under the License is distributed on an "AS IS" BASIS,
014: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015: * See the License for the specific language governing permissions and
016: * limitations under the License.
017: */package org.apache.openejb.jee;
018:
019: import java.util.AbstractCollection;
020: import java.util.Collection;
021: import java.util.Iterator;
022: import java.util.LinkedHashMap;
023: import java.util.Map;
024:
025: /**
026: * A KeyedCollection is a light weight wrapper around a Map (LinkedHashMap) values set.
027: * When a value is added using the add method of this class a key is obtained for
028: * the value using either the provided KeyExtractor, or if no KeyExtractor was
029: * provided, the value is cast to Keyable and the getKey() method is called.
030: *
031: * The underlying Map can be obtainded with the toMap method. Any changes to this
032: * map are directly reflected in this collection. Additions to the map do not
033: * need to implement Keyable, nor do the values need to be keyed using the key
034: * returned from the KeyExtractor.getKey(value) or the key returned from the
035: * Keyable.getKey() Method.
036: */
037: public class KeyedCollection<K, V> extends AbstractCollection<V> {
038: private final KeyExtractor<? extends K, ? super V> keyExtractor;
039: private final LinkedHashMap<K, V> map;
040:
041: @SuppressWarnings({"unchecked"})
042: public KeyedCollection() {
043: // NOTE: V must implement Keyable or class cast exception will be thrown on add
044: keyExtractor = null;
045: map = new LinkedHashMap<K, V>();
046: }
047:
048: public KeyedCollection(
049: KeyExtractor<? extends K, ? super V> keyExtractor) {
050: this .keyExtractor = keyExtractor;
051: map = new LinkedHashMap<K, V>();
052: }
053:
054: @SuppressWarnings({"unchecked"})
055: public KeyedCollection(Collection<? extends V> c) {
056: if (c instanceof KeyedCollection) {
057: KeyedCollection keyedCollection = (KeyedCollection) c;
058: // NOTE: if types don't match bad things could happen
059: keyExtractor = keyedCollection.keyExtractor;
060: } else {
061: // NOTE: V must implement Keyable or class cast exception will be thrown on add
062: keyExtractor = null;
063: }
064: map = new LinkedHashMap<K, V>();
065: addAll(c);
066: }
067:
068: @SuppressWarnings({"unchecked"})
069: public KeyedCollection(int initialCapacity) {
070: // NOTE: V must implement Keyable or class cast exception will be thrown on add
071: keyExtractor = null;
072: map = new LinkedHashMap<K, V>(initialCapacity);
073: }
074:
075: /**
076: * Get the underlying map used by this collection.
077: *
078: * Any changes to this
079: * map are directly reflected in this collection. Additions to the map do not
080: * need to implement Keyable, nor do the values need to be keyed using the key
081: * returned from the KeyExtractor.getKey(value) or the key returned from the
082: * Keyable.getKey() Method.
083: * @return the indexed contents of this collection
084: */
085: public Map<K, V> toMap() {
086: return map;
087: }
088:
089: public boolean add(V value) {
090: K key = getKey(value);
091: if (key == null) {
092: throw new NullPointerException("key is null");
093: }
094: V oldValue = map.put(key, value);
095: return value != oldValue;
096: }
097:
098: public Iterator<V> iterator() {
099: return map.values().iterator();
100: }
101:
102: public int size() {
103: return map.size();
104: }
105:
106: public boolean isEmpty() {
107: return map.isEmpty();
108: }
109:
110: public void clear() {
111: map.clear();
112: }
113:
114: public String toString() {
115: return map.toString();
116: }
117:
118: @SuppressWarnings({"unchecked"})
119: protected K getKey(V value) {
120: if (keyExtractor == null) {
121: return ((Keyable<? extends K>) value).getKey();
122: } else {
123: return keyExtractor.getKey(value);
124: }
125: }
126:
127: }
|