Server.java 5.6 KB

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