Our connected world is full of events, that are triggered or received by different software services. One of the big issues is that event publishers tend to describe events differently and in ways that are mostly incompatible with each other. To address this, the Serverless Working Group from the Cloud Native Computing Foundation(CNCF) recently announced the version 0.1
of the CloudEvents specification. CloudEvents aim to describe event data in a common, standardized way. To some degree a CloudEvenet is an abstract envelope with some specified attributes that describe a concrete event and its data.
In addition to the specification the CloudEvents team from the Serverless Working Group is working on different SDKs for various platforms, such as JavaScript, Golang, CSharp, Java and Python. This article will give a quick overview of Java SDK and how it can be used inside an application, built with Eclipse Vert.x. The api
is very simple and contains a generic CloudEvent class as well as a builder to create an instance of a CloudEvent:
final CloudEvent<Map<String, String>> simpleKeyValueEvent = new CloudEventBuilder()
.data(Map.of("key1", "value1", "key2", "val2"))
.eventType( "My.Cloud.Event.Type")
.eventID(UUID.randomUUID().toString();)
.source(URI.create("/trigger");)
.build();
Above we use the CloudEventBuilder
to create a very simple CloudEvent
instance! However, in isolation the API does not show its strength.
Eclipse Vert.x is a tool-kit for building reactive applications on the JVM. It is event driven and non blocking, which means applications can handle a lot of concurrency using a small number of kernel threads. Luckily there is support for Eclipse Vert.x included in the CloudEvents Java SDK:
<dependency>
<groupId>io.cloudevents</groupId>
<artifactId>http-vertx</artifactId>
<version>0.1.0</version>
</dependency>
Now that we have our CloudEvent object, capturing out event data, we want to send it to a remote cloud service, which will then process it:
final HttpClientRequest request = vertx.createHttpClient().post(8080, "localhost", "/");
// add a client response handler
request.handler(resp -> {
// react on the server response
});
// write the CloudEvent to the given HTTP Post request object
VertxCloudEvents.create().writeToHttpClientRequest(cloudEvent, request);
request.end();
After creating a HTTP Post request, we setup an async handler to deal with the future response of the server. Finally the writeToHttpClientRequest
of our VertxCloudEvents
utility is used to serialize the actual CloudEvent
object to the given HttpClientRequest
.
The VertxCloudEvents
utility also contains a different function to receive a CloudEvent inside an Eclipse Vert.x HTTP-Server application:
import io.cloudevents.http.reactivex.vertx.VertxCloudEvents;
import io.vertx.core.http.HttpHeaders;
import io.vertx.reactivex.core.AbstractVerticle;
public class CloudEventVerticle extends AbstractVerticle {
public void start() {
vertx.createHttpServer()
.requestHandler(req -> VertxCloudEvents.create().rxReadFromRequest(req)
.subscribe((receivedEvent, throwable) -> {
if (receivedEvent != null) {
// I got a CloudEvent object:
System.out.println("The event type: " + receivedEvent.getEventType())
}
}))
.rxListen(8080)
.subscribe(server -> {
System.out.println("Server running!");
});
}
}
Above we start a simple HTTPServer
, using the Vert.x API for RxJava 2. Inside of the reactive request handler we invoke the rxReadFromRequest()
method, and subscribe to the CloudEvents it returns for further processing. Now we can work with the CloudEvent object inside our own server-side framework!
Working with CloudEvents is simple and Vert.x provides a powerful JVM toolkit to either generate or receive and process CloudEvents in our system. CloudEvents are being adopted my more and more tools and frameworks such as Knative, which uses CloudEvents to exchange data between different components and services in a standardised format.
The CloudEvent Specification is in its early stages and work on the next iteration, the 0.2 version, is currently ongoing. However, even in such infancy it is generating traction and proving an increasingly useful specification to allow interoperability between applications.