HelloWebServer.java 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. package hello;
  2. import com.fasterxml.jackson.databind.ObjectMapper;
  3. import com.github.mustachejava.DefaultMustacheFactory;
  4. import com.github.mustachejava.MustacheFactory;
  5. import com.google.common.cache.CacheBuilder;
  6. import com.google.common.cache.CacheLoader;
  7. import com.google.common.cache.LoadingCache;
  8. import com.mongodb.DB;
  9. import com.mongodb.MongoClient;
  10. import io.undertow.Handlers;
  11. import io.undertow.Undertow;
  12. import io.undertow.util.Headers;
  13. import javax.sql.DataSource;
  14. import java.io.IOException;
  15. import java.io.InputStream;
  16. import java.sql.Connection;
  17. import java.sql.PreparedStatement;
  18. import java.sql.ResultSet;
  19. import java.sql.SQLException;
  20. import java.util.Properties;
  21. /**
  22. * An implementation of the TechEmpower benchmark tests using the Undertow web
  23. * server. The only test that truly exercises Undertow in isolation is the
  24. * plaintext test. For the rest, it uses best-of-breed components that are
  25. * expected to perform well. The idea is that using these components enables
  26. * these tests to serve as performance baselines for hypothetical, Undertow-based
  27. * frameworks. For instance, it is unlikely that such frameworks would complete
  28. * the JSON test faster than this will, because this implementation uses
  29. * Undertow and Jackson in the most direct way possible to fulfill the test
  30. * requirements.
  31. */
  32. public final class HelloWebServer {
  33. public static void main(String[] args) throws Exception {
  34. new HelloWebServer();
  35. }
  36. /**
  37. * Creates and starts a new web server whose configuration is specified in the
  38. * {@code server.properties} file.
  39. *
  40. * @throws IOException if the application properties file cannot be read or
  41. * the Mongo database hostname cannot be resolved
  42. * @throws SQLException if reading from the SQL database (while priming the
  43. * cache) fails
  44. */
  45. public HelloWebServer() throws IOException, SQLException {
  46. Properties properties = new Properties();
  47. try (InputStream in = HelloWebServer.class.getResourceAsStream(
  48. "server.properties")) {
  49. properties.load(in);
  50. }
  51. final ObjectMapper objectMapper = new ObjectMapper();
  52. final MustacheFactory mustacheFactory = new DefaultMustacheFactory();
  53. final DataSource mysql = Helper.newDataSource(
  54. properties.getProperty("mysql.uri"),
  55. properties.getProperty("mysql.user"),
  56. properties.getProperty("mysql.password"));
  57. final DataSource postgresql = Helper.newDataSource(
  58. properties.getProperty("postgresql.uri"),
  59. properties.getProperty("postgresql.user"),
  60. properties.getProperty("postgresql.password"));
  61. final DB mongodb = new MongoClient(properties.getProperty("mongodb.host"))
  62. .getDB(properties.getProperty("mongodb.name"));
  63. //
  64. // The world cache is primed at startup with all values. It doesn't
  65. // matter which database backs it; they all contain the same information
  66. // and the CacheLoader.load implementation below is never invoked.
  67. //
  68. final LoadingCache<Integer, World> worldCache = CacheBuilder.newBuilder()
  69. .build(new CacheLoader<Integer, World>() {
  70. @Override
  71. public World load(Integer id) throws Exception {
  72. try (Connection connection = mysql.getConnection();
  73. PreparedStatement statement = connection.prepareStatement(
  74. "SELECT * FROM World WHERE id = ?",
  75. ResultSet.TYPE_FORWARD_ONLY,
  76. ResultSet.CONCUR_READ_ONLY)) {
  77. statement.setInt(1, id);
  78. try (ResultSet resultSet = statement.executeQuery()) {
  79. resultSet.next();
  80. return new World(
  81. resultSet.getInt("id"),
  82. resultSet.getInt("randomNumber"));
  83. }
  84. }
  85. }
  86. });
  87. try (Connection connection = mysql.getConnection();
  88. PreparedStatement statement = connection.prepareStatement(
  89. "SELECT * FROM World",
  90. ResultSet.TYPE_FORWARD_ONLY,
  91. ResultSet.CONCUR_READ_ONLY);
  92. ResultSet resultSet = statement.executeQuery()) {
  93. while (resultSet.next()) {
  94. World world = new World(
  95. resultSet.getInt("id"),
  96. resultSet.getInt("randomNumber"));
  97. worldCache.put(world.id, world);
  98. }
  99. }
  100. Undertow.builder()
  101. .addListener(
  102. Integer.parseInt(properties.getProperty("web.port")),
  103. properties.getProperty("web.host"))
  104. .setBufferSize(1024 * 16)
  105. .setHandler(Handlers.date(Handlers.header(Handlers.path()
  106. .addPath("/json",
  107. new JsonHandler(objectMapper))
  108. .addPath("/db/mysql",
  109. new DbSqlHandler(objectMapper, mysql))
  110. .addPath("/db/postgresql",
  111. new DbSqlHandler(objectMapper, postgresql))
  112. .addPath("/db/mongodb",
  113. new DbMongoHandler(objectMapper, mongodb))
  114. .addPath("/fortunes/mysql",
  115. new FortunesSqlHandler(mustacheFactory, mysql))
  116. .addPath("/fortunes/postgresql",
  117. new FortunesSqlHandler(mustacheFactory, postgresql))
  118. .addPath("/fortunes/mongodb",
  119. new FortunesMongoHandler(mustacheFactory, mongodb))
  120. .addPath("/updates/mysql",
  121. new UpdatesSqlHandler(objectMapper, mysql))
  122. .addPath("/updates/postgresql",
  123. new UpdatesSqlHandler(objectMapper, postgresql))
  124. .addPath("/updates/mongodb",
  125. new UpdatesMongoHandler(objectMapper, mongodb))
  126. .addPath("/plaintext",
  127. new PlaintextHandler())
  128. .addPath("/cache",
  129. new CacheHandler(objectMapper, worldCache)),
  130. Headers.SERVER_STRING, "undertow")))
  131. .build()
  132. .start();
  133. }
  134. }