From b1e08ba4e0f7ad07be9ecaf2e5ad2f31f73540e1 Mon Sep 17 00:00:00 2001 From: Jan Bartel Date: Tue, 14 Jul 2020 11:20:20 +0200 Subject: [PATCH] Issue #5020 Make servlets,filters,listeners beans again (#5028) * Issue #5020 Make servlets,filters,listeners beans again Signed-off-by: Jan Bartel --- .../eclipse/jetty/servlet/ServletHandler.java | 26 ++++++- .../jetty/servlet/ServletHandlerTest.java | 73 +++++++++++++++++++ .../util/component/ContainerLifeCycle.java | 2 +- .../jetty/util/component/Dumpable.java | 27 ++++++- 4 files changed, 120 insertions(+), 8 deletions(-) diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHandler.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHandler.java index eebc610f0b3..00e34d91fed 100644 --- a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHandler.java +++ b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHandler.java @@ -133,6 +133,12 @@ public class ServletHandler extends ScopedHandler { } + @Override + public boolean isDumpable(Object o) + { + return !(o instanceof Holder || o instanceof BaseHolder || o instanceof FilterMapping || o instanceof ServletMapping); + } + @Override public void dump(Appendable out, String indent) throws IOException { @@ -220,6 +226,13 @@ public class ServletHandler extends ScopedHandler if (!(l instanceof Holder)) super.start(l); } + + @Override + protected void stop(LifeCycle l) throws Exception + { + if (!(l instanceof Holder)) + super.stop(l); + } @Override protected synchronized void doStop() @@ -262,8 +275,10 @@ public class ServletHandler extends ScopedHandler //Retain only filters and mappings that were added using jetty api (ie Source.EMBEDDED) FilterHolder[] fhs = (FilterHolder[])LazyList.toArray(filterHolders, FilterHolder.class); + updateBeans(_filters, fhs); _filters = fhs; FilterMapping[] fms = (FilterMapping[])LazyList.toArray(filterMappings, FilterMapping.class); + updateBeans(_filterMappings, fms); _filterMappings = fms; _matchAfterIndex = (_filterMappings == null || _filterMappings.length == 0 ? -1 : _filterMappings.length - 1); @@ -305,8 +320,10 @@ public class ServletHandler extends ScopedHandler //Retain only Servlets and mappings added via jetty apis (ie Source.EMBEDDED) ServletHolder[] shs = (ServletHolder[])LazyList.toArray(servletHolders, ServletHolder.class); + updateBeans(_servlets, shs); _servlets = shs; ServletMapping[] sms = (ServletMapping[])LazyList.toArray(servletMappings, ServletMapping.class); + updateBeans(_servletMappings, sms); _servletMappings = sms; if (_contextHandler != null) @@ -331,6 +348,7 @@ public class ServletHandler extends ScopedHandler } } ListenerHolder[] listeners = (ListenerHolder[])LazyList.toArray(listenerHolders, ListenerHolder.class); + updateBeans(_listeners, listeners); _listeners = listeners; //will be regenerated on next start @@ -814,7 +832,7 @@ public class ServletHandler extends ScopedHandler { holder.setServletHandler(this); } - + updateBeans(_listeners,listeners); _listeners = listeners; } @@ -1516,6 +1534,7 @@ public class ServletHandler extends ScopedHandler */ public void setFilterMappings(FilterMapping[] filterMappings) { + updateBeans(_filterMappings,filterMappings); _filterMappings = filterMappings; if (isStarted()) updateMappings(); @@ -1529,7 +1548,7 @@ public class ServletHandler extends ScopedHandler { holder.setServletHandler(this); } - + updateBeans(_filters,holders); _filters = holders; updateNameMappings(); invalidateChainsCache(); @@ -1540,6 +1559,7 @@ public class ServletHandler extends ScopedHandler */ public void setServletMappings(ServletMapping[] servletMappings) { + updateBeans(_servletMappings,servletMappings); _servletMappings = servletMappings; if (isStarted()) updateMappings(); @@ -1558,7 +1578,7 @@ public class ServletHandler extends ScopedHandler { holder.setServletHandler(this); } - + updateBeans(_servlets,holders); _servlets = holders; updateNameMappings(); invalidateChainsCache(); diff --git a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/ServletHandlerTest.java b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/ServletHandlerTest.java index 3cd678e3dd9..29dc90ad1c1 100644 --- a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/ServletHandlerTest.java +++ b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/ServletHandlerTest.java @@ -18,10 +18,15 @@ package org.eclipse.jetty.servlet; +import java.util.ArrayList; import java.util.EnumSet; +import java.util.List; import javax.servlet.DispatcherType; +import javax.servlet.http.HttpSessionEvent; +import javax.servlet.http.HttpSessionListener; import org.eclipse.jetty.http.pathmap.MappedResource; +import org.eclipse.jetty.util.component.Container; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -657,4 +662,72 @@ public class ServletHandlerTest assertTrue(fh3 == mappings[5].getFilterHolder()); //isMatchAfter = true; assertTrue(pf == mappings[6].getFilterHolder()); //isMatchAfter = true; } + + @Test + public void testFiltersServletsListenersAsBeans() throws Exception + { + ServletContextHandler context = new ServletContextHandler(); + + ServletHandler handler = context.getServletHandler(); + + //test that filters, servlets and listeners are added as beans + //and thus reported in a Container.Listener + List addResults = new ArrayList<>(); + List removeResults = new ArrayList<>(); + handler.addEventListener(new Container.Listener() + { + @Override + public void beanAdded(Container parent, Object child) + { + addResults.add(child); + } + + @Override + public void beanRemoved(Container parent, Object child) + { + removeResults.add(child); + } + + }); + + handler.addFilter(fh1); + handler.addServlet(sh1); + ListenerHolder lh1 = new ListenerHolder(new Source(Source.Origin.DESCRIPTOR, "foo.xml")); + lh1.setInstance(new HttpSessionListener() + { + @Override + public void sessionDestroyed(HttpSessionEvent se) + { + } + + @Override + public void sessionCreated(HttpSessionEvent se) + { + } + }); + handler.addListener(lh1); + + assertTrue(addResults.contains(fh1)); + assertTrue(addResults.contains(sh1)); + assertTrue(addResults.contains(lh1)); + + //test that servlets, filters and listeners are dumped, but + //not as beans + String dump = handler.dump(); + dump = dump.substring(0, dump.indexOf("key:")); + + assertFalse(dump.contains("+-")); //not dumped as beans + assertFalse(dump.contains("+=")); //not dumped as managed beans + assertFalse(dump.contains("+~")); //not dumped as unmanaged beans + assertFalse(dump.contains("+?")); //not dumped as auto beans + + handler.setFilters(null); + handler.setServlets(null); + handler.setListeners(null); + + //check they're removed as beans + assertTrue(removeResults.contains(fh1)); + assertTrue(removeResults.contains(sh1)); + assertTrue(removeResults.contains(lh1)); + } } diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/component/ContainerLifeCycle.java b/jetty-util/src/main/java/org/eclipse/jetty/util/component/ContainerLifeCycle.java index b4d56e68546..3051a0a7dce 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/component/ContainerLifeCycle.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/component/ContainerLifeCycle.java @@ -75,7 +75,7 @@ import org.eclipse.jetty.util.log.Logger; * */ @ManagedObject("Implementation of Container and LifeCycle") -public class ContainerLifeCycle extends AbstractLifeCycle implements Container, Destroyable, Dumpable +public class ContainerLifeCycle extends AbstractLifeCycle implements Container, Destroyable, Dumpable.DumpableContainer { private static final Logger LOG = Log.getLogger(ContainerLifeCycle.class); private final List _beans = new CopyOnWriteArrayList<>(); diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/component/Dumpable.java b/jetty-util/src/main/java/org/eclipse/jetty/util/component/Dumpable.java index 05c25e28193..0eca4657e0d 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/component/Dumpable.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/component/Dumpable.java @@ -145,9 +145,9 @@ public interface Dumpable static void dumpObjects(Appendable out, String indent, Object object, Object... extraChildren) throws IOException { dumpObject(out, object); - + int extras = extraChildren == null ? 0 : extraChildren.length; - + if (object instanceof Stream) object = ((Stream)object).toArray(); if (object instanceof Array) @@ -181,7 +181,7 @@ public interface Dumpable dumpObjects(out, nextIndent, item); } } - + static void dumpContainer(Appendable out, String indent, Container object, boolean last) throws IOException { Container container = object; @@ -189,6 +189,10 @@ public interface Dumpable for (Iterator i = container.getBeans().iterator(); i.hasNext(); ) { Object bean = i.next(); + + if (container instanceof DumpableContainer && !((DumpableContainer)container).isDumpable(bean)) + continue; //won't be dumped as a child bean + String nextIndent = indent + ((i.hasNext() || !last) ? "| " : " "); if (bean instanceof LifeCycle) { @@ -229,7 +233,7 @@ public interface Dumpable } } } - + static void dumpIterable(Appendable out, String indent, Iterable iterable, boolean last) throws IOException { for (Iterator i = iterable.iterator(); i.hasNext(); ) @@ -267,4 +271,19 @@ public interface Dumpable Dumpable.dumpObjects(out, indent, object); }; } + + /** + * DumpableContainer + * + * A Dumpable that is a container of beans can implement this + * interface to allow it to refine which of its beans can be + * dumped. + */ + public interface DumpableContainer extends Dumpable + { + default boolean isDumpable(Object o) + { + return true; + } + } }