Vert.x for real time web apps in Java

P. Madanasekaran

Introduction

The explosion in the number of mobile clients to applications, like real time chat, collaborative document editing, massively multiplayer online (MMO) games, stock trading applications etc-called “C10K” problem- and the advent of multi-core processors had their impact on software industry. Mostly our web applications have been using HTTP which follows Request-Response cycle, where only the client can initiate a request. Server can only send a response to the request in a separate connection. The half-duplex HTTP connections with their overheads could not meet the needs of these new apps. The shared memory multi-threaded model of synchronous Servlet technology also could not scale well to meet their demands. There is a growing shift to asynchronous, functional and concurrent programming and wider adoption of the Web-Socket to handle the situation. The new found of popularity of Erlang and Lisp languages and the advent of reactive frameworks like Node.js, Netty, Akka are indicators of this new trend. Vert.x, Reactor from Spring Source, Avatar from Oracle are also attempts in this direction. Spring is also expected to become reactive from version 5 –probably built on top of NIO and Netty like Vertx. In short the reactive frameworks have become main-stream and Web-socket is increasingly used to tackle “C10K”.

Web-socket

The soft real time apps require high speed connections with low latency. They also require a full- duplex connection in which server can push data when there is some data for the client even without the client asking for it. Take the example of Twitter or FaceBook Notifications. They are examples of soft real time apps. You will be notified of developments relevant to you even without you asking for it. To build such a real-time functionality into our app, WebSocket standard, which makes use of a TCP, a lower level Transport layer protocol has been laid down. It is a standard communication/wire protocol for bidirectional fully duplex connections. In other words, as against the separate connections used by client and server in HTTP request and response, both the server and the client will be using the same TCP connection when web-socket is used. HTTP is used only for initial handshake and there after messages are pushed as streams without over-heads such as cookies headers etc in TCP connections. This reduces the size of the data passed and as well as the time taken-latency. The extra over-head is only ping-pong frames to keep the connection alive.

Verticle:

Verticles are chunks of code that get deployed and run by Vert.x. Verticles can be written in any of the languages that Vert.x supports and a single application can include Verticles written in multiple languages. The different Verticle instances communicate with each other by sending messages on the event bus. They can be broadly classified into two types. 1) Standard Verticles: They are assigned an event loop thread when they are created and the start method is called with that event loop. Normally we have to code event-handlers within the Verticle which will be called later only after the concerned event has happened. Vert.x sees to it that those handlers, when called, will be executed on the same event loop. In other words all the code in your Verticle instance is always executed on the same event loop. Thus you can write all the code in your application as single threaded and let Vert.x worry about the threading and scaling 2) A worker Verticle: It is just like a standard Verticle but it’s executed not using an event loop, but using a thread from the Vert.x worker thread pool. Worker Verticles are designed for calling blocking code, and hence they won’t be run on event loops.

Event-bus:

The event bus is the nervous system of Vert.x. There is a single event bus instance for every Vert.x instance and it is obtained using the method eventBus(). The event bus allows different parts of your application to communicate with each other irrespective of what language they are written in, and whether they’re in the same Vert.x instance, or in a different Vert.x instances. It is bridged to allow client side JavaScript running in a browser to communicate on the same event bus- as we will see in our sample. The event bus forms a distributed peer-to-peer messaging system spanning multiple server nodes and multiple browsers. The event bus supports publish/subscribe, point to point, and request-response messaging. The event bus API is very simple. It basically involves registering handlers, unregistering handlers and sending and publishing messages. The event-bus is similar Channels in other languages and efficiently tunnels traffic through Web-socket/SockJS connections and makes Vertx suitable for soft real-time apps.

Web-Socket Emulation libraries

 Web-socket can provide low latency high speed connections. But older browsers without support for Web Socket are still in wide use. The emulation libraries, like Sock.js, Socket.io, are meant to handle the situation. In newer browsers they use WebSocket; in older browsers that don’t support WebSocket, these emulation libraries use “older HTTP hacks” like XHR polling, Comet etc to provide real-time communication. The standard WebSocket API is for JavaScript and there is a Java standard JSR 356 which is implemented in Java servers. Likewise there is a SockJS protocol and a SockJS server implementation in JavaScript and it is used in Node.js. Other frameworks like Spring, Vert.x have their own implementations of the SockJS server protocol in Java. We will see the Vert.x implementation. SockJs server may be implemented in any language but the JavaScript Sockjs client-side library should be used to contact the SockJS server. Then SockJS sockets will transmit data to the SockJS server. Vert.x event-bus client library uses this SockJS client library to tunnel the event bus traffic over SockJS connections to the SockJSHandler/server. SockJS Handler is bridged to Vert.x Event-bus as shown in the figure below:

The bridge is actually a built-in SockJS socket handler, which effectively extends the server-side Vert.x event bus into client side JavaScript. This creates a distributed event bus which not only spans multiple Vert.x instances on the server side, but includes client side JavaScript running in the browsers. The above-referred client side JavaScript library vertx-eventbus.js provides an API very similar to the server-side Vert.x event-bus API, which allows you to send and publish messages to the event bus and register handlers to receive messages.

Sample

There are no external dependencies. So there is no need for a dependency management tool like Maven and we will use the local Vertx installation. We will run our Java sample using runtime “vertx”. As mentioned in the earlier article, no prior pre-compilation is necessary and the Java file will be compiled on the fly and run. No elaborate directory structure is required. Just create a folder “chat” and code a java file in it. The default directory for static content is “webroot”. The “index.html” can be created under it. The client side ”vertx-event-bus.js”referred above  should also be placed in it. The code for Server.java is given below: 

Server.java


package chat; //imports classes from Vertx-Core to create  Verticle,EventBus,Vertx objects import io.vertx.core.AbstractVerticle; import io.vertx.core.eventbus.EventBus; import io.vertx.core.Vertx;
/**  Imports classes from Vertx-web to create routes and handlers
import io.vertx.ext.web.Router; import io.vertx.ext.web.handler.StaticHandler; import io.vertx.ext.web.handler.sockjs.BridgeOptions; import io.vertx.ext.web.handler.sockjs.PermittedOptions; import io.vertx.ext.web.handler.sockjs.SockJSHandler;
//imports from java SDK
import java.text.DateFormat; import java.time.Instant; import java.util.Date;

 

public class Server extends AbstractVerticle {

  //  method to run the app
public static void main(String[] args) { Vertx vertx = Vertx.vertx(); vertx.deployVerticle(new Server()); }

  @Override public void start() throws Exception {

    Router router = Router.router(vertx);

    // Allow events for the specified addresses in/out of the event bus bridge
BridgeOptions opts = new BridgeOptions() .addInboundPermitted(new PermittedOptions().setAddress("to-server")) .addOutboundPermitted(new PermittedOptions().setAddress("to-client"));

    //  the event bus bridge is created and added to the router.
SockJSHandler ebHandler = SockJSHandler.create(vertx).bridge(opts); router.route("/eventbus/*").handler(ebHandler);   //------1)

    //A router for the static content.
router.route().handler(StaticHandler.create()); vertx.createHttpServer().requestHandler(router::accept).listen(8080); //--2)

    EventBus eb = vertx.eventBus();

    // Register to listen for messages coming into the server
eb.consumer("to-server").handler(message -> {   //-------3)
// Create a timestamp string
String timestamp = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.MEDIUM).format(Date.from(Instant.now()));
// Send the message back out to all clients with the timestamp prepended.
eb.publish("to-client", timestamp + ": " + message.body());  //-----4) })
  }
}

Our Verticle implements a simple, real-time, multiuser chat. Anyone can connect to the chat application on port 8080 and type messages. The messages will be rebroadcast to all connected users via EventBus-SockJs bridge.

 Vertx-web provides a Router object. To it we have to add routes and provide handlers so that it can match the incoming request and forward it to the appropriate handler. Here only built-in handlers- StaticHandler and SockjsHandler- are used for requests for static file and for requests from a Sockjs client respectively.

  1. The static method create() creates an instance of SockJS handler. As the bridge() method, bridges the SockJS handler instance to an event-bus instance , the  handler instance is able to handle the traffic for event-bus. But as mentioned above, the client should use “vertx- event-bus” client side library. Event-bus also acts like a fire-wall. Only events from and to certain addresses are allowed in and out of Event-bus.
  2. Recall in WebSocket protocol,  HTTP is used  for initial handshake. The TCP connection used by the client to make a request for protocol upgrade becomes a permanent connection, when the server accepts the request. Thereafter it is used by both the server and the client for “pushing” messages. HTTP server is necessary for establishing the connection. Thereafter the SockJS handler pushes messages from EventBus into SockJS sockets and transports messages from SockJS sockets to specified addresses in Event-bus. The bridge() installs a built-in SockJS socket handler which takes SockJS traffic and bridges it to the event bus, thus allowing you to extend the server-side Vert.x event bus to browsers
  3. The consumer() method in the event-bus is used to register the handler for incoming messages
  4. Publish() method is used to publish the message to all clients. More than one client can register with an address to receive messages from that address- remember “publish-subscribe” and “topic” in messaging systems.

The above code creates a micro-service/self contained chat service in Java. There is no need for any web-container or application server. There is no JEE (Servlet or EJB.) Only Java APIs are used, apart from the classes in the Vertx library. It can be run anywhere if the system has Java and Vertx installed. In an earlier article we saw how to use Maven to build a fat.jar of our app, which can be run even without any local Vertx installation.

View file: The code for the html file to access the above service is given below: 

index.html


<html> <head> <title>Distributed Chat Service</title> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://code.jquery.com/jquery-1.11.2.min.js"></script>
// Sockjs JavaScript client will be downloaded and used
<script src="//cdn.jsdelivr.net/sockjs/0.3.4/sockjs.min.js"></script>
//clientside javascript vertx-event-bus supplied with Vertx 
<script src="vertx-eventbus.js"></script> <style> .inset { box-shadow: inset 0 0 4px #000000;
-moz-box-shadow: inset 0 0 4px #000000; -webkit-box-shadow: inset 0 0 4px #000000; width: 400px; border-width: 4px; padding: 5px; }

 

    input.inset { height: 40px;
}

div.inset { height: 500px; white-space: pre-wrap }
</style> </head> <body> -<script> $(function() {    //------------------1) var eb = new EventBus("/eventbus/"); //--------2) eb.onopen = function () {   //-----------3) eb.registerHandler("to-client", function (err, msg) { $('#chat').append(msg.body + "\n"); }); };

       $('#form1').submit(function (e) { e.preventDefault();                                 //-------------4)
var message = $('#msg').val(); if (message.length > 0) {

        eb.publish("to-server", message); //-----5) $('#msg').val("");
} }); }); </script> <div id="chat" class="inset"></div>

    <div> <h1> Event-bus-Sample </h1> </div> <form id="form1"> <input id="msg" type="text" size =35 class="inset"/> <input type="submit" class= "inset" />  </form> </body> </html>

In the earlier articles we used angular in the presentation layer. Here we are another popular JavaScript library –JQuery. The index.html is similar to one we used in the “Node-socket.io” sample. JQuery is used, as it is a light-weight library suitable for soft real-time apps.

  1. The alternative syntax for document.ready() is used.The code is enclosed within the function that is executed after the page is loaded.
  2. To the constructor of EventBus, the uri is passed, so that the instance can connect to the event-bus.
  3. Within the handler for onopen event, handler for registerHandler event  is registered.This handler executes/handles incoming message.
  4. When the form is submitted the framework will look for default action.To prevent that preventDefault() is called.The callback function passed to submit() is called when the form is successfully submitted.
  5. Publish() in event-bus is used to publish the message to the address in event-bus. 

Conclusion

Vert.x implements SockJS server protocol. SockJS client library is needed to pass data to this handler thorough SockJS sockets. You can download it separately and use it. To use Event-bus from a JavaScript client you have to use “vertx event-bus.js” file provided in the client folder of Vert.x distribution. On the server side you have to use “bridge()” method in SockJS server implementation of Vert.x, to bridge SockJS handler and the event-bus. Then JavaScript clients will be able to send and receive messages from event-bus. The bridge()installs a built-in SockJS socket handler which takes SockJS traffic and bridges it to the event bus, thus allowing you to extend the server-side Vert.x event bus to browsers. SockJS uses WebSocket in modern browsers.  WebSocket is an asynchronous, bidirectional, full-duplex protocol that provides a communication channel over a single TCP connection. WebSocket solves many problems which prevented the HTTP protocol from being suitable for use in modern, real-time applications.  WebSocket does not need to open multiple HTTP connections, they provide a reduction of unnecessary network traffic and reduce latency. But when you use WebSocket/SockJS in a blocking multi-threaded synchronous HTTPServer/ environment (JEE or Spring), the improvement in performance may not match the potential of the WebSocket technology. With WebSocket and SockJS, there is a permanently open connection for each client, and it is used only occasionally. Allocating a thread to each connection results in a large number of threads. Most of, threads are inactive at any one time or other. Threads require dedicated data for tasks such as administration, and switching between threads also takes time. But when they are used with a reactive framework like Vertx, the event loop will not be blocked and will be called only when there is some event/message in the connection. The multi-reactor pattern enables it to use Event-loops equal to the number of cores in the system. The event-bus bridge enables Javascript/Socks clients to use the event-bus and transmit or receive data without any latency. Thus Vertx with WebSocket/Sockjs can scale well to meet the demands of real time web apps.

Vertx is a light-weight web framework suitable for “soft real time” as well as traditional web services and applications. There are such light-weight web frameworks in other languages such as Python,Perl, JavaScript, Ruby etc. But whether it can succeed in Java, as it will mean the heavy investment in servers and synchronous Servlet based frameworks by many enterprises will become useless. There is another doubt over “whether it will be sufficiently promoted by Red-Hat, as it will harm its own important business interests –Jboss/Wildfly Server business. In the words of Eberlhard  Wolff a java champion,  “Vertx environment is quite different from traditional enterprise Java. There's just a Java process and no servlet or application container. However, there is a trend towards asynchronous systems. There are Erlang, Scala and Akka and frameworks like Spring Integration and Apache Camel - each one coming with different approaches and a different focus.... The idea of Erlang was to achieve high performance and reliability. vert.x is similar. .. The challenge is, that for its full power, servlet and application containers have to be exchanged for the vert.x runtime.”- a non-blocking, asynchronous runtime environment within JVM.








}