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:
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:
- the event bus address you're listening to
- the event bus address you're publishing to
- 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
.
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
:
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:
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.htmlStep 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:
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:
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