1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.jetty.websocket.jsr356.metadata;
20
21 import java.util.ArrayList;
22 import java.util.Iterator;
23 import java.util.List;
24 import java.util.Map;
25 import java.util.concurrent.ConcurrentHashMap;
26
27 import org.eclipse.jetty.websocket.api.InvalidWebSocketException;
28
29
30
31
32
33
34
35
36
37
38
39 public abstract class CoderMetadataSet<T, M extends CoderMetadata<T>> implements Iterable<M>
40 {
41
42
43
44 private final List<M> metadatas;
45
46
47
48 private final List<Class<? extends T>> coders;
49
50
51
52 private final Map<Class<?>, Integer> typeMap;
53
54
55
56 private final Map<Class<? extends T>, List<Integer>> implMap;
57
58 protected CoderMetadataSet()
59 {
60 metadatas = new ArrayList<>();
61 coders = new ArrayList<>();
62 typeMap = new ConcurrentHashMap<>();
63 implMap = new ConcurrentHashMap<>();
64 }
65
66 public void add(Class<? extends T> coder)
67 {
68 List<M> metadatas = discover(coder);
69 trackMetadata(metadatas);
70 }
71
72 public List<M> addAll(Class<? extends T>[] coders)
73 {
74 List<M> metadatas = new ArrayList<>();
75
76 for (Class<? extends T> coder : coders)
77 {
78 metadatas.addAll(discover(coder));
79 }
80
81 trackMetadata(metadatas);
82 return metadatas;
83 }
84
85 public List<M> addAll(List<Class<? extends T>> coders)
86 {
87 List<M> metadatas = new ArrayList<>();
88
89 for (Class<? extends T> coder : coders)
90 {
91 metadatas.addAll(discover(coder));
92 }
93
94 trackMetadata(metadatas);
95 return metadatas;
96 }
97
98
99
100
101
102
103
104
105
106
107
108 protected abstract List<M> discover(Class<? extends T> coder);
109
110 public Class<? extends T> getCoder(Class<?> type)
111 {
112 M metadata = getMetadataByType(type);
113 if (metadata == null)
114 {
115 return null;
116 }
117 return metadata.getCoderClass();
118 }
119
120 public List<Class<? extends T>> getList()
121 {
122 return coders;
123 }
124
125 public List<M> getMetadataByImplementation(Class<? extends T> clazz)
126 {
127 List<Integer> indexes = implMap.get(clazz);
128 if (indexes == null)
129 {
130 return null;
131 }
132 List<M> ret = new ArrayList<>();
133 for (Integer idx : indexes)
134 {
135 ret.add(metadatas.get(idx));
136 }
137 return ret;
138 }
139
140 public M getMetadataByType(Class<?> type)
141 {
142 Integer idx = typeMap.get(type);
143 if (idx == null)
144 {
145
146 idx = getMetadataByAssignableType(type);
147 if (idx != null)
148 {
149
150 typeMap.put(type,idx);
151 }
152 }
153
154
155 if (idx == null)
156 {
157 return null;
158 }
159 return metadatas.get(idx);
160 }
161
162 private Integer getMetadataByAssignableType(Class<?> type)
163 {
164 for (Map.Entry<Class<?>, Integer> entry : typeMap.entrySet())
165 {
166 if (entry.getKey().isAssignableFrom(type))
167 {
168 return entry.getValue();
169 }
170 }
171
172 return null;
173 }
174
175 @Override
176 public Iterator<M> iterator()
177 {
178 return metadatas.iterator();
179 }
180
181 @Override
182 public String toString()
183 {
184 StringBuilder builder = new StringBuilder();
185 builder.append(this.getClass().getSimpleName());
186 builder.append("[metadatas=");
187 builder.append(metadatas.size());
188 builder.append(",coders=");
189 builder.append(coders.size());
190 builder.append("]");
191 return builder.toString();
192 }
193
194 protected void trackMetadata(List<M> metadatas)
195 {
196 for (M metadata : metadatas)
197 {
198 trackMetadata(metadata);
199 }
200 }
201
202 protected void trackMetadata(M metadata)
203 {
204 synchronized (metadatas)
205 {
206
207 boolean duplicate = false;
208
209
210 if (metadatas.contains(metadata))
211 {
212 duplicate = true;
213 }
214
215
216 Class<?> type = metadata.getObjectType();
217 if (typeMap.containsKey(type))
218 {
219 duplicate = true;
220 }
221
222 if (duplicate)
223 {
224 StringBuilder err = new StringBuilder();
225 err.append("Duplicate decoder for type: ");
226 err.append(type);
227 err.append(" (class ").append(metadata.getCoderClass().getName());
228
229
230 M dup = getMetadataByType(type);
231 err.append(" duplicates ");
232 err.append(dup.getCoderClass().getName());
233 err.append(")");
234 throw new IllegalStateException(err.toString());
235 }
236
237
238 Class<? extends T> coderClass = metadata.getCoderClass();
239 int newidx = metadatas.size();
240 metadatas.add(metadata);
241 coders.add(coderClass);
242 typeMap.put(type,newidx);
243
244 List<Integer> indexes = implMap.get(coderClass);
245 if (indexes == null)
246 {
247 indexes = new ArrayList<>();
248 }
249 if (indexes.contains(newidx))
250 {
251
252 }
253 indexes.add(newidx);
254 implMap.put(coderClass,indexes);
255 }
256 }
257 }