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 (_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);
}
if (listener instanceof ServletContextAttributeListener)
_servletContextAttributeListeners.add((ServletContextAttributeListener)listener);
@ -933,31 +950,19 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
public void contextInitialized() throws Exception
{
// 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();
if (!_servletContextListeners.isEmpty())
{
ServletContextEvent event = new ServletContextEvent(_scontext);
for (ServletContextListener listener : _servletContextListeners)
{
callContextInitialized(listener, event);
_destroyServletContextListeners.add(listener);
}
}
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.Collections;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.http.HttpServletRequest;
@ -39,6 +40,7 @@ import org.eclipse.jetty.util.resource.Resource;
import org.hamcrest.Matchers;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.slf4j.LoggerFactory;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString;
@ -778,6 +780,71 @@ public class ContextHandlerTest
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
{
File testDirectory = setupTestDirectory();

View File

@ -16,6 +16,7 @@ package org.eclipse.jetty.servlet;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.EnumSet;
import java.util.EventListener;
@ -27,6 +28,7 @@ import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.servlet.DispatcherType;
import javax.servlet.Filter;
@ -87,8 +89,8 @@ public class ServletHandler extends ScopedHandler
private final AutoLock _lock = new AutoLock();
private ServletContextHandler _contextHandler;
private ServletContext _servletContext;
private FilterHolder[] _filters = new FilterHolder[0];
private FilterMapping[] _filterMappings;
private final List<FilterHolder> _filters = new ArrayList<>();
private final List<FilterMapping> _filterMappings = new ArrayList<>();
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 boolean _filterChainsCached = true;
@ -98,17 +100,18 @@ public class ServletHandler extends ScopedHandler
private IdentityService _identityService;
private boolean _allowDuplicateMappings = false;
private ServletHolder[] _servlets = new ServletHolder[0];
private ServletMapping[] _servletMappings;
private final List<ServletHolder> _servlets = new ArrayList<>();
private final List<ServletMapping> _servletMappings = new ArrayList<>();
private final Map<String, FilterHolder> _filterNameMap = new HashMap<>();
private List<FilterMapping> _filterPathMappings;
private MultiMap<FilterMapping> _filterNameMappings;
private List<FilterMapping> _wildFilterNameMappings;
private final List<BaseHolder<?>> _durable = new ArrayList<>();
private final Map<String, MappedServlet> _servletNameMap = new HashMap<>();
private PathMappings<MappedServlet> _servletPathMap;
private ListenerHolder[] _listeners = new ListenerHolder[0];
private final List<ListenerHolder> _listeners = new ArrayList<>();
private boolean _initialized = false;
@SuppressWarnings("unchecked")
@ -126,6 +129,13 @@ public class ServletHandler extends ScopedHandler
return _lock.lock();
}
private <T> void updateAndSet(Collection<T> target, Collection<T> values)
{
updateBeans(target, values);
target.clear();
target.addAll(values);
}
@Override
public boolean isDumpable(Object o)
{
@ -136,17 +146,18 @@ public class ServletHandler extends ScopedHandler
public void dump(Appendable out, String indent) throws IOException
{
dumpObjects(out, indent,
DumpableCollection.fromArray("listeners " + this, _listeners),
DumpableCollection.fromArray("filters " + this, _filters),
DumpableCollection.fromArray("filterMappings " + this, _filterMappings),
DumpableCollection.fromArray("servlets " + this, _servlets),
DumpableCollection.fromArray("servletMappings " + this, _servletMappings));
DumpableCollection.from("listeners " + this, _listeners),
DumpableCollection.from("filters " + this, _filters),
DumpableCollection.from("filterMappings " + this, _filterMappings),
DumpableCollection.from("servlets " + this, _servlets),
DumpableCollection.from("servletMappings " + this, _servletMappings),
DumpableCollection.from("durable " + this, _durable));
}
@Override
protected void doStart() throws Exception
{
try (AutoLock l = lock())
try (AutoLock ignored = lock())
{
ContextHandler.Context context = ContextHandler.getCurrentContext();
_servletContext = context == null ? new ContextHandler.StaticContext() : context;
@ -159,6 +170,11 @@ public class ServletHandler extends ScopedHandler
_identityService = securityHandler.getIdentityService();
}
_durable.clear();
_durable.addAll(Arrays.asList(getFilters()));
_durable.addAll(Arrays.asList(getServlets()));
_durable.addAll(Arrays.asList(getListeners()));
updateNameMappings();
updateMappings();
@ -226,113 +242,93 @@ public class ServletHandler extends ScopedHandler
@Override
protected void doStop() throws Exception
{
try (AutoLock l = lock())
try (AutoLock ignored = lock())
{
super.doStop();
// Stop filters
List<FilterHolder> filterHolders = new ArrayList<>();
List<FilterMapping> filterMappings = ArrayUtil.asMutableList(_filterMappings);
if (_filters != null)
for (int i = _filters.size(); i-- > 0; )
{
for (int i = _filters.length; i-- > 0; )
FilterHolder filter = _filters.get(i);
try
{
FilterHolder filter = _filters[i];
try
{
filter.stop();
}
catch (Exception e)
{
LOG.warn("Unable to stop filter {}", filter, e);
}
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
filter.stop();
}
catch (Exception e)
{
LOG.warn("Unable to stop filter {}", filter, e);
}
if (_durable.contains(filter))
{
filterHolders.add(filter); //only retain durable
}
}
//Retain only filters and mappings that were added using jetty api (ie Source.EMBEDDED)
FilterHolder[] fhs = filterHolders.toArray(new FilterHolder[0]);
updateBeans(_filters, fhs);
_filters = fhs;
FilterMapping[] fms = filterMappings.toArray(new FilterMapping[0]);
updateBeans(_filterMappings, fms);
_filterMappings = fms;
_matchAfterIndex = (_filterMappings.length == 0 ? -1 : _filterMappings.length - 1);
_matchBeforeIndex = -1;
//Retain only durable filters
updateBeans(_filters, filterHolders);
_filters.clear();
_filters.addAll(filterHolders);
// Stop servlets
List<ServletHolder> servletHolders = new ArrayList<>(); //will be remaining servlets
List<ServletMapping> servletMappings = ArrayUtil.asMutableList(_servletMappings); //will be remaining mappings
if (_servlets != null)
for (int i = _servlets.size(); i-- > 0; )
{
for (int i = _servlets.length; i-- > 0; )
ServletHolder servlet = _servlets.get(i);
try
{
ServletHolder servlet = _servlets[i];
try
{
servlet.stop();
}
catch (Exception e)
{
LOG.warn("Unable to stop servlet {}", servlet, e);
}
servlet.stop();
}
catch (Exception e)
{
LOG.warn("Unable to stop servlet {}", servlet, e);
}
if (servlet.getSource() != Source.EMBEDDED)
{
//remove from servlet name map
_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
if (_durable.contains(servlet))
{
servletHolders.add(servlet); //only retain embedded
}
}
//Retain only Servlets and mappings added via jetty apis (ie Source.EMBEDDED)
ServletHolder[] shs = servletHolders.toArray(new ServletHolder[0]);
updateBeans(_servlets, shs);
_servlets = shs;
ServletMapping[] sms = servletMappings.toArray(new ServletMapping[0]);
updateBeans(_servletMappings, sms);
_servletMappings = sms;
//Retain only durable Servlets
updateBeans(_servlets, servletHolders);
_servlets.clear();
_servlets.addAll(servletHolders);
updateNameMappings();
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)
_contextHandler.contextDestroyed();
//Retain only Listeners added via jetty apis (is Source.EMBEDDED)
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];
try
{
listener.stop();
}
catch (Exception e)
{
LOG.warn("Unable to stop listener {}", listener, e);
}
if (listener.getSource() == Source.EMBEDDED)
listenerHolders.add(listener);
listener.stop();
}
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;
_filterNameMappings = null;
_servletPathMap = null;
@ -348,13 +344,13 @@ public class ServletHandler extends ScopedHandler
@ManagedAttribute(value = "filters", readonly = true)
public FilterMapping[] getFilterMappings()
{
return _filterMappings;
return _filterMappings.toArray(new FilterMapping[0]);
}
@ManagedAttribute(value = "filters", readonly = true)
public FilterHolder[] getFilters()
{
return _filters;
return _filters.toArray(new FilterHolder[0]);
}
public ServletContext getServletContext()
@ -370,7 +366,7 @@ public class ServletHandler extends ScopedHandler
@ManagedAttribute(value = "mappings of servlets", readonly = true)
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)
{
if (pathSpec == null || _servletMappings == null)
if (pathSpec == null)
return 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)
{
for (String p : m.getPathSpecs())
@ -406,7 +402,7 @@ public class ServletHandler extends ScopedHandler
@ManagedAttribute(value = "servlets", readonly = true)
public ServletHolder[] getServlets()
{
return _servlets;
return _servlets.toArray(new ServletHolder[0]);
}
public List<ServletHolder> getServlets(Class<?> clazz)
@ -483,7 +479,7 @@ public class ServletHandler extends ScopedHandler
FilterChain chain = null;
// 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);
if (LOG.isDebugEnabled())
@ -702,7 +698,7 @@ public class ServletHandler extends ScopedHandler
};
//Start the listeners so we can call them
Arrays.stream(_listeners).forEach(c);
_listeners.forEach(c);
//call listeners contextInitialized
if (_contextHandler != null)
@ -713,8 +709,8 @@ public class ServletHandler extends ScopedHandler
//Start the filters then the servlets
Stream.concat(
Arrays.stream(_filters),
Arrays.stream(_servlets).sorted())
_filters.stream(),
_servlets.stream().sorted())
.forEach(c);
mx.ifExceptionThrow();
@ -728,7 +724,7 @@ public class ServletHandler extends ScopedHandler
return _initialized;
}
protected void initializeHolders(BaseHolder<?>[] holders)
protected void initializeHolders(Collection<? extends BaseHolder<?>> holders)
{
for (BaseHolder<?> holder : holders)
{
@ -772,15 +768,16 @@ public class ServletHandler extends ScopedHandler
public ListenerHolder[] getListeners()
{
return _listeners;
return _listeners.toArray(new ListenerHolder[0]);
}
public void setListeners(ListenerHolder[] listeners)
public void setListeners(ListenerHolder[] holders)
{
if (listeners != null)
initializeHolders(listeners);
List<ListenerHolder> listeners = holders == null ? Collections.emptyList() : Arrays.asList(holders);
initializeHolders(listeners);
updateBeans(_listeners, listeners);
_listeners = listeners;
_listeners.clear();
_listeners.addAll(listeners);
}
public ListenerHolder newListenerHolder(Source source)
@ -842,7 +839,7 @@ public class ServletHandler extends ScopedHandler
ServletHolder[] holders = getServlets();
try
{
try (AutoLock l = lock())
try (AutoLock ignored = lock())
{
if (!containsServletHolder(servlet))
setServlets(ArrayUtil.addToArray(holders, servlet, ServletHolder.class));
@ -870,7 +867,7 @@ public class ServletHandler extends ScopedHandler
if (holder == null)
return;
try (AutoLock l = lock())
try (AutoLock ignored = lock())
{
if (!containsServletHolder(holder))
setServlets(ArrayUtil.addToArray(getServlets(), holder, ServletHolder.class));
@ -954,7 +951,7 @@ public class ServletHandler extends ScopedHandler
try
{
try (AutoLock l = lock())
try (AutoLock ignored = lock())
{
if (!containsFilterHolder(holder))
setFilters(ArrayUtil.addToArray(holders, holder, FilterHolder.class));
@ -1023,7 +1020,7 @@ public class ServletHandler extends ScopedHandler
try
{
try (AutoLock l = lock())
try (AutoLock ignored = lock())
{
if (!containsFilterHolder(holder))
setFilters(ArrayUtil.addToArray(holders, holder, FilterHolder.class));
@ -1052,7 +1049,7 @@ public class ServletHandler extends ScopedHandler
{
if (filter != null)
{
try (AutoLock l = lock())
try (AutoLock ignored = lock())
{
if (!containsFilterHolder(filter))
setFilters(ArrayUtil.addToArray(getFilters(), filter, FilterHolder.class));
@ -1072,7 +1069,7 @@ public class ServletHandler extends ScopedHandler
if (filter == null)
return;
try (AutoLock l = lock())
try (AutoLock ignored = lock())
{
if (!containsFilterHolder(filter))
setFilters(ArrayUtil.addToArray(getFilters(), filter, FilterHolder.class));
@ -1089,7 +1086,7 @@ public class ServletHandler extends ScopedHandler
if (filter == null)
return;
try (AutoLock l = lock())
try (AutoLock ignored = lock())
{
if (!containsFilterHolder(filter))
setFilters(ArrayUtil.prependToArray(filter, getFilters(), FilterHolder.class));
@ -1103,24 +1100,27 @@ public class ServletHandler extends ScopedHandler
*/
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());
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)
_matchAfterIndex = 0;
}
else
{
//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.
if (Source.JAVAX_API == source)
{
setFilterMappings(insertFilterMapping(mapping, mappings.length - 1, false));
_filterMappings.add(mapping);
if (_matchAfterIndex < 0)
_matchAfterIndex = getFilterMappings().length - 1;
}
@ -1128,15 +1128,15 @@ public class ServletHandler extends ScopedHandler
{
//insert non-programmatic filter mappings before any matchAfters, if any
if (_matchAfterIndex < 0)
setFilterMappings(insertFilterMapping(mapping, mappings.length - 1, false));
_filterMappings.add(mapping);
else
{
FilterMapping[] newMappings = insertFilterMapping(mapping, _matchAfterIndex, true);
++_matchAfterIndex;
setFilterMappings(newMappings);
}
_filterMappings.add(_matchAfterIndex++, mapping);
}
}
addBean(mapping);
if (isRunning())
updateMappings();
invalidateChainsCache();
}
}
@ -1147,13 +1147,15 @@ public class ServletHandler extends ScopedHandler
*/
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());
FilterMapping[] mappings = getFilterMappings();
if (mappings == null || mappings.length == 0)
if (_filterMappings.isEmpty())
{
setFilterMappings(insertFilterMapping(mapping, 0, false));
_filterMappings.add(mapping);
if (Source.JAVAX_API == source)
_matchBeforeIndex = 0;
}
@ -1169,235 +1171,168 @@ public class ServletHandler extends ScopedHandler
{
//no programmatically defined prepended filter mappings yet, prepend this one
_matchBeforeIndex = 0;
FilterMapping[] newMappings = insertFilterMapping(mapping, 0, true);
setFilterMappings(newMappings);
_filterMappings.add(0, mapping);
}
else
{
FilterMapping[] newMappings = insertFilterMapping(mapping, _matchBeforeIndex, false);
++_matchBeforeIndex;
setFilterMappings(newMappings);
_filterMappings.add(1 + _matchBeforeIndex++, mapping);
}
}
else
{
//non programmatically defined, just prepend to list
FilterMapping[] newMappings = insertFilterMapping(mapping, 0, true);
setFilterMappings(newMappings);
_filterMappings.add(0, mapping);
}
//adjust matchAfterIndex ptr to take account of the mapping we just prepended
if (_matchAfterIndex >= 0)
++_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()
{
try (AutoLock l = lock())
try (AutoLock ignored = lock())
{
// update filter name map
_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
_servletNameMap.clear();
if (_servlets != null)
// update the maps
for (ServletHolder servlet : _servlets)
{
// update the maps
for (ServletHolder servlet : _servlets)
{
_servletNameMap.put(servlet.getName(), new MappedServlet(null, servlet));
servlet.setServletHandler(this);
}
_servletNameMap.put(servlet.getName(), new MappedServlet(null, servlet));
servlet.setServletHandler(this);
}
}
}
protected void updateMappings()
{
try (AutoLock l = lock())
try (AutoLock ignored = lock())
{
// update filter mappings
if (_filterMappings == null)
_filterPathMappings = new ArrayList<>();
_filterNameMappings = new MultiMap<>();
for (FilterMapping filtermapping : _filterMappings)
{
_filterPathMappings = null;
_filterNameMappings = null;
_wildFilterNameMappings = Collections.emptyList();
}
else
{
_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);
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();
for (String name : names)
{
if (name != null)
_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
if (_servletMappings == null)
{
_servletPathMap = null;
}
else
{
PathMappings<MappedServlet> pm = new PathMappings<>();
PathMappings<MappedServlet> pm = new PathMappings<>();
//create a map of paths to set of ServletMappings that define that mapping
HashMap<String, List<ServletMapping>> sms = new HashMap<>();
for (ServletMapping servletMapping : _servletMappings)
//create a map of paths to set of ServletMappings that define that mapping
HashMap<String, List<ServletMapping>> sms = new HashMap<>();
for (ServletMapping servletMapping : _servletMappings)
{
String[] pathSpecs = servletMapping.getPathSpecs();
if (pathSpecs != null)
{
String[] pathSpecs = servletMapping.getPathSpecs();
if (pathSpecs != null)
for (String pathSpec : pathSpecs)
{
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
for (String pathSpec : sms.keySet())
//evaluate path to servlet map based on servlet mappings
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
//if a mapping is for a servlet that is not enabled, skip it
List<ServletMapping> mappings = sms.get(pathSpec);
//Get servlet associated with the mapping and check it is enabled
ServletHolder servletHolder = getServlet(mapping.getServletName());
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;
for (ServletMapping mapping : mappings)
//only accept a default mapping if we don't have any other
if (finalMapping == null)
finalMapping = mapping;
else
{
//Get servlet associated with the mapping and check it is enabled
ServletHolder servletHolder = getServlet(mapping.getServletName());
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;
//only accept a default mapping if we don't have any other
if (finalMapping == null)
//already have a candidate - only accept another one
//if the candidate is a default, or we're allowing duplicate mappings
if (finalMapping.isFromDefaultDescriptor())
finalMapping = mapping;
else if (isAllowDuplicateMappings())
{
LOG.warn("Multiple servlets map to path {}: {} and {}, choosing {}", pathSpec, finalMapping.getServletName(), mapping.getServletName(), mapping);
finalMapping = mapping;
}
else
{
//already have a candidate - only accept another one
//if the candidate is a default, or we're allowing duplicate mappings
if (finalMapping.isFromDefaultDescriptor())
finalMapping = mapping;
else if (isAllowDuplicateMappings())
//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())
{
LOG.warn("Multiple servlets map to path {}: {} and {}, choosing {}", pathSpec, finalMapping.getServletName(), mapping.getServletName(), mapping);
finalMapping = mapping;
}
else
{
//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() + "]");
}
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
for (int i = _chainCache.length; i-- > 0; )
{
@ -1423,33 +1358,17 @@ public class ServletHandler extends ScopedHandler
protected boolean containsFilterHolder(FilterHolder holder)
{
try (AutoLock l = lock())
try (AutoLock ignored = lock())
{
if (_filters == null)
return false;
for (FilterHolder f : _filters)
{
if (f == holder)
return true;
}
return false;
return _filters.contains(holder);
}
}
protected boolean containsServletHolder(ServletHolder holder)
{
try (AutoLock l = lock())
try (AutoLock ignored = lock())
{
if (_servlets == null)
return false;
for (ServletHolder s : _servlets)
{
@SuppressWarnings("ReferenceEquality")
boolean foundServletHolder = (s == holder);
if (foundServletHolder)
return true;
}
return false;
return _servlets.contains(holder);
}
}
@ -1466,22 +1385,23 @@ public class ServletHandler extends ScopedHandler
*/
public void setFilterMappings(FilterMapping[] filterMappings)
{
updateBeans(_filterMappings, filterMappings);
_filterMappings = filterMappings;
if (isRunning())
updateMappings();
invalidateChainsCache();
try (AutoLock ignored = lock())
{
List<FilterMapping> mappings = filterMappings == null ? Collections.emptyList() : Arrays.asList(filterMappings);
updateAndSet(_filterMappings, mappings);
if (isRunning())
updateMappings();
invalidateChainsCache();
}
}
public void setFilters(FilterHolder[] holders)
{
try (AutoLock l = lock())
try (AutoLock ignored = lock())
{
if (holders != null)
initializeHolders(holders);
updateBeans(_filters, holders);
_filters = holders;
List<FilterHolder> filters = holders == null ? Collections.emptyList() : Arrays.asList(holders);
initializeHolders(filters);
updateAndSet(_filters, filters);
updateNameMappings();
invalidateChainsCache();
}
@ -1492,8 +1412,8 @@ public class ServletHandler extends ScopedHandler
*/
public void setServletMappings(ServletMapping[] servletMappings)
{
updateBeans(_servletMappings, servletMappings);
_servletMappings = servletMappings;
List<ServletMapping> mappings = servletMappings == null ? Collections.emptyList() : Arrays.asList(servletMappings);
updateAndSet(_servletMappings, mappings);
if (isRunning())
updateMappings();
invalidateChainsCache();
@ -1506,12 +1426,11 @@ public class ServletHandler extends ScopedHandler
*/
public void setServlets(ServletHolder[] holders)
{
try (AutoLock l = lock())
try (AutoLock ignored = lock())
{
if (holders != null)
initializeHolders(holders);
updateBeans(_servlets, holders);
_servlets = holders;
List<ServletHolder> servlets = holders == null ? Collections.emptyList() : Arrays.asList(holders);
initializeHolders(servlets);
updateAndSet(_servlets, servlets);
updateNameMappings();
invalidateChainsCache();
}

View File

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

View File

@ -15,19 +15,23 @@ package org.eclipse.jetty.servlet;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.List;
import javax.servlet.DispatcherType;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContextListener;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
import org.eclipse.jetty.http.pathmap.MappedResource;
import org.eclipse.jetty.server.LocalConnector;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.util.component.Container;
@ -35,7 +39,9 @@ import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.contains;
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.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
@ -107,34 +113,33 @@ public class ServletHandlerTest
}
@Test
public void testAddFilterIgnoresDuplicates() throws Exception
public void testAddFilterIgnoresDuplicates()
{
ServletHandler handler = new ServletHandler();
FilterHolder h = new FilterHolder();
h.setName("x");
handler.addFilter(h);
FilterHolder[] holders = handler.getFilters();
assertNotNull(holders);
assertTrue(holders[0] == h);
assertThat(h, is(holders[0]));
handler.addFilter(h);
holders = handler.getFilters();
assertNotNull(holders);
assertTrue(holders.length == 1);
assertTrue(holders[0] == h);
assertThat(1, is(holders.length));
assertThat(h, is(holders[0]));
FilterHolder h2 = new FilterHolder();
h2.setName("x"); //not allowed by servlet spec, just here to test object equality
handler.addFilter(h2);
holders = handler.getFilters();
assertNotNull(holders);
assertTrue(holders.length == 2);
assertTrue(holders[1] == h2);
assertThat(2, is(holders.length));
assertThat(h2, is(holders[1]));
}
@Test
public void testAddFilterIgnoresDuplicates2() throws Exception
public void testAddFilterIgnoresDuplicates2()
{
ServletHandler handler = new ServletHandler();
@ -147,7 +152,7 @@ public class ServletHandlerTest
handler.addFilter(h, m);
FilterHolder[] holders = handler.getFilters();
assertNotNull(holders);
assertTrue(holders[0] == h);
assertThat(h, is(holders[0]));
FilterMapping m2 = new FilterMapping();
m2.setPathSpec("/*");
@ -155,8 +160,8 @@ public class ServletHandlerTest
handler.addFilter(h, m2);
holders = handler.getFilters();
assertNotNull(holders);
assertTrue(holders.length == 1);
assertTrue(holders[0] == h);
assertThat(1, is(holders.length));
assertThat(h, is(holders[0]));
FilterHolder h2 = new FilterHolder();
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);
holders = handler.getFilters();
assertNotNull(holders);
assertTrue(holders.length == 2);
assertTrue(holders[1] == h2);
assertThat(2, is(holders.length));
assertThat(h2, is(holders[1]));
}
@Test
public void testAddFilterWithMappingIgnoresDuplicateFilters() throws Exception
public void testAddFilterWithMappingIgnoresDuplicateFilters()
{
ServletHandler handler = new ServletHandler();
FilterHolder h = new FilterHolder();
@ -181,13 +186,13 @@ public class ServletHandlerTest
handler.addFilterWithMapping(h, "/*", 0);
FilterHolder[] holders = handler.getFilters();
assertNotNull(holders);
assertTrue(holders[0] == h);
assertThat(h, is(holders[0]));
handler.addFilterWithMapping(h, "/*", 1);
holders = handler.getFilters();
assertNotNull(holders);
assertTrue(holders.length == 1);
assertTrue(holders[0] == h);
assertThat(1, is(holders.length));
assertThat(h, is(holders[0]));
FilterHolder h2 = new FilterHolder();
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);
holders = handler.getFilters();
assertNotNull(holders);
assertTrue(holders.length == 2);
assertTrue(holders[1] == h2);
assertThat(2, is(holders.length));
assertThat(h2, is(holders[1]));
}
@Test
public void testAddFilterWithMappingIngoresDuplicateFilters2() throws Exception
public void testAddFilterWithMappingIngoresDuplicateFilters2()
{
ServletHandler handler = new ServletHandler();
FilterHolder h = new FilterHolder();
@ -209,13 +214,13 @@ public class ServletHandlerTest
handler.addFilterWithMapping(h, "/*", EnumSet.allOf(DispatcherType.class));
FilterHolder[] holders = handler.getFilters();
assertNotNull(holders);
assertTrue(holders[0] == h);
assertThat(h, is(holders[0]));
handler.addFilterWithMapping(h, "/x", EnumSet.allOf(DispatcherType.class));
holders = handler.getFilters();
assertNotNull(holders);
assertTrue(holders.length == 1);
assertTrue(holders[0] == h);
assertThat(1, is(holders.length));
assertThat(h, is(holders[0]));
FilterHolder h2 = new FilterHolder();
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));
holders = handler.getFilters();
assertNotNull(holders);
assertTrue(holders.length == 2);
assertTrue(holders[1] == h2);
assertThat(2, is(holders.length));
assertThat(h2, is(holders[1]));
}
@Test
public void testDuplicateMappingsForbidden() throws Exception
public void testDuplicateMappingsForbidden()
{
ServletHandler handler = new ServletHandler();
handler.setAllowDuplicateMappings(false);
@ -250,7 +255,7 @@ public class ServletHandlerTest
}
@Test
public void testDuplicateMappingsWithDefaults() throws Exception
public void testDuplicateMappingsWithDefaults()
{
ServletHandler handler = new ServletHandler();
handler.setAllowDuplicateMappings(false);
@ -269,7 +274,7 @@ public class ServletHandlerTest
}
@Test
public void testDuplicateMappingsSameServlet() throws Exception
public void testDuplicateMappingsSameServlet()
{
ServletHolder sh4 = new ServletHolder();
@ -292,7 +297,7 @@ public class ServletHandlerTest
}
@Test
public void testDuplicateMappingsAllowed() throws Exception
public void testDuplicateMappingsAllowed()
{
ServletHandler handler = new ServletHandler();
handler.setAllowDuplicateMappings(true);
@ -310,7 +315,7 @@ public class ServletHandlerTest
}
@Test
public void testAllNonProgrammaticFilterMappings() throws Exception
public void testAllNonProgrammaticFilterMappings()
{
ServletHandler handler = new ServletHandler();
handler.addFilter(fh1);
@ -322,8 +327,8 @@ public class ServletHandlerTest
FilterMapping[] mappings = handler.getFilterMappings();
assertNotNull(mappings);
assertTrue(fm1 == mappings[0]);
assertTrue(fm2 == mappings[1]);
assertThat(mappings[0], is(fm1));
assertThat(mappings[1], is(fm2));
//add another ordinary mapping
FilterHolder of1 = new FilterHolder(new Source(Source.Origin.DESCRIPTOR, "foo.xml"));
@ -336,13 +341,13 @@ public class ServletHandlerTest
mappings = handler.getFilterMappings();
assertNotNull(mappings);
assertTrue(fm1 == mappings[0]);
assertTrue(fm2 == mappings[1]);
assertTrue(ofm1 == mappings[2]);
assertThat(mappings[0], is(fm1));
assertThat(mappings[1], is(fm2));
assertThat(mappings[2], is(ofm1));
}
@Test
public void testAllBeforeFilterMappings() throws Exception
public void testAllBeforeFilterMappings()
{
ServletHandler handler = new ServletHandler();
@ -362,12 +367,12 @@ public class ServletHandlerTest
assertNotNull(mappings);
assertEquals(2, mappings.length);
assertTrue(fm4 == mappings[0]);
assertTrue(fm5 == mappings[1]);
assertThat(mappings[0], is(fm4));
assertThat(mappings[1], is(fm5));
}
@Test
public void testAllAfterFilterMappings() throws Exception
public void testAllAfterFilterMappings()
{
ServletHandler handler = new ServletHandler();
//do equivalent of FilterRegistration.addMappingForUrlPatterns(isMatchAfter=true)
@ -375,19 +380,19 @@ public class ServletHandlerTest
handler.addFilterMapping(fm4);
FilterMapping[] mappings = handler.getFilterMappings();
assertEquals(1, mappings.length);
assertTrue(fm4 == mappings[0]);
assertThat(mappings[0], is(fm4));
//do equivalent of FilterRegistration.addMappingForUrlPatterns(isMatchAfter=true)
handler.addFilter(fh5);
handler.addFilterMapping(fm5);
mappings = handler.getFilterMappings();
assertEquals(2, mappings.length);
assertTrue(fm4 == mappings[0]);
assertTrue(fm5 == mappings[1]);
assertThat(mappings[0], is(fm4));
assertThat(mappings[1], is(fm5));
}
@Test
public void testMatchAfterAndBefore() throws Exception
public void testMatchAfterAndBefore()
{
ServletHandler handler = new ServletHandler();
@ -397,7 +402,7 @@ public class ServletHandlerTest
FilterMapping[] mappings = handler.getFilterMappings();
assertNotNull(mappings);
assertEquals(1, mappings.length);
assertTrue(fm3 == mappings[0]);
assertThat(mappings[0], is(fm3));
//add a programmatic one, isMatchAfter=false
handler.addFilter(fh4);
@ -405,12 +410,12 @@ public class ServletHandlerTest
mappings = handler.getFilterMappings();
assertNotNull(mappings);
assertEquals(2, mappings.length);
assertTrue(fm4 == mappings[0]);
assertTrue(fm3 == mappings[1]);
assertThat(mappings[0], is(fm4));
assertThat(mappings[1], is(fm3));
}
@Test
public void testMatchBeforeAndAfter() throws Exception
public void testMatchBeforeAndAfter()
{
ServletHandler handler = new ServletHandler();
@ -420,7 +425,7 @@ public class ServletHandlerTest
FilterMapping[] mappings = handler.getFilterMappings();
assertNotNull(mappings);
assertEquals(1, mappings.length);
assertTrue(fm3 == mappings[0]);
assertThat(mappings[0], is(fm3));
//add a programmatic one, isMatchAfter=true
handler.addFilter(fh4);
@ -428,12 +433,12 @@ public class ServletHandlerTest
mappings = handler.getFilterMappings();
assertNotNull(mappings);
assertEquals(2, mappings.length);
assertTrue(fm3 == mappings[0]);
assertTrue(fm4 == mappings[1]);
assertThat(mappings[0], is(fm3));
assertThat(mappings[1], is(fm4));
}
@Test
public void testExistingFilterMappings() throws Exception
public void testExistingFilterMappings()
{
ServletHandler handler = new ServletHandler();
handler.addFilter(fh1);
@ -445,26 +450,26 @@ public class ServletHandlerTest
FilterMapping[] mappings = handler.getFilterMappings();
assertNotNull(mappings);
assertTrue(fm1 == mappings[0]);
assertTrue(fm2 == mappings[1]);
assertThat(mappings[0], is(fm1));
assertThat(mappings[1], is(fm2));
//do equivalent of FilterRegistration.addMappingForUrlPatterns(isMatchAfter=false)
handler.addFilter(fh4);
handler.prependFilterMapping(fm4);
mappings = handler.getFilterMappings();
assertEquals(3, mappings.length);
assertTrue(fm4 == mappings[0]);
assertThat(mappings[0], is(fm4));
//do equivalent of FilterRegistration.addMappingForUrlPatterns(isMatchAfter=true)
handler.addFilter(fh5);
handler.addFilterMapping(fm5);
mappings = handler.getFilterMappings();
assertEquals(4, mappings.length);
assertTrue(fm5 == mappings[mappings.length - 1]);
assertThat(mappings[mappings.length - 1], is(fm5));
}
@Test
public void testFilterMappingNoFilter() throws Exception
public void testFilterMappingNoFilter()
{
FilterMapping mapping = new FilterMapping();
mapping.setPathSpec("/*");
@ -474,7 +479,7 @@ public class ServletHandlerTest
}
@Test
public void testFilterMappingsMix() throws Exception
public void testFilterMappingsMix()
{
ServletHandler handler = new ServletHandler();
@ -483,7 +488,7 @@ public class ServletHandlerTest
handler.addFilterMapping(fm1);
FilterMapping[] mappings = handler.getFilterMappings();
assertNotNull(mappings);
assertTrue(fm1 == mappings[0]);
assertThat(mappings[0], is(fm1));
//add a programmatic one, isMatchAfter=false
handler.addFilter(fh4);
@ -491,8 +496,8 @@ public class ServletHandlerTest
mappings = handler.getFilterMappings();
assertNotNull(mappings);
assertEquals(2, mappings.length);
assertTrue(fm4 == mappings[0]);
assertTrue(fm1 == mappings[1]);
assertThat(mappings[0], is(fm4));
assertThat(mappings[1], is(fm1));
//add a programmatic one, isMatchAfter=true
handler.addFilter(fh3);
@ -500,9 +505,9 @@ public class ServletHandlerTest
mappings = handler.getFilterMappings();
assertNotNull(mappings);
assertEquals(3, mappings.length);
assertTrue(fm4 == mappings[0]);
assertTrue(fm1 == mappings[1]);
assertTrue(fm3 == mappings[2]);
assertThat(mappings[0], is(fm4));
assertThat(mappings[1], is(fm1));
assertThat(mappings[2], is(fm3));
//add a programmatic one, isMatchAfter=false
handler.addFilter(fh5);
@ -510,10 +515,10 @@ public class ServletHandlerTest
mappings = handler.getFilterMappings();
assertNotNull(mappings);
assertEquals(4, mappings.length);
assertTrue(fm4 == mappings[0]); //isMatchAfter = false;
assertTrue(fm5 == mappings[1]); //isMatchAfter = false;
assertTrue(fm1 == mappings[2]); //ordinary
assertTrue(fm3 == mappings[3]); //isMatchAfter = true;
assertThat(mappings[0], is(fm4)); //isMatchAfter = false;
assertThat(mappings[1], is(fm5)); //isMatchAfter = false;
assertThat(mappings[2], is(fm1)); //ordinary
assertThat(mappings[3], is(fm3)); //isMatchAfter = true;
//add a non-programmatic one
FilterHolder f = new FilterHolder(Source.EMBEDDED);
@ -526,11 +531,11 @@ public class ServletHandlerTest
mappings = handler.getFilterMappings();
assertNotNull(mappings);
assertEquals(5, mappings.length);
assertTrue(fm4 == mappings[0]); //isMatchAfter = false;
assertTrue(fm5 == mappings[1]); //isMatchAfter = false;
assertTrue(fm1 == mappings[2]); //ordinary
assertTrue(fm == mappings[3]); //ordinary
assertTrue(fm3 == mappings[4]); //isMatchAfter = true;
assertThat(mappings[0], is(fm4)); //isMatchAfter = false;
assertThat(mappings[1], is(fm5)); //isMatchAfter = false;
assertThat(mappings[2], is(fm1)); //ordinary
assertThat(mappings[3], is(fm)); //ordinary
assertThat(mappings[4], is(fm3)); //isMatchAfter = true;
//add a programmatic one, isMatchAfter=true
FilterHolder pf = new FilterHolder(Source.JAVAX_API);
@ -543,12 +548,12 @@ public class ServletHandlerTest
mappings = handler.getFilterMappings();
assertNotNull(mappings);
assertEquals(6, mappings.length);
assertTrue(fm4 == mappings[0]); //isMatchAfter = false;
assertTrue(fm5 == mappings[1]); //isMatchAfter = false;
assertTrue(fm1 == mappings[2]); //ordinary
assertTrue(fm == mappings[3]); //ordinary
assertTrue(fm3 == mappings[4]); //isMatchAfter = true;
assertTrue(pfm == mappings[5]); //isMatchAfter = true;
assertThat(mappings[0], is(fm4)); //isMatchAfter = false;
assertThat(mappings[1], is(fm5)); //isMatchAfter = false;
assertThat(mappings[2], is(fm1)); //ordinary
assertThat(mappings[3], is(fm)); //ordinary
assertThat(mappings[4], is(fm3)); //isMatchAfter = true;
assertThat(mappings[5], is(pfm)); //isMatchAfter = true;
//add a programmatic one, isMatchAfter=false
FilterHolder pf2 = new FilterHolder(Source.JAVAX_API);
@ -561,17 +566,17 @@ public class ServletHandlerTest
mappings = handler.getFilterMappings();
assertNotNull(mappings);
assertEquals(7, mappings.length);
assertTrue(fm4 == mappings[0]); //isMatchAfter = false;
assertTrue(fm5 == mappings[1]); //isMatchAfter = false;
assertTrue(pfm2 == mappings[2]); //isMatchAfter = false;
assertTrue(fm1 == mappings[3]); //ordinary
assertTrue(fm == mappings[4]); //ordinary
assertTrue(fm3 == mappings[5]); //isMatchAfter = true;
assertTrue(pfm == mappings[6]); //isMatchAfter = true;
assertThat(mappings[0], is(fm4)); //isMatchAfter = false;
assertThat(mappings[1], is(fm5)); //isMatchAfter = false;
assertThat(mappings[2], is(pfm2)); //isMatchAfter = false;
assertThat(mappings[3], is(fm1)); //ordinary
assertThat(mappings[4], is(fm)); //ordinary
assertThat(mappings[5], is(fm3)); //isMatchAfter = true;
assertThat(mappings[6], is(pfm)); //isMatchAfter = true;
}
@Test
public void testAddFilterWithMappingAPI() throws Exception
public void testAddFilterWithMappingAPI()
{
ServletHandler handler = new ServletHandler();
@ -580,7 +585,7 @@ public class ServletHandlerTest
handler.updateMappings();
FilterMapping[] mappings = handler.getFilterMappings();
assertNotNull(mappings);
assertTrue(fh1 == mappings[0].getFilterHolder());
assertThat(mappings[0].getFilterHolder(), is(fh1));
//add a programmatic one, isMatchAfter=false
fh4.setServletHandler(handler);
@ -590,8 +595,8 @@ public class ServletHandlerTest
mappings = handler.getFilterMappings();
assertNotNull(mappings);
assertEquals(2, mappings.length);
assertTrue(fh4 == mappings[0].getFilterHolder());
assertTrue(fh1 == mappings[1].getFilterHolder());
assertThat(mappings[0].getFilterHolder(), is(fh4));
assertThat(mappings[1].getFilterHolder(), is(fh1));
//add a programmatic one, isMatchAfter=true
fh3.setServletHandler(handler);
@ -601,9 +606,9 @@ public class ServletHandlerTest
mappings = handler.getFilterMappings();
assertNotNull(mappings);
assertEquals(3, mappings.length);
assertTrue(fh4 == mappings[0].getFilterHolder());
assertTrue(fh1 == mappings[1].getFilterHolder());
assertTrue(fh3 == mappings[2].getFilterHolder());
assertThat(mappings[0].getFilterHolder(), is(fh4));
assertThat(mappings[1].getFilterHolder(), is(fh1));
assertThat(mappings[2].getFilterHolder(), is(fh3));
//add a programmatic one, isMatchAfter=false
fh5.setServletHandler(handler);
@ -613,10 +618,10 @@ public class ServletHandlerTest
mappings = handler.getFilterMappings();
assertNotNull(mappings);
assertEquals(4, mappings.length);
assertTrue(fh4 == mappings[0].getFilterHolder()); //isMatchAfter = false;
assertTrue(fh5 == mappings[1].getFilterHolder()); //isMatchAfter = false;
assertTrue(fh1 == mappings[2].getFilterHolder()); //ordinary
assertTrue(fh3 == mappings[3].getFilterHolder()); //isMatchAfter = true;
assertThat(mappings[0].getFilterHolder(), is(fh4)); //isMatchAfter = false;
assertThat(mappings[1].getFilterHolder(), is(fh5)); //isMatchAfter = false;
assertThat(mappings[2].getFilterHolder(), is(fh1)); //ordinary
assertThat(mappings[3].getFilterHolder(), is(fh3)); //isMatchAfter = true;
//add a non-programmatic one
FilterHolder f = new FilterHolder(Source.EMBEDDED);
@ -626,11 +631,11 @@ public class ServletHandlerTest
mappings = handler.getFilterMappings();
assertNotNull(mappings);
assertEquals(5, mappings.length);
assertTrue(fh4 == mappings[0].getFilterHolder()); //isMatchAfter = false;
assertTrue(fh5 == mappings[1].getFilterHolder()); //isMatchAfter = false;
assertTrue(fh1 == mappings[2].getFilterHolder()); //ordinary
assertTrue(f == mappings[3].getFilterHolder()); //ordinary
assertTrue(fh3 == mappings[4].getFilterHolder()); //isMatchAfter = true;
assertThat(mappings[0].getFilterHolder(), is(fh4)); //isMatchAfter = false;
assertThat(mappings[1].getFilterHolder(), is(fh5)); //isMatchAfter = false;
assertThat(mappings[2].getFilterHolder(), is(fh1)); //ordinary
assertThat(mappings[3].getFilterHolder(), is(f)); //ordinary
assertThat(mappings[4].getFilterHolder(), is(fh3)); //isMatchAfter = true;
//add a programmatic one, isMatchAfter=true
FilterHolder pf = new FilterHolder(Source.JAVAX_API);
@ -642,12 +647,12 @@ public class ServletHandlerTest
mappings = handler.getFilterMappings();
assertNotNull(mappings);
assertEquals(6, mappings.length);
assertTrue(fh4 == mappings[0].getFilterHolder()); //isMatchAfter = false;
assertTrue(fh5 == mappings[1].getFilterHolder()); //isMatchAfter = false;
assertTrue(fh1 == mappings[2].getFilterHolder()); //ordinary
assertTrue(f == mappings[3].getFilterHolder()); //ordinary
assertTrue(fh3 == mappings[4].getFilterHolder()); //isMatchAfter = true;
assertTrue(pf == mappings[5].getFilterHolder()); //isMatchAfter = true;
assertThat(mappings[0].getFilterHolder(), is(fh4)); //isMatchAfter = false;
assertThat(mappings[1].getFilterHolder(), is(fh5)); //isMatchAfter = false;
assertThat(mappings[2].getFilterHolder(), is(fh1)); //ordinary
assertThat(mappings[3].getFilterHolder(), is(f)); //ordinary
assertThat(mappings[4].getFilterHolder(), is(fh3)); //isMatchAfter = true;
assertThat(mappings[5].getFilterHolder(), is(pf)); //isMatchAfter = true;
//add a programmatic one, isMatchAfter=false
FilterHolder pf2 = new FilterHolder(Source.JAVAX_API);
@ -660,17 +665,17 @@ public class ServletHandlerTest
assertNotNull(mappings);
assertEquals(7, mappings.length);
assertTrue(fh4 == mappings[0].getFilterHolder()); //isMatchAfter = false;
assertTrue(fh5 == mappings[1].getFilterHolder()); //isMatchAfter = false;
assertTrue(pf2 == mappings[2].getFilterHolder()); //isMatchAfter = false;
assertTrue(fh1 == mappings[3].getFilterHolder()); //ordinary
assertTrue(f == mappings[4].getFilterHolder()); //ordinary
assertTrue(fh3 == mappings[5].getFilterHolder()); //isMatchAfter = true;
assertTrue(pf == mappings[6].getFilterHolder()); //isMatchAfter = true;
assertThat(mappings[0].getFilterHolder(), is(fh4)); //isMatchAfter = false;
assertThat(mappings[1].getFilterHolder(), is(fh5)); //isMatchAfter = false;
assertThat(mappings[2].getFilterHolder(), is(pf2)); //isMatchAfter = false;
assertThat(mappings[3].getFilterHolder(), is(fh1)); //ordinary
assertThat(mappings[4].getFilterHolder(), is(f)); //ordinary
assertThat(mappings[5].getFilterHolder(), is(fh3)); //isMatchAfter = true;
assertThat(mappings[6].getFilterHolder(), is(pf)); //isMatchAfter = true;
}
@Test
public void testFiltersServletsListenersAsBeans() throws Exception
public void testFiltersServletsListenersAsBeans()
{
ServletContextHandler context = new ServletContextHandler();
@ -747,7 +752,7 @@ public class ServletHandlerTest
handler.addServletWithMapping(new ServletHolder(new HttpServlet()
{
@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 + "'");
}
@ -779,7 +784,7 @@ public class ServletHandlerTest
ServletHolder foo = new ServletHolder(new HttpServlet()
{
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException
{
resp.getOutputStream().println("FOO");
}
@ -790,7 +795,7 @@ public class ServletHandlerTest
ServletHolder def = new ServletHolder(new HttpServlet()
{
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException
{
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"));
}
@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
{
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.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.EventListener;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
@ -489,12 +491,13 @@ public class ContainerLifeCycle extends AbstractLifeCycle implements Container,
if (super.removeEventListener(listener))
{
removeBean(listener);
if (_listeners.remove(listener))
if (listener instanceof Container.Listener && _listeners.remove(listener))
{
Container.Listener cl = (Container.Listener)listener;
// remove existing 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)
((Container)b._bean).removeBean(listener);
@ -813,40 +816,28 @@ public class ContainerLifeCycle extends AbstractLifeCycle implements Container,
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
if (oldBeans != null)
for (Object o : oldBeans)
{
loop:
for (Object o : oldBeans)
{
if (newBeans != null)
{
for (Object n : newBeans)
{
if (o == n)
continue loop;
}
}
if (!newBeans.contains(o))
removeBean(o);
}
}
// add new beans not in old
if (newBeans != null)
for (Object n : newBeans)
{
loop:
for (Object n : newBeans)
{
if (oldBeans != null)
{
for (Object o : oldBeans)
{
if (o == n)
continue loop;
}
}
if (!oldBeans.contains(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));
}
public static DumpableCollection from(String name, Collection<?> collection)
{
return new DumpableCollection(name, collection);
}
@Override
public String dump()
{