This document will show you how to exchange messages of types generated by Protocol Buffers on the Event Bus.
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
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: 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:
pom.xml
link:pom.xml[role=include]
In src/main/proto/greetings.proto
, we define:
-
a
GreetingRequest
which holds aname
, and -
a
GreetingReply
which holds amessage
link:src/main/proto/greetings.proto[role=include]
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
link:src/main/java/io/vertx/howtos/protobuf/eventbus/ReceiverVerticle.java[role=include]
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. |
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
link:src/main/java/io/vertx/howtos/protobuf/eventbus/SenderVerticle.java[role=include]
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.
link:src/main/java/io/vertx/howtos/protobuf/eventbus/ProtobufCodec.java[role=include]
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)
link:src/main/java/io/vertx/howtos/protobuf/eventbus/CheckedClassNameObjectInputStream.java[role=include]
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
link:src/main/java/io/vertx/howtos/protobuf/eventbus/CustomLauncher.java[role=include]
First you must build the application:
./mvnw clean package
Then start the receiver:
java -Djava.net.preferIPv4Stack=true -jar target/protobuf-eventbus-howto-1.0.0-SNAPSHOT-fat.jar run 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:
java -Djava.net.preferIPv4Stack=true -jar target/protobuf-eventbus-howto-1.0.0-SNAPSHOT-fat.jar run 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.
link:src/main/java/io/vertx/howtos/protobuf/eventbus/MainVerticle.java[role=include]
Open a terminal, build the project again and run the executable JAR.
./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.
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