== Vertx

https://vertx.io/[Vertx] Reactive applications on the JVM.

This module export the following services:

- io.vertx.core.Vertx
- io.vertx.core.eventbus.EventBus
- io.vertx.core.file.FileSystem

=== Usage

1) Add the dependency:

[dependency, artifactId="jooby-vertx"]
.

2) Install

.Java
[source, java, role="primary"]
----
import io.jooby.vertx.VertxModule;
import static io.jooby.vertx.VertxHandler.vertx;
{
  install(new VertxModule());                                         <1>

  use(vertx());                                                       <2>

  get("/bus}", ctx -> {
    var eb = require(EventBus.class);                                 <3>

    eventBus.publish("msg", ctx.query("msg").value("Event Bus!"));    <4>
    ...
  });
  
  get("/*filepath", ctx -> {
    var fs = require(FileSytem.class);                                <5>
    return fs.open(ctx.path("filepath").value(), new OpenOptions());  <6>
  });
}
----

.Kotlin
[source, kt, role="secondary"]
---- 
import io.jooby.vertx.VertxModule

{
  install(VertxModule())                                              <1>

  use(vertx())                                                        <2>

  get("/bus") {
    val eb = require(EventBus::class)                                 <3>

    eventBus.publish("msg", ctx.query("msg").value("Event Bus!"))     <4>
    ...
  }

  get("/*filepath") {
    varl fs = require(FileSytem::class)                               <5>
    fs.open(ctx.path("filepath").value(), OpenOptions())              <6>
  }
}
----

<1> Install Vertx
<2> Install vertx handler. Know how to render future, promise and buffer.
<3> Get EventBus instance
<4> Send message to `msg`
<5> Get FileSystem
<6> Open a possible large file and send it to client.

=== Options

Options can be provided manually or from application.conf properties:

.Manually
[source, java]
----
import io.jooby.vertx.VertxModule;

{
  install(new VertxModule(new VertxOptions()
    .setEventLoopSize(5)
    .setWorkerPoolSize(20)
    .setBlockedThreadCheckInterval(500)
    .setMaxEventLoopExecuteTime(2000)
  ));
}
----

.application.conf
[source, properties]
----
vertx.eventLoopPoolSize=5
vertx.workerPoolSize = 20
vertx.blockedThreadCheckInterval=500
vertx.maxEventLoopExecuteTime=2000
...
----

[source, java]
----
import io.jooby.vertx.VertxModule;

{
  install(new VertxModule());
}
----

A clustered vertx instance can be provided at creation time:

.Clustered
[source, java]
----
import io.jooby.vertx.VertxModule;

{
  install(new VertxModule(options -> Vertx.builder()
     .with(options)
     .withClusteredManager(cm)
     .buildClustered()
  ));
}
----

include::modules/vertx-sql-client.adoc[]

== Vertx Server (Advanced)

The javadoc:vertx.VertxServer[] allow you to share the Vertx acceptor and event loop groups within 
the javadoc:netty.NettyServer[], so both vertx and netty web server implementation share the same
resources. See https://vertx.io/docs/guides/advanced-vertx-guide/#integrating-netty[for more information].

The vertx server must be manually provided at boot time (there is no service loader support for it):

.Java
[source, java, role="primary"]
----
import io.jooby.vertx.VertxServer;

{
  get("/vertx", ctx -> {
    return "Running from vertx event loop";
  });
}

public static void main(String[] args) {
  runApp(args, new VertxServer(), EVENT_LOOP, App::new);
}
----

.Kotlin
[source, kt, role="secondary"]
---- 
import io.jooby.vertx.VertxServer

import io.jooby.vertx.VertxServer;

{
  get("/vertx") {
    "Running from vertx event loop"
  }
}

un main(args: Array<String>) {
  runApp(args, VertxServer(), EVENT_LOOP, ::App)
}
----

If you run multiple applications, they all share a single Vertx instance.

[IMPORTANT]
====
*VertxModule must NOT be installed while running on VertxServer*
====

One of the main benefits of running on the VertxServer is to share/reuse the event loop threads.
You can run non-blocking code on the Vertx event loop thread without context switch. A good example
of this is to run within

=== Sql Connection

These modules exist as part of the performance tests required by https://www.techempower.com/benchmarks[Techempower].

You are free to use them, but keep in mind they are for very specific kind of application.

include::vertx-sql-connection.template[artifactId="jooby-vertx-mysql-client" sqlClient="MySQL" moduleName="VertxMySQLConnectionModule"]

include::vertx-sql-connection.template[artifactId="jooby-vertx-pg-client" sqlClient="Postgres" moduleName="VertxPgConnectionModule"]


==== How it works?

There is an internal Verticle (one per IO threads) with a dedicated https://vertx.io/docs/apidocs/io/vertx/sqlclient/SqlConnection.html[SqlConnection]. This connection is only 
accessible from a Vertx thread any attempt to access to the connection from a non Vertx thread
will result in exception.

Same applies for the https://vertx.io/docs/apidocs/io/vertx/sqlclient/PreparedStatement.html[PreparedStatement] / https://vertx.io/docs/apidocs/io/vertx/sqlclient/PreparedQuery.html[PreparedQuery] instances.

.PreparedStatement example:
[source,java]
----
import io.jooby.Reified;

String SELECT_WORLD = "SELECT id, randomnumber from WORLD where id=$1";

Reified<PreparedQuery<RowSet<Row>>> PreparedQueryType =
    getParameterized(PreparedQuery.class, getParameterized(RowSet.class, Row.class));

{
  install(new VertxPgConnectionModule()
     .preparedStatement(Map.of("selectWorld", List.of(SELECT_WORLD)))      <1>
  );

  use(vertx());                                                            <2>

  var selectWorldQuery = ctx.require(PreparedQueryType, "selectWorld");    <3>
  get("/world/{id}", ctx -> {
    return selectWorldQuery.execute(Tuple.of(ctx.path("id").longValue()))
          .map(
              result -> {
                var row = result.iterator().next();
                return new World(row.getInteger(0), row.getInteger(1));
              });
  });
}

public static void main(String[] args) {
  runApp(args, new VertxServer(), EVENT_LOOP, App::new);
}
----

<1> Created a prepared statement. This is done when Verticle is deployed
<2> Add Vertx handler, so it can render Future and Promise.
<3> Get a reference to the prepared statement

The line:

    var selectWorldQuery = ctx.require(PreparedQueryType, "selectWorld");

Allow you to get a reference/proxy to the prepared statement/query. The proxy will thrown an exception
if you try to use from a non Vertx thread. The prepared statement is compiled when the Verticle
is deployed (at application startup time).

If you work with any of the dependency injection supported framework, you can inject the prepared
statement like:

[source,java]
----
@Inject
public WorldRepository(@Named("selectWorld") PreparedQuery<RowSet<Row>> selectWorld) {
  this.selectWorld = selectWorld;
}
----
