diff --git a/jetty-ant/src/main/java/org/eclipse/jetty/ant/AntWebAppContext.java b/jetty-ant/src/main/java/org/eclipse/jetty/ant/AntWebAppContext.java index e46b30941f1..ba71267a162 100644 --- a/jetty-ant/src/main/java/org/eclipse/jetty/ant/AntWebAppContext.java +++ b/jetty-ant/src/main/java/org/eclipse/jetty/ant/AntWebAppContext.java @@ -27,7 +27,6 @@ import java.security.CodeSource; import java.security.PermissionCollection; import java.util.ArrayList; import java.util.Enumeration; -import java.util.EventListener; import java.util.HashSet; import java.util.Iterator; import java.util.List; @@ -615,9 +614,9 @@ public class AntWebAppContext extends WebAppContext TaskLog.logWithTimestamp("Stopping web application " + this); Thread.currentThread().sleep(500L); super.doStop(); - //remove all filters, servlets and listeners. They will be recreated - //either via application of a context xml file or web.xml or annotation or servlet api - setEventListeners(new EventListener[0]); + // remove all filters and servlets. They will be recreated + // either via application of a context xml file or web.xml or annotation or servlet api. + // Event listeners are reset in ContextHandler.doStop() getServletHandler().setFilters(new FilterHolder[0]); getServletHandler().setFilterMappings(new FilterMapping[0]); getServletHandler().setServlets(new ServletHolder[0]); diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTP.java b/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTP.java index 8043261e130..c289ab5a481 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTP.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTP.java @@ -22,6 +22,7 @@ import java.io.EOFException; import java.nio.ByteBuffer; import org.eclipse.jetty.client.HttpClient; +import org.eclipse.jetty.client.HttpClientTransport; import org.eclipse.jetty.client.HttpExchange; import org.eclipse.jetty.client.HttpReceiver; import org.eclipse.jetty.client.HttpResponse; @@ -50,8 +51,13 @@ public class HttpReceiverOverHTTP extends HttpReceiver implements HttpParser.Res super(channel); HttpClient httpClient = channel.getHttpDestination().getHttpClient(); parser = new HttpParser(this, -1, httpClient.getHttpCompliance()); - parser.setHeaderCacheSize(((HttpClientTransportOverHTTP)httpClient.getTransport()).getHeaderCacheSize()); - parser.setHeaderCacheCaseSensitive(((HttpClientTransportOverHTTP)httpClient.getTransport()).isHeaderCacheCaseSensitive()); + HttpClientTransport transport = httpClient.getTransport(); + if (transport instanceof HttpClientTransportOverHTTP) + { + HttpClientTransportOverHTTP httpTransport = (HttpClientTransportOverHTTP)transport; + parser.setHeaderCacheSize(httpTransport.getHeaderCacheSize()); + parser.setHeaderCacheCaseSensitive(httpTransport.isHeaderCacheCaseSensitive()); + } } @Override diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/jmx/HttpClientJMXTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/jmx/HttpClientJMXTest.java index c5d254cc3c3..c852d304b29 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/jmx/HttpClientJMXTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/jmx/HttpClientJMXTest.java @@ -39,7 +39,6 @@ public class HttpClientJMXTest String name = "foo"; HttpClient httpClient = new HttpClient(); httpClient.setName(name); - httpClient.start(); try { @@ -47,6 +46,7 @@ public class HttpClientJMXTest MBeanContainer mbeanContainer = new MBeanContainer(mbeanServer); // Adding MBeanContainer as a bean will trigger the registration of MBeans. httpClient.addBean(mbeanContainer); + httpClient.start(); String domain = HttpClient.class.getPackage().getName(); ObjectName pattern = new ObjectName(domain + ":type=" + HttpClient.class.getSimpleName().toLowerCase(Locale.ENGLISH) + ",*"); diff --git a/jetty-home/src/main/resources/etc/jetty-setuid.xml b/jetty-home/src/main/resources/etc/jetty-setuid.xml index 2fd25150b6c..3f2bff2f06b 100644 --- a/jetty-home/src/main/resources/etc/jetty-setuid.xml +++ b/jetty-home/src/main/resources/etc/jetty-setuid.xml @@ -6,7 +6,7 @@ - + diff --git a/jetty-home/src/main/resources/etc/jetty-started.xml b/jetty-home/src/main/resources/etc/jetty-started.xml index b8d6007fbcd..11a2e151795 100644 --- a/jetty-home/src/main/resources/etc/jetty-started.xml +++ b/jetty-home/src/main/resources/etc/jetty-started.xml @@ -5,7 +5,7 @@ - + diff --git a/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientConnectionFactory.java b/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientConnectionFactory.java index bede2c57125..626388eb846 100644 --- a/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientConnectionFactory.java +++ b/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientConnectionFactory.java @@ -73,7 +73,7 @@ public class HTTP2ClientConnectionFactory implements ClientConnectionFactory final HTTP2ClientConnection connection = new HTTP2ClientConnection(client, byteBufferPool, executor, endPoint, parser, session, client.getInputBufferSize(), promise, listener); - connection.addListener(connectionListener); + connection.addEventListener(connectionListener); return customize(connection, context); } diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/AbstractHTTP2ServerConnectionFactory.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/AbstractHTTP2ServerConnectionFactory.java index d8ff0c3ee62..cccd7c6f16f 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/AbstractHTTP2ServerConnectionFactory.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/AbstractHTTP2ServerConnectionFactory.java @@ -261,7 +261,7 @@ public abstract class AbstractHTTP2ServerConnectionFactory extends AbstractConne endPoint, httpConfiguration, parser, session, getInputBufferSize(), listener); connection.setUseInputDirectByteBuffers(isUseInputDirectByteBuffers()); connection.setUseOutputDirectByteBuffers(isUseOutputDirectByteBuffers()); - connection.addListener(sessionContainer); + connection.addEventListener(sessionContainer); return configure(connection, connector, endPoint); } diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractConnection.java b/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractConnection.java index 74ba6f0ed52..f4ee23bd67e 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractConnection.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractConnection.java @@ -18,6 +18,7 @@ package org.eclipse.jetty.io; +import java.util.EventListener; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.Executor; @@ -57,13 +58,14 @@ public abstract class AbstractConnection implements Connection } @Override - public void addListener(Listener listener) + public void addEventListener(EventListener listener) { - _listeners.add(listener); + if (listener instanceof Listener) + _listeners.add((Listener)listener); } @Override - public void removeListener(Listener listener) + public void removeEventListener(EventListener listener) { _listeners.remove(listener); } diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/ClientConnectionFactory.java b/jetty-io/src/main/java/org/eclipse/jetty/io/ClientConnectionFactory.java index 56f71586c63..fd81e7a3245 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/ClientConnectionFactory.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/ClientConnectionFactory.java @@ -19,6 +19,7 @@ package org.eclipse.jetty.io; import java.io.IOException; +import java.util.EventListener; import java.util.List; import java.util.Map; @@ -43,7 +44,7 @@ public interface ClientConnectionFactory { ContainerLifeCycle client = (ContainerLifeCycle)context.get(CLIENT_CONTEXT_KEY); if (client != null) - client.getBeans(Connection.Listener.class).forEach(connection::addListener); + client.getBeans(EventListener.class).forEach(connection::addEventListener); return connection; } diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/Connection.java b/jetty-io/src/main/java/org/eclipse/jetty/io/Connection.java index 885aee928cd..c8ccb25b73e 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/Connection.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/Connection.java @@ -20,6 +20,7 @@ package org.eclipse.jetty.io; import java.io.Closeable; import java.nio.ByteBuffer; +import java.util.EventListener; import org.eclipse.jetty.util.component.Container; @@ -38,14 +39,14 @@ public interface Connection extends Closeable * * @param listener the listener to add */ - public void addListener(Listener listener); + public void addEventListener(EventListener listener); /** *

Removes a listener of connection events.

* * @param listener the listener to remove */ - public void removeListener(Listener listener); + public void removeEventListener(EventListener listener); /** *

Callback method invoked when this connection is opened.

@@ -133,7 +134,7 @@ public interface Connection extends Closeable * the Connector or ConnectionFactory are added as listeners to all new connections *

*/ - public interface Listener + public interface Listener extends EventListener { public void onOpened(Connection connection); diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/SelectorManager.java b/jetty-io/src/main/java/org/eclipse/jetty/io/SelectorManager.java index 4115e471a77..8d51487b7c8 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/SelectorManager.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/SelectorManager.java @@ -38,6 +38,7 @@ import java.util.function.IntUnaryOperator; import org.eclipse.jetty.util.ProcessorUtils; import org.eclipse.jetty.util.annotation.ManagedAttribute; import org.eclipse.jetty.util.annotation.ManagedObject; +import org.eclipse.jetty.util.component.Container; import org.eclipse.jetty.util.component.ContainerLifeCycle; import org.eclipse.jetty.util.component.Dumpable; import org.eclipse.jetty.util.log.Log; @@ -389,31 +390,37 @@ public abstract class SelectorManager extends ContainerLifeCycle implements Dump */ public abstract Connection newConnection(SelectableChannel channel, EndPoint endpoint, Object attachment) throws IOException; - public void addEventListener(EventListener listener) + /** + * @param listener An EventListener + * @see AcceptListener + * @see Container#addEventListener(EventListener) + */ + @Override + public boolean addEventListener(EventListener listener) { if (isRunning()) throw new IllegalStateException(this.toString()); - if (listener instanceof AcceptListener) - addAcceptListener(AcceptListener.class.cast(listener)); + if (super.addEventListener(listener)) + { + if (listener instanceof AcceptListener) + _acceptListeners.add((AcceptListener)listener); + return true; + } + return false; } - public void removeEventListener(EventListener listener) + @Override + public boolean removeEventListener(EventListener listener) { if (isRunning()) throw new IllegalStateException(this.toString()); - if (listener instanceof AcceptListener) - removeAcceptListener(AcceptListener.class.cast(listener)); - } - - public void addAcceptListener(AcceptListener listener) - { - if (!_acceptListeners.contains(listener)) - _acceptListeners.add(listener); - } - - public void removeAcceptListener(AcceptListener listener) - { - _acceptListeners.remove(listener); + if (super.removeEventListener(listener)) + { + if (listener instanceof AcceptListener) + _acceptListeners.remove(listener); + return true; + } + return false; } protected void onAccepting(SelectableChannel channel) @@ -461,12 +468,16 @@ public abstract class SelectorManager extends ContainerLifeCycle implements Dump } } + public interface SelectorManagerListener extends EventListener + { + } + /** *

A listener for accept events.

*

This listener is called from either the selector or acceptor thread * and implementations must be non blocking and fast.

*/ - public interface AcceptListener extends EventListener + public interface AcceptListener extends SelectorManagerListener { /** * Called immediately after a new SelectableChannel is accepted, but diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/WriteFlusher.java b/jetty-io/src/main/java/org/eclipse/jetty/io/WriteFlusher.java index a1e040754d7..0a39a7bd075 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/WriteFlusher.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/WriteFlusher.java @@ -571,7 +571,8 @@ public abstract class WriteFlusher } /** - *

A listener of {@link WriteFlusher} events.

+ *

A listener of {@link WriteFlusher} events. + * If implemented by a Connection class, the {@link #onFlushed(long)} event will be delivered to it.

*/ public interface Listener { diff --git a/jetty-maven-plugin/src/it/javax-annotation-api/src/config/jetty.xml b/jetty-maven-plugin/src/it/javax-annotation-api/src/config/jetty.xml index 4dd58944725..4e43b5305df 100644 --- a/jetty-maven-plugin/src/it/javax-annotation-api/src/config/jetty.xml +++ b/jetty-maven-plugin/src/it/javax-annotation-api/src/config/jetty.xml @@ -24,7 +24,7 @@
- + diff --git a/jetty-maven-plugin/src/it/jetty-cdi-run-forked/src/main/jetty/jetty.xml b/jetty-maven-plugin/src/it/jetty-cdi-run-forked/src/main/jetty/jetty.xml index 9e32909fd93..8f1c473fb3f 100644 --- a/jetty-maven-plugin/src/it/jetty-cdi-run-forked/src/main/jetty/jetty.xml +++ b/jetty-maven-plugin/src/it/jetty-cdi-run-forked/src/main/jetty/jetty.xml @@ -24,7 +24,7 @@ - + diff --git a/jetty-maven-plugin/src/it/jetty-deploy-war-mojo-it/src/config/jetty.xml b/jetty-maven-plugin/src/it/jetty-deploy-war-mojo-it/src/config/jetty.xml index 4dd58944725..4e43b5305df 100644 --- a/jetty-maven-plugin/src/it/jetty-deploy-war-mojo-it/src/config/jetty.xml +++ b/jetty-maven-plugin/src/it/jetty-deploy-war-mojo-it/src/config/jetty.xml @@ -24,7 +24,7 @@ - + diff --git a/jetty-maven-plugin/src/it/jetty-maven-plugin-provided-module-dep/web/src/config/jetty.xml b/jetty-maven-plugin/src/it/jetty-maven-plugin-provided-module-dep/web/src/config/jetty.xml index de81416a934..7df44bd5ad7 100644 --- a/jetty-maven-plugin/src/it/jetty-maven-plugin-provided-module-dep/web/src/config/jetty.xml +++ b/jetty-maven-plugin/src/it/jetty-maven-plugin-provided-module-dep/web/src/config/jetty.xml @@ -30,7 +30,7 @@ - + diff --git a/jetty-maven-plugin/src/it/jetty-run-distro-mojo-it/jetty-simple-webapp/src/base/etc/test-jetty.xml b/jetty-maven-plugin/src/it/jetty-run-distro-mojo-it/jetty-simple-webapp/src/base/etc/test-jetty.xml index 08d848ec4c6..c3df301c562 100644 --- a/jetty-maven-plugin/src/it/jetty-run-distro-mojo-it/jetty-simple-webapp/src/base/etc/test-jetty.xml +++ b/jetty-maven-plugin/src/it/jetty-run-distro-mojo-it/jetty-simple-webapp/src/base/etc/test-jetty.xml @@ -3,7 +3,7 @@ - + diff --git a/jetty-maven-plugin/src/it/jetty-run-forked-mojo-it/jetty-simple-webapp/src/config/jetty.xml b/jetty-maven-plugin/src/it/jetty-run-forked-mojo-it/jetty-simple-webapp/src/config/jetty.xml index 4dd58944725..4e43b5305df 100644 --- a/jetty-maven-plugin/src/it/jetty-run-forked-mojo-it/jetty-simple-webapp/src/config/jetty.xml +++ b/jetty-maven-plugin/src/it/jetty-run-forked-mojo-it/jetty-simple-webapp/src/config/jetty.xml @@ -24,7 +24,7 @@ - + diff --git a/jetty-maven-plugin/src/it/jetty-run-mojo-it/jetty-simple-webapp/src/config/jetty.xml b/jetty-maven-plugin/src/it/jetty-run-mojo-it/jetty-simple-webapp/src/config/jetty.xml index 4dd58944725..4e43b5305df 100644 --- a/jetty-maven-plugin/src/it/jetty-run-mojo-it/jetty-simple-webapp/src/config/jetty.xml +++ b/jetty-maven-plugin/src/it/jetty-run-mojo-it/jetty-simple-webapp/src/config/jetty.xml @@ -24,7 +24,7 @@ - + diff --git a/jetty-maven-plugin/src/it/jetty-run-mojo-jsp/src/config/jetty.xml b/jetty-maven-plugin/src/it/jetty-run-mojo-jsp/src/config/jetty.xml index 4dd58944725..4e43b5305df 100644 --- a/jetty-maven-plugin/src/it/jetty-run-mojo-jsp/src/config/jetty.xml +++ b/jetty-maven-plugin/src/it/jetty-run-mojo-jsp/src/config/jetty.xml @@ -24,7 +24,7 @@ - + diff --git a/jetty-maven-plugin/src/it/jetty-run-mojo-multi-module-single-war-it/webapp-war/src/config/jetty.xml b/jetty-maven-plugin/src/it/jetty-run-mojo-multi-module-single-war-it/webapp-war/src/config/jetty.xml index 4dd58944725..4e43b5305df 100644 --- a/jetty-maven-plugin/src/it/jetty-run-mojo-multi-module-single-war-it/webapp-war/src/config/jetty.xml +++ b/jetty-maven-plugin/src/it/jetty-run-mojo-multi-module-single-war-it/webapp-war/src/config/jetty.xml @@ -24,7 +24,7 @@ - + diff --git a/jetty-maven-plugin/src/it/jetty-run-war-exploded-mojo-it/jetty-simple-webapp/src/config/jetty.xml b/jetty-maven-plugin/src/it/jetty-run-war-exploded-mojo-it/jetty-simple-webapp/src/config/jetty.xml index 4dd58944725..4e43b5305df 100644 --- a/jetty-maven-plugin/src/it/jetty-run-war-exploded-mojo-it/jetty-simple-webapp/src/config/jetty.xml +++ b/jetty-maven-plugin/src/it/jetty-run-war-exploded-mojo-it/jetty-simple-webapp/src/config/jetty.xml @@ -24,7 +24,7 @@ - + diff --git a/jetty-maven-plugin/src/it/jetty-run-war-mojo-it/jetty-simple-webapp/src/config/jetty.xml b/jetty-maven-plugin/src/it/jetty-run-war-mojo-it/jetty-simple-webapp/src/config/jetty.xml index 4dd58944725..4e43b5305df 100644 --- a/jetty-maven-plugin/src/it/jetty-run-war-mojo-it/jetty-simple-webapp/src/config/jetty.xml +++ b/jetty-maven-plugin/src/it/jetty-run-war-mojo-it/jetty-simple-webapp/src/config/jetty.xml @@ -24,7 +24,7 @@ - + diff --git a/jetty-maven-plugin/src/it/jetty-start-mojo-it/jetty-simple-webapp/src/config/jetty.xml b/jetty-maven-plugin/src/it/jetty-start-mojo-it/jetty-simple-webapp/src/config/jetty.xml index 4dd58944725..4e43b5305df 100644 --- a/jetty-maven-plugin/src/it/jetty-start-mojo-it/jetty-simple-webapp/src/config/jetty.xml +++ b/jetty-maven-plugin/src/it/jetty-start-mojo-it/jetty-simple-webapp/src/config/jetty.xml @@ -24,7 +24,7 @@ - + diff --git a/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-server/src/config/jetty.xml b/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-server/src/config/jetty.xml index 4dd58944725..4e43b5305df 100644 --- a/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-server/src/config/jetty.xml +++ b/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-server/src/config/jetty.xml @@ -24,7 +24,7 @@ - + diff --git a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyWebAppContext.java b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyWebAppContext.java index 302d267f00d..2714997a8ed 100644 --- a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyWebAppContext.java +++ b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyWebAppContext.java @@ -23,7 +23,6 @@ import java.io.IOException; import java.lang.reflect.Method; import java.net.MalformedURLException; import java.util.ArrayList; -import java.util.EventListener; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -356,11 +355,9 @@ public class JettyWebAppContext extends WebAppContext super.doStop(); - // remove all listeners, servlets and filters. This is because we will - // re-apply - // any context xml file, which means they would potentially be added - // multiple times. - setEventListeners(new EventListener[0]); + // remove all servlets and filters. This is because we will + // re-appy any context xml file, which means they would potentially be + // added multiple times. getServletHandler().setFilters(new FilterHolder[0]); getServletHandler().setFilterMappings(new FilterMapping[0]); getServletHandler().setServlets(new ServletHolder[0]); diff --git a/jetty-maven-plugin/src/main/resources/jetty-maven.xml b/jetty-maven-plugin/src/main/resources/jetty-maven.xml index 8ee79fbec55..47d10a84d4f 100644 --- a/jetty-maven-plugin/src/main/resources/jetty-maven.xml +++ b/jetty-maven-plugin/src/main/resources/jetty-maven.xml @@ -2,7 +2,7 @@ - + diff --git a/jetty-osgi/test-jetty-osgi-server/src/main/java/com/acme/osgi/Activator.java b/jetty-osgi/test-jetty-osgi-server/src/main/java/com/acme/osgi/Activator.java index 0c688fe393c..6b3d9fa24f4 100644 --- a/jetty-osgi/test-jetty-osgi-server/src/main/java/com/acme/osgi/Activator.java +++ b/jetty-osgi/test-jetty-osgi-server/src/main/java/com/acme/osgi/Activator.java @@ -46,7 +46,7 @@ public class Activator implements BundleActivator { //For test purposes, use a random port Server server = new Server(0); - server.getConnectors()[0].addLifeCycleListener(new AbstractLifeCycleListener() + server.getConnectors()[0].addEventListener(new AbstractLifeCycleListener() { /** diff --git a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http-boot-context-as-service.xml b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http-boot-context-as-service.xml index e5baeae8106..5333433aab7 100644 --- a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http-boot-context-as-service.xml +++ b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http-boot-context-as-service.xml @@ -31,7 +31,7 @@ - + boot.context.service.port diff --git a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http-boot-webapp-as-service.xml b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http-boot-webapp-as-service.xml index 3f034f1334b..b90533d0b60 100644 --- a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http-boot-webapp-as-service.xml +++ b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http-boot-webapp-as-service.xml @@ -31,7 +31,7 @@ - + boot.webapp.service.port diff --git a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http-boot-with-annotations.xml b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http-boot-with-annotations.xml index ccb14c09de9..271f12e042c 100644 --- a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http-boot-with-annotations.xml +++ b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http-boot-with-annotations.xml @@ -31,7 +31,7 @@ - + boot.annotations.port diff --git a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http-boot-with-bundle.xml b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http-boot-with-bundle.xml index 80335e9184a..6cb5d15395a 100644 --- a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http-boot-with-bundle.xml +++ b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http-boot-with-bundle.xml @@ -31,7 +31,7 @@ - + boot.bundle.port diff --git a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http-boot-with-javax-websocket.xml b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http-boot-with-javax-websocket.xml index 6f28312891c..4ff583996c4 100644 --- a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http-boot-with-javax-websocket.xml +++ b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http-boot-with-javax-websocket.xml @@ -31,7 +31,7 @@ - + boot.javax.websocket.port diff --git a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http-boot-with-jsp.xml b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http-boot-with-jsp.xml index 5ae769fca57..9edaf7b56c0 100644 --- a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http-boot-with-jsp.xml +++ b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http-boot-with-jsp.xml @@ -31,7 +31,7 @@ - + boot.jsp.port diff --git a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http-boot-with-websocket.xml b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http-boot-with-websocket.xml index 20bb83b2765..e1b37e7c70f 100644 --- a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http-boot-with-websocket.xml +++ b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http-boot-with-websocket.xml @@ -31,7 +31,7 @@ - + boot.websocket.port diff --git a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http.xml b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http.xml index 8995bfc70ce..6b883c59a0e 100644 --- a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http.xml +++ b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http.xml @@ -31,7 +31,7 @@ - + foo.foo diff --git a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-https.xml b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-https.xml index 41fb957e7f0..941216afee1 100644 --- a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-https.xml +++ b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-https.xml @@ -16,7 +16,7 @@ - + boot.https.port diff --git a/jetty-security/src/test/java/org/eclipse/jetty/security/authentication/SpnegoAuthenticatorTest.java b/jetty-security/src/test/java/org/eclipse/jetty/security/authentication/SpnegoAuthenticatorTest.java index 25b6dbe6235..b1fbd915252 100644 --- a/jetty-security/src/test/java/org/eclipse/jetty/security/authentication/SpnegoAuthenticatorTest.java +++ b/jetty-security/src/test/java/org/eclipse/jetty/security/authentication/SpnegoAuthenticatorTest.java @@ -125,6 +125,31 @@ public class SpnegoAuthenticatorTest assertEquals(HttpHeader.NEGOTIATE.asString(), res.getHeader(HttpHeader.WWW_AUTHENTICATE.asString())); assertEquals(HttpServletResponse.SC_UNAUTHORIZED, res.getStatus()); } + + class MockConnector extends AbstractConnector + { + public MockConnector() + { + super(new Server() , null, null, null, 0); + } + + @Override + protected void accept(int acceptorID) throws IOException, InterruptedException + { + } + + @Override + public Object getTransport() + { + return null; + } + + @Override + public String dumpSelf() + { + return null; + } + } } class MockConnector extends AbstractConnector diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnectionFactory.java b/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnectionFactory.java index af5bf1f0ec9..74c3402e3da 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnectionFactory.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnectionFactory.java @@ -23,7 +23,6 @@ import java.util.Collections; import java.util.List; import org.eclipse.jetty.io.AbstractConnection; -import org.eclipse.jetty.io.Connection; import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.util.ArrayUtil; import org.eclipse.jetty.util.annotation.ManagedAttribute; @@ -32,17 +31,7 @@ import org.eclipse.jetty.util.component.ContainerLifeCycle; import org.eclipse.jetty.util.ssl.SslContextFactory; /** - *

Provides the common handling for {@link ConnectionFactory} implementations including:

- *
    - *
  • Protocol identification
  • - *
  • Configuration of new Connections: - *
      - *
    • Setting inputbuffer size
    • - *
    • Calling {@link Connection#addListener(Connection.Listener)} for all - * Connection.Listener instances found as beans on the {@link Connector} - * and this {@link ConnectionFactory}
    • - *
    - *
+ *

Provides the common handling for {@link ConnectionFactory} implementations.

*/ @ManagedObject public abstract class AbstractConnectionFactory extends ContainerLifeCycle implements ConnectionFactory @@ -92,19 +81,10 @@ public abstract class AbstractConnectionFactory extends ContainerLifeCycle imple connection.setInputBufferSize(getInputBufferSize()); // Add Connection.Listeners from Connector - if (connector instanceof ContainerLifeCycle) - { - ContainerLifeCycle aggregate = (ContainerLifeCycle)connector; - for (Connection.Listener listener : aggregate.getBeans(Connection.Listener.class)) - { - connection.addListener(listener); - } - } + connector.getEventListeners().forEach(connection::addEventListener); + // Add Connection.Listeners from this factory - for (Connection.Listener listener : getBeans(Connection.Listener.class)) - { - connection.addListener(listener); - } + getEventListeners().forEach(connection::addEventListener); return connection; } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java index 536fe39a16e..c2300504210 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java @@ -104,7 +104,6 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor _state = new HttpChannelState(this); _request = new Request(this, newHttpInput(_state)); _response = new Response(this, newHttpOutput()); - _executor = connector.getServer().getThreadPool(); _requestLog = connector.getServer().getRequestLog(); _combinedListener = (connector instanceof AbstractConnector) @@ -1224,15 +1223,16 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor public void succeeded() { _written += _length; - if (_complete) - _response.getHttpOutput().closed(); - super.succeeded(); if (_commit) _combinedListener.onResponseCommit(_request); if (_length > 0) _combinedListener.onResponseContent(_request, _content); if (_complete && _state.completeResponse()) + { + _response.getHttpOutput().closed(); _combinedListener.onResponseEnd(_request); + } + super.succeeded(); } @Override diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpOutput.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpOutput.java index feaf21afd12..030499d8b2a 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpOutput.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpOutput.java @@ -386,22 +386,7 @@ public class HttpOutput extends ServletOutputStream implements Runnable if (!_state.compareAndSet(state, State.CLOSED)) break; - // Just make sure write and output stream really are closed - try - { - _channel.getResponse().closeOutput(); - } - catch (Throwable x) - { - if (LOG.isDebugEnabled()) - LOG.debug(x); - abort(x); - } - finally - { - releaseBuffer(); - } - // Return even if an exception is thrown by closeOutput(). + releaseBuffer(); return; } } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/ServerConnector.java b/jetty-server/src/main/java/org/eclipse/jetty/server/ServerConnector.java index e7aec0ea14e..4f11e3df363 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/ServerConnector.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/ServerConnector.java @@ -223,10 +223,8 @@ public class ServerConnector extends AbstractNetworkConnector @Override protected void doStart() throws Exception { - for (EventListener l : getBeans(EventListener.class)) - { + for (EventListener l : getBeans(SelectorManager.SelectorManagerListener.class)) _manager.addEventListener(l); - } super.doStart(); diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java index 875b532cfb3..0050e2fd8da 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java @@ -198,7 +198,6 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu private boolean _compactPath = false; private boolean _usingSecurityManager = System.getSecurityManager() != null; - private final List _eventListeners = new CopyOnWriteArrayList<>(); private final List _programmaticListeners = new CopyOnWriteArrayList<>(); private final List _servletContextListeners = new CopyOnWriteArrayList<>(); private final List _destroySerletContextListeners = new ArrayList<>(); @@ -206,7 +205,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu private final List _servletRequestListeners = new CopyOnWriteArrayList<>(); private final List _servletRequestAttributeListeners = new CopyOnWriteArrayList<>(); private final List _contextListeners = new CopyOnWriteArrayList<>(); - private final List _durableListeners = new CopyOnWriteArrayList<>(); + private final Set _durableListeners = new HashSet<>(); private String[] _protectedTargets; private final CopyOnWriteArrayList _aliasChecks = new CopyOnWriteArrayList(); @@ -260,7 +259,6 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu { dumpObjects(out, indent, new ClassLoaderDump(getClassLoader()), - new DumpableCollection("eventListeners " + this, _eventListeners), new DumpableCollection("handler attributes " + this, ((AttributesMap)getAttributes()).getAttributeEntrySet()), new DumpableCollection("context attributes " + this, ((Context)getServletContext()).getAttributeEntrySet()), new DumpableCollection("initparams " + this, getInitParams().entrySet())); @@ -606,101 +604,68 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu return _displayName; } - public EventListener[] getEventListeners() - { - return _eventListeners.toArray(new EventListener[_eventListeners.size()]); - } - - /** - * Set the context event listeners. - * - * @param eventListeners the event listeners - * @see ServletContextListener - * @see ServletContextAttributeListener - * @see ServletRequestListener - * @see ServletRequestAttributeListener - */ - public void setEventListeners(EventListener[] eventListeners) - { - _contextListeners.clear(); - _servletContextListeners.clear(); - _servletContextAttributeListeners.clear(); - _servletRequestListeners.clear(); - _servletRequestAttributeListeners.clear(); - _eventListeners.clear(); - - if (eventListeners != null) - for (EventListener listener : eventListeners) - { - addEventListener(listener); - } - } - /** * Add a context event listeners. * * @param listener the event listener to add + * @return true if the listener was added + * @see ContextScopeListener * @see ServletContextListener * @see ServletContextAttributeListener * @see ServletRequestListener * @see ServletRequestAttributeListener */ - public void addEventListener(EventListener listener) + @Override + public boolean addEventListener(EventListener listener) { - _eventListeners.add(listener); - - if (!(isStarted() || isStarting())) + if (super.addEventListener(listener)) { - _durableListeners.add(listener); + if (listener instanceof ContextScopeListener) + { + _contextListeners.add((ContextScopeListener)listener); + if (__context.get() != null) + ((ContextScopeListener)listener).enterScope(__context.get(), null, "Listener registered"); + } + + if (listener instanceof ServletContextListener) + _servletContextListeners.add((ServletContextListener)listener); + + if (listener instanceof ServletContextAttributeListener) + _servletContextAttributeListeners.add((ServletContextAttributeListener)listener); + + if (listener instanceof ServletRequestListener) + _servletRequestListeners.add((ServletRequestListener)listener); + + if (listener instanceof ServletRequestAttributeListener) + _servletRequestAttributeListeners.add((ServletRequestAttributeListener)listener); + + return true; } - - if (listener instanceof ContextScopeListener) - { - _contextListeners.add((ContextScopeListener)listener); - if (__context.get() != null) - ((ContextScopeListener)listener).enterScope(__context.get(), null, "Listener registered"); - } - - if (listener instanceof ServletContextListener) - _servletContextListeners.add((ServletContextListener)listener); - - if (listener instanceof ServletContextAttributeListener) - _servletContextAttributeListeners.add((ServletContextAttributeListener)listener); - - if (listener instanceof ServletRequestListener) - _servletRequestListeners.add((ServletRequestListener)listener); - - if (listener instanceof ServletRequestAttributeListener) - _servletRequestAttributeListeners.add((ServletRequestAttributeListener)listener); + return false; } - /** - * Remove a context event listeners. - * - * @param listener the event listener to remove - * @see ServletContextListener - * @see ServletContextAttributeListener - * @see ServletRequestListener - * @see ServletRequestAttributeListener - */ - public void removeEventListener(EventListener listener) + @Override + public boolean removeEventListener(EventListener listener) { - _eventListeners.remove(listener); + if (super.removeEventListener(listener)) + { + if (listener instanceof ContextScopeListener) + _contextListeners.remove(listener); - if (listener instanceof ContextScopeListener) - _contextListeners.remove(listener); + if (listener instanceof ServletContextListener) + _servletContextListeners.remove(listener); - if (listener instanceof ServletContextListener) - _servletContextListeners.remove(listener); + if (listener instanceof ServletContextAttributeListener) + _servletContextAttributeListeners.remove(listener); - if (listener instanceof ServletContextAttributeListener) - _servletContextAttributeListeners.remove(listener); + if (listener instanceof ServletRequestListener) + _servletRequestListeners.remove(listener); - if (listener instanceof ServletRequestListener) - _servletRequestListeners.remove(listener); - - if (listener instanceof ServletRequestAttributeListener) - _servletRequestAttributeListeners.remove(listener); + if (listener instanceof ServletRequestAttributeListener) + _servletRequestAttributeListeners.remove(listener); + return true; + } + return false; } /** @@ -720,7 +685,11 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu public boolean isDurableListener(EventListener listener) { - return _durableListeners.contains(listener); + // The durable listeners are those set when the context is started + if (isStarted()) + return _durableListeners.contains(listener); + // If we are not yet started then all set listeners are durable + return getEventListeners().contains(listener); } /** @@ -800,6 +769,8 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu if (_mimeTypes == null) _mimeTypes = new MimeTypes(); + _durableListeners.addAll(getEventListeners()); + try { // Set the classloader, context and enter scope @@ -975,7 +946,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu stopContext(); // retain only durable listeners - setEventListeners(_durableListeners.toArray(new EventListener[_durableListeners.size()])); + setEventListeners(_durableListeners); _durableListeners.clear(); if (_errorHandler != null) diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/SessionHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/SessionHandler.java index 86241449c95..789dc903236 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/SessionHandler.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/SessionHandler.java @@ -261,33 +261,26 @@ public class SessionHandler extends ScopedHandler * Individual SessionManagers implementations may accept arbitrary listener types, * but they are expected to at least handle HttpSessionActivationListener, * HttpSessionAttributeListener, HttpSessionBindingListener and HttpSessionListener. + * @return true if the listener was added * @see #removeEventListener(EventListener) + * @see HttpSessionAttributeListener + * @see HttpSessionListener + * @see HttpSessionIdListener */ - public void addEventListener(EventListener listener) + @Override + public boolean addEventListener(EventListener listener) { - if (listener instanceof HttpSessionAttributeListener) - _sessionAttributeListeners.add((HttpSessionAttributeListener)listener); - if (listener instanceof HttpSessionListener) - _sessionListeners.add((HttpSessionListener)listener); - if (listener instanceof HttpSessionIdListener) - _sessionIdListeners.add((HttpSessionIdListener)listener); - addBean(listener, false); - } - - /** - * Removes all event listeners for session-related events. - * - * @see #removeEventListener(EventListener) - */ - public void clearEventListeners() - { - for (EventListener e : getBeans(EventListener.class)) + if (super.addEventListener(listener)) { - removeBean(e); + if (listener instanceof HttpSessionAttributeListener) + _sessionAttributeListeners.add((HttpSessionAttributeListener)listener); + if (listener instanceof HttpSessionListener) + _sessionListeners.add((HttpSessionListener)listener); + if (listener instanceof HttpSessionIdListener) + _sessionIdListeners.add((HttpSessionIdListener)listener); + return true; } - _sessionAttributeListeners.clear(); - _sessionListeners.clear(); - _sessionIdListeners.clear(); + return false; } /** @@ -785,21 +778,20 @@ public class SessionHandler extends ScopedHandler } } - /** - * Removes an event listener for for session-related events. - * - * @param listener the session event listener to remove - * @see #addEventListener(EventListener) - */ - public void removeEventListener(EventListener listener) + @Override + public boolean removeEventListener(EventListener listener) { - if (listener instanceof HttpSessionAttributeListener) - _sessionAttributeListeners.remove(listener); - if (listener instanceof HttpSessionListener) - _sessionListeners.remove(listener); - if (listener instanceof HttpSessionIdListener) - _sessionIdListeners.remove(listener); - removeBean(listener); + if (super.removeEventListener(listener)) + { + if (listener instanceof HttpSessionAttributeListener) + _sessionAttributeListeners.remove(listener); + if (listener instanceof HttpSessionListener) + _sessionListeners.remove(listener); + if (listener instanceof HttpSessionIdListener) + _sessionIdListeners.remove(listener); + return true; + } + return false; } /** diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/DelayedServerTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/DelayedServerTest.java new file mode 100644 index 00000000000..ba11cf4f979 --- /dev/null +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/DelayedServerTest.java @@ -0,0 +1,112 @@ +// +// ======================================================================== +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.server; + +import java.nio.ByteBuffer; + +import org.eclipse.jetty.http.HttpCompliance; +import org.eclipse.jetty.http.MetaData; +import org.eclipse.jetty.io.Connection; +import org.eclipse.jetty.io.EndPoint; +import org.eclipse.jetty.util.Callback; +import org.eclipse.jetty.util.thread.ThreadPool; +import org.junit.jupiter.api.BeforeEach; + +/** + * Extended Server Tester. + */ +public class DelayedServerTest extends HttpServerTestBase +{ + @BeforeEach + public void init() throws Exception + { + startServer(new ServerConnector(_server, new HttpConnectionFactory() + { + @Override + public Connection newConnection(Connector connector, EndPoint endPoint) + { + return configure(new DelayedHttpConnection(getHttpConfiguration(), connector, endPoint), connector, endPoint); + } + })); + } + + private static class DelayedHttpConnection extends HttpConnection + { + public DelayedHttpConnection(HttpConfiguration config, Connector connector, EndPoint endPoint) + { + super(config, connector, endPoint, false); + } + + @Override + public void send(MetaData.Request request, MetaData.Response response, ByteBuffer content, boolean lastContent, Callback callback) + { + DelayedCallback delay = new DelayedCallback(callback, getServer().getThreadPool()); + super.send(request, response, content, lastContent, delay); + } + } + + private static class DelayedCallback extends Callback.Nested + { + final ThreadPool pool; + + public DelayedCallback(Callback callback, ThreadPool threadPool) + { + super(callback); + pool = threadPool; + } + + @Override + public void succeeded() + { + pool.execute(()-> + { + try + { + Thread.sleep(10); + } + catch (InterruptedException e) + { + } + finally + { + super.succeeded(); + } + }); + } + + @Override + public void failed(Throwable x) + { + pool.execute(()-> + { + try + { + Thread.sleep(20); + } + catch (InterruptedException e) + { + } + finally + { + super.failed(x); + } + }); + } + } +} diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/ExtendedServerTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/ExtendedServerTest.java index 3f37bcaa233..24311ba0f48 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/ExtendedServerTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/ExtendedServerTest.java @@ -21,7 +21,6 @@ package org.eclipse.jetty.server; import java.io.IOException; import java.io.OutputStream; import java.net.Socket; -import java.nio.channels.SelectableChannel; import java.nio.channels.SelectionKey; import java.nio.channels.SocketChannel; import java.nio.charset.StandardCharsets; @@ -73,11 +72,6 @@ public class ExtendedServerTest extends HttpServerTestBase { private volatile long _lastSelected; - public ExtendedEndPoint(SelectableChannel channel, ManagedSelector selector, SelectionKey key, Scheduler scheduler) - { - super(channel, selector, key, scheduler); - } - public ExtendedEndPoint(SocketChannel channel, ManagedSelector selector, SelectionKey key, Scheduler scheduler) { super(channel, selector, key, scheduler); diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpServerTestBase.java b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpServerTestBase.java index e37d334d55d..6377df45ee0 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpServerTestBase.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpServerTestBase.java @@ -28,10 +28,12 @@ import java.io.LineNumberReader; import java.io.OutputStream; import java.net.Socket; import java.net.URL; +import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.concurrent.Exchanger; import java.util.concurrent.atomic.AtomicBoolean; +import javax.servlet.AsyncContext; import javax.servlet.ServletException; import javax.servlet.ServletInputStream; import javax.servlet.ServletOutputStream; @@ -42,6 +44,8 @@ import org.eclipse.jetty.http.tools.HttpTester; import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.io.EofException; import org.eclipse.jetty.server.handler.AbstractHandler; +import org.eclipse.jetty.util.BufferUtil; +import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.IO; import org.eclipse.jetty.util.log.AbstractLogger; import org.eclipse.jetty.util.log.Log; @@ -1816,4 +1820,53 @@ public abstract class HttpServerTestBase extends HttpServerTestFixture assertThat(client.getInputStream().read(), is(-1)); } } + + @Test + public void testSendAsyncContent() throws Exception + { + int size = 64 * 1024; + configureServer(new SendAsyncContentHandler(size)); + + try (Socket client = newSocket(_serverURI.getHost(), _serverURI.getPort())) + { + OutputStream os = client.getOutputStream(); + os.write(("GET / HTTP/1.1\r\nHost: localhost\r\n\r\n").getBytes(StandardCharsets.ISO_8859_1)); + os.flush(); + + HttpTester.Response response = HttpTester.parseResponse(client.getInputStream()); + assertThat(response.getStatus(), is(200)); + assertThat(response.getContentBytes().length, is(size)); + + // Try again to check previous request completed OK + os.write(("GET / HTTP/1.1\r\nHost: localhost\r\n\r\n").getBytes(StandardCharsets.ISO_8859_1)); + os.flush(); + response = HttpTester.parseResponse(client.getInputStream()); + assertThat(response.getStatus(), is(200)); + assertThat(response.getContentBytes().length, is(size)); + } + } + + private class SendAsyncContentHandler extends AbstractHandler + { + final ByteBuffer content; + + public SendAsyncContentHandler(int size) + { + content = BufferUtil.allocate(size); + Arrays.fill(content.array(),0,size,(byte)'X'); + content.position(0); + content.limit(size); + } + + @Override + public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException + { + baseRequest.setHandled(true); + response.setStatus(200); + response.setContentType("application/unknown"); + response.setContentLength(content.remaining()); + AsyncContext async = request.startAsync(); + ((HttpOutput)response.getOutputStream()).sendContent(content.slice(), Callback.from(async::complete)); + } + } } diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ShutdownHandlerTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ShutdownHandlerTest.java index 04101fabc6a..c8bb17e6d7f 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ShutdownHandlerTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ShutdownHandlerTest.java @@ -70,7 +70,7 @@ public class ShutdownHandlerTest start(null); CountDownLatch stopLatch = new CountDownLatch(1); - server.addLifeCycleListener(new AbstractLifeCycle.AbstractLifeCycleListener() + server.addEventListener(new AbstractLifeCycle.AbstractLifeCycleListener() { @Override public void lifeCycleStopped(LifeCycle event) diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ListenerHolder.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ListenerHolder.java index 9313237ea4e..f61014503d2 100644 --- a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ListenerHolder.java +++ b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ListenerHolder.java @@ -61,6 +61,7 @@ public class ListenerHolder extends BaseHolder * just like ServletHolder and FilterHolder, * the listener will not be introspected for * annotations like Resource etc. + * @param listener The listener instance */ public void setListener(EventListener listener) { diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletContextHandler.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletContextHandler.java index 9f69fce9b3d..a08bfb5ba45 100644 --- a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletContextHandler.java +++ b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletContextHandler.java @@ -196,24 +196,33 @@ public class ServletContextHandler extends ContextHandler /** * Add EventListener - * Adds an EventListener to the list. @see org.eclipse.jetty.server.handler.ContextHandler#addEventListener(). - * Also adds any listeners that are session related to the SessionHandler. * * @param listener the listener to add + * @return true if the listener was added + * @see HttpSessionAttributeListener + * @see HttpSessionActivationListener + * @see HttpSessionBindingListener + * @see HttpSessionListener + * @see HttpSessionIdListener + * @see ContextHandler#addEventListener(EventListener) */ @Override - public void addEventListener(EventListener listener) + public boolean addEventListener(EventListener listener) { - super.addEventListener(listener); - if ((listener instanceof HttpSessionActivationListener) || - (listener instanceof HttpSessionAttributeListener) || - (listener instanceof HttpSessionBindingListener) || - (listener instanceof HttpSessionListener) || - (listener instanceof HttpSessionIdListener)) + if (super.addEventListener(listener)) { - if (_sessionHandler != null) - _sessionHandler.addEventListener(listener); + if ((listener instanceof HttpSessionActivationListener) || + (listener instanceof HttpSessionAttributeListener) || + (listener instanceof HttpSessionBindingListener) || + (listener instanceof HttpSessionListener) || + (listener instanceof HttpSessionIdListener)) + { + if (_sessionHandler != null) + _sessionHandler.addEventListener(listener); + } + return true; } + return false; } @Override diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHolder.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHolder.java index feb16756019..266363431cd 100644 --- a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHolder.java +++ b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHolder.java @@ -670,7 +670,7 @@ public class ServletHolder extends Holder implements UserIdentity.Scope //Register a listener to delete tmp files that are created as a result of this //servlet calling Request.getPart() or Request.getParts() ContextHandler ch = ContextHandler.getContextHandler(getServletHandler().getServletContext()); - if (!Arrays.asList(ch.getEventListeners()).contains(MultiPartCleanerListener.INSTANCE)) + if (!ch.getEventListeners().contains(MultiPartCleanerListener.INSTANCE)) ch.addEventListener(MultiPartCleanerListener.INSTANCE); } } diff --git a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/ServletContextHandlerTest.java b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/ServletContextHandlerTest.java index 080e045eca2..67bf4b71b44 100644 --- a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/ServletContextHandlerTest.java +++ b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/ServletContextHandlerTest.java @@ -29,7 +29,6 @@ import java.util.Objects; import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; - import javax.servlet.DispatcherType; import javax.servlet.Filter; import javax.servlet.FilterChain; @@ -462,11 +461,9 @@ public class ServletContextHandlerTest assertTrue(root.isProgrammaticListener(l.getListener())); } } - - EventListener[] listeners = root.getEventListeners(); - assertNotNull(listeners); + List listenerClassNames = new ArrayList<>(); - for (EventListener l : listeners) + for (EventListener l : root.getEventListeners()) listenerClassNames.add(l.getClass().getName()); assertTrue(listenerClassNames.contains("org.eclipse.jetty.servlet.ServletContextHandlerTest$MySCAListener")); diff --git a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/ServletLifeCycleTest.java b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/ServletLifeCycleTest.java index 01100eb8b03..eb79854e970 100644 --- a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/ServletLifeCycleTest.java +++ b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/ServletLifeCycleTest.java @@ -21,6 +21,7 @@ package org.eclipse.jetty.servlet; import java.io.IOException; import java.util.EnumSet; import java.util.EventListener; +import java.util.List; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; import javax.servlet.DispatcherType; @@ -120,9 +121,19 @@ public class ServletLifeCycleTest "Destroy class org.eclipse.jetty.servlet.ServletLifeCycleTest$TestListener")); // Listener added before start is not destroyed - EventListener[] listeners = context.getEventListeners(); - assertThat(listeners.length, is(1)); - assertThat(listeners[0].getClass(), is(TestListener2.class)); + List listeners = context.getEventListeners(); + assertThat(listeners.size(), is(1)); + assertThat(listeners.get(0).getClass(), is(TestListener2.class)); + + server.start(); + context.addEventListener(new EventListener() {});listeners = context.getEventListeners(); + listeners = context.getEventListeners(); + assertThat(listeners.size(), is(3)); + + server.stop(); + listeners = context.getEventListeners(); + assertThat(listeners.size(), is(1)); + assertThat(listeners.get(0).getClass(), is(TestListener2.class)); } public static class TestDecorator implements Decorator diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/Decorator.java b/jetty-util/src/main/java/org/eclipse/jetty/util/Decorator.java index 3346aa5f183..556451b56a0 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/Decorator.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/Decorator.java @@ -19,10 +19,7 @@ package org.eclipse.jetty.util; /** - * Interface for 3rd party libraries to decorate recently created objects in Jetty. - *

- * Most common use is weld/CDI. - *

+ * Interface to decorate objects created by the {@link DecoratedObjectFactory} */ public interface Decorator { diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/component/AbstractLifeCycle.java b/jetty-util/src/main/java/org/eclipse/jetty/util/component/AbstractLifeCycle.java index 75b9aa9f74f..96474dc22c0 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/component/AbstractLifeCycle.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/component/AbstractLifeCycle.java @@ -18,6 +18,9 @@ package org.eclipse.jetty.util.component; +import java.util.Collection; +import java.util.EventListener; +import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; import org.eclipse.jetty.util.Uptime; @@ -49,7 +52,7 @@ public abstract class AbstractLifeCycle implements LifeCycle public static final String STARTED = State.STARTED.toString(); public static final String STOPPING = State.STOPPING.toString(); - private final CopyOnWriteArrayList _listeners = new CopyOnWriteArrayList(); + private final List _eventListener = new CopyOnWriteArrayList<>(); private final Object _lock = new Object(); private volatile State _state = State.STOPPED; private long _stopTimeout = 30000; @@ -186,16 +189,39 @@ public abstract class AbstractLifeCycle implements LifeCycle return _state == State.FAILED; } - @Override - public void addLifeCycleListener(LifeCycle.Listener listener) + public List getEventListeners() { - _listeners.add(listener); + return _eventListener; + } + + public void setEventListeners(Collection eventListeners) + { + for (EventListener l : _eventListener) + { + if (!eventListeners.contains(l)) + removeEventListener(l); + } + + for (EventListener l : eventListeners) + { + if (!_eventListener.contains(l)) + addEventListener(l); + } } @Override - public void removeLifeCycleListener(LifeCycle.Listener listener) + public boolean addEventListener(EventListener listener) { - _listeners.remove(listener); + if (_eventListener.contains(listener)) + return false; + _eventListener.add(listener); + return true; + } + + @Override + public boolean removeEventListener(EventListener listener) + { + return _eventListener.remove(listener); } @ManagedAttribute(value = "Lifecycle State for this instance", readonly = true) @@ -226,8 +252,9 @@ public abstract class AbstractLifeCycle implements LifeCycle _state = State.STARTED; if (LOG.isDebugEnabled()) LOG.debug("STARTED @{}ms {}", Uptime.getUptime(), this); - for (Listener listener : _listeners) - listener.lifeCycleStarted(this); + for (EventListener listener : _eventListener) + if (listener instanceof Listener) + ((Listener)listener).lifeCycleStarted(this); } } @@ -236,8 +263,9 @@ public abstract class AbstractLifeCycle implements LifeCycle if (LOG.isDebugEnabled()) LOG.debug("STARTING {}", this); _state = State.STARTING; - for (Listener listener : _listeners) - listener.lifeCycleStarting(this); + for (EventListener listener : _eventListener) + if (listener instanceof Listener) + ((Listener)listener).lifeCycleStarting(this); } private void setStopping() @@ -245,8 +273,9 @@ public abstract class AbstractLifeCycle implements LifeCycle if (LOG.isDebugEnabled()) LOG.debug("STOPPING {}", this); _state = State.STOPPING; - for (Listener listener : _listeners) - listener.lifeCycleStopping(this); + for (EventListener listener : _eventListener) + if (listener instanceof Listener) + ((Listener)listener).lifeCycleStopping(this); } private void setStopped() @@ -256,10 +285,9 @@ public abstract class AbstractLifeCycle implements LifeCycle _state = State.STOPPED; if (LOG.isDebugEnabled()) LOG.debug("STOPPED {}", this); - for (Listener listener : _listeners) - { - listener.lifeCycleStopped(this); - } + for (EventListener listener : _eventListener) + if (listener instanceof Listener) + ((Listener)listener).lifeCycleStopped(this); } } @@ -268,9 +296,10 @@ public abstract class AbstractLifeCycle implements LifeCycle _state = State.FAILED; if (LOG.isDebugEnabled()) LOG.warn("FAILED " + this + ": " + th, th); - for (Listener listener : _listeners) + for (EventListener listener : _eventListener) { - listener.lifeCycleFailure(this, th); + if (listener instanceof Listener) + ((Listener)listener).lifeCycleFailure(this, th); } } diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/component/Container.java b/jetty-util/src/main/java/org/eclipse/jetty/util/component/Container.java index af5c52d2cf0..0b1de9bb5b6 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/component/Container.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/component/Container.java @@ -18,25 +18,28 @@ package org.eclipse.jetty.util.component; +import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; +import java.util.EventListener; +import java.util.List; /** * A Container */ public interface Container { - /** - * Add a bean. If the bean is-a {@link Listener}, then also do an implicit {@link #addEventListener(Listener)}. + * Add a bean. If the bean is-a {@link EventListener}, then also do an implicit {@link #addEventListener(EventListener)}. * * @param o the bean object to add * @return true if the bean was added, false if it was already present */ - public boolean addBean(Object o); + boolean addBean(Object o); /** * Adds the given bean, explicitly managing it or not. - * + * If the bean is-a {@link EventListener}, then also do an implicit {@link #addEventListener(EventListener)}. * @param o The bean object to add * @param managed whether to managed the lifecycle of the bean * @return true if the bean was added, false if it was already present @@ -47,7 +50,7 @@ public interface Container * @return the list of beans known to this aggregate * @see #getBean(Class) */ - public Collection getBeans(); + Collection getBeans(); /** * @param clazz the class of the beans @@ -56,39 +59,56 @@ public interface Container * @see #getBeans() * @see #getContainedBeans(Class) */ - public Collection getBeans(Class clazz); + Collection getBeans(Class clazz); + + /** + * @param clazz the class of the beans + * @param the Bean type + * @return a list of beans of the given class (or subclass), which may be cached/shared. + * @see #getBeans() + * @see #getContainedBeans(Class) + */ + default Collection getCachedBeans(Class clazz) + { + return getBeans(clazz); + } /** * @param clazz the class of the bean * @param the Bean type * @return the first bean of a specific class (or subclass), or null if no such bean exist */ - public T getBean(Class clazz); + T getBean(Class clazz); + /** * Removes the given bean. - * If the bean is-a {@link Listener}, then also do an implicit {@link #removeEventListener(Listener)}. + * If the bean is-a {@link EventListener}, then also do an implicit {@link #removeEventListener(EventListener)}. * * @param o the bean to remove * @return whether the bean was removed */ - public boolean removeBean(Object o); + boolean removeBean(Object o); /** * Add an event listener. - * + * EventListeners added by this method are also added as beans. * @param listener the listener to add + * @return true if the listener was added + * @see Container.Listener + * @see LifeCycle.Listener * @see Container#addBean(Object) */ - public void addEventListener(Listener listener); + boolean addEventListener(EventListener listener); /** * Remove an event listener. * * @param listener the listener to remove + * @return true if the listener was removed * @see Container#removeBean(Object) */ - public void removeEventListener(Listener listener); + boolean removeEventListener(EventListener listener); /** * Unmanages a bean already contained by this aggregate, so that it is not started/stopped/destroyed with this @@ -114,12 +134,35 @@ public interface Container */ boolean isManaged(Object bean); + /** + * @param clazz the class of the beans + * @param the Bean type + * @return the list of beans of the given class from the entire Container hierarchy + */ + Collection getContainedBeans(Class clazz); + + /** + * Get the beans added to the container that are EventListeners. + * This is essentially equivalent to getBeans(EventListener.class);, + * except that:
    + *
  • The result may be precomputed, so it can be more efficient
  • + *
  • The result is ordered by the order added.
  • + *
  • The result is immutable.
  • + *
+ * @see #getBeans(Class) + * @return An unmodifiable list of EventListener beans + */ + default List getEventListeners() + { + return Collections.unmodifiableList(new ArrayList<>(getBeans(EventListener.class))); + } + /** * A listener for Container events. * If an added bean implements this interface it will receive the events * for this container. */ - public interface Listener + interface Listener extends EventListener { void beanAdded(Container parent, Object child); @@ -131,14 +174,7 @@ public interface Container * If an added bean implements this interface, then it will * be added to all contained beans that are themselves Containers */ - public interface InheritedListener extends Listener + interface InheritedListener extends Listener { } - - /** - * @param clazz the class of the beans - * @param the Bean type - * @return the list of beans of the given class from the entire Container hierarchy - */ - public Collection getContainedBeans(Class clazz); } diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/component/ContainerLifeCycle.java b/jetty-util/src/main/java/org/eclipse/jetty/util/component/ContainerLifeCycle.java index b39fd4b5beb..c805018837d 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/component/ContainerLifeCycle.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/component/ContainerLifeCycle.java @@ -22,6 +22,7 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.EventListener; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -64,6 +65,10 @@ import org.eclipse.jetty.util.log.Logger; * If adding a bean that is shared between multiple {@link ContainerLifeCycle} instances, then it should be started * before being added, so it is unmanaged, or the API must be used to explicitly set it as unmanaged. *

+ * All {@link EventListener}s added via {@link #addEventListener(EventListener)} are also added as beans and all beans + * added via an {@link #addBean(Object)} method that are also {@link EventListener}s are added as listeners via a + * call to {@link #addEventListener(EventListener)}. + *

* This class also provides utility methods to dump deep structures of objects. * In the dump, the following symbols are used to indicate the type of contained object: *

@@ -340,18 +345,17 @@ public class ContainerLifeCycle extends AbstractLifeCycle implements Container,
 
         Bean newBean = new Bean(o);
 
-        // if the bean is a Listener
-        if (o instanceof Container.Listener)
-            addEventListener((Container.Listener)o);
-
         // Add the bean
         _beans.add(newBean);
 
-        // Tell existing listeners about the new bean
+        // Tell any existing listeners about the new bean
         for (Container.Listener l : _listeners)
-        {
             l.beanAdded(this, o);
-        }
+
+        // if the bean is an EventListener, then add it. Because we have already added it as a bean above, then
+        // addBean will not be called back.
+        if (o instanceof EventListener)
+            addEventListener((EventListener)o);
 
         try
         {
@@ -448,27 +452,62 @@ public class ContainerLifeCycle extends AbstractLifeCycle implements Container,
     }
 
     @Override
-    public void addEventListener(Container.Listener listener)
+    public boolean addEventListener(EventListener listener)
     {
-        if (_listeners.contains(listener))
-            return;
-
-        _listeners.add(listener);
-
-        // tell it about existing beans
-        for (Bean b : _beans)
+        // Has it already been added as a listener?
+        if (super.addEventListener(listener))
         {
-            listener.beanAdded(this, b._bean);
+            // If it is not yet a bean,
+            if (!contains(listener))
+                // add it as a bean, we will be called back to add it as an event listener, but it will have
+                // already been added, so we will not enter this branch.
+                addBean(listener);
 
-            // handle inheritance
-            if (listener instanceof InheritedListener && b.isManaged() && b._bean instanceof Container)
+            if (listener instanceof Container.Listener)
             {
-                if (b._bean instanceof ContainerLifeCycle)
-                    ((ContainerLifeCycle)b._bean).addBean(listener, false);
-                else
-                    ((Container)b._bean).addBean(listener);
+                Container.Listener cl = (Container.Listener)listener;
+                _listeners.add(cl);
+
+                // tell it about existing beans
+                for (Bean b : _beans)
+                {
+                    cl.beanAdded(this, b._bean);
+
+                    // handle inheritance
+                    if (listener instanceof InheritedListener && b.isManaged() && b._bean instanceof Container)
+                    {
+                        if (b._bean instanceof ContainerLifeCycle)
+                            ((ContainerLifeCycle)b._bean).addBean(listener, false);
+                        else
+                            ((Container)b._bean).addBean(listener);
+                    }
+                }
             }
+            return true;
         }
+        return false;
+    }
+
+    @Override
+    public boolean removeEventListener(EventListener listener)
+    {
+        if (super.removeEventListener(listener))
+        {
+            removeBean(listener);
+            if (_listeners.remove(listener))
+            {
+                // remove existing beans
+                for (Bean b : _beans)
+                {
+                    ((Container.Listener)listener).beanRemoved(this, b._bean);
+
+                    if (listener instanceof InheritedListener && b.isManaged() && b._bean instanceof Container)
+                        ((Container)b._bean).removeBean(listener);
+                }
+            }
+            return true;
+        }
+        return false;
     }
 
     /**
@@ -637,8 +676,9 @@ public class ContainerLifeCycle extends AbstractLifeCycle implements Container,
                 l.beanRemoved(this, bean._bean);
             }
 
-            if (bean._bean instanceof Container.Listener)
-                removeEventListener((Container.Listener)bean._bean);
+            // Remove event listeners, checking list here to avoid calling extended removeEventListener if already removed.
+            if (bean._bean instanceof EventListener && getEventListeners().contains(bean._bean))
+                removeEventListener((EventListener)bean._bean);
 
             // stop managed beans
             if (wasManaged && bean._bean instanceof LifeCycle)
@@ -661,22 +701,6 @@ public class ContainerLifeCycle extends AbstractLifeCycle implements Container,
         return false;
     }
 
-    @Override
-    public void removeEventListener(Container.Listener listener)
-    {
-        if (_listeners.remove(listener))
-        {
-            // remove existing beans
-            for (Bean b : _beans)
-            {
-                listener.beanRemoved(this, b._bean);
-
-                if (listener instanceof InheritedListener && b.isManaged() && b._bean instanceof Container)
-                    ((Container)b._bean).removeBean(listener);
-            }
-        }
-    }
-
     @Override
     public void setStopTimeout(long stopTimeout)
     {
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/component/LifeCycle.java b/jetty-util/src/main/java/org/eclipse/jetty/util/component/LifeCycle.java
index 58f4b9b8397..6eb4c936e1f 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/component/LifeCycle.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/component/LifeCycle.java
@@ -138,9 +138,9 @@ public interface LifeCycle
      */
     boolean isFailed();
 
-    void addLifeCycleListener(LifeCycle.Listener listener);
+    boolean addEventListener(EventListener listener);
 
-    void removeLifeCycleListener(LifeCycle.Listener listener);
+    boolean removeEventListener(EventListener listener);
 
     /**
      * Listener.
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/component/StopLifeCycle.java b/jetty-util/src/main/java/org/eclipse/jetty/util/component/StopLifeCycle.java
index 02d480c1e84..1839d7990af 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/component/StopLifeCycle.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/component/StopLifeCycle.java
@@ -33,7 +33,7 @@ public class StopLifeCycle extends AbstractLifeCycle implements LifeCycle.Listen
     public StopLifeCycle(LifeCycle lifecycle)
     {
         _lifecycle = lifecycle;
-        addLifeCycleListener(this);
+        addEventListener(this);
     }
 
     @Override
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/resource/Resource.java b/jetty-util/src/main/java/org/eclipse/jetty/util/resource/Resource.java
index 186b6cdad3c..c16c60b8429 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/resource/Resource.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/resource/Resource.java
@@ -482,6 +482,7 @@ public abstract class Resource implements ResourceFactory, Closeable
      * @param parent True if the parent directory should be included
      * @param query query params
      * @return String of HTML
+     * @throws IOException on failure to generate a list.
      */
     public String getListHTML(String base, boolean parent, String query) throws IOException
     {
diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/component/ContainerLifeCycleTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/component/ContainerLifeCycleTest.java
index f4994e8e2e7..3315a8c192e 100644
--- a/jetty-util/src/test/java/org/eclipse/jetty/util/component/ContainerLifeCycleTest.java
+++ b/jetty-util/src/test/java/org/eclipse/jetty/util/component/ContainerLifeCycleTest.java
@@ -443,6 +443,11 @@ public class ContainerLifeCycleTest
 
         c0.addBean(inherited);
 
+        assertEquals("listener", handled.poll());
+        assertEquals("added", operation.poll());
+        assertEquals(c0, parent.poll());
+        assertEquals(inherited, child.poll());
+
         assertEquals("inherited", handled.poll());
         assertEquals("added", operation.poll());
         assertEquals(c0, parent.poll());
@@ -453,11 +458,6 @@ public class ContainerLifeCycleTest
         assertEquals(c0, parent.poll());
         assertEquals(listener, child.poll());
 
-        assertEquals("listener", handled.poll());
-        assertEquals("added", operation.poll());
-        assertEquals(c0, parent.poll());
-        assertEquals(inherited, child.poll());
-
         assertEquals("inherited", handled.poll());
         assertEquals("added", operation.poll());
         assertEquals(c0, parent.poll());
diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/component/LifeCycleListenerNestedTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/component/LifeCycleListenerNestedTest.java
index 05842671974..024724fb248 100644
--- a/jetty-util/src/test/java/org/eclipse/jetty/util/component/LifeCycleListenerNestedTest.java
+++ b/jetty-util/src/test/java/org/eclipse/jetty/util/component/LifeCycleListenerNestedTest.java
@@ -161,7 +161,7 @@ public class LifeCycleListenerNestedTest
         {
             if (child instanceof LifeCycle)
             {
-                ((LifeCycle)child).addLifeCycleListener(this);
+                ((LifeCycle)child).addEventListener(this);
             }
         }
 
@@ -170,7 +170,7 @@ public class LifeCycleListenerNestedTest
         {
             if (child instanceof LifeCycle)
             {
-                ((LifeCycle)child).removeLifeCycleListener(this);
+                ((LifeCycle)child).removeEventListener(this);
             }
         }
     }
@@ -185,7 +185,7 @@ public class LifeCycleListenerNestedTest
         foo.addBean(barb);
 
         CapturingListener listener = new CapturingListener();
-        foo.addLifeCycleListener(listener);
+        foo.addEventListener(listener);
         if (workaround)
             foo.addEventListener(listener);
 
@@ -216,7 +216,7 @@ public class LifeCycleListenerNestedTest
         Foo foo = new Foo();
 
         CapturingListener listener = new CapturingListener();
-        foo.addLifeCycleListener(listener);
+        foo.addEventListener(listener);
         if (workaround)
             foo.addEventListener(listener);
 
@@ -254,7 +254,7 @@ public class LifeCycleListenerNestedTest
         Bar barb = new Bar("b");
 
         CapturingListener listener = new CapturingListener();
-        foo.addLifeCycleListener(listener);
+        foo.addEventListener(listener);
         if (workaround)
             foo.addEventListener(listener);
 
diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/component/LifeCycleListenerTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/component/LifeCycleListenerTest.java
index 651f3bfe5c0..2ee938352f0 100644
--- a/jetty-util/src/test/java/org/eclipse/jetty/util/component/LifeCycleListenerTest.java
+++ b/jetty-util/src/test/java/org/eclipse/jetty/util/component/LifeCycleListenerTest.java
@@ -36,7 +36,7 @@ public class LifeCycleListenerTest
     {
         TestLifeCycle lifecycle = new TestLifeCycle();
         TestListener listener = new TestListener();
-        lifecycle.addLifeCycleListener(listener);
+        lifecycle.addEventListener(listener);
 
         lifecycle.setCause(cause);
 
@@ -72,7 +72,7 @@ public class LifeCycleListenerTest
     {
         TestLifeCycle lifecycle = new TestLifeCycle();
         TestListener listener = new TestListener();
-        lifecycle.addLifeCycleListener(listener);
+        lifecycle.addEventListener(listener);
 
         // need to set the state to something other than stopped or stopping or
         // else
@@ -116,11 +116,11 @@ public class LifeCycleListenerTest
     {
         TestLifeCycle lifecycle = new TestLifeCycle();
         TestListener listener = new TestListener();
-        lifecycle.addLifeCycleListener(listener);
+        lifecycle.addEventListener(listener);
 
         lifecycle.start();
         assertTrue(listener.starting, "The starting event didn't occur");
-        lifecycle.removeLifeCycleListener(listener);
+        lifecycle.removeEventListener(listener);
         lifecycle.stop();
         assertFalse(listener.stopping, "The stopping event occurred");
     }
diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppContext.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppContext.java
index 7bdb0e1a387..e8b5f81c81d 100644
--- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppContext.java
+++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppContext.java
@@ -556,15 +556,6 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
         }
     }
 
-    /*
-     * @see org.eclipse.thread.AbstractLifeCycle#doStop()
-     */
-    @Override
-    protected void doStop() throws Exception
-    {
-        super.doStop();
-    }
-
     @Override
     public void destroy()
     {
@@ -957,7 +948,7 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
             new DumpableCollection("Configurations " + name, _configurations),
             new DumpableCollection("Handler attributes " + name, ((AttributesMap)getAttributes()).getAttributeEntrySet()),
             new DumpableCollection("Context attributes " + name, getServletContext().getAttributeEntrySet()),
-            new DumpableCollection("EventListeners " + this, Arrays.asList(getEventListeners())),
+            new DumpableCollection("EventListeners " + this, getEventListeners()),
             new DumpableCollection("Initparams " + name, getInitParams().entrySet())
         );
     }
@@ -1080,27 +1071,22 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
     }
 
     @Override
-    public void setEventListeners(EventListener[] eventListeners)
+    public boolean removeEventListener(EventListener listener)
     {
-        if (_sessionHandler != null)
-            _sessionHandler.clearEventListeners();
-
-        super.setEventListeners(eventListeners);
-    }
-
-    @Override
-    public void removeEventListener(EventListener listener)
-    {
-        super.removeEventListener(listener);
-        if ((listener instanceof HttpSessionActivationListener) ||
-            (listener instanceof HttpSessionAttributeListener) ||
-            (listener instanceof HttpSessionBindingListener) ||
-            (listener instanceof HttpSessionListener) ||
-            (listener instanceof HttpSessionIdListener))
+        if (super.removeEventListener(listener))
         {
-            if (_sessionHandler != null)
-                _sessionHandler.removeEventListener(listener);
+            if ((listener instanceof HttpSessionActivationListener) ||
+                (listener instanceof HttpSessionAttributeListener) ||
+                (listener instanceof HttpSessionBindingListener) ||
+                (listener instanceof HttpSessionListener) ||
+                (listener instanceof HttpSessionIdListener))
+            {
+                if (_sessionHandler != null)
+                    _sessionHandler.removeEventListener(listener);
+            }
+            return true;
         }
+        return false;
     }
 
     /**
diff --git a/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/WebAppContextTest.java b/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/WebAppContextTest.java
index 04f40e0f02d..56244812cca 100644
--- a/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/WebAppContextTest.java
+++ b/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/WebAppContextTest.java
@@ -90,7 +90,7 @@ public class WebAppContextTest
         server.setHandler(wac);
         wac.addEventListener(new MySessionListener());
 
-        Collection listeners = wac.getSessionHandler().getBeans(org.eclipse.jetty.webapp.WebAppContextTest.MySessionListener.class);
+        Collection listeners = wac.getSessionHandler().getBeans(MySessionListener.class);
         assertNotNull(listeners);
         assertEquals(1, listeners.size());
     }
diff --git a/jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/internal/JavaxWebSocketServerContainer.java b/jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/internal/JavaxWebSocketServerContainer.java
index a9cc4e484d0..9259526d1b2 100644
--- a/jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/internal/JavaxWebSocketServerContainer.java
+++ b/jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/internal/JavaxWebSocketServerContainer.java
@@ -99,7 +99,7 @@ public class JavaxWebSocketServerContainer extends JavaxWebSocketClientContainer
                 WebSocketComponents.ensureWebSocketComponents(servletContext),
                 coreClientSupplier);
             contextHandler.addManaged(container);
-            contextHandler.addLifeCycleListener(container);
+            contextHandler.addEventListener(container);
         }
         // Store a reference to the ServerContainer per - javax.websocket spec 1.0 final - section 6.4: Programmatic Server Deployment
         servletContext.setAttribute(JAVAX_WEBSOCKET_CONTAINER_ATTRIBUTE, container);
diff --git a/jetty-websocket/jetty-websocket-server/src/main/java/org/eclipse/jetty/websocket/server/JettyWebSocketServerContainer.java b/jetty-websocket/jetty-websocket-server/src/main/java/org/eclipse/jetty/websocket/server/JettyWebSocketServerContainer.java
index cb2b886e879..f9fa837f8d5 100644
--- a/jetty-websocket/jetty-websocket-server/src/main/java/org/eclipse/jetty/websocket/server/JettyWebSocketServerContainer.java
+++ b/jetty-websocket/jetty-websocket-server/src/main/java/org/eclipse/jetty/websocket/server/JettyWebSocketServerContainer.java
@@ -76,7 +76,7 @@ public class JettyWebSocketServerContainer extends ContainerLifeCycle implements
                 WebSocketComponents.ensureWebSocketComponents(servletContext), executor);
             servletContext.setAttribute(JETTY_WEBSOCKET_CONTAINER_ATTRIBUTE, container);
             contextHandler.addManaged(container);
-            contextHandler.addLifeCycleListener(container);
+            contextHandler.addEventListener(container);
         }
 
         return container;
@@ -112,7 +112,7 @@ public class JettyWebSocketServerContainer extends ContainerLifeCycle implements
         {
             factory = new JettyServerFrameHandlerFactory(this);
             contextHandler.addManaged(factory);
-            contextHandler.addLifeCycleListener(factory);
+            contextHandler.addEventListener(factory);
         }
         frameHandlerFactory = factory;
 
diff --git a/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/core/client/ClientUpgradeRequest.java b/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/core/client/ClientUpgradeRequest.java
index c1b6057e41f..659ec139ef6 100644
--- a/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/core/client/ClientUpgradeRequest.java
+++ b/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/core/client/ClientUpgradeRequest.java
@@ -48,7 +48,6 @@ import org.eclipse.jetty.http.HttpScheme;
 import org.eclipse.jetty.http.HttpStatus;
 import org.eclipse.jetty.http.HttpVersion;
 import org.eclipse.jetty.io.ByteBufferPool;
-import org.eclipse.jetty.io.Connection;
 import org.eclipse.jetty.io.EndPoint;
 import org.eclipse.jetty.util.Callback;
 import org.eclipse.jetty.util.QuotedStringTokenizer;
@@ -371,14 +370,8 @@ public abstract class ClientUpgradeRequest extends HttpRequest implements Respon
 
         HttpClient httpClient = wsClient.getHttpClient();
         WebSocketConnection wsConnection = newWebSocketConnection(endp, httpClient.getExecutor(), httpClient.getScheduler(), httpClient.getByteBufferPool(), coreSession);
-
-        for (Connection.Listener listener : wsClient.getBeans(Connection.Listener.class))
-        {
-            wsConnection.addListener(listener);
-        }
-
+        wsClient.getEventListeners().forEach(wsConnection::addEventListener);
         coreSession.setWebSocketConnection(wsConnection);
-
         notifyUpgradeListeners((listener) -> listener.onHandshakeResponse(this, response));
 
         // Now swap out the connection
diff --git a/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/core/server/internal/RFC6455Handshaker.java b/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/core/server/internal/RFC6455Handshaker.java
index 2ecd11ef599..dddacc09f9e 100644
--- a/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/core/server/internal/RFC6455Handshaker.java
+++ b/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/core/server/internal/RFC6455Handshaker.java
@@ -30,7 +30,6 @@ import org.eclipse.jetty.http.HttpMethod;
 import org.eclipse.jetty.http.HttpVersion;
 import org.eclipse.jetty.http.PreEncodedHttpField;
 import org.eclipse.jetty.io.ByteBufferPool;
-import org.eclipse.jetty.io.Connection;
 import org.eclipse.jetty.io.EndPoint;
 import org.eclipse.jetty.server.ConnectionFactory;
 import org.eclipse.jetty.server.Connector;
@@ -211,10 +210,7 @@ public final class RFC6455Handshaker implements Handshaker
         if (connection == null)
             throw new WebSocketException("not upgraded: no connection");
 
-        for (Connection.Listener listener : connector.getBeans(Connection.Listener.class))
-        {
-            connection.addListener(listener);
-        }
+        connector.getEventListeners().forEach(connection::addEventListener);
 
         coreSession.setWebSocketConnection(connection);
 
diff --git a/tests/test-integration/pom.xml b/tests/test-integration/pom.xml
index 565cb25e1e8..4168685fe5e 100644
--- a/tests/test-integration/pom.xml
+++ b/tests/test-integration/pom.xml
@@ -170,5 +170,10 @@
       ${project.version}
       test
     
+    
+      ch.qos.logback
+      logback-classic
+      1.2.3
+    
   
 
diff --git a/tests/test-integration/src/test/resources/jetty-logging.properties b/tests/test-integration/src/test/resources/jetty-logging.properties
index d79ba45bdd3..f076e496439 100644
--- a/tests/test-integration/src/test/resources/jetty-logging.properties
+++ b/tests/test-integration/src/test/resources/jetty-logging.properties
@@ -1,4 +1,5 @@
 org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
-org.eclipse.jetty.LEVEL=INFO
+#org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.Slf4jLog
+org.eclipse.jetty.LEVEL=WARN
 #org.eclipse.jetty.LEVEL=DEBUG
 #org.eclipse.jetty.websocket.LEVEL=DEBUG
diff --git a/tests/test-integration/src/test/resources/logback.xml b/tests/test-integration/src/test/resources/logback.xml
new file mode 100644
index 00000000000..4d184bd4589
--- /dev/null
+++ b/tests/test-integration/src/test/resources/logback.xml
@@ -0,0 +1,19 @@
+
+  
+    target/logs/jetty.txt
+    false
+    
+      %date %level [%thread] %logger{10} [%file:%line] %msg%n
+    
+  
+
+  
+    
+      %msg%n
+    
+  
+
+  
+    
+  
+
diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/TestHttpChannelCompleteListener.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/TestHttpChannelCompleteListener.java
index 7fb22f00007..8e2faa9e5ce 100644
--- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/TestHttpChannelCompleteListener.java
+++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/TestHttpChannelCompleteListener.java
@@ -26,7 +26,7 @@ import org.eclipse.jetty.server.Request;
 
 public class TestHttpChannelCompleteListener implements Listener
 {
-    private final AtomicReference _exitSynchronizer = new AtomicReference<>();
+    AtomicReference _exitSynchronizer = new AtomicReference<>();
 
     /**
      * @param exitSynchronizer the exitSynchronizer to set