Newsletter sign-up
View all newsletters

Enterprise Java Newsletter
Stay up to date on the latest tutorials and Java community news posted on JavaWorld

Sponsored Links

Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs

Open source Java projects: Vert.x

Enterprise messaging and integration with Vert.x

  • Print
  • Feedback

Page 6 of 6

The publish() method accepts a destination, which in this case is "com.geekcap.vertxexamples.Server.announcements". Recall that the naming of this destination is arbitrary, but prefacing the type of notification (announcement in this example) with the fully-qualified name of the class makes it clear where the message came from.

Listing 5 shows the source code for the AuditVerticle class.

Listing 5. AuditVerticle.java

package com.geekcap.vertxexamples;

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.logging.Logger;
import org.vertx.java.platform.Verticle;

public class AuditVerticle extends Verticle {

    @Override
    public void start() {
        // Let's register ourselves as a listener to Server notifications
        EventBus eb = vertx.eventBus();
        Handler<Message> auditHandler = new Handler<Message>() {
            @Override
            public void handle(Message message) {
                Logger logger = container.logger();
                logger.info( "AuditVerticle here, someone requested resource: " + message.body() );
            }
        };
        eb.registerHandler( "com.geekcap.vertxexamples.Server.announcements", auditHandler );
    }
}

The AuditVerticle in Listing 5 acts much like a reporting engine: it listens for "announcements" from the Server class and then writes those out as informational log messages. When something of interest happens in the Server class, it can publish it to its announcements topic and different subscribers can do different things, such as logging the message or inserting it in a Hadoop cluster for later analysis.

Listing 5 then creates a Handler in-line instance (an anonymous inner class is created and assigned to a variable without creating the class in a separate file) that logs the message. Next, it registers a handler to the "com.geekcap.vertxexamples.Server.announcements" address by invoking the EventBus's registerHandler() method. Now, any time that the Server class publishes a message to this destination, the AuditHandler's handle() method will be invoked.

Point-to-point messaging example

Point-to-point messaging is used either when you want a message to be processed only by a single consumer or as a mechanism for components to communicate with one another asynchronously. In this section I demonstrate the latter by creating a new class that relies on a worker verticle to do its work for it, and then that worker verticle communicates the result back to the Server2.

Listing 6 shows the source code for the Server2 class.

Listing 6. Server2.java

package com.geekcap.vertxexamples;

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.HttpServerRequest;
import org.vertx.java.core.logging.Logger;
import org.vertx.java.deploy.Verticle;

import java.util.concurrent.ConcurrentMap;

public class Server2 extends Verticle {
    public void start() {

        // Create our dependent verticles
        container.deployWorkerVerticle("com.geekcap.vertxexamples.MyWorkerVerticle");

        // Start a server that handles things with point-to-point messaging
        vertx.createHttpServer().requestHandler(new Handler<HttpServerRequest>() {
            @Override
            public void handle(final HttpServerRequest req) {

                // Set a shared variable
                ConcurrentMap<String, String> map = vertx.sharedData().getMap("mymap");
                map.put("mykey", "myvalue");

                // Let's send a message to a worker verticle and wait for it to respond
                EventBus eb = vertx.eventBus();
                eb.send("request.worker", req.path, new Handler<Message<String>>() {
                    @Override
                    public void handle(Message<String> message) {
                        Logger logger = container.getLogger();
                        logger.info( "Received a reply from our worker: " + message.body );
                        req.response.headers().put("Content-Length", Integer.toString(message.body.length()));
                        req.response.write(message.body);
                    }
                });
            }
        }).listen(8080);
    }
}

The Server2 class starts by deploying a worker verticle. Worker verticles are different from standard verticles in that they do not contain an event look and are expected to be triggered by an event bus message. Worker verticles are deployed by obtaining access to the Vert.x container and invoking its deployWorkerVerticle() method.

Next, the Server2 obtains access to the EventBus, again by invoking the eventBus() method on the vertx instance variable. This time the Server2 invokes the send() method, which is the gateway to sending messages in a point-to-point fashion. In this case it sends the request path to a destination named "request.worker". The first parameter to the send() method is the destination, the second parameter is the data to send to the destination, and an optional third parameter is a Handler that can be called back by the recipient of the message.

The MyWorkerVerticle, which is shown in Listing 7, is designed to construct a response for the specified request path and send that response back to the Server2's Handler. The handler logs the response and then writes that response back to the HttpServerRequest that initiated the action. The only thing that is a little challenging is that before we're able to write back to the HttpServerRequest we need to specify the HTTP Content-Length of the response, which is just the length of the string we're returning.

Two additional Vert.x features are added to the Server2 class:

  • Logging: The container variable has a method named getLogger() that provides access to Vert.x's logger. This logger is very similar to log4j and provides methods like debug(), info(), and fatal() to log messages at different logging levels. By default, logging information will be echoed to standard output and will be written to a file named vertx.log located in the TMPDIR-defined directory.
  • Shared data: Sharing data between verticles is accomplished by executing the sharedData() method on the vertx instance and then invoking one of the shared data accessor methods. In Listing 4, we store data in a Map that is retrieved by invoking getMap(); you can likewise retrieve shared data in a Set by invoking getSet(). All of the verticles in your Vert.x instance have access to the same shared data using the same paradigm, so it is a way for you to share immutable data between verticles.

Listing 7 shows the source code for the MyWorkerVerticle class.

Listing 7. MyWorkerVerticle.java

package com.geekcap.vertxexamples;

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.logging.Logger;
import org.vertx.java.platform.Verticle;

import java.util.concurrent.ConcurrentMap;

public class MyWorkerVerticle extends Verticle {
    @Override
    public void start() {
        // Register a listener
        EventBus eb = vertx.eventBus();
        Handler<Message> workerHandler = new Handler<Message>() {
            @Override
            public void handle(Message message) {
                Logger logger = container.logger();
                logger.info( "MyWorkerVerticle just received a request for: " + message.body() );

                // Examine our shared map
                ConcurrentMap<String, String> map = vertx.sharedData().getMap("mymap");
                logger.info( "Shared data: " + map.get( "mykey" ) );

                message.reply( "<html><head><title>Worker Response</title></head><body>Hello, from the worker verticle</body></html>" );
            }
        };
        eb.registerHandler( "request.worker", workerHandler );

    }
}

The MyWorkerVerticle class creates a new Handler instance with a handle() method that processes messages from the Server2 class. Recall from Listing 6 that one of the arguments passed to the send() method was a Handler instance that could be invoked by the message recipient. Listing 7 invokes message.reply(), which sends a response back to the originator (which in this example is the Server2's Handler.)

The MyWorkerVerticle class obtains access to the EventBus and then registers its handler to listen to messages sent to the "request.worker" destination, to complete the loop.

As far as functionality, the MyWorkerVerticle simply constructs an HTML document and returns it back to the Server2 class. You could build upon this example by connecting to a database or reading data from another server to retrieve the data with which to build the response.

And you'll notice that MyWorkerVerticle retrieves the shared data from the vertx's sharedData() map.

In conclusion

As enterprise systems evolve in complexity, integration has become one of the biggest programming challenges for software developers. Vert.x addresses the complexity of integration in a couple of ways: First, it is built around an event bus that loosely couples verticles while supporting multiple programming languages. Regardless of whether code is written in Java, Ruby, Python, or JavaScript, you can seamlessly integrate it inside the Vert.x event bus. Additionally, the event bus natively supports asynchronous messaging and an event-driven architecture, which yields high-scalability and loose-coupling.

This article has presented an overview of Vert.x, its unique vernacular, and the core components that it combines to build highly scalable enterprise solutions. I demonstrated both a web server and a messaging system written in Vert.x, using the latter example to develop a publish/subscribe messaging and a point-to-point messaging solution. In the latter example I also demonstrated event logging, shared data, and the difference between standard and worker verticles. While this article has been introductory, I've touched on some of the major features that illustrate the power of Vert.x, a solution similar to Node.js but built on the JVM. I hope that you are inspired to learn more about Vert.x and the types of programming challenge it resolves.

About the author

Steven Haines is a technical architect at Kit Digital, currently working onsite at Disney in Orlando. He is the founder of www.geekcap.com, an online education website, and has written hundreds of Java-related articles as well as three books: Java 2 From Scratch, Java 2 Primer Plus, and Pro Java EE Performance Management and Optimization. He lives with his wife and two children in Apopka, Florida.

Read more about Enterprise Java in JavaWorld's Enterprise Java section.

  • Print
  • Feedback

Resources