Skip to content

Commit

Permalink
Make LayerGroupContainmentCache available only on required services
Browse files Browse the repository at this point in the history
`LayerGroupContainmentCache` can incur in quite a performance penalty
during startup, as it'll get all layer groups and the layers/groups
they're linked to.

`LayerGroupContainmentCache` is a securtity subsystem aid only used by
WMS.

This patch contributes a no-op implementation or a customized one
depending on the value of the
`geoserver.security.layergroup-containmentcache` boolean config
property, which is set to `true` in the default config's `geoserver.yml`
for the `wms`, `gwc`, and `webui` services.

Additionally, the customized `LayerGroupContainmentCache` implementation
avoids re-creating the cache multiple times during startup. The original
implementation does it at the class constructor and on a
`ContextRefreshedEvent` event.
Now, this event is triggered on any `ApplicationContext` refreshed,
which for our spring boot services was being triggered three times:
for the app context itself, the servlet context, and the actuator
context.

Now we make sure the cache is built only when the root application
context is refreshed.
  • Loading branch information
groldan committed May 14, 2024
1 parent ac6ae91 commit 828d9a5
Show file tree
Hide file tree
Showing 6 changed files with 903 additions and 25 deletions.
2 changes: 1 addition & 1 deletion config
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
*/
package org.geoserver.cloud.config.catalog.backend.core;

import lombok.extern.slf4j.Slf4j;

import org.geoserver.catalog.Catalog;
import org.geoserver.catalog.LayerGroupVisibilityPolicy;
import org.geoserver.catalog.impl.AdvertisedCatalog;
Expand All @@ -23,20 +25,22 @@
import org.geoserver.security.SecureCatalogImpl;
import org.geoserver.security.impl.DataAccessRuleDAO;
import org.geoserver.security.impl.DefaultResourceAccessManager;
import org.geoserver.security.impl.GsCloudLayerGroupContainmentCache;
import org.geoserver.security.impl.LayerGroupContainmentCache;
import org.geoserver.security.impl.NoopLayerGroupContainmentCache;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.context.event.ApplicationContextEvent;
import org.springframework.context.event.ContextRefreshedEvent;

// proxyBeanMethods = true required to avoid circular reference exceptions, especially related to
// GeoServerExtensions still being created
@Configuration(proxyBeanMethods = true)
@EnableConfigurationProperties(CatalogProperties.class)
@Slf4j(topic = "org.geoserver.cloud.config.catalog.backend.core")
public class CoreBackendConfiguration {

@Bean
Expand Down Expand Up @@ -111,26 +115,40 @@ DefaultResourceAccessManager defaultResourceAccessManager( //
}

/**
* Added to {@literal gs-main.jar} in 2.22.x as
* Actuial {@link LayerGroupContainmentCache}, matches if the config proeprty {@code
* geoserver.security.layergroup-containmentcache=true}
*
* <pre>
* {@code
* <bean id="layerGroupContainmentCache" class="org.geoserver.security.impl.LayerGroupContainmentCache">
* <constructor-arg ref="rawCatalog"/>
* </bean>
* }
* <p>
* <strong>Overridden</strong> here to act only upon {@link ContextRefreshedEvent}
* instead of on every {@link ApplicationContextEvent},
* especially due to {@code org.springframework.cloud.client.discovery.event.HeartbeatEvent} and possibly
* others.
* <p>
* Update: as of geoserver 2.23.2, {@code LayerGroupContainmentCache} implements {@code ApplicationListener<ContextRefreshedEvent>}
* @see #noOpLayerGroupContainmentCache(Catalog)
*/
@Bean
LayerGroupContainmentCache layerGroupContainmentCache(
@Bean(name = "layerGroupContainmentCache")
@ConditionalOnGeoServerSecurityEnabled
@ConditionalOnProperty(
name = "geoserver.security.layergroup-containmentcache",
havingValue = "true",
matchIfMissing = false)
LayerGroupContainmentCache enabledLayerGroupContainmentCache(
@Qualifier("rawCatalog") Catalog rawCatalog) {
return new LayerGroupContainmentCache(rawCatalog);

log.info("using {}", GsCloudLayerGroupContainmentCache.class.getSimpleName());
return new GsCloudLayerGroupContainmentCache(rawCatalog);
}

/**
* Default {@link LayerGroupContainmentCache} is a no-op, matches if the config proeprty {@code
* geoserver.security.layergroup-containmentcache=false} or is not specified
*
* @see #enabledLayerGroupContainmentCache(Catalog)
*/
@Bean(name = "layerGroupContainmentCache")
@ConditionalOnGeoServerSecurityEnabled
@ConditionalOnProperty(
name = "geoserver.security.layergroup-containmentcache",
havingValue = "false",
matchIfMissing = true)
LayerGroupContainmentCache noOpLayerGroupContainmentCache() {

log.info("using {}", NoopLayerGroupContainmentCache.class.getSimpleName());
return new NoopLayerGroupContainmentCache();
}

@ConditionalOnGeoServerSecurityDisabled
Expand All @@ -145,8 +163,7 @@ Catalog secureCatalogDisabled(@Qualifier("rawCatalog") Catalog rawCatalog) {
*/
@Bean
Catalog advertisedCatalog(
@Qualifier("secureCatalog") Catalog secureCatalog, CatalogProperties properties)
throws Exception {
@Qualifier("secureCatalog") Catalog secureCatalog, CatalogProperties properties) {
if (properties.isAdvertised()) {
AdvertisedCatalog advertisedCatalog = new AdvertisedCatalog(secureCatalog);
advertisedCatalog.setLayerGroupVisibilityPolicy(LayerGroupVisibilityPolicy.HIDE_NEVER);
Expand All @@ -161,8 +178,8 @@ Catalog advertisedCatalog(
*/
@Bean(name = {"catalog", "localWorkspaceCatalog"})
Catalog localWorkspaceCatalog(
@Qualifier("advertisedCatalog") Catalog advertisedCatalog, CatalogProperties properties)
throws Exception {
@Qualifier("advertisedCatalog") Catalog advertisedCatalog,
CatalogProperties properties) {
return properties.isLocalWorkspace()
? new LocalWorkspaceCatalog(advertisedCatalog)
: advertisedCatalog;
Expand Down
Loading

0 comments on commit 828d9a5

Please sign in to comment.