- create a simple Vertx project
- write simple and concise code via Vertx-Sync
- create simple REST API via Vertx-Web
- get some web content using HTTP client
- use MongoDB as an example for using of database from Vertx.
- JDK 1.8
- Maven
- MongoDB
use testDB ;
db.createCollection('Entities');
Create Vertx simple project.
It’s time now to create our Vertx project. Let’s do it! Our start point of the project is:import io.vertx.core.Vertx;
import io.vertx.core.logging.Logger;
import io.vertx.core.logging.LoggerFactory;
public class Launcher {
private static final Logger logger = LoggerFactory.getLogger(MainVerticle.class);
public static void main(String[] args) {
Vertx.vertx().deployVerticle(MainVerticle.class.getName(), h -> {
if (h.succeeded()) {
logger.info("Success: {0}", h.result());
} else {
logger.error("Something went wrong: {0}", h.cause());
}
});
}
}
- And our Vertical :
import io.vertx.ext.web.client.WebClient;
import io.vertx.ext.web.client.WebClientOptions;
import io.vertx.ext.web.handler.BodyHandler;
import io.vertx.ext.web.handler.ErrorHandler;
import java.util.List;
public class MainVerticle extends SyncVerticle {
private static final Logger
logger = LoggerFactory.getLogger(MainVerticle.class);
private static final String COLLECTION_NAME= "Entities";
private WebClient webClient;
private MongoClient mongoClient;
@Override
@Suspendable
public void start(Future<Void> startFuture) throws Exception {
super.start(startFuture);
HttpServer server = vertx.createHttpServer();
Router router = Router.router(vertx);
// enable BodyHandler globally for easiness of body accessing
router.route().handler(BodyHandler.create()).failureHandler(ErrorHandler.create());
router.route(HttpMethod.GET,
"/getWebContent").handler(Sync.fiberHandler(this::getWebContent));
router.route(HttpMethod.GET,
"/entities").handler(Sync.fiberHandler(this::getAllEntities));
router.route(HttpMethod.GET,
"/entities/:id").handler(Sync.fiberHandler(this::getEntityById));
router.route(HttpMethod.PUT,
"/entities").handler(Sync.fiberHandler(this::saveNewEntity));
// HttpServer will be automatically shared if port matches
server.requestHandler(router::accept).listen(8089);
webClient = WebClient.create(vertx, new WebClientOptions().setSsl(true));
mongoClient = MongoClient.createShared
(vertx, new JsonObject().put("connection_string", "mongodb://127.0.0.1:27017/testDb"));
}
@Suspendable
private void saveNewEntity(RoutingContext routingContext){
final String response = Sync.awaitResult
(h -> mongoClient.save(COLLECTION_NAME, routingContext.getBodyAsJson(), h));
routingContext.response().end(response);
}
@Suspendable
private void getAllEntities(RoutingContext routingContext){
final List<JsonObject> entities = Sync.awaitResult
(h -> mongoClient.find(COLLECTION_NAME, new JsonObject(), h));
routingContext.response().end(Json.encodePrettily(entities));
}
@Suspendable
private void getEntityById(RoutingContext routingContext){
final JsonObject query = new JsonObject()
.put("_id", routingContext.pathParam("id"));
final List<JsonObject> entity = Sync.awaitResult
(h -> mongoClient.find(COLLECTION_NAME, query, h));
routingContext.response()
.end(Json.encodePrettily(entity));
}
@Suspendable
private void getWebContent(RoutingContext routingContext){
final HttpResponse<Buffer> response = Sync.awaitResult
(h -> webClient.getAbs("https://www.google.com").send(h));
final String responseContent = response.bodyAsString("UTF-8");
logger.info("Result of Http request: {0}", responseContent);
routingContext.response()
.putHeader(HttpHeaderNames.CONTENT_TYPE, "text/html")
.end(responseContent);
}
}
- Launcher class is just for starting of our program and deploying of our MainVerticle.
- It has to be considered that our MainVerticle extends io.vertx.ext.sync.SyncVerticle. If it is not deployed as SyncVerticle instance fibers will not work.
- Create HttpServer and router for handling of our REST API ( following the next 3 steps):
- GET https://localhost:8089/getWebContent // request to "https://www.google.com" just for testing of async Http client.
- GET https://localhost:8089/entities
- GET https://localhost:8089/entities/:id //:id is path parameter for finding of some entity
- PUT https://localhost:8089/entities // Create a new entity record. As request body Json as payload should be applied for example : {“name”: “Charlie Harper”}
- Create WebClient and MongoClient and use their async APIs synchronously via fibers.
- It is very important to use Sync.fiberHandler() when we need to use any handlers. So for usage of fibers in a normal handler, e.g. in the request handler of an Http server we must first convert the normal handler to a fiber handler.
- To get response from async APIs that return AsyncResult<T> as callback is very easy with Sync.awaitResul() . Below is some copied documentation from Vertx about it:
final List<JsonObject> entity = Sync.awaitResult
(h -> mongoClient.find(COLLECTION_NAME, query, h));
final HttpResponse<Buffer>
response = Sync.awaitResult
(h -> webClient.getAbs("https://www.google.com").send(h));
7. The most important thing is to instrument our bytecode. Vertx use Quasar and their fiber implementation use bytecode instrumentation. We don’t need to do anything special but just have to start JVM with javaagent as VM option. For example: -javaagent:/path/to/quasar/core/quasar-core.jar. For that case we use “exec-maven-plugin” . That is content of pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project
xmlns_xsi="https://www.w3.org/2001/XMLSchema-instance"
xsi_schemaLocation="https://maven.apache.org/POM/4.0.0
https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.idle.fibers</groupId>
<artifactId>vertx-sync-fibers</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<vertx.version>3.4.1</vertx.version>
<main.verticle>org.idle.easy.fibers.MainVerticle</main.verticle>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-dependencies</artifactId>
<version>${vertx.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-web</artifactId>
<version>${vertx.version}</version>
</dependency>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-web-client</artifactId>
<version>${vertx.version}</version>
</dependency>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-auth-oauth2</artifactId>
<version>${vertx.version}</version>
</dependency>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-sync</artifactId>
<version>${vertx.version}</version>
</dependency>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-mongo-client</artifactId>
<version>${vertx.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.0.0</version>
<configuration>
<filesets>
<fileset>
<directory>${project.basedir}/src/main/generated</directory>
</fileset>
</filesets>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.6.0</version>
<configuration>
<mainClass>org.idle.easy.fibers.Launcher</mainClass>
<workingDirectory>target/classes</workingDirectory>
<executable>java</executable>
<arguments>
<argument>-javaagent:${co.paralleluniverse:quasar-core:jar}</argument>
</arguments>
</configuration>
</plugin>
</plugins>
</build>
</project>
8. Finally to start our program just type : mvn clean package exec:java And that is all :-)
