Skip to content

Commit

Permalink
Issue #8885 - Restore HttpChannel.Listener
Browse files Browse the repository at this point in the history
  • Loading branch information
joakime committed May 10, 2023
1 parent ba67602 commit 9b49da3
Show file tree
Hide file tree
Showing 5 changed files with 401 additions and 191 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
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.ssl.SslContextFactory;
Expand Down Expand Up @@ -137,6 +138,7 @@
@ManagedObject("Abstract implementation of the Connector Interface")
public abstract class AbstractConnector extends ContainerLifeCycle implements Connector, Dumpable
{
public static final HttpChannel.Listener NOOP_LISTENER = new HttpChannel.Listener() {};
protected static final Logger LOG = LoggerFactory.getLogger(AbstractConnector.class);

private final AutoLock _lock = new AutoLock();
Expand All @@ -150,6 +152,7 @@ public abstract class AbstractConnector extends ContainerLifeCycle implements Co
private final Set<EndPoint> _endpoints = Collections.newSetFromMap(new ConcurrentHashMap<>());
private final Set<EndPoint> _immutableEndPoints = Collections.unmodifiableSet(_endpoints);
private Shutdown _shutdown;
private HttpChannel.Listener _httpChannelListeners = NOOP_LISTENER;
private long _idleTimeout = 30000;
private long _shutdownIdleTimeout = 1000L;
private String _defaultProtocol;
Expand Down Expand Up @@ -188,6 +191,23 @@ public AbstractConnector(
_bufferPool = bufferPool != null ? bufferPool : server.getByteBufferPool();
addBean(_bufferPool, bufferPool != null);

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));
}
});

for (ConnectionFactory factory : factories)
{
addConnectionFactory(factory);
Expand Down Expand Up @@ -267,6 +287,16 @@ public int getAcceptors()
return _acceptors.length;
}

/**
* Get the {@link HttpChannel.Listener} for this connector.
*
* @return the {@link HttpChannel.Listener} for this connector.
*/
public HttpChannel.Listener getHttpChannelListeners()
{
return _httpChannelListeners;
}

@Override
protected void doStart() throws Exception
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@

package org.eclipse.jetty.server;

import java.nio.ByteBuffer;
import java.util.EventListener;

import org.eclipse.jetty.http.MetaData;
import org.eclipse.jetty.server.internal.HttpChannelState;
import org.eclipse.jetty.util.thread.Invocable;
Expand Down Expand Up @@ -101,6 +104,203 @@ interface Factory
HttpChannel newHttpChannel(ConnectionMetaData connectionMetaData);
}

/**
* <p>Listener for {@link HttpChannel} events.</p>
* <p>HttpChannel will emit events for the various phases it goes through while
* processing an HTTP request and response.</p>
* <p>Implementations of this interface may listen to those events to track
* timing and/or other values such as request URI, etc.</p>
* <p>The events parameters, especially the {@link Request} object, may be
* in a transient state depending on the event, and not all properties/features
* of the parameters may be available inside a listener method.</p>
* <p>It is recommended that the event parameters are <em>not</em> acted upon
* in the listener methods, or undefined behavior may result. For example, it
* would be a bad idea to try to read some content from the
* {@link Request#read()} in listener methods. On the other
* hand, it is legit to store request attributes in one listener method that
* may be possibly retrieved in another listener method in a later event.</p>
* <p>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).</p>
* <p>Listener instances that are set as a bean on the {@link Connector} are
* efficiently added to {@link HttpChannel}.
*/
public interface Listener extends EventListener
{
/**
* Invoked just after the HTTP request line and headers have been parsed.
*
* @param request the request object
* @param response the response object
*/
default void onRequestBegin(Request request, Response response)
{
// done
}

/**
* Invoked just before calling the application.
*
* @param request the request object
* @param response the response object
*/
default void onBeforeDispatch(Request request, Response response)
{
// done
}

/**
* Invoked when the application threw an exception.
*
* @param request the request object
* @param response the response object
* @param failure the exception thrown by the application
*/
default void onDispatchFailure(Request request, Response response, Throwable failure)
{
// done
}

/**
* Invoked just after the application returns from the first invocation.
*
* @param request the request object
* @param response the response object
*/
default void onAfterDispatch(Request request, Response response)
{
// done
}

/**
* Invoked every time a request content chunk has been parsed, just before
* making it available to the application.
*
* @param request the request object
* @param response the response object
* @param content a {@link ByteBuffer#slice() slice} of the request content chunk
*/
default void onRequestContent(Request request, Response response, ByteBuffer content)
{
// done
}

/**
* Invoked when the end of the request content is detected.
*
* @param request the request object
* @param response the response object
*/
default void onRequestContentEnd(Request request, Response response)
{
// done
}

/**
* Invoked when the request trailers have been parsed.
*
* @param request the request object
* @param response the response object
*/
default void onRequestTrailers(Request request, Response response)
{
// done
}

/**
* Invoked when the request has been fully parsed.
*
* @param request the request object
* @param response the response object
*/
default void onRequestEnd(Request request, Response response)
{
// done
}

/**
* Invoked when the request processing failed.
*
* @param request the request object
* @param response the response object
* @param failure the request failure
*/
default void onRequestFailure(Request request, Response response, Throwable failure)
{
// done
}

/**
* Invoked just before the response line is written to the network.
*
* @param request the request object
* @param response the response object
*/
default void onResponseBegin(Request request, Response response)
{
// done
}

/**
* Invoked just after the response is committed (that is, the response
* line, headers and possibly some content have been written to the
* network).
*
* @param request the request object
* @param response the response object
*/
default void onResponseCommit(Request request, Response response)
{
// done
}

/**
* Invoked after a response content chunk has been written to the network.
*
* @param request the request object
* @param response the response object
* @param content a {@link ByteBuffer#slice() slice} of the response content chunk
*/
default void onResponseContent(Request request, Response response, ByteBuffer content)
{
// done
}

/**
* Invoked when the response has been fully written.
*
* @param request the request object
* @param response the response object
*/
default void onResponseEnd(Request request, Response response)
{
// done
}

/**
* Invoked when the response processing failed.
*
* @param request the request object
* @param response the response object
* @param failure the response failure
*/
default void onResponseFailure(Request request, Response response, Throwable failure)
{
// done
}

/**
* Invoked when the request <em>and</em> response processing are complete.
*
* @param request the request object
* @param response the response object
*/
default void onComplete(Request request, Response response)
{
// done
}
}

/**
* <p>The factory that creates default implementations of {@link HttpChannel}.</p>
*/
Expand Down
Loading

0 comments on commit 9b49da3

Please sign in to comment.