Server.java 5.8 KB

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