1 /*
2 * Copyright (c) 2005-2007 Creative Sphere Limited.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors:
9 *
10 * Creative Sphere - initial API and implementation
11 *
12 */
13 package org.abstracthorizon.extend.server.support;
14
15 import java.util.Collection;
16 import java.util.LinkedHashMap;
17 import java.util.LinkedHashSet;
18 import java.util.Map;
19 import java.util.Set;
20
21 /**
22 * This map maintains separate set of values. This allows if two key/value pairs contain same
23 * value and {@link #remove(Object)} method is called with value both values are going to be
24 * removed from the map. Also, having set of values {@link #values()} method returns that
25 * set which is faster. Values set is implemented as {@link LinkedHashSet}
26 *
27 */
28 public class EnhancedMap<KeyType, ValueType> implements Map<KeyType, ValueType> {
29
30 /** Map */
31 protected LinkedHashMap<KeyType, ValueType> map = new LinkedHashMap<KeyType, ValueType>();
32
33 /** Values */
34 protected InternalSet<ValueType> values = new InternalSet<ValueType>();
35
36 /** Empty constractor */
37 public EnhancedMap() {
38 }
39
40 /**
41 * Returns get value
42 * @param key key
43 * @return value
44 */
45 public ValueType get(Object key) {
46 return map.get(key);
47 }
48
49 /**
50 * Adds new element to the map
51 * @param key key
52 * @param value value
53 * @return previous value under that key
54 */
55 public ValueType put(KeyType key, ValueType value) {
56 values.add(value);
57 ValueType res = map.put(key, value);
58 return res;
59 }
60
61 /**
62 * Removes value value
63 * @param value value to be removed
64 * @return <code>true</code> if removed
65 */
66 @SuppressWarnings("unchecked")
67 public ValueType remove(Object value) {
68 if (values.remove(value)) {
69 while (map.values().remove(value)) {
70 }
71 return (ValueType)value;
72 } else {
73 ValueType result = map.remove(value);
74 if (result != null) {
75 if (!map.values().contains(result)) {
76 values.remove(result);
77 }
78 }
79 return result;
80 }
81 }
82
83
84 /**
85 * Clears the map.
86 */
87 public void clear() {
88 map.clear();
89 values.clear();
90 }
91
92 /**
93 * Returns values
94 * @return values
95 */
96 public Collection<ValueType> values() {
97 return values;
98 }
99
100 /**
101 * Checks map if key exsits
102 * @param key key
103 * @return <code>true</code> if key exists
104 */
105 public boolean containsKey(Object key) {
106 return map.containsKey(key);
107 }
108
109 /**
110 * Checks values set if value exsits
111 * @param value value
112 * @return <code>true</code> if value exists
113 */
114 public boolean containsValue(Object value) {
115 return values.contains(value);
116 }
117
118 /**
119 * Returns entry set of a map
120 * @return entry set of a map
121 */
122 public Set<Map.Entry<KeyType, ValueType>> entrySet() {
123 return map.entrySet();
124 }
125
126 /**
127 * Returns if is empty
128 * @return <code>true</code> if is empty
129 */
130 public boolean isEmpty() {
131 return values.isEmpty();
132 }
133
134 /**
135 * Returns key set
136 * @return key set
137 */
138 public Set<KeyType> keySet() {
139 return map.keySet();
140 }
141
142 /**
143 * Stores all
144 * @param t map
145 */
146 public void putAll(Map<? extends KeyType, ? extends ValueType> t) {
147 values.addAll(t.values());
148 map.putAll(t);
149 }
150
151 /**
152 * Returns map size
153 * @return map size
154 */
155 public int size() {
156 return map.size();
157 }
158
159 /**
160 * Internal implementation of {@link LinkedHashSet} so invoking {@link LinkedHashSet#remove(Object)}
161 * method removes all values from the map as well
162 *
163 * @param <Type>
164 * @author Daniel Sendula
165 */
166 protected class InternalSet<Type> extends LinkedHashSet<Type> {
167 public boolean remove(Object object) {
168 if (removeInternal(object)) {
169 while (map.values().remove(object)) {
170 }
171 return true;
172 } else {
173 return false;
174 }
175 }
176
177 /**
178 * Internal remove method - invokes super remove method.
179 * @param object object to be removed
180 * @return <code>true</code> if removed
181 */
182 protected boolean removeInternal(Object object) {
183 boolean removed = super.remove(object);
184 return removed;
185 }
186 }
187
188 public static void main(String[] args) throws Exception {
189 EnhancedMap<String, Object> map = new EnhancedMap<String, Object>();
190
191 String key1 = "key1";
192 String key2 = "key2";
193 String key3 = "key3";
194
195 Object o1 = new Object() { public String toString() { return "o1"; } };
196 Object o2 = new Object() { public String toString() { return "o2"; } };
197
198 map.put(key1, o1);
199 map.put(key2, o2);
200 map.put(key3, o1);
201
202 System.out.println("-----");
203
204 for (Object value : map.values()) {
205 System.out.println(value);
206 }
207
208 map.remove(key2);
209
210 System.out.println("-----");
211
212 for (Object value : map.values()) {
213 System.out.println(value);
214 }
215
216
217 }
218 }