If you are using Maven or Gradle, add the following dependency to the dependencies section of your project descriptor to access the Vert.x Core API and enable the Groovy support:
-
Maven (in your
pom.xml
):
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-core</artifactId>
<version>4.0.0.Beta1</version>
</dependency>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-lang-groovy</artifactId>
<version>4.0.0.Beta1</version>
</dependency>
-
Gradle (in your
build.gradle
file):
compile "io.vertx:vertx-core:4.0.0.Beta1"
compile "io.vertx:vertx-lang-groovy:4.0.0.Beta1"
----=== Error handling
As you saw in previous sections the DnsClient allows you to pass in a Handler which will be notified with an
AsyncResult once the query was complete. In case of an error it will be notified with a DnsException which will
hole a `link:../../apidocs/io/vertx/core/dns/DnsResponseCode.html[DnsResponseCode]` that indicate why the resolution failed. This DnsResponseCode
can be used to inspect the cause in more detail.
Possible DnsResponseCodes are:
- `link:../../apidocs/io/vertx/core/dns/DnsResponseCode.html#NOERROR[NOERROR]` No record was found for a given query
- `link:../../apidocs/io/vertx/core/dns/DnsResponseCode.html#FORMERROR[FORMERROR]` Format error
- `link:../../apidocs/io/vertx/core/dns/DnsResponseCode.html#SERVFAIL[SERVFAIL]` Server failure
- `link:../../apidocs/io/vertx/core/dns/DnsResponseCode.html#NXDOMAIN[NXDOMAIN]` Name error
- `link:../../apidocs/io/vertx/core/dns/DnsResponseCode.html#NOTIMPL[NOTIMPL]` Not implemented by DNS Server
- `link:../../apidocs/io/vertx/core/dns/DnsResponseCode.html#REFUSED[REFUSED]` DNS Server refused the query
- `link:../../apidocs/io/vertx/core/dns/DnsResponseCode.html#YXDOMAIN[YXDOMAIN]` Domain name should not exist
- `link:../../apidocs/io/vertx/core/dns/DnsResponseCode.html#YXRRSET[YXRRSET]` Resource record should not exist
- `link:../../apidocs/io/vertx/core/dns/DnsResponseCode.html#NXRRSET[NXRRSET]` RRSET does not exist
- `link:../../apidocs/io/vertx/core/dns/DnsResponseCode.html#NOTZONE[NOTZONE]` Name not in zone
- `link:../../apidocs/io/vertx/core/dns/DnsResponseCode.html#BADVERS[BADVERS]` Bad extension mechanism for version
- `link:../../apidocs/io/vertx/core/dns/DnsResponseCode.html#BADSIG[BADSIG]` Bad signature
- `link:../../apidocs/io/vertx/core/dns/DnsResponseCode.html#BADKEY[BADKEY]` Bad key
- `link:../../apidocs/io/vertx/core/dns/DnsResponseCode.html#BADTIME[BADTIME]` Bad timestamp
All of those errors are "generated" by the DNS Server itself.
You can obtain the `DnsResponseCode` from the `DnsException` like:
[source,groovy]
def client = vertx.createDnsClient(53, "8.8.8.8"); client.lookup("missing.vertx.io", { ar → if (ar.succeeded()) { def record = ar.result(); println "record: " + record; } else { def cause = ar.cause(); if (cause instanceof DnsException) { def code = cause.code(); println "Code : " + code // … } else { println("Failed to resolve entry" + ar.cause()); } } }) ----==== Message Codecs
You can send any object you like across the event bus if you define and register a message codec
for it.
Message codecs have a name and you specify that name in the DeliveryOptions
when sending or publishing the message:
eventBus.registerCodec(myCodec)
def options = [
codecName:myCodec.name()
]
eventBus.send("orders", new MyPOJO(), options)
If you always want the same codec to be used for a particular type then you can register a default codec for it, then you don’t have to specify the codec on each send in the delivery options:
eventBus.registerDefaultCodec(MyPOJO.class, myCodec);
eventBus.send("orders", new MyPOJO());
You unregister a message codec with unregisterCodec
.
Message codecs don’t always have to encode and decode as the same type. For example you can write a codec that allows a MyPOJO class to be sent, but when that message is sent to a handler it arrives as a MyOtherPOJO class.==== Setting headers on messages
Messages sent over the event bus can also contain headers. This can be specified by setting options when sending or publishing:
def options = [
headers: [
"some-header" : "some-value"
]
]
vertx.eventBus().send("news.uk.sport", "Yay! Someone kicked a ball", options);
On the other side, a consumer can retrieve the headers as follows:
vertx.eventBus().consumer("news.uk.sport", { e ->
println e.headers()["some-header"];
});
----== JSON
To manipulate JSON object, Vert.x proposes its own implementation of `link:../../apidocs/io/vertx/core/json/JsonObject.html[JsonObject]` and
`link:../../apidocs/io/vertx/core/json/JsonArray.html[JsonArray]`. This is because, unlike some other languages, Java does not have first class
support for http://json.org/[JSON].
When developping a vert.x application with Groovy, you can rely on these two classes, or use the
(http://www.groovy-lang.org/json.html)[JSON support from Groovy]. This section explains how to use the Vert.x
classes.
NOTE: Most vert.x methods taking a JSON object as argument in their Java version, take a map instead.
=== JSON objects
The `link:../../apidocs/io/vertx/core/json/JsonObject.html[JsonObject]` class represents JSON objects.
A JSON object is basically just a map which has string keys and values can be of one of the JSON supported types
(string, number, boolean).
JSON objects also support `null` values.
==== Creating JSON objects
Empty JSON objects can be created with the default constructor.
You can create a JSON object from a string or g-string JSON representation as follows:
[source,groovy]
def object = new JsonObject("{\"foo\":\"bar\"}") def object2 = new JsonObject(""" { "foo": "bar" } """)
In Groovy it's also convenient to create a JSON object from a map: [source, groovy]
def map = [ "foo" : "bar" ] def json = new JsonObject(map)
Nested maps are transformed to nested JSON objects. It can be achieved using a Groovy cast as well: [source, groovy]
def map = [ "foo" : "bar" ] def json = map as JsonObject
==== Putting entries into a JSON object Use the `link:../../apidocs/io/vertx/core/json/JsonObject.html#put-java.lang.String-java.lang.Object-[put]` methods to put values into the JSON object. The method invocations can be chained because of the fluent API: [source,groovy]
def object = new JsonObject() object.put("foo", "bar").put("num", 123).put("mybool", true)
The Groovy subscript operator works too: [source,groovy]
def object = new JsonObject() object["foo"] = "bar" object["num"] = 123 object["mybool"] = true
==== Getting values from a JSON object You get values from a JSON object using the `getXXX` methods, for example: [source,java]
dev val1 = jsonObject.getString("some-key") def val2 = jsonObject.getInteger("some-other-key")
The Groovy subscript operator works too: [source,groovy]
dev val1 = jsonObject["some-key"] def val2 = jsonObject["some-other-key"]
==== Encoding the JSON object to a String You use `link:../../apidocs/io/vertx/core/json/JsonObject.html#encode--[encode]` to encode the object to a String form. There is also a `link:../../apidocs/io/vertx/core/json/JsonObject.html#encodePrettily--[encodePrettily]` that makes the output pretty (understand multi-line and indented). === JSON arrays The `link:../../apidocs/io/vertx/core/json/JsonArray.html[JsonArray]` class represents JSON arrays. A JSON array is a sequence of values (string, number, boolean). JSON arrays can also contain `null` values. ==== Creating JSON arrays Empty JSON arrays can be created with the default constructor. You can create a JSON array from a string JSON representation or a list as follows: [source,groovy]
def object = new JsonArray("[\"foo\", \"bar\"]") def object2 = new JsonObject(""" [ "foo", "bar" ] """)
In Groovy it's also convenient to create a JSON array from a list: [source, groovy]
def list = [ "foo", "bar" ] def json = new JsonArray(list)
Nested maps are transformed to nested JSON objects. It can be achieved using a Groovy cast as well: [source, groovy]
def list = [ "foo", "bar" ] def json = map as JsonArray
==== Adding entries into a JSON array You add entries to a JSON array using the `link:../../apidocs/io/vertx/core/json/JsonArray.html#add-java.lang.Object-[add]` methods. [source,groovy]
def array = new JsonArray() array.add("foo").add(123).add(false)
The left shift operator can be used as well: [source,groovy]
def array = new JsonArray() array << "foo" array << 123 array << false
==== Getting values from a JSON array You get values from a JSON array using the `getXXX` methods, for example: [source,groovy]
def val = array.getString(0) def intVal = array.getInteger(1) def boolVal = array.getBoolean(2)
The Groovy subscript operator works too: [source,groovy]
def val = array[0] def intVal = array[1] def boolVal = array[2]
==== Encoding the JSON array to a String You use `link:../../apidocs/io/vertx/core/json/JsonArray.html#encode--[encode]` to encode the array to a String form. There is also a `link:../../apidocs/io/vertx/core/json/JsonObject.html#encodePrettily--[encodePrettily]` that makes the output pretty (understand multi-line and indented).=== Passing configuration to a verticle Configuration in the form of Map can be passed to a verticle at deployment time: [source,groovy]
def config = [ name:"tim", directory:"/blah" ] def options = [ "config" : config ]; vertx.deployVerticle("com.mycompany.MyOrderProcessorVerticle", options);
This configuration is then available via the `link:../../apidocs/io/vertx/core/Context.html[Context]`, The configuration is returned as a Map object so you can retrieve data as follows: [source,groovy]
println vertx.getOrCreateContext().config()["name"]
NOTE: The configuration can also be a `link:../../apidocs/io/vertx/core/json/JsonObject.html[JsonObject]` object. === Accessing environment variables in a Verticle Environment variables and system properties are accessible using the Java API: [source,groovy]
println System.getProperty("foo") println System.getenv("HOME") ----=== Writing Verticles
There are two alternatives to create verticles in Groovy:
a plain Groovy script
a Groovy class implementing the Verticle
interface or extending the AbstractVerticle
class
For example, the next snippet is a valid Groovy verticle:
println "Hello from vertx"
On deployment, by default, Vert.x executes the script. Optionally, your script can provide the startVertx
and
stopVertx
methods. Theses methods are called respectively when the verticle starts and stops:
void vertxStart() {
println "starting"
}
void vertxStop() {
println "stopping"
}
Alternatively, you can extend the AbstractVerticle
class and implement the start
and
stop
methods:
import io.vertx.core.AbstractVerticle;
public class HelloWorldHttpVerticle extends AbstractVerticle {
public void start() {
println("Starting")
}
public void stop() {
println("Stopping")
}
}
When Vert.x deploys the verticle it will call the start
method, and when the method has completed the
verticle will be considered started.
You can also optionally override the stop
method. This will be called by Vert.x when the verticle is undeployed
and when the method has completed the verticle will be considered stopped.
Accessing the vertx instance from a verticle
Regardless the way you use to implement your verticle, you access the vert.x instance using the vertx
variable /
field.
vertx.deployVerticle("another_verticle.rb")
import io.vertx.lang.groovy.GroovyVerticle;
public class HelloWorldHttpVerticle extends GroovyVerticle {
public void start() {
vertx.deployVerticle("another_verticle.js")
}
}
Asynchronous Verticle start and stop
Sometimes you want to do something in your verticle start-up which takes some time and you don’t want the verticle to be considered deployed until that happens. For example you might want to deploy other verticles in the start method.
You can’t block waiting for the other verticles to deploy in your start method as that would break the Golden Rule.
So how can you do this?
The way to do it is to implement theasynchronous* start method. This version of the method takes a Future as a parameter.When the method returns the verticle willnot* be considered deployed.
Some time later, after you’ve done everything you need to do (e.g. start other verticles), you can call complete on the Future (or fail) to signal that you’re done. Similarly, there is an asynchronous version of the stop method too. You use this if you want to do some verticle cleanup that takes some time.
When your verticle is implemented as a script, asynchronous start and stop are implemented as follows:
import io.vertx.core.Future
void vertxStart(Future<Void> future) {
println "starting"
vertx.deployVerticle("v.rb", { res ->
if (res.succeeded()) {
future.complete()
} else {
future.fail()
}
})
}
void vertxStop(Future<Void> future) {
println "stopping"
future.complete()
}
If your verticle extends AbstractVerticle
, you override the
start
and
stop
methods:
import io.vertx.core.Future
import io.vertx.core.AbstractVerticle
public class HelloWorldHttpVerticle extends AbstractVerticle {
public void start(Future<Void> future) {
println "starting"
vertx.deployVerticle("v.rb",
{ res ->
if (res.succeeded()) {
future.complete()
} else {
future.fail()
}
})
}
public void stop(Future<Void> future) {
println("stopping")
future.complete()
}
}
Note
|
You don’t need to manually undeploy child verticles started by a verticle, in the verticle’s stop method. Vert.x will automatically undeploy any child verticles when the parent is undeployed. |
API changes from previous versions
Vert.x for Groovy has been revamped in Vert.x 3.4.x and provided an automatic migration path for Verticles written against the previous API.
Vert.x 3.5.0 assumes that applications have been migrated to the new API.