# 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

```
//annotated server endpoint with all its configuration elements

@ServerEnpdoint(
    value = "/chat/",
    configurator = ChatEndpointConfigurator.class, //discussed later
    decoders = JSONToChatObjectDecoder.class,
    encoders = ChatObjectToJSONEncoder.class,
    subprotocols = {"chat"}
)
public class ChatServer {
    //business logic...
}
```

The `EndpointConfig` instance is automatically injected (at run time by the WebSocket container) as a parameter of the `@OnOpen` method

```
//server endpoint configuration in action

@OnOpen
public void onOpenCallback(Session session, EndpointConfig epConfig){
    ServerEndpointConfig serverConfig = (ServerEndpointConfig) epConfig;
    Map<String, Object> globalPropertiesMap = serverConfig.getUserProperties();
    ......
}
```

### 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

```
ServerEndpointConfig serverConfig = ServerEndpointConfig.Builder
    .create(StockTrackerEndpoint.class , "/pop-stocks/").
    .configurator(StockTrackerConfigurator.getInstance()) //discussed later
    .decoders(JSONToStockTickerObject.class)
    .encoders(StockTickerObjectToJSON.class)
    .build();
```

An instance of `ServerEndpointConfig` is made available in the `onOpen` method of the `javax.websocket.Endpoint` (as a parameter)

```
public class ProgrammaticChatClient extends Endpoint {
    @Override
    public void onOpen(Session session, EndpointConfig config){
      ServerEndpointConfig serverConfig = (ServerEndpointConfig) epConfig;
      .....
    }
}
```

## 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

```
@ClientEndpoint(
    configurator = ChatClientEndpointConfigurator.class, //discussed later
    decoders = JSONToChatObjectDecoder.class,
    encoders = ChatObjectToJSONEncoder.class,
    subprotocols = {"chat"}
)
public class ChatClient {
 //business logic...
}
```

This instance is automatically injected (at runtime) as a parameter of the `@OnOpen` method

```
//server endpoint configuration in action

@OnOpen
public void onOpenCallback(Session session, EndpointConfig epConfig){
  ClientEndpointConfig clientConfig = (ClientEndpointConfig) epConfig;
  ......
}
```

### Configuring programmatic client endpoints

Just like their server side counterparts, configuration for programmatic clients can be coded using a fluent builder API - `ClientEndpointConfig`

```
ClientEndpointConfig cec = ClientEndpointConfig.Builder
    .configurator(ChatClientConfigurator.getInstance()) //discussed later
    .decoders(JSONToStockTickerObject.class)
    .encoders(StockTickerObjectToJSON.class)
    .build();
```

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 a `getUserProperties()` method which exposes a mutable `Map`

## 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 in `ServerEndpointConfig` as well as appropriate the method in the `ServerEndpointConfig.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 in `ClientEndpointConfig` as well as appropriate the method in the `ClientEndpointConfig.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 the `Configurator` 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

```
//custom configurator

public class CustomServerEndpointConfigurator extends ServerEndpointConfig.Configurator {

    @Override
    public <T> T getEndpointInstance(Class<T> endpointClass){
        //override the default behavior by providing a 'Singleton'
        return (T) StockTickerEndpoint.getInstance();
    }

    @Override
    public boolean checkOrigin(String originHeaderValue){
        //just audit this
        audit(originHeaderValue);
        return true;
    }

    private String user;

    @Override
    public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response){
        //introspect the request headers
        System.out.println(request);

        //the authenticated user
        this.user = request.getUserPrincipal().getName();

    }

    @Override
    public List<Extension> getNegotiatedExtensions(List<Extension> installed, List<Extension> requested){
        //invoke default implementation
        return super.getNegotiatedExtensions(installed, requested);
    }

    @Override
    public String getNegotiatedSubprotocol(List<String> supported, List<String> requested){
        //invoke default implementation
        return super.getNegotiatedSubprotocol(supported, requested);
    }
}
```

```
//declaring the custom configuration

@ServerEndpoint(value = "/letschat" , configurator = CustomServerEndpointConfigurator.class)
public class AnnotatedServerEndpointExample {
  //call back life cycle method(s) implementation...
}
```

### 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)` |

```
//custom configurator

public class CustomClientEndpointConfigurator extends ClientEndpointConfig.Configurator {

    @Override
    public void beforeRequest(Map<String,List<String>> headers){
        //mutate the header
        String token = ...;
        headers.put("X-token" , Arrays.asList(token));
    }


    @Override
    public void afterResponse(HandshakeResponse hr){
        //introspect the handshake response
        System.out.println(hr.getHeaders());
    }
}
```

```
//declaring the client configuration

@ClientEndpoint(configurator = CustomClientEndpointConfigurator.class)
public class AnnotatedClientEndpointExample {
  //call back life cycle method(s) implementation...
}
```

### Let's move on...

.. and take a closer look at the **Deployment** related aspects


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://abhishek-gupta.gitbook.io/java-websocket-api-handbook/configuration.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
