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 7e1381e4904..25b6dbe6235 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 @@ -25,6 +25,7 @@ import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpURI; import org.eclipse.jetty.http.MetaData; +import org.eclipse.jetty.server.AbstractConnector; import org.eclipse.jetty.server.Authentication; import org.eclipse.jetty.server.HttpChannel; import org.eclipse.jetty.server.HttpChannelState; @@ -53,7 +54,7 @@ public class SpnegoAuthenticatorTest @Test public void testChallengeSentWithNoAuthorization() throws Exception { - HttpChannel channel = new HttpChannel(null, new HttpConfiguration(), null, null) + HttpChannel channel = new HttpChannel(new MockConnector(), new HttpConfiguration(), null, null) { @Override public Server getServer() @@ -89,7 +90,7 @@ public class SpnegoAuthenticatorTest @Test public void testChallengeSentWithUnhandledAuthorization() throws Exception { - HttpChannel channel = new HttpChannel(null, new HttpConfiguration(), null, null) + HttpChannel channel = new HttpChannel(new MockConnector(), new HttpConfiguration(), null, null) { @Override public Server getServer() @@ -124,4 +125,29 @@ 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; + } } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java b/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java index 46c18701b7e..f1425dde301 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java @@ -45,6 +45,7 @@ import org.eclipse.jetty.util.ProcessorUtils; import org.eclipse.jetty.util.StringUtil; 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.component.Graceful; @@ -154,6 +155,7 @@ public abstract class AbstractConnector extends ContainerLifeCycle implements Co private final Set _endpoints = Collections.newSetFromMap(new ConcurrentHashMap<>()); private final Set _immutableEndPoints = Collections.unmodifiableSet(_endpoints); private final Graceful.Shutdown _shutdown = new Graceful.Shutdown(); + private HttpChannel.Listener _httpChannelListeners = HttpChannel.NOOP_LISTENER; private CountDownLatch _stopping; private long _idleTimeout = 30000; private String _defaultProtocol; @@ -188,6 +190,23 @@ public abstract class AbstractConnector extends ContainerLifeCycle implements Co pool = _server.getBean(ByteBufferPool.class); _byteBufferPool = pool != null ? pool : new ArrayByteBufferPool(); + addEventListener(new Container.Listener() + { + @Override + public void beanAdded(Container parent, Object bean) + { + if (bean instanceof HttpChannel.Listener) + _httpChannelListeners = new HttpChannelListeners(getBeans(HttpChannel.Listener.class)); + } + + @Override + public void beanRemoved(Container parent, Object bean) + { + if (bean instanceof HttpChannel.Listener) + _httpChannelListeners = new HttpChannelListeners(getBeans(HttpChannel.Listener.class)); + } + }); + addBean(_server, false); addBean(_executor); if (executor == null) @@ -208,6 +227,24 @@ public abstract class AbstractConnector extends ContainerLifeCycle implements Co _acceptors = new Thread[acceptors]; } + /** + * Get the {@link HttpChannel.Listener}s added to the connector + * as a single combined Listener. + * This is equivalent to a listener that iterates over the individual + * listeners returned from getBeans(HttpChannel.Listener.class);, + * except that: + * @see #getBeans(Class) + * @return An unmodifiable list of EventListener beans + */ + public HttpChannel.Listener getHttpChannelListeners() + { + return _httpChannelListeners; + } + @Override public Server getServer() { 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 c036d746728..50d33efe7da 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 @@ -22,6 +22,7 @@ import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.util.ArrayList; +import java.util.EventListener; import java.util.List; import java.util.concurrent.Executor; import java.util.concurrent.TimeoutException; @@ -69,6 +70,7 @@ import org.eclipse.jetty.util.thread.Scheduler; */ public class HttpChannel implements Runnable, HttpOutput.Interceptor { + public static Listener NOOP_LISTENER = new Listener(){}; private static final Logger LOG = Log.getLogger(HttpChannel.class); private final AtomicLong _requests = new AtomicLong(); @@ -80,9 +82,11 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor private final HttpChannelState _state; private final Request _request; private final Response _response; + private final HttpChannel.Listener _combinedListener; + @Deprecated + private final List _transientListeners = new ArrayList<>(); private HttpFields _trailers; private final Supplier _trailerSupplier = () -> _trailers; - private final List _listeners; private MetaData.Response _committedMetaData; private RequestLog _requestLog; private long _oldIdleTimeout; @@ -103,13 +107,11 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor _request = new Request(this, newHttpInput(_state)); _response = new Response(this, newHttpOutput()); - _executor = connector == null ? null : connector.getServer().getThreadPool(); - _requestLog = connector == null ? null : connector.getServer().getRequestLog(); - - List listeners = new ArrayList<>(); - if (connector != null) - listeners.addAll(connector.getBeans(Listener.class)); - _listeners = listeners; + _executor = connector.getServer().getThreadPool(); + _requestLog = connector.getServer().getRequestLog(); + _combinedListener = (connector instanceof AbstractConnector) + ? ((AbstractConnector)connector).getHttpChannelListeners() + : NOOP_LISTENER; if (LOG.isDebugEnabled()) LOG.debug("new {} -> {},{},{}", @@ -139,14 +141,32 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor return _state; } + /** + * Add a transient Listener to the HttpChannel. + *

Listeners added by this method will only be notified + * if the HttpChannel has been constructed with an instance of + * {@link TransientListeners} as an {@link AbstractConnector} + * provided listener

+ *

Transient listeners are removed after every request cycle

+ * @param listener + * @return true if the listener was added. + */ + @Deprecated public boolean addListener(Listener listener) { - return _listeners.add(listener); + return _transientListeners.add(listener); } + @Deprecated public boolean removeListener(Listener listener) { - return _listeners.remove(listener); + return _transientListeners.remove(listener); + } + + @Deprecated + public List getTransientListeners() + { + return _transientListeners; } public long getBytesWritten() @@ -294,6 +314,7 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor _written = 0; _trailers = null; _oldIdleTimeout = 0; + _transientListeners.clear(); } public void onAsyncWaitForContent() @@ -555,17 +576,17 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor try { _request.setDispatcherType(type); - notifyBeforeDispatch(_request); + _combinedListener.onBeforeDispatch(_request); dispatchable.dispatch(); } catch (Throwable x) { - notifyDispatchFailure(_request, x); + _combinedListener.onDispatchFailure(_request, x); throw x; } finally { - notifyAfterDispatch(_request); + _combinedListener.onAfterDispatch(_request); _request.setDispatcherType(null); } } @@ -688,7 +709,7 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor _request.setSecure(HttpScheme.HTTPS.is(request.getURI().getScheme())); - notifyRequestBegin(_request); + _combinedListener.onRequestBegin(_request); if (LOG.isDebugEnabled()) LOG.debug("REQUEST for {} on {}{}{} {} {}{}{}", request.getURIString(), this, System.lineSeparator(), @@ -700,7 +721,7 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor { if (LOG.isDebugEnabled()) LOG.debug("onContent {} {}", this, content); - notifyRequestContent(_request, content.getByteBuffer()); + _combinedListener.onRequestContent(_request, content.getByteBuffer()); return _request.getHttpInput().addContent(content); } @@ -708,7 +729,7 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor { if (LOG.isDebugEnabled()) LOG.debug("onContentComplete {}", this); - notifyRequestContentEnd(_request); + _combinedListener.onRequestContentEnd(_request); return false; } @@ -717,7 +738,7 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor if (LOG.isDebugEnabled()) LOG.debug("onTrailers {} {}", this, trailers); _trailers = trailers; - notifyRequestTrailers(_request); + _combinedListener.onRequestTrailers(_request); } public boolean onRequestComplete() @@ -725,7 +746,7 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor if (LOG.isDebugEnabled()) LOG.debug("onRequestComplete {}", this); boolean result = _request.getHttpInput().eof(); - notifyRequestEnd(_request); + _combinedListener.onRequestEnd(_request); return result; } @@ -756,7 +777,7 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor setIdleTimeout(_oldIdleTimeout); _request.onCompleted(); - notifyComplete(_request); + _combinedListener.onComplete(_request); _transport.onCompleted(); } @@ -772,7 +793,7 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor if (status < HttpStatus.BAD_REQUEST_400 || status > 599) failure = new BadMessageException(HttpStatus.BAD_REQUEST_400, reason, failure); - notifyRequestFailure(_request, failure); + _combinedListener.onRequestFailure(_request, failure); Action action; try @@ -844,7 +865,7 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor ? new Send100Callback(callback) : new SendCallback(callback, content, true, complete); - notifyResponseBegin(_request); + _combinedListener.onResponseBegin(_request); // committing write _transport.send(_request.getMetaData(), response, content, complete, committed); @@ -970,7 +991,7 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor { if (_state.abortResponse()) { - notifyResponseFailure(_request, failure); + _combinedListener.onResponseFailure(_request, failure); _transport.abort(failure); } } @@ -985,84 +1006,9 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor throw new UnsupportedOperationException("Tunnelling not supported"); } - private void notifyRequestBegin(Request request) - { - notifyEvent1(listener -> listener::onRequestBegin, request); - } - - private void notifyBeforeDispatch(Request request) - { - notifyEvent1(listener -> listener::onBeforeDispatch, request); - } - - private void notifyDispatchFailure(Request request, Throwable failure) - { - notifyEvent2(listener -> listener::onDispatchFailure, request, failure); - } - - private void notifyAfterDispatch(Request request) - { - notifyEvent1(listener -> listener::onAfterDispatch, request); - } - - private void notifyRequestContent(Request request, ByteBuffer content) - { - notifyEvent2(listener -> listener::onRequestContent, request, content); - } - - private void notifyRequestContentEnd(Request request) - { - notifyEvent1(listener -> listener::onRequestContentEnd, request); - } - - private void notifyRequestTrailers(Request request) - { - notifyEvent1(listener -> listener::onRequestTrailers, request); - } - - private void notifyRequestEnd(Request request) - { - notifyEvent1(listener -> listener::onRequestEnd, request); - } - - private void notifyRequestFailure(Request request, Throwable failure) - { - notifyEvent2(listener -> listener::onRequestFailure, request, failure); - } - - private void notifyResponseBegin(Request request) - { - notifyEvent1(listener -> listener::onResponseBegin, request); - } - - private void notifyResponseCommit(Request request) - { - notifyEvent1(listener -> listener::onResponseCommit, request); - } - - private void notifyResponseContent(Request request, ByteBuffer content) - { - notifyEvent2(listener -> listener::onResponseContent, request, content); - } - - private void notifyResponseEnd(Request request) - { - notifyEvent1(listener -> listener::onResponseEnd, request); - } - - private void notifyResponseFailure(Request request, Throwable failure) - { - notifyEvent2(listener -> listener::onResponseFailure, request, failure); - } - - private void notifyComplete(Request request) - { - notifyEvent1(listener -> listener::onComplete, request); - } - private void notifyEvent1(Function> function, Request request) { - for (Listener listener : _listeners) + for (Listener listener : _transientListeners) { try { @@ -1077,7 +1023,7 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor private void notifyEvent2(Function> function, Request request, ByteBuffer content) { - for (Listener listener : _listeners) + for (Listener listener : _transientListeners) { ByteBuffer view = content.slice(); try @@ -1093,7 +1039,7 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor private void notifyEvent2(Function> function, Request request, Throwable failure) { - for (Listener listener : _listeners) + for (Listener listener : _transientListeners) { try { @@ -1129,8 +1075,13 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor *

Listener methods are invoked synchronously from the thread that is * performing the request processing, and they should not call blocking code * (otherwise the request processing will be blocked as well).

+ *

Listener instances that are set as a bean on the {@link Connector} are + * efficiently added to {@link HttpChannel}. If additional listeners are added + * using the deprecated {@link HttpChannel#addListener(Listener)}

method, + * then an instance of {@link TransientListeners} must be added to the connector + * in order for them to be invoked. */ - public interface Listener + public interface Listener extends EventListener { /** * Invoked just after the HTTP request line and headers have been parsed. @@ -1300,11 +1251,11 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor _response.getHttpOutput().closed(); super.succeeded(); if (_commit) - notifyResponseCommit(_request); + _combinedListener.onResponseCommit(_request); if (_length > 0) - notifyResponseContent(_request, _content); + _combinedListener.onResponseContent(_request, _content); if (_complete && _state.completeResponse()) - notifyResponseEnd(_request); + _combinedListener.onResponseEnd(_request); } @Override @@ -1357,4 +1308,102 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor super.failed(new IllegalStateException()); } } + + /** + * A Listener instance that can be added as a bean to {@link AbstractConnector} so that + * the listeners obtained from HttpChannel{@link #getTransientListeners()} + */ + @Deprecated + public static class TransientListeners implements Listener + { + @Override + public void onRequestBegin(Request request) + { + request.getHttpChannel().notifyEvent1(listener -> listener::onRequestBegin, request); + } + + @Override + public void onBeforeDispatch(Request request) + { + request.getHttpChannel().notifyEvent1(listener -> listener::onBeforeDispatch, request); + } + + @Override + public void onDispatchFailure(Request request, Throwable failure) + { + request.getHttpChannel().notifyEvent2(listener -> listener::onDispatchFailure, request, failure); + } + + @Override + public void onAfterDispatch(Request request) + { + request.getHttpChannel().notifyEvent1(listener -> listener::onAfterDispatch, request); + } + + @Override + public void onRequestContent(Request request, ByteBuffer content) + { + request.getHttpChannel().notifyEvent2(listener -> listener::onRequestContent, request, content); + } + + @Override + public void onRequestContentEnd(Request request) + { + request.getHttpChannel().notifyEvent1(listener -> listener::onRequestContentEnd, request); + } + + @Override + public void onRequestTrailers(Request request) + { + request.getHttpChannel().notifyEvent1(listener -> listener::onRequestTrailers, request); + } + + @Override + public void onRequestEnd(Request request) + { + request.getHttpChannel().notifyEvent1(listener -> listener::onRequestEnd, request); + } + + @Override + public void onRequestFailure(Request request, Throwable failure) + { + request.getHttpChannel().notifyEvent2(listener -> listener::onRequestFailure, request, failure); + } + + @Override + public void onResponseBegin(Request request) + { + request.getHttpChannel().notifyEvent1(listener -> listener::onResponseBegin, request); + } + + @Override + public void onResponseCommit(Request request) + { + request.getHttpChannel().notifyEvent1(listener -> listener::onResponseCommit, request); + } + + @Override + public void onResponseContent(Request request, ByteBuffer content) + { + request.getHttpChannel().notifyEvent2(listener -> listener::onResponseContent, request, content); + } + + @Override + public void onResponseEnd(Request request) + { + request.getHttpChannel().notifyEvent1(listener -> listener::onResponseEnd, request); + } + + @Override + public void onResponseFailure(Request request, Throwable failure) + { + request.getHttpChannel().notifyEvent2(listener -> listener::onResponseFailure, request, failure); + } + + @Override + public void onComplete(Request request) + { + request.getHttpChannel().notifyEvent1(listener -> listener::onComplete, request); + } + } } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelListeners.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelListeners.java new file mode 100644 index 00000000000..281c7f5eb04 --- /dev/null +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelListeners.java @@ -0,0 +1,286 @@ +// +// ======================================================================== +// 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 java.util.Collection; + +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; + +/** + * A {@link HttpChannel.Listener} that holds a collection of + * other {@link HttpChannel.Listener} instances that are efficiently + * invoked without iteration. + * @see AbstractConnector + */ +public class HttpChannelListeners implements HttpChannel.Listener +{ + static final Logger LOG = Log.getLogger(HttpChannel.class); + public static HttpChannel.Listener NOOP = new HttpChannel.Listener() {}; + + private final NotifyRequest onRequestBegin; + private final NotifyRequest onBeforeDispatch; + private final NotifyFailure onDispatchFailure; + private final NotifyRequest onAfterDispatch; + private final NotifyContent onRequestContent; + private final NotifyRequest onRequestContentEnd; + private final NotifyRequest onRequestTrailers; + private final NotifyRequest onRequestEnd; + private final NotifyFailure onRequestFailure; + private final NotifyRequest onResponseBegin; + private final NotifyRequest onResponseCommit; + private final NotifyContent onResponseContent; + private final NotifyRequest onResponseEnd; + private final NotifyFailure onResponseFailure; + private final NotifyRequest onComplete; + + public HttpChannelListeners(Collection listeners) + { + try + { + NotifyRequest onRequestBegin = NotifyRequest.NOOP; + NotifyRequest onBeforeDispatch = NotifyRequest.NOOP; + NotifyFailure onDispatchFailure = NotifyFailure.NOOP; + NotifyRequest onAfterDispatch = NotifyRequest.NOOP; + NotifyContent onRequestContent = NotifyContent.NOOP; + NotifyRequest onRequestContentEnd = NotifyRequest.NOOP; + NotifyRequest onRequestTrailers = NotifyRequest.NOOP; + NotifyRequest onRequestEnd = NotifyRequest.NOOP; + NotifyFailure onRequestFailure = NotifyFailure.NOOP; + NotifyRequest onResponseBegin = NotifyRequest.NOOP; + NotifyRequest onResponseCommit = NotifyRequest.NOOP; + NotifyContent onResponseContent = NotifyContent.NOOP; + NotifyRequest onResponseEnd = NotifyRequest.NOOP; + NotifyFailure onResponseFailure = NotifyFailure.NOOP; + NotifyRequest onComplete = NotifyRequest.NOOP; + + for (HttpChannel.Listener listener : listeners) + { + if (!listener.getClass().getMethod("onRequestBegin", Request.class).isDefault()) + onRequestBegin = combine(onRequestBegin, listener::onRequestBegin); + if (!listener.getClass().getMethod("onBeforeDispatch", Request.class).isDefault()) + onBeforeDispatch = combine(onBeforeDispatch, listener::onBeforeDispatch); + if (!listener.getClass().getMethod("onDispatchFailure", Request.class, Throwable.class).isDefault()) + onDispatchFailure = combine(onDispatchFailure, listener::onDispatchFailure); + if (!listener.getClass().getMethod("onAfterDispatch", Request.class).isDefault()) + onAfterDispatch = combine(onAfterDispatch, listener::onAfterDispatch); + if (!listener.getClass().getMethod("onRequestContent", Request.class, ByteBuffer.class).isDefault()) + onRequestContent = combine(onRequestContent, listener::onRequestContent); + if (!listener.getClass().getMethod("onRequestContentEnd", Request.class).isDefault()) + onRequestContentEnd = combine(onRequestContentEnd, listener::onRequestContentEnd); + if (!listener.getClass().getMethod("onRequestTrailers", Request.class).isDefault()) + onRequestTrailers = combine(onRequestTrailers, listener::onRequestTrailers); + if (!listener.getClass().getMethod("onRequestEnd", Request.class).isDefault()) + onRequestEnd = combine(onRequestEnd, listener::onRequestEnd); + if (!listener.getClass().getMethod("onRequestFailure", Request.class, Throwable.class).isDefault()) + onRequestFailure = combine(onRequestFailure, listener::onRequestFailure); + if (!listener.getClass().getMethod("onResponseBegin", Request.class).isDefault()) + onResponseBegin = combine(onResponseBegin, listener::onResponseBegin); + if (!listener.getClass().getMethod("onResponseCommit", Request.class).isDefault()) + onResponseCommit = combine(onResponseCommit, listener::onResponseCommit); + if (!listener.getClass().getMethod("onResponseContent", Request.class, ByteBuffer.class).isDefault()) + onResponseContent = combine(onResponseContent, listener::onResponseContent); + if (!listener.getClass().getMethod("onResponseEnd", Request.class).isDefault()) + onResponseEnd = combine(onResponseEnd, listener::onResponseEnd); + if (!listener.getClass().getMethod("onResponseFailure", Request.class, Throwable.class).isDefault()) + onResponseFailure = combine(onResponseFailure, listener::onResponseFailure); + if (!listener.getClass().getMethod("onComplete", Request.class).isDefault()) + onComplete = combine(onComplete, listener::onComplete); + } + + this.onRequestBegin = onRequestBegin; + this.onBeforeDispatch = onBeforeDispatch; + this.onDispatchFailure = onDispatchFailure; + this.onAfterDispatch = onAfterDispatch; + this.onRequestContent = onRequestContent; + this.onRequestContentEnd = onRequestContentEnd; + this.onRequestTrailers = onRequestTrailers; + this.onRequestEnd = onRequestEnd; + this.onRequestFailure = onRequestFailure; + this.onResponseBegin = onResponseBegin; + this.onResponseCommit = onResponseCommit; + this.onResponseContent = onResponseContent; + this.onResponseEnd = onResponseEnd; + this.onResponseFailure = onResponseFailure; + this.onComplete = onComplete; + } + catch (Exception e) + { + throw new RuntimeException(e); + } + } + + @Override + public void onRequestBegin(Request request) + { + onRequestBegin.onRequest(request); + } + + @Override + public void onBeforeDispatch(Request request) + { + onBeforeDispatch.onRequest(request); + } + + @Override + public void onDispatchFailure(Request request, Throwable failure) + { + onDispatchFailure.onFailure(request, failure); + } + + @Override + public void onAfterDispatch(Request request) + { + onAfterDispatch.onRequest(request); + } + + @Override + public void onRequestContent(Request request, ByteBuffer content) + { + onRequestContent.onContent(request, content); + } + + @Override + public void onRequestContentEnd(Request request) + { + onRequestContentEnd.onRequest(request); + } + + @Override + public void onRequestTrailers(Request request) + { + onRequestTrailers.onRequest(request); + } + + @Override + public void onRequestEnd(Request request) + { + onRequestEnd.onRequest(request); + } + + @Override + public void onRequestFailure(Request request, Throwable failure) + { + onRequestFailure.onFailure(request, failure); + } + + @Override + public void onResponseBegin(Request request) + { + onResponseBegin.onRequest(request); + } + + @Override + public void onResponseCommit(Request request) + { + onResponseCommit.onRequest(request); + } + + @Override + public void onResponseContent(Request request, ByteBuffer content) + { + onResponseContent.onContent(request, content); + } + + @Override + public void onResponseEnd(Request request) + { + onResponseEnd.onRequest(request); + } + + @Override + public void onResponseFailure(Request request, Throwable failure) + { + onResponseFailure.onFailure(request, failure); + } + + @Override + public void onComplete(Request request) + { + onComplete.onRequest(request); + } + + private interface NotifyRequest + { + void onRequest(Request request); + + NotifyRequest NOOP = request -> + { + }; + } + + private interface NotifyFailure + { + void onFailure(Request request, Throwable failure); + + NotifyFailure NOOP = (request, failure) -> + { + }; + } + + private interface NotifyContent + { + void onContent(Request request, ByteBuffer content); + + NotifyContent NOOP = (request, content) -> + { + }; + } + + private static NotifyRequest combine(NotifyRequest first, NotifyRequest second) + { + if (first == NotifyRequest.NOOP) + return second; + if (second == NotifyRequest.NOOP) + return first; + return request -> + { + first.onRequest(request); + second.onRequest(request); + }; + } + + private static NotifyFailure combine(NotifyFailure first, NotifyFailure second) + { + if (first == NotifyFailure.NOOP) + return second; + if (second == NotifyFailure.NOOP) + return first; + return (request, throwable) -> + { + first.onFailure(request, throwable); + second.onFailure(request, throwable); + }; + } + + private static NotifyContent combine(NotifyContent first, NotifyContent second) + { + if (first == NotifyContent.NOOP) + return (request, content) -> second.onContent(request, content.slice()); + if (second == NotifyContent.NOOP) + return (request, content) -> first.onContent(request, content.slice()); + return (request, content) -> + { + content = content.slice(); + first.onContent(request, content); + second.onContent(request, content); + }; + } +} diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java index 54094f43329..55444641720 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java @@ -1863,6 +1863,7 @@ public class Request implements HttpServletRequest _remote = null; _sessions = null; _input.recycle(); + _requestAttributeListeners.clear(); } /* diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpChannelEventTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpChannelEventTest.java index 7dbd89e7a94..8adab6bf92f 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpChannelEventTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpChannelEventTest.java @@ -240,6 +240,37 @@ public class HttpChannelEventTest assertThat(elapsed.get(), Matchers.greaterThan(0L)); } + @Test + public void testTransientListener() throws Exception + { + start(new TestHandler()); + + CountDownLatch latch = new CountDownLatch(1); + connector.addBean(new HttpChannel.TransientListeners()); + connector.addBean(new HttpChannel.Listener() + { + @Override + public void onRequestBegin(Request request) + { + request.getHttpChannel().addListener(new HttpChannel.Listener() + { + @Override + public void onComplete(Request request) + { + latch.countDown(); + } + }); + } + }); + + HttpTester.Request request = HttpTester.newRequest(); + request.setHeader("Host", "localhost"); + HttpTester.Response response = HttpTester.parseResponse(connector.getResponse(request.toString(), 5, TimeUnit.SECONDS)); + + assertEquals(HttpStatus.OK_200, response.getStatus()); + assertTrue(latch.await(5, TimeUnit.SECONDS)); + } + private static class TestHandler extends AbstractHandler.ErrorDispatchHandler { @Override diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpInputAsyncStateTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpInputAsyncStateTest.java index fcabf1acfe9..a537317f7f9 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpInputAsyncStateTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpInputAsyncStateTest.java @@ -95,7 +95,7 @@ public class HttpInputAsyncStateTest public void before() { _noReadInDataAvailable = false; - _in = new HttpInput(new HttpChannelState(new HttpChannel(null, new HttpConfiguration(), null, null) + _in = new HttpInput(new HttpChannelState(new HttpChannel(new MockConnector(), new HttpConfiguration(), null, null) { @Override public void onAsyncWaitForContent() diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpInputTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpInputTest.java index c2b43ed0954..fa9fa1a25df 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpInputTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpInputTest.java @@ -92,7 +92,7 @@ public class HttpInputTest @BeforeEach public void before() { - _in = new HttpInput(new HttpChannelState(new HttpChannel(null, new HttpConfiguration(), null, null) + _in = new HttpInput(new HttpChannelState(new HttpChannel(new MockConnector(), new HttpConfiguration(), null, null) { @Override public void onAsyncWaitForContent() diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpWriterTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpWriterTest.java index 69a3dd171bb..c2a54f8de30 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpWriterTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpWriterTest.java @@ -45,7 +45,7 @@ public class HttpWriterTest final ByteBufferPool pool = new ArrayByteBufferPool(); - HttpChannel channel = new HttpChannel(null, new HttpConfiguration(), null, null) + HttpChannel channel = new HttpChannel(new MockConnector(), new HttpConfiguration(), null, null) { @Override public ByteBufferPool getByteBufferPool() diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/MockConnector.java b/jetty-server/src/test/java/org/eclipse/jetty/server/MockConnector.java new file mode 100644 index 00000000000..847bc34b7f9 --- /dev/null +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/MockConnector.java @@ -0,0 +1,46 @@ +// +// ======================================================================== +// 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.io.IOException; + +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; + } +} 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 f348e95dc78..af5c52d2cf0 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 @@ -52,7 +52,7 @@ public interface Container /** * @param clazz the class of the beans * @param the Bean type - * @return the list of beans of the given class (or subclass) + * @return a list of beans of the given class (or subclass) * @see #getBeans() * @see #getContainedBeans(Class) */ diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractClusteredInvalidationSessionTest.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractClusteredInvalidationSessionTest.java index ecce32321af..e0af754ec22 100644 --- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractClusteredInvalidationSessionTest.java +++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractClusteredInvalidationSessionTest.java @@ -65,8 +65,8 @@ public abstract class AbstractClusteredInvalidationSessionTest extends AbstractT TestServer server1 = new TestServer(0, maxInactiveInterval, scavengeInterval, cacheFactory1, storeFactory1); ServletContextHandler context = server1.addContext(contextPath); context.addServlet(TestServlet.class, servletMapping); - TestContextScopeListener scopeListener = new TestContextScopeListener(); - context.addEventListener(scopeListener); + TestHttpChannelCompleteListener scopeListener = new TestHttpChannelCompleteListener(); + server1.getServerConnector().addBean(scopeListener); try { diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractClusteredSessionScavengingTest.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractClusteredSessionScavengingTest.java index d812834eb30..06bf2f6edc9 100644 --- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractClusteredSessionScavengingTest.java +++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractClusteredSessionScavengingTest.java @@ -77,8 +77,8 @@ public abstract class AbstractClusteredSessionScavengingTest extends AbstractTes TestServlet servlet1 = new TestServlet(); ServletHolder holder1 = new ServletHolder(servlet1); ServletContextHandler context = server1.addContext(contextPath); - TestContextScopeListener scopeListener = new TestContextScopeListener(); - context.addEventListener(scopeListener); + TestHttpChannelCompleteListener scopeListener = new TestHttpChannelCompleteListener(); + server1.getServerConnector().addBean(scopeListener); TestSessionListener listener1 = new TestSessionListener(); context.getSessionHandler().addEventListener(listener1); context.addServlet(holder1, servletMapping); @@ -96,8 +96,8 @@ public abstract class AbstractClusteredSessionScavengingTest extends AbstractTes ((AbstractSessionDataStoreFactory)storeFactory2).setSavePeriodSec(0); //always save when the session exits TestServer server2 = new TestServer(0, maxInactivePeriod, scavengePeriod, cacheFactory2, storeFactory2); ServletContextHandler context2 = server2.addContext(contextPath); - TestContextScopeListener scopeListener2 = new TestContextScopeListener(); - context2.addEventListener(scopeListener2); + TestHttpChannelCompleteListener scopeListener2 = new TestHttpChannelCompleteListener(); + server2.getServerConnector().addBean(scopeListener2); context2.addServlet(TestServlet.class, servletMapping); SessionHandler m2 = context2.getSessionHandler(); diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractWebAppObjectInSessionTest.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractWebAppObjectInSessionTest.java index 31029113ac2..7a9af4b985d 100644 --- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractWebAppObjectInSessionTest.java +++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractWebAppObjectInSessionTest.java @@ -23,7 +23,6 @@ import java.io.FileOutputStream; import java.io.FileWriter; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; - import javax.servlet.http.HttpServletResponse; import org.eclipse.jetty.client.HttpClient; @@ -104,8 +103,8 @@ public abstract class AbstractWebAppObjectInSessionTest extends AbstractTestBase TestServer server1 = new TestServer(0, TestServer.DEFAULT_MAX_INACTIVE, TestServer.DEFAULT_SCAVENGE_SEC, cacheFactory, storeFactory); WebAppContext wac1 = server1.addWebAppContext(warDir.getCanonicalPath(), contextPath); - TestContextScopeListener scopeListener = new TestContextScopeListener(); - wac1.addEventListener(scopeListener); + TestHttpChannelCompleteListener scopeListener = new TestHttpChannelCompleteListener(); + server1.getServerConnector().addBean(scopeListener); wac1.addServlet(WebAppObjectInSessionServlet.class.getName(), servletMapping); try diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/TestContextScopeListener.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/TestContextScopeListener.java deleted file mode 100644 index 99f4d0e13a2..00000000000 --- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/TestContextScopeListener.java +++ /dev/null @@ -1,76 +0,0 @@ -// -// ======================================================================== -// 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.session; - -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.atomic.AtomicReference; - -import org.eclipse.jetty.server.HttpChannel.Listener; -import org.eclipse.jetty.server.HttpChannelState; -import org.eclipse.jetty.server.Request; -import org.eclipse.jetty.server.handler.ContextHandler.Context; -import org.eclipse.jetty.server.handler.ContextHandler.ContextScopeListener; - -public class TestContextScopeListener implements ContextScopeListener -{ - AtomicReference _exitSynchronizer = new AtomicReference<>(); - boolean listenerAdded = false; - - /** - * @return the exitSynchronizer - */ - public CountDownLatch getExitSynchronizer() - { - return _exitSynchronizer.get(); - } - - /** - * @param exitSynchronizer the exitSynchronizer to set - */ - public void setExitSynchronizer(CountDownLatch exitSynchronizer) - { - _exitSynchronizer.set(exitSynchronizer); - } - - @Override - public void enterScope(Context context, org.eclipse.jetty.server.Request request, Object reason) - { - //noop - } - - @Override - public void exitScope(final Context context, final org.eclipse.jetty.server.Request request) - { - if (request != null && !listenerAdded) - { - listenerAdded = true; - request.getHttpChannel().addListener(new Listener() - { - @Override - public void onComplete(Request request) - { - Listener.super.onComplete(request); - if (_exitSynchronizer.get() != null) - _exitSynchronizer.get().countDown(); - } - - }); - } - } -} 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 new file mode 100644 index 00000000000..7fb22f00007 --- /dev/null +++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/TestHttpChannelCompleteListener.java @@ -0,0 +1,45 @@ +// +// ======================================================================== +// 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.session; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicReference; + +import org.eclipse.jetty.server.HttpChannel.Listener; +import org.eclipse.jetty.server.Request; + +public class TestHttpChannelCompleteListener implements Listener +{ + private final AtomicReference _exitSynchronizer = new AtomicReference<>(); + + /** + * @param exitSynchronizer the exitSynchronizer to set + */ + public void setExitSynchronizer(CountDownLatch exitSynchronizer) + { + _exitSynchronizer.set(exitSynchronizer); + } + + @Override + public void onComplete(Request request) + { + if (_exitSynchronizer.get() != null) + _exitSynchronizer.get().countDown(); + } +} diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/TestServer.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/TestServer.java index a8e6be63f10..91299fa8778 100644 --- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/TestServer.java +++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/TestServer.java @@ -20,6 +20,7 @@ package org.eclipse.jetty.server.session; import org.eclipse.jetty.server.NetworkConnector; import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.ServerConnector; import org.eclipse.jetty.server.SessionIdManager; import org.eclipse.jetty.server.handler.ContextHandlerCollection; import org.eclipse.jetty.servlet.ServletContextHandler; @@ -93,6 +94,11 @@ public class TestServer return h; } + public ServerConnector getServerConnector() + { + return _server.getBean(ServerConnector.class); + } + public void start() throws Exception { // server -> contexts collection -> context handler -> session handler -> servlet handler diff --git a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/AsyncTest.java b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/AsyncTest.java index 9985ba0e3c8..2807faeb48d 100644 --- a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/AsyncTest.java +++ b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/AsyncTest.java @@ -22,7 +22,6 @@ import java.io.IOException; import java.lang.reflect.Proxy; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; - import javax.servlet.AsyncContext; import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; @@ -65,8 +64,8 @@ public class AsyncTest String mapping = "/server"; ServletContextHandler contextHandler = server.addContext(contextPath); - TestContextScopeListener scopeListener = new TestContextScopeListener(); - contextHandler.addEventListener(scopeListener); + TestHttpChannelCompleteListener scopeListener = new TestHttpChannelCompleteListener(); + server.getServerConnector().addBean(scopeListener); TestServlet servlet = new TestServlet(); ServletHolder holder = new ServletHolder(servlet); contextHandler.addServlet(holder, mapping); @@ -117,8 +116,8 @@ public class AsyncTest String mapping = "/server"; ServletContextHandler contextHandler = server.addContext(contextPath); - TestContextScopeListener scopeListener = new TestContextScopeListener(); - contextHandler.addEventListener(scopeListener); + TestHttpChannelCompleteListener scopeListener = new TestHttpChannelCompleteListener(); + server.getServerConnector().addBean(scopeListener); TestServlet servlet = new TestServlet(); ServletHolder holder = new ServletHolder(servlet); contextHandler.addServlet(holder, mapping); @@ -167,8 +166,8 @@ public class AsyncTest TestServer server = new TestServer(0, -1, -1, cacheFactory, storeFactory); ServletContextHandler contextA = server.addContext("/ctxA"); - TestContextScopeListener scopeListener = new TestContextScopeListener(); - contextA.addEventListener(scopeListener); //just pick one of the contexts to register the listener + TestHttpChannelCompleteListener scopeListener = new TestHttpChannelCompleteListener(); + server.getServerConnector().addBean(scopeListener); //just pick one of the contexts to register the listener CrossContextServlet ccServlet = new CrossContextServlet(); ServletHolder ccHolder = new ServletHolder(ccServlet); contextA.addServlet(ccHolder, "/*"); @@ -224,8 +223,8 @@ public class AsyncTest String mapping = "/server"; ServletContextHandler contextHandler = server.addContext(contextPath); - TestContextScopeListener scopeListener = new TestContextScopeListener(); - contextHandler.addEventListener(scopeListener); + TestHttpChannelCompleteListener scopeListener = new TestHttpChannelCompleteListener(); + server.getServerConnector().addBean(scopeListener); TestServlet servlet = new TestServlet(); ServletHolder holder = new ServletHolder(servlet); @@ -277,8 +276,8 @@ public class AsyncTest TestServer server = new TestServer(0, -1, -1, cacheFactory, storeFactory); ServletContextHandler contextA = server.addContext("/ctxA"); - TestContextScopeListener scopeListener = new TestContextScopeListener(); - contextA.addEventListener(scopeListener); //just pick a context + TestHttpChannelCompleteListener scopeListener = new TestHttpChannelCompleteListener(); + server.getServerConnector().addBean(scopeListener); CrossContextServlet ccServlet = new CrossContextServlet(); ServletHolder ccHolder = new ServletHolder(ccServlet); contextA.addServlet(ccHolder, "/*"); diff --git a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/CreationTest.java b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/CreationTest.java index ec64165ca1c..d2bbef021d8 100644 --- a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/CreationTest.java +++ b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/CreationTest.java @@ -76,8 +76,8 @@ public class CreationTest TestServlet servlet = new TestServlet(); ServletHolder holder = new ServletHolder(servlet); ServletContextHandler contextHandler = server1.addContext(contextPath); - TestContextScopeListener scopeListener = new TestContextScopeListener(); - contextHandler.addEventListener(scopeListener); + TestHttpChannelCompleteListener scopeListener = new TestHttpChannelCompleteListener(); + server1.getServerConnector().addBean(scopeListener); contextHandler.addServlet(holder, servletMapping); servlet.setStore(contextHandler.getSessionHandler().getSessionCache().getSessionDataStore()); server1.start(); @@ -145,8 +145,8 @@ public class CreationTest TestServlet servlet = new TestServlet(); ServletHolder holder = new ServletHolder(servlet); ServletContextHandler contextHandler = server1.addContext(contextPath); - TestContextScopeListener scopeListener = new TestContextScopeListener(); - contextHandler.addEventListener(scopeListener); + TestHttpChannelCompleteListener scopeListener = new TestHttpChannelCompleteListener(); + server1.getServerConnector().addBean(scopeListener); contextHandler.addServlet(holder, servletMapping); servlet.setStore(contextHandler.getSessionHandler().getSessionCache().getSessionDataStore()); server1.start(); @@ -197,8 +197,8 @@ public class CreationTest TestServlet servlet = new TestServlet(); ServletHolder holder = new ServletHolder(servlet); ServletContextHandler contextHandler = server1.addContext(contextPath); - TestContextScopeListener scopeListener = new TestContextScopeListener(); - contextHandler.addEventListener(scopeListener); + TestHttpChannelCompleteListener scopeListener = new TestHttpChannelCompleteListener(); + server1.getServerConnector().addBean(scopeListener); contextHandler.addServlet(holder, servletMapping); servlet.setStore(contextHandler.getSessionHandler().getSessionCache().getSessionDataStore()); server1.start(); @@ -245,8 +245,8 @@ public class CreationTest TestServlet servlet = new TestServlet(); ServletHolder holder = new ServletHolder(servlet); ServletContextHandler contextHandler = server1.addContext(contextPath); - TestContextScopeListener scopeListener = new TestContextScopeListener(); - contextHandler.addEventListener(scopeListener); + TestHttpChannelCompleteListener scopeListener = new TestHttpChannelCompleteListener(); + server1.getServerConnector().addBean(scopeListener); contextHandler.addServlet(holder, servletMapping); servlet.setStore(contextHandler.getSessionHandler().getSessionCache().getSessionDataStore()); server1.start(); @@ -299,8 +299,8 @@ public class CreationTest TestServlet servlet = new TestServlet(); ServletHolder holder = new ServletHolder(servlet); ServletContextHandler contextHandler = server1.addContext(contextPath); - TestContextScopeListener scopeListener = new TestContextScopeListener(); - contextHandler.addEventListener(scopeListener); + TestHttpChannelCompleteListener scopeListener = new TestHttpChannelCompleteListener(); + server1.getServerConnector().addBean(scopeListener); contextHandler.addServlet(holder, servletMapping); ServletContextHandler ctxB = server1.addContext(contextB); ctxB.addServlet(TestServletB.class, servletMapping); @@ -354,8 +354,8 @@ public class CreationTest TestServlet servlet = new TestServlet(); ServletHolder holder = new ServletHolder(servlet); ServletContextHandler contextHandler = server1.addContext(contextPath); - TestContextScopeListener scopeListener = new TestContextScopeListener(); - contextHandler.addEventListener(scopeListener); + TestHttpChannelCompleteListener scopeListener = new TestHttpChannelCompleteListener(); + server1.getServerConnector().addBean(scopeListener); contextHandler.addServlet(holder, servletMapping); ServletContextHandler ctxB = server1.addContext(contextB); ctxB.addServlet(TestServletB.class, servletMapping); diff --git a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/DefaultSessionCacheTest.java b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/DefaultSessionCacheTest.java index 87182acca2f..21b9bc44b83 100644 --- a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/DefaultSessionCacheTest.java +++ b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/DefaultSessionCacheTest.java @@ -22,7 +22,6 @@ import java.util.Collections; import java.util.Random; import java.util.Set; import java.util.concurrent.TimeUnit; - import javax.servlet.http.HttpSession; import javax.servlet.http.HttpSessionActivationListener; import javax.servlet.http.HttpSessionEvent; @@ -79,8 +78,8 @@ public class DefaultSessionCacheTest SessionDataStoreFactory storeFactory = new TestSessionDataStoreFactory(); TestServer server = new TestServer(0, inactivePeriod, scavengePeriod, cacheFactory, storeFactory); ServletContextHandler contextHandler = server.addContext("/test"); - TestContextScopeListener scopeListener = new TestContextScopeListener(); - contextHandler.addEventListener(scopeListener); + TestHttpChannelCompleteListener scopeListener = new TestHttpChannelCompleteListener(); + server.getServerConnector().addBean(scopeListener); TestHttpSessionListener listener = new TestHttpSessionListener(); contextHandler.getSessionHandler().addEventListener(listener); diff --git a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/DeleteUnloadableSessionTest.java b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/DeleteUnloadableSessionTest.java index 6913d87acc3..2ede7430b8b 100644 --- a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/DeleteUnloadableSessionTest.java +++ b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/DeleteUnloadableSessionTest.java @@ -151,8 +151,8 @@ public class DeleteUnloadableSessionTest TestServer server = new TestServer(0, inactivePeriod, scavengePeriod, cacheFactory, storeFactory); ServletContextHandler context = server.addContext(contextPath); - TestContextScopeListener scopeListener = new TestContextScopeListener(); - context.addEventListener(scopeListener); + TestHttpChannelCompleteListener scopeListener = new TestHttpChannelCompleteListener(); + server.getServerConnector().addBean(scopeListener); TestServlet servlet = new TestServlet(); ServletHolder holder = new ServletHolder(servlet); diff --git a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/DirtyAttributeTest.java b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/DirtyAttributeTest.java index 640c37801bd..92505dcfa75 100644 --- a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/DirtyAttributeTest.java +++ b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/DirtyAttributeTest.java @@ -94,8 +94,8 @@ public class DirtyAttributeTest ServletContextHandler ctxA = server.addContext("/mod"); ctxA.addServlet(TestDirtyServlet.class, "/test"); - TestContextScopeListener scopeListener = new TestContextScopeListener(); - ctxA.addEventListener(scopeListener); + TestHttpChannelCompleteListener scopeListener = new TestHttpChannelCompleteListener(); + server.getServerConnector().addBean(scopeListener); server.start(); int port = server.getPort(); @@ -125,14 +125,12 @@ public class DirtyAttributeTest assertEquals(HttpServletResponse.SC_OK, response.getStatus()); //ensure request fully finished processing - latch.await(5, TimeUnit.SECONDS); + assertTrue(latch.await(5, TimeUnit.SECONDS)); A_VALUE.assertPassivatesEquals(1); A_VALUE.assertActivatesEquals(1); A_VALUE.assertBindsEquals(1); A_VALUE.assertUnbindsEquals(0); - - //do another request using the cookie to try changing the session attribute to the same value again latch = new CountDownLatch(1); diff --git a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/IdleSessionTest.java b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/IdleSessionTest.java index 859c63f08e2..c66713e9f72 100644 --- a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/IdleSessionTest.java +++ b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/IdleSessionTest.java @@ -76,8 +76,8 @@ public class IdleSessionTest _server1 = new TestServer(0, inactivePeriod, scavengePeriod, cacheFactory, storeFactory); ServletHolder holder = new ServletHolder(_servlet); ServletContextHandler contextHandler = _server1.addContext(contextPath); - TestContextScopeListener scopeListener = new TestContextScopeListener(); - contextHandler.addEventListener(scopeListener); + TestHttpChannelCompleteListener scopeListener = new TestHttpChannelCompleteListener(); + _server1.getServerConnector().addBean(scopeListener); contextHandler.addServlet(holder, servletMapping); _server1.start(); int port1 = _server1.getPort(); @@ -202,8 +202,8 @@ public class IdleSessionTest _server1 = new TestServer(0, inactivePeriod, scavengePeriod, cacheFactory, storeFactory); ServletHolder holder = new ServletHolder(_servlet); ServletContextHandler contextHandler = _server1.addContext(contextPath); - TestContextScopeListener scopeListener = new TestContextScopeListener(); - contextHandler.addEventListener(scopeListener); + TestHttpChannelCompleteListener scopeListener = new TestHttpChannelCompleteListener(); + _server1.getServerConnector().addBean(scopeListener); contextHandler.addServlet(holder, servletMapping); _server1.start(); int port1 = _server1.getPort(); diff --git a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/NonClusteredSessionScavengingTest.java b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/NonClusteredSessionScavengingTest.java index 07c3b8f284c..0c7d6b43dc7 100644 --- a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/NonClusteredSessionScavengingTest.java +++ b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/NonClusteredSessionScavengingTest.java @@ -75,8 +75,8 @@ public class NonClusteredSessionScavengingTest extends AbstractTestBase context1.addServlet(TestServlet.class, servletMapping); TestHttpSessionListener listener = new TestHttpSessionListener(); context1.getSessionHandler().addEventListener(listener); - TestContextScopeListener scopeListener = new TestContextScopeListener(); - context1.addEventListener(scopeListener); + TestHttpChannelCompleteListener scopeListener = new TestHttpChannelCompleteListener(); + server1.getServerConnector().addBean(scopeListener); try { @@ -144,8 +144,8 @@ public class NonClusteredSessionScavengingTest extends AbstractTestBase TestServer server = new TestServer(0, maxInactivePeriod, scavengePeriod, cacheFactory, storeFactory); ServletContextHandler context = server.addContext("/"); - TestContextScopeListener scopeListener = new TestContextScopeListener(); - context.addEventListener(scopeListener); + TestHttpChannelCompleteListener scopeListener = new TestHttpChannelCompleteListener(); + server.getServerConnector().addBean(scopeListener); _dataStore = context.getSessionHandler().getSessionCache().getSessionDataStore(); context.addServlet(TestServlet.class, servletMapping); @@ -208,8 +208,8 @@ public class NonClusteredSessionScavengingTest extends AbstractTestBase TestServer server = new TestServer(0, maxInactivePeriod, scavengePeriod, cacheFactory, storeFactory); ServletContextHandler context = server.addContext("/"); - TestContextScopeListener scopeListener = new TestContextScopeListener(); - context.addEventListener(scopeListener); + TestHttpChannelCompleteListener scopeListener = new TestHttpChannelCompleteListener(); + server.getServerConnector().addBean(scopeListener); _dataStore = context.getSessionHandler().getSessionCache().getSessionDataStore(); context.addServlet(TestServlet.class, servletMapping); String contextPath = "/"; diff --git a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/ReentrantRequestSessionTest.java b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/ReentrantRequestSessionTest.java index 6d861a23102..a3b68761603 100644 --- a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/ReentrantRequestSessionTest.java +++ b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/ReentrantRequestSessionTest.java @@ -59,8 +59,8 @@ public class ReentrantRequestSessionTest ServletContextHandler context = server.addContext(contextPath); context.addServlet(TestServlet.class, servletMapping); - TestContextScopeListener scopeListener = new TestContextScopeListener(); - context.addEventListener(scopeListener); + TestHttpChannelCompleteListener scopeListener = new TestHttpChannelCompleteListener(); + server.getServerConnector().addBean(scopeListener); try { diff --git a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/SameContextForwardedSessionTest.java b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/SameContextForwardedSessionTest.java index 368283c365f..2fe9d7b4469 100644 --- a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/SameContextForwardedSessionTest.java +++ b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/SameContextForwardedSessionTest.java @@ -58,8 +58,8 @@ public class SameContextForwardedSessionTest TestServer testServer = new TestServer(0, -1, -1, cacheFactory, storeFactory); ServletContextHandler testServletContextHandler = testServer.addContext("/context"); - TestContextScopeListener scopeListener = new TestContextScopeListener(); - testServletContextHandler.addEventListener(scopeListener); + TestHttpChannelCompleteListener scopeListener = new TestHttpChannelCompleteListener(); + testServer.getServerConnector().addBean(scopeListener); ServletHolder holder = new ServletHolder(new Servlet1()); testServletContextHandler.addServlet(holder, "/one"); testServletContextHandler.addServlet(Servlet2.class, "/two"); diff --git a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/SaveOptimizeTest.java b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/SaveOptimizeTest.java index a036bd0bd5c..4acc49516aa 100644 --- a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/SaveOptimizeTest.java +++ b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/SaveOptimizeTest.java @@ -124,8 +124,8 @@ public class SaveOptimizeTest _servlet = new TestServlet(); ServletHolder holder = new ServletHolder(_servlet); ServletContextHandler contextHandler = _server1.addContext(contextPath); - TestContextScopeListener scopeListener = new TestContextScopeListener(); - contextHandler.addEventListener(scopeListener); + TestHttpChannelCompleteListener scopeListener = new TestHttpChannelCompleteListener(); + _server1.getServerConnector().addBean(scopeListener); contextHandler.addServlet(holder, servletMapping); _servlet.setStore(contextHandler.getSessionHandler().getSessionCache().getSessionDataStore()); _server1.start(); @@ -207,8 +207,8 @@ public class SaveOptimizeTest _servlet = new TestServlet(); ServletHolder holder = new ServletHolder(_servlet); ServletContextHandler contextHandler = _server1.addContext(contextPath); - TestContextScopeListener scopeListener = new TestContextScopeListener(); - contextHandler.addEventListener(scopeListener); + TestHttpChannelCompleteListener scopeListener = new TestHttpChannelCompleteListener(); + _server1.getServerConnector().addBean(scopeListener); contextHandler.addServlet(holder, servletMapping); _servlet.setStore(contextHandler.getSessionHandler().getSessionCache().getSessionDataStore()); _server1.start(); @@ -297,8 +297,8 @@ public class SaveOptimizeTest _servlet = new TestServlet(); ServletHolder holder = new ServletHolder(_servlet); ServletContextHandler contextHandler = _server1.addContext(contextPath); - TestContextScopeListener scopeListener = new TestContextScopeListener(); - contextHandler.addEventListener(scopeListener); + TestHttpChannelCompleteListener scopeListener = new TestHttpChannelCompleteListener(); + _server1.getServerConnector().addBean(scopeListener); contextHandler.addServlet(holder, servletMapping); _servlet.setStore(contextHandler.getSessionHandler().getSessionCache().getSessionDataStore()); _server1.start(); @@ -392,8 +392,8 @@ public class SaveOptimizeTest _servlet = new TestServlet(); ServletHolder holder = new ServletHolder(_servlet); ServletContextHandler contextHandler = _server1.addContext(contextPath); - TestContextScopeListener scopeListener = new TestContextScopeListener(); - contextHandler.addEventListener(scopeListener); + TestHttpChannelCompleteListener scopeListener = new TestHttpChannelCompleteListener(); + _server1.getServerConnector().addBean(scopeListener); contextHandler.addServlet(holder, servletMapping); _servlet.setStore(contextHandler.getSessionHandler().getSessionCache().getSessionDataStore()); _server1.start(); @@ -471,8 +471,8 @@ public class SaveOptimizeTest _servlet = new TestServlet(); ServletHolder holder = new ServletHolder(_servlet); ServletContextHandler contextHandler = _server1.addContext(contextPath); - TestContextScopeListener scopeListener = new TestContextScopeListener(); - contextHandler.addEventListener(scopeListener); + TestHttpChannelCompleteListener scopeListener = new TestHttpChannelCompleteListener(); + _server1.getServerConnector().addBean(scopeListener); contextHandler.addServlet(holder, servletMapping); _servlet.setStore(contextHandler.getSessionHandler().getSessionCache().getSessionDataStore()); _server1.start(); diff --git a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/SessionRenewTest.java b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/SessionRenewTest.java index 828991aee94..69b8b5ec813 100644 --- a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/SessionRenewTest.java +++ b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/SessionRenewTest.java @@ -22,7 +22,6 @@ import java.io.IOException; import java.net.HttpCookie; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; - import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; @@ -41,7 +40,6 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNotSame; -import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; /** @@ -118,8 +116,8 @@ public class SessionRenewTest String contextPathA = ""; String servletMapping = "/server"; WebAppContext contextA = _server.addWebAppContext(".", contextPathA); - TestContextScopeListener scopeListener = new TestContextScopeListener(); - contextA.addEventListener(scopeListener); + TestHttpChannelCompleteListener scopeListener = new TestHttpChannelCompleteListener(); + _server.getServerConnector().addBean(scopeListener); contextA.setParentLoaderPriority(true); contextA.addServlet(TestServlet.class, servletMapping); @@ -185,8 +183,8 @@ public class SessionRenewTest String contextPath = ""; String servletMapping = "/server"; WebAppContext context = _server.addWebAppContext(".", contextPath); - TestContextScopeListener scopeListener = new TestContextScopeListener(); - context.addEventListener(scopeListener); + TestHttpChannelCompleteListener scopeListener = new TestHttpChannelCompleteListener(); + _server.getServerConnector().addBean(scopeListener); context.setParentLoaderPriority(true); context.addServlet(TestServlet.class, servletMapping); TestHttpSessionIdListener testListener = new TestHttpSessionIdListener();