Servlet: Now logs a message on context startup to aid debugging.

+ bonus generic refactorings
This commit is contained in:
Harald Kuhr 2023-03-09 12:17:20 +01:00
parent 77c98c917e
commit 25cd351eee
2 changed files with 30 additions and 26 deletions

View File

@ -37,6 +37,7 @@ import java.util.List;
import javax.imageio.ImageIO; import javax.imageio.ImageIO;
import javax.imageio.spi.IIORegistry; import javax.imageio.spi.IIORegistry;
import javax.imageio.spi.ServiceRegistry; import javax.imageio.spi.ServiceRegistry;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener; import javax.servlet.ServletContextListener;
@ -57,31 +58,38 @@ import javax.servlet.ServletContextListener;
public final class IIOProviderContextListener implements ServletContextListener { public final class IIOProviderContextListener implements ServletContextListener {
public void contextInitialized(final ServletContextEvent event) { public void contextInitialized(final ServletContextEvent event) {
event.getServletContext().log("Scanning for locally installed ImageIO plugin providers");
// Registers all locally available IIO plugins. // Registers all locally available IIO plugins.
ImageIO.scanForPlugins(); ImageIO.scanForPlugins();
} }
public void contextDestroyed(final ServletContextEvent event) { public void contextDestroyed(final ServletContextEvent event) {
ServletContext servletContext = event.getServletContext();
// De-register any locally registered IIO plugins. Relies on each web app having its own context class loader. // De-register any locally registered IIO plugins. Relies on each web app having its own context class loader.
final IIORegistry registry = IIORegistry.getDefaultInstance(); LocalFilter localFilter = new LocalFilter(Thread.currentThread().getContextClassLoader()); // scanForPlugins uses context class loader
final LocalFilter localFilter = new LocalFilter(Thread.currentThread().getContextClassLoader()); // scanForPlugins uses context class loader
IIORegistry registry = IIORegistry.getDefaultInstance();
Iterator<Class<?>> categories = registry.getCategories(); Iterator<Class<?>> categories = registry.getCategories();
while (categories.hasNext()) { while (categories.hasNext()) {
Class<?> category = categories.next(); deregisterLocalProvidersForCategory(registry, localFilter, categories.next(), servletContext);
Iterator<?> providers = registry.getServiceProviders(category, localFilter, false); }
}
// Copy the providers, as de-registering while iterating over providers will lead to ConcurrentModificationExceptions. private static <T> void deregisterLocalProvidersForCategory(IIORegistry registry, LocalFilter localFilter, Class<T> category, ServletContext context) {
List<Object> providersCopy = new ArrayList<>(); Iterator<T> providers = registry.getServiceProviders(category, localFilter, false);
while (providers.hasNext()) {
providersCopy.add(providers.next());
}
for (Object provider : providersCopy) { // Copy the providers, as de-registering while iterating over providers will lead to ConcurrentModificationExceptions.
registry.deregisterServiceProvider(provider); List<T> providersCopy = new ArrayList<>();
event.getServletContext().log(String.format("Unregistered locally installed provider class: %s", provider.getClass())); while (providers.hasNext()) {
} providersCopy.add(providers.next());
}
for (T provider : providersCopy) {
registry.deregisterServiceProvider(provider, category);
context.log(String.format("Unregistered locally installed provider class: %s", provider.getClass()));
} }
} }

View File

@ -33,7 +33,6 @@ package com.twelvemonkeys.servlet.image;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.util.Locale; import java.util.Locale;
@ -54,32 +53,29 @@ import org.junit.Test;
* @version $Id: IIOProviderContextListenerTest.java,v 1.0 02.01.14 12:33 haraldk Exp$ * @version $Id: IIOProviderContextListenerTest.java,v 1.0 02.01.14 12:33 haraldk Exp$
*/ */
public class IIOProviderContextListenerTest { public class IIOProviderContextListenerTest {
private final ServletContext context = mock(ServletContext.class);
private final ServletContextEvent initialized = new ServletContextEvent(context);
private final ServletContextEvent destroyed = new ServletContextEvent(context);
@Test @Test
public void testContextInitialized() { public void testContextInitialized() {
ServletContextListener listener = new IIOProviderContextListener(); ServletContextListener listener = new IIOProviderContextListener();
listener.contextInitialized(mock(ServletContextEvent.class)); listener.contextInitialized(initialized);
} }
@Test @Test
public void testContextDestroyed() { public void testContextDestroyed() {
ServletContext context = mock(ServletContext.class);
ServletContextEvent destroyed = mock(ServletContextEvent.class);
when(destroyed.getServletContext()).thenReturn(context);
ServletContextListener listener = new IIOProviderContextListener(); ServletContextListener listener = new IIOProviderContextListener();
listener.contextInitialized(mock(ServletContextEvent.class)); listener.contextInitialized(initialized);
listener.contextDestroyed(destroyed); listener.contextDestroyed(destroyed);
} }
// Regression test for issue #29 // Regression test for issue #29
@Test @Test
public void testDestroyConcurrentModRegression() { public void testDestroyConcurrentModRegression() {
ServletContext context = mock(ServletContext.class);
ServletContextEvent destroyed = mock(ServletContextEvent.class);
when(destroyed.getServletContext()).thenReturn(context);
ServletContextListener listener = new IIOProviderContextListener(); ServletContextListener listener = new IIOProviderContextListener();
listener.contextInitialized(mock(ServletContextEvent.class)); listener.contextInitialized(initialized);
ImageReaderSpi provider1 = new MockImageReaderSpiOne(); ImageReaderSpi provider1 = new MockImageReaderSpiOne();
ImageReaderSpi provider2 = new MockImageReaderSpiToo(); ImageReaderSpi provider2 = new MockImageReaderSpiToo();