Open source Java projects: Vert.x

Enterprise messaging and integration with Vert.x

If you were excited about Node.js, Vert.x could be the next big thing for you: a similarly architected enterprise system that is built on the JVM. This installment of the Open source Java projects series introduces Vert.x with two hands-on examples based on the newly released Vert.x 2.0: First, build a simple Vert.x web server, then discover for yourself how the Vert.x event bus handles publish/subscribe and point-to-point messaging for effective enterprise integration.

When Node.js emerged a few years ago, many developers were excited about its unusual approach to building scalable server-side applications. Rather than starting heavyweight containers that would service requests using multiple threads, Node.js starts multiple lightweight, single-threaded servers and routes traffic to them. Now a similar framework has emerged, which deploys servers inside a JVM, using JVM facilities to manage traffic to lightweight server processes. In this installment of the Open source Java projects series you'll learn about Vert.x, an event-driven framework similar to Node.js, that builds on the JVM and also extends it in some important new ways.

Highlights of Vert.x

Vert.x applications are event-driven, asynchronous, and single-threaded. Vert.x processes communicate via an event bus, which is a built-in piece of Vert.x's event-driven architecture. Combining asynchronous processing, single-threaded components, and an event bus yields a high degree of scalability, and writing single-threaded applications can be a relief for Java developers accustomed to multithreaded concurrency. Arguably, the best part of Vert.x is its modular JVM-based architecture. Vert.x applications can run on virtually any operating system, and they can be written using any supported JVM-compatible programming language. A Vert.x application can be written entirely in a single language, or it could be a mash-up of modules written in different programming languages. Vert.x modules are integrated on the Vert.x event bus.

Event-based programming in Vert.x

Like other tools and frameworks I've recently covered in this series, Vert.x speaks the language of modern enterprise development, but puts its own emergent spin on familiar technology. Vert.x's event-based programming model is a mix of standard and unique features. Vert.x applications are largely written by defining event-handlers, which do things like manage HTTP requests and pass messages through the event bus. Unlike traditional event-based applications, however, Vert.x applications are guaranteed not to block. Rather than opening a socket to a server, requesting a resource, and then waiting (blocking) for the response, Vert.x sends the response to your application asynchronously, via an event handler.

Vert.x's programming framework includes some vernacular that will be helpful to know when you work through the two demo applications later in this article:

  • A verticle is the unit of deployment in Vert.x. Every verticle contains a main method that starts it. An application may be a single verticle or may consist of multiple verticles that communicate with one another via the event bus.
  • Verticles run inside of a Vert.x instance. Each Vert.x instance runs in its own JVM instance and can host multiple verticles. A Vert.x instance ensures that verticles are isolated from each other by running each one in its own classloader, so that there is no risk of one instance modifying another's static variables. A host may run a single Vert.x instance or multiple ones.
  • A Vert.x instance guarantees that each verticle instance is always executed in the same thread. Concurrency in Vert.x is single-threaded.
  • Internally, Vert.x instances maintain a set of threads (typically one for each CPU core) that executes in an event loop: check to see if there's work to do, do it, and go to sleep.
  • Verticles communicate by passing messages using an event bus. This message-passing strategy closely resembles the Actor model employed by the Akka framework, which I profiled in May 2013.
  • While you might assume that shared data and scalability are diametrically opposed, that's only true when data is mutable. Vert.x provides a shared map and a shared-set facility for passing immutable data across verticles running in the same Vert.x instance.
  • Vert.x uses relatively few threads to create an event loop and execute verticles. But in some cases a verticle needs to do something either computationally expensive, or that might block, such as connecting to a database. When this happens Vert.x allows you to mark a verticle instance as a worker verticle, in which case it will be executed by a background thread pool. Vert.x ensures that worker verticles will never be executed concurrently, so you want to keep them to a minimum, but they are there to help you when you need them.

Figure 1 shows the architecture of a Vert.x system consisting of Vert.x instances, verticles, JVMs, the server host, and the event bus.

Figure 1. Architecture of a Vert.x system (click to enlarge)

Vert.x core services and modules

Vert.x functionality can be divided into two categories: core services and modules. Core services are services that can be directly called from a verticle and include clients and servers for TCP/SSL, HTTP, and web sockets; services to access the Vert.x event bus; timers, buffers, flow control, file system access, shared maps and sets, logging, access configuration, SockJS servers, and deploying and undeploying verticles. Core services are fairly static and not expected to change, so all other functionality is provided by modules.

Vert.x applications and resources can easily be packaged into modules and shared via the Vert.x public module repository. Interacting with modules is asynchronous via the Vert.x event bus: send a module a message in JSON and your application will receive a response. This decoupling between modules and integration through the service bus means that modules can be written in any supported language and used by any other supported language. So, if someone writes a module in Ruby that you want to use in your Java application, nothing is stopping you from doing it!

Write a Java-based Vert.x web server

We'll start getting to know Vert.x by setting up an environment that we can use to develop our two examples for this article: a basic web server application and a message-passing system. First download Vert.x; as of this writing the latest version is 2.0.0.final. Decompress it locally and add its bin folder to your PATH. Note that you will need to install Java 7 if you haven't already.

If you're a Maven person like me, then you can simply add the following dependencies to your POM file:

Listing 1. Maven POM for Vert.x

   <dependency>
        <groupId>io.vertx</groupId>
        <artifactId>vertx-core</artifactId>
        <version>2.0.0-final</version>
        </dependency>
        <dependency>
          <groupId>io.vertx</groupId>
          <artifactId>vertx-platform</artifactId>
          <version>2.0.0-final</version>
        </dependency>

Vert.x's "Hello, World" application is a web server, a good starter application for getting to know Vert.x's event-based programming model. The in-house Vert.x tutorial demonstrates how to create a web server that serves content from a directory called webroot with just a few lines of code. I've written a Java-based variation on the demo as an introductory exercise.

Listing 2 shows the contents of my Server.java file, which is very similar to the one found on the Vert.x homepage. Download the source code for this article to see the complete file.

Listing 2. Server.java

package com.geekcap.vertxexamples;

import org.vertx.java.core.Handler;
import org.vertx.java.core.http.HttpServerRequest;
import org.vertx.java.deploy.Verticle;

public class Server extends Verticle {
    public void start() {
        vertx.createHttpServer().requestHandler(new Handler<HttpServerRequest>() {
            public void handle(HttpServerRequest req) {
                String file = req.path.equals("/") ? "index.html" : req.path;
                req.response.sendFile("webroot/" + file);
            }
        }).listen(8080);
    }
}

The first few lines in Listing 2 import the required Vert.x classes:

  • Handler is the base class for all handlers; in short: something happened asynchronously, so handle it!
  • HttpServerRequest represents a server-side HTTP request in Vert.x. An instance of this class will be created for each request that is handled by the server, then passed to your application via the Handler instance (which you will have registered with the HttpServer).
  • Verticle is the primary unit of deployment in a Vert.x application. In order to use Vert.x, you need to extend the Verticle class and override the start() method, which is the entry-point to your Verticle.

See the Vert.x Javadoc to learn more about these classes.

Notice the vertx variable in Listing 2: What is it for? The Verticle class defines vertx as a protected member variable (that your Verticle inherits), which provides access to the Vert.x runtime. The vertx variable is of type Vertx, which exposes the following methods:

  • createHttpClient() creates an HTTP/HTTPS client
  • createHttpServer() creates an HTTP/HTTPS server
  • createNetClient() creates a TCP/SSL client
  • createNetServer() creates a TCP/SSL server
  • creatSockJSServer() creates a SockJS server that wraps an HTTP server
  • eventBus() provides your application access to the event bus
  • fileSystem() provides your application access to the file system
  • sharedData() provides your application access to the shared data object, which can be used to share data between Verticles

The code in Listing 2 creates a new HTTP server, retrieves its request-handler reference, and sets the request handler to a newly created HttpServerRequest handler. The Handle interface defines a method named handler() and uses generics to define the type of instance that is passed to it in the class definition; in this case HttpServerRequest. The HttpServerRequest then defines the following fields:

  • method is a String containing the method of the given request, such as GET, POST, PUT, DELETE, and so forth.
  • path is a String containing the requested path, such as /index.html.
  • query is a String containing the query parameters, such as the part that follows the question mark in the following: ?key=value.
  • response is a reference to an HttpServerResponse that represents the response to the HTTP request.
  • uri is the complete URI of the request.

Listing 2 completes by mapping an empty request -- "/" -- to index.html, and then invoking the HttpServerResponse's sendFile() method to tell Vert.x to stream the specified file back to the caller.

In summary, the Server class accesses the Vert.x runtime, asks it to create a new HTTP server, and registers a Handler (that expects an HttpServerRequest variable) with the HttpServer. In the Handler's handle() method, the Server class serves files from the filesystem located in the webroot directory, which is relative to wherever you launched the Server Verticle from.

Building the web server

Let's build the sample application, then we'll use Vert.x to execute it. The Maven POM file for this project is shown in Listing 3.

1 2 3 Page
Join the discussion
Be the first to comment on this article. Our Commenting Policies
See more