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

@ -82,11 +82,9 @@ public class WebListenerAnnotation extends DiscoveredAnnotation
MetaData metaData = _context.getMetaData(); MetaData metaData = _context.getMetaData();
if (metaData.getOrigin(clazz.getName()+".listener") == Origin.NotSet) 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())); ListenerHolder h = _context.getServletHandler().newListenerHolder(new Source(Source.Origin.ANNOTATION, clazz.getName()));
h.setListener(listener); h.setHeldClass(clazz);
_context.getServletHandler().addListener(h); _context.getServletHandler().addListener(h);
_context.addEventListener(listener);
} }
} }
else else

View File

@ -185,6 +185,26 @@
<artifactId>jetty-server</artifactId> <artifactId>jetty-server</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
</dependency> </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> <dependency>
<groupId>org.eclipse.jetty</groupId> <groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-jmx</artifactId> <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.ErrorPageErrorHandler;
import org.eclipse.jetty.servlet.FilterHolder; import org.eclipse.jetty.servlet.FilterHolder;
import org.eclipse.jetty.servlet.FilterMapping; import org.eclipse.jetty.servlet.FilterMapping;
import org.eclipse.jetty.servlet.ListenerHolder;
import org.eclipse.jetty.servlet.ServletContextHandler.JspConfig; import org.eclipse.jetty.servlet.ServletContextHandler.JspConfig;
import org.eclipse.jetty.servlet.ServletHandler; import org.eclipse.jetty.servlet.ServletHandler;
import org.eclipse.jetty.servlet.ServletHolder; import org.eclipse.jetty.servlet.ServletHolder;
@ -176,10 +177,10 @@ public class QuickStartDescriptorGenerator
.tag("param-value",_webApp.getInitParameter(p)) .tag("param-value",_webApp.getInitParameter(p))
.closeTag(); .closeTag();
if (_webApp.getEventListeners() != null) if (_webApp.getServletHandler().getListeners() != null)
for (EventListener e : _webApp.getEventListeners()) for (ListenerHolder e : _webApp.getServletHandler().getListeners())
out.openTag("listener",origin(md,e.getClass().getCanonicalName() + ".listener")) out.openTag("listener",origin(md,e.getClassName() + ".listener"))
.tag("listener-class",e.getClass().getCanonicalName()) .tag("listener-class",e.getClassName())
.closeTag(); .closeTag();
ServletHandler servlets = _webApp.getServletHandler(); ServletHandler servlets = _webApp.getServletHandler();

View File

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

View File

@ -21,54 +21,112 @@ package org.eclipse.jetty.servlet;
import java.util.EventListener; import java.util.EventListener;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
/** /**
* ListenerHolder * 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, * allows us to record where the listener originated - web.xml,
* annotation, api etc. * annotation, api etc.
*/ */
public class ListenerHolder extends BaseHolder<EventListener> public class ListenerHolder extends BaseHolder<EventListener>
{ {
private EventListener _listener; private EventListener _listener;
private boolean _initialized = false;
public ListenerHolder ()
{
this (Source.EMBEDDED);
}
public ListenerHolder(Source source) public ListenerHolder(Source source)
{ {
super(source); super(source);
} }
public void setListener(EventListener listener)
{
_listener = listener;
setClassName(listener.getClass().getName());
setHeldClass(listener.getClass());
_extInstance=true;
}
public EventListener getListener() public EventListener getListener()
{ {
return _listener; 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 @Override
public void doStart() throws Exception 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(); 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 @Override
public String toString() 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) if (_servletHandler != null)
{ {
// Call decorators on all holders, and also on any EventListeners before //Ensure listener instances are created, added to ContextHandler
// decorators are called on any other classes (like servlets and filters)
if(_servletHandler.getListeners() != null) if(_servletHandler.getListeners() != null)
{ {
for (ListenerHolder holder:_servletHandler.getListeners()) 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

@ -1912,16 +1912,10 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor
((WebDescriptor)descriptor).addClassName(className); ((WebDescriptor)descriptor).addClassName(className);
Class<? extends EventListener> listenerClass = (Class<? extends EventListener>)context.loadClass(className); ListenerHolder h = context.getServletHandler().newListenerHolder(new Source (Source.Origin.DESCRIPTOR, descriptor.getResource().toString()));
listener = newListenerInstance(context,listenerClass, descriptor); h.setClassName(className);
if (!(listener instanceof EventListener)) context.getServletHandler().addListener(h);
{
LOG.warn("Not an EventListener: " + listener);
return;
}
context.addEventListener(listener);
context.getMetaData().setOrigin(className+".listener", descriptor); context.getMetaData().setOrigin(className+".listener", descriptor);
} }
} }
catch (Exception e) catch (Exception e)
@ -1960,14 +1954,4 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor
((ConstraintAware)context.getSecurityHandler()).setDenyUncoveredHttpMethods(true); ((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;
}
} }