Fix #5835 Durable filters and servlets (#6027)

Fix #5835 Durable filters and servlets with a general ServletHandler cleanup
update indexes after updating mapping
update mappings/indexes before destroyed listeners

Signed-off-by: Greg Wilkins <gregw@webtide.com>
This commit is contained in:
Greg Wilkins 2021-03-22 18:28:25 +08:00 committed by GitHub
parent cc81b309f3
commit c59de808f1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 566 additions and 498 deletions

View File

@ -651,7 +651,24 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
} }
if (listener instanceof ServletContextListener) if (listener instanceof ServletContextListener)
{
if (_contextStatus == ContextStatus.INITIALIZED)
{
ServletContextListener scl = (ServletContextListener)listener;
_destroyServletContextListeners.add(scl);
if (isStarting())
{
LOG.warn("ContextListener {} added whilst starting {}", scl, this);
callContextInitialized(scl, new ServletContextEvent(_scontext));
}
else
{
LOG.warn("ContextListener {} added after starting {}", scl, this);
}
}
_servletContextListeners.add((ServletContextListener)listener); _servletContextListeners.add((ServletContextListener)listener);
}
if (listener instanceof ServletContextAttributeListener) if (listener instanceof ServletContextAttributeListener)
_servletContextAttributeListeners.add((ServletContextAttributeListener)listener); _servletContextAttributeListeners.add((ServletContextAttributeListener)listener);
@ -933,31 +950,19 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
public void contextInitialized() throws Exception public void contextInitialized() throws Exception
{ {
// Call context listeners // Call context listeners
switch (_contextStatus) if (_contextStatus == ContextStatus.NOTSET)
{ {
case NOTSET: _contextStatus = ContextStatus.INITIALIZED;
_destroyServletContextListeners.clear();
if (!_servletContextListeners.isEmpty())
{ {
try ServletContextEvent event = new ServletContextEvent(_scontext);
for (ServletContextListener listener : _servletContextListeners)
{ {
_destroyServletContextListeners.clear(); callContextInitialized(listener, event);
if (!_servletContextListeners.isEmpty()) _destroyServletContextListeners.add(listener);
{
ServletContextEvent event = new ServletContextEvent(_scontext);
for (ServletContextListener listener : _servletContextListeners)
{
callContextInitialized(listener, event);
_destroyServletContextListeners.add(listener);
}
}
} }
finally
{
_contextStatus = ContextStatus.INITIALIZED;
}
break;
} }
default:
break;
} }
} }

View File

@ -22,6 +22,7 @@ import java.nio.file.Path;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener; import javax.servlet.ServletContextListener;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
@ -39,6 +40,7 @@ import org.eclipse.jetty.util.resource.Resource;
import org.hamcrest.Matchers; import org.hamcrest.Matchers;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.ExtendWith;
import org.slf4j.LoggerFactory;
import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.containsString;
@ -778,6 +780,71 @@ public class ContextHandlerTest
assertThat("classpath", classpath, containsString(jar.toString())); assertThat("classpath", classpath, containsString(jar.toString()));
} }
@Test
public void testNonDurableContextListener() throws Exception
{
Server server = new Server();
ContextHandler context = new ContextHandler();
server.setHandler(context);
AtomicInteger initialized = new AtomicInteger();
AtomicInteger destroyed = new AtomicInteger();
context.addEventListener(new ServletContextListener()
{
@Override
public void contextInitialized(ServletContextEvent sce)
{
initialized.incrementAndGet();
context.addEventListener(new ServletContextListener()
{
@Override
public void contextInitialized(ServletContextEvent sce)
{
initialized.incrementAndGet();
}
@Override
public void contextDestroyed(ServletContextEvent sce)
{
destroyed.incrementAndGet();
}
});
}
@Override
public void contextDestroyed(ServletContextEvent sce)
{
destroyed.incrementAndGet();
}
});
LoggerFactory.getLogger(ContextHandler.class).info("Expect WARN ContextListener ... add whilst starting ...");
server.start();
assertThat(initialized.get(), is(2));
LoggerFactory.getLogger(ContextHandler.class).info("Expect WARN ContextListener ... add after starting ...");
context.addEventListener(new ServletContextListener()
{
@Override
public void contextInitialized(ServletContextEvent sce)
{
// This should not get called because added after started
initialized.incrementAndGet();
}
@Override
public void contextDestroyed(ServletContextEvent sce)
{
destroyed.incrementAndGet();
}
});
assertThat(initialized.get(), is(2));
server.stop();
assertThat(destroyed.get(), is(3));
}
private void checkResourcePathsForExampleWebApp(String root) throws IOException private void checkResourcePathsForExampleWebApp(String root) throws IOException
{ {
File testDirectory = setupTestDirectory(); File testDirectory = setupTestDirectory();

View File

@ -16,6 +16,7 @@ package org.eclipse.jetty.servlet;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.EventListener; import java.util.EventListener;
@ -27,6 +28,7 @@ import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentMap;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
import javax.servlet.DispatcherType; import javax.servlet.DispatcherType;
import javax.servlet.Filter; import javax.servlet.Filter;
@ -87,8 +89,8 @@ public class ServletHandler extends ScopedHandler
private final AutoLock _lock = new AutoLock(); private final AutoLock _lock = new AutoLock();
private ServletContextHandler _contextHandler; private ServletContextHandler _contextHandler;
private ServletContext _servletContext; private ServletContext _servletContext;
private FilterHolder[] _filters = new FilterHolder[0]; private final List<FilterHolder> _filters = new ArrayList<>();
private FilterMapping[] _filterMappings; private final List<FilterMapping> _filterMappings = new ArrayList<>();
private int _matchBeforeIndex = -1; //index of last programmatic FilterMapping with isMatchAfter=false private int _matchBeforeIndex = -1; //index of last programmatic FilterMapping with isMatchAfter=false
private int _matchAfterIndex = -1; //index of 1st programmatic FilterMapping with isMatchAfter=true private int _matchAfterIndex = -1; //index of 1st programmatic FilterMapping with isMatchAfter=true
private boolean _filterChainsCached = true; private boolean _filterChainsCached = true;
@ -98,17 +100,18 @@ public class ServletHandler extends ScopedHandler
private IdentityService _identityService; private IdentityService _identityService;
private boolean _allowDuplicateMappings = false; private boolean _allowDuplicateMappings = false;
private ServletHolder[] _servlets = new ServletHolder[0]; private final List<ServletHolder> _servlets = new ArrayList<>();
private ServletMapping[] _servletMappings; private final List<ServletMapping> _servletMappings = new ArrayList<>();
private final Map<String, FilterHolder> _filterNameMap = new HashMap<>(); private final Map<String, FilterHolder> _filterNameMap = new HashMap<>();
private List<FilterMapping> _filterPathMappings; private List<FilterMapping> _filterPathMappings;
private MultiMap<FilterMapping> _filterNameMappings; private MultiMap<FilterMapping> _filterNameMappings;
private List<FilterMapping> _wildFilterNameMappings; private List<FilterMapping> _wildFilterNameMappings;
private final List<BaseHolder<?>> _durable = new ArrayList<>();
private final Map<String, MappedServlet> _servletNameMap = new HashMap<>(); private final Map<String, MappedServlet> _servletNameMap = new HashMap<>();
private PathMappings<MappedServlet> _servletPathMap; private PathMappings<MappedServlet> _servletPathMap;
private ListenerHolder[] _listeners = new ListenerHolder[0]; private final List<ListenerHolder> _listeners = new ArrayList<>();
private boolean _initialized = false; private boolean _initialized = false;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@ -126,6 +129,13 @@ public class ServletHandler extends ScopedHandler
return _lock.lock(); return _lock.lock();
} }
private <T> void updateAndSet(Collection<T> target, Collection<T> values)
{
updateBeans(target, values);
target.clear();
target.addAll(values);
}
@Override @Override
public boolean isDumpable(Object o) public boolean isDumpable(Object o)
{ {
@ -136,17 +146,18 @@ public class ServletHandler extends ScopedHandler
public void dump(Appendable out, String indent) throws IOException public void dump(Appendable out, String indent) throws IOException
{ {
dumpObjects(out, indent, dumpObjects(out, indent,
DumpableCollection.fromArray("listeners " + this, _listeners), DumpableCollection.from("listeners " + this, _listeners),
DumpableCollection.fromArray("filters " + this, _filters), DumpableCollection.from("filters " + this, _filters),
DumpableCollection.fromArray("filterMappings " + this, _filterMappings), DumpableCollection.from("filterMappings " + this, _filterMappings),
DumpableCollection.fromArray("servlets " + this, _servlets), DumpableCollection.from("servlets " + this, _servlets),
DumpableCollection.fromArray("servletMappings " + this, _servletMappings)); DumpableCollection.from("servletMappings " + this, _servletMappings),
DumpableCollection.from("durable " + this, _durable));
} }
@Override @Override
protected void doStart() throws Exception protected void doStart() throws Exception
{ {
try (AutoLock l = lock()) try (AutoLock ignored = lock())
{ {
ContextHandler.Context context = ContextHandler.getCurrentContext(); ContextHandler.Context context = ContextHandler.getCurrentContext();
_servletContext = context == null ? new ContextHandler.StaticContext() : context; _servletContext = context == null ? new ContextHandler.StaticContext() : context;
@ -159,6 +170,11 @@ public class ServletHandler extends ScopedHandler
_identityService = securityHandler.getIdentityService(); _identityService = securityHandler.getIdentityService();
} }
_durable.clear();
_durable.addAll(Arrays.asList(getFilters()));
_durable.addAll(Arrays.asList(getServlets()));
_durable.addAll(Arrays.asList(getListeners()));
updateNameMappings(); updateNameMappings();
updateMappings(); updateMappings();
@ -226,113 +242,93 @@ public class ServletHandler extends ScopedHandler
@Override @Override
protected void doStop() throws Exception protected void doStop() throws Exception
{ {
try (AutoLock l = lock()) try (AutoLock ignored = lock())
{ {
super.doStop(); super.doStop();
// Stop filters // Stop filters
List<FilterHolder> filterHolders = new ArrayList<>(); List<FilterHolder> filterHolders = new ArrayList<>();
List<FilterMapping> filterMappings = ArrayUtil.asMutableList(_filterMappings); for (int i = _filters.size(); i-- > 0; )
if (_filters != null)
{ {
for (int i = _filters.length; i-- > 0; ) FilterHolder filter = _filters.get(i);
try
{ {
FilterHolder filter = _filters[i]; filter.stop();
try }
{ catch (Exception e)
filter.stop(); {
} LOG.warn("Unable to stop filter {}", filter, e);
catch (Exception e) }
{ if (_durable.contains(filter))
LOG.warn("Unable to stop filter {}", filter, e); {
} filterHolders.add(filter); //only retain durable
if (filter.getSource() != Source.EMBEDDED)
{
//remove all of the mappings that were for non-embedded filters
_filterNameMap.remove(filter.getName());
//remove any mappings associated with this filter
filterMappings.removeIf(fm -> fm.getFilterName().equals(filter.getName()));
}
else
filterHolders.add(filter); //only retain embedded
} }
} }
//Retain only filters and mappings that were added using jetty api (ie Source.EMBEDDED) //Retain only durable filters
FilterHolder[] fhs = filterHolders.toArray(new FilterHolder[0]); updateBeans(_filters, filterHolders);
updateBeans(_filters, fhs); _filters.clear();
_filters = fhs; _filters.addAll(filterHolders);
FilterMapping[] fms = filterMappings.toArray(new FilterMapping[0]);
updateBeans(_filterMappings, fms);
_filterMappings = fms;
_matchAfterIndex = (_filterMappings.length == 0 ? -1 : _filterMappings.length - 1);
_matchBeforeIndex = -1;
// Stop servlets // Stop servlets
List<ServletHolder> servletHolders = new ArrayList<>(); //will be remaining servlets List<ServletHolder> servletHolders = new ArrayList<>(); //will be remaining servlets
List<ServletMapping> servletMappings = ArrayUtil.asMutableList(_servletMappings); //will be remaining mappings for (int i = _servlets.size(); i-- > 0; )
if (_servlets != null)
{ {
for (int i = _servlets.length; i-- > 0; ) ServletHolder servlet = _servlets.get(i);
try
{ {
ServletHolder servlet = _servlets[i]; servlet.stop();
try }
{ catch (Exception e)
servlet.stop(); {
} LOG.warn("Unable to stop servlet {}", servlet, e);
catch (Exception e) }
{
LOG.warn("Unable to stop servlet {}", servlet, e);
}
if (servlet.getSource() != Source.EMBEDDED) if (_durable.contains(servlet))
{ {
//remove from servlet name map servletHolders.add(servlet); //only retain embedded
_servletNameMap.remove(servlet.getName());
//remove any mappings associated with this servlet
servletMappings.removeIf(sm -> sm.getServletName().equals(servlet.getName()));
}
else
servletHolders.add(servlet); //only retain embedded
} }
} }
//Retain only Servlets and mappings added via jetty apis (ie Source.EMBEDDED) //Retain only durable Servlets
ServletHolder[] shs = servletHolders.toArray(new ServletHolder[0]); updateBeans(_servlets, servletHolders);
updateBeans(_servlets, shs); _servlets.clear();
_servlets = shs; _servlets.addAll(servletHolders);
ServletMapping[] sms = servletMappings.toArray(new ServletMapping[0]);
updateBeans(_servletMappings, sms); updateNameMappings();
_servletMappings = sms; updateAndSet(_servletMappings, _servletMappings.stream().filter(m -> _servletNameMap.containsKey(m.getServletName())).collect(Collectors.toList()));
updateAndSet(_filterMappings, _filterMappings.stream().filter(m -> _filterNameMap.containsKey(m.getFilterName())).collect(Collectors.toList()));
updateMappings();
if (_contextHandler != null) if (_contextHandler != null)
_contextHandler.contextDestroyed(); _contextHandler.contextDestroyed();
//Retain only Listeners added via jetty apis (is Source.EMBEDDED) //Retain only Listeners added via jetty apis (is Source.EMBEDDED)
List<ListenerHolder> listenerHolders = new ArrayList<>(); List<ListenerHolder> listenerHolders = new ArrayList<>();
if (_listeners != null) for (int i = _listeners.size(); i-- > 0; )
{ {
for (int i = _listeners.length; i-- > 0; ) ListenerHolder listener = _listeners.get(i);
try
{ {
ListenerHolder listener = _listeners[i]; listener.stop();
try
{
listener.stop();
}
catch (Exception e)
{
LOG.warn("Unable to stop listener {}", listener, e);
}
if (listener.getSource() == Source.EMBEDDED)
listenerHolders.add(listener);
} }
catch (Exception e)
{
LOG.warn("Unable to stop listener {}", listener, e);
}
if (_durable.contains(listener))
listenerHolders.add(listener);
} }
ListenerHolder[] listeners = listenerHolders.toArray(new ListenerHolder[0]);
updateBeans(_listeners, listeners);
_listeners = listeners;
//will be regenerated on next start updateBeans(_listeners, listenerHolders);
_listeners.clear();
_listeners.addAll(listenerHolders);
// Update indexes for prepending filters
_matchAfterIndex = (_filterMappings.size() == 0 ? -1 : _filterMappings.size() - 1);
_matchBeforeIndex = -1;
_durable.clear();
_filterPathMappings = null; _filterPathMappings = null;
_filterNameMappings = null; _filterNameMappings = null;
_servletPathMap = null; _servletPathMap = null;
@ -348,13 +344,13 @@ public class ServletHandler extends ScopedHandler
@ManagedAttribute(value = "filters", readonly = true) @ManagedAttribute(value = "filters", readonly = true)
public FilterMapping[] getFilterMappings() public FilterMapping[] getFilterMappings()
{ {
return _filterMappings; return _filterMappings.toArray(new FilterMapping[0]);
} }
@ManagedAttribute(value = "filters", readonly = true) @ManagedAttribute(value = "filters", readonly = true)
public FilterHolder[] getFilters() public FilterHolder[] getFilters()
{ {
return _filters; return _filters.toArray(new FilterHolder[0]);
} }
public ServletContext getServletContext() public ServletContext getServletContext()
@ -370,7 +366,7 @@ public class ServletHandler extends ScopedHandler
@ManagedAttribute(value = "mappings of servlets", readonly = true) @ManagedAttribute(value = "mappings of servlets", readonly = true)
public ServletMapping[] getServletMappings() public ServletMapping[] getServletMappings()
{ {
return _servletMappings; return _servletMappings.toArray(new ServletMapping[0]);
} }
/** /**
@ -381,13 +377,13 @@ public class ServletHandler extends ScopedHandler
*/ */
public ServletMapping getServletMapping(String pathSpec) public ServletMapping getServletMapping(String pathSpec)
{ {
if (pathSpec == null || _servletMappings == null) if (pathSpec == null)
return null; return null;
ServletMapping mapping = null; ServletMapping mapping = null;
for (int i = 0; i < _servletMappings.length && mapping == null; i++) for (int i = 0; i < _servletMappings.size() && mapping == null; i++)
{ {
ServletMapping m = _servletMappings[i]; ServletMapping m = _servletMappings.get(i);
if (m.getPathSpecs() != null) if (m.getPathSpecs() != null)
{ {
for (String p : m.getPathSpecs()) for (String p : m.getPathSpecs())
@ -406,7 +402,7 @@ public class ServletHandler extends ScopedHandler
@ManagedAttribute(value = "servlets", readonly = true) @ManagedAttribute(value = "servlets", readonly = true)
public ServletHolder[] getServlets() public ServletHolder[] getServlets()
{ {
return _servlets; return _servlets.toArray(new ServletHolder[0]);
} }
public List<ServletHolder> getServlets(Class<?> clazz) public List<ServletHolder> getServlets(Class<?> clazz)
@ -483,7 +479,7 @@ public class ServletHandler extends ScopedHandler
FilterChain chain = null; FilterChain chain = null;
// find the servlet // find the servlet
if (servletHolder != null && _filterMappings != null && _filterMappings.length > 0) if (servletHolder != null && _filterMappings.size() > 0)
chain = getFilterChain(baseRequest, target.startsWith("/") ? target : null, servletHolder); chain = getFilterChain(baseRequest, target.startsWith("/") ? target : null, servletHolder);
if (LOG.isDebugEnabled()) if (LOG.isDebugEnabled())
@ -702,7 +698,7 @@ public class ServletHandler extends ScopedHandler
}; };
//Start the listeners so we can call them //Start the listeners so we can call them
Arrays.stream(_listeners).forEach(c); _listeners.forEach(c);
//call listeners contextInitialized //call listeners contextInitialized
if (_contextHandler != null) if (_contextHandler != null)
@ -713,8 +709,8 @@ public class ServletHandler extends ScopedHandler
//Start the filters then the servlets //Start the filters then the servlets
Stream.concat( Stream.concat(
Arrays.stream(_filters), _filters.stream(),
Arrays.stream(_servlets).sorted()) _servlets.stream().sorted())
.forEach(c); .forEach(c);
mx.ifExceptionThrow(); mx.ifExceptionThrow();
@ -728,7 +724,7 @@ public class ServletHandler extends ScopedHandler
return _initialized; return _initialized;
} }
protected void initializeHolders(BaseHolder<?>[] holders) protected void initializeHolders(Collection<? extends BaseHolder<?>> holders)
{ {
for (BaseHolder<?> holder : holders) for (BaseHolder<?> holder : holders)
{ {
@ -772,15 +768,16 @@ public class ServletHandler extends ScopedHandler
public ListenerHolder[] getListeners() public ListenerHolder[] getListeners()
{ {
return _listeners; return _listeners.toArray(new ListenerHolder[0]);
} }
public void setListeners(ListenerHolder[] listeners) public void setListeners(ListenerHolder[] holders)
{ {
if (listeners != null) List<ListenerHolder> listeners = holders == null ? Collections.emptyList() : Arrays.asList(holders);
initializeHolders(listeners); initializeHolders(listeners);
updateBeans(_listeners, listeners); updateBeans(_listeners, listeners);
_listeners = listeners; _listeners.clear();
_listeners.addAll(listeners);
} }
public ListenerHolder newListenerHolder(Source source) public ListenerHolder newListenerHolder(Source source)
@ -842,7 +839,7 @@ public class ServletHandler extends ScopedHandler
ServletHolder[] holders = getServlets(); ServletHolder[] holders = getServlets();
try try
{ {
try (AutoLock l = lock()) try (AutoLock ignored = lock())
{ {
if (!containsServletHolder(servlet)) if (!containsServletHolder(servlet))
setServlets(ArrayUtil.addToArray(holders, servlet, ServletHolder.class)); setServlets(ArrayUtil.addToArray(holders, servlet, ServletHolder.class));
@ -870,7 +867,7 @@ public class ServletHandler extends ScopedHandler
if (holder == null) if (holder == null)
return; return;
try (AutoLock l = lock()) try (AutoLock ignored = lock())
{ {
if (!containsServletHolder(holder)) if (!containsServletHolder(holder))
setServlets(ArrayUtil.addToArray(getServlets(), holder, ServletHolder.class)); setServlets(ArrayUtil.addToArray(getServlets(), holder, ServletHolder.class));
@ -954,7 +951,7 @@ public class ServletHandler extends ScopedHandler
try try
{ {
try (AutoLock l = lock()) try (AutoLock ignored = lock())
{ {
if (!containsFilterHolder(holder)) if (!containsFilterHolder(holder))
setFilters(ArrayUtil.addToArray(holders, holder, FilterHolder.class)); setFilters(ArrayUtil.addToArray(holders, holder, FilterHolder.class));
@ -1023,7 +1020,7 @@ public class ServletHandler extends ScopedHandler
try try
{ {
try (AutoLock l = lock()) try (AutoLock ignored = lock())
{ {
if (!containsFilterHolder(holder)) if (!containsFilterHolder(holder))
setFilters(ArrayUtil.addToArray(holders, holder, FilterHolder.class)); setFilters(ArrayUtil.addToArray(holders, holder, FilterHolder.class));
@ -1052,7 +1049,7 @@ public class ServletHandler extends ScopedHandler
{ {
if (filter != null) if (filter != null)
{ {
try (AutoLock l = lock()) try (AutoLock ignored = lock())
{ {
if (!containsFilterHolder(filter)) if (!containsFilterHolder(filter))
setFilters(ArrayUtil.addToArray(getFilters(), filter, FilterHolder.class)); setFilters(ArrayUtil.addToArray(getFilters(), filter, FilterHolder.class));
@ -1072,7 +1069,7 @@ public class ServletHandler extends ScopedHandler
if (filter == null) if (filter == null)
return; return;
try (AutoLock l = lock()) try (AutoLock ignored = lock())
{ {
if (!containsFilterHolder(filter)) if (!containsFilterHolder(filter))
setFilters(ArrayUtil.addToArray(getFilters(), filter, FilterHolder.class)); setFilters(ArrayUtil.addToArray(getFilters(), filter, FilterHolder.class));
@ -1089,7 +1086,7 @@ public class ServletHandler extends ScopedHandler
if (filter == null) if (filter == null)
return; return;
try (AutoLock l = lock()) try (AutoLock ignored = lock())
{ {
if (!containsFilterHolder(filter)) if (!containsFilterHolder(filter))
setFilters(ArrayUtil.prependToArray(filter, getFilters(), FilterHolder.class)); setFilters(ArrayUtil.prependToArray(filter, getFilters(), FilterHolder.class));
@ -1103,24 +1100,27 @@ public class ServletHandler extends ScopedHandler
*/ */
public void addFilterMapping(FilterMapping mapping) public void addFilterMapping(FilterMapping mapping)
{ {
if (mapping != null) if (mapping == null)
return;
try (AutoLock ignored = lock())
{ {
Source source = (mapping.getFilterHolder() == null ? null : mapping.getFilterHolder().getSource()); Source source = (mapping.getFilterHolder() == null ? null : mapping.getFilterHolder().getSource());
FilterMapping[] mappings = getFilterMappings();
if (mappings == null || mappings.length == 0) if (_filterMappings.isEmpty())
{ {
setFilterMappings(insertFilterMapping(mapping, 0, false)); _filterMappings.add(mapping);
if (source == Source.JAVAX_API) if (source == Source.JAVAX_API)
_matchAfterIndex = 0; _matchAfterIndex = 0;
} }
else else
{ {
//there are existing entries. If this is a programmatic filtermapping, it is added at the end of the list. //there are existing entries. If this is a programmatic filtermapping, it is added at the end of the list.
//If this is a normal filtermapping, it is inserted after all the other filtermappings (matchBefores and normals), //If this is a normal filtermapping, it is inserted after all the other filtermappings (matchBefores and normals),
//but before the first matchAfter filtermapping. //but before the first matchAfter filtermapping.
if (Source.JAVAX_API == source) if (Source.JAVAX_API == source)
{ {
setFilterMappings(insertFilterMapping(mapping, mappings.length - 1, false)); _filterMappings.add(mapping);
if (_matchAfterIndex < 0) if (_matchAfterIndex < 0)
_matchAfterIndex = getFilterMappings().length - 1; _matchAfterIndex = getFilterMappings().length - 1;
} }
@ -1128,15 +1128,15 @@ public class ServletHandler extends ScopedHandler
{ {
//insert non-programmatic filter mappings before any matchAfters, if any //insert non-programmatic filter mappings before any matchAfters, if any
if (_matchAfterIndex < 0) if (_matchAfterIndex < 0)
setFilterMappings(insertFilterMapping(mapping, mappings.length - 1, false)); _filterMappings.add(mapping);
else else
{ _filterMappings.add(_matchAfterIndex++, mapping);
FilterMapping[] newMappings = insertFilterMapping(mapping, _matchAfterIndex, true);
++_matchAfterIndex;
setFilterMappings(newMappings);
}
} }
} }
addBean(mapping);
if (isRunning())
updateMappings();
invalidateChainsCache();
} }
} }
@ -1147,13 +1147,15 @@ public class ServletHandler extends ScopedHandler
*/ */
public void prependFilterMapping(FilterMapping mapping) public void prependFilterMapping(FilterMapping mapping)
{ {
if (mapping != null) if (mapping == null)
return;
try (AutoLock ignored = lock())
{ {
Source source = (mapping.getFilterHolder() == null ? null : mapping.getFilterHolder().getSource()); Source source = (mapping.getFilterHolder() == null ? null : mapping.getFilterHolder().getSource());
FilterMapping[] mappings = getFilterMappings(); if (_filterMappings.isEmpty())
if (mappings == null || mappings.length == 0)
{ {
setFilterMappings(insertFilterMapping(mapping, 0, false)); _filterMappings.add(mapping);
if (Source.JAVAX_API == source) if (Source.JAVAX_API == source)
_matchBeforeIndex = 0; _matchBeforeIndex = 0;
} }
@ -1169,235 +1171,168 @@ public class ServletHandler extends ScopedHandler
{ {
//no programmatically defined prepended filter mappings yet, prepend this one //no programmatically defined prepended filter mappings yet, prepend this one
_matchBeforeIndex = 0; _matchBeforeIndex = 0;
FilterMapping[] newMappings = insertFilterMapping(mapping, 0, true); _filterMappings.add(0, mapping);
setFilterMappings(newMappings);
} }
else else
{ {
FilterMapping[] newMappings = insertFilterMapping(mapping, _matchBeforeIndex, false); _filterMappings.add(1 + _matchBeforeIndex++, mapping);
++_matchBeforeIndex;
setFilterMappings(newMappings);
} }
} }
else else
{ {
//non programmatically defined, just prepend to list //non programmatically defined, just prepend to list
FilterMapping[] newMappings = insertFilterMapping(mapping, 0, true); _filterMappings.add(0, mapping);
setFilterMappings(newMappings);
} }
//adjust matchAfterIndex ptr to take account of the mapping we just prepended //adjust matchAfterIndex ptr to take account of the mapping we just prepended
if (_matchAfterIndex >= 0) if (_matchAfterIndex >= 0)
++_matchAfterIndex; ++_matchAfterIndex;
} }
addBean(mapping);
if (isRunning())
updateMappings();
invalidateChainsCache();
} }
} }
/**
* Insert a filtermapping in the list
*
* @param mapping the FilterMapping to add
* @param pos the position in the existing arry at which to add it
* @param before if true, insert before pos, if false insert after it
* @return the new FilterMappings post-insert
*/
protected FilterMapping[] insertFilterMapping(FilterMapping mapping, int pos, boolean before)
{
if (pos < 0)
throw new IllegalArgumentException("FilterMapping insertion pos < 0");
FilterMapping[] mappings = getFilterMappings();
if (mappings == null || mappings.length == 0)
{
return new FilterMapping[]{mapping};
}
FilterMapping[] newMappings = new FilterMapping[mappings.length + 1];
if (before)
{
//copy existing filter mappings up to but not including the pos
System.arraycopy(mappings, 0, newMappings, 0, pos);
//add in the new mapping
newMappings[pos] = mapping;
//copy the old pos mapping and any remaining existing mappings
System.arraycopy(mappings, pos, newMappings, pos + 1, mappings.length - pos);
}
else
{
//copy existing filter mappings up to and including the pos
System.arraycopy(mappings, 0, newMappings, 0, pos + 1);
//add in the new mapping after the pos
newMappings[pos + 1] = mapping;
//copy the remaining existing mappings
if (mappings.length > pos + 1)
System.arraycopy(mappings, pos + 1, newMappings, pos + 2, mappings.length - (pos + 1));
}
return newMappings;
}
protected void updateNameMappings() protected void updateNameMappings()
{ {
try (AutoLock l = lock()) try (AutoLock ignored = lock())
{ {
// update filter name map // update filter name map
_filterNameMap.clear(); _filterNameMap.clear();
if (_filters != null) for (FilterHolder filter : _filters)
{ {
for (FilterHolder filter : _filters) _filterNameMap.put(filter.getName(), filter);
{ filter.setServletHandler(this);
_filterNameMap.put(filter.getName(), filter);
filter.setServletHandler(this);
}
} }
// Map servlet names to holders // Map servlet names to holders
_servletNameMap.clear(); _servletNameMap.clear();
if (_servlets != null) // update the maps
for (ServletHolder servlet : _servlets)
{ {
// update the maps _servletNameMap.put(servlet.getName(), new MappedServlet(null, servlet));
for (ServletHolder servlet : _servlets) servlet.setServletHandler(this);
{
_servletNameMap.put(servlet.getName(), new MappedServlet(null, servlet));
servlet.setServletHandler(this);
}
} }
} }
} }
protected void updateMappings() protected void updateMappings()
{ {
try (AutoLock l = lock()) try (AutoLock ignored = lock())
{ {
// update filter mappings // update filter mappings
if (_filterMappings == null) _filterPathMappings = new ArrayList<>();
_filterNameMappings = new MultiMap<>();
for (FilterMapping filtermapping : _filterMappings)
{ {
_filterPathMappings = null; FilterHolder filterHolder = _filterNameMap.get(filtermapping.getFilterName());
_filterNameMappings = null; if (filterHolder == null)
_wildFilterNameMappings = Collections.emptyList(); throw new IllegalStateException("No filter named " + filtermapping.getFilterName());
} filtermapping.setFilterHolder(filterHolder);
else if (filtermapping.getPathSpecs() != null)
{ _filterPathMappings.add(filtermapping);
_filterPathMappings = new ArrayList<>();
_filterNameMappings = new MultiMap<>();
for (FilterMapping filtermapping : _filterMappings)
{
FilterHolder filterHolder = _filterNameMap.get(filtermapping.getFilterName());
if (filterHolder == null)
throw new IllegalStateException("No filter named " + filtermapping.getFilterName());
filtermapping.setFilterHolder(filterHolder);
if (filtermapping.getPathSpecs() != null)
_filterPathMappings.add(filtermapping);
if (filtermapping.getServletNames() != null) if (filtermapping.getServletNames() != null)
{
String[] names = filtermapping.getServletNames();
for (String name : names)
{ {
String[] names = filtermapping.getServletNames(); if (name != null)
for (String name : names) _filterNameMappings.add(name, filtermapping);
{
if (name != null)
_filterNameMappings.add(name, filtermapping);
}
} }
} }
// Reverse filter mappings to apply as wrappers last filter wrapped first
for (Map.Entry<String, List<FilterMapping>> entry : _filterNameMappings.entrySet())
Collections.reverse(entry.getValue());
Collections.reverse(_filterPathMappings);
_wildFilterNameMappings = _filterNameMappings.get("*");
if (_wildFilterNameMappings != null)
Collections.reverse(_wildFilterNameMappings);
} }
// Reverse filter mappings to apply as wrappers last filter wrapped first
for (Map.Entry<String, List<FilterMapping>> entry : _filterNameMappings.entrySet())
Collections.reverse(entry.getValue());
Collections.reverse(_filterPathMappings);
_wildFilterNameMappings = _filterNameMappings.get("*");
if (_wildFilterNameMappings != null)
Collections.reverse(_wildFilterNameMappings);
// Map servlet paths to holders // Map servlet paths to holders
if (_servletMappings == null) PathMappings<MappedServlet> pm = new PathMappings<>();
{
_servletPathMap = null;
}
else
{
PathMappings<MappedServlet> pm = new PathMappings<>();
//create a map of paths to set of ServletMappings that define that mapping //create a map of paths to set of ServletMappings that define that mapping
HashMap<String, List<ServletMapping>> sms = new HashMap<>(); HashMap<String, List<ServletMapping>> sms = new HashMap<>();
for (ServletMapping servletMapping : _servletMappings) for (ServletMapping servletMapping : _servletMappings)
{
String[] pathSpecs = servletMapping.getPathSpecs();
if (pathSpecs != null)
{ {
String[] pathSpecs = servletMapping.getPathSpecs(); for (String pathSpec : pathSpecs)
if (pathSpecs != null)
{ {
for (String pathSpec : pathSpecs) List<ServletMapping> mappings = sms.computeIfAbsent(pathSpec, k -> new ArrayList<>());
{ mappings.add(servletMapping);
List<ServletMapping> mappings = sms.computeIfAbsent(pathSpec, k -> new ArrayList<>());
mappings.add(servletMapping);
}
} }
} }
}
//evaluate path to servlet map based on servlet mappings //evaluate path to servlet map based on servlet mappings
for (String pathSpec : sms.keySet()) for (String pathSpec : sms.keySet())
{
//for each path, look at the mappings where it is referenced
//if a mapping is for a servlet that is not enabled, skip it
List<ServletMapping> mappings = sms.get(pathSpec);
ServletMapping finalMapping = null;
for (ServletMapping mapping : mappings)
{ {
//for each path, look at the mappings where it is referenced //Get servlet associated with the mapping and check it is enabled
//if a mapping is for a servlet that is not enabled, skip it ServletHolder servletHolder = getServlet(mapping.getServletName());
List<ServletMapping> mappings = sms.get(pathSpec); if (servletHolder == null)
throw new IllegalStateException("No such servlet: " + mapping.getServletName());
//if the servlet related to the mapping is not enabled, skip it from consideration
if (!servletHolder.isEnabled())
continue;
ServletMapping finalMapping = null; //only accept a default mapping if we don't have any other
for (ServletMapping mapping : mappings) if (finalMapping == null)
finalMapping = mapping;
else
{ {
//Get servlet associated with the mapping and check it is enabled //already have a candidate - only accept another one
ServletHolder servletHolder = getServlet(mapping.getServletName()); //if the candidate is a default, or we're allowing duplicate mappings
if (servletHolder == null) if (finalMapping.isFromDefaultDescriptor())
throw new IllegalStateException("No such servlet: " + mapping.getServletName());
//if the servlet related to the mapping is not enabled, skip it from consideration
if (!servletHolder.isEnabled())
continue;
//only accept a default mapping if we don't have any other
if (finalMapping == null)
finalMapping = mapping; finalMapping = mapping;
else if (isAllowDuplicateMappings())
{
LOG.warn("Multiple servlets map to path {}: {} and {}, choosing {}", pathSpec, finalMapping.getServletName(), mapping.getServletName(), mapping);
finalMapping = mapping;
}
else else
{ {
//already have a candidate - only accept another one //existing candidate isn't a default, if the one we're looking at isn't a default either, then its an error
//if the candidate is a default, or we're allowing duplicate mappings if (!mapping.isFromDefaultDescriptor())
if (finalMapping.isFromDefaultDescriptor())
finalMapping = mapping;
else if (isAllowDuplicateMappings())
{ {
LOG.warn("Multiple servlets map to path {}: {} and {}, choosing {}", pathSpec, finalMapping.getServletName(), mapping.getServletName(), mapping); ServletHolder finalMappedServlet = getServlet(finalMapping.getServletName());
finalMapping = mapping; throw new IllegalStateException("Multiple servlets map to path " +
} pathSpec + ": " +
else finalMappedServlet.getName() + "[mapped:" + finalMapping.getSource() + "]," +
{ mapping.getServletName() + "[mapped:" + mapping.getSource() + "]");
//existing candidate isn't a default, if the one we're looking at isn't a default either, then its an error
if (!mapping.isFromDefaultDescriptor())
{
ServletHolder finalMappedServlet = getServlet(finalMapping.getServletName());
throw new IllegalStateException("Multiple servlets map to path " +
pathSpec + ": " +
finalMappedServlet.getName() + "[mapped:" + finalMapping.getSource() + "]," +
mapping.getServletName() + "[mapped:" + mapping.getSource() + "]");
}
} }
} }
} }
if (finalMapping == null)
throw new IllegalStateException("No acceptable servlet mappings for " + pathSpec);
if (LOG.isDebugEnabled())
LOG.debug("Path={}[{}] mapped to servlet={}[{}]",
pathSpec,
finalMapping.getSource(),
finalMapping.getServletName(),
getServlet(finalMapping.getServletName()).getSource());
ServletPathSpec servletPathSpec = new ServletPathSpec(pathSpec);
MappedServlet mappedServlet = new MappedServlet(servletPathSpec, getServlet(finalMapping.getServletName()));
pm.put(servletPathSpec, mappedServlet);
} }
if (finalMapping == null)
throw new IllegalStateException("No acceptable servlet mappings for " + pathSpec);
_servletPathMap = pm; if (LOG.isDebugEnabled())
LOG.debug("Path={}[{}] mapped to servlet={}[{}]",
pathSpec,
finalMapping.getSource(),
finalMapping.getServletName(),
getServlet(finalMapping.getServletName()).getSource());
ServletPathSpec servletPathSpec = new ServletPathSpec(pathSpec);
MappedServlet mappedServlet = new MappedServlet(servletPathSpec, getServlet(finalMapping.getServletName()));
pm.put(servletPathSpec, mappedServlet);
} }
_servletPathMap = pm;
// flush filter chain cache // flush filter chain cache
for (int i = _chainCache.length; i-- > 0; ) for (int i = _chainCache.length; i-- > 0; )
{ {
@ -1423,33 +1358,17 @@ public class ServletHandler extends ScopedHandler
protected boolean containsFilterHolder(FilterHolder holder) protected boolean containsFilterHolder(FilterHolder holder)
{ {
try (AutoLock l = lock()) try (AutoLock ignored = lock())
{ {
if (_filters == null) return _filters.contains(holder);
return false;
for (FilterHolder f : _filters)
{
if (f == holder)
return true;
}
return false;
} }
} }
protected boolean containsServletHolder(ServletHolder holder) protected boolean containsServletHolder(ServletHolder holder)
{ {
try (AutoLock l = lock()) try (AutoLock ignored = lock())
{ {
if (_servlets == null) return _servlets.contains(holder);
return false;
for (ServletHolder s : _servlets)
{
@SuppressWarnings("ReferenceEquality")
boolean foundServletHolder = (s == holder);
if (foundServletHolder)
return true;
}
return false;
} }
} }
@ -1466,22 +1385,23 @@ public class ServletHandler extends ScopedHandler
*/ */
public void setFilterMappings(FilterMapping[] filterMappings) public void setFilterMappings(FilterMapping[] filterMappings)
{ {
updateBeans(_filterMappings, filterMappings); try (AutoLock ignored = lock())
_filterMappings = filterMappings; {
if (isRunning()) List<FilterMapping> mappings = filterMappings == null ? Collections.emptyList() : Arrays.asList(filterMappings);
updateMappings(); updateAndSet(_filterMappings, mappings);
invalidateChainsCache(); if (isRunning())
updateMappings();
invalidateChainsCache();
}
} }
public void setFilters(FilterHolder[] holders) public void setFilters(FilterHolder[] holders)
{ {
try (AutoLock l = lock()) try (AutoLock ignored = lock())
{ {
if (holders != null) List<FilterHolder> filters = holders == null ? Collections.emptyList() : Arrays.asList(holders);
initializeHolders(holders); initializeHolders(filters);
updateAndSet(_filters, filters);
updateBeans(_filters, holders);
_filters = holders;
updateNameMappings(); updateNameMappings();
invalidateChainsCache(); invalidateChainsCache();
} }
@ -1492,8 +1412,8 @@ public class ServletHandler extends ScopedHandler
*/ */
public void setServletMappings(ServletMapping[] servletMappings) public void setServletMappings(ServletMapping[] servletMappings)
{ {
updateBeans(_servletMappings, servletMappings); List<ServletMapping> mappings = servletMappings == null ? Collections.emptyList() : Arrays.asList(servletMappings);
_servletMappings = servletMappings; updateAndSet(_servletMappings, mappings);
if (isRunning()) if (isRunning())
updateMappings(); updateMappings();
invalidateChainsCache(); invalidateChainsCache();
@ -1506,12 +1426,11 @@ public class ServletHandler extends ScopedHandler
*/ */
public void setServlets(ServletHolder[] holders) public void setServlets(ServletHolder[] holders)
{ {
try (AutoLock l = lock()) try (AutoLock ignored = lock())
{ {
if (holders != null) List<ServletHolder> servlets = holders == null ? Collections.emptyList() : Arrays.asList(holders);
initializeHolders(holders); initializeHolders(servlets);
updateBeans(_servlets, holders); updateAndSet(_servlets, servlets);
_servlets = holders;
updateNameMappings(); updateNameMappings();
invalidateChainsCache(); invalidateChainsCache();
} }

View File

@ -1448,11 +1448,13 @@ public class DefaultServletTest
Path image = docRoot.resolve("image.jpg"); Path image = docRoot.resolve("image.jpg");
createFile(image, "not an image"); createFile(image, "not an image");
server.stop();
ServletHolder defholder = context.addServlet(DefaultServlet.class, "/"); ServletHolder defholder = context.addServlet(DefaultServlet.class, "/");
defholder.setInitParameter("dirAllowed", "false"); defholder.setInitParameter("dirAllowed", "false");
defholder.setInitParameter("redirectWelcome", "false"); defholder.setInitParameter("redirectWelcome", "false");
defholder.setInitParameter("welcomeServlets", "false"); defholder.setInitParameter("welcomeServlets", "false");
defholder.setInitParameter("gzip", "false"); defholder.setInitParameter("gzip", "false");
server.start();
String rawResponse; String rawResponse;
HttpTester.Response response; HttpTester.Response response;

View File

@ -15,19 +15,23 @@ package org.eclipse.jetty.servlet;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.List; import java.util.List;
import javax.servlet.DispatcherType; import javax.servlet.DispatcherType;
import javax.servlet.Filter; import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig; import javax.servlet.FilterConfig;
import javax.servlet.ServletContextListener;
import javax.servlet.ServletException; import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSessionEvent; import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener; import javax.servlet.http.HttpSessionListener;
import org.eclipse.jetty.http.pathmap.MappedResource;
import org.eclipse.jetty.server.LocalConnector; import org.eclipse.jetty.server.LocalConnector;
import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.util.component.Container; import org.eclipse.jetty.util.component.Container;
@ -35,7 +39,9 @@ import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.is;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNotNull;
@ -107,34 +113,33 @@ public class ServletHandlerTest
} }
@Test @Test
public void testAddFilterIgnoresDuplicates() throws Exception public void testAddFilterIgnoresDuplicates()
{ {
ServletHandler handler = new ServletHandler(); ServletHandler handler = new ServletHandler();
FilterHolder h = new FilterHolder(); FilterHolder h = new FilterHolder();
h.setName("x"); h.setName("x");
handler.addFilter(h); handler.addFilter(h);
FilterHolder[] holders = handler.getFilters(); FilterHolder[] holders = handler.getFilters();
assertNotNull(holders); assertNotNull(holders);
assertTrue(holders[0] == h); assertThat(h, is(holders[0]));
handler.addFilter(h); handler.addFilter(h);
holders = handler.getFilters(); holders = handler.getFilters();
assertNotNull(holders); assertNotNull(holders);
assertTrue(holders.length == 1); assertThat(1, is(holders.length));
assertTrue(holders[0] == h); assertThat(h, is(holders[0]));
FilterHolder h2 = new FilterHolder(); FilterHolder h2 = new FilterHolder();
h2.setName("x"); //not allowed by servlet spec, just here to test object equality h2.setName("x"); //not allowed by servlet spec, just here to test object equality
handler.addFilter(h2); handler.addFilter(h2);
holders = handler.getFilters(); holders = handler.getFilters();
assertNotNull(holders); assertNotNull(holders);
assertTrue(holders.length == 2); assertThat(2, is(holders.length));
assertTrue(holders[1] == h2); assertThat(h2, is(holders[1]));
} }
@Test @Test
public void testAddFilterIgnoresDuplicates2() throws Exception public void testAddFilterIgnoresDuplicates2()
{ {
ServletHandler handler = new ServletHandler(); ServletHandler handler = new ServletHandler();
@ -147,7 +152,7 @@ public class ServletHandlerTest
handler.addFilter(h, m); handler.addFilter(h, m);
FilterHolder[] holders = handler.getFilters(); FilterHolder[] holders = handler.getFilters();
assertNotNull(holders); assertNotNull(holders);
assertTrue(holders[0] == h); assertThat(h, is(holders[0]));
FilterMapping m2 = new FilterMapping(); FilterMapping m2 = new FilterMapping();
m2.setPathSpec("/*"); m2.setPathSpec("/*");
@ -155,8 +160,8 @@ public class ServletHandlerTest
handler.addFilter(h, m2); handler.addFilter(h, m2);
holders = handler.getFilters(); holders = handler.getFilters();
assertNotNull(holders); assertNotNull(holders);
assertTrue(holders.length == 1); assertThat(1, is(holders.length));
assertTrue(holders[0] == h); assertThat(h, is(holders[0]));
FilterHolder h2 = new FilterHolder(); FilterHolder h2 = new FilterHolder();
h2.setName("x"); //not allowed by servlet spec, just here to test object equality h2.setName("x"); //not allowed by servlet spec, just here to test object equality
@ -167,12 +172,12 @@ public class ServletHandlerTest
handler.addFilter(h2, m3); handler.addFilter(h2, m3);
holders = handler.getFilters(); holders = handler.getFilters();
assertNotNull(holders); assertNotNull(holders);
assertTrue(holders.length == 2); assertThat(2, is(holders.length));
assertTrue(holders[1] == h2); assertThat(h2, is(holders[1]));
} }
@Test @Test
public void testAddFilterWithMappingIgnoresDuplicateFilters() throws Exception public void testAddFilterWithMappingIgnoresDuplicateFilters()
{ {
ServletHandler handler = new ServletHandler(); ServletHandler handler = new ServletHandler();
FilterHolder h = new FilterHolder(); FilterHolder h = new FilterHolder();
@ -181,13 +186,13 @@ public class ServletHandlerTest
handler.addFilterWithMapping(h, "/*", 0); handler.addFilterWithMapping(h, "/*", 0);
FilterHolder[] holders = handler.getFilters(); FilterHolder[] holders = handler.getFilters();
assertNotNull(holders); assertNotNull(holders);
assertTrue(holders[0] == h); assertThat(h, is(holders[0]));
handler.addFilterWithMapping(h, "/*", 1); handler.addFilterWithMapping(h, "/*", 1);
holders = handler.getFilters(); holders = handler.getFilters();
assertNotNull(holders); assertNotNull(holders);
assertTrue(holders.length == 1); assertThat(1, is(holders.length));
assertTrue(holders[0] == h); assertThat(h, is(holders[0]));
FilterHolder h2 = new FilterHolder(); FilterHolder h2 = new FilterHolder();
h2.setName("x"); //not allowed by servlet spec, just here to test object equality h2.setName("x"); //not allowed by servlet spec, just here to test object equality
@ -195,12 +200,12 @@ public class ServletHandlerTest
handler.addFilterWithMapping(h2, "/*", 0); handler.addFilterWithMapping(h2, "/*", 0);
holders = handler.getFilters(); holders = handler.getFilters();
assertNotNull(holders); assertNotNull(holders);
assertTrue(holders.length == 2); assertThat(2, is(holders.length));
assertTrue(holders[1] == h2); assertThat(h2, is(holders[1]));
} }
@Test @Test
public void testAddFilterWithMappingIngoresDuplicateFilters2() throws Exception public void testAddFilterWithMappingIngoresDuplicateFilters2()
{ {
ServletHandler handler = new ServletHandler(); ServletHandler handler = new ServletHandler();
FilterHolder h = new FilterHolder(); FilterHolder h = new FilterHolder();
@ -209,13 +214,13 @@ public class ServletHandlerTest
handler.addFilterWithMapping(h, "/*", EnumSet.allOf(DispatcherType.class)); handler.addFilterWithMapping(h, "/*", EnumSet.allOf(DispatcherType.class));
FilterHolder[] holders = handler.getFilters(); FilterHolder[] holders = handler.getFilters();
assertNotNull(holders); assertNotNull(holders);
assertTrue(holders[0] == h); assertThat(h, is(holders[0]));
handler.addFilterWithMapping(h, "/x", EnumSet.allOf(DispatcherType.class)); handler.addFilterWithMapping(h, "/x", EnumSet.allOf(DispatcherType.class));
holders = handler.getFilters(); holders = handler.getFilters();
assertNotNull(holders); assertNotNull(holders);
assertTrue(holders.length == 1); assertThat(1, is(holders.length));
assertTrue(holders[0] == h); assertThat(h, is(holders[0]));
FilterHolder h2 = new FilterHolder(); FilterHolder h2 = new FilterHolder();
h2.setName("x"); //not allowed by servlet spec, just here to test object equality h2.setName("x"); //not allowed by servlet spec, just here to test object equality
@ -223,12 +228,12 @@ public class ServletHandlerTest
handler.addFilterWithMapping(h2, "/*", EnumSet.allOf(DispatcherType.class)); handler.addFilterWithMapping(h2, "/*", EnumSet.allOf(DispatcherType.class));
holders = handler.getFilters(); holders = handler.getFilters();
assertNotNull(holders); assertNotNull(holders);
assertTrue(holders.length == 2); assertThat(2, is(holders.length));
assertTrue(holders[1] == h2); assertThat(h2, is(holders[1]));
} }
@Test @Test
public void testDuplicateMappingsForbidden() throws Exception public void testDuplicateMappingsForbidden()
{ {
ServletHandler handler = new ServletHandler(); ServletHandler handler = new ServletHandler();
handler.setAllowDuplicateMappings(false); handler.setAllowDuplicateMappings(false);
@ -250,7 +255,7 @@ public class ServletHandlerTest
} }
@Test @Test
public void testDuplicateMappingsWithDefaults() throws Exception public void testDuplicateMappingsWithDefaults()
{ {
ServletHandler handler = new ServletHandler(); ServletHandler handler = new ServletHandler();
handler.setAllowDuplicateMappings(false); handler.setAllowDuplicateMappings(false);
@ -269,7 +274,7 @@ public class ServletHandlerTest
} }
@Test @Test
public void testDuplicateMappingsSameServlet() throws Exception public void testDuplicateMappingsSameServlet()
{ {
ServletHolder sh4 = new ServletHolder(); ServletHolder sh4 = new ServletHolder();
@ -292,7 +297,7 @@ public class ServletHandlerTest
} }
@Test @Test
public void testDuplicateMappingsAllowed() throws Exception public void testDuplicateMappingsAllowed()
{ {
ServletHandler handler = new ServletHandler(); ServletHandler handler = new ServletHandler();
handler.setAllowDuplicateMappings(true); handler.setAllowDuplicateMappings(true);
@ -310,7 +315,7 @@ public class ServletHandlerTest
} }
@Test @Test
public void testAllNonProgrammaticFilterMappings() throws Exception public void testAllNonProgrammaticFilterMappings()
{ {
ServletHandler handler = new ServletHandler(); ServletHandler handler = new ServletHandler();
handler.addFilter(fh1); handler.addFilter(fh1);
@ -322,8 +327,8 @@ public class ServletHandlerTest
FilterMapping[] mappings = handler.getFilterMappings(); FilterMapping[] mappings = handler.getFilterMappings();
assertNotNull(mappings); assertNotNull(mappings);
assertTrue(fm1 == mappings[0]); assertThat(mappings[0], is(fm1));
assertTrue(fm2 == mappings[1]); assertThat(mappings[1], is(fm2));
//add another ordinary mapping //add another ordinary mapping
FilterHolder of1 = new FilterHolder(new Source(Source.Origin.DESCRIPTOR, "foo.xml")); FilterHolder of1 = new FilterHolder(new Source(Source.Origin.DESCRIPTOR, "foo.xml"));
@ -336,13 +341,13 @@ public class ServletHandlerTest
mappings = handler.getFilterMappings(); mappings = handler.getFilterMappings();
assertNotNull(mappings); assertNotNull(mappings);
assertTrue(fm1 == mappings[0]); assertThat(mappings[0], is(fm1));
assertTrue(fm2 == mappings[1]); assertThat(mappings[1], is(fm2));
assertTrue(ofm1 == mappings[2]); assertThat(mappings[2], is(ofm1));
} }
@Test @Test
public void testAllBeforeFilterMappings() throws Exception public void testAllBeforeFilterMappings()
{ {
ServletHandler handler = new ServletHandler(); ServletHandler handler = new ServletHandler();
@ -362,12 +367,12 @@ public class ServletHandlerTest
assertNotNull(mappings); assertNotNull(mappings);
assertEquals(2, mappings.length); assertEquals(2, mappings.length);
assertTrue(fm4 == mappings[0]); assertThat(mappings[0], is(fm4));
assertTrue(fm5 == mappings[1]); assertThat(mappings[1], is(fm5));
} }
@Test @Test
public void testAllAfterFilterMappings() throws Exception public void testAllAfterFilterMappings()
{ {
ServletHandler handler = new ServletHandler(); ServletHandler handler = new ServletHandler();
//do equivalent of FilterRegistration.addMappingForUrlPatterns(isMatchAfter=true) //do equivalent of FilterRegistration.addMappingForUrlPatterns(isMatchAfter=true)
@ -375,19 +380,19 @@ public class ServletHandlerTest
handler.addFilterMapping(fm4); handler.addFilterMapping(fm4);
FilterMapping[] mappings = handler.getFilterMappings(); FilterMapping[] mappings = handler.getFilterMappings();
assertEquals(1, mappings.length); assertEquals(1, mappings.length);
assertTrue(fm4 == mappings[0]); assertThat(mappings[0], is(fm4));
//do equivalent of FilterRegistration.addMappingForUrlPatterns(isMatchAfter=true) //do equivalent of FilterRegistration.addMappingForUrlPatterns(isMatchAfter=true)
handler.addFilter(fh5); handler.addFilter(fh5);
handler.addFilterMapping(fm5); handler.addFilterMapping(fm5);
mappings = handler.getFilterMappings(); mappings = handler.getFilterMappings();
assertEquals(2, mappings.length); assertEquals(2, mappings.length);
assertTrue(fm4 == mappings[0]); assertThat(mappings[0], is(fm4));
assertTrue(fm5 == mappings[1]); assertThat(mappings[1], is(fm5));
} }
@Test @Test
public void testMatchAfterAndBefore() throws Exception public void testMatchAfterAndBefore()
{ {
ServletHandler handler = new ServletHandler(); ServletHandler handler = new ServletHandler();
@ -397,7 +402,7 @@ public class ServletHandlerTest
FilterMapping[] mappings = handler.getFilterMappings(); FilterMapping[] mappings = handler.getFilterMappings();
assertNotNull(mappings); assertNotNull(mappings);
assertEquals(1, mappings.length); assertEquals(1, mappings.length);
assertTrue(fm3 == mappings[0]); assertThat(mappings[0], is(fm3));
//add a programmatic one, isMatchAfter=false //add a programmatic one, isMatchAfter=false
handler.addFilter(fh4); handler.addFilter(fh4);
@ -405,12 +410,12 @@ public class ServletHandlerTest
mappings = handler.getFilterMappings(); mappings = handler.getFilterMappings();
assertNotNull(mappings); assertNotNull(mappings);
assertEquals(2, mappings.length); assertEquals(2, mappings.length);
assertTrue(fm4 == mappings[0]); assertThat(mappings[0], is(fm4));
assertTrue(fm3 == mappings[1]); assertThat(mappings[1], is(fm3));
} }
@Test @Test
public void testMatchBeforeAndAfter() throws Exception public void testMatchBeforeAndAfter()
{ {
ServletHandler handler = new ServletHandler(); ServletHandler handler = new ServletHandler();
@ -420,7 +425,7 @@ public class ServletHandlerTest
FilterMapping[] mappings = handler.getFilterMappings(); FilterMapping[] mappings = handler.getFilterMappings();
assertNotNull(mappings); assertNotNull(mappings);
assertEquals(1, mappings.length); assertEquals(1, mappings.length);
assertTrue(fm3 == mappings[0]); assertThat(mappings[0], is(fm3));
//add a programmatic one, isMatchAfter=true //add a programmatic one, isMatchAfter=true
handler.addFilter(fh4); handler.addFilter(fh4);
@ -428,12 +433,12 @@ public class ServletHandlerTest
mappings = handler.getFilterMappings(); mappings = handler.getFilterMappings();
assertNotNull(mappings); assertNotNull(mappings);
assertEquals(2, mappings.length); assertEquals(2, mappings.length);
assertTrue(fm3 == mappings[0]); assertThat(mappings[0], is(fm3));
assertTrue(fm4 == mappings[1]); assertThat(mappings[1], is(fm4));
} }
@Test @Test
public void testExistingFilterMappings() throws Exception public void testExistingFilterMappings()
{ {
ServletHandler handler = new ServletHandler(); ServletHandler handler = new ServletHandler();
handler.addFilter(fh1); handler.addFilter(fh1);
@ -445,26 +450,26 @@ public class ServletHandlerTest
FilterMapping[] mappings = handler.getFilterMappings(); FilterMapping[] mappings = handler.getFilterMappings();
assertNotNull(mappings); assertNotNull(mappings);
assertTrue(fm1 == mappings[0]); assertThat(mappings[0], is(fm1));
assertTrue(fm2 == mappings[1]); assertThat(mappings[1], is(fm2));
//do equivalent of FilterRegistration.addMappingForUrlPatterns(isMatchAfter=false) //do equivalent of FilterRegistration.addMappingForUrlPatterns(isMatchAfter=false)
handler.addFilter(fh4); handler.addFilter(fh4);
handler.prependFilterMapping(fm4); handler.prependFilterMapping(fm4);
mappings = handler.getFilterMappings(); mappings = handler.getFilterMappings();
assertEquals(3, mappings.length); assertEquals(3, mappings.length);
assertTrue(fm4 == mappings[0]); assertThat(mappings[0], is(fm4));
//do equivalent of FilterRegistration.addMappingForUrlPatterns(isMatchAfter=true) //do equivalent of FilterRegistration.addMappingForUrlPatterns(isMatchAfter=true)
handler.addFilter(fh5); handler.addFilter(fh5);
handler.addFilterMapping(fm5); handler.addFilterMapping(fm5);
mappings = handler.getFilterMappings(); mappings = handler.getFilterMappings();
assertEquals(4, mappings.length); assertEquals(4, mappings.length);
assertTrue(fm5 == mappings[mappings.length - 1]); assertThat(mappings[mappings.length - 1], is(fm5));
} }
@Test @Test
public void testFilterMappingNoFilter() throws Exception public void testFilterMappingNoFilter()
{ {
FilterMapping mapping = new FilterMapping(); FilterMapping mapping = new FilterMapping();
mapping.setPathSpec("/*"); mapping.setPathSpec("/*");
@ -474,7 +479,7 @@ public class ServletHandlerTest
} }
@Test @Test
public void testFilterMappingsMix() throws Exception public void testFilterMappingsMix()
{ {
ServletHandler handler = new ServletHandler(); ServletHandler handler = new ServletHandler();
@ -483,7 +488,7 @@ public class ServletHandlerTest
handler.addFilterMapping(fm1); handler.addFilterMapping(fm1);
FilterMapping[] mappings = handler.getFilterMappings(); FilterMapping[] mappings = handler.getFilterMappings();
assertNotNull(mappings); assertNotNull(mappings);
assertTrue(fm1 == mappings[0]); assertThat(mappings[0], is(fm1));
//add a programmatic one, isMatchAfter=false //add a programmatic one, isMatchAfter=false
handler.addFilter(fh4); handler.addFilter(fh4);
@ -491,8 +496,8 @@ public class ServletHandlerTest
mappings = handler.getFilterMappings(); mappings = handler.getFilterMappings();
assertNotNull(mappings); assertNotNull(mappings);
assertEquals(2, mappings.length); assertEquals(2, mappings.length);
assertTrue(fm4 == mappings[0]); assertThat(mappings[0], is(fm4));
assertTrue(fm1 == mappings[1]); assertThat(mappings[1], is(fm1));
//add a programmatic one, isMatchAfter=true //add a programmatic one, isMatchAfter=true
handler.addFilter(fh3); handler.addFilter(fh3);
@ -500,9 +505,9 @@ public class ServletHandlerTest
mappings = handler.getFilterMappings(); mappings = handler.getFilterMappings();
assertNotNull(mappings); assertNotNull(mappings);
assertEquals(3, mappings.length); assertEquals(3, mappings.length);
assertTrue(fm4 == mappings[0]); assertThat(mappings[0], is(fm4));
assertTrue(fm1 == mappings[1]); assertThat(mappings[1], is(fm1));
assertTrue(fm3 == mappings[2]); assertThat(mappings[2], is(fm3));
//add a programmatic one, isMatchAfter=false //add a programmatic one, isMatchAfter=false
handler.addFilter(fh5); handler.addFilter(fh5);
@ -510,10 +515,10 @@ public class ServletHandlerTest
mappings = handler.getFilterMappings(); mappings = handler.getFilterMappings();
assertNotNull(mappings); assertNotNull(mappings);
assertEquals(4, mappings.length); assertEquals(4, mappings.length);
assertTrue(fm4 == mappings[0]); //isMatchAfter = false; assertThat(mappings[0], is(fm4)); //isMatchAfter = false;
assertTrue(fm5 == mappings[1]); //isMatchAfter = false; assertThat(mappings[1], is(fm5)); //isMatchAfter = false;
assertTrue(fm1 == mappings[2]); //ordinary assertThat(mappings[2], is(fm1)); //ordinary
assertTrue(fm3 == mappings[3]); //isMatchAfter = true; assertThat(mappings[3], is(fm3)); //isMatchAfter = true;
//add a non-programmatic one //add a non-programmatic one
FilterHolder f = new FilterHolder(Source.EMBEDDED); FilterHolder f = new FilterHolder(Source.EMBEDDED);
@ -526,11 +531,11 @@ public class ServletHandlerTest
mappings = handler.getFilterMappings(); mappings = handler.getFilterMappings();
assertNotNull(mappings); assertNotNull(mappings);
assertEquals(5, mappings.length); assertEquals(5, mappings.length);
assertTrue(fm4 == mappings[0]); //isMatchAfter = false; assertThat(mappings[0], is(fm4)); //isMatchAfter = false;
assertTrue(fm5 == mappings[1]); //isMatchAfter = false; assertThat(mappings[1], is(fm5)); //isMatchAfter = false;
assertTrue(fm1 == mappings[2]); //ordinary assertThat(mappings[2], is(fm1)); //ordinary
assertTrue(fm == mappings[3]); //ordinary assertThat(mappings[3], is(fm)); //ordinary
assertTrue(fm3 == mappings[4]); //isMatchAfter = true; assertThat(mappings[4], is(fm3)); //isMatchAfter = true;
//add a programmatic one, isMatchAfter=true //add a programmatic one, isMatchAfter=true
FilterHolder pf = new FilterHolder(Source.JAVAX_API); FilterHolder pf = new FilterHolder(Source.JAVAX_API);
@ -543,12 +548,12 @@ public class ServletHandlerTest
mappings = handler.getFilterMappings(); mappings = handler.getFilterMappings();
assertNotNull(mappings); assertNotNull(mappings);
assertEquals(6, mappings.length); assertEquals(6, mappings.length);
assertTrue(fm4 == mappings[0]); //isMatchAfter = false; assertThat(mappings[0], is(fm4)); //isMatchAfter = false;
assertTrue(fm5 == mappings[1]); //isMatchAfter = false; assertThat(mappings[1], is(fm5)); //isMatchAfter = false;
assertTrue(fm1 == mappings[2]); //ordinary assertThat(mappings[2], is(fm1)); //ordinary
assertTrue(fm == mappings[3]); //ordinary assertThat(mappings[3], is(fm)); //ordinary
assertTrue(fm3 == mappings[4]); //isMatchAfter = true; assertThat(mappings[4], is(fm3)); //isMatchAfter = true;
assertTrue(pfm == mappings[5]); //isMatchAfter = true; assertThat(mappings[5], is(pfm)); //isMatchAfter = true;
//add a programmatic one, isMatchAfter=false //add a programmatic one, isMatchAfter=false
FilterHolder pf2 = new FilterHolder(Source.JAVAX_API); FilterHolder pf2 = new FilterHolder(Source.JAVAX_API);
@ -561,17 +566,17 @@ public class ServletHandlerTest
mappings = handler.getFilterMappings(); mappings = handler.getFilterMappings();
assertNotNull(mappings); assertNotNull(mappings);
assertEquals(7, mappings.length); assertEquals(7, mappings.length);
assertTrue(fm4 == mappings[0]); //isMatchAfter = false; assertThat(mappings[0], is(fm4)); //isMatchAfter = false;
assertTrue(fm5 == mappings[1]); //isMatchAfter = false; assertThat(mappings[1], is(fm5)); //isMatchAfter = false;
assertTrue(pfm2 == mappings[2]); //isMatchAfter = false; assertThat(mappings[2], is(pfm2)); //isMatchAfter = false;
assertTrue(fm1 == mappings[3]); //ordinary assertThat(mappings[3], is(fm1)); //ordinary
assertTrue(fm == mappings[4]); //ordinary assertThat(mappings[4], is(fm)); //ordinary
assertTrue(fm3 == mappings[5]); //isMatchAfter = true; assertThat(mappings[5], is(fm3)); //isMatchAfter = true;
assertTrue(pfm == mappings[6]); //isMatchAfter = true; assertThat(mappings[6], is(pfm)); //isMatchAfter = true;
} }
@Test @Test
public void testAddFilterWithMappingAPI() throws Exception public void testAddFilterWithMappingAPI()
{ {
ServletHandler handler = new ServletHandler(); ServletHandler handler = new ServletHandler();
@ -580,7 +585,7 @@ public class ServletHandlerTest
handler.updateMappings(); handler.updateMappings();
FilterMapping[] mappings = handler.getFilterMappings(); FilterMapping[] mappings = handler.getFilterMappings();
assertNotNull(mappings); assertNotNull(mappings);
assertTrue(fh1 == mappings[0].getFilterHolder()); assertThat(mappings[0].getFilterHolder(), is(fh1));
//add a programmatic one, isMatchAfter=false //add a programmatic one, isMatchAfter=false
fh4.setServletHandler(handler); fh4.setServletHandler(handler);
@ -590,8 +595,8 @@ public class ServletHandlerTest
mappings = handler.getFilterMappings(); mappings = handler.getFilterMappings();
assertNotNull(mappings); assertNotNull(mappings);
assertEquals(2, mappings.length); assertEquals(2, mappings.length);
assertTrue(fh4 == mappings[0].getFilterHolder()); assertThat(mappings[0].getFilterHolder(), is(fh4));
assertTrue(fh1 == mappings[1].getFilterHolder()); assertThat(mappings[1].getFilterHolder(), is(fh1));
//add a programmatic one, isMatchAfter=true //add a programmatic one, isMatchAfter=true
fh3.setServletHandler(handler); fh3.setServletHandler(handler);
@ -601,9 +606,9 @@ public class ServletHandlerTest
mappings = handler.getFilterMappings(); mappings = handler.getFilterMappings();
assertNotNull(mappings); assertNotNull(mappings);
assertEquals(3, mappings.length); assertEquals(3, mappings.length);
assertTrue(fh4 == mappings[0].getFilterHolder()); assertThat(mappings[0].getFilterHolder(), is(fh4));
assertTrue(fh1 == mappings[1].getFilterHolder()); assertThat(mappings[1].getFilterHolder(), is(fh1));
assertTrue(fh3 == mappings[2].getFilterHolder()); assertThat(mappings[2].getFilterHolder(), is(fh3));
//add a programmatic one, isMatchAfter=false //add a programmatic one, isMatchAfter=false
fh5.setServletHandler(handler); fh5.setServletHandler(handler);
@ -613,10 +618,10 @@ public class ServletHandlerTest
mappings = handler.getFilterMappings(); mappings = handler.getFilterMappings();
assertNotNull(mappings); assertNotNull(mappings);
assertEquals(4, mappings.length); assertEquals(4, mappings.length);
assertTrue(fh4 == mappings[0].getFilterHolder()); //isMatchAfter = false; assertThat(mappings[0].getFilterHolder(), is(fh4)); //isMatchAfter = false;
assertTrue(fh5 == mappings[1].getFilterHolder()); //isMatchAfter = false; assertThat(mappings[1].getFilterHolder(), is(fh5)); //isMatchAfter = false;
assertTrue(fh1 == mappings[2].getFilterHolder()); //ordinary assertThat(mappings[2].getFilterHolder(), is(fh1)); //ordinary
assertTrue(fh3 == mappings[3].getFilterHolder()); //isMatchAfter = true; assertThat(mappings[3].getFilterHolder(), is(fh3)); //isMatchAfter = true;
//add a non-programmatic one //add a non-programmatic one
FilterHolder f = new FilterHolder(Source.EMBEDDED); FilterHolder f = new FilterHolder(Source.EMBEDDED);
@ -626,11 +631,11 @@ public class ServletHandlerTest
mappings = handler.getFilterMappings(); mappings = handler.getFilterMappings();
assertNotNull(mappings); assertNotNull(mappings);
assertEquals(5, mappings.length); assertEquals(5, mappings.length);
assertTrue(fh4 == mappings[0].getFilterHolder()); //isMatchAfter = false; assertThat(mappings[0].getFilterHolder(), is(fh4)); //isMatchAfter = false;
assertTrue(fh5 == mappings[1].getFilterHolder()); //isMatchAfter = false; assertThat(mappings[1].getFilterHolder(), is(fh5)); //isMatchAfter = false;
assertTrue(fh1 == mappings[2].getFilterHolder()); //ordinary assertThat(mappings[2].getFilterHolder(), is(fh1)); //ordinary
assertTrue(f == mappings[3].getFilterHolder()); //ordinary assertThat(mappings[3].getFilterHolder(), is(f)); //ordinary
assertTrue(fh3 == mappings[4].getFilterHolder()); //isMatchAfter = true; assertThat(mappings[4].getFilterHolder(), is(fh3)); //isMatchAfter = true;
//add a programmatic one, isMatchAfter=true //add a programmatic one, isMatchAfter=true
FilterHolder pf = new FilterHolder(Source.JAVAX_API); FilterHolder pf = new FilterHolder(Source.JAVAX_API);
@ -642,12 +647,12 @@ public class ServletHandlerTest
mappings = handler.getFilterMappings(); mappings = handler.getFilterMappings();
assertNotNull(mappings); assertNotNull(mappings);
assertEquals(6, mappings.length); assertEquals(6, mappings.length);
assertTrue(fh4 == mappings[0].getFilterHolder()); //isMatchAfter = false; assertThat(mappings[0].getFilterHolder(), is(fh4)); //isMatchAfter = false;
assertTrue(fh5 == mappings[1].getFilterHolder()); //isMatchAfter = false; assertThat(mappings[1].getFilterHolder(), is(fh5)); //isMatchAfter = false;
assertTrue(fh1 == mappings[2].getFilterHolder()); //ordinary assertThat(mappings[2].getFilterHolder(), is(fh1)); //ordinary
assertTrue(f == mappings[3].getFilterHolder()); //ordinary assertThat(mappings[3].getFilterHolder(), is(f)); //ordinary
assertTrue(fh3 == mappings[4].getFilterHolder()); //isMatchAfter = true; assertThat(mappings[4].getFilterHolder(), is(fh3)); //isMatchAfter = true;
assertTrue(pf == mappings[5].getFilterHolder()); //isMatchAfter = true; assertThat(mappings[5].getFilterHolder(), is(pf)); //isMatchAfter = true;
//add a programmatic one, isMatchAfter=false //add a programmatic one, isMatchAfter=false
FilterHolder pf2 = new FilterHolder(Source.JAVAX_API); FilterHolder pf2 = new FilterHolder(Source.JAVAX_API);
@ -660,17 +665,17 @@ public class ServletHandlerTest
assertNotNull(mappings); assertNotNull(mappings);
assertEquals(7, mappings.length); assertEquals(7, mappings.length);
assertTrue(fh4 == mappings[0].getFilterHolder()); //isMatchAfter = false; assertThat(mappings[0].getFilterHolder(), is(fh4)); //isMatchAfter = false;
assertTrue(fh5 == mappings[1].getFilterHolder()); //isMatchAfter = false; assertThat(mappings[1].getFilterHolder(), is(fh5)); //isMatchAfter = false;
assertTrue(pf2 == mappings[2].getFilterHolder()); //isMatchAfter = false; assertThat(mappings[2].getFilterHolder(), is(pf2)); //isMatchAfter = false;
assertTrue(fh1 == mappings[3].getFilterHolder()); //ordinary assertThat(mappings[3].getFilterHolder(), is(fh1)); //ordinary
assertTrue(f == mappings[4].getFilterHolder()); //ordinary assertThat(mappings[4].getFilterHolder(), is(f)); //ordinary
assertTrue(fh3 == mappings[5].getFilterHolder()); //isMatchAfter = true; assertThat(mappings[5].getFilterHolder(), is(fh3)); //isMatchAfter = true;
assertTrue(pf == mappings[6].getFilterHolder()); //isMatchAfter = true; assertThat(mappings[6].getFilterHolder(), is(pf)); //isMatchAfter = true;
} }
@Test @Test
public void testFiltersServletsListenersAsBeans() throws Exception public void testFiltersServletsListenersAsBeans()
{ {
ServletContextHandler context = new ServletContextHandler(); ServletContextHandler context = new ServletContextHandler();
@ -747,7 +752,7 @@ public class ServletHandlerTest
handler.addServletWithMapping(new ServletHolder(new HttpServlet() handler.addServletWithMapping(new ServletHolder(new HttpServlet()
{ {
@Override @Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException
{ {
resp.getOutputStream().println("mapping='" + mapping + "'"); resp.getOutputStream().println("mapping='" + mapping + "'");
} }
@ -779,7 +784,7 @@ public class ServletHandlerTest
ServletHolder foo = new ServletHolder(new HttpServlet() ServletHolder foo = new ServletHolder(new HttpServlet()
{ {
@Override @Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException
{ {
resp.getOutputStream().println("FOO"); resp.getOutputStream().println("FOO");
} }
@ -790,7 +795,7 @@ public class ServletHandlerTest
ServletHolder def = new ServletHolder(new HttpServlet() ServletHolder def = new ServletHolder(new HttpServlet()
{ {
@Override @Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException
{ {
resp.getOutputStream().println("default"); resp.getOutputStream().println("default");
} }
@ -830,6 +835,67 @@ public class ServletHandlerTest
assertThat(connector.getResponse("GET /other.bob HTTP/1.0\r\n\r\n"), containsString("path-/*-path-*.bob-default")); assertThat(connector.getResponse("GET /other.bob HTTP/1.0\r\n\r\n"), containsString("path-/*-path-*.bob-default"));
} }
@Test
public void testDurable() throws Exception
{
Server server = new Server();
ServletContextHandler context = new ServletContextHandler();
server.setHandler(context);
ServletHandler handler = new ServletHandler();
context.setHandler(handler);
ListenerHolder lh1 = new ListenerHolder(HSListener.class);
ListenerHolder lh2 = new ListenerHolder(SCListener.class);
fh1.setFilter(new SomeFilter());
fm1.setPathSpec("/sm1");
fm1.setFilterHolder(fh1);
fh2.setFilter(new SomeFilter(){});
fm2.setPathSpec("/sm2");
fm2.setFilterHolder(fh2);
sh1.setServlet(new SomeServlet());
sm1.setPathSpec("/sm1");
sm1.setServletName(sh1.getName());
sh2.setServlet(new SomeServlet());
sm2.setPathSpec("/sm2");
sm2.setServletName(sh2.getName());
handler.setListeners(new ListenerHolder[] {lh1});
handler.setFilters(new FilterHolder[] {fh1});
handler.setFilterMappings(new FilterMapping[] {fm1});
handler.setServlets(new ServletHolder[] {sh1});
handler.setServletMappings(new ServletMapping[] {sm1});
server.start();
handler.setListeners(new ListenerHolder[] {lh1, lh2});
handler.setFilters(new FilterHolder[] {fh1, fh2});
handler.setFilterMappings(new FilterMapping[] {fm1, fm2});
handler.setServlets(new ServletHolder[] {sh1, sh2});
handler.setServletMappings(new ServletMapping[] {sm1, sm2});
assertThat(Arrays.asList(handler.getListeners()), contains(lh1, lh2));
assertThat(Arrays.asList(handler.getFilters()), contains(fh1, fh2));
assertThat(Arrays.asList(handler.getFilterMappings()), contains(fm1, fm2));
assertThat(Arrays.asList(handler.getServlets()), contains(sh1, sh2));
assertThat(Arrays.asList(handler.getServletMappings()), contains(sm1, sm2));
server.stop();
assertThat(Arrays.asList(handler.getListeners()), contains(lh1));
assertThat(Arrays.asList(handler.getFilters()), contains(fh1));
assertThat(Arrays.asList(handler.getFilterMappings()), contains(fm1));
assertThat(Arrays.asList(handler.getServlets()), contains(sh1));
assertThat(Arrays.asList(handler.getServletMappings()), contains(sm1));
}
public static class HSListener implements HttpSessionListener
{
}
public static class SCListener implements ServletContextListener
{
}
private interface TestFilter extends Filter private interface TestFilter extends Filter
{ {
default void init(FilterConfig filterConfig) throws ServletException default void init(FilterConfig filterConfig) throws ServletException
@ -842,4 +908,17 @@ public class ServletHandlerTest
} }
} }
public static class SomeFilter implements TestFilter
{
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException
{
chain.doFilter(request, response);
}
}
public static class SomeServlet extends HttpServlet
{
}
} }

View File

@ -15,11 +15,13 @@ package org.eclipse.jetty.util.component;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.EventListener; import java.util.EventListener;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Objects;
import java.util.Set; import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArrayList;
@ -489,12 +491,13 @@ public class ContainerLifeCycle extends AbstractLifeCycle implements Container,
if (super.removeEventListener(listener)) if (super.removeEventListener(listener))
{ {
removeBean(listener); removeBean(listener);
if (_listeners.remove(listener)) if (listener instanceof Container.Listener && _listeners.remove(listener))
{ {
Container.Listener cl = (Container.Listener)listener;
// remove existing beans // remove existing beans
for (Bean b : _beans) for (Bean b : _beans)
{ {
((Container.Listener)listener).beanRemoved(this, b._bean); cl.beanRemoved(this, b._bean);
if (listener instanceof InheritedListener && b.isManaged() && b._bean instanceof Container) if (listener instanceof InheritedListener && b.isManaged() && b._bean instanceof Container)
((Container)b._bean).removeBean(listener); ((Container)b._bean).removeBean(listener);
@ -813,40 +816,28 @@ public class ContainerLifeCycle extends AbstractLifeCycle implements Container,
public void updateBeans(Object[] oldBeans, final Object[] newBeans) public void updateBeans(Object[] oldBeans, final Object[] newBeans)
{ {
updateBeans(
oldBeans == null ? Collections.emptyList() : Arrays.asList(oldBeans),
newBeans == null ? Collections.emptyList() : Arrays.asList(newBeans));
}
public void updateBeans(final Collection<?> oldBeans, final Collection<?> newBeans)
{
Objects.requireNonNull(oldBeans);
Objects.requireNonNull(newBeans);
// remove oldChildren not in newChildren // remove oldChildren not in newChildren
if (oldBeans != null) for (Object o : oldBeans)
{ {
loop: if (!newBeans.contains(o))
for (Object o : oldBeans)
{
if (newBeans != null)
{
for (Object n : newBeans)
{
if (o == n)
continue loop;
}
}
removeBean(o); removeBean(o);
}
} }
// add new beans not in old // add new beans not in old
if (newBeans != null) for (Object n : newBeans)
{ {
loop: if (!oldBeans.contains(n))
for (Object n : newBeans)
{
if (oldBeans != null)
{
for (Object o : oldBeans)
{
if (o == n)
continue loop;
}
}
addBean(n); addBean(n);
}
} }
} }

View File

@ -39,6 +39,11 @@ public class DumpableCollection implements Dumpable
return new DumpableCollection(name, items == null ? Collections.emptyList() : Arrays.asList(items)); return new DumpableCollection(name, items == null ? Collections.emptyList() : Arrays.asList(items));
} }
public static DumpableCollection from(String name, Collection<?> collection)
{
return new DumpableCollection(name, collection);
}
@Override @Override
public String dump() public String dump()
{ {