Blog

Vaadin meets Vert.x

By  
Marco Collovati
Marco Collovati
·
On Dec 9, 2020 5:09:33 PM
·

Vaadin server-side applications usually run in a servlet container, such as Jetty, Tomcat, or Undertow. However, Vaadin is not limited to these environments.

The Vaadin building blocks are wisely designed on top of abstractions—VaadinRequest, VaadinResponse, VaadinService, VaadinSession, and VaadinContext are all (mainly) decoupled from the Servlet technology. This leaves the door open to implementations based on other server-side runtimes. In this post, I'd like to show how Vert.x can be used to run Vaadin applications, instead of a servlet container.

What is Vert.x

Vert.x is an open-source project from the Eclipse Foundation. On their website, Vert.x is defined as a tool-kit for building reactive applications on the JVM. Vert.x is not a framework or an application server, but a set of libraries that can be assembled to build event-driven and non-blocking applications that handle concurrency using a small number of kernel threads. Some of these threads are event loops and are responsible for dispatching the events to handlers.

Vert.x is very flexible and can be used for many different types of applications, from simple network utilities, to complex web applications, HTTP/REST microservices, and event processing. It is also polyglot, meaning you can write applications with multiple languages including Java, Kotlin, Javascript, Groovy, Ruby, and Scala.

A lot of modules are available for different purposes; here are a few examples:

  • Vert.x Web is a tool-kit for writing sophisticated modern web applications and HTTP microservices.
  • Vert.x Web Client is an easy to use advanced HTTP client.
  • JDBC client, Redis client, MongoDB client for data access.
  • Vert.x Service Discovery, Vert.x Circuit Breaker, Vert.x Config for microservice-based applications.
  • Hazelcast, Infinispan, Apache Ignite and Apache Zookeeper for clustering and high availability.
  • Many more that you can find on the documentation page.

Vert.x main concepts

The unit of deployment in Vert.x is called a Verticle: it is a software component that processes incoming events over an event loop. Events can be anything, like responses to HTTP calls or messages sent by other verticles. Each event needs to be processed in a reasonable amount of time to avoid blocking the event loop, but Vert.x does allow you to offload blocking operations to a separated worker thread. Verticles communicate with each other passing any kind of data on an event bus that supports point-to-point, request-response, and publish-subscribe messaging patterns.

It is worth noting that the event bus allows verticles to communicate in more than one JVM process. In clustered mode, messages can be sent to verticles on different nodes, but the event bus can also be accessed through a simple TCP protocol or exposed over general-purpose messaging bridges (for example AMQP and Stomp). Furthermore, a SockJS bridge allows applications to access the event bus, even from Javascript running in the browser.

Below is an example of a verticle that starts an HTTP server on port 8080 and responds with a Hello from Vert.x! message to every incoming request.

import io.vertx.core.AbstractVerticle;

public class Server extends AbstractVerticle {

 public void start() {
   vertx.createHttpServer().requestHandler(req -> {
     req.response()
       .putHeader("content-type", "text/plain")
       .end("Hello from Vert.x!");
   }).listen(8080);
 }

}

Vaadin on Vert.x

As I said before, Vaadin usually runs on servlet containers; for it to work on Vert.x, it needs a verticle that receives incoming HTTP requests and dispatches them to VaadinService, wrapping the underlying request and response into VaadinRequest and VaadinResponse instances, and serves static resources, such as Flow's client javascript bundles. This is exactly what Vertx-Vaadin provides.

Vertx-Vaadin is an adapter that lets you run Vaadin applications on top of Vert.x. This means you can mix the simplicity and robustness of Vaadin applications, with the powerful tools provided by Vert.x, such as the event bus, clustering, high availability, and failover.

Vertx-Vaadin was originally targeted to Vaadin Framework and later ported to Vaadin Flow. Support for Vaadin Framework is limited; version 7 has been completely dropped and the latest compatible version is Vaadin Framework 8.7.

This post focuses on the adapter for Vaadin Flow, called vertx-vaadin-flow. Adapter releases follow Vaadin major releases: this means you can find vertx-vaadin-flow:10.x.y, vertx-vaadin-flow:14.x.y, and so on. See the compatibility matrix for the complete list.

Vertx-Vaadin is made up of two libraries:

  • vertx-vaadin-flow: Provides a custom implementation of Vaadin’s low-level API, such as VaadinService (inspired by VaadinServletService), VaadinRequest, VaadinResponse, VaadinSession, VaadinContext, and a VaadinVerticle that bootstraps Vaadin, starts an HTTP server, and sets up a Vert.x web router to handle incoming requests.
  • vaadin-flow-sockjs: A repackage of Flow client that replaces the Atmosphere-based PUSH communication layer with a brand new SockJS implementation.

Adding Vertx-Vaadin in an existing Maven project is straightforward: just add the vertx-vaadin-flow and servlet-api dependencies; servlet-api is required by Vaadin, but not provided by Vert.x.

<dependency>
  <groupId>com.github.mcollovati.vertx</groupId>
  <artifactId>vertx-vaadin-flow</artifactId>
  <version>${vertx-vaadin.version}</version>
</dependency>

<dependency>
  <groupId>jakarta.servlet</groupId>
  <artifactId>jakarta.servlet-api</artifactId>
  <version>${servlet-api.version}</version>
  <scope>runtime</scope>
</dependency>

vaadin-flow-sockjs is needed only if the application requires the PUSH feature; in this case flow-client and flow-push dependencies must be removed from the runtime distribution. With Maven this means they should be explicitly excluded

<dependency>
<groupId>com.github.mcollovati.vertx</groupId>
<artifactId>vaadin-flow-sockjs</artifactId>
<version>${vertx-vaadin.version}</version>
</dependency>

<dependency>
<groupId>com.vaadin</groupId>
<artifactId>vaadin-core</artifactId>
<exclusions>
<exclusion>
<groupId>com.vaadin</groupId>
<artifactId>flow-push</artifactId>
</exclusion>
<exclusion>
<groupId>com.vaadin</groupId>
<artifactId>flow-client</artifactId>
</exclusion>
</exclusions>
</dependency>

For better compatibility, vaadin-flow-sockjs can be declared by specifying a classifier for the Vaadin version in use. For example:

<dependency>
<groupId>com.github.mcollovati.vertx</groupId>
<artifactId>vaadin-flow-sockjs</artifactId>
<version>${vertx-vaadin.version}</version>
<classifier>vaadin-${vaadin.version}</classifier>
</dependency>

You can now run the application by executing VaadinVerticle (or your own subclass) in any of the ways Vert.x makes available: vertx command line tool, packaged as a fat jar, using vertx-maven-plugin, etc.

The simplest way is to configure the vertx-maven-plugin as follows and then run mvn vertx:run or mvn vertx:debug:

<plugins>

...

<plugin>
<groupId>io.reactiverse</groupId>
<artifactId>vertx-maven-plugin</artifactId>
<version>${vertx-maven-plugin.version}</version>
<executions>
<execution>
<id>vmp-init-package</id>
<goals>
<goal>initialize</goal>
<goal>package</goal>
</goals>
</execution>
</executions>
<configuration>
<redeploy>true</redeploy>
<classifier>fat</classifier>
<attach>true</attach>
<stripWebJarVersion>false</stripWebJarVersion>
<webRoot>${project.build.outputDirectory}/META-INF/resources/webjars</webRoot>
<workDirectory>${project.build.directory}</workDirectory>
<!--
Custom VaadinVerticle extension
you can also use com.github.mcollovati.vertx.vaadin.VaadinVerticle
-->
<verticle>com.github.mcollovati.vaadin.exampleapp.UIVerticle</verticle>
</configuration>
</plugin>

...

</plugins>

A running example

When learning Vert.x, a good starting point is the Vert.x - From zero to (micro)-hero workshop by Clement Escoffier and Julien Viet. It shows you how to build a fake financial app based on several microservices, with an HTML+JS web dashboard presenting available services, the value of the company’s quotes, the latest set of operations made by traders, and the current state of the portfolio. It also shows the state of the different circuit breakers. The source code for the workshop can be found at https://github.com/cescoffier/vertx-microservices-workshop.

To demonstrate the usage of Vertx-Vaadin, I replace the dashboard verticle with a new one written with Vaadin. To simplify things a bit, I've set up a github repository with the solution code from the workshop and a Vaadin dashboard project for our new user interface. The original dashboard looks like this:

dashboard-initial-state

We change things a bit: we will have two separate views for financial data and for services monitoring, and a menu on the left to switch between them. To run the example, clone the repository and then run mvn package -Pproduction from the root of the project. Open 5 different terminals and launch the services in the following order:

cd quote-generator
java jar target/quote-generator-1.0-SNAPSHOT-fat.jar

cd portfolio-service
java -jar target/portfolio-service-1.0-SNAPSHOT-fat.jar

cd compulsive-traders
java -jar target/compulsive-traders-1.0-SNAPSHOT-fat.jar

cd audit-service
java-jar target/audit-service-1.0-SNAPSHOT-fat.jar

cd vaadin-trader-dashboard
java -jar target/vaadin-trader-dashboard-1.0-SNAPSHOT-fat.jar

Open your browser and request http://localhost:8080. You should see this:

pasted image 0
pasted image 0 (1)

Distributed session issues

By default, when running Vert.x in a clustered environment, Vertx-Vaadin stores sessions in a distributed map so they are available across the cluster. This allows you to achieve high availability. Data put into the clustered session store should be serialized to be transferred across the nodes; Vert.x supports serialization for all primitive and wrapper types, and for objects implementing ClusterSerializable or Serializable.

Vaadin stores the state of UI components in a VaadinSession, so all the components must be Serializable. Consequently, all non-transient references inside components must be Serializable as well.

Implementing Serializable is not a big effort for your own classes and components, but it can be a drawback when relying on third-party libraries that do not follow the rules imposed by VaadinSession. Furthermore, there are cases in which even if software components are defined as Serializable, the serialization/deserialization process may fail at runtime. For serializable lambda expressions with self-reference expressions, see this flow issue for an example. In these situations, the solution is not always easy. You can try to workaround the problem with reflection tricks, or, better, you can get in touch with the maintainers of the library to fix the problem so that other people can also benefit from your findings. If there are no other solutions, you can force Vertx-Vaadin to use a local session store by overriding VaadinVerticle createVertxVaadin method as follows (you will obviously lose session replication and high availability with this approach):

protected VertxVaadin createVertxVaadin(StartupContext startupContext) {
return VertxVaadin.create(
vertx, ExtendedLocalSessionStore.create(vertx), startupContext);
}

Simplifying session serialization is an open topic in Vertx-Vaadin; some preliminary experiments have been made with Kryo library, but investigation is still at an early stage.

Conclusion

Vert.x is a great tool for writing a reactive and distributed system; using it to run a Vaadin app is not only a good fit for micro frontends, but also for complex applications that need to interact with multiple services in different manners, such as messaging systems. With Vertx-Vaadin, Vaadin applications are no longer limited to servlet containers.

Marco Collovati
Marco Collovati
Marco lives in Udine, a town in northeast Italy, and works as a Software Developer at Vaadin. He enjoys learning new software technologies and languages, likes reading books about archeology and history, and dedicates most of his spare time to his wife and daughter.
Other posts by Marco Collovati