diff --git a/pom.xml b/pom.xml index d1acba3fc8..8dea2c6d55 100644 --- a/pom.xml +++ b/pom.xml @@ -2195,7 +2195,7 @@ 1.19.3 ${jersey1.version} 1.3.7 - 1.10.2 + 1.35 1.44 5.6.0 4.0.2 diff --git a/tests/performance/benchmarks/pom.xml b/tests/performance/benchmarks/pom.xml index 07cbc44237..1c7567964d 100644 --- a/tests/performance/benchmarks/pom.xml +++ b/tests/performance/benchmarks/pom.xml @@ -46,6 +46,14 @@ org.glassfish.jersey.media jersey-media-json-jackson + + org.glassfish.jersey.media + jersey-media-jaxb + + + com.sun.xml.bind + jaxb-osgi + org.glassfish.jersey.ext jersey-entity-filtering @@ -58,6 +66,10 @@ org.glassfish.jersey.connectors jersey-grizzly-connector + + org.glassfish.jersey.connectors + jersey-jnh-connector + jakarta.annotation jakarta.annotation-api diff --git a/tests/performance/benchmarks/src/main/java/org/glassfish/jersey/tests/performance/benchmark/JNHConnectorBenchmark.java b/tests/performance/benchmarks/src/main/java/org/glassfish/jersey/tests/performance/benchmark/JNHConnectorBenchmark.java new file mode 100644 index 0000000000..42e212f10b --- /dev/null +++ b/tests/performance/benchmarks/src/main/java/org/glassfish/jersey/tests/performance/benchmark/JNHConnectorBenchmark.java @@ -0,0 +1,235 @@ +/* + * Copyright (c) 2022 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package org.glassfish.jersey.tests.performance.benchmark; + +import jakarta.ws.rs.client.Client; +import jakarta.ws.rs.client.ClientBuilder; +import jakarta.ws.rs.client.Entity; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.StreamingOutput; +import org.glassfish.grizzly.http.server.HttpServer; +import org.glassfish.grizzly.nio.transport.TCPNIOTransport; +import org.glassfish.grizzly.threadpool.ThreadPoolConfig; +import org.glassfish.jersey.client.ClientConfig; +import org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory; +import org.glassfish.jersey.jackson.JacksonFeature; +import org.glassfish.jersey.jnh.connector.JavaNetHttpConnectorProvider; +import org.glassfish.jersey.tests.performance.benchmark.server.jnh.Book; +import org.glassfish.jersey.tests.performance.benchmark.server.jnh.BookShelfApplication; +import org.glassfish.jersey.tests.performance.benchmark.server.jnh.BookShelfResource; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.TearDown; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.runner.Runner; +import org.openjdk.jmh.runner.options.Options; +import org.openjdk.jmh.runner.options.OptionsBuilder; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.util.List; +import java.util.concurrent.TimeUnit; + +/** + * jersey-jnh-connector {@link org.glassfish.jersey.jnh.connector.JavaNetHttpConnector} benchmark. + * + */ +@BenchmarkMode(Mode.Throughput) +@OutputTimeUnit(TimeUnit.SECONDS) +@Warmup(iterations = 1, time = 1) +@Measurement(iterations = 16, time = 1) +@Fork(1) +@State(Scope.Benchmark) +public class JNHConnectorBenchmark { + + private static final URI BASE_URI = URI.create("http://localhost:8080/"); + + private static final String REQUEST_TARGET = "HttpMethod"; + private volatile HttpServer server; + + private volatile Client client; + private volatile Client defaultClient; + + private final Book postBook = new Book("The Bonfire of the Vanities", "Tom Wolfe", 11); + private final Book postDefaultBook = new Book("More Die of Heartbreak", "Saul Bellow", 22); + private final Book putBook = new Book("Silmarillion", "J. R. R. Tolkien", 110); + private final Book putDefaultBook = new Book("The Lord of the Rings", "John Tolkien", 220); + + @Setup + public void start() throws Exception { + server = + GrizzlyHttpServerFactory.createHttpServer(BASE_URI, new BookShelfApplication(), false); + final TCPNIOTransport transport = server.getListener("grizzly").getTransport(); + transport.setSelectorRunnersCount(4); + transport.setWorkerThreadPoolConfig(ThreadPoolConfig.defaultConfig().setCorePoolSize(8).setMaxPoolSize(8)); + + server.start(); + client = ClientBuilder.newClient( + new ClientConfig() + .connectorProvider(new JavaNetHttpConnectorProvider()) + .register(JacksonFeature.class) + ); + defaultClient = ClientBuilder.newClient( + new ClientConfig() + .register(JacksonFeature.class) + ); + + } + + @Setup(Level.Iteration) + public void request() { + } + + @TearDown + public void shutdown() { + server.shutdownNow(); + } + + @Benchmark + public void measureGetStringResource() { + client.target(BASE_URI).path(REQUEST_TARGET).request(MediaType.TEXT_PLAIN).get(String.class); + } + + @Benchmark + public void measureGetStringDefaultResource() { + defaultClient.target(BASE_URI).path(REQUEST_TARGET).request(MediaType.TEXT_PLAIN).get(String.class); + } + + @Benchmark + public void measureEntityGetResource() { + client.target(BASE_URI).path(REQUEST_TARGET).path("books") + .request(MediaType.APPLICATION_JSON_TYPE).get(); + } + @Benchmark + public void measureEntityGetXmlResource() throws IOException { + final InputStream stream = client.target(BASE_URI).path(REQUEST_TARGET).path("books") + .request(MediaType.APPLICATION_XML_TYPE).get(InputStream.class); + try { + System.out.print(new String(stream.readAllBytes()).charAt(0)); + } finally { + stream.close(); + } + } + + @Benchmark + public void measureEntityGetOneXmlResource() throws IOException { + final Book book = client.target(BASE_URI).path(REQUEST_TARGET).path("book") + .request(MediaType.APPLICATION_XML_TYPE).get(Book.class); + System.out.print(book.getId()); + } + @Benchmark + public void measureEntityGetDefaultResource() { + defaultClient.target(BASE_URI).path(REQUEST_TARGET).path("books") + .request(MediaType.APPLICATION_JSON_TYPE).get(); + } + + @Benchmark + public void measureEntityGetXmlDefaultResource() throws IOException { + final InputStream stream = defaultClient.target(BASE_URI).path(REQUEST_TARGET).path("books") + .request(MediaType.APPLICATION_XML_TYPE).get(InputStream.class); + try { + System.out.print(new String(stream.readAllBytes()).charAt(0)); + } finally { + stream.close(); + } + } + @Benchmark + public void measureEntityGetOneXmlDefaultResource() { + final Book book = defaultClient.target(BASE_URI).path(REQUEST_TARGET).path("book") + .request(MediaType.APPLICATION_XML_TYPE).get(Book.class); + System.out.print(book.getId()); + } + + @Benchmark + public void measurePost() { + client.target(BASE_URI).path(REQUEST_TARGET).path("postBook") + .request().post(Entity.json(postBook)); + } + + @Benchmark + public void measurePostDefault() { + defaultClient.target(BASE_URI).path(REQUEST_TARGET).path("postBook") + .request().post(Entity.json(postDefaultBook)); + } + + @Benchmark + public void measureBigPost() { + client.target(BASE_URI).path(REQUEST_TARGET).path("postBooks") + .request().post(Entity.entity(convertLongEntity(BookShelfResource.bookList), MediaType.TEXT_PLAIN_TYPE)); + } + + @Benchmark + public void measureBigPostDefault() { + defaultClient.target(BASE_URI).path(REQUEST_TARGET).path("postBooks") + .request().post(Entity.entity(convertLongEntity(BookShelfResource.bookList), MediaType.TEXT_PLAIN_TYPE)); + } + + private static final StreamingOutput convertLongEntity(List books) { + return out -> { + int offset = 0; + while (offset < books.size()) { + out.write(books.get(offset).toByteArray()); + out.write('\n'); + offset++; + } + }; + } + + + @Benchmark + public void measurePut() { + client.target(BASE_URI).path(REQUEST_TARGET).path("putBook") + .request().put(Entity.json(putBook)); + } + + @Benchmark + public void measurePutDefault() { + defaultClient.target(BASE_URI).path(REQUEST_TARGET).path("putBook") + .request().put(Entity.json(putDefaultBook)); + } + + @Benchmark + public void measureDelete() { + client.target(BASE_URI).path(REQUEST_TARGET).path("deleteBook") + .request().delete(); + } + + @Benchmark + public void measureDeleteDefault() { + defaultClient.target(BASE_URI).path(REQUEST_TARGET).path("deleteBook") + .request().delete(); + } + + + public static void main(final String[] args) throws Exception { + final Options opt = new OptionsBuilder() + // Register our benchmarks. + .include(JNHConnectorBenchmark.class.getSimpleName()) + .build(); + + new Runner(opt).run(); + } +} \ No newline at end of file diff --git a/tests/performance/benchmarks/src/main/java/org/glassfish/jersey/tests/performance/benchmark/server/jnh/Book.java b/tests/performance/benchmarks/src/main/java/org/glassfish/jersey/tests/performance/benchmark/server/jnh/Book.java new file mode 100644 index 0000000000..93e1d39de6 --- /dev/null +++ b/tests/performance/benchmarks/src/main/java/org/glassfish/jersey/tests/performance/benchmark/server/jnh/Book.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2022 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package org.glassfish.jersey.tests.performance.benchmark.server.jnh; + +import jakarta.xml.bind.annotation.XmlRootElement; + +@XmlRootElement +public class Book { + + private String title; + private String author; + private int id; + + + public Book(String title, String author, int id) { + this.title = title; + this.author = author; + this.id = id; + } + + public Book() { + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getAuthor() { + return author; + } + + public void setAuthor(String author) { + this.author = author; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public byte[] toByteArray() { + return String.format("%s, %s, %d", title, author, id).getBytes(); + } +} diff --git a/tests/performance/benchmarks/src/main/java/org/glassfish/jersey/tests/performance/benchmark/server/jnh/BookShelfApplication.java b/tests/performance/benchmarks/src/main/java/org/glassfish/jersey/tests/performance/benchmark/server/jnh/BookShelfApplication.java new file mode 100644 index 0000000000..d5569d0460 --- /dev/null +++ b/tests/performance/benchmarks/src/main/java/org/glassfish/jersey/tests/performance/benchmark/server/jnh/BookShelfApplication.java @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2022 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package org.glassfish.jersey.tests.performance.benchmark.server.jnh; + +import org.glassfish.jersey.server.ResourceConfig; + +public class BookShelfApplication extends ResourceConfig { + public BookShelfApplication() { + register(BookShelfResource.class); + } +} diff --git a/tests/performance/benchmarks/src/main/java/org/glassfish/jersey/tests/performance/benchmark/server/jnh/BookShelfResource.java b/tests/performance/benchmarks/src/main/java/org/glassfish/jersey/tests/performance/benchmark/server/jnh/BookShelfResource.java new file mode 100644 index 0000000000..03f6c4402d --- /dev/null +++ b/tests/performance/benchmarks/src/main/java/org/glassfish/jersey/tests/performance/benchmark/server/jnh/BookShelfResource.java @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2022 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package org.glassfish.jersey.tests.performance.benchmark.server.jnh; + +import jakarta.ws.rs.DELETE; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.PUT; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; +import org.glassfish.grizzly.http.util.HttpStatus; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +@Path("HttpMethod") +public class BookShelfResource { + + private static final int BOOK_LIST_SIZE = 1000; + + public static final List bookList = generateBooks(); + + @GET + @Produces(MediaType.TEXT_PLAIN) + public String getStatus() { + return HttpStatus.OK_200.getReasonPhrase(); + } + + @GET + @Produces({MediaType.APPLICATION_XML, MediaType.TEXT_XML, MediaType.APPLICATION_JSON}) + @Path("books") + public List getBooks() { + return bookList; + } + + @GET + @Produces({MediaType.APPLICATION_XML, MediaType.TEXT_XML, MediaType.APPLICATION_JSON}) + @Path("book") + public Book getBook() { + return new Book("1", "2", 3); + } + + @POST + @Path("postBook") + public void postBook(Book book) { + /*System.out.println(String.format("Just got a book by: %s, which is called: %s, giving it an id: %d", + book.getAuthor(), + book.getTitle(), + book.getId()));*/ + } + @POST + @Path("postBooks") + public Response postBooks(InputStream data) throws IOException { + final BufferedReader reader = new BufferedReader(new InputStreamReader(data)); + long linesReceived = reader.lines().count(); + reader.close(); + return linesReceived == bookList.size() ? Response.ok().build() : Response.serverError().build(); + } + + @PUT + @Path("putBook") + public void putBook(Book book) { + /*System.out.println(String.format("A book by: %s, with name: %s, is putted back under the id: %d", + book.getAuthor(), + book.getTitle(), + book.getId()));*/ + } + + @DELETE + @Path("deleteBook") + @Produces(MediaType.TEXT_PLAIN) + public String deleteBook() { + return "HttpStatus.OK_200"; + + } + + private static final List generateBooks() { + final List books = new ArrayList<>(); + for (int i = 0; i < BOOK_LIST_SIZE; i++) { + books.add(new Book("Title: " + i, "Author: " + i, i)); + } + return Collections.unmodifiableList(books); + } +}