Issue #2578 - Listener behavior cleanup (Jetty 10.0.x) (#3966)

* Avoid creating listener list for rarely used requestAttributeListener

Signed-off-by: Greg Wilkins <gregw@webtide.com>

* Issue #3964

Keep a list of EventListeners in the AbstractConnector to make it
more efficient to add and iterate over them.

Signed-off-by: Greg Wilkins <gregw@webtide.com>

* Issue #2578 EventListener

Use addEventListener rather than bespoke listener methods.
Support getEventListenerBeans at Container level for fast lookup
improve javadoc

Signed-off-by: Greg Wilkins <gregw@webtide.com>

* Issue #2578 EventListener

fixed test
more javadoc

Signed-off-by: Greg Wilkins <gregw@webtide.com>

* Issue #2578 EventListener

fixed tests

Signed-off-by: Greg Wilkins <gregw@webtide.com>

* Issue #3964

Don't use null for empty lists of listeners

Signed-off-by: Greg Wilkins <gregw@webtide.com>

* fix merge

Signed-off-by: Greg Wilkins <gregw@webtide.com>

* Issue #2578 EventListener

Resolve differences between eventListeners added as beans and beans
added as EventListeners.   The behaviour should now be the same
regardless of how they listener is added and all listeners are now
beans.

Signed-off-by: Greg Wilkins <gregw@webtide.com>

* Issue #2578 EventListener

Add only SelectorManager listeners to manager from connector

Signed-off-by: Greg Wilkins <gregw@webtide.com>

* Issue #2578 EventListener

Fixed javadoc

Signed-off-by: Greg Wilkins <gregw@webtide.com>

* Issue #2578 EventListener

removed old TODO

Signed-off-by: Greg Wilkins <gregw@webtide.com>

* Issue #2578 EventListener

connector cannot be null

Signed-off-by: Greg Wilkins <gregw@webtide.com>

* Issue #2578 EventListener

javadoc

Signed-off-by: Greg Wilkins <gregw@webtide.com>

* Issue #3964

AbstractConnector keeps a specific list of HttpChannel.Listeners
to avoid Connection.Listeners and MBean listeners being added to
the HttpChannel listener list.

Signed-off-by: Greg Wilkins <gregw@webtide.com>

* Issue #2578 EventListener

fixed merge

Signed-off-by: Greg Wilkins <gregw@webtide.com>

* fixed javadoc

Signed-off-by: Greg Wilkins <gregw@webtide.com>

* Issue #2578 EventListener

removed the ability to set/clear context listeners
Instead just remove non-durable ones.

Signed-off-by: Greg Wilkins <gregw@webtide.com>

* Issue #3964 Listeners

Simplified listener handling by avoiding null connector, previously
only needed for testing.

Signed-off-by: Greg Wilkins <gregw@webtide.com>

* fixed bad merge

Signed-off-by: Greg Wilkins <gregw@webtide.com>

* Issue #3964 Listeners

Fixed test that assumed HttpChannel listeners were not cleared by a recycle

Signed-off-by: Greg Wilkins <gregw@webtide.com>

* Issue #3964 Listeners

Separated out durable vs cyclic HttpChannel.Listeners, so as to
simplify handling.

Deprecated cyclic HttpChannel.Listeners, as I'm not sure the channel is
the right place for them.

Signed-off-by: Greg Wilkins <gregw@webtide.com>

* removed deprecated cyclic HttpChannel listeners

Signed-off-by: Greg Wilkins <gregw@webtide.com>

* removed deprecated cyclic HttpChannel listeners - import

Signed-off-by: Greg Wilkins <gregw@webtide.com>

* Issue #4003 Cleanup quickstart

* Fixed tests that scan for "Started" on console

Signed-off-by: Greg Wilkins <gregw@webtide.com>

* updates from review

Signed-off-by: Greg Wilkins <gregw@webtide.com>
This commit is contained in:
Greg Wilkins 2019-11-13 11:04:38 +11:00 committed by GitHub
parent 774160c7ec
commit 46a3368f3b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
65 changed files with 434 additions and 377 deletions

View File

@ -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]);

View File

@ -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) + ",*");

View File

@ -6,7 +6,7 @@
<!-- ================================================================ -->
<Configure id="Server" class="org.eclipse.jetty.server.Server">
<Call name="addLifeCycleListener">
<Call name="addEventListener">
<Arg>
<New class="org.eclipse.jetty.setuid.SetUIDListener">
<Set name="startServerAsPrivileged"><Property name="jetty.setuid.startServerAsPrivileged" default="false"/></Set>

View File

@ -5,7 +5,7 @@
<!-- Mixin the Start FileNoticeLifeCycleListener -->
<!-- =============================================================== -->
<Configure id="Server" class="org.eclipse.jetty.server.Server">
<Call name="addLifeCycleListener">
<Call name="addEventListener">
<Arg>
<New class="org.eclipse.jetty.util.component.FileNoticeLifeCycleListener">
<Arg><Property name="jetty.state" default="./jetty.state"/></Arg>

View File

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

View File

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

View File

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

View File

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

View File

@ -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);
/**
* <p>Removes a listener of connection events.</p>
*
* @param listener the listener to remove
*/
public void removeListener(Listener listener);
public void removeEventListener(EventListener listener);
/**
* <p>Callback method invoked when this connection is opened.</p>
@ -133,7 +134,7 @@ public interface Connection extends Closeable
* the Connector or ConnectionFactory are added as listeners to all new connections
* </p>
*/
public interface Listener
public interface Listener extends EventListener
{
public void onOpened(Connection connection);

View File

@ -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
{
}
/**
* <p>A listener for accept events.</p>
* <p>This listener is called from either the selector or acceptor thread
* and implementations must be non blocking and fast.</p>
*/
public interface AcceptListener extends EventListener
public interface AcceptListener extends SelectorManagerListener
{
/**
* Called immediately after a new SelectableChannel is accepted, but

View File

@ -571,7 +571,8 @@ public abstract class WriteFlusher
}
/**
* <p>A listener of {@link WriteFlusher} events.</p>
* <p>A listener of {@link WriteFlusher} events.
* If implemented by a Connection class, the {@link #onFlushed(long)} event will be delivered to it.</p>
*/
public interface Listener
{

View File

@ -24,7 +24,7 @@
</Item>
</Array>
</Arg>
<Call name="addLifeCycleListener">
<Call name="addEventListener">
<Arg>
<New class="org.eclipse.jetty.maven.plugin.ServerConnectorListener">
<Set name="fileName"><Property name="jetty.port.file" default="port.txt"/></Set>

View File

@ -24,7 +24,7 @@
</Item>
</Array>
</Arg>
<Call name="addLifeCycleListener">
<Call name="addEventListener">
<Arg>
<New class="org.eclipse.jetty.maven.plugin.ServerConnectorListener">
<Set name="fileName"><Property name="jetty.port.file" default="port.txt"/></Set>

View File

@ -24,7 +24,7 @@
</Item>
</Array>
</Arg>
<Call name="addLifeCycleListener">
<Call name="addEventListener">
<Arg>
<New class="org.eclipse.jetty.maven.plugin.ServerConnectorListener">
<Set name="fileName"><Property name="jetty.port.file" default="port.txt"/></Set>

View File

@ -30,7 +30,7 @@
</Item>
</Array>
</Arg>
<Call name="addLifeCycleListener">
<Call name="addEventListener">
<Arg>
<New class="org.eclipse.jetty.maven.plugin.ServerConnectorListener">
</New>

View File

@ -3,7 +3,7 @@
<Configure id="Server" class="org.eclipse.jetty.server.Server">
<Ref id="httpConnector">
<Call name="addLifeCycleListener">
<Call name="addEventListener">
<Arg>
<New class="org.eclipse.jetty.maven.plugin.ServerConnectorListener">
<Set name="fileName"><Property name="jetty.port.file" default="port.txt"/></Set>

View File

@ -24,7 +24,7 @@
</Item>
</Array>
</Arg>
<Call name="addLifeCycleListener">
<Call name="addEventListener">
<Arg>
<New class="org.eclipse.jetty.maven.plugin.ServerConnectorListener">
<Set name="fileName"><Property name="jetty.port.file" default="port.txt"/></Set>

View File

@ -24,7 +24,7 @@
</Item>
</Array>
</Arg>
<Call name="addLifeCycleListener">
<Call name="addEventListener">
<Arg>
<New class="org.eclipse.jetty.maven.plugin.ServerConnectorListener">
<Set name="fileName"><Property name="jetty.port.file" default="port.txt"/></Set>

View File

@ -24,7 +24,7 @@
</Item>
</Array>
</Arg>
<Call name="addLifeCycleListener">
<Call name="addEventListener">
<Arg>
<New class="org.eclipse.jetty.maven.plugin.ServerConnectorListener">
<Set name="fileName"><Property name="jetty.port.file" default="port.txt"/></Set>

View File

@ -24,7 +24,7 @@
</Item>
</Array>
</Arg>
<Call name="addLifeCycleListener">
<Call name="addEventListener">
<Arg>
<New class="org.eclipse.jetty.maven.plugin.ServerConnectorListener">
<Set name="fileName"><Property name="jetty.port.file" default="port.txt"/></Set>

View File

@ -24,7 +24,7 @@
</Item>
</Array>
</Arg>
<Call name="addLifeCycleListener">
<Call name="addEventListener">
<Arg>
<New class="org.eclipse.jetty.maven.plugin.ServerConnectorListener">
<Set name="fileName"><Property name="jetty.port.file" default="port.txt"/></Set>

View File

@ -24,7 +24,7 @@
</Item>
</Array>
</Arg>
<Call name="addLifeCycleListener">
<Call name="addEventListener">
<Arg>
<New class="org.eclipse.jetty.maven.plugin.ServerConnectorListener">
<Set name="fileName"><Property name="jetty.port.file" default="port.txt"/></Set>

View File

@ -24,7 +24,7 @@
</Item>
</Array>
</Arg>
<Call name="addLifeCycleListener">
<Call name="addEventListener">
<Arg>
<New class="org.eclipse.jetty.maven.plugin.ServerConnectorListener">
<Set name="fileName"><Property name="jetty.port.file" default="port.txt"/></Set>

View File

@ -24,7 +24,7 @@
</Item>
</Array>
</Arg>
<Call name="addLifeCycleListener">
<Call name="addEventListener">
<Arg>
<New class="org.eclipse.jetty.maven.plugin.ServerConnectorListener">
<Set name="fileName"><Property name="jetty.port.file" default="port.txt"/></Set>

View File

@ -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]);

View File

@ -2,7 +2,7 @@
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://www.eclipse.org/jetty/configure_9_3.dtd">
<Configure id="Server" class="org.eclipse.jetty.server.Server">
<Call name="addLifeCycleListener">
<Call name="addEventListener">
<Arg>
<New class="org.eclipse.jetty.maven.plugin.ServerListener">
<Set name="tokenFile"><Property name="jetty.token.file"/></Set>

View File

@ -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()
{
/**

View File

@ -31,7 +31,7 @@
</Item>
</Array>
</Arg>
<Call name="addLifeCycleListener">
<Call name="addEventListener">
<Arg>
<New class="org.eclipse.jetty.osgi.boot.utils.ServerConnectorListener">
<Set name="sysPropertyName">boot.context.service.port</Set>

View File

@ -31,7 +31,7 @@
</Item>
</Array>
</Arg>
<Call name="addLifeCycleListener">
<Call name="addEventListener">
<Arg>
<New class="org.eclipse.jetty.osgi.boot.utils.ServerConnectorListener">
<Set name="sysPropertyName">boot.webapp.service.port</Set>

View File

@ -31,7 +31,7 @@
</Item>
</Array>
</Arg>
<Call name="addLifeCycleListener">
<Call name="addEventListener">
<Arg>
<New class="org.eclipse.jetty.osgi.boot.utils.ServerConnectorListener">
<Set name="sysPropertyName">boot.annotations.port</Set>

View File

@ -31,7 +31,7 @@
</Item>
</Array>
</Arg>
<Call name="addLifeCycleListener">
<Call name="addEventListener">
<Arg>
<New class="org.eclipse.jetty.osgi.boot.utils.ServerConnectorListener">
<Set name="sysPropertyName">boot.bundle.port</Set>

View File

@ -31,7 +31,7 @@
</Item>
</Array>
</Arg>
<Call name="addLifeCycleListener">
<Call name="addEventListener">
<Arg>
<New class="org.eclipse.jetty.osgi.boot.utils.ServerConnectorListener">
<Set name="sysPropertyName">boot.javax.websocket.port</Set>

View File

@ -31,7 +31,7 @@
</Item>
</Array>
</Arg>
<Call name="addLifeCycleListener">
<Call name="addEventListener">
<Arg>
<New class="org.eclipse.jetty.osgi.boot.utils.ServerConnectorListener">
<Set name="sysPropertyName">boot.jsp.port</Set>

View File

@ -31,7 +31,7 @@
</Item>
</Array>
</Arg>
<Call name="addLifeCycleListener">
<Call name="addEventListener">
<Arg>
<New class="org.eclipse.jetty.osgi.boot.utils.ServerConnectorListener">
<Set name="sysPropertyName">boot.websocket.port</Set>

View File

@ -31,7 +31,7 @@
</Item>
</Array>
</Arg>
<Call name="addLifeCycleListener">
<Call name="addEventListener">
<Arg>
<New class="org.eclipse.jetty.osgi.boot.utils.ServerConnectorListener">
<Set name="sysPropertyName">foo.foo</Set>

View File

@ -16,7 +16,7 @@
</New>
</Arg>
</Call>
<Call name="addLifeCycleListener">
<Call name="addEventListener">
<Arg>
<New class="org.eclipse.jetty.osgi.boot.utils.ServerConnectorListener">
<Set name="sysPropertyName">boot.https.port</Set>

View File

@ -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

View File

@ -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;
/**
* <p>Provides the common handling for {@link ConnectionFactory} implementations including:</p>
* <ul>
* <li>Protocol identification</li>
* <li>Configuration of new Connections:
* <ul>
* <li>Setting inputbuffer size</li>
* <li>Calling {@link Connection#addListener(Connection.Listener)} for all
* Connection.Listener instances found as beans on the {@link Connector}
* and this {@link ConnectionFactory}</li>
* </ul>
* </ul>
* <p>Provides the common handling for {@link ConnectionFactory} implementations.</p>
*/
@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;
}

View File

@ -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)

View File

@ -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();

View File

@ -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<EventListener> _eventListeners = new CopyOnWriteArrayList<>();
private final List<EventListener> _programmaticListeners = new CopyOnWriteArrayList<>();
private final List<ServletContextListener> _servletContextListeners = new CopyOnWriteArrayList<>();
private final List<ServletContextListener> _destroySerletContextListeners = new ArrayList<>();
@ -206,7 +205,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
private final List<ServletRequestListener> _servletRequestListeners = new CopyOnWriteArrayList<>();
private final List<ServletRequestAttributeListener> _servletRequestAttributeListeners = new CopyOnWriteArrayList<>();
private final List<ContextScopeListener> _contextListeners = new CopyOnWriteArrayList<>();
private final List<EventListener> _durableListeners = new CopyOnWriteArrayList<>();
private final Set<EventListener> _durableListeners = new HashSet<>();
private String[] _protectedTargets;
private final CopyOnWriteArrayList<AliasCheck> _aliasChecks = new CopyOnWriteArrayList<ContextHandler.AliasCheck>();
@ -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)

View File

@ -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;
}
/**

View File

@ -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)

View File

@ -61,6 +61,7 @@ public class ListenerHolder extends BaseHolder<EventListener>
* 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)
{

View File

@ -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

View File

@ -670,7 +670,7 @@ public class ServletHolder extends Holder<Servlet> 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);
}
}

View File

@ -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<String> 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"));

View File

@ -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<EventListener> 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

View File

@ -19,10 +19,7 @@
package org.eclipse.jetty.util;
/**
* Interface for 3rd party libraries to decorate recently created objects in Jetty.
* <p>
* Most common use is weld/CDI.
* <p>
* Interface to decorate objects created by the {@link DecoratedObjectFactory}
*/
public interface Decorator
{

View File

@ -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<LifeCycle.Listener> _listeners = new CopyOnWriteArrayList<LifeCycle.Listener>();
private final List<EventListener> _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<EventListener> getEventListeners()
{
_listeners.add(listener);
return _eventListener;
}
public void setEventListeners(Collection<EventListener> 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);
}
}

View File

@ -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<Object> getBeans();
Collection<Object> getBeans();
/**
* @param clazz the class of the beans
@ -56,39 +59,56 @@ public interface Container
* @see #getBeans()
* @see #getContainedBeans(Class)
*/
public <T> Collection<T> getBeans(Class<T> clazz);
<T> Collection<T> getBeans(Class<T> clazz);
/**
* @param clazz the class of the beans
* @param <T> 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 <T> Collection<T> getCachedBeans(Class<T> clazz)
{
return getBeans(clazz);
}
/**
* @param clazz the class of the bean
* @param <T> the Bean type
* @return the first bean of a specific class (or subclass), or null if no such bean exist
*/
public <T> T getBean(Class<T> clazz);
<T> T getBean(Class<T> 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 <T> the Bean type
* @return the list of beans of the given class from the entire Container hierarchy
*/
<T> Collection<T> getContainedBeans(Class<T> clazz);
/**
* Get the beans added to the container that are EventListeners.
* This is essentially equivalent to <code>getBeans(EventListener.class);</code>,
* except that: <ul>
* <li>The result may be precomputed, so it can be more efficient</li>
* <li>The result is ordered by the order added.</li>
* <li>The result is immutable.</li>
* </ul>
* @see #getBeans(Class)
* @return An unmodifiable list of EventListener beans
*/
default List<EventListener> 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 <T> the Bean type
* @return the list of beans of the given class from the entire Container hierarchy
*/
public <T> Collection<T> getContainedBeans(Class<T> clazz);
}

View File

@ -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.
* <p>
* 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)}.
* <p>
* 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:
* <pre>
@ -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)
{

View File

@ -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.

View File

@ -33,7 +33,7 @@ public class StopLifeCycle extends AbstractLifeCycle implements LifeCycle.Listen
public StopLifeCycle(LifeCycle lifecycle)
{
_lifecycle = lifecycle;
addLifeCycleListener(this);
addEventListener(this);
}
@Override

View File

@ -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
{

View File

@ -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());

View File

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

View File

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

View File

@ -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;
}
/**

View File

@ -90,7 +90,7 @@ public class WebAppContextTest
server.setHandler(wac);
wac.addEventListener(new MySessionListener());
Collection<MySessionListener> listeners = wac.getSessionHandler().getBeans(org.eclipse.jetty.webapp.WebAppContextTest.MySessionListener.class);
Collection<MySessionListener> listeners = wac.getSessionHandler().getBeans(MySessionListener.class);
assertNotNull(listeners);
assertEquals(1, listeners.size());
}

View File

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

View File

@ -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;

View File

@ -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

View File

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

View File

@ -26,7 +26,7 @@ import org.eclipse.jetty.server.Request;
public class TestHttpChannelCompleteListener implements Listener
{
private final AtomicReference<CountDownLatch> _exitSynchronizer = new AtomicReference<>();
AtomicReference<CountDownLatch> _exitSynchronizer = new AtomicReference<>();
/**
* @param exitSynchronizer the exitSynchronizer to set