Professional Documents
Culture Documents
Toggle navigation
Download
Documentation
Wiki
Community
Blog
Vert.x 2
1/66
9/1/2015
Handling exceptions
Event bus write handler
Local and remote addresses
Sending files
Streaming sockets
Upgrading connections to SSL/TLS
Closing a TCP Server
Automatic clean-up in verticles
Scaling - sharing TCP servers
Creating a TCP client
Configuring a TCP client
Making connections
Configuring connection attempts
Configuring servers and clients to work with SSL/TLS
Writing HTTP servers and clients
Creating an HTTP Server
Configuring an HTTP server
Start the Server Listening
Getting notified of incoming requests
Handling requests
Sending back responses
HTTP Compression
Creating an HTTP client
Making requests
Handling http responses
Enabling compression on the client
Pooling and keep alive
Pipe-lining
Server sharing
Using HTTPS with Vert.x
WebSockets
Automatic clean-up in verticles
Using Shared Data with Vert.x
Local shared maps
Cluster-wide asynchronous maps
Cluster-wide locks
Cluster-wide counters
Using the file system with Vert.x
Asynchronous files
Datagram sockets (UDP)
Creating a DatagramSocket
Sending Datagram packets
Receiving Datagram packets
Multicast
DNS client
lookup
lookup4
lookup6
resolveA
resolveAAAA
resolveCNAME
resolveMX
resolveTXT
resolveNS
resolveSRV
resolvePTR
reverseLookup
Error handling
Streams
ReadStream
WriteStream
Pump
Record Parser
Thread safety
Metrics SPI
OSGi
The 'vertx' command line
Run verticles
Executing verticles packaged as a fat jar
Displaying version of Vert.x
Cluster Managers
Logging
http://vertx.io/docs/vertx-core/groovy/
2/66
9/1/2015
Table of Contents
In the beginning there was Vert.x
Specifying options when creating a Vertx object
Creating a clustered Vert.x object
Are you fluent?
Dont call us, well call you.
Dont block me!
Reactor and Multi-Reactor
The Golden Rule - Dont Block the Event Loop
Running blocking code
Verticles
Writing Verticles
Accessing the vertx instance from a verticle
Asynchronous Verticle start and stop
Verticle Types
Standard verticles
Worker verticles
Deploying verticles programmatically
Rules for mapping a verticle name to a verticle factory
How are Verticle Factories located?
Waiting for deployment to complete
Undeploying verticle deployments
Specifying number of verticle instances
Passing configuration to a verticle
Accessing environment variables in a Verticle
Verticle Isolation Groups
High Availability
Running Verticles from the command line
Causing Vert.x to exit
The Context object
Executing periodic and delayed actions
The Event Bus
The Theory
The Event Bus API
Automatic clean-up in verticles
JSON
JSON objects
JSON arrays
Buffers
Creating buffers
Writing to a Buffer
Reading from a Buffer
Buffer length
Copying buffers
Slicing buffers
Buffer re-use
Writing TCP servers and clients
Creating a TCP server
Configuring a TCP server
Start the Server Listening
Listening on a random port
Getting notified of incoming connections
Reading data from the socket
Writing data to a socket
Closed handler
Handling exceptions
Event bus write handler
Local and remote addresses
http://vertx.io/docs/vertx-core/groovy/
3/66
9/1/2015
Sending files
Streaming sockets
Upgrading connections to SSL/TLS
Closing a TCP Server
Automatic clean-up in verticles
Scaling - sharing TCP servers
Creating a TCP client
Configuring a TCP client
Making connections
Configuring connection attempts
Configuring servers and clients to work with SSL/TLS
Writing HTTP servers and clients
Creating an HTTP Server
Configuring an HTTP server
Start the Server Listening
Getting notified of incoming requests
Handling requests
Sending back responses
HTTP Compression
Creating an HTTP client
Making requests
Handling http responses
Enabling compression on the client
Pooling and keep alive
Pipe-lining
Server sharing
Using HTTPS with Vert.x
WebSockets
Automatic clean-up in verticles
Using Shared Data with Vert.x
Local shared maps
Cluster-wide asynchronous maps
Cluster-wide locks
Cluster-wide counters
Using the file system with Vert.x
Asynchronous files
Datagram sockets (UDP)
Creating a DatagramSocket
Sending Datagram packets
Receiving Datagram packets
Multicast
DNS client
lookup
lookup4
lookup6
resolveA
resolveAAAA
resolveCNAME
resolveMX
resolveTXT
resolveNS
resolveSRV
resolvePTR
reverseLookup
Error handling
Streams
ReadStream
WriteStream
Pump
Record Parser
Thread safety
Metrics SPI
OSGi
The 'vertx' command line
Run verticles
Executing verticles packaged as a fat jar
Displaying version of Vert.x
Cluster Managers
Logging
Configuring JUL logging
Using another logging framework
Logging from your application
http://vertx.io/docs/vertx-core/groovy/
4/66
9/1/2015
Most applications will only need a single Vert.x instance, but its possible to create multiple Vert.x instances if you require, for
example, isolation between the event bus or different groups of servers and clients.
http://vertx.io/docs/vertx-core/groovy/
5/66
9/1/2015
The VertxOptionsobject has many settings and allows you to configure things like clustering, high availability, pool sizes and various
other settings. The Javadoc describes all the settings in detail.
Some time later when Vert.x has an event to pass to your handler Vert.x will call it asynchronously.
This leads us to some important concepts in Vert.x:
http://vertx.io/docs/vertx-core/groovy/
6/66
9/1/2015
Even though a Vertx instance maintains multiple event loops, any particular handler will never be executed concurrently, and in
most cases (with the exception of worker verticles) will always be called using the exact same event loop.
7/66
9/1/2015
Vert.x will also provide stack traces to pinpoint exactly where the blocking is occurring.
If you want to turn of these warnings or change the settings, you can do that in the VertxOptionsobject before creating the Vertx
object.
By default, if executeBlocking is called several times from the same context (e.g. the same verticle instance) then the different
executeBlocking are executed serially (i.e. one after another).
If you dont care about ordering you can call executeBlockingspecifying falseas the argument to ordered. In this case any
executeBlocking may be executed in parallel on the worker pool.
An alternative way to run blocking code is to use a worker verticle
http://vertx.io/docs/vertx-core/groovy/
8/66
9/1/2015
A worker verticle is always executed with a thread from the worker pool.
Verticles
Vert.x comes with a simple, scalable, actor-like deployment and concurrency model out of the box that you can use to save you writing
your own.
This model is entirely optional and Vert.x does not force you to create your applications in this way if you dont want to..
The model does not claim to be a strict actor-model implementation, but it does share similarities especially with respect to
concurrency, scaling and deployment.
To use this model, you write your code as set of verticles.
Verticles are chunks of code that get deployed and run by Vert.x. Verticles can be written in any of the languages that Vert.x supports
and a single application can include verticles written in multiple languages.
You can think of a verticle as a bit like an actor in the Actor Model.
An application would typically be composed of many verticle instances running in the same Vert.x instance at the same time. The
different verticle instances communicate with each other by sending messages on the event bus.
Writing Verticles
There are three alternatives to create verticles in Groovy:
a plain Groovy script
a Groovy class extending the GroovyVerticleclass
a Groovy class implementing the Verticleinterface or extending the AbstractVerticleclass
We will not cover the third case in this manual, as it is a plain Java class and instead you should read the
Vert.x manual for Java.
On deployment, by default, Vert.x executes the script. Optionally, your script can provide the startVertxand stopVertxmethods.
Theses methods are called respectively when the verticle starts and stops:
void vertxStart() {
println "starting"
}
void vertxStop() {
println "stopping"
}
Alternatively, you can extend the GroovyVerticleclass and implement the startand stopmethods:
import io.vertx.lang.groovy.GroovyVerticle;
public class HelloWorldHttpVerticle extends GroovyVerticle {
public void start() {
println("Starting")
}
public void stop() {
println("Stopping")
}
}
As in Java, vert.x creates a new instance of the class automatically. When Vert.x deploys the verticle it will call the startmethod, and
when the method has completed the verticle will be considered started.
You can also optionally override the stopmethod. This will be called by Vert.x when the verticle is undeployed and when the method
has completed the verticle will be considered stopped.
9/66
9/1/2015
vertx.deployVerticle("another_verticle.rb")
Important
Note
Notice that depending your implementation choice, the Futureclass is different. Groovy verticle implemented as script are
using io.vertx.groovy.core.Future, while classes are using io.vertx.core.Future
You dont need to manually undeploy child verticles started by a verticle, in the verticles stop method. Vert.x will automatically
undeploy any child verticles when the parent is undeployed.
Verticle Types
http://vertx.io/docs/vertx-core/groovy/
10/66
9/1/2015
Standard verticles
Standard verticles are assigned an event loop thread when they are created and the start method is called with that event loop. When you
call any other methods that takes a handler on a core API from an event loop then Vert.x will guarantee that those handlers, when called,
will be executed on the same event loop.
This means we can guarantee that all the code in your verticle instance is always executed on the same event loop (as long as you dont
create your own threads and call it!).
This means you can write all the code in your application as single threaded and let Vert.x worrying about the threading and scaling. No
more worrying about synchronized and volatile any more, and you also avoid many other cases of race conditions and deadlock so
prevalent when doing hand-rolled 'traditional' multi-threaded application development.
Worker verticles
A worker verticle is just like a standard verticle but its executed not using an event loop, but using a thread from the Vert.x worker
thread pool.
Worker verticles are designed for calling blocking code, as they wont block any event loops.
If you dont want to use a worker verticle to run blocking code, you can also run inline blocking code directly while on an event loop.
If you want to deploy a verticle as a worker verticle you do that with worker.
def options = [
worker:true
]
vertx.deployVerticle("com.mycompany.MyOrderProcessorVerticle", options)
Worker verticle instances are never executed concurrently by Vert.x by more than one thread, but can executed by different threads at
different times.
Multi-threaded worker verticles
A multi-threaded worker verticle is just like a normal worker verticle but it can be executed concurrently by different threads.
Multi-threaded worker verticles are an advanced feature and most applications will have no need for them. Because of the
Warning concurrency in these verticles you have to be very careful to keep the verticle in a consistent state using standard Java
techniques for multi-threaded programming.
11/66
9/1/2015
If no prefix is present, Vert.x will look for a suffix and use that to lookup the factory, e.g.
foo.js // Will also use the JavaScript verticle factory
SomeScript.groovy // Will use the Groovy verticle factory
If no prefix or suffix is present, Vert.x will assume its a Java fully qualified class name (FQCN) and try and instantiate that.
The completion handler will be passed a result containing the deployment ID string, if deployment succeeded.
This deployment ID can be used later if you want to undeploy the deployment.
http://vertx.io/docs/vertx-core/groovy/
12/66
9/1/2015
This is useful for scaling easily across multiple cores. For example you might have a web-server verticle to deploy and multiple cores on
your machine, so you want to deploy multiple instances to take utilise all the cores.
This configuration is then available via the Context, The configuration is returned as a Map object so you can retrieve data as follows:
println vertx.getOrCreateContext().config()["name"]
High Availability
Verticles can be deployed with High Availability (HA) enabled. In that context, when a verticle is deployed on a vert.x instance that
dies abruptly, the verticle is redeployed on another vert.x instance from the cluster.
To run an verticle with the high availability enabled, just append the -haswitch:
vertx run my-verticle.js -ha
13/66
9/1/2015
However you can also run Vert.x verticles directly from the command line if you wish.
To do this you need to download and install a Vert.x distribution, and add the bindirectory of the installation to your PATHenvironment
variable. Also make sure you have a Java 8 JDK on your PATH.
Note The JDK is required to support on the fly compilation of Java code.
You can now run verticles by using the vertx runcommand. Here are some examples:
# Run a JavaScript verticle
vertx run my_verticle.js
# Run a Ruby verticle
vertx run a_n_other_verticle.rb
# Run a Groovy script verticle, clustered
vertx run FooVerticle.groovy -cluster
You can even run Java source verticles without compiling them first!
vertx run SomeJavaSourceFile.java
Vert.x will compile the Java source file on the fly before running it. This is really useful for quickly prototyping verticles and great for
demos. No need to set-up a Maven or Gradle build first to get going!
For full information on the various options available when executing vertxon the command line, type vertxat the command line.
If the current thread has a context associated with it, it reuses the context object. If not a new instance of context is created. You can test
the type of context you have retrieved:
import io.vertx.groovy.core.Context
def context = vertx.getOrCreateContext()
if (context.isEventLoopContext()) {
println("Context attached to Event Loop")
} else if (context.isWorkerContext()) {
println("Context attached to Worker Thread")
} else if (context.isMultiThreadedWorkerContext()) {
println("Context attached to Worker Thread - multi threaded worker")
} else if (!Context.isOnVertxThread()) {
println("Context not attached to a thread managed by vert.x")
}
When you have retrieved the context object, you can run code in this context asynchronously. In other words, you submit a task that will
be eventually run in the same context, but later:
vertx.getOrCreateContext().runOnContext({ v ->
println("This will be executed asynchronously in the same context")
})
When several handlers run in the same context, they may want to share data. The context object offers methods to store and retrieve data
shared in the context. For instance, it lets you pass data to some action run with runOnContext:
def context = vertx.getOrCreateContext()
context.put("data", "hello")
context.runOnContext({ v ->
def hello = context.get("data")
})
The context object also let you access verticle configuration using the configmethod. Check the Passing configuration to a verticle
http://vertx.io/docs/vertx-core/groovy/
14/66
9/1/2015
The return value is a unique timer id which can later be used to cancel the timer. The handler is also passed the timer id.
Periodic Timers
You can also set a timer to fire periodically by using setPeriodic.
There will be an initial delay equal to the period.
The return value of setPeriodicis a unique timer id (long). This can be later used if the timer needs to be cancelled.
The argument passed into the timer event handler is also the unique timer id:
Keep in mind that the timer will fire on a periodic basis. If your periodic treatment takes a long amount of time to proceed, your timer
events could run continuously or even worse : stack up.
In this case, you should consider using setTimerinstead. Once your treatment has finished, you can set the next timer.
def timerID = vertx.setPeriodic(1000, { id ->
println("And every second this is printed")
})
println("First this is printed")
Cancelling timers
To cancel a periodic timer, call cancelTimerspecifying the timer id. For example:
vertx.cancelTimer(timerID)
15/66
9/1/2015
The Theory
Addressing
Messages are sent on the event bus to an address.
Vert.x doesnt bother with any fancy addressing schemes. In Vert.x an address is simply a string. Any string is valid. However it is wise
to use some kind of scheme, e.g. using periods to demarcate a namespace.
Some examples of valid addresses are europe.news.feed1, acme.games.pacman, sausages, and X.
Handlers
Messages are received in handlers. You register a handler at an address.
Many different handlers can be registered at the same address.
A single handler can be registered at many different addresses.
Publish / subscribe messaging
The event bus supports publishing messages.
Messages are published to an address. Publishing means delivering the message to all handlers that are registered at that address.
This is the familiar publish/subscribe messaging pattern.
Point to point and Request-Response messaging
The event bus also supports point to point messaging.
Messages are sent to an address. Vert.x will then route it to just one of the handlers registered at that address.
If there is more than one handler registered at the address, one will be chosen using a non-strict round-robin algorithm.
With point to point messaging, an optional reply handler can be specified when sending the message.
When a message is received by a recipient, and has been handled, the recipient can optionally decide to reply to the message. If they do
so the reply handler will be called.
When the reply is received back at the sender, it too can be replied to. This can be repeated ad-infinitum, and allows a dialog to be setup between two different verticles.
This is a common messaging pattern called the request-response pattern.
Best-effort delivery
Vert.x does its best to deliver messages and wont consciously throw them away. This is called best-effort delivery.
However, in case of failure of all or parts of the event bus, there is a possibility messages will be lost.
If your application cares about lost messages, you should code your handlers to be idempotent, and your senders to retry after recovery.
Types of messages
Out of the box Vert.x allows any primitive/simple type, String, or buffersto be sent as messages.
However its a convention and common practice in Vert.x to send messages as JSON
JSON is very easy to create, read and parse in all the languages that Vert.x supports so it has become a kind of lingua franca for Vert.x.
However you are not forced to use JSON if you dont want to.
The event bus is very flexible and also supports sending arbitrary objects over the event bus. You do this by defining a codecfor the
objects you want to send.
16/66
9/1/2015
When a message arrives for your handler, your handler will be called, passing in the message.
The object returned from call to consumer() is an instance of MessageConsumer
This object can subsequently be used to unregister the handler, or use the handler as a stream.
Alternatively you can use consumerto to return a MessageConsumer with no handler set, and then set the handler on that. For example:
def eb = vertx.eventBus()
def consumer = eb.consumer("news.uk.sport")
consumer.handler({ message ->
println("I have received a message: ${message.body()}")
})
When registering a handler on a clustered event bus, it can take some time for the registration to reach all nodes of the cluster.
If you want to be notified when this has completed, you can register a completion handleron the MessageConsumer object.
consumer.completionHandler({ res ->
if (res.succeeded()) {
println("The handler registration has reached all nodes")
} else {
println("Registration failed!")
}
})
Un-registering Handlers
To unregister a handler, call unregister.
If you are on a clustered event bus, un-registering can take some time to propagate across the nodes, if you want to be notified when this
is complete use unregister.
consumer.unregister({ res ->
if (res.succeeded()) {
println("The handler un-registration has reached all nodes")
} else {
println("Un-registration failed!")
}
})
Publishing messages
Publishing a message is simple. Just use publishspecifying the address to publish it to.
eventBus.publish("news.uk.sport", "Yay! Someone kicked a ball")
That message will then be delivered to all handlers registered against the address news.uk.sport.
Sending messages
Sending a message will result in only one handler registered at the address receiving the message. This is the point to point messaging
pattern. The handler is chosen in a non-strict round-robin fashion.
You can send a message with send
eventBus.send("news.uk.sport", "Yay! Someone kicked a ball")
http://vertx.io/docs/vertx-core/groovy/
17/66
9/1/2015
The sender:
eventBus.send("news.uk.sport", "Yay! Someone kicked a ball across a patch of grass", { ar ->
if (ar.succeeded()) {
println("Received reply: ${ar.result().body()}")
}
})
The replies themselves can also be replied to so you can create a dialog between two different parties consisting of multiple rounds.
Sending with timeouts
When sending a message with a reply handler you can specify a timeout in the DeliveryOptions.
If a reply is not received within that time, the reply handler will be called with a failure.
The default timeout is 30 seconds.
Send Failures
Message sends can fail for other reasons, including:
There are no handlers available to send the message to
The recipient has explicitly failed the message using fail
In all cases the reply handler will be called with the specific failure.
http://vertx.io/docs/vertx-core/groovy/
18/66
9/1/2015
Message Codecs
Message codecs are available exclusively with the Java api.
Clustered Event Bus
The event bus doesnt just exist in a single Vert.x instance. By clustering different Vert.x instances together on your network they can
form a single, distributed, event bus.
Clustering programmatically
If youre creating your Vert.x instance programmatically you get a clustered event bus by configuring the Vert.x instance as clustered;
import io.vertx.groovy.core.Vertx
def options = [:]
Vertx.clusteredVertx(options, { res ->
if (res.succeeded()) {
def vertx = res.result()
def eventBus = vertx.eventBus()
println("We now have a clustered event bus: ${eventBus}")
} else {
println("Failed: ${res.cause()}")
}
})
You should also make sure you have a ClusterManagerimplementation on your classpath, for example the default
HazelcastClusterManager.
Clustering on the command line
You can run Vert.x clustered on the command line with
vertx run my-verticle.js -cluster
JSON
To manipulate JSON object, Vert.x proposes its own implementation of JsonObjectand JsonArray.
This is because, unlike some other languages, Java does not have first class support for JSON.
When developping a vert.x application with Groovy, you can rely on these two classes, or use the (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 JsonObjectclass 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 nullvalues.
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:
def object = new JsonObject("{\"foo\":\"bar\"}")
def object2 = new JsonObject("""
{
"foo": "bar"
}
""")
http://vertx.io/docs/vertx-core/groovy/
19/66
9/1/2015
JSON arrays
The JsonArrayclass represents JSON arrays.
A JSON array is a sequence of values (string, number, boolean).
JSON arrays can also contain nullvalues.
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 map as follows:
def object = new JsonObject("""{foo:["bar", "baz"}""")
def object2 = new JsonObject(["foo": ["bar", "baz"]])
Buffers
Most data is shuffled around inside Vert.x using buffers.
A buffer is a sequence of zero or more bytes that can read from or written to and which expands automatically as necessary to
accommodate any bytes written to it. You can perhaps think of a buffer as smart byte array.
http://vertx.io/docs/vertx-core/groovy/
20/66
9/1/2015
Creating buffers
Buffers can create by using one of the static Buffer.buffermethods.
Buffers can be initialised from strings or byte arrays, or empty buffers can be created.
Here are some examples of creating buffers:
Create a new empty buffer:
import io.vertx.groovy.core.buffer.Buffer
def buff = Buffer.buffer()
Create a buffer from a String. The String will be encoded in the buffer using UTF-8.
import io.vertx.groovy.core.buffer.Buffer
def buff = Buffer.buffer("some string")
Create a buffer from a String: The String will be encoded using the specified encoding, e.g:
import io.vertx.groovy.core.buffer.Buffer
def buff = Buffer.buffer("some string", "UTF-16")
Create a buffer with an initial size hint. If you know your buffer will have a certain amount of data written to it you can create the buffer
and specify this size. This makes the buffer initially allocate that much memory and is more efficient than the buffer automatically
resizing multiple times as data is written to it.
Note that buffers created this way are empty. It does not create a buffer filled with zeros up to the specified size.
import io.vertx.groovy.core.buffer.Buffer
def buff = Buffer.buffer(10000)
Writing to a Buffer
There are two ways to write to a buffer: appending, and random access. In either case buffers will always expand automatically to
encompass the bytes. Its not possible to get an IndexOutOfBoundsExceptionwith a buffer.
Appending to a Buffer
To append to a buffer, you use the appendXXXmethods. Append methods exist for appending various different types.
The return value of the appendXXXmethods is the buffer itself, so these can be chained:
import io.vertx.groovy.core.buffer.Buffer
def buff = Buffer.buffer()
buff.appendInt(123).appendString("hello\n")
socket.write(buff)
Buffer length
http://vertx.io/docs/vertx-core/groovy/
21/66
9/1/2015
Use lengthto obtain the length of the buffer. The length of a buffer is the index of the byte in the buffer with the largest index + 1.
Copying buffers
Use copyto make a copy of the buffer
Slicing buffers
A sliced buffer is a new buffer which backs onto the original buffer, i.e. it does not copy the underlying data. Use sliceto create a
sliced buffers
Buffer re-use
After writing a buffer to a socket or other similar place, they cannot be re-used.
Or to specify the host and port in the call to listen, ignoring what is configured in the options:
def server = vertx.createNetServer()
server.listen(1234, "localhost")
The default host is 0.0.0.0which means 'listen on all available addresses' and the default port is 0, which is a special value that
instructs the server to find a random unused local port and use that.
The actual bind is asynchronous so the server might not actually be listening until some time after the call to listen has returned.
If you want to be notified when the server is actually listening you can provide a handler to the listencall. For example:
def server = vertx.createNetServer()
server.listen(1234, "localhost", { res ->
if (res.succeeded()) {
println("Server is now listening!")
} else {
println("Failed to bind!")
}
})
http://vertx.io/docs/vertx-core/groovy/
22/66
9/1/2015
} else {
println("Failed to bind!")
}
})
When a connection is made the handler will be called with an instance of NetSocket.
This is a socket-like interface to the actual connection, and allows you to read and write data as well as do various other things like close
the socket.
Write operations are asynchronous and may not occur until some time after the call to write has returned.
Closed handler
If you want to be notified when a socket is closed, you can set a closeHandleron it:
socket.closeHandler({ v ->
println("The socket has been closed")
})
Handling exceptions
You can set an exceptionHandlerto receive any exceptions that happen on the socket.
23/66
9/1/2015
The remote address, (i.e. the address of the other end of the connection) of a NetSocketcan be retrieved using remoteAddress.
Sending files
Files can be written to the socket directly using sendFile. This can be a very efficient way to send files, as it can be handled by the OS
kernel directly where supported by the operating system.
socket.sendFile("myfile.dat")
Streaming sockets
Instances of NetSocketare also ReadStreamand WriteStreaminstances so they can be used to pump data to or from other read and
write streams.
See the chapter on streams and pumps for more information.
or, if you are using verticles you can simply deploy more instances of your server verticle by using the -instancesoption on the
command line:
vertx run com.mycompany.MyVerticle -instances 10
24/66
9/1/2015
def options = [
instances:10
]
vertx.deployVerticle("com.mycompany.MyVerticle", options)
Once you do this you will find the echo server works functionally identically to before, but all your cores on your server can be utilised
and more work can be handled.
At this point you might be asking yourself 'How can you have more than one server listening on the same host and port? Surely
you will get port conflicts as soon as you try and deploy more than one instance?'
Vert.x does a little magic here.*
When you deploy another server on the same host and port as an existing server it doesnt actually try and create a new server listening
on the same host/port.
Instead it internally maintains just a single server, and, as incoming connections arrive it distributes them in a round-robin fashion to any
of the connect handlers.
Consequently Vert.x TCP servers can scale over available cores while each instance remains single threaded.
Making connections
To make a connection to a server you use connect, specifying the port and host of the server and a handler that will be called with a
result containing the NetSocketwhen connection is successful or with a failure if connection failed.
def options = [
connectTimeout:10000
]
def client = vertx.createNetClient(options)
client.connect(4321, "localhost", { res ->
if (res.succeeded()) {
println("Connected!")
def socket = res.result()
} else {
println("Failed to connect: ${res.cause().getMessage()}")
}
})
Currently Vert.x will not attempt to reconnect if a connection fails, reconnect attempts and interval only apply to creating initial
connections.
25/66
9/1/2015
Alternatively you can read the key store yourself as a buffer and provide that directly:
def myKeyStoreAsABuffer = vertx.fileSystem().readFileBlocking("/path/to/your/server-keystore.jks")
def jksOptions = [
value:myKeyStoreAsABuffer,
password:"password-of-your-keystore"
]
def options = [
ssl:true,
keyStoreOptions:jksOptions
]
def server = vertx.createNetServer(options)
Key/certificate in PKCS#12 format (http://en.wikipedia.org/wiki/PKCS_12), usually with the .pfxor the .p12extension can also be
loaded in a similar fashion than JKS key stores:
def options = [
ssl:true,
pfxKeyCertOptions:[
path:"/path/to/your/server-keystore.pfx",
password:"password-of-your-keystore"
]
]
def server = vertx.createNetServer(options)
Another way of providing server private key and certificate separately using .pemfiles.
def options = [
ssl:true,
pemKeyCertOptions:[
keyPath:"/path/to/your/server-key.pem",
certPath:"/path/to/your/server-cert.pem"
]
]
def server = vertx.createNetServer(options)
http://vertx.io/docs/vertx-core/groovy/
26/66
9/1/2015
keyValue:myKeyAsABuffer,
certValue:myCertAsABuffer
]
def options = [
ssl:true,
pemKeyCertOptions:pemOptions
]
def server = vertx.createNetServer(options)
Keep in mind that pem configuration, the private key is not crypted.
Specifying trust for the server
SSL/TLS servers can use a certificate authority in order to verify the identity of the clients.
Certificate authorities can be configured for servers in several ways:
Java trust stores can be managed with the keytool utility which ships with the JDK.
The password for the trust store should also be provided:
def options = [
ssl:true,
clientAuthRequired:true,
trustStoreOptions:[
path:"/path/to/your/truststore.jks",
password:"password-of-your-truststore"
]
]
def server = vertx.createNetServer(options)
Alternatively you can read the trust store yourself as a buffer and provide that directly:
def myTrustStoreAsABuffer = vertx.fileSystem().readFileBlocking("/path/to/your/truststore.jks")
def options = [
ssl:true,
clientAuthRequired:true,
trustStoreOptions:[
value:myTrustStoreAsABuffer,
password:"password-of-your-truststore"
]
]
def server = vertx.createNetServer(options)
Certificate authority in PKCS#12 format (http://en.wikipedia.org/wiki/PKCS_12), usually with the .pfxor the .p12extension can also
be loaded in a similar fashion than JKS trust stores:
def options = [
ssl:true,
clientAuthRequired:true,
pfxTrustOptions:[
path:"/path/to/your/truststore.pfx",
password:"password-of-your-truststore"
]
]
def server = vertx.createNetServer(options)
http://vertx.io/docs/vertx-core/groovy/
27/66
9/1/2015
If trustAllis not set then a client trust store must be configured and should contain the certificates of the servers that the client trusts.
Likewise server configuration, the client trust can be configured in several ways:
The first method is by specifying the location of a Java trust-store which contains the certificate authority.
It is just a standard Java key store, the same as the key stores on the server side. The client trust store location is set by using the
function pathon the jks options. If a server presents a certificate during connection which is not in the client trust store, the
connection attempt will not succeed.
def options = [
ssl:true,
trustStoreOptions:[
path:"/path/to/your/truststore.jks",
password:"password-of-your-truststore"
]
]
def client = vertx.createNetClient(options)
Certificate authority in PKCS#12 format (http://en.wikipedia.org/wiki/PKCS_12), usually with the .pfxor the .p12extension can also
be loaded in a similar fashion than JKS trust stores:
def options = [
ssl:true,
pfxTrustOptions:[
path:"/path/to/your/truststore.pfx",
password:"password-of-your-truststore"
]
]
def client = vertx.createNetClient(options)
http://vertx.io/docs/vertx-core/groovy/
28/66
9/1/2015
pfxTrustOptions:[
value:myTrustStoreAsABuffer,
password:"password-of-your-truststore"
]
]
def client = vertx.createNetClient(options)
Key/certificate in PKCS#12 format (http://en.wikipedia.org/wiki/PKCS_12), usually with the .pfxor the .p12extension can also be
loaded in a similar fashion than JKS key stores:
def options = [
ssl:true,
pfxKeyCertOptions:[
path:"/path/to/your/client-keystore.pfx",
password:"password-of-your-keystore"
]
]
def client = vertx.createNetClient(options)
http://vertx.io/docs/vertx-core/groovy/
29/66
9/1/2015
ssl:true,
pfxKeyCertOptions:pfxOptions
]
def client = vertx.createNetClient(options)
Another way of providing server private key and certificate separately using .pemfiles.
def options = [
ssl:true,
pemKeyCertOptions:[
keyPath:"/path/to/your/client-key.pem",
certPath:"/path/to/your/client-cert.pem"
]
]
def client = vertx.createNetClient(options)
Keep in mind that pem configuration, the private key is not crypted.
Revoking certificate authorities
Trust can be configured to use a certificate revocation list (CRL) for revoked certificates that should no longer be trusted. The crlPath
configures the crl list to use:
def options = [
ssl:true,
trustStoreOptions:trustOptions,
crlPaths:[
"/path/to/your/crl.pem"
]
]
def client = vertx.createNetClient(options)
30/66
9/1/2015
Or to specify the host and port in the call to listen, ignoring what is configured in the options:
def server = vertx.createHttpServer()
server.listen(8080, "myhost.com")
The default host is 0.0.0.0which means 'listen on all available addresses' and the default port is 80.
The actual bind is asynchronous so the server might not actually be listening until some time after the call to listen has returned.
If you want to be notified when the server is actually listening you can provide a handler to the listencall. For example:
def server = vertx.createHttpServer()
server.listen(8080, "myhost.com", { res ->
if (res.succeeded()) {
println("Server is now listening!")
} else {
println("Failed to bind!")
}
})
Handling requests
When a request arrives, the request handler is called passing in an instance of HttpServerRequest. This object represents the server
side HTTP request.
The handler is called when the headers of the request have been fully read.
If the request contains a body, that body will arrive at the server some time after the request handler has been called.
The server request object allows you to retrieve the uri, path, paramsand headers, amongst other things.
Each server request object is associated with one server response object. You use responseto get a reference to the
HttpServerResponseobject.
Heres a simple example of a server handling a request and replying with "hello world" to it.
vertx.createHttpServer().requestHandler({ request ->
request.response().end("Hello world")
}).listen(8080)
Request version
http://vertx.io/docs/vertx-core/groovy/
31/66
9/1/2015
The version of HTTP specified in the request can be retrieved with version
Request method
Use methodto retrieve the HTTP method of the request. (i.e. whether its GET, POST, PUT, DELETE, HEAD, OPTIONS, etc).
Request URI
Use urito retrieve the URI of the request.
Note that this is the actual URI as passed in the HTTP request, and its almost always a relative URI.
The URI is as defined in Section 5.1.2 of the HTTP specification - Request-URI
Request path
Use pathto return the path part of the URI
For example, if the request URI was:
a/b/c/page.html?param1=abc¶m2=xyz
Request query
Use queryto return the query part of the URI
For example, if the request URI was:
a/b/c/page.html?param1=abc¶m2=xyz
Request headers
Use headersto return the headers of the HTTP request.
This returns an instance of MultiMap- which is like a normal Map or Hash but allows multiple values for the same key - this is because
HTTP allows multiple header values with the same key.
It also has case-insensitive keys, that means you can do the following:
def headers = request.headers()
// Get the User-Agent:
println("User agent is ${headers.get("user-agent")}")
// You can also do this and get the same result:
println("User agent is ${headers.get("User-Agent")}")
Request parameters
Use paramsto return the parameters of the HTTP request.
Just like headersthis returns an instance of MultiMapas there can be more than one parameter with the same name.
Request parameters are sent on the request URI, after the path. For example if the URI was:
/page.html?param1=abc¶m2=xyz
Note that these request parameters are retrieved from the URL of the request. If you have form attributes that have been sent as part of
the submission of an HTML form submitted in the body of a multi-part/form-datarequest then they will not appear in the params
here.
http://vertx.io/docs/vertx-core/groovy/
32/66
9/1/2015
Remote address
The address of the sender of the request can be retrieved with remoteAddress.
Absolute URI
The URI passed in an HTTP request is usually relative. If you wish to retrieve the absolute URI corresponding to the request, you can
get it with absoluteURI
End handler
The endHandlerof the request is invoked when the entire request, including any body has been fully read.
Reading Data from the Request Body
Often an HTTP request contains a body that we want to read. As previously mentioned the request handler is called when just the
headers of the request have arrived so the request object does not have a body at that point.
This is because the body may be very large (e.g. a file upload) and we dont generally want to buffer the entire body in memory before
handing it to you, as that could cause the server to exhaust available memory.
To receive the body, you can use the handleron the request, this will get called every time a chunk of the request body arrives. Heres
an example:
request.handler({ buffer ->
println("I have received a chunk of the body of length ${buffer.length()}")
})
The object passed into the handler is a Buffer, and the handler can be called multiple times as data arrives from the network, depending
on the size of the body.
In some cases (e.g. if the body is small) you will want to aggregate the entire body in memory, so you could do the aggregation yourself
as follows:
import io.vertx.groovy.core.buffer.Buffer
// Create an empty buffer
def totalBuffer = Buffer.buffer()
request.handler({ buffer ->
println("I have received a chunk of the body of length ${buffer.length()}")
totalBuffer.appendBuffer(buffer)
})
request.endHandler({ v ->
println("Full body received, length = ${totalBuffer.length()}")
})
This is such a common case, that Vert.x provides a bodyHandlerto do this for you. The body handler is called once when all the body
has been received:
request.bodyHandler({ totalBuffer ->
println("Full body received, length = ${totalBuffer.length()}")
})
Pumping requests
The request object is a ReadStreamso you can pump the request body to any WriteStreaminstance.
See the chapter on streams and pumps for a detailed explanation.
Handling HTML forms
HTML forms can be submitted with either a content type of application/x-www-form-urlencodedor multipart/form-data.
For url encoded forms, the form attributes are encoded in the url, just like normal query parameters.
For multi-part forms they are encoded in the request body, and as such are not available until the entire body has been read from the
wire.
Multi-part forms can also contain file uploads.
If you want to retrieve the attributes of a multi-part form you should tell Vert.x that you expect to receive such a form before any of the
body is read by calling setExpectMultipartwith true, and then you should retrieve the actual attributes using formAttributesonce
http://vertx.io/docs/vertx-core/groovy/
33/66
9/1/2015
File uploads can be large we dont provide the entire upload in a single buffer as that might result in memory exhaustion, instead, the
upload data is received in chunks:
request.uploadHandler({ upload ->
upload.handler({ chunk ->
println("Received a chunk of the upload of length ${chunk.length()}")
})
})
The upload object is a ReadStreamso you can pump the request body to any WriteStreaminstance. See the chapter on streams and
pumps for a detailed explanation.
If you just want to upload the file to disk somewhere you can use streamToFileSystem:
request.uploadHandler({ upload ->
upload.streamToFileSystem("myuploads_directory/${upload.filename()}")
})
Warning
Make sure you check the filename in a production system to avoid malicious clients uploading files to arbitrary places on
your filesystem. See security notes for more information.
With a string. In this case the string will encoded using UTF-8 and the result written to the wire.
http://vertx.io/docs/vertx-core/groovy/
34/66
9/1/2015
def response = request.response()
response.write("hello world!")
With a string and an encoding. In this case the string will encoded using the specified encoding and the result written to the wire.
def response = request.response()
response.write("hello world!", "UTF-16")
Writing to a response is asynchronous and always returns immediately after the write has been queued.
If you are just writing a single string or buffer to the HTTP response you can write it and end the response in a single call to the end
The first call to write results in the response header being being written to the response. Consequently, if you are not using HTTP
chunking then you must set the Content-Lengthheader before writing to the response, since it will be too late otherwise. If you are
using HTTP chunking you do not have to worry.
Ending HTTP responses
Once you have finished with the HTTP response you should endit.
This can be done in several ways:
With no arguments, the response is simply ended.
def response = request.response()
response.write("hello world!")
response.end()
It can also be called with a string or buffer in the same way writeis called. In this case its just the same as calling write with a string or
buffer followed by calling end with no arguments. For example:
def response = request.response()
response.end("hello world!")
Headers must all be added before any parts of the response body are written.
Chunked HTTP responses and trailers
Vert.x supports HTTP Chunked Transfer Encoding.
This allows the HTTP response body to be written in chunks, and is normally used when a large response body is being streamed to a
client and the total size is not known in advance.
You put the HTTP response into chunked mode as follows:
def response = request.response()
response.setChunked(true)
Default is non-chunked. When in chunked mode, each call to one of the writemethods will result in a new HTTP chunk being written
out.
When in chunked mode you can also write HTTP response trailers to the response. These are actually written in the final chunk of the
http://vertx.io/docs/vertx-core/groovy/
35/66
9/1/2015
response.
To add trailers to the response, add them directly to the trailers.
def response = request.response()
response.setChunked(true)
def trailers = response.trailers()
trailers.set("X-wibble", "woobble").set("X-quux", "flooble")
Or use putTrailer.
def response = request.response()
response.setChunked(true)
response.putTrailer("X-wibble", "woobble").putTrailer("X-quux", "flooble")
Sending a file is asynchronous and may not complete until some time after the call has returned. If you want to be notified when the file
has been writen you can use sendFile
If you use sendFilewhile using HTTPS it will copy through user-space, since if the kernel is copying data directly from disk to
socket it doesnt give us an opportunity to apply any encryption.
If youre going to write web servers directly using Vert.x be careful that users cannot exploit the path to access files outside
Warning
the directory from which you want to serve them. It may be safer instead to use Vert.x Web.
Note
Pumping responses
The server response is a WriteStreaminstance so you can pump to it from any ReadStream, e.g. AsyncFile, NetSocket, WebSocketor
HttpServerRequest.
Heres an example which echoes the request body back in the response for any PUT methods. It uses a pump for the body, so it will
work even if the HTTP request body is much larger than can fit in memory at any one time:
import io.vertx.core.http.HttpMethod
import io.vertx.groovy.core.streams.Pump
vertx.createHttpServer().requestHandler({ request ->
def response = request.response()
if (request.method() == HttpMethod.PUT) {
response.setChunked(true)
Pump.pump(request, response).start()
request.endHandler({ v ->
response.end()
})
} else {
response.setStatusCode(400).end()
}
}).listen(8080)
HTTP Compression
Vert.x comes with support for HTTP Compression out of the box.
This means you are able to automatically compress the body of the responses before they are sent back to the client.
http://vertx.io/docs/vertx-core/groovy/
36/66
9/1/2015
If the client does not support HTTP compression the responses are sent back without compressing the body.
This allows to handle Client that support HTTP Compression and those that not support it at the same time.
To enable compression use can configure it with compressionSupported.
By default compression is not enabled.
When HTTP compression is enabled the server will check if the client incldes an Accept-Encodingheader which includes the
supported compressions. Commonly used are deflate and gzip. Both are supported by Vert.x.
If such a header is found the server will automatically compress the body of the response with one of the supported compressions and
send it back to the client.
Be aware that compression may be able to reduce network traffic but is more CPU-intensive.
If you want to configure options for the client, you create it as follows:
def options = [
keepAlive:false
]
def client = vertx.createHttpClient(options)
Making requests
The http client is very flexible and there are various ways you can make requests with it.
Often you want to make many requests to the same host/port with an http client. To avoid you repeating the host/port every time you
make a request you can configure the client with a default host/port:
// Set the default host
def options = [
defaultHost:"wibble.com"
]
// Can also set default port if you want...
def client = vertx.createHttpClient(options)
client.getNow("/some-uri", { response ->
println("Received response with status code ${response.statusCode()}")
})
Alternatively if you find yourself making lots of requests to different host/ports with the same client you can simply specify the
host/port when doing the request.
def client = vertx.createHttpClient()
// Specify both port and host name
client.getNow(8080, "myserver.mycompany.com", "/some-uri", { response ->
println("Received response with status code ${response.statusCode()}")
})
// This time use the default port 80 but specify the host name
client.getNow("foo.othercompany.com", "/other-uri", { response ->
println("Received response with status code ${response.statusCode()}")
})
Both methods of specifying host/port are supported for all the different ways of making requests with the client.
Simple requests with no request body
Often, youll want to make HTTP requests with no request body. This is usually the case with HTTP GET, OPTIONS and HEAD
requests.
The simplest way to do this with the Vert.x http client is using the methods prefixed with Now. For example getNow.
These methods create the http request and send it in a single method call and allow you to provide a handler that will be called with the
http response when it comes back.
def client = vertx.createHttpClient()
// Send a GET request
client.getNow("/some-uri", { response ->
http://vertx.io/docs/vertx-core/groovy/
37/66
9/1/2015
Vert.x Core Manual · Vert.x
println("Received response with status code ${response.statusCode()}")
})
// Send a GET request
client.headNow("/other-uri", { response ->
println("Received response with status code ${response.statusCode()}")
})
Methods exist to write strings in UTF-8 encoding and in any specific encoding and to write buffers:
import io.vertx.groovy.core.buffer.Buffer
// Write string encoded in UTF-8
request.write("some data")
// Write string encoded in specific encoding
request.write("some other data", "UTF-16")
// Write a buffer
def buffer = Buffer.buffer()
buffer.appendInt(123).appendLong(245L)
request.write(buffer)
If you are just writing a single string or buffer to the HTTP request you can write it and end the request in a single call to the end
function.
import io.vertx.groovy.core.buffer.Buffer
http://vertx.io/docs/vertx-core/groovy/
38/66
9/1/2015
Vert.x Core Manual · Vert.x
// Write string and end the request (send it) in a single call
request.end("some simple data")
// Write buffer and end the request (send it) in a single call
def buffer = Buffer.buffer().appendDouble(12.34d).appendLong(432L)
request.end(buffer)
When youre writing to a request, the first call to writewill result in the request headers being written out to the wire.
The actual write is asynchronous and might not occur until some time after the call has returned.
Non-chunked HTTP requests with a request body require a Content-Lengthheader to be provided.
Consequently, if you are not using chunked HTTP then you must set the Content-Lengthheader before writing to the request, as it will
be too late otherwise.
If you are calling one of the endmethods that take a string or buffer then Vert.x will automatically calculate and set the ContentLengthheader before writing the request body.
If you are using HTTP chunking a a Content-Lengthheader is not required, so you do not have to calculate the size up-front.
Writing request headers
You can write headers to a request using the headersmulti-map as follows:
// Write some headers using the headers() multimap
def headers = request.headers()
headers.set("content-type", "application/json").set("other-header", "foo")
The headers are an instance of MultiMapwhich provides operations for adding, setting and removing entries. Http headers allow more
than one value for a specific key.
You can also write headers using putHeader
// Write some headers using the putHeader method
request.putHeader("content-type", "application/json").putHeader("other-header", "foo")
If you wish to write headers to the request you must do so before any part of the request body is written.
Ending HTTP requests
Once you have finished with the HTTP request you must end it with one of the endoperations.
Ending a request causes any headers to be written, if they have not already been written and the request to be marked as complete.
Requests can be ended in several ways. With no arguments the request is simply ended:
request.end()
Or a string or buffer can be provided in the call to end. This is like calling writewith the string or buffer before calling endwith no
arguments
import io.vertx.groovy.core.buffer.Buffer
// End the request with a string
request.end("some-data")
// End it with a buffer
def buffer = Buffer.buffer().appendFloat(12.3f).appendInt(321)
request.end(buffer)
http://vertx.io/docs/vertx-core/groovy/
39/66
9/1/2015
for (def i = 0;i < 10;i++) {
request.write("this-is-chunk-${i}")
}
request.end()
Request timeouts
You can set a timeout for a specific http request using setTimeout.
If the request does not return any data within the timeout period an exception will be passed to the exception handler (if provided) and
the request will be closed.
Handling exceptions
You can handle exceptions corresponding to a request by setting an exception handler on the HttpClientRequestinstance:
def request = client.post("some-uri", { response ->
println("Received response with status code ${response.statusCode()}")
})
request.exceptionHandler({ e ->
println("Received exception: ${e.getMessage()}")
e.printStackTrace()
})
This does not handle non 2xx response that need to be handled in the HttpClientResponsecode:
def request = client.post("some-uri", { response ->
if (response.statusCode() == 200) {
println("Everything fine")
return
}
if (response.statusCode() == 500) {
println("Unexpected behavior on the server side")
return
}
})
request.end()
http://vertx.io/docs/vertx-core/groovy/
40/66
9/1/2015
Vert.x Core Manual · Vert.x
// the status message e.g. "OK" or "Not Found".
println("Status message is ${response.statusMessage()}")
})
Chunked HTTP responses can also contain trailers - these are sent in the last chunk of the response body.
You use trailersto get the trailers. Trailers are also a MultiMap.
Reading the request body
The response handler is called when the headers of the response have been read from the wire.
If the response has a body this might arrive in several pieces some time after the headers have been read. We dont wait for all the body
to arrive before calling the response handler as the response could be very large and we might be waiting a long time, or run out of
memory for large responses.
As parts of the response body arrive, the handleris called with a Bufferrepresenting the piece of the body:
client.getNow("some-uri", { response ->
response.handler({ buffer ->
println("Received a part of the response body: ${buffer}")
})
})
If you know the response body is not very large and want to aggregate it all in memory before handling it, you can either aggregate it
yourself:
import io.vertx.groovy.core.buffer.Buffer
client.getNow("some-uri", { response ->
// Create an empty buffer
def totalBuffer = Buffer.buffer()
response.handler({ buffer ->
println("Received a part of the response body: ${buffer.length()}")
totalBuffer.appendBuffer(buffer)
})
response.endHandler({ v ->
// Now all the body has been read
println("Total response body length is ${totalBuffer.length()}")
})
})
Or you can use the convenience bodyHandlerwhich is called with the entire body when the response has been fully read:
client.getNow("some-uri", { response ->
response.bodyHandler({ totalBuffer ->
// Now all the body has been read
println("Total response body length is ${totalBuffer.length()}")
})
})
http://vertx.io/docs/vertx-core/groovy/
41/66
9/1/2015
You can retrieve the list of cookies from a response using cookies.
Alternatively you can just parse the Set-Cookieheaders yourself in the response.
100-Continue handling
According to the HTTP 1.1 specification a client can set a header Expect: 100-Continueand send the request header before sending
the rest of the request body.
The server can then respond with an interim response status Status: 100 (Continue)to signify to the client that it is ok to send the
rest of the body.
The idea here is it allows the server to authorise and accept/reject the request before large amounts of data are sent. Sending large
amounts of data if the request might not be accepted is a waste of bandwidth and ties up the server in reading data that it will just
discard.
Vert.x allows you to set a continueHandleron the client request object
This will be called if the server sends back a Status: 100 (Continue)response to signify that it is ok to send the rest of the request.
This is used in conjunction with `sendHead`to send the head of the request.
Heres an example:
def request = client.put("some-uri", { response ->
println("Received response with status code ${response.statusCode()}")
})
request.putHeader("Expect", "100-Continue")
request.continueHandler({ v ->
// OK to send rest of body
request.write("Some data")
request.write("Some more data")
request.end()
})
The server will choose then from one of these. You can detect if a server ompressed the body by checking for the Content-Encoding
header in the response sent back from it.
If the body of the response was compressed via gzip it will include for example the following header:
Content-Encoding: gzip
To enable compression set tryUseCompressionon the options used when creating the client.
By default compression is disabled.
http://vertx.io/docs/vertx-core/groovy/
42/66
9/1/2015
The maximum number of connections to pool for each server is configured using maxPoolSize
When making a request with pooling enabled, Vert.x will create a new connection if there are less than the maximum number of
connections already created for that server, otherwise it will add the request to a queue.
When a response returns, if there are pending requests for the server, then the connection will be reused, otherwise it will be closed.
This gives the benefits of keep alive when the client is loaded but means we dont keep connections hanging around unnecessarily when
there would be no benefits anyway.
Pipe-lining
The client also supports pipe-lining of requests on a connection.
Pipe-lining means another request is sent on the same connection before the response from the preceding one has returned. Pipe-lining is
not appropriate for all requests.
To enable pipe-lining, it must be enabled using pipelining. By default pipe-lining is disabled.
When pipe-lining is enabled requests will be written to connections without waiting for previous responses to return.
When pipe-line responses return at the client, the connection will be automatically closed when all in-flight responses have returned and
there are no outstanding pending requests to write.
Server sharing
When several HTTP servers listen on the same port, vert.x orchestrates the request handling using a round-robin strategy.
Lets take a verticle creating a HTTP server such as:
io.vertx.examples.http.sharing.HttpServerVerticle
vertx.createHttpServer().requestHandler({ request ->
request.response().end("Hello from server ${this}")
}).listen(8080)
This service is listening on the port 8080. So, when this verticle is instantiated multiple times as with: vertx run
io.vertx.examples.http.sharing.HttpServerVerticle -instances 2, whats happening ? If both verticles would bind to the same
port, you would receive a socket exception. Fortunately, vert.x is handling this case for you. When you deploy another server on the
same host and port as an existing server it doesnt actually try and create a new server listening on the same host/port. It binds only once
to the socket. When receiving a request it calls the server handlers following a round robin strategy.
Lets now imagine a client such as:
vertx.setPeriodic(100, { l ->
vertx.createHttpClient().getNow(8080, "localhost", "/", { resp ->
resp.bodyHandler({ body ->
println(body.toString("ISO-8859-1"))
})
})
})
Consequently the servers can scale over available cores while each Vert.x verticle instance remains strictly single threaded, and you
dont have to do any special tricks like writing load-balancers in order to scale your server on your multi-core machine.
WebSockets
WebSockets are a web technology that allows a full duplex socket-like connection between HTTP servers and HTTP clients (typically
browsers).
Vert.x supports WebSockets on both the client and server-side.
http://vertx.io/docs/vertx-core/groovy/
43/66
9/1/2015
Upgrading to WebSocket
The second way of handling WebSockets is to handle the HTTP Upgrade request that was sent from the client, and call upgradeon the
server request.
server.requestHandler({ request ->
if (request.path() == "/myapi") {
def websocket = request.upgrade()
// Do something
} else {
// Reject
request.response().setStatusCode(400).end()
}
})
The ServerWebSocketinstance enables you to retrieve the headers, pathpath}, queryand uriURI} of the HTTP request of the
WebSocket handshake.
WebSockets on the client
The Vert.x HttpClientsupports WebSockets.
You can connect a WebSocket to a server using one of the websocketoperations and providing a handler.
The handler will be called with an instance of WebSocketwhen the connection has been made:
client.websocket("/some-uri", { websocket ->
println("Connected!")
})
If the WebSocket message is larger than the maximum websocket frame size as configured with maxWebsocketFrameSizethen Vert.x
will split it into multiple WebSocket frames before sending it on the wire.
Writing frames to WebSockets
A WebSocket message can be composed of multiple frames. In this case the first frame is either a binary or text frame followed by zero
or more continuation frames.
http://vertx.io/docs/vertx-core/groovy/
44/66
9/1/2015
In many cases you just want to send a websocket message that consists of a single final frame, so we provide a couple of shortcut
methods to do that with writeFinalBinaryFrameand writeFinalTextFrame.
Heres an example:
import io.vertx.groovy.core.buffer.Buffer
// Send a websocket messages consisting of a single final text frame:
websocket.writeFinalTextFrame("Geronimo!")
// Send a websocket messages consisting of a single final binary frame:
def buff = Buffer.buffer().appendInt(12).appendString("foo")
websocket.writeFinalBinaryFrame(buff)
Closing WebSockets
Use closeto close the WebSocket connection when you have finished with it.
Streaming WebSockets
The WebSocketinstance is also a ReadStreamand a WriteStreamso it can be used with pumps.
When using a WebSocket as a write stream or a read stream it can only be used with WebSockets connections that are used with binary
frames that are no split over multiple frames.
you to share data safely between different event loops (e.g. different verticles) in the same Vert.x instance.
http://vertx.io/docs/vertx-core/groovy/
45/66
9/1/2015
Local shared maps only allow certain data types to be used as keys and values. Those types must either be immutable, or certain other
types that can be copied like Buffer. In the latter case the key/value will be copied before putting it in the map.
This way we can ensure there is no shared access to mutable state between different threads in your Vert.x application so you dont
have to worry about protecting that state by synchronising access to it.
Heres an example of using a shared local map:
import io.vertx.groovy.core.buffer.Buffer
def sd = vertx.sharedData()
def map1 = sd.getLocalMap("mymap1")
map1.put("foo", "bar")
def map2 = sd.getLocalMap("mymap2")
map2.put("eek", Buffer.buffer().appendInt(123))
// Then... in another part of your application:
map1 = sd.getLocalMap("mymap1")
def val = map1.get("foo")
map2 = sd.getLocalMap("mymap2")
def buff = map2.get("eek")
http://vertx.io/docs/vertx-core/groovy/
46/66
9/1/2015
Other map operations
You can also remove entries from an asynchronous map, clear them and get the size.
See the API docsfor more information.
Cluster-wide locks
Cluster wide locksallow
you to obtain exclusive locks across the cluster - this is useful when you want to do something or access a
resource on only one node of a cluster at any one time.
Cluster wide locks have an asynchronous API unlike most lock APIs which block the calling thread until the lock is obtained.
To obtain a lock use getLock.
This wont block, but when the lock is available, the handler will be called with an instance of Lock, signifying that you now own the
lock.
While you own the lock no other caller, anywhere on the cluster will be able to obtain the lock.
When youve finished with the lock, you call releaseto release it, so another caller can obtain it.
sd.getLock("mylock", { res ->
if (res.succeeded()) {
// Got the lock!
def lock = res.result()
// 5 seconds later we release the lock so someone else can get it
vertx.setTimer(5000, { tid ->
lock.release()
})
} else {
// Something went wrong
}
})
You can also get a lock with a timeout. If it fails to obtain the lock within the timeout the handler will be called with a failure:
sd.getLockWithTimeout("mylock", 10000, { res ->
if (res.succeeded()) {
// Got the lock!
def lock = res.result()
} else {
// Failed to get lock
}
})
Cluster-wide counters
Its often useful to maintain an atomic counter across the different nodes of your application.
You can do this with Counter.
You obtain an instance with getCounter:
sd.getCounter("mycounter", { res ->
if (res.succeeded()) {
def counter = res.result()
} else {
// Something went wrong!
}
})
Once you have an instance you can retrieve the current count, atomically increment it, decrement and add a value to it using the various
methods.
See the API docsfor more information.
47/66
9/1/2015
A blocking and a non blocking version of each operation is provided. The non blocking versions take a handler which is called when the
operation completes or an error occurs.
Heres an example of an asynchronous copy of a file:
def fs = vertx.fileSystem()
// Copy file from foo.txt to bar.txt
fs.copy("foo.txt", "bar.txt", { res ->
if (res.succeeded()) {
// Copied ok!
} else {
// Something went wrong
}
})
The blocking versions are named xxxBlockingand return the results or throw exceptions directly. In many cases, depending on the
operating system and file system, some of the potentially blocking operations can return quickly, which is why we provide them, but its
highly recommended that you test how long they take to return in your particular application before using them from an event loop, so
as not to break the Golden Rule.
Heres the copy using the blocking API:
def fs = vertx.fileSystem()
// Copy file from foo.txt to bar.txt synchronously
fs.copyBlocking("foo.txt", "bar.txt")
Many operations exist to copy, move, truncate, chmod and many other file operations. We wont list them all here, please consult the
API docsfor the full list.
Lets see a couple of examples using asynchronous methods:
import io.vertx.groovy.core.Vertx
import io.vertx.groovy.core.buffer.Buffer
def vertx = Vertx.vertx()
// Read a file
vertx.fileSystem().readFile("target/classes/readme.txt", { result ->
if (result.succeeded()) {
println(result.result())
} else {
System.err.println("Oh oh ...${result.cause()}")
}
})
// Copy a file
vertx.fileSystem().copy("target/classes/readme.txt", "target/classes/readme2.txt", { result ->
if (result.succeeded()) {
println("File copied")
} else {
System.err.println("Oh oh ...${result.cause()}")
}
})
// Write a file
vertx.fileSystem().writeFile("target/classes/hello.txt", Buffer.buffer("Hello"), { result ->
if (result.succeeded()) {
println("File written")
} else {
System.err.println("Oh oh ...${result.cause()}")
}
})
// Check existence and delete
vertx.fileSystem().exists("target/classes/junk.txt", { result ->
if (result.succeeded() && result.result()) {
vertx.fileSystem().delete("target/classes/junk.txt", { r ->
println("File deleted")
})
} else {
System.err.println("Oh oh ... - cannot delete the file: ${result.cause()}")
}
})
Asynchronous files
Vert.x provides an asynchronous file abstraction that allows you to manipulate a file on the file system.
You open an AsyncFileas follows:
def options = [:]
http://vertx.io/docs/vertx-core/groovy/
48/66
9/1/2015
Vert.x Core Manual · Vert.x
fileSystem.open("myfile.txt", options, { res ->
if (res.succeeded()) {
def file = res.result()
} else {
// Something went wrong!
}
})
AsyncFileimplements ReadStreamand WriteStreamso
you can pump files to and from other stream objects such as net sockets, http
buffer to write.
position: an
integer position in the file where to write the buffer. If the position is greater or equal to the size of the file, the file
will be enlarged to accommodate the offset.
handler: the
result handler
integer offset into the buffer where the read data will be placed.
position: the
length: the
handler: the
result handler
http://vertx.io/docs/vertx-core/groovy/
49/66
9/1/2015
}
} else {
System.err.println("Cannot open file ${result.cause()}")
}
})
Opening Options
When opening an AsyncFile, you pass an OpenOptionsinstance. These options describe the behavior of the file access. For instance,
you can configure the file permissions with the read, writeand permsmethods.
You can also configure the behavior if the open file already exists with createNewand truncateExisting.
You can also mark the file to be deleted on close or when the JVM is shutdown with deleteOnClose.
Flushing data to underlying storage.
In the OpenOptions, you can enable/disable the automatic synchronisation of the content on every write using DSync. In that case, you
can manually flush any writes from the OS cache by calling the flushmethod.
This method can also be called with an handler which will be called when the flush is complete.
Using AsyncFile as ReadStream and WriteStream
AsyncFileimplements ReadStreamand WriteStream. You
can then use them with a pump to pump data to and from other read and
write streams. For example, this would copy the content to another AsyncFile:
import io.vertx.groovy.core.Vertx
import io.vertx.groovy.core.streams.Pump
def vertx = Vertx.vertx()
def output = vertx.fileSystem().openBlocking("target/classes/plagiary.txt", [:])
vertx.fileSystem().open("target/classes/les_miserables.txt", [:], { result ->
if (result.succeeded()) {
def file = result.result()
Pump.pump(file, output).start()
file.endHandler({ r ->
println("Copy done")
})
} else {
System.err.println("Cannot open file ${result.cause()}")
}
})
You can also use the pump to write file content into HTTP responses, or more generally in any WriteStream.
Closing an AsyncFile
To close an AsyncFilecall the closemethod. Closing is asynchronous and if you want to be notified when the close has been
completed you can specify a handler function as an argument.
50/66
9/1/2015
Because of the nature of UDP it is best fit for Applications where you are allowed to drop packets (like for example a monitoring
application).
The benefits are that it has a lot less overhead compared to TCP, which can be handled by the NetServer and NetClient (see above).
Creating a DatagramSocket
To use UDP you first need t create a DatagramSocket. It does not matter here if you only want to send data or send and receive.
def socket = vertx.createDatagramSocket([:])
The returned DatagramSocketwill not be bound to a specific port. This is not a problem if you only want to send data (like a client), but
more on this in the next section.
So to listen on a specific address and port you would do something like shown here:
def socket = vertx.createDatagramSocket([:])
socket.listen(1234, "0.0.0.0", { asyncResult ->
if (asyncResult.succeeded()) {
socket.handler({ packet ->
// Do something with the packet
})
} else {
println("Listen failed${asyncResult.cause()}")
}
})
Be aware that even if the {code AsyncResult} is successed it only means it might be written on the network stack, but gives no
guarantee that it ever reached or will reach the remote peer at all.
If you need such a guarantee then you want to use TCP with some handshaking logic build on top.
Multicast
Sending Multicast packets
Multicast allows multiple sockets to receive the same packets. This works by have same join a multicast group to which you can send
packets.
http://vertx.io/docs/vertx-core/groovy/
51/66
9/1/2015
We will look at how you can joint a Multicast Group and so receive packets in the next section.
For now let us focus on how to send those. Sending multicast packets is not different to send normal Datagram Packets.
The only difference is that you would pass in a multicast group address to the send method.
This is show here:
import io.vertx.groovy.core.buffer.Buffer
def socket = vertx.createDatagramSocket([:])
def buffer = Buffer.buffer("content")
// Send a Buffer to a multicast address
socket.send(buffer, 1234, "230.0.0.1", { asyncResult ->
println("Send succeeded? ${asyncResult.succeeded()}")
})
All sockets that have joined the multicast group 230.0.0.1 will receive the packet.
Receiving Multicast packets
If you want to receive packets for specific Multicast group you need to bind the DatagramSocketby calling listen()on it and join
the Multicast group.
This way you will be able to receive DatagramPackets that were sent to the address and port on which the DatagramSocketlistens and
also to those sent to the Multicast group.
Beside this you also want to set a Handler which will be called for each received DatagramPacket.
The DatagramPackethas the following methods:
sender(): The
data(): The
So to listen on a specific address and port and also receive packets for the Multicast group 230.0.0.1 you would do something like
shown here:
def socket = vertx.createDatagramSocket([:])
socket.listen(1234, "0.0.0.0", { asyncResult ->
if (asyncResult.succeeded()) {
socket.handler({ packet ->
// Do something with the packet
})
// join the multicast group
socket.listenMulticastGroup("230.0.0.1", { asyncResult2 ->
println("Listen succeeded? ${asyncResult2.succeeded()}")
})
} else {
println("Listen failed${asyncResult.cause()}")
}
})
There are sometimes situations where you want to receive packets for a Multicast group for a limited time.
In this situations you can first start to listen for them and then later unlisten.
This is shown here:
def socket = vertx.createDatagramSocket([:])
socket.listen(1234, "0.0.0.0", { asyncResult ->
if (asyncResult.succeeded()) {
socket.handler({ packet ->
// Do something with the packet
})
// join the multicast group
socket.listenMulticastGroup("230.0.0.1", { asyncResult2 ->
if (asyncResult2.succeeded()) {
// will now receive packets for group
// do some work
socket.unlistenMulticastGroup("230.0.0.1", { asyncResult3 ->
println("Unlisten succeeded? ${asyncResult3.succeeded()}")
})
} else {
http://vertx.io/docs/vertx-core/groovy/
52/66
9/1/2015
}
})
} else {
println("Listen failed${asyncResult.cause()}")
}
})
Blocking multicast
Beside unlisten a Multicast address its also possible to just block multicast for a specific sender address.
Be aware this only work on some Operating Systems and kernel versions. So please check the Operating System documentation if its
supported.
This an expert feature.
To block multicast from a specific address you can call blockMulticastGroup()on the DatagramSocket like shown here:
def socket = vertx.createDatagramSocket([:])
// Some code
// This would block packets which are send from 10.0.0.2
socket.blockMulticastGroup("230.0.0.1", "10.0.0.2", { asyncResult ->
println("block succeeded? ${asyncResult.succeeded()}")
})
DatagramSocket properties
When creating a DatagramSocketthere are multiple properties you can set to change its behaviour with the DatagramSocketOptions
object. Those are listed here:
sendBufferSizeSets
receiveBufferSizeSets
reuseAddressIf
true then addresses in TIME_WAIT state can be reused after they have been closed.
trafficClass
broadcastSets
or clears the SO_BROADCAST socket option. When this option is set, Datagram (UDP) packets may be sent to a
local interfaces broadcast address.
multicastNetworkInterfaceSets
or clears the IP_MULTICAST_LOOP socket option. When this option is set, multicast
packets will also be received on the local interface.
multicastTimeToLiveSets
the IP_MULTICAST_TTL socket option. TTL stands for "Time to Live," but in this context it
specifies the number of IP hops that a packet is allowed to go through, specifically for multicast traffic. Each router or gateway
that forwards a packet decrements the TTL. If the TTL is decremented to 0 by a router, it will not be forwarded.
DatagramSocket Local Address
You can find out the local address of the socket (i.e. the address of this side of the UDP Socket) by calling localAddress. This will
only return an InetSocketAddressif you bound the DatagramSocketwith listen()before, otherwise it will return null.
Closing a DatagramSocket
You can close a socket by invoking the closemethod. This will close the socket and release all resources
DNS client
Often you will find yourself in situations where you need to obtain DNS informations in an asynchronous fashion.
Unfortunally this is not possible with the API that is shipped with the Java Virtual Machine itself. Because of this Vert.x offers its own
API for DNS resolution which is fully asynchronous.
To obtain a DnsClient instance you will create a new via the Vertx instance.
def client = vertx.createDnsClient(53, "10.0.0.1")
Be aware that you can pass in a varargs of InetSocketAddress arguments to specifiy more then one DNS Server to try to query for DNS
resolution. The DNS Servers will be queried in the same order as specified here. Where the next will be used once the first produce an
error while be used.
http://vertx.io/docs/vertx-core/groovy/
53/66
9/1/2015
lookup
Try to lookup the A (ipv4) or AAAA (ipv6) record for a given name. The first which is returned will be used, so it behaves the same
way as you may be used from when using "nslookup" on your operation system.
To lookup the A / AAAA record for "vertx.io" you would typically use it like:
def client = vertx.createDnsClient(53, "10.0.0.1")
client.lookup("vertx.io", { ar ->
if (ar.succeeded()) {
println(ar.result())
} else {
println("Failed to resolve entry${ar.cause()}")
}
})
lookup4
Try to lookup the A (ipv4) record for a given name. The first which is returned will be used, so it behaves the same way as you may be
used from when using "nslookup" on your operation system.
To lookup the A record for "vertx.io" you would typically use it like:
def client = vertx.createDnsClient(53, "10.0.0.1")
client.lookup4("vertx.io", { ar ->
if (ar.succeeded()) {
println(ar.result())
} else {
println("Failed to resolve entry${ar.cause()}")
}
})
lookup6
Try to lookup the AAAA (ipv6) record for a given name. The first which is returned will be used, so it behaves the same way as you
may be used from when using "nslookup" on your operation system.
To lookup the A record for "vertx.io" you would typically use it like:
def client = vertx.createDnsClient(53, "10.0.0.1")
client.lookup6("vertx.io", { ar ->
if (ar.succeeded()) {
println(ar.result())
} else {
println("Failed to resolve entry${ar.cause()}")
}
})
resolveA
Try to resolve all A (ipv4) records for a given name. This is quite similar to using "dig" on unix like operation systems.
To lookup all the A records for "vertx.io" you would typically do:
def client = vertx.createDnsClient(53, "10.0.0.1")
client.resolveA("vertx.io", { ar ->
if (ar.succeeded()) {
def records = ar.result()
records.each { record ->
println(record)
}
} else {
println("Failed to resolve entry${ar.cause()}")
}
})
resolveAAAA
Try to resolve all AAAA (ipv6) records for a given name. This is quite similar to using "dig" on unix like operation systems.
To lookup all the AAAAA records for "vertx.io" you would typically do:
def client = vertx.createDnsClient(53, "10.0.0.1")
client.resolveAAAA("vertx.io", { ar ->
if (ar.succeeded()) {
def records = ar.result()
records.each { record ->
println(record)
http://vertx.io/docs/vertx-core/groovy/
54/66
9/1/2015
Vert.x Core Manual · Vert.x
}
} else {
println("Failed to resolve entry${ar.cause()}")
}
})
resolveCNAME
Try to resolve all CNAME records for a given name. This is quite similar to using "dig" on unix like operation systems.
To lookup all the CNAME records for "vertx.io" you would typically do:
def client = vertx.createDnsClient(53, "10.0.0.1")
client.resolveCNAME("vertx.io", { ar ->
if (ar.succeeded()) {
def records = ar.result()
records.each { record ->
println(record)
}
} else {
println("Failed to resolve entry${ar.cause()}")
}
})
resolveMX
Try to resolve all MX records for a given name. The MX records are used to define which Mail-Server accepts emails for a given
domain.
To lookup all the MX records for "vertx.io" you would typically do:
def client = vertx.createDnsClient(53, "10.0.0.1")
client.resolveMX("vertx.io", { ar ->
if (ar.succeeded()) {
def records = ar.result()
records.each { record ->
println(record)
}
} else {
println("Failed to resolve entry${ar.cause()}")
}
})
Be aware that the List will contain the MxRecordsorted by the priority of them, which means MX records with smaller priority coming
first in the List.
The MxRecordallows you to access the priority and the name of the MX record by offer methods for it like:
record.priority()
record.name()
resolveTXT
Try to resolve all TXT records for a given name. TXT records are often used to define extra informations for a domain.
To resolve all the TXT records for "vertx.io" you could use something along these lines:
def client = vertx.createDnsClient(53, "10.0.0.1")
client.resolveTXT("vertx.io", { ar ->
if (ar.succeeded()) {
def records = ar.result()
records.each { record ->
println(record)
}
} else {
println("Failed to resolve entry${ar.cause()}")
}
})
resolveNS
Try to resolve all NS records for a given name. The NS records specify which DNS Server hosts the DNS informations for a given
domain.
To resolve all the NS records for "vertx.io" you could use something along these lines:
def client = vertx.createDnsClient(53, "10.0.0.1")
client.resolveNS("vertx.io", { ar ->
if (ar.succeeded()) {
http://vertx.io/docs/vertx-core/groovy/
55/66
9/1/2015
Vert.x Core Manual · Vert.x
def records = ar.result()
records.each { record ->
println(record)
}
} else {
println("Failed to resolve entry${ar.cause()}")
}
})
resolveSRV
Try to resolve all SRV records for a given name. The SRV records are used to define extra informations like port and hostname of
services. Some protocols need this extra informations.
To lookup all the SRV records for "vertx.io" you would typically do:
def client = vertx.createDnsClient(53, "10.0.0.1")
client.resolveSRV("vertx.io", { ar ->
if (ar.succeeded()) {
def records = ar.result()
records.each { record ->
println(record)
}
} else {
println("Failed to resolve entry${ar.cause()}")
}
})
Be aware that the List will contain the SrvRecords sorted by the priority of them, which means SrvRecords with smaller priority coming
first in the List.
The SrvRecordallows you to access all informations contained in the SRV record itself:
record.priority()
record.name()
record.weight()
record.port()
record.protocol()
record.service()
record.target()
resolvePTR
Try to resolve the PTR record for a given name. The PTR record maps an ipaddress to a name.
To resolve the PTR record for the ipaddress 10.0.0.1 you would use the PTR notion of "1.0.0.10.in-addr.arpa"
def client = vertx.createDnsClient(53, "10.0.0.1")
client.resolvePTR("1.0.0.10.in-addr.arpa", { ar ->
if (ar.succeeded()) {
def record = ar.result()
println(record)
} else {
println("Failed to resolve entry${ar.cause()}")
}
})
reverseLookup
Try to do a reverse lookup for an ipaddress. This is basically the same as resolve a PTR record, but allows you to just pass in the
ipaddress and not a valid PTR query string.
To do a reverse lookup for the ipaddress 10.0.0.1 do something similar like this:
def client = vertx.createDnsClient(53, "10.0.0.1")
client.reverseLookup("10.0.0.1", { ar ->
if (ar.succeeded()) {
def record = ar.result()
println(record)
} else {
println("Failed to resolve entry${ar.cause()}")
}
})
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
http://vertx.io/docs/vertx-core/groovy/
56/66
9/1/2015
FORMERRORFormat
error
SERVFAILServer
failure
NXDOMAINName
error
NOTIMPLNot
REFUSEDDNS
YXDOMAINDomain
YXRRSETResource
NXRRSETRRSET
NOTZONEName
BADVERSBad
not in zone
BADSIGBad
signature
BADKEYBad
key
BADTIMEBad
timestamp
Streams
There are several objects in Vert.x that allow items to be read from and written.
In previous versions the streams.adoc package was manipulating Bufferobjects exclusively. From now, streams are not anymore
coupled to buffers and work with any kind of objects.
In Vert.x, calls to write item return immediately and writes are internally queued.
Its not hard to see that if you write to an object faster than it can actually write the data to its underlying resource then the write queue
could grow without bound - eventually resulting in exhausting available memory.
To solve this problem a simple flow control capability is provided by some objects in the Vert.x API.
Any flow control aware object that can be written-to implements ReadStream, and any flow control object that can be read-from is said
to implement WriteStream.
Lets take an example where we want to read from a ReadStreamand write the data to a WriteStream.
A very simple example would be reading from a NetSocketon a server and writing back to the same NetSocket- since NetSocket
http://vertx.io/docs/vertx-core/groovy/
57/66
9/1/2015
implements both ReadStreamand WriteStream, but you can do this between any ReadStreamand any WriteStream, including HTTP
requests and response, async files, WebSockets, etc.
A naive way to do this would be to directly take the data thats been read and immediately write it to the NetSocket, for example:
def server = vertx.createNetServer([
port:1234,
host:"localhost"
])
server.connectHandler({ sock ->
sock.handler({ buffer ->
// Write the data straight back
sock.write(buffer)
})
}).listen()
Theres a problem with the above example: If data is read from the socket faster than it can be written back to the socket, it will build up
in the write queue of the NetSocket, eventually running out of RAM. This might happen, for example if the client at the other end of the
socket wasnt reading very fast, effectively putting back-pressure on the connection.
Since NetSocketimplements WriteStream, we can check if the WriteStreamis full before writing to it:
def server = vertx.createNetServer([
port:1234,
host:"localhost"
])
server.connectHandler({ sock ->
sock.handler({ buffer ->
if (!sock.writeQueueFull()) {
sock.write(buffer)
}
})
}).listen()
This example wont run out of RAM but well end up losing data if the write queue gets full. What we really want to do is pause the
NetSocketwhen the write queue is full. Lets do that:
def server = vertx.createNetServer([
port:1234,
host:"localhost"
])
server.connectHandler({ sock ->
sock.handler({ buffer ->
sock.write(buffer)
if (sock.writeQueueFull()) {
sock.pause()
}
})
}).listen()
Were almost there, but not quite. The NetSocketnow gets paused when the file is full, but we also need to unpause it when the write
queue has processed its backlog:
def server = vertx.createNetServer([
port:1234,
host:"localhost"
])
server.connectHandler({ sock ->
sock.handler({ buffer ->
sock.write(buffer)
if (sock.writeQueueFull()) {
sock.pause()
sock.drainHandler({ done ->
sock.resume()
})
}
})
}).listen()
And there we have it. The drainHandlerevent handler will get called when the write queue is ready to accept more data, this resumes
the NetSocketwhich allows it to read more data.
Its very common to want to do this when writing Vert.x applications, so we provide a helper class called Pumpwhich does all this hard
work for you. You just feed it the ReadStreamand the WriteStreamand it tell it to start:
import io.vertx.groovy.core.streams.Pump
def server = vertx.createNetServer([
port:1234,
host:"localhost"
])
server.connectHandler({ sock ->
http://vertx.io/docs/vertx-core/groovy/
58/66
9/1/2015
Pump.pump(sock, sock).start()
}).listen()
Which does exactly the same thing as the more verbose example.
Lets look at the methods on ReadStreamand WriteStreamin more detail:
ReadStream
ReadStreamis implemented by HttpClientResponse, DatagramSocket, HttpClientRequest, HttpServerFileUpload,
HttpServerRequest, HttpServerRequestStream, MessageConsumer, NetSocket, NetSocketStream, WebSocket, WebSocketStream,
TimeoutStream, AsyncFile.
Functions:
handler: set
pause: pause
resume: resume
exceptionHandler: Will
endHandler: Will
be called when end of stream is reached. This might be when EOF is reached if the ReadStream represents a
file, or when end of request is reached if its an HTTP request, or when the connection is closed if its a TCP socket.
WriteStream
WriteStreamis implemented
and MessageProducer
Functions:
write: write
an object to the WriteStream. This method will never block. Writes are queued internally and asynchronously
written to the underlying resource.
setWriteQueueMaxSize: set the number of object at which the write queue is considered full, and the method writeQueueFull
returns true. Note that, when the write queue is considered full, if write is called the data will still be accepted and queued. The
actual number depends on the stream implementation, for Bufferthe size represents the actual number of bytes written and not
Pump
Instances of Pump have the following methods:
start: Start
the pump.
stop: Stops
setWriteQueueMaxSize: This
Record Parser
The record parser allows you to easily parse protocols which are delimited by a sequence of bytes, or fixed size records.
It transforms an sequence of input buffer to a sequence of buffer structured as configured (either fixed size or separated records).
For example, if you have a simple ASCII text protocol delimited by '\n' and the input is the following:
buffer1:HELLO\nHOW ARE Y
buffer2:OU?\nI AM
buffer3: DOING OK
buffer4:\n
http://vertx.io/docs/vertx-core/groovy/
59/66
9/1/2015
Thread safety
Most Vert.x objects are safe to access from different threads. However performance is optimised when they are accessed from the same
context they were created from.
For example if you have deployed a verticle which creates a NetServerwhich provides NetSocketinstances in its handler, then its
best to always access that socket instance from the event loop of the verticle.
If you stick to the standard Vert.x verticle deployment model and avoid sharing objects between verticles then this should be the case
without you having to think about it.
Metrics SPI
By default Vert.x does not record any metrics. Instead it provides an SPI for others to implement which can be added to the classpath.
The metrics SPI is an advanced feature which allows implementers to capture events from Vert.x in order to gather metrics. For more
information on this, please consult the API Documentation.
OSGi
Vert.x Core is packaged as an OSGi bundle, so can be used in any OSGi R4.2+ environment such as Apache Felix or Eclipse Equinox.
The bundle exports io.vertx.core*.
However, the bundle has some dependencies on Jackson and Netty. To get the vert.x core bundle resolved deploy:
Jackson Annotation [2.5.0,3)
Jackson Core [2.5.0,3)
Jackson Databind [2.5.0,3)
Netty Buffer [4.0.27,5)
Netty Codec [4.0.27,5)
Netty Codec/Socks [4.0.27,5)
Netty Codec/Common [4.0.27,5)
Netty Codec/Handler [4.0.27,5)
Netty Codec/Transport [4.0.27,5)
Here is a working deployment on Apache Felix 4.6.1:
14|Active
15|Active
16|Active
|
|
|
1|Jackson-annotations (2.5.3)
1|Jackson-core (2.5.3)
1|jackson-databind (2.5.3)
http://vertx.io/docs/vertx-core/groovy/
60/66
9/1/2015
17|Active
18|Active
19|Active
20|Active
21|Active
22|Active
23|Active
25|Active
|
|
|
|
|
|
|
|
Run verticles
You can run raw Vert.x verticles directly from the command line using vertx run. Here is a couple of examples:
vertx run my-verticle.js
vertx run my-verticle.groovy
vertx run my-verticle.rb
(1)
(2)
(3)
(6)
The vertx runcommand can take a few optional parameters, they are:
-conf <config_file>-
Provides some configuration to the verticle. config_fileis the name of a text file containing a JSON
object that represents the configuration for the verticle. This is optional.
-cp <path>-
The path on which to search for the verticle and any other resources used by the verticle. This defaults to .(current
directory). If your verticle references other scripts, classes or other resources (e.g. jar files) then make sure these are on this path.
The path can contain multiple path entries separated by :(colon) or ;(semi-colon) depending on the operating system. Each path
entry can be an absolute or relative path to a directory containing scripts, or absolute or relative filenames for jar or zip files. An
example path might be -cp classes:lib/otherscripts:jars/myjar.jar:jars/otherjar.jar. Always use the path to
reference any resources that your verticle requires. Do not put them on the system classpath as this can cause isolation issues
between deployed verticles.
-instances <instances>-
The number of instances of the verticle to instantiate. Each verticle instance is strictly single threaded
so to scale your application across available cores you might want to deploy more than one instance. If omitted a single instance
will be deployed.
-worker-
-cluster-
This option determines whether the Vert.x instance will attempt to form a cluster with other Vert.x instances on the
network. Clustering Vert.x instances allows Vert.x to form a distributed event bus with other nodes. Default is false(not
clustered).
-cluster-port-
If the cluster option has also been specified then this determines which port will be used for cluster
communication with other Vert.x instances. Default is 0- which means 'choose a free random port'. You dont usually need to
http://vertx.io/docs/vertx-core/groovy/
61/66
9/1/2015
specify this parameter unless you really need to bind to a specific port.
-cluster-host-
If the cluster option has also been specified then this determines which host address will be used for cluster
communication with other Vert.x instances. By default it will try and pick one from the available interfaces. If you have more
than one interface and you want to use a specific one, specify it here.
-ha-
if specified the verticle will be deployed as high availability (HA) deployment. See related section for more details
-quorum-
used in conjunction with -ha. It specifies the minimum number of nodes in the cluster for any HA deploymentIDs to be
active. Defaults to 0.
-hagroup-
used in conjunction with -ha. It specifies the HA group this node will join. There can be multiple HA groups in a
cluster. Nodes will only failover to other nodes in the same group. The default value is ` __DEFAULT__`
Here are some more examples:
Run a JavaScript verticle server.js with default settings
vertx run server.js
Run two JavaScript verticles on the same machine and let them cluster together with each other and any other servers on the network
vertx run handler.js -cluster
vertx run sender.js -cluster
The config will be available inside the verticle via the core API.
When using the high-availability feature of vert.x you may want to create a bare instance of vert.x. This instance does not deploy any
verticles when launched, but will receive a verticle if another node of the cluster dies. To create a bare instance, launch:
vertx -ha
Depending on your cluster configuration, you may have to append the cluster-hostand cluster-portparameters.
to io.vertx.core.Starter
Main-Verticlespecifying
You can also provide the usual command line arguments that you would pass to vertx run:
java -jar my-verticle-fat.jar -cluster -conf myconf.json
java -jar my-verticle-fat.jar -cluster -conf myconf.json -cp path/to/dir/conf/cluster_xml
Note fat jar can be built using Gradle build or the Maven plugin. Check the vertx examples for instructions.
http://vertx.io/docs/vertx-core/groovy/
62/66
9/1/2015
Cluster Managers
In Vert.x a cluster manager is used for various functions including:
Discovery and group membership of Vert.x nodes in a cluster
Maintaining cluster wide topic subscriber lists (so we know which nodes are interested in which event bus addresses)
Distributed Map support
Distributed Locks
Distributed Counters
Cluster managers do not handle the event bus inter-node transport, this is done directly by Vert.x with TCP connections.
The default cluster manager used in the Vert.x distributions is one that uses Hazelcast but this can be easily replaced by a different
implementation as Vert.x cluster managers are pluggable.
A cluster manager must implement the interface ClusterManager. Vert.x locates cluster managers at run-time by using the Java Service
Loader functionality to locate instances of ClusterManageron the classpath.
If you are using Vert.x at the command line and you want to use clustering you should make sure the libdirectory of the Vert.x
installation contains your cluster manager jar.
If you are using Vert.x from a Maven or Gradle project just add the cluster manager jar as a dependency of your project.
You can also specify cluster managers programmatically if embedding Vert.x using clusterManager.
Logging
Vert.x logs using its in-built logging API. The default implementation uses the JDK (JUL) logging so no extra logging dependencies
are needed.
http://vertx.io/docs/vertx-core/groovy/
63/66
9/1/2015
Vert.x Core Manual · Vert.x
def logger = io.vertx.core.logging.LoggerFactory.getLogger(className)
logger.info("something happened")
logger.error("oops!", exception)
Automatic failover
When vert.x runs with HA enabled, if a vert.x instance where a verticle runs fails or dies, the verticle is redeployed automatically on
another vert.x instance of the cluster. We call this verticle fail-over.
To run vert.x with the HA enabled, just add the -haflag to the command line:
vertx run my-verticle.js -ha
Now for HA to work, you need more than one Vert.x instances in the cluster, so lets say you have another Vert.x instance that you have
already started, for example:
vertx run my-other-verticle.js -ha
If the Vert.x instance that is running my-verticle.jsnow dies (you can test this by killing the process with kill -9), the Vert.x
instance that is running my-other-verticle.jswill automatic deploy my-verticle .jsso now that Vert.x instance is running both
verticles.
Note the migration is only possible if the second vert.x instance has access to the verticle file (here my-verticle.js).
Important Please note that cleanly closing a Vert.x instance will not cause failover to occur, e.g. CTRL-Cor kill -SIGINT
You can also start bare Vert.x instances - i.e. instances that are not initially running any verticles, they will also failover for nodes in the
cluster. To start a bare instance you simply do:
vertx run -ha
When using the -haswitch you do not need to provide the -clusterswitch, as a cluster is assumed if you want HA.
Note
depending on your cluster configuration, you may need to customize the cluster manager configuration (Hazelcast by default),
and/or add the cluster-hostand cluster-portparameters.
HA groups
When running a Vert.x instance with HA you can also optional specify a HA group. A HA group denotes a logical group of nodes in the
cluster. Only nodes with the same HA group will failover onto one another. If you dont specify a HA group the default group
__DEFAULT__is used.
To specify an HA group you use the -hagroupswitch when running the verticle, e.g.
vertx run my-verticle.js -ha -ha-group my-group
In a second terminal, lets run another verticle using the same group:
vertx run my-other-verticle.js -ha -hagroup g1
If we kill the instance in terminal 1, it will fail over to the instance in terminal 2, not the instance in terminal 3 as that has a different
group.
If we kill the instance in terminal 3, it wont get failed over as there is no other vert.x instance in that group.
64/66
9/1/2015
At this point the Vert.x instance will start but not deploy the module (yet) because there is only one node in the cluster, not 3.
In a second terminal:
vertx run my-other-verticle.js -ha -quorum 3
At this point the Vert.x instance will start but not deploy the module (yet) because there are only two nodes in the cluster, not 3.
In a third console, you can start another instance of vert.x:
vertx run yet-another-verticle.js -ha -quorum 3
Yay! - we have three nodes, thats a quorum. At this point the modules will automatically deploy on all instances.
If we now close or kill one of the nodes the modules will automatically undeploy on the other nodes, as there is no longer a quorum.
Quora can also be used in conjunction with ha groups. In that case, quora are resolved for each particular group.
Security notes
Vert.x is a toolkit, not an opinionated framework where we force you to do things in a certain way. This gives you great power as a
developer but with that comes great responsibility.
As with any toolkit, its possible to write insecure applications, so you should always be careful when developing your application
especially if its exposed to the public (e.g. over the internet).
Web applications
If writing a web application its highly recommended that you use Vert.x-Web instead of Vert.x core directly for serving resources and
handling file uploads.
Vert.x-Web normalises the path in requests to prevent malicious clients from crafting URLs to access resources outside of the web root.
Similarly for file uploads Vert.x-Web provides functionality for uploading to a known place on disk and does not rely on the filename
provided by the client in the upload which could be crafted to upload to a different place on disk.
Vert.x core itself does not provide such checks so it would be up to you as a developer to implement them yourself.
Vert.x
Home
Download
http://vertx.io/docs/vertx-core/groovy/
65/66
9/1/2015
Documentation
Wiki
Vert.x 2
Community
Help & Contributors
User Group
Developer Group
Vert.x is open source and dual licensed under the Eclipse Public License 1.0 and Apache License 2.0.
This website is licensed under the CC BY-SA 3.0 License.
Design by Michel Krmer. Entypo pictograms by Daniel Bruce.
http://vertx.io/docs/vertx-core/groovy/
66/66