1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.opensaml.xml.util;
18
19 import java.util.AbstractSet;
20 import java.util.HashMap;
21 import java.util.HashSet;
22 import java.util.Iterator;
23 import java.util.Set;
24
25
26
27
28
29
30
31
32 public class ClassIndexedSet<T> extends AbstractSet<T> implements Set<T> {
33
34
35 private HashSet<T> set;
36
37
38 private HashMap<Class<? extends T>, T> index;
39
40
41
42
43
44 public ClassIndexedSet() {
45 set = new HashSet<T>();
46 index = new HashMap<Class<? extends T>, T>();
47 }
48
49
50 public boolean add(T o) {
51 return add(o, false);
52 }
53
54
55
56
57
58
59
60
61
62
63
64
65 @SuppressWarnings("unchecked")
66 public boolean add(T o, boolean replace) throws NullPointerException, IllegalArgumentException {
67 if (o == null) {
68 throw new NullPointerException("Null elements are not allowed");
69 }
70 boolean replacing = false;
71 Class<? extends T> indexClass = getIndexClass(o);
72 T existing = get(indexClass);
73 if (existing != null) {
74 replacing = true;
75 if (replace) {
76 remove(existing);
77 } else {
78 throw new IllegalArgumentException("Set already contains a member of index class "
79 + indexClass.getName());
80 }
81 }
82 index.put(indexClass, o);
83 set.add(o);
84 return replacing;
85 }
86
87
88 public void clear() {
89 set.clear();
90 index.clear();
91 }
92
93
94 @SuppressWarnings("unchecked")
95 public boolean remove(Object o) {
96 if (set.contains(o)) {
97 removeFromIndex((T) o);
98 set.remove(o);
99 return true;
100 }
101 return false;
102 }
103
104
105 public Iterator<T> iterator() {
106 return new ClassIndexedSetIterator(this, set.iterator());
107 }
108
109
110 public int size() {
111 return set.size();
112 }
113
114
115
116
117
118
119
120 public boolean contains(Class<? extends T> clazz) {
121 return get(clazz)!=null;
122 }
123
124
125
126
127
128
129
130
131 @SuppressWarnings("unchecked")
132 public <X extends T> X get(Class<X> clazz) {
133 return (X) index.get(clazz);
134 }
135
136
137
138
139
140
141
142
143 @SuppressWarnings("unchecked")
144 protected Class<? extends T> getIndexClass(Object o) {
145 return (Class<? extends T>) o.getClass();
146 }
147
148
149
150
151
152
153 private void removeFromIndex(T o) {
154 index.remove(getIndexClass(o));
155 }
156
157
158
159
160
161 protected class ClassIndexedSetIterator implements Iterator<T> {
162
163
164 private ClassIndexedSet<T> set;
165
166
167 private Iterator<T> iterator;
168
169
170 private boolean nextCalled;
171
172
173 private boolean removeStateValid;;
174
175
176
177 private T current;
178
179
180
181
182
183
184
185 protected ClassIndexedSetIterator(ClassIndexedSet<T> parentSet, Iterator<T> parentIterator) {
186 set = parentSet;
187 iterator = parentIterator;
188 current = null;
189 nextCalled = false;
190 removeStateValid = false;
191 }
192
193
194 public boolean hasNext() {
195 return iterator.hasNext();
196 }
197
198
199 public T next() {
200 current = iterator.next();
201 nextCalled = true;
202 removeStateValid = true;
203 return current;
204 }
205
206
207 public void remove() {
208 if (! nextCalled) {
209 throw new IllegalStateException("remove() was called before calling next()");
210 }
211 if (! removeStateValid) {
212 throw new IllegalStateException("remove() has already been called since the last call to next()");
213 }
214 iterator.remove();
215 set.removeFromIndex(current);
216 removeStateValid = false;
217 }
218
219 }
220
221 }