Skip to content

Package: ServerEndpointConfig$Configurator

ServerEndpointConfig$Configurator

nameinstructionbranchcomplexitylinemethod
ServerEndpointConfig.Configurator()
M: 3 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
checkOrigin(String)
M: 5 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
fetchContainerDefaultConfigurator()
M: 18 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 4 C: 0
0%
M: 1 C: 0
0%
getContainerDefaultConfigurator()
M: 9 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
getEndpointInstance(Class)
M: 5 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
getNegotiatedExtensions(List, List)
M: 6 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
getNegotiatedSubprotocol(List, List)
M: 6 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
modifyHandshake(ServerEndpointConfig, HandshakeRequest, HandshakeResponse)
M: 1 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%

Coverage

1: /*
2: * Copyright (c) 2018, 2021 Oracle and/or its affiliates and others.
3: * All rights reserved.
4: *
5: * This program and the accompanying materials are made available under the
6: * terms of the Eclipse Public License v. 2.0, which is available at
7: * http://www.eclipse.org/legal/epl-2.0.
8: *
9: * This Source Code may also be made available under the following Secondary
10: * Licenses when the conditions for such availability set forth in the
11: * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
12: * version 2 with the GNU Classpath Exception, which is available at
13: * https://www.gnu.org/software/classpath/license.html.
14: *
15: * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
16: */
17:
18: package jakarta.websocket.server;
19:
20: import java.util.ArrayList;
21: import java.util.Collections;
22: import java.util.List;
23: import java.util.ServiceLoader;
24: import jakarta.websocket.Decoder;
25: import jakarta.websocket.Encoder;
26: import jakarta.websocket.EndpointConfig;
27: import jakarta.websocket.Extension;
28: import jakarta.websocket.HandshakeResponse;
29:
30: /**
31: * The ServerEndpointConfig is a special kind of endpoint configuration object that contains web socket configuration
32: * information specific only to server endpoints. For developers deploying programmatic endpoints, ServerEndpointConfig
33: * objects can be created using a {@link ServerEndpointConfig.Builder}. Certain configuration operations can be
34: * customized by providing a {@link ServerEndpointConfig.Configurator}
35: *
36: * @author dannycoward
37: */
38: public interface ServerEndpointConfig extends EndpointConfig {
39:
40: /**
41: * Returns the Class of the endpoint this configuration is configuring. If the endpoint is an annotated endpoint,
42: * the value is the class of the Java class annotated with @ServerEndpoint. if the endpoint is a programmatic, the
43: * value is the class of the subclass of Endpoint.
44: *
45: * @return the class of the endpoint, annotated or programmatic.
46: */
47: Class<?> getEndpointClass();
48:
49: /**
50: * Return the path for this endpoint configuration. The path is the URI or URI-template (level 1) relative to the
51: * websocket root of the server to which the endpoint using this configuration will be mapped. The path is always
52: * non-null and always begins with a leading "/".
53: *
54: * @return the relative path for this configuration.
55: */
56: String getPath();
57:
58: /**
59: * Return the websocket subprotocols configured.
60: *
61: * @return the list of subprotocols, the empty list if none
62: */
63: List<String> getSubprotocols();
64:
65: /**
66: * Return the websocket extensions configured.
67: *
68: * @return the list of extensions, the empty list if none.
69: */
70: List<Extension> getExtensions();
71:
72: /**
73: * Return the {@link ServerEndpointConfig.Configurator} this configuration is using. If none was set by calling
74: * {@link ServerEndpointConfig.Builder#configurator(jakarta.websocket.server.ServerEndpointConfig.Configurator) } this
75: * methods returns the platform default configurator.
76: *
77: * @return the configurator in use.
78: */
79: ServerEndpointConfig.Configurator getConfigurator();
80:
81: /**
82: * The ServerEndpointConfig.Configurator class may be extended by developers who want to provide custom
83: * configuration algorithms, such as intercepting the opening handshake, or providing arbitrary methods and
84: * algorithms that can be accessed from each endpoint instance configured with this configurator.
85: *
86: * The implementation must provide a platform default configurator loading using the service loader.
87: */
88: public class Configurator {
89: private ServerEndpointConfig.Configurator containerDefaultConfigurator;
90:
91: static ServerEndpointConfig.Configurator fetchContainerDefaultConfigurator() {
92:• for (ServerEndpointConfig.Configurator impl : ServiceLoader
93: .load(jakarta.websocket.server.ServerEndpointConfig.Configurator.class)) {
94: return impl;
95: }
96: throw new RuntimeException("Cannot load platform configurator");
97: }
98:
99: /**
100: * Return the platform default configurator.
101: *
102: * @return the platform default configurator
103: *
104: * @since WebSocket 2.1
105: */
106: public ServerEndpointConfig.Configurator getContainerDefaultConfigurator() {
107:• if (this.containerDefaultConfigurator == null) {
108: this.containerDefaultConfigurator = fetchContainerDefaultConfigurator();
109: }
110: return this.containerDefaultConfigurator;
111:
112: }
113:
114: /**
115: * Return the subprotocol the server endpoint has chosen from the requested list supplied by a client who wishes
116: * to connect, or none if there wasn't one this server endpoint liked. See
117: * <a href="http://tools.ietf.org/html/rfc6455#section-4.2.2">Sending the Server's Opening Handshake</a>.
118: * Subclasses may provide custom algorithms based on other factors.
119: *
120: * <p>
121: * The default platform implementation of this method returns the first subprotocol in the list sent by the
122: * client that the server supports, or the empty string if there isn't one.
123: *
124: * @param requested the requested subprotocols from the client endpoint
125: * @param supported the subprotocols supported by the server endpoint
126: * @return the negotiated subprotocol or the empty string if there isn't one.
127: */
128: public String getNegotiatedSubprotocol(List<String> supported, List<String> requested) {
129: return this.getContainerDefaultConfigurator().getNegotiatedSubprotocol(supported, requested);
130: }
131:
132: /**
133: * Return the ordered list of extensions that t server endpoint will support given the requested extension list
134: * passed in, the empty list if none. See <a href="http://tools.ietf.org/html/rfc6455#section-9.1">Negotiating
135: * Extensions</a>
136: *
137: * <p>
138: * The default platform implementation of this method returns a list containing all of the requested extensions
139: * passed to this method that it supports, using the order in the requested extensions, the empty list if none.
140: *
141: * @param installed the installed extensions on the implementation.
142: * @param requested the requested extensions, in the order they were requested by the client
143: * @return the list of extensions negotiated, the empty list if none.
144: */
145: public List<Extension> getNegotiatedExtensions(List<Extension> installed, List<Extension> requested) {
146: return this.getContainerDefaultConfigurator().getNegotiatedExtensions(installed, requested);
147: }
148:
149: /**
150: * Check the value of the Origin header (<a href="http://tools.ietf.org/html/rfc6454">See Origin Header</a>) the
151: * client passed during the opening handshake.
152: *
153: * <p>
154: * The platform default implementation of this method makes a check of the validity of the Origin header sent
155: * along with the opening handshake following the recommendation at:
156: * <a href="http://tools.ietf.org/html/rfc6455#section-4.2">Sending the Server's Opening Handshake</a>.
157: *
158: * @param originHeaderValue the value of the origin header passed by the client.
159: * @return whether the check passed or not
160: */
161: public boolean checkOrigin(String originHeaderValue) {
162: return this.getContainerDefaultConfigurator().checkOrigin(originHeaderValue);
163: }
164:
165: /**
166: * Called by the container after it has formulated a handshake response resulting from a well-formed handshake
167: * request. The container has already checked that this configuration has a matching URI, determined the
168: * validity of the origin using the checkOrigin method, and filled out the negotiated subprotocols and
169: * extensions based on this configuration. Custom configurations may override this method in order to inspect
170: * the request parameters and modify the handshake response that the server has formulated. and the URI checking
171: * also.
172: *
173: * <p>
174: * If the developer does not override this method, no further modification of the request and response are made
175: * by the implementation.
176: * <p>
177: * The user properties made available via {@link ServerEndpointConfig#getUserProperties()} must be a per
178: * WebSocket connection (i.e. per {@link jakarta.websocket.Session}) copy of the user properties. This copy,
179: * including any modifications made to the user properties during the execution of this method must be used to
180: * populate the initial contents of {@link jakarta.websocket.Session#getUserProperties()}.
181: *
182: * @param sec the configuration object involved in the handshake
183: * @param request the opening handshake request.
184: * @param response the proposed opening handshake response
185: */
186: public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) {
187: // nothing.
188: }
189:
190: /**
191: * This method is called by the container each time a new client connects to the logical endpoint this
192: * configurator configures. Developers may override this method to control instantiation of endpoint instances
193: * in order to customize the initialization of the endpoint instance, or manage them in some other way. If the
194: * developer overrides this method, services like dependency injection that are otherwise supported, for
195: * example, when the implementation is part of the Java EE platform may not be available. The platform default
196: * implementation of this method returns a new endpoint instance per call, thereby ensuring that there is one
197: * endpoint instance per client, the default deployment cardinality.
198: *
199: * @param endpointClass the class of the endpoint
200: * @param <T> the type of the endpoint
201: * @return an instance of the endpoint that will handle all interactions from a new client.
202: * @throws InstantiationException if there was an error producing the endpoint instance.
203: */
204: public <T> T getEndpointInstance(Class<T> endpointClass) throws InstantiationException {
205: return this.getContainerDefaultConfigurator().getEndpointInstance(endpointClass);
206: }
207:
208: }
209:
210: /**
211: * The ServerEndpointConfig.Builder is a class used for creating {@link ServerEndpointConfig.Builder} objects for
212: * the purposes of deploying a server endpoint.
213: *
214: * <p>
215: * Here are some examples:
216: *
217: * <p>
218: * Building a plain configuration for an endpoint with just a path.
219: *
220: * <pre>
221: * <code>
222: * ServerEndpointConfig config = ServerEndpointConfig.Builder.create(ProgrammaticEndpoint.class, "/foo").build();
223: * </code>
224: * </pre>
225: *
226: * <p>
227: * Building a configuration with no subprotocols and a custom configurator.
228: *
229: * <pre>
230: * <code>
231: * ServerEndpointConfig config = ServerEndpointConfig.Builder.create(ProgrammaticEndpoint.class, "/bar")
232: * .subprotocols(subprotocols)
233: * .configurator(new MyServerConfigurator())
234: * .build();
235: * </code>
236: * </pre>
237: *
238: * @author dannycoward
239: */
240: public final class Builder {
241: private String path;
242: private Class<?> endpointClass;
243: private List<String> subprotocols = Collections.emptyList();
244: private List<Extension> extensions = Collections.emptyList();
245: private List<Class<? extends Encoder>> encoders = Collections.emptyList();
246: private List<Class<? extends Decoder>> decoders = Collections.emptyList();
247: private ServerEndpointConfig.Configurator serverEndpointConfigurator;
248:
249: /**
250: * Creates the builder with the mandatory information of the endpoint class (programmatic or annotated), the
251: * relative URI or URI-template to use, and with no subprotocols, extensions, encoders, decoders or custom
252: * configurator.
253: *
254: * @param endpointClass the class of the endpoint to configure
255: * @param path The URI or URI template where the endpoint will be deployed. A trailing "/" will be
256: * ignored and the path must begin with /.
257: * @return a new instance of ServerEndpointConfig.Builder
258: */
259: public static Builder create(Class<?> endpointClass, String path) {
260: return new Builder(endpointClass, path);
261: }
262:
263: // only one way to build them
264: private Builder() {
265:
266: }
267:
268: /**
269: * Builds the configuration object using the current attributes that have been set on this builder object.
270: *
271: * @return a new ServerEndpointConfig object.
272: */
273: public ServerEndpointConfig build() {
274: return new DefaultServerEndpointConfig(this.endpointClass, this.path, this.subprotocols, this.extensions,
275: this.encoders, this.decoders, this.serverEndpointConfigurator);
276: }
277:
278: private Builder(Class<?> endpointClass, String path) {
279: if (endpointClass == null) {
280: throw new IllegalArgumentException("endpointClass cannot be null");
281: }
282: this.endpointClass = endpointClass;
283: if (path == null || !path.startsWith("/")) {
284: throw new IllegalStateException("Path cannot be null and must begin with /");
285: }
286: this.path = path;
287: }
288:
289: /**
290: * Sets the list of encoder implementation classes for this builder.
291: *
292: * @param encoders the encoders
293: * @return this builder instance
294: */
295: public ServerEndpointConfig.Builder encoders(List<Class<? extends Encoder>> encoders) {
296: this.encoders = (encoders == null) ? new ArrayList<>() : encoders;
297: return this;
298: }
299:
300: /**
301: * Sets the decoder implementation classes to use in the configuration.
302: *
303: * @param decoders the decoders
304: * @return this builder instance.
305: */
306: public ServerEndpointConfig.Builder decoders(List<Class<? extends Decoder>> decoders) {
307: this.decoders = (decoders == null) ? new ArrayList<>() : decoders;
308: return this;
309: }
310:
311: /**
312: * Sets the subprotocols to use in the configuration.
313: *
314: * @param subprotocols the subprotocols.
315: * @return this builder instance
316: */
317: public ServerEndpointConfig.Builder subprotocols(List<String> subprotocols) {
318: this.subprotocols = (subprotocols == null) ? new ArrayList<>() : subprotocols;
319: return this;
320: }
321:
322: /**
323: * Sets the extensions to use in the configuration.
324: *
325: * @param extensions the extensions to use.
326: * @return this builder instance.
327: */
328: public ServerEndpointConfig.Builder extensions(List<Extension> extensions) {
329: this.extensions = (extensions == null) ? new ArrayList<>() : extensions;
330: return this;
331: }
332:
333: /**
334: * Sets the custom configurator to use on the configuration object built by this builder.
335: *
336: * @param serverEndpointConfigurator the configurator
337: * @return this builder instance
338: */
339: public ServerEndpointConfig.Builder configurator(ServerEndpointConfig.Configurator serverEndpointConfigurator) {
340: this.serverEndpointConfigurator = serverEndpointConfigurator;
341: return this;
342: }
343:
344: }
345:
346: }