vert.x Event Bus – The quick intro

Cool elephants

The vert.x framework includes a very neat way of doing remote messaging. This mechanism has the name of Event Bus. Through it messages can be sent within a single verticle instance, between different instances of the same verticle and between instances of different verticles. In addition, it also allows for within browser and browser/server messaging.

The sample application presented in this post demonstrates the different options in a very simple manner.

The server Verticle

On the server side, we start by creating the HTTP server in the Verticle.start() method. The HTTP server handler will simple provide access to all files in the “webroot” directory.

		HttpServer server = vertx.createHttpServer();

		// Register HTTP handler
		server.requestHandler(new Handler() {

			@Override
			public void handle(HttpServerRequest req) {
				String file = req.path.equals("/") ? "index.html" : req.path;
				req.response.sendFile("webroot/" + file);
			}

		});

The next step is to create the SockJS server that will be used to bridge messages from browser to server and vice versa.

Notice that for this example no inbound or outbound permissions are set, meaning that everything will be allowed to pass through between client and server.

Another detail to pay attention to is the “prefix” value passed to the SockJS bridge. This prefix is basically the Event Bus HTTP end-point address and used by the browser to communicate with the server side. Once a connection has been established by the browser messages can be sent from each side of the communication channel.

		// Set security permission to let everything go through
		JsonArray permitted = new JsonArray();
		permitted.add(new JsonObject());

		// Create SockJS and bridge it to the Event Bus
		SockJSServer sockJSServer = vertx.createSockJSServer(server);
		sockJSServer.bridge(new JsonObject().putString("prefix", "/eventbus"),
				permitted, permitted);

With the SockJS in place the last step is to register some handlers for the server side. This demo application registers two handlers on the same destination address “app.conduit”. One handler is “local” and the other “shared”. Local handlers are not shared among instances of the same verticle whenever an application is set to run in “cluster” mode. For purpose of this app, both handlers will simply log the received message.

		EventBus eb = vertx.eventBus();

		// Register Handler 1
		eb.registerLocalHandler("app.conduit",
				new Handler<Message>() {

					@Override
					public void handle(Message message) {
						logger.info("Handler 1 (Local) received: "
								+ message.body.toString());
					}

				});

		// Register Handler 2
		eb.registerHandler("app.conduit", new Handler<Message>() {

			@Override
			public void handle(Message message) {
				logger.info("Handler 2 (Shared) received: " + message.body.toString());
			}

		});

The full server side source is shown below.

EventBusTestServer.java

package org.riaconnection.vertx.server;

import org.vertx.java.core.Handler;
import org.vertx.java.core.eventbus.EventBus;
import org.vertx.java.core.eventbus.Message;
import org.vertx.java.core.http.HttpServer;
import org.vertx.java.core.http.HttpServerRequest;
import org.vertx.java.core.json.JsonArray;
import org.vertx.java.core.json.JsonObject;
import org.vertx.java.core.logging.Logger;
import org.vertx.java.core.sockjs.SockJSServer;
import org.vertx.java.deploy.Verticle;

public class EventBusTestServer extends Verticle {
	Logger logger;

	@Override
	public void start() throws Exception {
		logger = container.getLogger();

		HttpServer server = vertx.createHttpServer();

		// Register HTTP handler
		server.requestHandler(new Handler() {

			@Override
			public void handle(HttpServerRequest req) {
				String file = req.path.equals("/") ? "index.html" : req.path;
				req.response.sendFile("webroot/" + file);
			}

		});

		// Set security permission to let everything go through
		JsonArray permitted = new JsonArray();
		permitted.add(new JsonObject());

		// Create SockJS and bridge it to the Event Bus
		SockJSServer sockJSServer = vertx.createSockJSServer(server);
		sockJSServer.bridge(new JsonObject().putString("prefix", "/eventbus"),
				permitted, permitted);

		EventBus eb = vertx.eventBus();

		// Register Handler 1
		eb.registerLocalHandler("app.conduit",
				new Handler<Message>() {

					@Override
					public void handle(Message message) {
						logger.info("Handler 1 received: "
								+ message.body.toString());
					}

				});

		// Register Handler 2
		eb.registerHandler("app.conduit", new Handler<Message>() {

			@Override
			public void handle(Message message) {
				logger.info("Handler 2 received: " + message.body.toString());
			}

		});

		// Start the server
		server.listen(8080);
	}
}

The client side

For the client side we have a very simple HTML and Javascript web page.

As you might expect, the first step is to connect the client to the Event Bus end-point.

	  	  	eb = new vertx.EventBus("http://localhost:8080/eventbus");

Once a connection happens the web page allows for messages to be submitted in either “publish” or “send” mode. A publish submission will have the message handled by all handlers subscribed to a single address whilst a send submission will have the message handled by a single handler on a round-robin fashion.

		function submitMessage(type, address,  message) {
			if (eb) {
				var json = {text: message};
				if (type == 'send') {
					eb.send(address, {text: 'Send message: ' + message});
				} else {
					eb.publish(address, {text: 'Publish message: ' + message});
				}
			}
		}

Event Bus handlers can also be added on the client side in the same fashion that handlers can be registered on the server side. The code snippet below show how easy it is to register and unregisters event bus handlers on the browser side.

		function browserHandler(msg, replyTo) {
			$('#received').append(msg.text + "
");
		}

		function subscribe(address) {
			if (eb) {
				eb.registerHandler(address, browserHandler);
				$('#subscribed').append($("<code>").text("Address:" + address));
				$('#subscribed').append($("</code>
"));
			}
		}

		function unsubscribe(address) {
			if (eb) {
				eb.unregisterHandler(address, browserHandler);
			}
		}

The source code for the client is shown below:

index.html


	Vert.X Event Bus - Quick Introduction</pre>
<h1>Vert.X Event Bus Test App</h1>
<form onsubmit="return false;">
		<input id="connectButton" type="button" value="Open connection" />
	</form>
<div id="submitForm"><form onsubmit="return false;">
		    Message:<input id="sendMessage" type="text" value="Hello from Vert.X!" />
		    <input type="radio" name="submissionType" value="publish" /> Publish
			<input type="radio" name="submissionType" value="send" checked="checked" /> Send
		    <input id="submitButton" type="button" value="Submit message" />
		</form><form onsubmit="return false;">
			<input type="checkbox" name="enableHandlerOnBrowser" value="true" />Enable message handler on browser

		</form></div>
<pre>

	Messages received on browser handler:

</pre>

<hr />

<div id="received" class="innerbox" style="width: 400px; height: 275px;"></div>
<pre>
<script type="text/javascript" src="js/jquery-1.7.1.min.js"></script><script type="text/javascript" src="js/sockjs-0.2.1.min.js"></script>
<script type="text/javascript" src="js/vertxbus.js"></script><script type="text/javascript">// <![CDATA[
		var eb = null;
		var addressName = 'app.conduit';

		function submitMessage(type, address,  message) {
			if (eb) {
				var json = {text: message};
				if (type == 'send') {
					eb.send(address, {text: 'Send message: ' + message});
				} else {
					eb.publish(address, {text: 'Publish message: ' + message});
				}
			}
		}

		function browserHandler(msg, replyTo) {
			$('#received').append(msg.text + "
");
		}

		function subscribe(address) {
			if (eb) {
				eb.registerHandler(address, browserHandler);
				$('#subscribed').append($("<code>").text("Address:" + address));
				$('#subscribed').append($("</code>
"));
			}
		}

		function unsubscribe(address) {
			if (eb) {
				eb.unregisterHandler(address, browserHandler);
			}
		}

	  	function closeConn() {
			if (eb) {
				eb.close();
			}
			$('#connectButton').val("Open Connection");
			$("#connectButton").on('click.openConnection', function() {
				openConn();
			});
		}

	  	function openConn() {
	  	  	eb = new vertx.EventBus("http://localhost:8080/eventbus");

	  	  	eb.onclose = function() {
				eb = null;
				$('#submitForm').hide();
			};

			eb.onopen = function() {
				$('#connectButton').val('Close Connection');
				$("#connectButton").off('click.openConnection');
				$('#connectButton').on('click.closeConnection', function() {
					$("#connectButton").off('click.closeConnection');
					closeConn();
				});

				$('#submitForm').show();
			};
		}

		$(document).ready(function() {
			$('#submitForm').hide();

			$("#submitButton").click(function() {
				submitMessage($("input[@name=submissionType]:checked").val(), addressName, $("#sendMessage").val());
			});

			$('input[@name=enableHandlerOnBrowser]:checkbox').change(function() {
				if (this.checked) {
					subscribe(addressName);
				} else {
					unsubscribe(addressName);
				}
			});

			closeConn();
		});

// ]]></script>

Full source code is available at github.

Advertisements

About CrazyPenguin

Software Engineer
This entry was posted in Java, JavaScript, Vert.X IO. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s