Browse Source

Update vertx entry (#2968)

Julien Viet 8 years ago
parent
commit
d8ea58c517

+ 35 - 6
frameworks/Java/vertx/README.md

@@ -1,22 +1,35 @@
 # Vertx Benchmarking Test
 
-This is the vertx portion of a [benchmarking test suite](../) comparing a variety of web development platforms.
-
-Minimal attempts have been made for performance. 
+This is the Vert.x portion of a [benchmarking test suite](../) comparing a variety of web development platforms.
 
 ### Plaintext Test
 
-* [Plaintext test source](WebServer.java)
+* [Plaintext test source](src/main/java/vertx/App.java)
 
 ### JSON Serialization Test
 
-* [JSON test source](WebServer.java)
+* [JSON test source](src/main/java/vertx/App.java)
+
+### Database Query Test
+
+* [Database Query test source](src/main/java/vertx/App.java)
+
+### Database Queries Test
+
+* [Database Queries test source](src/main/java/vertx/App.java)
+
+### Database Update Test
+
+* [Database Update test source](src/main/java/vertx/App.java)
+
+### Template rendering Test
 
+* [Template rendering test source](src/main/java/vertx/App.java)
 
 ## Versions
 
 * [Java OpenJDK 1.8](http://openjdk.java.net/)
-* [vertx 3.1.0](http://vertx.io/)
+* [vertx 3.5.0.Beta1](http://vertx.io/)
 
 ## Test URLs
 
@@ -27,3 +40,19 @@ Minimal attempts have been made for performance.
 ### JSON Encoding Test
 
     http://localhost:8080/json
+
+### Database Query Test
+
+    http://localhost:8080/db
+
+### Database Queries Test
+
+    http://localhost:8080/queries?queries=5
+
+### Database Update Test
+
+    http://localhost:8080/updates?queries=5
+
+### Template rendering Test
+
+    http://localhost:8080/fortunes

+ 24 - 2
frameworks/Java/vertx/benchmark_config.json

@@ -13,13 +13,35 @@
       "language": "Java",
       "flavor": "None",
       "orm": "Raw",
-      "platform": "Netty",
+      "platform": "Vert.x",
       "webserver": "None",
       "os": "Linux",
       "database_os": "Linux",
       "display_name": "vertx",
       "notes": "",
-      "versus": "netty"
+      "versus": ""
+    },
+    "postgres": {
+      "setup_file": "setup_postgresql",
+      "db_url": "/db",
+      "query_url": "/queries?queries=",
+      "fortune_url": "/fortunes",
+      "update_url": "/updates?queries=",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "Platform",
+      "database": "Postgres",
+      "framework": "None",
+      "language": "Java",
+      "flavor": "None",
+      "orm": "Raw",
+      "platform": "Vert.x",
+      "webserver": "None",
+      "os": "Linux",
+      "database_os": "Linux",
+      "display_name": "vertx-postgres",
+      "notes": "",
+      "versus": ""
     }
   }]
 }

+ 37 - 19
frameworks/Java/vertx/pom.xml

@@ -1,37 +1,32 @@
 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 	<modelVersion>4.0.0</modelVersion>
-	<groupId>com.jebbstewart</groupId>
+	<groupId>com.techempower</groupId>
 	<artifactId>vertx.benchmark</artifactId>
 	<version>0.0.1-SNAPSHOT</version>
 
 	<properties>
 		<!-- the main class -->
-		<main.class>vertx.WebServer</main.class>
-		<stack.version>3.3.2</stack.version>
+		<main.class>vertx.App</main.class>
+		<stack.version>3.5.0.Beta1</stack.version>
 	</properties>
 
-	<repositories>
-		<repository>
-			<id>sonatype-nexus-snapshots</id>
-			<name>Sonatype Nexus Snapshots</name>
-			<url>https://oss.sonatype.org/content/repositories/snapshots</url>
-			<releases>
-				<enabled>false</enabled>
-			</releases>
-			<snapshots>
-				<enabled>true</enabled>
-			</snapshots>
-		</repository>
-	</repositories>
-
-
 	<dependencies>
 		<dependency>
 			<groupId>io.vertx</groupId>
 			<artifactId>vertx-core</artifactId>
 			<version>${stack.version}</version>
 		</dependency>
+		<dependency>
+			<groupId>com.julienviet</groupId>
+			<artifactId>vertx-pg-client</artifactId>
+			<version>0.3.0</version>
+		</dependency>
+		<dependency>
+			<groupId>com.fizzed</groupId>
+			<artifactId>rocker-compiler</artifactId>
+			<version>0.22.0</version>
+		</dependency>
 	</dependencies>
 
 	<build>
@@ -44,6 +39,29 @@
 					<target>1.8</target>
 				</configuration>
 			</plugin>
+			<plugin>
+				<groupId>com.fizzed</groupId>
+				<artifactId>rocker-maven-plugin</artifactId>
+				<version>0.22.0</version>
+				<executions>
+					<execution>
+						<id>generate-rocker-templates</id>
+						<phase>generate-sources</phase>
+						<goals>
+							<goal>generate</goal>
+						</goals>
+						<configuration>
+							<javaVersion>1.8</javaVersion>
+							<templateDirectory>${basedir}/src/main/templates</templateDirectory>
+							<outputDirectory>${basedir}/target/generated-sources/rocker</outputDirectory>
+							<discardLogicWhitespace>false</discardLogicWhitespace>
+							<addAsSources>true</addAsSources>
+							<optimize>true</optimize>
+							<failOnError>true</failOnError>
+						</configuration>
+					</execution>
+				</executions>
+			</plugin>
 			<plugin>
 				<groupId>org.apache.maven.plugins</groupId>
 				<artifactId>maven-shade-plugin</artifactId>
@@ -78,4 +96,4 @@
 
 	</build>
 
-</project>
+</project>

+ 4 - 3
frameworks/Java/vertx/setup.sh

@@ -1,8 +1,9 @@
 #!/bin/bash
 
+sed -i 's|localhost|'"${DBHOST}"'|g' src/main/conf/config.json
+
 fw_depends java maven
 
-mvn clean package 
+mvn clean package
 
-cd target
-java -server -XX:+UseNUMA -XX:+UseParallelGC -XX:+AggressiveOpts -Dvertx.disableWebsockets=true -Dvertx.flashPolicyHandler=false -Dvertx.threadChecks=false -Dvertx.disableContextTimings=true -Dvertx.disableTCCL=true -jar vertx.benchmark-0.0.1-SNAPSHOT-fat.jar &
+java -Xms2G -Xmx2G -server -XX:+UseNUMA -XX:+UseParallelGC -XX:+AggressiveOpts -Dvertx.disableMetrics=true -Dvertx.disableH2c=true -Dvertx.disableWebsockets=true -Dvertx.flashPolicyHandler=false -Dvertx.threadChecks=false -Dvertx.disableContextTimings=true -Dvertx.disableTCCL=true -jar target/vertx.benchmark-0.0.1-SNAPSHOT-fat.jar src/main/conf/config.json &

+ 5 - 0
frameworks/Java/vertx/setup_postgresql.sh

@@ -0,0 +1,5 @@
+#!/bin/bash
+
+fw_depends postgresql
+
+source ./setup.sh

+ 1 - 0
frameworks/Java/vertx/source_code

@@ -1 +1,2 @@
 ./vertx/src/main/java/vertx/WebServer.java
+./vertx/src/main/java/vertx/model/World.java

+ 7 - 0
frameworks/Java/vertx/src/main/conf/config.json

@@ -0,0 +1,7 @@
+{
+  "host": "localhost",
+  "username": "benchmarkdbuser",
+  "password": "benchmarkdbpass",
+  "database": "hello_world",
+  "maxPoolSize": 64
+}

+ 403 - 0
frameworks/Java/vertx/src/main/java/vertx/App.java

@@ -0,0 +1,403 @@
+package vertx;
+
+import com.julienviet.pgclient.PgBatch;
+import com.julienviet.pgclient.PgClient;
+import com.julienviet.pgclient.PgClientOptions;
+import com.julienviet.pgclient.PgConnection;
+import com.julienviet.pgclient.PgConnectionPool;
+import com.julienviet.pgclient.PgPoolOptions;
+import com.julienviet.pgclient.PgPreparedStatement;
+import com.julienviet.pgclient.PoolingMode;
+import io.vertx.core.AbstractVerticle;
+import io.vertx.core.DeploymentOptions;
+import io.vertx.core.Future;
+import io.vertx.core.Handler;
+import io.vertx.core.MultiMap;
+import io.vertx.core.Vertx;
+import io.vertx.core.buffer.Buffer;
+import io.vertx.core.http.HttpHeaders;
+import io.vertx.core.http.HttpServer;
+import io.vertx.core.http.HttpServerOptions;
+import io.vertx.core.http.HttpServerRequest;
+import io.vertx.core.http.HttpServerResponse;
+import io.vertx.core.json.Json;
+import io.vertx.core.json.JsonArray;
+import io.vertx.core.json.JsonObject;
+import io.vertx.core.logging.Logger;
+import io.vertx.core.logging.LoggerFactory;
+import vertx.model.Fortune;
+import vertx.model.Message;
+import vertx.model.World;
+
+import java.io.File;
+import java.nio.file.Files;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.ThreadLocalRandom;
+
+public class App extends AbstractVerticle implements Handler<HttpServerRequest> {
+
+  /**
+   * Returns the value of the "queries" getRequest parameter, which is an integer
+   * bound between 1 and 500 with a default value of 1.
+   *
+   * @param request the current HTTP request
+   * @return the value of the "queries" parameter
+   */
+  static int getQueries(HttpServerRequest request) {
+    String param = request.getParam("queries");
+
+    if (param == null) {
+      return 1;
+    }
+    try {
+      int parsedValue = Integer.parseInt(param);
+      return Math.min(500, Math.max(1, parsedValue));
+    } catch (NumberFormatException e) {
+      return 1;
+    }
+  }
+
+  static Logger logger = LoggerFactory.getLogger(App.class.getName());
+
+  private static final String PATH_PLAINTEXT = "/plaintext";
+  private static final String PATH_JSON = "/json";
+  private static final String PATH_DB = "/db";
+  private static final String PATH_QUERIES = "/queries";
+  private static final String PATH_UPDATES = "/updates";
+  private static final String PATH_FORTUNES = "/fortunes";
+
+  private static final CharSequence RESPONSE_TYPE_PLAIN = HttpHeaders.createOptimized("text/plain");
+  private static final CharSequence RESPONSE_TYPE_HTML = HttpHeaders.createOptimized("text/html; charset=UTF-8");
+  private static final CharSequence RESPONSE_TYPE_JSON = HttpHeaders.createOptimized("application/json");
+
+  private static final String HELLO_WORLD = "Hello, world!";
+  private static final Buffer HELLO_WORLD_BUFFER = Buffer.buffer(HELLO_WORLD);
+
+  private static final CharSequence HEADER_SERVER = HttpHeaders.createOptimized("server");
+  private static final CharSequence HEADER_DATE = HttpHeaders.createOptimized("date");
+  private static final CharSequence HEADER_CONTENT_TYPE = HttpHeaders.createOptimized("content-type");
+  private static final CharSequence HEADER_CONTENT_LENGTH = HttpHeaders.createOptimized("content-length");
+
+  private static final CharSequence HELLO_WORLD_LENGTH = HttpHeaders.createOptimized("" + HELLO_WORLD.length());
+  private static final CharSequence SERVER = HttpHeaders.createOptimized("vert.x");
+
+  private static final String UPDATE_WORLD = "UPDATE world SET randomnumber=$1 WHERE id=$2";
+  private static final String SELECT_WORLD = "SELECT id, randomnumber from WORLD where id=$1";
+  private static final String SELECT_FORTUNE = "SELECT id, message from FORTUNE";
+
+  private CharSequence dateString;
+
+  private HttpServer server;
+
+  private PgClient client;
+  private PgConnectionPool pool;
+
+  @Override
+  public void start() throws Exception {
+    int port = 8080;
+    server = vertx.createHttpServer(new HttpServerOptions());
+    server.requestHandler(App.this).listen(port);
+    dateString = HttpHeaders.createOptimized(java.time.format.DateTimeFormatter.RFC_1123_DATE_TIME.format(java.time.ZonedDateTime.now()));
+    JsonObject config = config();
+    vertx.setPeriodic(1000, handler -> {
+      dateString = HttpHeaders.createOptimized(java.time.format.DateTimeFormatter.RFC_1123_DATE_TIME.format(java.time.ZonedDateTime.now()));
+    });
+    PgClientOptions options = new PgClientOptions();
+    options.setDatabase(config.getString("database"));
+    options.setHost(config.getString("host"));
+    options.setPort(config.getInteger("port", 5432));
+    options.setUsername(config.getString("username"));
+    options.setPassword(config.getString("password"));
+    options.setCachePreparedStatements(true);
+    client = PgClient.create(vertx, options);
+    pool = client.createPool(new PgPoolOptions().setMode(PoolingMode.STATEMENT));
+  }
+
+  @Override
+  public void handle(HttpServerRequest request) {
+    switch (request.path()) {
+      case PATH_PLAINTEXT:
+        handlePlainText(request);
+        break;
+      case PATH_JSON:
+        handleJson(request);
+        break;
+      case PATH_DB:
+        handleDb(request);
+        break;
+      case PATH_QUERIES:
+        new Queries().handle(request);
+        break;
+      case PATH_UPDATES:
+        new Update(request).handle();
+        break;
+      case PATH_FORTUNES:
+        handleFortunes(request);
+        break;
+      default:
+        request.response().setStatusCode(404);
+        request.response().end();
+        break;
+    }
+  }
+
+  @Override
+  public void stop() {
+    if (server != null) server.close();
+  }
+
+  private void handlePlainText(HttpServerRequest request) {
+    HttpServerResponse response = request.response();
+    MultiMap headers = response.headers();
+    headers
+        .add(HEADER_CONTENT_TYPE, RESPONSE_TYPE_PLAIN)
+        .add(HEADER_SERVER, SERVER)
+        .add(HEADER_DATE, dateString)
+        .add(HEADER_CONTENT_LENGTH, HELLO_WORLD_LENGTH);
+    response.end(HELLO_WORLD_BUFFER);
+  }
+
+  private void handleJson(HttpServerRequest request) {
+    HttpServerResponse response = request.response();
+    MultiMap headers = response.headers();
+    headers
+        .add(HEADER_CONTENT_TYPE, RESPONSE_TYPE_JSON)
+        .add(HEADER_SERVER, SERVER)
+        .add(HEADER_DATE, dateString);
+    response.end(new Message("Hello, World!").toBuffer());
+  }
+
+  /**
+   * Returns a random integer that is a suitable value for both the {@code id}
+   * and {@code randomNumber} properties of a world object.
+   *
+   * @return a random world number
+   */
+  private static int randomWorld() {
+    return 1 + ThreadLocalRandom.current().nextInt(10000);
+  }
+
+  private void handleDb(HttpServerRequest req) {
+    pool.getConnection(res -> {
+      if (res.succeeded()) {
+        handleDb(req, res.result());
+      } else {
+        logger.error(res.cause());
+        req.response().setStatusCode(500).end(res.cause().getMessage());
+      }
+    });
+  }
+
+  private void handleDb(HttpServerRequest req, PgConnection conn) {
+    PgPreparedStatement worldSelect = conn.prepare(SELECT_WORLD);
+    HttpServerResponse resp = req.response();
+    worldSelect.query(randomWorld()).execute(res -> {
+      conn.close();
+      if (res.succeeded()) {
+        List<JsonArray> resultSet = res.result().getResults();
+        if (resultSet.isEmpty()) {
+          resp.setStatusCode(404).end();
+          return;
+        }
+        JsonArray row = resultSet.get(0);
+        resp
+            .putHeader(HttpHeaders.SERVER, SERVER)
+            .putHeader(HttpHeaders.DATE, dateString)
+            .putHeader(HttpHeaders.CONTENT_TYPE, RESPONSE_TYPE_JSON)
+            .end(Json.encode(new World(row.getInteger(0), row.getInteger(1))));
+      } else {
+        logger.error(res.cause());
+        resp.setStatusCode(500).end(res.cause().getMessage());
+      }
+    });
+  }
+
+  class Queries {
+
+    boolean failed;
+    JsonArray worlds = new JsonArray();
+
+    private void handle(HttpServerRequest req) {
+      pool.getConnection(res -> {
+        if (res.succeeded()) {
+          handle(req, res.result());
+        } else {
+          logger.error(res.cause());
+          req.response().setStatusCode(500).end(res.cause().getMessage());
+        }
+      });
+    }
+
+    void handle(HttpServerRequest req, PgConnection conn) {
+      PgPreparedStatement worldSelect = conn.prepare(SELECT_WORLD);
+      HttpServerResponse resp = req.response();
+      final int queries = getQueries(req);
+      for (int i = 0; i < queries; i++) {
+        worldSelect.query(randomWorld()).execute(ar -> {
+          if (!failed) {
+            if (ar.failed()) {
+              conn.close();
+              failed = true;
+              resp.setStatusCode(500).end(ar.cause().getMessage());
+              return;
+            }
+
+            // we need a final reference
+            final JsonArray row = ar.result().getResults().get(0);
+            worlds.add(new JsonObject().put("id", "" + row.getInteger(0)).put("randomNumber", "" + row.getInteger(1)));
+
+            // stop condition
+            if (worlds.size() == queries) {
+              conn.close();
+              resp
+                  .putHeader(HttpHeaders.SERVER, SERVER)
+                  .putHeader(HttpHeaders.DATE, dateString)
+                  .putHeader(HttpHeaders.CONTENT_TYPE, RESPONSE_TYPE_JSON)
+                  .end(worlds.encode());
+            }
+          }
+        });
+      }
+    }
+
+  }
+
+  class Update {
+
+    final HttpServerRequest req;
+    boolean failed;
+    int queryCount;
+    final World[] worlds;
+
+    public Update(HttpServerRequest req) {
+      final int queries = getQueries(req);
+      this.req = req;
+      this.worlds = new World[queries];
+    }
+
+    private void handle() {
+      pool.getConnection(res -> {
+        if (res.succeeded()) {
+          handle(res.result());
+        } else {
+          logger.error(res.cause());
+          req.response().setStatusCode(500).end(res.cause().getMessage());
+        }
+      });
+    }
+
+    private void handle(PgConnection conn) {
+      PgPreparedStatement worldSelect = conn.prepare(SELECT_WORLD);
+      for (int i = 0; i < worlds.length; i++) {
+        int id = randomWorld();
+        int index = i;
+        worldSelect.query(id).execute(ar2 -> {
+          if (!failed) {
+            if (ar2.failed()) {
+              failed = true;
+              conn.close();
+              sendError(ar2.cause());
+              return;
+            }
+            worlds[index] = new World(ar2.result().getResults().get(0).getInteger(0), randomWorld());
+            if (++queryCount == worlds.length) {
+              handleUpdates(conn);
+            }
+          }
+        });
+      }
+    }
+
+    void handleUpdates(PgConnection conn) {
+      Arrays.sort(worlds);
+      PgPreparedStatement worldUpdate = conn.prepare(UPDATE_WORLD);
+      PgBatch batch = worldUpdate.batch();
+      JsonArray json = new JsonArray();
+      for (World world : worlds) {
+        batch.add(world.getRandomNumber(), world.getId());
+      }
+      batch.execute(ar3 -> {
+        conn.close();
+        if (ar3.failed()) {
+          sendError(ar3.cause());
+          return;
+        }
+        for (World world : worlds) {
+          json.add(new JsonObject().put("id", "" + world.getId()).put("randomNumber", "" + world.getRandomNumber()));
+        }
+        req.response()
+            .putHeader(HttpHeaders.SERVER, SERVER)
+            .putHeader(HttpHeaders.DATE, dateString)
+            .putHeader(HttpHeaders.CONTENT_TYPE, RESPONSE_TYPE_JSON)
+            .end(json.toBuffer());
+      });
+    }
+
+    void sendError(Throwable err) {
+      logger.error("", err);
+      req.response().setStatusCode(500).end(err.getMessage());
+    }
+  }
+
+  private void handleFortunes(HttpServerRequest req) {
+    pool.getConnection(res -> {
+      if (res.succeeded()) {
+        PgConnection conn = res.result();
+        handleFortunes(req, conn);
+      } else {
+        logger.error(res.cause());
+        req.response().setStatusCode(500).end(res.cause().getMessage());
+      }
+    });
+  }
+
+  private void handleFortunes(HttpServerRequest req, PgConnection conn) {
+    PgPreparedStatement fortuneSelect = conn.prepare(SELECT_FORTUNE);
+    fortuneSelect.query().execute(ar -> {
+      conn.close();
+      HttpServerResponse response = req.response();
+      if (ar.succeeded()) {
+        List<Fortune> fortunes = new ArrayList<>();
+        List<JsonArray> resultSet = ar.result().getResults();
+        if (resultSet == null || resultSet.size() == 0) {
+          response.setStatusCode(404).end("No results");
+          return;
+        }
+        for (JsonArray row : resultSet) {
+          fortunes.add(new Fortune(row.getInteger(0), row.getString(1)));
+        }
+        fortunes.add(new Fortune(0, "Additional fortune added at request time."));
+        Collections.sort(fortunes);
+        response
+            .putHeader(HttpHeaders.SERVER, SERVER)
+            .putHeader(HttpHeaders.DATE, dateString)
+            .putHeader(HttpHeaders.CONTENT_TYPE, RESPONSE_TYPE_HTML)
+            .end(FortunesTemplate.template(fortunes).render().toString());
+      } else {
+        Throwable err = ar.cause();
+        logger.error("", err);
+        response.setStatusCode(500).end(err.getMessage());
+      }
+    });
+  }
+
+  public static void main(String[] args) throws Exception {
+    JsonObject config = new JsonObject(new String(Files.readAllBytes(new File(args[0]).toPath())));
+    int procs = Runtime.getRuntime().availableProcessors();
+    Vertx vertx = Vertx.vertx();
+    vertx.exceptionHandler(err -> {
+      err.printStackTrace();
+    });
+    vertx.deployVerticle(App.class.getName(),
+        new DeploymentOptions().setInstances(procs * 2).setConfig(config), event -> {
+          if (event.succeeded()) {
+            logger.debug("Your Vert.x application is started!");
+          } else {
+            logger.error("Unable to start your application", event.cause());
+          }
+        });
+  }
+}

+ 0 - 101
frameworks/Java/vertx/src/main/java/vertx/WebServer.java

@@ -1,101 +0,0 @@
-package vertx;
-
-import io.netty.util.AsciiString;
-import io.vertx.core.AbstractVerticle;
-import io.vertx.core.DeploymentOptions;
-import io.vertx.core.Handler;
-import io.vertx.core.Vertx;
-import io.vertx.core.buffer.Buffer;
-import io.vertx.core.http.HttpServer;
-import io.vertx.core.http.HttpServerRequest;
-import io.vertx.core.json.Json;
-import io.vertx.core.logging.Logger;
-import io.vertx.core.logging.LoggerFactory;
-
-import java.util.Collections;
-
-import static io.vertx.core.http.HttpHeaders.*;
-
-public class WebServer extends AbstractVerticle implements Handler<HttpServerRequest> {
-
-	static Logger logger = LoggerFactory.getLogger(WebServer.class.getName());
-
-	private static final String PATH_PLAINTEXT = "/plaintext";
-	private static final String PATH_JSON = "/json";
-
-	private static final CharSequence RESPONSE_TYPE_PLAIN = new AsciiString("text/plain");
-	private static final CharSequence RESPONSE_TYPE_JSON = new AsciiString("application/json");
-
-	private static final String MESSAGE = "message";
-	private static final String HELLO_WORLD = "Hello, world!";
-
-	private static final Buffer HELLO_WORLD_BUFFER = Buffer.buffer(HELLO_WORLD);
-	private static final CharSequence HELLO_WORLD_CONTENT_LENGTH = new AsciiString(String.valueOf(HELLO_WORLD.length()));
-
-	private static final CharSequence VERTX = new AsciiString("vertx".toCharArray());
-
-	private CharSequence dateString;
-
-	private HttpServer server;
-
-	@Override
-	public void start() {
-
-		int port = 8080;
-
-		server = vertx.createHttpServer();
-
-		server.requestHandler(WebServer.this).listen(port);
-
-		dateString = new AsciiString(java.time.format.DateTimeFormatter.RFC_1123_DATE_TIME.format(java.time.ZonedDateTime.now()).getBytes());
-
-		vertx.setPeriodic(1000, handler -> {
-			dateString = java.time.format.DateTimeFormatter.RFC_1123_DATE_TIME.format(java.time.ZonedDateTime.now());
-		});
-	}
-
-	@Override
-	public void handle(HttpServerRequest request) {
-		switch (request.path()) {
-		case PATH_PLAINTEXT:
-			handlePlainText(request);
-			break;
-		case PATH_JSON:
-			handleJson(request);
-			break;
-		default:
-			request.response().setStatusCode(404);
-			request.response().end();
-		}
-	}
-
-	@Override
-	public void stop(){
-		if ( server != null ) server.close();        
-	}
-
-	private void handlePlainText(HttpServerRequest request) {
-		request.response()
-		.putHeader(CONTENT_TYPE , RESPONSE_TYPE_PLAIN).putHeader(SERVER, VERTX)
-		.putHeader(DATE, dateString).putHeader(CONTENT_LENGTH, HELLO_WORLD_CONTENT_LENGTH).end(HELLO_WORLD_BUFFER);
-	}
-
-	private void handleJson(HttpServerRequest request) {
-	  Buffer buff = Buffer.buffer(Json.encode(Collections.singletonMap(MESSAGE, HELLO_WORLD)));
-		request.response().putHeader(CONTENT_TYPE, RESPONSE_TYPE_JSON).putHeader(SERVER,  VERTX)
-		.putHeader(DATE, dateString).end(buff);
-	}
-	
-	public static void main(String[] args) {
-		int procs = Runtime.getRuntime().availableProcessors();
-		Vertx vertx = Vertx.vertx();
-		vertx.deployVerticle(WebServer.class.getName(), 
-				new DeploymentOptions().setInstances(procs*2), event -> {
-					if (event.succeeded()) {
-						logger.debug("Your Vert.x application is started!");
-					} else {
-						logger.error("Unable to start your application", event.cause());
-					}
-				});
-	}
-}

+ 42 - 0
frameworks/Java/vertx/src/main/java/vertx/model/Fortune.java

@@ -0,0 +1,42 @@
+package vertx.model;
+
+import io.vertx.core.json.JsonObject;
+
+import java.util.Collections;
+
+/**
+ * The model for the "fortune" database table.
+ */
+public final class Fortune extends JsonObject implements Comparable<Fortune> {
+
+  private static final String ID = "id";
+  private static final String MESSAGE = "message";
+
+  /**
+   * Constructs a new fortune object with the given parameters.
+   *
+   * @param id the ID of the fortune
+   * @param message the message of the fortune
+   */
+  public Fortune(int id, String message) {
+    put(ID, id);
+    put(MESSAGE, message);
+  }
+
+  public Fortune(JsonObject doc) {
+    super(doc == null ? Collections.emptyMap() : doc.getMap());
+  }
+
+  public int getId() {
+    return getInteger(ID);
+  }
+
+  public String getMessage() {
+    return getString(MESSAGE);
+  }
+
+  @Override
+  public int compareTo(Fortune other) {
+    return getMessage().compareTo(other.getMessage());
+  }
+}

+ 16 - 0
frameworks/Java/vertx/src/main/java/vertx/model/Message.java

@@ -0,0 +1,16 @@
+package vertx.model;
+
+import io.vertx.core.json.JsonObject;
+
+public class Message extends JsonObject {
+
+  private static final String MESSAGE = "message";
+
+  public Message(String message) {
+    put(MESSAGE, message);
+  }
+
+  public String getMessage() {
+    return getString(MESSAGE);
+  }
+}

+ 34 - 0
frameworks/Java/vertx/src/main/java/vertx/model/World.java

@@ -0,0 +1,34 @@
+package vertx.model;
+
+/**
+ * The model for the "world" database table.
+ */
+public final class World implements Comparable<World> {
+
+  private final int id;
+  private final int randomNumber;
+
+  /**
+   * Constructs a new world object with the given parameters.
+   *
+   * @param id the ID of the world
+   * @param randomNumber the random number of the world
+   */
+  public World(int id, int randomNumber) {
+    this.id = id;
+    this.randomNumber = randomNumber;
+  }
+
+  public int getId() {
+    return id;
+  }
+
+  public int getRandomNumber() {
+    return randomNumber;
+  }
+
+  @Override
+  public int compareTo(World o) {
+    return Integer.compare(id, o.id);
+  }
+}

+ 65 - 0
frameworks/Java/vertx/src/main/resources/create-postgres.sql

@@ -0,0 +1,65 @@
+
+DROP TABLE IF EXISTS World;
+CREATE TABLE  World (
+  id integer NOT NULL,
+  randomNumber integer NOT NULL default 0,
+  PRIMARY KEY  (id)
+);
+GRANT SELECT, UPDATE ON World to benchmarkdbuser;
+
+INSERT INTO World (id, randomnumber)
+SELECT x.id, random() * 10000 + 1 FROM generate_series(1,10000) as x(id);
+
+DROP TABLE IF EXISTS Fortune;
+CREATE TABLE Fortune (
+  id integer NOT NULL,
+  message varchar(2048) NOT NULL,
+  PRIMARY KEY  (id)
+);
+GRANT SELECT ON Fortune to benchmarkdbuser;
+
+INSERT INTO Fortune (id, message) VALUES (1, 'fortune: No such file or directory');
+INSERT INTO Fortune (id, message) VALUES (2, 'A computer scientist is someone who fixes things that aren''t broken.');
+INSERT INTO Fortune (id, message) VALUES (3, 'After enough decimal places, nobody gives a damn.');
+INSERT INTO Fortune (id, message) VALUES (4, 'A bad random number generator: 1, 1, 1, 1, 1, 4.33e+67, 1, 1, 1');
+INSERT INTO Fortune (id, message) VALUES (5, 'A computer program does what you tell it to do, not what you want it to do.');
+INSERT INTO Fortune (id, message) VALUES (6, 'Emacs is a nice operating system, but I prefer UNIX. — Tom Christaensen');
+INSERT INTO Fortune (id, message) VALUES (7, 'Any program that runs right is obsolete.');
+INSERT INTO Fortune (id, message) VALUES (8, 'A list is only as strong as its weakest link. — Donald Knuth');
+INSERT INTO Fortune (id, message) VALUES (9, 'Feature: A bug with seniority.');
+INSERT INTO Fortune (id, message) VALUES (10, 'Computers make very fast, very accurate mistakes.');
+INSERT INTO Fortune (id, message) VALUES (11, '<script>alert("This should not be displayed in a browser alert box.");</script>');
+INSERT INTO Fortune (id, message) VALUES (12, 'フレームワークのベンチマーク');
+
+
+DROP TABLE IF EXISTS "World";
+CREATE TABLE  "World" (
+  id integer NOT NULL,
+  randomNumber integer NOT NULL default 0,
+  PRIMARY KEY  (id)
+);
+GRANT SELECT, UPDATE ON "World" to benchmarkdbuser;
+
+INSERT INTO "World" (id, randomnumber)
+SELECT x.id, random() * 10000 + 1 FROM generate_series(1,10000) as x(id);
+
+DROP TABLE IF EXISTS "Fortune";
+CREATE TABLE "Fortune" (
+  id integer NOT NULL,
+  message varchar(2048) NOT NULL,
+  PRIMARY KEY  (id)
+);
+GRANT SELECT ON "Fortune" to benchmarkdbuser;
+
+INSERT INTO "Fortune" (id, message) VALUES (1, 'fortune: No such file or directory');
+INSERT INTO "Fortune" (id, message) VALUES (2, 'A computer scientist is someone who fixes things that aren''t broken.');
+INSERT INTO "Fortune" (id, message) VALUES (3, 'After enough decimal places, nobody gives a damn.');
+INSERT INTO "Fortune" (id, message) VALUES (4, 'A bad random number generator: 1, 1, 1, 1, 1, 4.33e+67, 1, 1, 1');
+INSERT INTO "Fortune" (id, message) VALUES (5, 'A computer program does what you tell it to do, not what you want it to do.');
+INSERT INTO "Fortune" (id, message) VALUES (6, 'Emacs is a nice operating system, but I prefer UNIX. — Tom Christaensen');
+INSERT INTO "Fortune" (id, message) VALUES (7, 'Any program that runs right is obsolete.');
+INSERT INTO "Fortune" (id, message) VALUES (8, 'A list is only as strong as its weakest link. — Donald Knuth');
+INSERT INTO "Fortune" (id, message) VALUES (9, 'Feature: A bug with seniority.');
+INSERT INTO "Fortune" (id, message) VALUES (10, 'Computers make very fast, very accurate mistakes.');
+INSERT INTO "Fortune" (id, message) VALUES (11, '<script>alert("This should not be displayed in a browser alert box.");</script>');
+INSERT INTO "Fortune" (id, message) VALUES (12, 'フレームワークのベンチマーク');

+ 18 - 0
frameworks/Java/vertx/src/main/templates/vertx/FortunesTemplate.rocker.html

@@ -0,0 +1,18 @@
+@import vertx.model.Fortune
+@import java.util.List
+@args(List<Fortune> fortunes)
+<!DOCTYPE html>
+<html>
+<head><title>Fortunes</title></head>
+<body>
+<table>
+  <tr>
+    <th>id</th>
+    <th>message</th>
+  </tr> @for (fortune : fortunes) {
+  <tr>
+    <td>@fortune.getId()</td>
+    <td>@fortune.getMessage()</td>
+  </tr> } </table>
+</body>
+</html>