From 21ea7da7fc7e1b6696c8c06a5ec9d74adfa275e9 Mon Sep 17 00:00:00 2001 From: Gabriel Roldan Date: Thu, 9 Nov 2023 08:51:07 -0300 Subject: [PATCH] Change GeoTools log redirection from Log4j2 to Logback GeoTools version of Log4j2 (2.17.2) and the one used by spring-boot (2.21.1) differ in the API used by GeoTools to set the logging level, which produces an exception due to a missing setLevel(...) method in the new version. Change log redirection to use Logback, and make sure the ApplicationContextInitializers run only once, as they may be called twice, once for the webapp context, and again for the Actuator context. --- .../geotools/GeoToolsStaticContextInitializer.java | 5 +++++ .../GeoToolsHttpClientAutoConfigurationTest.java | 8 ++++---- .../jndi/SimpleJNDIStaticContextInitializer.java | 4 ++++ .../context/GeoServerContextInitializer.java | 14 +++++++++++--- 4 files changed, 24 insertions(+), 7 deletions(-) diff --git a/src/catalog/backends/common/src/main/java/org/geoserver/cloud/autoconfigure/geotools/GeoToolsStaticContextInitializer.java b/src/catalog/backends/common/src/main/java/org/geoserver/cloud/autoconfigure/geotools/GeoToolsStaticContextInitializer.java index c3a3fd5fe..d93fc4290 100644 --- a/src/catalog/backends/common/src/main/java/org/geoserver/cloud/autoconfigure/geotools/GeoToolsStaticContextInitializer.java +++ b/src/catalog/backends/common/src/main/java/org/geoserver/cloud/autoconfigure/geotools/GeoToolsStaticContextInitializer.java @@ -7,6 +7,7 @@ import org.geoserver.GeoserverInitStartupListener; import org.springframework.context.ApplicationContextInitializer; import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.web.context.support.GenericWebApplicationContext; /** * {@link ApplicationContextInitializer} replacing upstream's {@link GeoserverInitStartupListener}, @@ -22,6 +23,10 @@ public class GeoToolsStaticContextInitializer @Override public void initialize(ConfigurableApplicationContext applicationContext) { + // run once for the webapp context, ignore the actuator context + if (!(applicationContext instanceof GenericWebApplicationContext)) { + return; + } System.setProperty("org.geotools.referencing.forceXY", "true"); Boolean useEnvAwareHttpClient = diff --git a/src/catalog/backends/common/src/test/java/org/geoserver/cloud/autoconfigure/geotools/GeoToolsHttpClientAutoConfigurationTest.java b/src/catalog/backends/common/src/test/java/org/geoserver/cloud/autoconfigure/geotools/GeoToolsHttpClientAutoConfigurationTest.java index 0d127ffa6..88a169ef5 100644 --- a/src/catalog/backends/common/src/test/java/org/geoserver/cloud/autoconfigure/geotools/GeoToolsHttpClientAutoConfigurationTest.java +++ b/src/catalog/backends/common/src/test/java/org/geoserver/cloud/autoconfigure/geotools/GeoToolsHttpClientAutoConfigurationTest.java @@ -5,20 +5,20 @@ package org.geoserver.cloud.autoconfigure.geotools; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertNull; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.boot.test.context.runner.WebApplicationContextRunner; /** * @since 1.0 */ class GeoToolsHttpClientAutoConfigurationTest { - private ApplicationContextRunner runner = - new ApplicationContextRunner() // + private WebApplicationContextRunner runner = + new WebApplicationContextRunner() // .withInitializer(new GeoToolsStaticContextInitializer()) // .withConfiguration( AutoConfigurations.of(GeoToolsHttpClientAutoConfiguration.class)); diff --git a/src/library/spring-boot-simplejndi/src/main/java/org/geoserver/cloud/config/jndi/SimpleJNDIStaticContextInitializer.java b/src/library/spring-boot-simplejndi/src/main/java/org/geoserver/cloud/config/jndi/SimpleJNDIStaticContextInitializer.java index 13e314ad1..e43ac7223 100644 --- a/src/library/spring-boot-simplejndi/src/main/java/org/geoserver/cloud/config/jndi/SimpleJNDIStaticContextInitializer.java +++ b/src/library/spring-boot-simplejndi/src/main/java/org/geoserver/cloud/config/jndi/SimpleJNDIStaticContextInitializer.java @@ -24,6 +24,8 @@ public class SimpleJNDIStaticContextInitializer implements ApplicationContextInitializer { + private static boolean initialized; + /** * Register the context builder by registering it with the JNDI NamingManager. Note that once * this has been done, {@code new InitialContext()} will always return a context from this @@ -36,6 +38,8 @@ public class SimpleJNDIStaticContextInitializer */ @Override public void initialize(ConfigurableApplicationContext applicationContext) { + if (initialized) return; + initialized = true; if (NamingManager.hasInitialContextFactoryBuilder()) { log.info("JNDI InitialContextFactoryBuilder already set"); return; diff --git a/src/starters/webmvc/src/main/java/org/geoserver/cloud/autoconfigure/context/GeoServerContextInitializer.java b/src/starters/webmvc/src/main/java/org/geoserver/cloud/autoconfigure/context/GeoServerContextInitializer.java index 8c6f8462a..08829be73 100644 --- a/src/starters/webmvc/src/main/java/org/geoserver/cloud/autoconfigure/context/GeoServerContextInitializer.java +++ b/src/starters/webmvc/src/main/java/org/geoserver/cloud/autoconfigure/context/GeoServerContextInitializer.java @@ -7,6 +7,7 @@ import org.geoserver.GeoserverInitStartupListener; import org.springframework.context.ApplicationContextInitializer; import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.web.context.support.GenericWebApplicationContext; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; @@ -29,15 +30,22 @@ public class GeoServerContextInitializer @Override public void initialize(ConfigurableApplicationContext applicationContext) { + // run once for the webapp context, ignore the actuator context + if (!(applicationContext instanceof GenericWebApplicationContext)) { + return; + } + // tell geoserver not to control logging, spring-boot will do System.setProperty("RELINQUISH_LOG4J_CONTROL", "true"); // and tell geotools not to redirect to Log4J nor any other framework, we'll use - // spring-boot's logging redirection. Use Log4J2 redirection policy, JavaLogging + // spring-boot's logging redirection. Use Logback redirection policy, JavaLogging // will make GeoserverInitStartupListener's call to GeoTools.init() heuristically set // Logging.ALL.setLoggerFactory("org.geotools.util.logging.LogbackLoggerFactory") // with the caveat that it wrongly maps logging levels and hence if, for example, a logger - // with level FINE is called with INFO, it doesn't log at all - System.setProperty("GT2_LOGGING_REDIRECTION", "Log4J2"); + // with level FINE is called with INFO, it doesn't log at all. + // Log4J2 redirection policy will fail when calling java.util.logging.Logger.setLevel(..) + // because our version of Log4j2 is newer than GeoTools' and the API changed + System.setProperty("GT2_LOGGING_REDIRECTION", "Logback"); ServletContext source = mockServletContext(); ServletContextEvent sce = new ServletContextEvent(source); GeoserverInitStartupListener startupInitializer = new GeoserverInitStartupListener();