Server.java 5.5 KB

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