Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/vertx-howtos/protobuf-eventbus-howto

Exchanging generated Protobuf classes on the Event Bus
https://github.com/vertx-howtos/protobuf-eventbus-howto

eventbus protobuf vertx

Last synced: about 1 month ago
JSON representation

Exchanging generated Protobuf classes on the Event Bus

Awesome Lists containing this project

README

        

= Exchanging generated Protobuf classes on the Event Bus
:page-permalink: /
:page-github: vertx-howtos/protobuf-eventbus-howto

This document will show you how to exchange messages of types generated by https://developers.google.com/protocol-buffers[Protocol Buffers] on the Event Bus.

== What you will build

You will build an application that periodically generates a greeting message.
The application consists in:

* a sender verticle which sends a `GreetingRequest`
* a receiver verticle which replies to requests with a `GreetingResponse`

== What you need

* A text editor or an IDE,
* Java 11 or higher

== Create a project

Browse to https://start.vertx.io.
Click on advanced options to expand the hidden panel and then change the value of the following fields:

* _Group Id_: set to `io.vertx.howtos`
* _Artifact Id_: set to `protobuf-eventbus-howto`
* _Dependencies_: add `Hazelcast Cluster Manager`
* _Package_: set to `io.vertx.howtos.protobuf.eventbus`

When you're done, click on _Generate Project_ and extract the generated archive content somewhere on your filesystem.

[TIP]
====
You may alternatively do this from the command line:

[source,shell]
----
curl -G https://start.vertx.io/starter.zip -d "groupId=io.vertx.howtos" -d "artifactId=protobuf-eventbus-howto" -d "packageName=io.vertx.howtos.protobuf.eventbus" -d "vertxDependencies=vertx-hazelcast" -d "jdkVersion=11" -d "buildTool=maven" --output protobuf-eventbus-howto.zip
unzip -d protobuf-eventbus-howto protobuf-eventbus-howto.zip
----
====

Before coding, we need to make some adjustments to the build file:

* configure a custom Vert.x `Launcher` class (that will be used as entry point when running the executable JAR)
* add a dependency to _Protocol Buffers_
* configure Maven plugins to generate message classes from a `.proto` file.

Here is the content of the `pom.xml` file you should be using:

[source,xml,role="collapsed"]
.Maven `pom.xml`
----
include::pom.xml[]
----

== Implementation of the application

=== Definition of the messages

In `src/main/proto/greetings.proto`, we define:

* a `GreetingRequest` which holds a `name`, and
* a `GreetingReply` which holds a `message`

[source,protobuf]
.greetings.proto
----
include::src/main/proto/greetings.proto[]
----

=== Receiver verticle

The receiver verticle registers a consumer on the Event Bus.
When a request is received:

. the request is printed to the console along with its system _hash code_
. a reply is generated
. the reply is printed to the console along with its system _hash code_
. the reply is sent

[source,java]
.ReceiverVerticle.java
----
include::src/main/java/io/vertx/howtos/protobuf/eventbus/ReceiverVerticle.java[]
----

NOTE: The system _hash code_ is printed so that when we run the application in a single virtual machine, we can see whether objects are duplicated or not by the Event Bus.

=== Sender verticle

The sender verticle schedules a periodic task.
Every five seconds:

. a request is generated
. the request is printed to the console along with its system _hash code_
. the request is sent
. the reply is printed to the console along with its system _hash code_

[source,java]
.SenderVerticle.java
----
include::src/main/java/io/vertx/howtos/protobuf/eventbus/SenderVerticle.java[]
----

=== The EventBus codec

When designing the codec for Protocol Buffer message classes, we can take advantage of their properties:

* all messages are `Serializable` in the sense of the Java platform
* message objects are immutable

Therefore, message classes can be serialized/deserialized transparently when sent/received to/from the network.
Moreover, we do not need to duplicate message objects when they are exchanged locally.

[source,java]
.ProtobufCodec.java
----
include::src/main/java/io/vertx/howtos/protobuf/eventbus/ProtobufCodec.java[]
----

For safety reasons, we do not want to deserialize just any object on the receiver side.
This is why we use a `CheckedClassNameObjectInputStream` instead of a plain `ObjectInputStream`.

The implementation guarantees that only some classes are allowed:

* our message classes, of course
* Protocol Buffer's Java implementation classes
* classes allowed by default by the Vert.x Event Bus (e.g. byte arrays)

[source,java]
.CheckedClassNameObjectInputStream.java
----
include::src/main/java/io/vertx/howtos/protobuf/eventbus/CheckedClassNameObjectInputStream.java[]
----

Finally, in a custom `Launcher` class, we must:

* register this codec
* configure the Event Bus so that it uses this codec when the type of the message's body belongs to our package

[source,java]
.CustomLauncher.java
----
include::src/main/java/io/vertx/howtos/protobuf/eventbus/CustomLauncher.java[]
----

== Running the application

First you must build the application:

[source,shell]
----
./mvnw clean package
----

Then start the receiver:

[source,shell]
----
java -Djava.net.preferIPv4Stack=true -jar target/protobuf-eventbus-howto-1.0.0-SNAPSHOT-fat.jar io.vertx.howtos.protobuf.eventbus.ReceiverVerticle -cluster
----

When it is ready, you will see: `INFO: Succeeded in deploying verticle`.

Now start the sender in another terminal:

[source,shell]
----
java -Djava.net.preferIPv4Stack=true -jar target/protobuf-eventbus-howto-1.0.0-SNAPSHOT-fat.jar io.vertx.howtos.protobuf.eventbus.SenderVerticle -cluster
----

When it is ready, you will see: `INFO: Succeeded in deploying verticle`.

After some time, you will see in the sender console:

----
Sending request = Jane Doe (1445840961)
Received reply = Hello Jane Doe (654163465)
----

And in the receiver console:

----
Received request = Jane Doe (449456520)
Sending reply = Hello Jane Doe (522259462)
----

In clustered mode, the system _hash code_ that is printed is not important: objects living in distinct virtual machines are, obviously, different.

What about local mode?
To run the sender and the receiver in the same virtual machine, we can use a third verticle whose only purpose is to deploy them.

[source,java]
.MainVerticle.java
----
include::src/main/java/io/vertx/howtos/protobuf/eventbus/MainVerticle.java[]
----

Open a terminal, build the project again and run the executable JAR.

[source,shell]
----
./mvnw clean package
java -jar target/protobuf-eventbus-howto-1.0.0-SNAPSHOT-fat.jar
----

When it is ready, you will see: `INFO: Succeeded in deploying verticle`.

After some time, you will see in the console:

----
Sending request = Jane Doe (346056258)
Received request = Jane Doe (346056258)
Sending reply = Hello Jane Doe (1483137857)
Received reply = Hello Jane Doe (1483137857)
----

Pay attention to the system _hash code_.
Notice that the request object is the same in both the sender and receiver.
This is also true about the reply object.

== Summary

This document covered:

. creating a codec for messages of types generated by _Protocol Buffers_
. registering this codec and configuring the Event Bus to use it by default
. sending and receiving message objects locally and across the network

== See also

- https://vertx.io/docs/vertx-core/java/[The Vert.x core APIs documentation]