Server.java 5.9 KB

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