Vert.x Application Configuration

In our pre­vi­ous post, we de­vel­oped a very sim­ple Vert.x 3 ap­pli­ca­tion, and saw how this ap­pli­ca­tion can be tested, pack­aged and ex­e­cuted. That was nice, wasn’t it? Well, ok, that was only the be­gin­ning. In this post, we are going to en­hance our ap­pli­ca­tion to sup­port ex­ter­nal con­fig­u­ra­tion.

So just to re­mind you, we have an ap­pli­ca­tion start­ing a HTTP server on the port 8080 and re­ply­ing a po­lite “Hello” mes­sage to all HTTP re­quests. The pre­vi­ous code is avail­able here. The code de­vel­oped in this post is in the post-2 branch.

So, why do we need configuration?

That’s a good ques­tion. The ap­pli­ca­tion works right now, but well, let’s say you want to de­ploy it on a ma­chine where the port 8080 is al­ready taken. We would need to change the port in the ap­pli­ca­tion code and in the test, just for this ma­chine. That would be sad. For­tu­nately, Vert.x ap­pli­ca­tions are con­fig­urable.

Vert.x con­fig­u­ra­tions are using the JSON for­mat, so don’t ex­pect any­thing com­pli­cated. They can be passed to ver­ti­cle ei­ther from the com­mand line, or using an API. Let’s have a look.

No ‘8080’ anymore

The first step is to mod­ify the io.vertx.blog.first.MyFirstVerticle class to not bind to the port 8080, but to read it from the con­fig­u­ra­tion:

public void start(Future<Void> fut) {
  vertx
      .createHttpServer()
      .requestHandler(r -> {
        r.response().end("<h1>Hello from my first " +
            "Vert.x 3 application</h1>");
      })
      .listen(
          // Retrieve the port from the configuration,
          // default to 8080.
          config().getInteger("http.port", 8080),
          result -> {
            if (result.succeeded()) {
              fut.complete();
            } else {
              fut.fail(result.cause());
            }
          }
      );
}

So, the only dif­fer­ence with the pre­vi­ous ver­sion is config().getInteger("http.port", 8080). Here, our code is now re­quest­ing the con­fig­u­ra­tion and check whether the http.port prop­erty is set. If not, the port 8080 is used as fall-​back. The re­trieved con­fig­u­ra­tion is a JsonObject.

As we are using the port 8080 by de­fault, you can still pack­age our ap­pli­ca­tion and run it as be­fore:

mvn clean package
java -jar target/my-first-app-1.0-SNAPSHOT-fat.jar

Sim­ple right ?

API-based configuration - Random port for the tests

Now that the ap­pli­ca­tion is con­fig­urable, let’s try to pro­vide a con­fig­u­ra­tion. In our test, we are going to con­fig­ure our ap­pli­ca­tion to use the port 8081. So, pre­vi­ously we were de­ploy­ing our ver­ti­cle with:

vertx.deployVerticle(MyFirstVerticle.class.getName(), context.asyncAssertSuccess());

Let’s now pass some de­ploy­ment op­tions:

port = 8081;
DeploymentOptions options = new DeploymentOptions()
    .setConfig(new JsonObject().put("http.port", port));
vertx.deployVerticle(MyFirstVerticle.class.getName(), options, context.asyncAssertSuccess());

The DeploymentOptions ob­ject lets us cus­tomize var­i­ous pa­ra­me­ters. In par­tic­u­lar, it lets us in­ject the JsonObject re­trieved by the ver­ti­cle when using the config() method.

Ob­vi­ously, the test con­nect­ing to the server needs to be slightly mod­i­fied to use the right port (port is a field):

vertx.createHttpClient().getNow(port, "localhost", "/", response -> {
  response.handler(body -> {
    context.assertTrue(body.toString().contains("Hello"));
    async.complete();
  });
});

Ok, well, this does not re­ally fix our issue. What hap­pens when the port 8081 is used too. Let’s now pick a ran­dom port:

ServerSocket socket = new ServerSocket(0);
port = socket.getLocalPort();
socket.close();

DeploymentOptions options = new DeploymentOptions()
    .setConfig(new JsonObject().put("http.port", port));

vertx.deployVerticle(MyFirstVerticle.class.getName(), options, context.asyncAssertSuccess());

So, the idea is very sim­ple. We open a server socket that would pick a ran­dom port (that’s why we put 0 as pa­ra­me­ter). We re­trieve the used port and close the socket. Be aware that this method is not per­fect and may fail if the picked port be­comes used be­tween the close method and the start of our HTTP server. How­ever, it would work fine in the very high ma­jor­ity of the case.

With this in place, our test is now using a ran­dom port. Ex­e­cute them with:

mvn clean test

External configuration - Let’s run on another port

Ok, well ran­dom port is not what we want in pro­duc­tion. Could you imag­ine the face of your pro­duc­tion team if you tell them that your ap­pli­ca­tion is pick­ing a ran­dom port. It can ac­tu­ally be funny, but we should never mess with the pro­duc­tion team.

So for the ac­tual ex­e­cu­tion of your ap­pli­ca­tion, let’s pass the con­fig­u­ra­tion in an ex­ter­nal file. The con­fig­u­ra­tion is stored in a json file.

Cre­ate the src/main/conf/my-application-conf.json with the fol­low­ing con­tent:

{
  "http.port" : 8082
}

And now, to use this con­fig­u­ra­tion just launch your ap­pli­ca­tion with:

java -jar target/my-first-app-1.0-SNAPSHOT-fat.jar -conf src/main/conf/my-application-conf.json

Open a browser on http://lo­cal­host:8082, here it is !

How does that work ? Re­mem­ber, our fat jar is using the Starter class (pro­vided by Vert.x) to launch our ap­pli­ca­tion. This class is read­ing the -conf pa­ra­me­ter and cre­ate the cor­re­spond­ing de­ploy­ment op­tions when de­ploy­ing our ver­ti­cle.

Conclusion

After hav­ing de­vel­oped your first Vert.x ap­pli­ca­tion, we have seen how this ap­pli­ca­tion is con­fig­urable, and this with­out adding any com­plex­ity to our ap­pli­ca­tion. In the next post, we are going to see how we can use vertx-​web to de­velop a small ap­pli­ca­tion serv­ing sta­tic pages and a REST API. A bit more fancy, but still very sim­ple.

Happy Cod­ing and & Stay Tuned!

Next post

Some Rest with Vert.x

This post is part of the Introduction to Vert.x series. Let’s go a bit further this time and develop a CRUD-ish application

Read more
Previous post

My first Vert.x 3 Application

Let's say, you heard someone saying that Vert.x is awesome. Ok great, but you may want to try it by yourself. Well, the next natural question is “where do I start ?”

Read more
Related posts

Unit and Integration Tests

Let’s refresh our mind about what we developed so far in the introduction to vert.x series. We forgot an important task. We didn’t test the API.

Read more

Combine vert.x and mongo to build a giant

This blog post is part of the introduction to Vert.x series. We are now going to replace this JDBC client by the vertx-mongo-client, and thus connect to a Mongo database.

Read more

Some Rest with Vert.x

This post is part of the Introduction to Vert.x series. Let’s go a bit further this time and develop a CRUD-ish application

Read more