Skip to content

Commit

Permalink
[GEOS-11284] Load DataDirectoryGeoServerLoader through GeoserverLoade…
Browse files Browse the repository at this point in the history
…rProxy

Let GeoServerLoaderProxy decide whether to instantiate a
DefaultGeoServerLoader or a DataDirectoryGeoServerLoader based on
externalized configuration, and remove the spring @configuration class
for DataDirectoryGeoServerLoader.

This preserves the behavior of allowing only one GeoServerLoader bean
contributed by an external plugin. Otherwise the jdcconfig one would
fail.
  • Loading branch information
groldan committed Feb 15, 2024
1 parent de51ee2 commit 26877f3
Show file tree
Hide file tree
Showing 8 changed files with 138 additions and 212 deletions.
4 changes: 0 additions & 4 deletions src/main/src/main/java/applicationContext.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,6 @@
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">


<!-- defer loading of DataDirectoryLoader to the DataDirectoryLoaderConfiguration @Configuration class -->
<context:component-scan base-package="org.geoserver.catalog.datadir.config"/>

<context:component-scan base-package="org.geoserver.system.status"/>

<bean id="gsMainModule" class="org.geoserver.platform.ModuleStatusImpl">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

import com.google.common.base.Stopwatch;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.Executor;
import java.util.logging.Level;
import java.util.logging.Logger;
Expand All @@ -25,7 +26,6 @@
import org.geoserver.config.GeoServer;
import org.geoserver.config.GeoServerLoader;
import org.geoserver.config.ServiceInfo;
import org.geoserver.config.SettingsInfo;
import org.geoserver.config.util.XStreamPersister;
import org.geoserver.config.util.XStreamPersisterFactory;
import org.geoserver.config.util.XStreamServiceLoader;
Expand All @@ -40,6 +40,10 @@
import org.geotools.api.filter.IncludeFilter;
import org.geotools.util.factory.GeoTools;
import org.geotools.util.logging.Logging;
import org.springframework.context.ApplicationContext;
import org.springframework.core.env.Environment;
import org.springframework.lang.Nullable;
import org.springframework.util.StringUtils;

/**
* The loading process is multi-threaded, and will take place in an {@link Executor} whose
Expand All @@ -51,6 +55,8 @@
* @since 2.25
*/
public class DataDirectoryGeoServerLoader extends DefaultGeoServerLoader {
static final String SYSPROP_KEY = "datadir.loader.enabled";
static final String ENVVAR_KEY = "DATADIR_LOADER_ENABLED";

static final Logger LOGGER =
Logging.getLogger(DataDirectoryGeoServerLoader.class.getPackage().getName());
Expand Down Expand Up @@ -112,19 +118,23 @@ protected Catalog readCatalog(XStreamPersister xp) throws Exception {
logStop(startedStopWatch.stop(), catalog);

catalogLoaded = true;
disposeIfBothLoaded();
catalog.resolve();
decryptDataStorePasswords(catalog);
disposeIfBothLoaded();
return catalog;
}

@Override
protected void readConfiguration(GeoServer target, XStreamPersister xp) throws Exception {
if (isLegacyConfig()) {
super.readConfiguration(target, xp);
return;
}
LOGGER.config("Loading GeoServer config...");
Stopwatch stopWatch = Stopwatch.createStarted();

loader().loadGeoServer(target);
catalogLoaded = true;
geoserverLoaded = true;
disposeIfBothLoaded();

LOGGER.log(
Expand All @@ -150,18 +160,6 @@ protected CatalogImpl newTemporaryCatalog() {
return new CatalogImpl();
}

private void clear(GeoServer target) {
target.getServices().forEach(target::remove);

target.getCatalog().getWorkspaces().stream()
.forEach(
ws -> {
SettingsInfo settings = target.getSettings(ws);
if (null != settings) target.remove(settings);
target.getServices(ws).forEach(target::remove);
});
}

private void decryptDataStorePasswords(CatalogImpl catalog) {
ConfigurationPasswordEncryptionHelper helper;
helper = securityManager.getConfigPasswordEncryptionHelper();
Expand Down Expand Up @@ -240,4 +238,36 @@ private void logStop(Stopwatch stoppedSw, final Catalog catalog) {
catalog.count(LayerGroupInfo.class, all));
});
}

/**
* Determines whether the {@link DataDirectoryGeoServerLoader} shall be used, works like a
* spring-boot's {@code @ConditionalOnProperty(value="datadir.loader.enabled",
* havingValue="true", matchIfMissing=true)}, in which the both {@code datadir.loader.enabled}
* and {@code DATADIR_LOADER_ENABLED} can be used as System property, environment variable, or
* ApplicationContex {@link Environment} property.
*
* @return {@code true} by default, false if the enabled config property resolves to anything
* but {@code true}
* @param context if provided, used to fall back resolving the {@code datadir.loader.enabled} or
* {@code DATADIR_LOADER_ENABLED} config property if not provided as System property or
* environment variable.
*/
public static boolean isEnabled(@Nullable ApplicationContext context) {
String value =
getProperty(context, SYSPROP_KEY)
.or(() -> getProperty(context, ENVVAR_KEY))
.orElse("true");
return Boolean.parseBoolean(value);
}

private static Optional<String> getProperty(@Nullable ApplicationContext context, String prop) {
String value = GeoServerExtensions.getProperty(prop);
if (!StringUtils.hasText(value) && null != context) {
// GeoServerExtensions.getProperty() doesn't check the Environment property
// doing it here, with lower priority than env variables and system properties,
// so it also works with GeoServer Cloud's externalized configuration
value = context.getEnvironment().getProperty(prop);
}
return Optional.ofNullable(value);
}
}

This file was deleted.

13 changes: 9 additions & 4 deletions src/main/src/main/java/org/geoserver/config/GeoServerLoader.java
Original file line number Diff line number Diff line change
Expand Up @@ -948,13 +948,17 @@ Catalog readLegacyCatalog(Resource f, XStreamPersister xp) throws Exception {
return catalog2;
}

protected boolean isLegacyConfig() {
Resource legacyServicesConfigFile = resourceLoader.get("services.xml");
return Resources.exists(legacyServicesConfigFile);
}

protected void readConfiguration(GeoServer geoServer, XStreamPersister xp) throws Exception {
// look for services.xml, if it exists assume we are dealing with
// an old data directory
Resource f = resourceLoader.get("services.xml");
if (!Resources.exists(f)) {
if (!isLegacyConfig()) {
// assume 2.x style
f = resourceLoader.get("global.xml");
Resource f = resourceLoader.get("global.xml");
if (Resources.exists(f)) {
try {
GeoServerInfo global = depersist(xp, f, GeoServerInfo.class);
Expand Down Expand Up @@ -1032,7 +1036,8 @@ protected void readConfiguration(GeoServer geoServer, XStreamPersister xp) throw
geoServer.removeListener(p);

// rename the services.xml file
f.renameTo(f.parent().get("services.xml.old"));
Resource services = resourceLoader.get("services.xml");
services.renameTo(services.parent().get("services.xml.old"));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@
*/
package org.geoserver.config;

import org.geoserver.catalog.datadir.DataDirectoryGeoServerLoader;
import org.geoserver.platform.GeoServerExtensions;
import org.geoserver.platform.GeoServerResourceLoader;
import org.geoserver.security.GeoServerSecurityManager;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.ApplicationContext;
Expand Down Expand Up @@ -79,11 +81,27 @@ public void onApplicationEvent(ContextClosedEvent event) {
protected GeoServerLoader lookupGeoServerLoader(ApplicationContext appContext) {
GeoServerLoader loader = GeoServerExtensions.bean(GeoServerLoader.class, appContext);
if (loader == null) {
loader = new DefaultGeoServerLoader(resourceLoader);
loader = createDefaultLoader(appContext);
}
return loader;
}

/**
* @param appContext required for {@link
* DataDirectoryGeoServerLoader#isEnabled(ApplicationContext)}
* @return a new instance of {@link DataDirectoryGeoServerLoader} if {@link
* DataDirectoryGeoServerLoader#isEnabled() enabled}, or {@link DefaultGeoServerLoader}
* otherwise.
*/
protected GeoServerLoader createDefaultLoader(ApplicationContext appContext) {
if (DataDirectoryGeoServerLoader.isEnabled(appContext)) {
GeoServerSecurityManager securityManager =
GeoServerExtensions.bean(GeoServerSecurityManager.class);
return new DataDirectoryGeoServerLoader(resourceLoader, securityManager);
}
return new DefaultGeoServerLoader(resourceLoader);
}

@Override
public void initialize(GeoServer geoServer) throws Exception {
loader.initializeDefaultStyles(geoServer.getCatalog());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/* (c) 2022 Open Source Geospatial Foundation - all rights reserved
* This code is licensed under the GPL 2.0 license, available at the root
* application directory.
*/
package org.geoserver.catalog.datadir;

import static org.geoserver.catalog.datadir.DataDirectoryGeoServerLoader.ENVVAR_KEY;
import static org.geoserver.catalog.datadir.DataDirectoryGeoServerLoader.SYSPROP_KEY;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import org.geoserver.platform.GeoServerExtensionsHelper;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.core.env.Environment;

public class DataDirectoryGeoServerLoaderEnablementTest {

@Before
public void setup() {
GeoServerExtensionsHelper.setIsSpringContext(false);
}

@After
public void destroyAppContext() {
GeoServerExtensionsHelper.init(null);
}

@Test
public void testEnabledByDefault() {
assertTrue(DataDirectoryGeoServerLoader.isEnabled(null));
}

@Test
public void testEnabled() {
GeoServerExtensionsHelper.property(SYSPROP_KEY, "true");
assertTrue(DataDirectoryGeoServerLoader.isEnabled(null));
}

@Test
public void testDisabledWithSystemProperty() {
GeoServerExtensionsHelper.property(SYSPROP_KEY, "false");
assertFalse(DataDirectoryGeoServerLoader.isEnabled(null));
}

@Test
public void testDisabledWithEnvVariable() {
GeoServerExtensionsHelper.property(ENVVAR_KEY, "false");
assertFalse(DataDirectoryGeoServerLoader.isEnabled(null));
}

@Test
public void testDisabledWithAppContextEnvironment() {
ApplicationContext appContext = mock(ApplicationContext.class);
Environment env = mock(Environment.class);
when(appContext.getEnvironment()).thenReturn(env);
when(env.getProperty(ENVVAR_KEY)).thenReturn("false");
assertFalse(DataDirectoryGeoServerLoader.isEnabled(appContext));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
import org.geoserver.catalog.ResourceInfo;
import org.geoserver.catalog.StoreInfo;
import org.geoserver.catalog.WorkspaceInfo;
import org.geoserver.catalog.datadir.config.DataDirectoryLoaderConfiguration.DataDirLoaderEnabledCondition;
import org.geoserver.catalog.impl.CatalogImpl;
import org.geoserver.catalog.impl.MetadataLinkInfoImpl;
import org.geoserver.config.DefaultGeoServerLoader;
Expand Down Expand Up @@ -83,7 +82,7 @@ static class TestService2Impl extends ServiceInfoImpl implements TestService2 {}
*/
@Override
protected void setUpTestData(SystemTestData testData) throws Exception {
System.setProperty(DataDirLoaderEnabledCondition.SYSPROP_KEY, "false");
System.setProperty(DataDirectoryGeoServerLoader.SYSPROP_KEY, "false");
super.setUpTestData(testData);
}

Expand Down

0 comments on commit 26877f3

Please sign in to comment.