Przeglądaj źródła

jooby: upgrade to 4.0 (#10008)

- major dependencies upgrade
Edgar Espina 1 miesiąc temu
rodzic
commit
08de5e8402

+ 6 - 26
frameworks/Java/jooby/pom.xml

@@ -11,8 +11,7 @@
   <name>jooby</name>
 
   <properties>
-    <jooby.version>3.4.0</jooby.version>
-    <netty.version>4.1.113.Final</netty.version>
+    <jooby.version>4.0.2</jooby.version>
     <dsl-json.version>2.0.2</dsl-json.version>
     <postgresql.version>42.7.7</postgresql.version>
     <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
@@ -38,13 +37,6 @@
       <version>${jooby.version}</version>
     </dependency>
 
-    <!-- mySQL -->
-    <dependency>
-      <groupId>com.mysql</groupId>
-      <artifactId>mysql-connector-j</artifactId>
-      <version>8.4.0</version>
-    </dependency>
-
     <!-- postgresql -->
     <dependency>
       <groupId>org.postgresql</groupId>
@@ -55,7 +47,7 @@
     <dependency>
       <groupId>io.vertx</groupId>
       <artifactId>vertx-pg-client</artifactId>
-      <version>4.5.7</version>
+      <version>5.0.1</version>
     </dependency>
 
     <!-- json -->
@@ -72,7 +64,7 @@
       <plugin>
         <groupId>org.codehaus.mojo</groupId>
         <artifactId>build-helper-maven-plugin</artifactId>
-        <version>3.6.0</version>
+        <version>3.6.1</version>
         <executions>
           <execution>
             <id>add-source</id>
@@ -91,7 +83,7 @@
       <plugin>
         <groupId>com.fizzed</groupId>
         <artifactId>rocker-maven-plugin</artifactId>
-        <version>1.4.0</version>
+        <version>2.2.1</version>
         <executions>
           <execution>
             <id>generate-rocker-templates</id>
@@ -110,7 +102,7 @@
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-compiler-plugin</artifactId>
-        <version>3.13.0</version>
+        <version>3.14.0</version>
         <configuration>
           <annotationProcessorPaths>
             <path>
@@ -174,14 +166,10 @@
         </os>
       </activation>
       <dependencies>
-        <dependency>
-          <groupId>com.ongres.scram</groupId>
-          <artifactId>client</artifactId>
-          <version>2.1</version>
-        </dependency>
         <dependency>
           <groupId>io.netty</groupId>
           <artifactId>netty-resolver-dns-native-macos</artifactId>
+          <classifier>osx-aarch_64</classifier>
         </dependency>
       </dependencies>
     </profile>
@@ -221,14 +209,6 @@
 
   <dependencyManagement>
     <dependencies>
-      <dependency>
-        <groupId>io.netty</groupId>
-        <artifactId>netty-bom</artifactId>
-        <version>${netty.version}</version>
-        <type>pom</type>
-        <scope>import</scope>
-      </dependency>
-
       <dependency>
         <groupId>io.jooby</groupId>
         <artifactId>jooby-bom</artifactId>

+ 6 - 3
frameworks/Java/jooby/src/main/java/com/techempower/App.java

@@ -1,5 +1,6 @@
 package com.techempower;
 
+import static com.techempower.Util.boxedRandomWorld;
 import static com.techempower.Util.randomWorld;
 import static io.jooby.ExecutionMode.EVENT_LOOP;
 import static io.jooby.MediaType.JSON;
@@ -29,7 +30,6 @@ public class App extends Jooby {
   private static final byte[] MESSAGE_BYTES = MESSAGE.getBytes(StandardCharsets.US_ASCII);
 
   {
-    var bufferFactory = getBufferFactory();
     /** Database: */
     install(new HikariModule());
     DataSource ds = require(DataSource.class);
@@ -37,8 +37,11 @@ public class App extends Jooby {
     /** Template engine: */
     install(new RockerModule());
 
+    var outputFactory = getOutputFactory();
+    Json.configure(outputFactory);
+    var message = outputFactory.wrap(MESSAGE_BYTES);
     get("/plaintext", ctx ->
-        ctx.send(bufferFactory.wrap(MESSAGE_BYTES))
+        ctx.send(message)
     );
 
     get("/json", ctx -> ctx
@@ -99,7 +102,7 @@ public class App extends Jooby {
               statement.setInt(1, randomWorld());
               try (ResultSet rs = statement.executeQuery()) {
                 rs.next();
-                result[i] = new World(rs.getInt("id"), randomWorld());
+                result[i] = new World(rs.getInt("id"), boxedRandomWorld());
               }
               // prepare update query
               updateSql.add("(?, ?)");

+ 15 - 8
frameworks/Java/jooby/src/main/java/com/techempower/Json.java

@@ -6,6 +6,8 @@ import java.util.List;
 import com.dslplatform.json.DslJson;
 import com.dslplatform.json.JsonWriter;
 import com.dslplatform.json.runtime.Settings;
+import io.jooby.output.Output;
+import io.jooby.output.OutputFactory;
 
 public class Json {
   private final static DslJson<Object> dslJson = new DslJson<>(Settings.basicSetup());
@@ -15,36 +17,41 @@ public class Json {
       return dslJson.newWriter(1024);
     }
   };
+  private static OutputFactory outputFactory;
 
-  public static ByteBuffer encode(Message data) {
+  public static void configure(OutputFactory outputFactory) {
+    Json.outputFactory =outputFactory.getContextFactory();
+  }
+
+  public static Output encode(Message data) {
     JsonWriter writer = pool.get();
     writer.reset();
     var converter = new _Message_DslJsonConverter.ObjectFormatConverter(dslJson);
     converter.write(writer, data);
-    return ByteBuffer.wrap(writer.getByteBuffer(), 0, writer.size());
+    return outputFactory.wrap(writer.getByteBuffer(), 0, writer.size());
   }
 
-  public static ByteBuffer encode(World data) {
+  public static Output encode(World data) {
     JsonWriter writer = pool.get();
     writer.reset();
     var converter = new _World_DslJsonConverter.ObjectFormatConverter(dslJson);
     converter.write(writer, data);
-    return ByteBuffer.wrap(writer.getByteBuffer(), 0, writer.size());
+    return outputFactory.wrap(writer.getByteBuffer(), 0, writer.size());
   }
 
-  public static ByteBuffer encode(World[] data) {
+  public static Output encode(World[] data) {
     JsonWriter writer = pool.get();
     writer.reset();
     var converter = new _World_DslJsonConverter.ObjectFormatConverter(dslJson);
     writer.serialize(data, converter);
-    return ByteBuffer.wrap(writer.getByteBuffer(), 0, writer.size());
+    return outputFactory.wrap(writer.getByteBuffer(), 0, writer.size());
   }
 
-  public static ByteBuffer encode(List<World> data) {
+  public static Output encode(List<World> data) {
     JsonWriter writer = pool.get();
     writer.reset();
     var converter = new _World_DslJsonConverter.ObjectFormatConverter(dslJson);
     writer.serialize(data, converter);
-    return ByteBuffer.wrap(writer.getByteBuffer(), 0, writer.size());
+    return outputFactory.wrap(writer.getByteBuffer(), 0, writer.size());
   }
 }

+ 3 - 1
frameworks/Java/jooby/src/main/java/com/techempower/MvcApp.java

@@ -17,7 +17,9 @@ public class MvcApp {
       /** Template engine: */
       app.install(new RockerModule());
 
-      app.mvc(new Resource_(app.require(DataSource.class)));
+      Json.configure(app.getOutputFactory());
+
+      app.mvc(new Resource_(app.require(DataSource.class), app.getOutputFactory()));
     });
   }
 }

+ 44 - 34
frameworks/Java/jooby/src/main/java/com/techempower/PgClient.java

@@ -40,7 +40,45 @@ public class PgClient {
     private PreparedQuery<RowSet<Row>> UPDATE_WORLD_QUERY;
     private SqlClientInternal updates;
     @SuppressWarnings("unchecked")
-    private PreparedQuery<RowSet<Row>>[] AGGREGATED_UPDATE_WORLD_QUERY = new PreparedQuery[128];
+    private PreparedQuery<RowSet<Row>>[] AGGREGATED_UPDATE_WORLD_QUERY = new PreparedQuery[500];
+  }
+
+  public static class PgUpdate {
+      private DbConnection connection;
+
+    public PgUpdate(DbConnection connection) {
+      this.connection = connection;
+    }
+
+    public void selectWorldForUpdate(int queries, BiConsumer<Integer, PreparedQuery<RowSet<Row>>> consumer) {
+      connection.queries.group(c -> {
+        PreparedQuery<RowSet<Row>> statement = c.preparedQuery(SELECT_WORLD);
+        for (int i = 0; i < queries; i++) {
+          consumer.accept(i, statement);
+        }
+      });
+    }
+
+    public void updateWorld(World[] worlds, Handler<AsyncResult<RowSet<Row>>> handler) {
+      Arrays.sort(worlds);
+      int len = worlds.length;
+      if (0 < len && len <= connection.AGGREGATED_UPDATE_WORLD_QUERY.length) {
+        List<Object> arguments = new ArrayList<>();
+        for (World world : worlds) {
+          arguments.add(world.getId());
+          arguments.add(world.getRandomNumber());
+        }
+        Tuple tuple = Tuple.tuple(arguments);
+        PreparedQuery<RowSet<Row>> query = connection.AGGREGATED_UPDATE_WORLD_QUERY[len - 1];
+        query.execute(tuple).onComplete(handler);
+      } else {
+        List<Tuple> batch = new ArrayList<>();
+        for (World world : worlds) {
+          batch.add(Tuple.of(world.getRandomNumber(), world.getId()));
+        }
+        connection.UPDATE_WORLD_QUERY.executeBatch(batch).onComplete(handler);
+      }
+    }
   }
 
   private static class DbConnectionFactory extends ThreadLocal<DbConnection> {
@@ -129,51 +167,23 @@ public class PgClient {
   }
 
   public void selectWorld(Tuple row, Handler<AsyncResult<RowSet<Row>>> handler) {
-    this.sqlClient.get().SELECT_WORLD_QUERY.execute(row, handler);
+    this.sqlClient.get().SELECT_WORLD_QUERY.execute(row).onComplete(handler);
   }
 
   public void selectWorlds(int queries, Handler<AsyncResult<RowSet<Row>>> handler) {
     this.sqlClient.get().queries.group(c -> {
       for (int i = 0; i < queries; i++) {
-        c.preparedQuery(SELECT_WORLD).execute(Tuple.of(Util.randomWorld()), handler);
+        c.preparedQuery(SELECT_WORLD).execute(Tuple.of(Util.boxedRandomWorld())).onComplete(handler);
       }
     });
   }
 
   public void fortunes(Handler<AsyncResult<RowSet<Row>>> handler) {
-    this.sqlClient.get().SELECT_FORTUNE_QUERY.execute(handler);
-  }
-
-  public void selectWorldForUpdate(int queries,
-      BiConsumer<Integer, PreparedQuery<RowSet<Row>>> consumer) {
-    this.sqlClient.get().queries.group(c -> {
-      PreparedQuery<RowSet<Row>> statement = c.preparedQuery(SELECT_WORLD);
-      for (int i = 0; i < queries; i++) {
-        consumer.accept(i, statement);
-      }
-    });
+    this.sqlClient.get().SELECT_FORTUNE_QUERY.execute().onComplete(handler);
   }
 
-  public void updateWorld(World[] worlds, Handler<AsyncResult<RowSet<Row>>> handler) {
-    Arrays.sort(worlds);
-    int len = worlds.length;
-    var connection = this.sqlClient.get();
-    if (0 < len && len <= connection.AGGREGATED_UPDATE_WORLD_QUERY.length) {
-      List<Object> arguments = new ArrayList<>();
-      for (World world : worlds) {
-        arguments.add(world.getId());
-        arguments.add(world.getRandomNumber());
-      }
-      Tuple tuple = Tuple.tuple(arguments);
-      PreparedQuery<RowSet<Row>> query = connection.AGGREGATED_UPDATE_WORLD_QUERY[len - 1];
-      query.execute(tuple, handler);
-    } else {
-      List<Tuple> batch = new ArrayList<>();
-      for (World world : worlds) {
-        batch.add(Tuple.of(world.getRandomNumber(), world.getId()));
-      }
-      connection.UPDATE_WORLD_QUERY.executeBatch(batch, handler);
-    }
+  public PgUpdate updater() {
+    return new PgUpdate(sqlClient.get());
   }
 
   private PgConnectOptions pgPoolOptions(Config config) {

+ 16 - 26
frameworks/Java/jooby/src/main/java/com/techempower/ReactivePg.java

@@ -1,15 +1,13 @@
 package com.techempower;
 
+import static com.techempower.Util.boxedRandomWorld;
 import static com.techempower.Util.randomWorld;
 import static io.jooby.ExecutionMode.EVENT_LOOP;
 import static io.jooby.MediaType.JSON;
 
 import java.util.*;
 
-import com.fizzed.rocker.RockerOutputFactory;
-import com.techempower.rocker.BufferRockerOutput;
 import io.jooby.*;
-import io.jooby.rocker.DataBufferOutput;
 import io.jooby.rocker.RockerModule;
 import io.vertx.sqlclient.Row;
 import io.vertx.sqlclient.RowIterator;
@@ -17,22 +15,16 @@ import io.vertx.sqlclient.Tuple;
 
 public class ReactivePg extends Jooby {
   {
-    /** Reduce the number of resources due we do reactive processing. */
-    setServerOptions(
-        new ServerOptions()
-            .setIoThreads(Runtime.getRuntime().availableProcessors() + 1)
-            .setWorkerThreads(Runtime.getRuntime().availableProcessors() + 1)
-    );
-
     /** PG client: */
     PgClient client = new PgClient(getConfig().getConfig("db"));
 
     /** Template engine: */
     install(new RockerModule());
+    Json.configure(getOutputFactory());
 
     /** Single query: */
     get("/db", ctx -> {
-      client.selectWorld(Tuple.of(randomWorld()), rsp -> {
+      client.selectWorld(Tuple.of(boxedRandomWorld()), rsp -> {
         if (rsp.succeeded()) {
           RowIterator<Row> rs = rsp.result().iterator();
           Row row = rs.next();
@@ -43,7 +35,7 @@ public class ReactivePg extends Jooby {
         }
       });
       return ctx;
-    }).setNonBlocking(true);
+    });
 
     /** Multiple queries: */
     get("/queries", ctx -> {
@@ -64,24 +56,24 @@ public class ReactivePg extends Jooby {
         }
       });
       return ctx;
-    }).setNonBlocking(true);
+    });
 
     /** Update queries: */
     get("/updates", ctx -> {
       int queries = Util.queries(ctx);
       World[] result = new World[queries];
-      client.selectWorldForUpdate(queries, (index, statement) -> {
-        int id = randomWorld();
-        statement.execute(Tuple.of(id), selectCallback -> {
-          if (selectCallback.failed()) {
-            sendError(ctx, selectCallback.cause());
+      var updater = client.updater();
+      updater.selectWorldForUpdate(queries, (index, statement) -> {
+        statement.execute(Tuple.of(boxedRandomWorld())).onComplete(rsp -> {
+          if (rsp.failed()) {
+            sendError(ctx, rsp.cause());
             return;
           }
           result[index] = new World(
-              selectCallback.result().iterator().next().getInteger(0),
-              randomWorld());
+              rsp.result().iterator().next().getInteger(0),
+              boxedRandomWorld());
           if (index == queries - 1) {
-            client.updateWorld(result, updateCallback -> {
+            updater.updateWorld(result, updateCallback -> {
               if (updateCallback.failed()) {
                 sendError(ctx, updateCallback.cause());
               } else {
@@ -93,10 +85,9 @@ public class ReactivePg extends Jooby {
         });
       });
       return ctx;
-    }).setNonBlocking(true);
+    });
 
     /** Fortunes: */
-    var factory = BufferRockerOutput.factory();
     get("/fortunes", ctx -> {
       client.fortunes(rsp -> {
         if (rsp.succeeded()) {
@@ -112,15 +103,14 @@ public class ReactivePg extends Jooby {
           Collections.sort(fortunes);
 
           /** render view: */
-          views.fortunes template = views.fortunes.template(fortunes);
           ctx.setResponseType(MediaType.html)
-              .send(template.render(factory).toBuffer());
+                  .render(views.fortunes.template(fortunes));
         } else {
           sendError(ctx, rsp.cause());
         }
       });
       return ctx;
-    }).setNonBlocking(true);
+    });
   }
 
   private void sendError(Context ctx, Throwable cause) {

+ 6 - 2
frameworks/Java/jooby/src/main/java/com/techempower/Resource.java

@@ -4,6 +4,8 @@ import io.jooby.Context;
 import io.jooby.annotation.GET;
 import io.jooby.annotation.Path;
 import io.jooby.annotation.Dispatch;
+import io.jooby.output.Output;
+import io.jooby.output.OutputFactory;
 import views.fortunes;
 
 import javax.sql.DataSource;
@@ -28,14 +30,16 @@ public class Resource {
   private static final byte[] MESSAGE_BYTES = MESSAGE.getBytes(StandardCharsets.UTF_8);
 
   private final DataSource dataSource;
+  private final Output message;
 
-  public Resource(DataSource dataSource) {
+  public Resource(DataSource dataSource, OutputFactory factory) {
     this.dataSource = dataSource;
+    this.message = factory.wrap(MESSAGE_BYTES);
   }
 
   @GET @Path("/plaintext")
   public void plaintText(Context ctx) {
-    ctx.send(MESSAGE_BYTES);
+    ctx.send(message);
   }
 
   @GET @Path("/json")

+ 8 - 1
frameworks/Java/jooby/src/main/java/com/techempower/Util.java

@@ -1,11 +1,13 @@
 package com.techempower;
 
 import io.jooby.Context;
-import io.jooby.Value;
+import io.jooby.value.Value;
 
 import java.util.concurrent.ThreadLocalRandom;
+import java.util.stream.IntStream;
 
 public class Util {
+  private static final Integer[] BOXED_RND = IntStream.range(1, 10001).boxed().toArray(Integer[]::new);
 
   public static int queries(Context ctx) {
     try {
@@ -21,4 +23,9 @@ public class Util {
   public static int randomWorld() {
     return 1 + ThreadLocalRandom.current().nextInt(10000);
   }
+
+  public static int boxedRandomWorld() {
+    final int rndValue = ThreadLocalRandom.current().nextInt(1, 10001);
+    return BOXED_RND[rndValue - 1];
+  }
 }

+ 3 - 3
frameworks/Java/jooby/src/main/java/com/techempower/World.java

@@ -7,9 +7,9 @@ public class World implements Comparable<World> {
 
   private int id;
 
-  private int randomNumber;
+  private Integer randomNumber;
 
-  public World(int id, int randomNumber) {
+  public World(int id, Integer randomNumber) {
     this.id = id;
     this.randomNumber = randomNumber;
   }
@@ -18,7 +18,7 @@ public class World implements Comparable<World> {
     return id;
   }
 
-  public int getRandomNumber() {
+  public Integer getRandomNumber() {
     return randomNumber;
   }
 

+ 0 - 65
frameworks/Java/jooby/src/main/java/com/techempower/rocker/BufferRockerOutput.java

@@ -1,65 +0,0 @@
-package com.techempower.rocker;
-
-import com.fizzed.rocker.ContentType;
-import com.fizzed.rocker.RockerOutput;
-import com.fizzed.rocker.RockerOutputFactory;
-
-import java.io.IOException;
-import java.nio.Buffer;
-import java.nio.ByteBuffer;
-import java.nio.charset.Charset;
-import java.nio.charset.StandardCharsets;
-
-public class BufferRockerOutput implements RockerOutput<BufferRockerOutput> {
-    private final ByteBuffer buffer;
-
-    public BufferRockerOutput(ByteBuffer buffer) {
-        this.buffer = buffer;
-    }
-
-    @Override
-    public ContentType getContentType() {
-        return ContentType.RAW;
-    }
-
-    @Override
-    public Charset getCharset() {
-        return StandardCharsets.UTF_8;
-    }
-
-    @Override
-    public BufferRockerOutput w(String string) throws IOException {
-        buffer.put(string.getBytes(getCharset()));
-        return this;
-    }
-
-    @Override
-    public BufferRockerOutput w(byte[] bytes) throws IOException {
-        buffer.put(bytes);
-        return this;
-    }
-
-    @Override
-    public int getByteLength() {
-        return buffer.remaining();
-    }
-
-    public ByteBuffer toBuffer() {
-        return buffer.flip();
-    }
-
-    public static RockerOutputFactory<BufferRockerOutput> factory() {
-        var cache = new ThreadLocal<BufferRockerOutput>() {
-            @Override
-            protected BufferRockerOutput initialValue() {
-                return new BufferRockerOutput(ByteBuffer.allocateDirect(2048));
-            }
-        };
-        return (contentType, charsetName) -> cache.get().reset();
-    }
-
-    private BufferRockerOutput reset() {
-        buffer.clear();
-        return this;
-    }
-}

+ 3 - 3
frameworks/Kotlin/kooby/benchmark_config.json

@@ -14,15 +14,15 @@
       "framework": "kooby: jooby+kotlin",
       "language": "Kotlin",
       "flavor": "None",
-      "platform": "Undertow",
+      "platform": "Netty",
       "database": "Postgres",
       "database_os": "Linux",
       "orm": "Raw",
       "webserver": "None",
       "os": "Linux",
-      "notes": "Jooby with Kotlin and Undertow",
+      "notes": "Jooby with Kotlin and Netty",
       "display_name": "kooby",
-      "versus": "undertow"
+      "versus": "netty"
     }
   }]
 }

+ 2 - 2
frameworks/Kotlin/kooby/config.toml

@@ -14,6 +14,6 @@ database = "Postgres"
 database_os = "Linux"
 os = "Linux"
 orm = "Raw"
-platform = "Undertow"
+platform = "Netty"
 webserver = "None"
-versus = "undertow"
+versus = "netty"

+ 4 - 12
frameworks/Kotlin/kooby/pom.xml

@@ -12,12 +12,12 @@
   <name>kooby: jooby+kotlin</name>
 
   <properties>
-    <jooby.version>3.3.0</jooby.version>
+    <jooby.version>4.0.2</jooby.version>
     <postgresql.version>42.7.7</postgresql.version>
     <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
     <maven.compiler.source>22</maven.compiler.source>
     <maven.compiler.target>22</maven.compiler.target>
-    <kotlin.version>2.0.20</kotlin.version>
+    <kotlin.version>2.2.0</kotlin.version>
 
     <!-- Startup class -->
     <application.class>kooby.AppKt</application.class>
@@ -47,14 +47,6 @@
       <artifactId>jooby-rocker</artifactId>
     </dependency>
 
-    <!-- mySQL -->
-    <!-- mySQL -->
-    <dependency>
-      <groupId>com.mysql</groupId>
-      <artifactId>mysql-connector-j</artifactId>
-      <version>9.0.0</version>
-    </dependency>
-
     <!-- postgresql -->
     <dependency>
       <groupId>org.postgresql</groupId>
@@ -77,7 +69,7 @@
       <plugin>
         <groupId>com.fizzed</groupId>
         <artifactId>rocker-maven-plugin</artifactId>
-        <version>1.4.0</version>
+        <version>2.2.1</version>
         <executions>
           <execution>
             <id>generate-rocker-templates</id>
@@ -127,7 +119,7 @@
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-compiler-plugin</artifactId>
-        <version>3.13.0</version>
+        <version>3.14.0</version>
         <executions>
           <!-- Replacing default-compile as it is treated specially by maven -->
           <execution>

+ 3 - 2
frameworks/Kotlin/kooby/src/main/kotlin/kooby/App.kt

@@ -43,8 +43,9 @@ fun main(args: Array<String>) {
     install(HikariModule())
     val ds = require(DataSource::class)
 
+    val message = outputFactory.wrap(MESSAGE_BYTES);
     get("/plaintext") {
-      ctx.send(MESSAGE_BYTES)
+      ctx.send(message)
     }
 
     get("/json") {
@@ -158,6 +159,6 @@ private fun nextRandom(rnd: Random): Int {
 
 fun Context.queries() = try {
   this.query("queries").intValue(1).coerceIn(1, 500)
-} catch (x: BadRequestException) {
+} catch (_: BadRequestException) {
   1
 }