Configuration
In this lesson, we will dive into configuration parameters associated with WebSocket endpoints. Simply put, Configuration is nothing but a bunch of (meta) data associated with an endpoint (server or client). You will learn about
Server endpoint configuration (for both annotated and programmatic endpoints)
Client endpoint configuration (for both annotated and programmatic endpoints)
(Server & client) Endpoint Configurators
From an API perspective, a WebSocket endpoint Configuration is represented by the EndpointConfig
interface which is extended by ServerEndpointConfig
and ClientEndpointConfig
for server and client respectively
Server configuration
Before we dive into the details, here is a quick snapshot of the related interfaces
Class/Interface
Description
ServerEndpointConfig
A derivative of EndpointConfig
interface which is specific for configuration related to server side WebSocket endpoints
ServerEndpointConfig.Builder
Used only for programmatic server endpoints to build a ServerEndpointConfig
instance
ServerEndpointConfig.Configurator
An interface whose custom implementation allows sharing of global (for all endpoints) available logic/state as well opportunity to intercept the WebSocket handshake process (via method override)
Configuring annotated server endpoints
Annotated server endpoints are configured implicitly via the elements of the @ServerEndpoint
annotation. The WebSocket container picks up the value from the annotation elements and creates an instance of EndpointConfig
behind the scenes
The EndpointConfig
instance is automatically injected (at run time by the WebSocket container) as a parameter of the @OnOpen
method
Configuring programmatic server endpoints
Programmatic endpoints need (explicit) coding as far as configuration is concerned. This is because of the fact that programmatic endpoints are deployed differently and need an instance of ServerEndpointConfig
Don't worry about the deployment aspect since it's covered in detail in the next lesson
Here is where the fluent builder ServerEndpointConfig.Builder
comes into picture. Let's look at an example which demonstrates it's usage
An instance of ServerEndpointConfig
is made available in the onOpen
method of the javax.websocket.Endpoint
(as a parameter)
Client configuration
You must have built a fair understanding about WebSocket clients from the WebSocket Client API lesson. They too have configuration parameters associated with them which are used while connecting to WebSocket server endpoints. Before we dive into the details, here is a quick snapshot of the related interfaces
Class/Interface
Description
ClientEndPointConfig
A derivative of EndpointConfig
interface which is specific for configuration related to client side WebSocket endpoints
ClientEndpointConfig.Builder
Used only for programmatic client endpoints to build a ClientEndpointConfig
instance
ClientEndpointConfig.Configurator
The client side equivalent of ServerEndpointConfig.Configurator
Configuring annotated client endpoints
Annotated client endpoints are configured implicitly via the elements of the @ClientEndpoint
annotation
This instance is automatically injected (at runtime) as a parameter of the @OnOpen
method
Configuring programmatic client endpoints
Just like their server side counterparts, configuration for programmatic clients can be coded using a fluent builder API - ClientEndpointConfig
This configuration object is used while initiating connection to a WebSocket endpoint. Please refer to the WebSocket Client API chapter for code samples
Additional notes
As you might have already noticed, there is not much of a difference b/w annotated client and server side configurations, except for the fact that a client endpoint does not have the concept of a path or a URL where its listening for connections - that's something that a server endpoint does
An
EndpointConfig
instance provides the capability to store (global) properties which are common to all instances of an endpoint. It does so by providing agetUserProperties()
method which exposes a mutableMap
The big picture
Annotated and programmatic endpoint configuration are handled differently, but the end result is the same. Below is a table which illustrates this point for both server and client endpoints
For server endpoints, the table shows the mapping b/w corresponding element of the
@ServerEndpoint
annotation, the corresponding method inServerEndpointConfig
as well as appropriate the method in theServerEndpointConfig.Builder
, and
@ServerEndpoint annotation element
ServerEndpointConfig method
ServerEndpointConfig.Builder method
value
getPath()
create(Class<?> endpointClass, String path)
configurator
getConfigurator()
configurator(ServerEndpointConfig.Configurator sec)
decoders
getDecoders()
decoders(List<Class<? extends Decoder>> decoders)
encoders
getEncoders()
encoders(List<Class<? extends Encoder>> encoders)
subprotocols
getSubprotocols()
subprotocols(List<String> subprotocols)
In case of client endpoints, the table shows the mapping b/w corresponding element of the
@ClientEndpoint
annotation, the corresponding method inClientEndpointConfig
as well as appropriate the method in theClientEndpointConfig.Builder
@ClientEndpoint annotation element
ClientEndpointConfig method
ClientEndpointConfig.Builder method
configurator
getConfigurator()
configurator(ClientEndpointConfig.Configurator clientEndpointConfigurator)
decoders
getDecoders()
decoders(List<Class<? extends Decoder>> decoders)
encoders
getEncoders()
encoders(List<Class<? extends Encoder>> encoders)
subprotocols
getPreferredSubprotocols()
preferredSubprotocols(List<String> preferredSubprotocols)
Configurators
Basics
Configurator
s (which in my opinion could have been named differently) are applicable to both server and client side WebSocket endpoints. These are components which can intercept handshake phase of the WebSocket connection lifecycle. They can be used to implement a bunch of things such as
customizing the WebSocket handshake process
plugging in a custom implementation for producing endpoint instances
implementing common logic which can be used by all endpoint instances which are configured using the
Configuration
with which theConfigurator
is associated
If the developer does not override (provide a custom implementation) of a
Configurator
a default one is internally used by the container
Server side
The table below provides an overview. It lists out the methods of a ServerEndpointConfig.Configurator
which needs to be overridden to provide custom behavior
Capbility
Method in ServerEndpointConfig.Configurator
Details
Handshake modification
void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response)
a custom implementation can override this method in order to modify the HandshakeResponse
created by the runtime (in response to the handshake request)
Customizing endpoint creation
<T> T getEndpointInstance(Class<T> endpointClass)
overriding this method allows you to hook into the WebSocket endpoint substantiation process
Origin check
boolean checkOrigin(String originHeaderValue)
it provides the value of the HTTP Origin
header sent by the client during the handshake process in order to enforce security checks if required
Subprotocol negotiation
List<Extension> getNegotiatedExtensions(List<Extension> installed, List<Extension> requested)
selects the appropriate subprotocol depending upon the best match b/w what the server supports and what is being requested by the client (empty if there is no match)
Extension negotiation
String getNegotiatedSubprotocol(List<String> supported, List<String> requested)
similar to the subprotocol, the extension support can be negotiated as well
The catch If you choose to customize the endpoint creation process, (Java EE) container services like dependency injection might not available since the container default convention is being overridden
Let's look at en example
Client side
Client configurators are similar in sprirt to their server counterparts. They slightly less complicated and just define hooks for inercepting the phases before and after the handshake
Capbility
Method in ClientEndpointConfig.Configurator
Intercept Handshake
void afterResponse(HandshakeResponse hr)
, beforeRequest(Map<String,List<String>> headers)
Let's move on...
.. and take a closer look at the Deployment related aspects
Last updated