Server.java 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. package benchmarks;
  2. import java.io.ByteArrayOutputStream;
  3. import java.io.IOException;
  4. import java.net.InetSocketAddress;
  5. import java.sql.Connection;
  6. import java.sql.PreparedStatement;
  7. import java.sql.ResultSet;
  8. import java.sql.SQLException;
  9. import java.text.ParseException;
  10. import java.util.ArrayList;
  11. import java.util.Collections;
  12. import java.util.HashMap;
  13. import java.util.List;
  14. import java.util.Map;
  15. import java.util.Properties;
  16. import java.util.concurrent.Executors;
  17. import javax.sql.DataSource;
  18. import com.fasterxml.jackson.databind.ObjectMapper;
  19. import com.fasterxml.jackson.module.afterburner.AfterburnerModule;
  20. import com.sun.net.httpserver.HttpHandler;
  21. import com.sun.net.httpserver.HttpServer;
  22. import com.zaxxer.hikari.HikariConfig;
  23. import com.zaxxer.hikari.HikariDataSource;
  24. import httl.Engine;
  25. import httl.Template;
  26. public class Server {
  27. private static final String HELLO_TEXT = "Hello, World!";
  28. private static final byte[] HELLO_BYTES = HELLO_TEXT.getBytes();
  29. private static final int HELLO_LENGTH = HELLO_BYTES.length;
  30. private static final String SERVER_NAME = "httpserver";
  31. private static final ObjectMapper MAPPER = new ObjectMapper();
  32. static {
  33. MAPPER.registerModule(new AfterburnerModule());
  34. }
  35. private static List<Fortune> queryFortunes(DataSource ds) throws SQLException {
  36. List<Fortune> fortunes = new ArrayList<>();
  37. try (Connection conn = ds.getConnection();
  38. PreparedStatement statement = conn.prepareStatement("SELECT id, message FROM fortune");
  39. ResultSet resultSet = statement.executeQuery()) {
  40. while (resultSet.next())
  41. fortunes.add(new Fortune(resultSet.getInt(1), resultSet.getString(2)));
  42. }
  43. return fortunes;
  44. }
  45. private static DataSource createPostgresDataSource() {
  46. HikariConfig config = new HikariConfig();
  47. config.setJdbcUrl("jdbc:postgresql://tfb-database:5432/hello_world");
  48. config.setUsername("benchmarkdbuser");
  49. config.setPassword("benchmarkdbpass");
  50. config.setMaximumPoolSize(64);
  51. config.setMinimumIdle(0);
  52. config.setConnectionTimeout(1000);
  53. config.setIdleTimeout(15000);
  54. config.setMaxLifetime(60000);
  55. config.setAutoCommit(true);
  56. config.setPoolName("PostgreSQL-HikariCP-Pool");
  57. return new HikariDataSource(config);
  58. }
  59. private static Template loadTemplate() throws IOException, ParseException {
  60. Properties props = new Properties();
  61. props.put("import.packages", "java.util," + Fortune.class.getPackage().getName());
  62. props.put("input.encoding", "UTF-8");
  63. props.put("output.encoding", "UTF-8");
  64. props.put("precompiled", "false");
  65. Engine engine = Engine.getEngine(props);
  66. return engine.getTemplate("/fortunes.template.httl");
  67. }
  68. private static HttpHandler createPlaintextHandler() {
  69. return t -> {
  70. t.getResponseHeaders().add("Content-Type", "text/plain");
  71. t.getResponseHeaders().add("Server", SERVER_NAME);
  72. t.sendResponseHeaders(200, HELLO_LENGTH);
  73. t.getResponseBody().write(HELLO_BYTES);
  74. t.getResponseBody().close();
  75. };
  76. }
  77. private static HttpHandler createJSONHandler() {
  78. return t -> {
  79. // serialize message to JSON
  80. Message msg = new Message(HELLO_TEXT);
  81. byte[] bytes;
  82. try {
  83. bytes = MAPPER.writeValueAsBytes(msg);
  84. } catch (Exception e) {
  85. throw new RuntimeException(e);
  86. }
  87. // send response
  88. t.getResponseHeaders().add("Content-Type", "application/json");
  89. t.getResponseHeaders().add("Server", SERVER_NAME);
  90. t.sendResponseHeaders(200, bytes.length);
  91. t.getResponseBody().write(bytes);
  92. t.getResponseBody().flush();
  93. t.getResponseBody().close();
  94. };
  95. }
  96. private static HttpHandler createFortunesHandler(DataSource ds) throws IOException, ParseException {
  97. Template template = loadTemplate();
  98. return t -> {
  99. try {
  100. // query db
  101. List<Fortune> fortunes = queryFortunes(ds);
  102. fortunes.add(new Fortune(0, "Additional fortune added at request time."));
  103. Collections.sort(fortunes);
  104. // render template
  105. Map<String, Object> context = new HashMap<>(1);
  106. context.put("fortunes", fortunes);
  107. ByteArrayOutputStream out = new ByteArrayOutputStream();
  108. template.render(context, out);
  109. byte[] bytes = out.toByteArray();
  110. // send response
  111. t.getResponseHeaders().add("Content-Type", "text/html; charset=utf-8");
  112. t.getResponseHeaders().add("Server", SERVER_NAME);
  113. t.sendResponseHeaders(200, bytes.length);
  114. t.getResponseBody().write(bytes);
  115. t.getResponseBody().close();
  116. } catch (SQLException | ParseException e) {
  117. throw new IOException(e);
  118. }
  119. };
  120. }
  121. static void main(String[] args) throws Exception {
  122. // parse arguments
  123. String settings = args.length > 0 ? args[0] : "";
  124. int port = args.length > 1 ? Integer.parseInt(args[1]) : 8080;
  125. if (settings.contains("debug"))
  126. System.setProperty("org.slf4j.simpleLogger.defaultLogLevel", "DEBUG");
  127. // create server
  128. HttpServer server = HttpServer.create(new InetSocketAddress(port), 1024 * 8);
  129. server.setExecutor(Executors.newVirtualThreadPerTaskExecutor());
  130. server.createContext("/plaintext", createPlaintextHandler());
  131. server.createContext("/json", createJSONHandler());
  132. if (settings.contains("postgres")) {
  133. DataSource ds = createPostgresDataSource();
  134. server.createContext("/fortunes", createFortunesHandler(ds));
  135. }
  136. // start server
  137. server.start();
  138. }
  139. }