Jetty 9.4.x 2903 delay listener instantiation (#2930)

* Issue #2903 Ensure listeners not instantiated for quickstart gen

Signed-off-by: Jan Bartel <janb@webtide.com>
This commit is contained in:
Jan Bartel 2018-09-26 11:27:57 +10:00 committed by GitHub
parent 08d0092cbd
commit 5593e5b479
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 118 additions and 51 deletions

View File

@ -81,12 +81,10 @@ public class WebListenerAnnotation extends DiscoveredAnnotation
{
MetaData metaData = _context.getMetaData();
if (metaData.getOrigin(clazz.getName()+".listener") == Origin.NotSet)
{
java.util.EventListener listener = (java.util.EventListener)_context.getServletContext().createInstance(clazz);
{
ListenerHolder h = _context.getServletHandler().newListenerHolder(new Source(Source.Origin.ANNOTATION, clazz.getName()));
h.setListener(listener);
h.setHeldClass(clazz);
_context.getServletHandler().addListener(h);
_context.addEventListener(listener);
}
}
else

View File

@ -185,6 +185,26 @@
<artifactId>jetty-server</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-servlet</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-client</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-http</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-io</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-jmx</artifactId>

View File

@ -51,6 +51,7 @@ import org.eclipse.jetty.security.authentication.FormAuthenticator;
import org.eclipse.jetty.servlet.ErrorPageErrorHandler;
import org.eclipse.jetty.servlet.FilterHolder;
import org.eclipse.jetty.servlet.FilterMapping;
import org.eclipse.jetty.servlet.ListenerHolder;
import org.eclipse.jetty.servlet.ServletContextHandler.JspConfig;
import org.eclipse.jetty.servlet.ServletHandler;
import org.eclipse.jetty.servlet.ServletHolder;
@ -176,10 +177,10 @@ public class QuickStartDescriptorGenerator
.tag("param-value",_webApp.getInitParameter(p))
.closeTag();
if (_webApp.getEventListeners() != null)
for (EventListener e : _webApp.getEventListeners())
out.openTag("listener",origin(md,e.getClass().getCanonicalName() + ".listener"))
.tag("listener-class",e.getClass().getCanonicalName())
if (_webApp.getServletHandler().getListeners() != null)
for (ListenerHolder e : _webApp.getServletHandler().getListeners())
out.openTag("listener",origin(md,e.getClassName() + ".listener"))
.tag("listener-class",e.getClassName())
.closeTag();
ServletHandler servlets = _webApp.getServletHandler();

View File

@ -24,6 +24,7 @@ import static org.junit.jupiter.api.Assertions.*;
import java.io.File;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ListenerHolder;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.toolchain.test.FS;
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
@ -69,8 +70,10 @@ public class TestQuickStart
ServletHolder fooHolder = new ServletHolder();
fooHolder.setServlet(new FooServlet());
fooHolder.setName("foo");
quickstart.getServletHandler().addServlet(fooHolder);
quickstart.addEventListener(new FooContextListener());
quickstart.getServletHandler().addServlet(fooHolder);
ListenerHolder lholder = new ListenerHolder();
lholder.setListener(new FooContextListener());
quickstart.getServletHandler().addListener(lholder);
server.setHandler(quickstart);
server.start();
server.stop();

View File

@ -21,54 +21,112 @@ package org.eclipse.jetty.servlet;
import java.util.EventListener;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
/**
* ListenerHolder
*
* Specialization of AbstractHolder for servlet listeners. This
* Specialization of BaseHolder for servlet listeners. This
* allows us to record where the listener originated - web.xml,
* annotation, api etc.
*/
public class ListenerHolder extends BaseHolder<EventListener>
{
private EventListener _listener;
private boolean _initialized = false;
public ListenerHolder ()
{
this (Source.EMBEDDED);
}
public ListenerHolder(Source source)
{
super(source);
}
public void setListener(EventListener listener)
{
_listener = listener;
setClassName(listener.getClass().getName());
setHeldClass(listener.getClass());
_extInstance=true;
}
public EventListener getListener()
{
return _listener;
}
/**
* Set an explicit instance. In this case,
* just like ServletHolder and FilterHolder,
* the listener will not be introspected for
* annotations like Resource etc.
*
* @param listener
*/
public void setListener (EventListener listener)
{
_listener = listener;
_extInstance=true;
setHeldClass(_listener.getClass());
setClassName(_listener.getClass().getName());
}
public void initialize (ServletContext context) throws Exception
{
if (!_initialized)
{
initialize();
if (_listener == null)
{
//create an instance of the listener and decorate it
try
{
_listener = (context instanceof ServletContextHandler.Context)
?((ServletContextHandler.Context)context).createListener(getHeldClass())
:getHeldClass().getDeclaredConstructor().newInstance();
}
catch (ServletException se)
{
Throwable cause = se.getRootCause();
if (cause instanceof InstantiationException)
throw (InstantiationException)cause;
if (cause instanceof IllegalAccessException)
throw (IllegalAccessException)cause;
throw se;
}
}
_initialized = true;
}
}
@Override
public void doStart() throws Exception
{
//Listeners always have an instance eagerly created, it cannot be deferred to the doStart method
if (_listener == null)
throw new IllegalStateException("No listener instance");
super.doStart();
if (!java.util.EventListener.class.isAssignableFrom(_class))
{
String msg = _class+" is not a java.util.EventListener";
super.stop();
throw new IllegalStateException(msg);
}
}
@Override
public void doStop() throws Exception
{
super.doStop();
if (!_extInstance)
_listener = null;
_initialized = false;
}
@Override
public String toString()
{
return super.toString()+(_listener == null?"":": "+getClassName());
}
return super.toString()+": "+getClassName();
}
}

View File

@ -356,13 +356,16 @@ public class ServletContextHandler extends ContextHandler
if (_servletHandler != null)
{
// Call decorators on all holders, and also on any EventListeners before
// decorators are called on any other classes (like servlets and filters)
//Ensure listener instances are created, added to ContextHandler
if(_servletHandler.getListeners() != null)
{
for (ListenerHolder holder:_servletHandler.getListeners())
{
_objFactory.decorate(holder.getListener());
holder.start();
//we need to pass in the context because the ServletHandler has not
//yet got a reference to the ServletContext (happens in super.startContext)
holder.initialize(_scontext);
addEventListener(holder.getListener());
}
}
}

View File

@ -1911,17 +1911,11 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor
}
((WebDescriptor)descriptor).addClassName(className);
Class<? extends EventListener> listenerClass = (Class<? extends EventListener>)context.loadClass(className);
listener = newListenerInstance(context,listenerClass, descriptor);
if (!(listener instanceof EventListener))
{
LOG.warn("Not an EventListener: " + listener);
return;
}
context.addEventListener(listener);
ListenerHolder h = context.getServletHandler().newListenerHolder(new Source (Source.Origin.DESCRIPTOR, descriptor.getResource().toString()));
h.setClassName(className);
context.getServletHandler().addListener(h);
context.getMetaData().setOrigin(className+".listener", descriptor);
}
}
catch (Exception e)
@ -1960,14 +1954,4 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor
((ConstraintAware)context.getSecurityHandler()).setDenyUncoveredHttpMethods(true);
}
public EventListener newListenerInstance(WebAppContext context,Class<? extends EventListener> clazz, Descriptor descriptor) throws Exception
{
ListenerHolder h = context.getServletHandler().newListenerHolder(new Source (Source.Origin.DESCRIPTOR, descriptor.getResource().toString()));
EventListener l = context.getServletContext().createInstance(clazz);
h.setListener(l);
context.getServletHandler().addListener(h);
return l;
}
}