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;
20
21 import java.io.IOException;
22 import java.net.URI;
23 import java.security.Principal;
24 import java.util.ArrayList;
25 import java.util.Collections;
26 import java.util.HashMap;
27 import java.util.HashSet;
28 import java.util.List;
29 import java.util.Map;
30 import java.util.Objects;
31 import java.util.Set;
32
33 import javax.websocket.CloseReason;
34 import javax.websocket.EndpointConfig;
35 import javax.websocket.Extension;
36 import javax.websocket.MessageHandler;
37 import javax.websocket.RemoteEndpoint.Async;
38 import javax.websocket.RemoteEndpoint.Basic;
39 import javax.websocket.Session;
40 import javax.websocket.WebSocketContainer;
41
42 import org.eclipse.jetty.util.log.Log;
43 import org.eclipse.jetty.util.log.Logger;
44 import org.eclipse.jetty.websocket.api.BatchMode;
45 import org.eclipse.jetty.websocket.api.extensions.ExtensionConfig;
46 import org.eclipse.jetty.websocket.common.LogicalConnection;
47 import org.eclipse.jetty.websocket.common.WebSocketSession;
48 import org.eclipse.jetty.websocket.common.events.EventDriver;
49 import org.eclipse.jetty.websocket.jsr356.endpoints.AbstractJsrEventDriver;
50 import org.eclipse.jetty.websocket.jsr356.metadata.DecoderMetadata;
51 import org.eclipse.jetty.websocket.jsr356.metadata.EndpointMetadata;
52 import org.eclipse.jetty.websocket.jsr356.metadata.MessageHandlerMetadata;
53
54
55
56
57 public class JsrSession extends WebSocketSession implements javax.websocket.Session, Configurable
58 {
59 private static final Logger LOG = Log.getLogger(JsrSession.class);
60 private final ClientContainer container;
61 private final String id;
62 private final EndpointConfig config;
63 private final EndpointMetadata metadata;
64 private final DecoderFactory decoderFactory;
65 private final EncoderFactory encoderFactory;
66
67 private final MessageHandlerFactory messageHandlerFactory;
68
69 private final MessageHandlerWrapper wrappers[];
70 private Set<MessageHandler> messageHandlerSet;
71 private List<Extension> negotiatedExtensions;
72 private Map<String, String> pathParameters = new HashMap<>();
73 private JsrAsyncRemote asyncRemote;
74 private JsrBasicRemote basicRemote;
75
76 public JsrSession(ClientContainer container, String id, URI requestURI, EventDriver websocket, LogicalConnection connection)
77 {
78 super(container, requestURI, websocket, connection);
79 if (!(websocket instanceof AbstractJsrEventDriver))
80 {
81 throw new IllegalArgumentException("Cannot use, not a JSR WebSocket: " + websocket);
82 }
83 AbstractJsrEventDriver jsr = (AbstractJsrEventDriver)websocket;
84 this.config = jsr.getConfig();
85 this.metadata = jsr.getMetadata();
86 this.container = container;
87 this.id = id;
88 this.decoderFactory = new DecoderFactory(this,metadata.getDecoders(),container.getDecoderFactory());
89 this.encoderFactory = new EncoderFactory(this,metadata.getEncoders(),container.getEncoderFactory());
90 this.messageHandlerFactory = new MessageHandlerFactory();
91 this.wrappers = new MessageHandlerWrapper[MessageType.values().length];
92 this.messageHandlerSet = new HashSet<>();
93 }
94
95 @Override
96 public void addMessageHandler(MessageHandler handler) throws IllegalStateException
97 {
98 Objects.requireNonNull(handler, "MessageHandler cannot be null");
99
100 synchronized (wrappers)
101 {
102 for (MessageHandlerMetadata metadata : messageHandlerFactory.getMetadata(handler.getClass()))
103 {
104 DecoderFactory.Wrapper wrapper = decoderFactory.getWrapperFor(metadata.getMessageClass());
105 if (wrapper == null)
106 {
107 StringBuilder err = new StringBuilder();
108 err.append("Unable to find decoder for type <");
109 err.append(metadata.getMessageClass().getName());
110 err.append("> used in <");
111 err.append(metadata.getHandlerClass().getName());
112 err.append(">");
113 throw new IllegalStateException(err.toString());
114 }
115
116 MessageType key = wrapper.getMetadata().getMessageType();
117 MessageHandlerWrapper other = wrappers[key.ordinal()];
118 if (other != null)
119 {
120 StringBuilder err = new StringBuilder();
121 err.append("Encountered duplicate MessageHandler handling message type <");
122 err.append(wrapper.getMetadata().getObjectType().getName());
123 err.append(">, ").append(metadata.getHandlerClass().getName());
124 err.append("<");
125 err.append(metadata.getMessageClass().getName());
126 err.append("> and ");
127 err.append(other.getMetadata().getHandlerClass().getName());
128 err.append("<");
129 err.append(other.getMetadata().getMessageClass().getName());
130 err.append("> both implement this message type");
131 throw new IllegalStateException(err.toString());
132 }
133 else
134 {
135 MessageHandlerWrapper handlerWrapper = new MessageHandlerWrapper(handler,metadata,wrapper);
136 wrappers[key.ordinal()] = handlerWrapper;
137 }
138 }
139
140
141 updateMessageHandlerSet();
142 }
143 }
144
145 @Override
146 public void close(CloseReason closeReason) throws IOException
147 {
148 close(closeReason.getCloseCode().getCode(),closeReason.getReasonPhrase());
149 }
150
151 @Override
152 public Async getAsyncRemote()
153 {
154 if (asyncRemote == null)
155 {
156 asyncRemote = new JsrAsyncRemote(this);
157 }
158 return asyncRemote;
159 }
160
161 @Override
162 public Basic getBasicRemote()
163 {
164 if (basicRemote == null)
165 {
166 basicRemote = new JsrBasicRemote(this);
167 }
168 return basicRemote;
169 }
170
171 @Override
172 public WebSocketContainer getContainer()
173 {
174 return this.container;
175 }
176
177 public DecoderFactory getDecoderFactory()
178 {
179 return decoderFactory;
180 }
181
182 public EncoderFactory getEncoderFactory()
183 {
184 return encoderFactory;
185 }
186
187 public EndpointConfig getEndpointConfig()
188 {
189 return config;
190 }
191
192 public EndpointMetadata getEndpointMetadata()
193 {
194 return metadata;
195 }
196
197 @Override
198 public String getId()
199 {
200 return this.id;
201 }
202
203 @Override
204 public int getMaxBinaryMessageBufferSize()
205 {
206 return getPolicy().getMaxBinaryMessageSize();
207 }
208
209 @Override
210 public long getMaxIdleTimeout()
211 {
212 return getPolicy().getIdleTimeout();
213 }
214
215 @Override
216 public int getMaxTextMessageBufferSize()
217 {
218 return getPolicy().getMaxTextMessageSize();
219 }
220
221 public MessageHandlerFactory getMessageHandlerFactory()
222 {
223 return messageHandlerFactory;
224 }
225
226 @Override
227 public Set<MessageHandler> getMessageHandlers()
228 {
229
230 return new HashSet<MessageHandler>(messageHandlerSet);
231 }
232
233 public MessageHandlerWrapper getMessageHandlerWrapper(MessageType type)
234 {
235 synchronized (wrappers)
236 {
237 return wrappers[type.ordinal()];
238 }
239 }
240
241 @Override
242 public List<Extension> getNegotiatedExtensions()
243 {
244 if (negotiatedExtensions == null)
245 {
246 negotiatedExtensions = new ArrayList<Extension>();
247 for (ExtensionConfig cfg : getUpgradeResponse().getExtensions())
248 {
249 negotiatedExtensions.add(new JsrExtension(cfg));
250 }
251 }
252 return negotiatedExtensions;
253 }
254
255 @Override
256 public String getNegotiatedSubprotocol()
257 {
258 String acceptedSubProtocol = getUpgradeResponse().getAcceptedSubProtocol();
259 if (acceptedSubProtocol == null)
260 {
261 return "";
262 }
263 return acceptedSubProtocol;
264 }
265
266 @Override
267 public Set<Session> getOpenSessions()
268 {
269 return container.getOpenSessions();
270 }
271
272 @Override
273 public Map<String, String> getPathParameters()
274 {
275 return Collections.unmodifiableMap(pathParameters);
276 }
277
278 @Override
279 public String getQueryString()
280 {
281 return getUpgradeRequest().getRequestURI().getQuery();
282 }
283
284 @Override
285 public Map<String, List<String>> getRequestParameterMap()
286 {
287 return getUpgradeRequest().getParameterMap();
288 }
289
290 @Override
291 public Principal getUserPrincipal()
292 {
293 return getUpgradeRequest().getUserPrincipal();
294 }
295
296 @Override
297 public Map<String, Object> getUserProperties()
298 {
299 return config.getUserProperties();
300 }
301
302 @Override
303 public void init(EndpointConfig config)
304 {
305
306 encoderFactory.init(config);
307
308 decoderFactory.init(config);
309 }
310
311 @Override
312 public void removeMessageHandler(MessageHandler handler)
313 {
314 synchronized (wrappers)
315 {
316 try
317 {
318 for (MessageHandlerMetadata metadata : messageHandlerFactory.getMetadata(handler.getClass()))
319 {
320 DecoderMetadata decoder = decoderFactory.getMetadataFor(metadata.getMessageClass());
321 MessageType key = decoder.getMessageType();
322 wrappers[key.ordinal()] = null;
323 }
324 updateMessageHandlerSet();
325 }
326 catch (IllegalStateException e)
327 {
328 LOG.warn("Unable to identify MessageHandler: " + handler.getClass().getName(),e);
329 }
330 }
331 }
332
333 @Override
334 public void setMaxBinaryMessageBufferSize(int length)
335 {
336 getPolicy().setMaxBinaryMessageSize(length);
337 getPolicy().setMaxBinaryMessageBufferSize(length);
338 }
339
340 @Override
341 public void setMaxIdleTimeout(long milliseconds)
342 {
343 getPolicy().setIdleTimeout(milliseconds);
344 super.setIdleTimeout(milliseconds);
345 }
346
347 @Override
348 public void setMaxTextMessageBufferSize(int length)
349 {
350 getPolicy().setMaxTextMessageSize(length);
351 getPolicy().setMaxTextMessageBufferSize(length);
352 }
353
354 public void setPathParameters(Map<String, String> pathParams)
355 {
356 this.pathParameters.clear();
357 if (pathParams != null)
358 {
359 this.pathParameters.putAll(pathParams);
360 }
361 }
362
363 private void updateMessageHandlerSet()
364 {
365 messageHandlerSet.clear();
366 for (MessageHandlerWrapper wrapper : wrappers)
367 {
368 if (wrapper == null)
369 {
370
371 continue;
372 }
373 messageHandlerSet.add(wrapper.getHandler());
374 }
375 }
376
377 @Override
378 public BatchMode getBatchMode()
379 {
380
381 return BatchMode.OFF;
382 }
383 }