WebSockets with ActiveJ
Tags: java, webdev, tutorial, activej
Published: 2020-11-27 11:34:45

In this tutorial we'll create a basic client-server application with a WebSocket connection using ActiveJ framework.

You need to import the following dependencies:

    <dependencies>
        <dependency>
            <groupId>io.activej</groupId>
            <artifactId>activej-launchers-http</artifactId>
            <version>3.0</version>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
        </dependency>
    </dependencies>
The Logback dependency is optional.

In this tutorial we'll explicitly use the following ActiveJ technologies:
* [**ActiveJ HTTP**](https://activej.io/http) - high-performance asynchronous client and server implementations.
* [**ActiveInject**](https://inject.activej.io) - lightweight and powerful dependency injection library.
* [**ActiveJ Launcher**](https://activej.io/launcher) - highly generalized `main` method implementation for managing application lifecycle.
* [**ActiveJ Eventloop**](https://activej.io/eventloop) - provides efficient management of asynchronous operations without multithreading overhead.
* [**ActiveJ Promise**](https://activej.io/promise) - high-performance and handy Java Future alternative.
* [**ActiveJ Service Graph**](https://activej.io/service-graph) - designed to be used in combination with **ActiveInject** and **ActiveJ Launcher** as a means to start/stop application services according to their dependency graph.

### WebSocket Pong Server
Let’s create a “Pong” WebSocket server. For this purpose we need to provide a [`RoutingServlet`](https://github.com/activej/activej/blob/v3.0/core-http/src/main/java/io/activej/http/RoutingServlet.java) and use `mapWebSocket` method to map a `Consumer` of `WebSocket` as a servlet on `/path`. Our server will simply accept messages, print them out, and stream back a “Pong” message.

```java
public final class WebSocketPongServerExample extends HttpServerLauncher {

	@Provides
	AsyncServlet servlet() {
		return RoutingServlet.create()
				.mapWebSocket("/", webSocket -> webSocket.readMessage()
						.whenResult(message -> System.out.println("Received:" + message.getText()))
						.then(() -> webSocket.writeMessage(Message.text("Pong")))
						.whenComplete(webSocket::close));
	}

	public static void main(String[] args) throws Exception {
		WebSocketPongServerExample launcher = new WebSocketPongServerExample();
		launcher.launch(args);
	}
}
```

### WebSocket Ping Client
Now let’s create a client that will send a “Ping” message to server via WebSocket connection.

```java
public final class WebSocketPingClientExample extends Launcher {
	@Inject
	AsyncHttpClient httpClient;

	@Inject
	Eventloop eventloop;

	@Provides
	Eventloop eventloop() {
		return Eventloop.create();
	}

	@Provides
	AsyncHttpClient client(Eventloop eventloop) {
		return AsyncHttpClient.create(eventloop);
	}

	@Override
	protected Module getModule() {
		return ServiceGraphModule.create();
	}

	@Override
	protected void run() throws ExecutionException, InterruptedException {
		String url = args.length != 0 ? args[0] : "ws://127.0.0.1:8080/";
		System.out.println("\nWeb Socket request: " + url);
		CompletableFuture<?> future = eventloop.submit(() -> {
			System.out.println("Sending: Ping");
			return httpClient.webSocketRequest(HttpRequest.get(url))
					.then(webSocket -> webSocket.writeMessage(Message.text("Ping"))
							.then(webSocket::readMessage)
							.whenResult(message -> System.out.println("Received: " + message.getText()))
							.whenComplete(webSocket::close));
		});
		future.get();
	}

	public static void main(String[] args) throws Exception {
		WebSocketPingClientExample example = new WebSocketPingClientExample();
		example.launch(args);
	}
}
```
First, we provide the required dependencies: [`AsyncHttpClient`](https://github.com/activej/activej/blob/v3.0/core-http/src/main/java/io/activej/http/AsyncHttpClient.java) and an [`Eventloop`](https://github.com/activej/activej/tree/v3.0/core-eventloop/src/main/java/io/activej/eventloop/Eventloop.java) for it.
Next, we need to override Launcher's `getModule` and `run` methods. `getModule` supplies application with basic business logic module, while `run` represents the main `Launcher` method. 
In `run` method we create a supplier and override its `get` method via lambda. Here we call `AsyncHttpClient.webSocketRequest` that sends a request and returns a `Promise` of a WebSocket. Then we create a Function that sends a “Ping” message and receives a response from server.

And that's it, your WebSocket application is ready to be used. First, launch the server implementation, and then client. 
You can find the source code of the examples on [GitHub](https://github.com/activej/activej/tree/v3.0/examples/core/http/src/main/java/WebSocketPongServerExample.java).