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