Implement Eclipse Jetty core HTTP handler adapter
This provides an implementation of an HTTP Handler Adapter that is coded directly to the Eclipse Jetty core API, bypassing any servlet implementation. This includes a Jetty implementation of the spring `WebSocketClient` interface, `JettyWebSocketClient`, using an explicit dependency to the jetty-websocket-api. Closes gh-32097 Co-authored-by: Lachlan Roberts <lachlan@webtide.com> Co-authored-by: Arjen Poutsma <arjen.poutsma@broadcom.com>
This commit is contained in:
@@ -126,6 +126,7 @@ public abstract class AbstractHttpHandlerIntegrationTests {
|
||||
static Stream<Named<HttpServer>> httpServers() {
|
||||
return Stream.of(
|
||||
named("Jetty", new JettyHttpServer()),
|
||||
named("Jetty Core", new JettyCoreHttpServer()),
|
||||
named("Reactor Netty", new ReactorHttpServer()),
|
||||
named("Tomcat", new TomcatHttpServer()),
|
||||
named("Undertow", new UndertowHttpServer())
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.web.testfixture.http.server.reactive.bootstrap;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.eclipse.jetty.io.ArrayByteBufferPool;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.ServerConnector;
|
||||
import org.eclipse.jetty.websocket.server.ServerWebSocketContainer;
|
||||
|
||||
import org.springframework.http.server.reactive.JettyCoreHttpHandlerAdapter;
|
||||
|
||||
/**
|
||||
* @author Rossen Stoyanchev
|
||||
* @author Sam Brannen
|
||||
* @author Greg Wilkins
|
||||
* @since 6.2
|
||||
*/
|
||||
public class JettyCoreHttpServer extends AbstractHttpServer {
|
||||
|
||||
protected Log logger = LogFactory.getLog(getClass().getName());
|
||||
|
||||
private ArrayByteBufferPool byteBufferPool;
|
||||
|
||||
private Server jettyServer;
|
||||
|
||||
@Override
|
||||
protected void initServer() {
|
||||
if (logger.isTraceEnabled())
|
||||
this.byteBufferPool = new ArrayByteBufferPool.Tracking();
|
||||
this.jettyServer = new Server(null, null, byteBufferPool);
|
||||
|
||||
ServerConnector connector = new ServerConnector(this.jettyServer);
|
||||
connector.setHost(getHost());
|
||||
connector.setPort(getPort());
|
||||
this.jettyServer.addConnector(connector);
|
||||
this.jettyServer.setHandler(createHandlerAdapter());
|
||||
|
||||
ServerWebSocketContainer.ensure(jettyServer);
|
||||
}
|
||||
|
||||
private JettyCoreHttpHandlerAdapter createHandlerAdapter() {
|
||||
return new JettyCoreHttpHandlerAdapter(resolveHttpHandler());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void startInternal() throws Exception {
|
||||
this.jettyServer.start();
|
||||
setPort(((ServerConnector) this.jettyServer.getConnectors()[0]).getLocalPort());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void stopInternal() {
|
||||
boolean wasRunning = this.jettyServer.isRunning();
|
||||
try {
|
||||
this.jettyServer.stop();
|
||||
}
|
||||
catch (Exception ex) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
// TODO remove this or make debug only
|
||||
if (wasRunning && this.byteBufferPool instanceof ArrayByteBufferPool.Tracking tracking) {
|
||||
if (!tracking.getLeaks().isEmpty()) {
|
||||
System.err.println("Leaks:\n" + tracking.dumpLeaks());
|
||||
throw new IllegalStateException("LEAKS");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void resetInternal() {
|
||||
try {
|
||||
if (this.jettyServer.isRunning()) {
|
||||
stopInternal();
|
||||
}
|
||||
this.jettyServer.destroy();
|
||||
}
|
||||
finally {
|
||||
this.jettyServer = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -54,7 +54,6 @@ public class JettyHttpServer extends AbstractHttpServer {
|
||||
connector.setPort(getPort());
|
||||
this.jettyServer.addConnector(connector);
|
||||
this.jettyServer.setHandler(this.contextHandler);
|
||||
this.contextHandler.start();
|
||||
}
|
||||
|
||||
private ServletHttpHandlerAdapter createServletAdapter() {
|
||||
@@ -70,24 +69,10 @@ public class JettyHttpServer extends AbstractHttpServer {
|
||||
@Override
|
||||
protected void stopInternal() throws Exception {
|
||||
try {
|
||||
if (this.contextHandler.isRunning()) {
|
||||
this.contextHandler.stop();
|
||||
}
|
||||
this.jettyServer.stop();
|
||||
}
|
||||
finally {
|
||||
try {
|
||||
if (this.jettyServer.isRunning()) {
|
||||
// Do not configure a large stop timeout. For example, setting a stop timeout
|
||||
// of 5000 adds an additional 1-2 seconds to the runtime of each test using
|
||||
// the Jetty sever, resulting in 2-4 extra minutes of overall build time.
|
||||
this.jettyServer.setStopTimeout(100);
|
||||
this.jettyServer.stop();
|
||||
this.jettyServer.destroy();
|
||||
}
|
||||
}
|
||||
catch (Exception ex) {
|
||||
// ignore
|
||||
}
|
||||
catch (Exception ex) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,18 +80,14 @@ public class JettyHttpServer extends AbstractHttpServer {
|
||||
protected void resetInternal() {
|
||||
try {
|
||||
if (this.jettyServer.isRunning()) {
|
||||
// Do not configure a large stop timeout. For example, setting a stop timeout
|
||||
// of 5000 adds an additional 1-2 seconds to the runtime of each test using
|
||||
// the Jetty sever, resulting in 2-4 extra minutes of overall build time.
|
||||
this.jettyServer.setStopTimeout(100);
|
||||
this.jettyServer.stop();
|
||||
this.jettyServer.destroy();
|
||||
}
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
finally {
|
||||
this.jettyServer.destroy();
|
||||
this.jettyServer = null;
|
||||
this.contextHandler = null;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user