Skip to main content

Adding configuration options

While it's already great to have a Verticle that does its job, the effort of making it configurable, and thus, reusable, is minimal.

Developing your Verticle in a re-usable way means that it'll take far less time (and maybe not even re-compilation/a new release) to adjust to changed mission parameters.

Prerequisites

To complete this tutorial, you should be familiar with writing basic Verticles and using the JsonMessage interface from the Telestion APIs.

What you'll build

Base Code »/application/tutorials/using-jsonmessage/

Based on the code from the JsonMessage tutorial, you'll make your MessageTransformer Verticle configurable.

After the tutorial, your Verticle looks like this:

MessageTransformer.java
package de.wuespace.telestion.project.example;

import com.fasterxml.jackson.annotation.JsonProperty;
import de.wuespace.telestion.api.message.JsonMessage;
import de.wuespace.telestion.api.verticle.TelestionConfiguration;
import de.wuespace.telestion.api.verticle.TelestionVerticle;
import io.vertx.core.DeploymentOptions;
import io.vertx.core.Vertx;
import io.vertx.core.json.JsonObject;

public class MessageTransformer extends TelestionVerticle<MessageTransformer.Configuration> {

public static void main(String[] args) throws InterruptedException {
var vertx = Vertx.vertx();

// [...]

var config = new JsonObject().put("multiplier", 6);

vertx.deployVerticle(
new MessageTransformer(),
new DeploymentOptions().setConfig(config)
).onSuccess(res -> {
// [...]
});
}

public record Configuration(
@JsonProperty String inAddress,
@JsonProperty String outAddress,
@JsonProperty int multiplier
) implements TelestionConfiguration {
public Configuration() {
this("input", "output", 2); // default values
}
}

@Override
public void onStart() {
var eb = getVertx().eventBus();

eb.consumer(getConfig().inAddress(), event -> {
JsonMessage.on(IntegerMessage.class, event, message -> {
int received = message.value();
var output = new IntegerMessage(received * getConfig().multiplier());
eb.publish(getConfig().outAddress(), output.json());
});
});
}
}

Step 1: Defining the record Configuration for the Verticle

The Telestion APIs re-use the JsonMessage interface to deal with type safety in configuration options. The reason for this is basically the same as with the event bus: Vert.x natively uses JsonObject instances. While in specific, dynamic use-cases, this is useful, you typically want your configuration to be type safe, which is why you can use convenience functions that are like the JsonMessage APIs.

Since this Verticle is rather basic, there are only three parameters that you could expose to be configurable:

  1. the event bus address you're listening to
  2. the event bus address you're publishing to
  3. the multiplier

Add a record Configuration implements TelestionConfiguration containing these fields as a member of your MessageTransformer Verticle:

tip

It has become a convention to make the configuration records members of their Verticle and name them Configuration.

MessageTransformer.java
package de.wuespace.telestion.project.example;

// [...]

public class MessageTransformer extends TelestionVerticle<MessageTransformer.Configuration> {

public static void main(String[] args) throws InterruptedException {
// [...]
}

public record Configuration(
@JsonProperty String inAddress,
@JsonProperty String outAddress,
@JsonProperty int multiplier
) implements TelestionConfiguration {
}

@Override
public void onStart() {
// [...]
}
}

Now that you have defined a configuration record, you can take a look at how you can apply it in your Verticle.

Step 2: Adjusting the Verticle structure

To actually use your configuration, you need to make some slight adjustments to the existing code.

Now, the generic type enters the game. You need to give the TelestionVerticle class a hint about your new configuration. Replace the NoConfiguration type with your configuration type MessageTransformer.Configuration:

MessageTransformer.java
package de.wuespace.telestion.project.example;

// [...]

public class MessageTransformer extends TelestionVerticle<MessageTransformer.Configuration> {
// [...]
}

With that, your Verticle is fully set up to handle configuration objects.

Step 3: Retrieving configuration values

When the Verticle starts, it automatically retrieves and merges the configuration provided by the Vertx context with the default configuration.

Then it maps the merged configuration back to your Configuration type.

To access the configuration, use one of the TelestionVerticle's convenience methods:

MessageTransformer.java
package de.wuespace.telestion.project.example;

// [...]
import de.wuespace.telestion.api.config.Config;
// [...]

public class MessageTransformer extends TelestionVerticle<MessageTransformer.Configuration> {
// [...]

@Override
public void onStart() {
var eb = getVertx().eventBus();

eb.consumer(getConfig().inAddress(), event -> {
JsonMessage.on(IntegerMessage.class, event, message -> {
int received = message.value();
var output = new IntegerMessage(received * getConfig().multiplier());
eb.publish(getConfig().outAddress(), output.json());
});
});
}

// [...]
}

You can now just access configuration options by using the getConfig method provided by the TelestionVerticle base class.

To access the configuration in other types, take a look at the API reference of the TelestionVerticle:

TelestionVerticle API reference »https://javadoc.io/doc/de.wuespace.telestion/telestion-api/latest/de/wuespace/telestion/api/verticle/TelestionVerticle.html

Step 4: Adding default configuration parameters

Having every single configuration option for every single Verticle you deploy can be quite cumbersome.

It's good practice to define the default values for your Configuration record.

Add a default constructor with no arguments defining the default values to your Configuration class:

MessageTransformer.java
package de.wuespace.telestion.project.example;

// [...]

public class MessageTransformer extends TelestionVerticle<MessageTransformer.Configuration> {

// [...]

public record Configuration(
@JsonProperty String inAddress,
@JsonProperty String outAddress,
@JsonProperty int multiplier
) implements TelestionConfiguration {
public Configuration() {
this("input", "output", 2); // default values
}
}

// [...]
}

That's it. The TelestionVerticle class tries to load the default configuration once the Verticle starts.

Step 5: Adjusting the main() method

To test what you've just written, you also need to adjust your main() method.

Use new DeploymentOptions().setConfig(jsonObject) to pass a configuration object to the deployed Verticle:

MessageTransformer.java
package de.wuespace.telestion.project.example;

// [...]
import io.vertx.core.DeploymentOptions;
import io.vertx.core.json.JsonObject;

public class MessageTransformer extends TelestionVerticle<MessageTransformer.Configuration> {

public static void main(String[] args) throws InterruptedException {
var vertx = Vertx.vertx();

// [...]

var config = new JsonObject().put("multiplier", 6);

vertx.deployVerticle(
new MessageTransformer(),
new DeploymentOptions().setConfig(config)
).onSuccess(res -> {
// [...]
});
}

// [...]
}

That's it. When you now re-run the main method, you now get a value of 18, that is, 6 * 3.

tip

You're using new JsonObject().put() instead of new Configuration() since it wouldn't be possible to test your default values if you instantiated a "full" Configuration instance.

Next steps

And that's already it. While you may, of course, need to know how to use other Java functionalities, this is all the Telestion-specific knowledge you need to write Verticles and even whole extensions for the Telestion projects.

TelestionVerticle API reference »https://javadoc.io/doc/de.wuespace.telestion/telestion-api/latest/de/wuespace/telestion/api/verticle/TelestionVerticle.html