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